Skip to content

feat(extensions): add shared runtimes and independent view authoring - #1

Merged
Juliusolsson05 merged 4 commits into
mainfrom
fix/match-host-capability-set
Sep 13, 2026
Merged

Juliusolsson05 merged 4 commits into
mainfrom
fix/match-host-capability-set

Conversation

@Juliusolsson05

@Juliusolsson05 Juliusolsson05 commented Aug 28, 2026 •

Copy link
Copy Markdown
Owner

API v1 runs activation inside each visible view, so it cannot own one background engine or execute commands with every view closed. SDK 0.8.0 defines the API v2 contract implemented by Agent Code PR #577: one managed runtime owns commands/state, separate view modules own DOM, and both use the same permissioned host services.

Included

  • Typed defineRuntime and defineView helpers, host-issued view identities, bounded JSON requests/state, and explicit activation events.
  • A Vite preset for independent runtime/view entries and browser-safe shared chunks. Existing v1 single-entry/custom-filename builds remain supported.
  • Declarative, namespaced themes with the exported Agent Code appearance-token vocabulary.
  • Scoped files.readText and files.writeText for runtimes and views. Writes require fs.write, are create-only with expectedVersion: null, and require the opaque read version for replacement.
  • notifications.show(message) for runtimes and views, gated by the notifications.show permission. Agent Code shows the message (at most 200 characters) as a toast attributed to the extension, so background runtimes can report with no view open.
  • Updated source, generated dist, README, negative type contracts, and a typed counter fixture that exercises runtime and view reads/writes, a runtime notification and declarative themes.

Verification

  • SDK compile, valid/invalid author type contracts, v2 multi-entry build/import, legacy v1 build/dynamic import, and committed-dist checks pass.
  • Both SDK CI checks pass at 96acc89.
  • Agent Code's production Electron journey builds and installs this fixture, then verifies cold commands, two windows, shared state, zero-view background work, runtime/view file reads and writes, a runtime notification, theme lifecycle, and completed teardown.
  • Timer and Mini Games build against this SDK and install through the same Electron path.
  • A pre-merge review found two build-path defects, fixed in 9f109fb. The preset now pins the production JSX transform, so a build run with NODE_ENV=development no longer crashes views with jsxDEV is not a function; a regression test failed before the fix and passes after it. The exports map gains a default condition, so vite.config.ts loads in a CommonJS author package.
  • History has four focused commits: API v2 foundation 574900e, scoped file writes 9c30b919, background notifications 96acc89, and the build fixes 9f109fb.

No npm publication or merge has been performed. Merge this PR first; Agent Code #577 and both example extensions pin commits from it.

Host: Juliusolsson05/agent-code#577
Mini Games consumer: Juliusolsson05/agent-code-mini-games#9
Timer consumer: Juliusolsson05/agent-code-timer#2
Refs Juliusolsson05/agent-code#934

🤖 Generated with Claude Code

https://claude.ai/code/session_01SnzR4ggdHfDfmFcTA7H8kw

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
@Juliusolsson05 Juliusolsson05 changed the title fix: match the host's real capability set and correct the preset import feat(extensions): add shared runtimes and independent view authoring Sep 12, 2026
Expose shared background runtimes and independent sandboxed views with lifecycle hooks, commands, durable storage, declarative themes, and consent-gated project file reads.

Keep the frozen API v1 contract compatible, ship generated declaration and runtime artifacts, and verify real consumer builds against the public package surface.
@Juliusolsson05
Juliusolsson05 force-pushed the fix/match-host-capability-set branch from aa2084b to 574900e Compare September 12, 2026 23:14
Expose consent-gated API v2 writes to runtimes and views with explicit session targeting, bounded UTF-8 text, atomic publication, and mandatory create/version expectations.

Update the typed counter fixture to exercise real runtime and view writes while retaining v1 compile-time denial.
Expose a bounded permissioned toast service to API v2 runtimes and views so background work can report completion after its UI closes. Keep API v1 frozen and verify the public author fixture declares and compiles the new contract.\n\nRefs Juliusolsson05/agent-code#934
…g loading

The preset defined NODE_ENV=production, which bundles React's production
runtime, but Vite still chose the JSX transform from the shell's NODE_ENV. A
build run with NODE_ENV=development (the usual workaround for npm dropping
devDependencies) emitted jsxDEV calls against a runtime whose jsxDEV export is
undefined, so the view crashed on first render inside the frame. Timer and
Mini Games both hit this. The preset now sets esbuild.jsxDev to false, and a
regression test builds JSX under NODE_ENV=development.

The exports map offered only the import condition, so a vite.config.ts in a
CommonJS author package (the npm init default) failed to resolve the SDK
before building. A default condition lets Vite's config bundler load it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnzR4ggdHfDfmFcTA7H8kw
@Juliusolsson05
Juliusolsson05 merged commit 503bced into main Sep 13, 2026
2 checks passed
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