Skip to content

fix: match the host's real capability set and correct the preset import - #1

Open
Juliusolsson05 wants to merge 1 commit into
mainfrom
fix/match-host-capability-set
Open

fix: match the host's real capability set and correct the preset import#1
Juliusolsson05 wants to merge 1 commit into
mainfrom
fix/match-host-capability-set

Conversation

@Juliusolsson05

Copy link
Copy Markdown
Owner

Problem

Two things in this package told extension authors something Agent Code does not do.

ExtensionCapability declared ten capabilities; the host implements three. The other seven — fs.read, transcript.read, git.read, sessions.prompt, fs.write, git.commit, network.fetch — had no request method, no broker arm and no API surface anywhere in the host, and Agent Code now refuses to install a manifest that asks for one.

That inverted this package's entire purpose. It exists so an author gets a type error instead of a runtime surprise, and instead permissions: ['fs.write'] type-checked cleanly and then failed the install with a message about a capability the SDK had just told them was valid.

The vite preset's usage comment named agent-code-extension-api/vite. package.json declares exactly one export path ("."), so that specifier throws ERR_PACKAGE_PATH_NOT_EXPORTED — an author copying the line got a module-not-found before their first build. README.md already used the correct root specifier.

Change

  • ExtensionCapability is now the three implemented Tier-1 observe capabilities, with a comment recording the rule that produced the bug: a capability belongs in this union only once the host can perform it.
  • The preset comment uses the root specifier and explains why the subpath does not resolve.
  • Version 0.3.0, dist/ rebuilt.

Verification

npm run build — clean. dist/ regenerated and committed, since it is what consumers of the github: specifier actually receive.

Notes

Tagged v0.3.0 so the Agent Code superproject can pin a commit that stays reachable regardless of this branch's lifetime.

Follow-up, not in this PR: this repo has no CI workflow and satisfies 3 of the 10 scripts docs/testing/standard.md requires of an owned package, and nothing verifies the committed dist/ matches src/.

Refs Juliusolsson05/agent-code#577

Two things in this package told authors something the host does not do.

ExtensionCapability declared ten capabilities. The host implements three. The
other seven — fs.read, transcript.read, git.read, sessions.prompt, fs.write,
git.commit, network.fetch — had no request method, no broker arm and no API
surface, and Agent Code now refuses to install a manifest that asks for one.

That inverted this package's entire purpose. It exists so an author gets a type
error instead of a runtime surprise, and instead `permissions: ['fs.write']`
type-checked cleanly and then failed the install with a message about a
capability the SDK had just told them was valid. A capability belongs in this
union only once the host can perform it.

The vite preset's usage comment named `agent-code-extension-api/vite`. The
package declares exactly one export path ("."), so that subpath resolves to
nothing and an author copying the line got a module-not-found before their first
build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hyzz9bxqTQ2zSawmHDN72o
Juliusolsson05 added a commit to Juliusolsson05/agent-code that referenced this pull request Aug 28, 2026
…roject gap

Findings from an adversarial review of the build, packaging and CI slice. The
reviewer verified the end-to-end path in the built artifact rather than reasoning
about it — scheme registration provably lands before app.whenReady() in
out/main/index.js, the frame-src CSP survives into the built HTML, all 1253 src
files are type-checked, and in a CI-equivalent environment (HOME pointed at an
empty directory) the suite is 299/299 files green with coverage above every
threshold.

**The blocker was one I had just created.** The SDK submodule was re-pinned to a
commit reachable only from an unmerged feature branch. It clones today and stops
the moment that branch is deleted — GitHub's default one-click action after a
merge, automatic on squash — at which point `git clone --recurse-submodules`, the
release workflow's submodule init, and CI's `submodules: recursive` all fail
permanently, including for agent-code tags already released, because the
superproject commit hard-codes the SHA.

Fixed by tagging the SDK commit `v0.3.0` rather than by merging: a tag keeps the
object reachable regardless of the branch's lifetime, so the fuse is gone without
pre-empting review of the SDK change itself (opened as
Juliusolsson05/agent-code-extension-api#1).

**The shipped guide told authors to import a package with no install route.** It
is not on npm (404) and its GitHub release carries no asset, so every author
following §3 failed at `npm install`. The only working route — `npm i -D
github:…`, which works because `dist/` is committed — was documented nowhere. Now
it is, along with the fact that the SDK is optional: an extension is a plain ES
module and nothing in the host requires depending on it.

**A `*.test.tsx` outside the renderer naming convention ran in NO project.** The
unit project included only `.ts` and the renderer project takes only
`*.renderer.test.tsx`, so `Foo.test.tsx` matched nothing: vitest ran it nowhere,
reported success, and the contract script — which greps for `.only`, not for
project membership — agreed. A test that silently never runs is worse than a
missing one, because the coverage it appears to provide is counted. All ~300
current files map to exactly one project, so this closes a hole rather than
fixing a live miss. Widening the include required widening the tier excludes to
match: `*.renderer.test.tsx` matches the new glob too, and without the `.tsx`
excludes every renderer test was also collected into the node project — which is
exactly what happened on the first attempt, and is now pinned by the routing test.

Also corrects the preload header, which asserted that these methods had a single
call site in `apps/api/useAppHostApi.ts`. That module does not exist and five
files call them directly, so it stated a security-shaped invariant that was
false. The real rule is two rules: storage is extension-facing and
createAppHostApi is its chokepoint, while list/install/remove/granted-capabilities
are host-facing by design — an extension cannot reach them at all, having no
preload and no ipcRenderer.

Refs #577

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hyzz9bxqTQ2zSawmHDN72o
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant