Extension system with server-backed panels#397
Open
Anton-Horn wants to merge 9 commits into
Open
Conversation
End-to-end extension system that adds panels to Cate via a web frontend
and an optional local server, served through a token-injecting proxy.
- runtime capabilities: HTTP/WS tunneling + a managed server host
(src/runtime/capabilities/{server,tunnel}.ts)
- main: ExtensionManager, ExtensionServerManager, proxy server, catalog
download/install, and the cateHost reverse-API dispatch + storage
- preload: cateHost bridge injected into extension webview guests
- renderer: ExtensionPanel, ExtensionsSettings, useCateHostActionResponder
- shared: manifest/types, cate-host API typings, IPC channels
- docs/extensions.md describing the system
The extension catalog lives in its own repo (0-AI-UG/cate-extensions);
it's gitignored here and only checked out locally for dev/tests, which
skip when that checkout is absent.
b6f994b to
778d1cd
Compare
- ci.yml: check out + build 0-AI-UG/cate-extensions before unit tests so the distribution and kitchensink-server suites run against the real artifact instead of skipping. - kitchensinkServer.test: derive the server entry from the manifest command (works for server.js or compiled dist/server.js), guard the manifest read so the file imports without the catalog, and annotate the WebSocket socket 'data' chunk as Buffer (fixes the CI typecheck failure under a stricter @types/node). - distribution.test: read the built dist/catalog index and assert the manifest's declared server entry exists, layout/language-agnostic.
- eslint: ignore examples/ and the gitignored cate-extensions/ checkout (their own JS/TS projects), plus generated dist-runtime/ and local .cate/ worktrees, so lint only covers app source. This was the ubuntu CI lint failure (examples/ sample extensions tripping no-undef). - ci.yml: run the catalog checkout + build only on non-Windows. The catalog repo's bash build.sh resolves a manifest path that breaks under Git-Bash/MSYS on Windows; the extension tests skipIf the catalog is absent, so the Windows leg stays green.
Add cate.agent.* so an enabled extension can run one agent turn through the bundled pi. Gated by a dedicated `agent` scope, first-use user consent, and one run per extension at a time. The run is an owner-bound, visible agent session that resolves with the final assistant text (on pi's terminal agent_end). Reachable from both server-backed extensions (CATE_API) and frontend panels (cateHost bridge). Also lands the production-readiness fixes from the review: manifest scope enforcement, sender-derived guest identity, workspace path confinement, verified and traversal-safe artifact extraction, and quit/crash process hygiene.
…missions Remove documentation for cate.* methods that aren't implemented yet (workspace/theme.onChange, panel lifecycle + setBadge, editor getters, the commands namespace, and canvas methods beyond createPanel). They return 'unsupported' today; re-document if/when implemented. Settings: list each extension's declared cateApi scopes as readable permission chips (catalog + sideload rows), with the `agent` scope highlighted as the most sensitive.
Replace the one-shot cate.agent.run with a turn-based session API: open() returns a handle (pi's session file, so a conversation resumes with no Cate-side state), send() runs one turn and returns the full assistant message, dispose() tears down the live client. run() stays as open->send->dispose sugar. Drives the same create()/PiRpcClient/dispose() path a panel uses, so pi owns all conversation state and Cate only holds the live handle. One live session per extension, one turn in flight, the anti-runaway guard. Also surface failed turns: a turn that ends on stopReason error (an unsupported model, auth, bad request) now rejects with pi's reason instead of returning silent empty text, and the handler passes that reason to the extension. This was the cause of the persistent "(no text)".
… API
kitchensinkPanel.test.tsx runs the real shipped panel script in jsdom against
a mock cate bridge (mirrors frontendkitPanel) and drives the full surface,
including the agent flow: open-on-first-send, handle persisted to storage,
resume from a stored handle, error rendering, and dispose-on-end.
cateHost.test.tsx locks the preload wire contract: each cate.agent.* call maps
to the right { method, args } and guest identity on CATE_HOST_INVOKE. This was
the one untested layer between an extension calling cate.* and dispatch.
The real extensions live in the separate cate-extensions repo, not in-tree.
A canvas node persisted in `.cate` with a missing or invalid `size`/`origin` (corrupt, half-written, or older-schema data) was seeded straight into the store, so CanvasNode/useNodeResize crashed the whole canvas with an opaque "Cannot read properties of undefined (reading 'width')". loadWorkspaceCanvas now sanitizes loaded geometry: repair origin/size/counters where safe, drop the unrecoverable (no panelId), guard viewport/zoom, and log what changed. The next save persists the repaired state, healing the file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the extension system end to end: extensions add panels to Cate via a web frontend and an optional local server, served through a token-injecting proxy.
What's in it
src/runtime/capabilities/{server,tunnel}.ts)ExtensionManager,ExtensionServerManager, proxy server, catalog download/install, and thecateHostreverse-API dispatch + per-extension storagecateHostbridge injected into extension webview guestsExtensionPanel,ExtensionsSettings,useCateHostActionRespondercate-hostAPI typings, IPC channelsdocs/extensions.mdcate-extensions
The extension catalog is its own repo (
0-AI-UG/cate-extensions). It's gitignored here and only checked out locally for offline dev/tests. The two suites that use it (distribution.test.ts,kitchensinkServer.test.ts) skip when that checkout is absent. The Kitchen Sink demo's TS conversion is in 0-AI-UG/cate-extensions#1.Tests
typecheckclean; extension + runtime-capabilities suites green.