-
Notifications
You must be signed in to change notification settings - Fork 7
feat: Add kref-presence for E() on vat objects #754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: rekm/caplet-implementation
Are you sure you want to change the base?
Conversation
| } | ||
| } | ||
| return arg; // Pass primitive through | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nested presences not converted to kref strings in args
Medium Severity
The sendToKernel function only converts top-level presence objects to kref strings, not presences nested within objects or arrays. When calling E(presence).method({ nested: anotherPresence }), the nested presence won't be converted to its kref string before being passed to CapTP. This creates an asymmetry with convertKrefsToStandins on the kernel side, which does recursively convert nested kref strings. The nested presence may be incorrectly serialized by CapTP since it doesn't know about presences created by the presence manager.
451a6dd to
605f8d9
Compare
8b56b6b to
565d843
Compare
605f8d9 to
f08383c
Compare
565d843 to
544344e
Compare
f08383c to
34a1f08
Compare
544344e to
bad09bc
Compare
34a1f08 to
4caf528
Compare
88b8378 to
c7dd594
Compare
Answers @kumavis's challenge of "What're you afraid of CapTP or something?" by replacing our kernel JSON-RPC API with `E()` on a facet of the kernel. This makes it easy to expose as much of the kernel API as we want via eventual send, and allows us to benefit from pipelining internally. In addition, it facilitates the removal of the command stream and the related RPC API logic. Finally, a number of rationalizations are applied to the extension and omnium. This PR is part of a stack followed by: #752, #753, and #754 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces CapTP-based communication and removes the JSON-RPC command stream. > > - Add CapTP utilities in `kernel-browser-runtime`: `makeBackgroundCapTP`, `makeKernelCapTP`, `makeKernelFacade`, and JSON-RPC `captp` notification helpers; export new `KernelFacade` and `CapTPMessage` types > - Update `kernel-worker` to use CapTP for background↔kernel messaging; initialize kernel without a command stream; route internal RPC only for panel/internal comms > - Refactor `@MetaMask/ocap-kernel` to drop command stream handling and kernel RPC entrypoints; `Kernel.make` now accepts only platform services and the database; adjust `stop()` accordingly > - Migrate extension and omnium backgrounds/offscreens to CapTP over `ChromeRuntimeDuplexStream`, use global `E` and `kernel`/`omnium` helpers; remove `env/dev-console` and background trusted prelude files; add TS globals > - Add unit and integration tests for CapTP (`background-captp`, kernel-side CapTP, and E() end-to-end); introduce `vitest.integration.config.ts` and `test:integration` scripts; CI gains an "Integration Tests" job > - Update deps (add `@endo/captp`, `@endo/eventual-send`), tsconfigs, build constants, and minor coverage thresholds > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit cbf22fd. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Implement Phase 1.2 of the omnium plan - Define Caplet Structure: - Add modular controller architecture with POLA attenuation via makeFacet() - Add storage abstraction layer (StorageAdapter, NamespacedStorage) - Add Chrome storage adapter for platform storage - Add CapletController for managing installed caplets - Add Caplet types with superstruct validation - Wire CapletController into background.ts and expose on globalThis.omnium.caplet - Add comprehensive unit tests for all controller code - Update PLAN.md to reflect implementation
Consolidate CapletControllerState from multiple top-level keys (installed, manifests, subclusters, installedAt) into a single `caplets: Record<CapletId, InstalledCaplet>` structure. Changes: - Add ControllerStorage abstraction using Immer for state management - Controllers work with typed state object instead of storage keys - Only modified top-level keys are persisted (via Immer patches) - Remove state corruption checks (no longer possible with atomic storage) - Fix makeFacet type - use string | symbol instead of keyof MethodGuard - Update PLAN.md to reflect new storage architecture 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add abstract Controller class with state management via ControllerStorage - Convert CapletController to extend Controller base class - Use makeFacet() pattern for returning hardened exo methods - Add base-controller tests (12 tests) - Add semver deep import type declaration - Add storage permission to manifest.json Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Convert ControllerStorage from factory to class with static make() method - Implement synchronous update() with debounced fire-and-forget persistence - Fix critical debounce bug: accumulate modified keys across debounce window - Implement bounded latency (timer not reset, max delay = one debounce interval) - Add immediate writes when idle > debounceMs for better responsiveness - Add clear() and clearState() methods to reset storage to defaults - Remove old namespaced-storage implementation - Refactor all tests to use actual ControllerStorage with mock adapters - Add shared makeMockStorageAdapter() utility in test/utils.ts - Update controllers to create their own storage from adapters Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove strict reverse DNS format requirement for CapletId to allow more flexibility during early development. Now accepts any non-empty ASCII string without whitespace, removing restrictions on hyphens, underscores, uppercase, and segment count. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements Phase 1a of the caplet system, establishing the foundational architecture for caplet vats with a working echo-caplet example. This validates the caplet vat contract and installation lifecycle before tackling service injection complexity. Changes: - Add comprehensive caplet vat contract documentation - Create echo-caplet.js demonstrating buildRootObject pattern - Add bundle build script using @endo/bundle-source - Implement caplet integration tests (8 new tests, all passing) - Create test fixtures for caplet manifests - Refactor makeMockStorageAdapter to support shared storage - Add plan in .claude/plans for follow-up work Key achievements: - Caplet vat contract fully documented with examples - Echo-caplet bundles successfully (696KB) - Install/uninstall lifecycle tested and working - Service lookup by name validated - State persistence across controller restarts verified - 100% code coverage for CapletController maintained Deferred to future work (Phase 1b): - Kref capture mechanism - Service parameter injection - Consumer caplet implementation - Two-caplet communication Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements Phase 1b functionality to store caplet root kernel references (krefs) and expose them via omnium.caplet.getCapletRoot(). This enables: omnium.caplet.install(manifest), omnium.caplet.getCapletRoot(capletId), and E(presence).method() for calling vat methods from background console. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add explicit type annotation for kernelP and use spread operator for optional rootKref field. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove KrefWrapper type from kernel-browser-runtime types - Make rootKref a required string field in LaunchResult (not optional) - Make rootKref required in InstalledCaplet and omnium LaunchResult - Add assertions in kernel-facade for capData, subclusterId, and rootKref - Remove isKrefWrapper function (inline check kept in makeKrefTables) - Update tests to use simplified types and improved mocks Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tests for validation errors in kernel-facade launchSubcluster: - Throws when kernel returns no capData - Throws when capData body has no subclusterId - Throws when capData slots is empty (no root kref) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add omnium.manifests.echo so users can install caplets from the console: await omnium.caplet.install(omnium.manifests.echo) Changes: - Create src/manifests.ts with echo caplet manifest using chrome.runtime.getURL - Add echo-caplet.bundle to vite static copy targets - Expose manifests in background.ts via omnium.manifests - Update global.d.ts with manifests type and missing getCapletRoot Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add omnium.loadCaplet(id) to dynamically fetch caplet manifest and bundle - Fix vatPowers.logger missing in browser vats (iframe.ts) - Fix SubclusterLaunchResult to return bootstrapRootKref directly instead of trying to extract it from bootstrap() return slots The bootstrapRootKref is the kref of the vat root object, which is already known when the vat launches. Previously we incorrectly tried to get it from the slots of the bootstrap() method return value. Next step: Wire up CapTP marshalling so E(root).echo() works with the caplet root presence. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use nullable() instead of optional() for bootstrapResult field, and define a JSON-compatible LaunchSubclusterRpcResult type that uses null instead of undefined for JSON serialization. Also update tests to match the new behavior. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Set globalThis.kernel in the extension and omnium to the kernel itself. Remove ping and getKernel methods from background console interface. The kernel exposes ping().
…ects Implement slot translation pattern to enable E() (eventual sends) on vat objects from the extension background. This creates presences from kernel krefs that forward method calls to kernel.queueMessage() via the existing CapTP connection. Key changes: - Add background-kref.ts with makeBackgroundKref() factory - Add node-endoify.js to kernel-shims for Node.js environments - Update kernel-facade to convert kref strings to standins - Fix launch-subcluster RPC result to use null for JSON compatibility - Integrate resolveKref/krefOf into omnium background The new approach uses @endo/marshal with smallcaps format (matching the kernel) rather than trying to hook into CapTP internal marshalling, which uses incompatible capdata format. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ntegration Split the vitest configuration into two separate files to fix issues with tests running from the repo root: - vitest.config.ts: Unit tests with mock-endoify - vitest.integration.config.ts: Integration tests with node-endoify Add test:integration script to run integration tests separately. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…helpers - Remove packages/nodejs/src/env/endoify.ts re-export, use @metamask/kernel-shims/node-endoify directly - Update vitest configs to use kernel-shims for setup files - Remove inline endoify imports from test files (now handled by vitest setup) - Fix test helpers to handle SubclusterLaunchResult return type from launchSubcluster() - Add kernel-shims dependency to kernel-test and nodejs-test-workers packages - Set coverage thresholds to 0 temporarily Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…e configs - Fix accidentally broken nodejs vat worker (which broke all tests relying on it) - Rename node-endoify.js to endoify-node.js for consistency - Update package.json export from ./node-endoify to ./endoify-node - Update all vitest configs to use the new export path - Update depcheckrc.yml ignore pattern Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Import and initialize makeBackgroundKref to enable E() calls on vat objects - Expose captp.resolveKref and captp.krefOf on globalThis for console access - Refactor startDefaultSubcluster to return the bootstrap vat rootKref - Add greetBootstrapVat function that automatically calls hello() on the bootstrap vat after subcluster launch on startup - Update global.d.ts with captp type declaration for IDE support Co-Authored-By: Claude <noreply@anthropic.com>
- Rename background-kref.ts to kref-presence.ts - Rename makeBackgroundKref to makePresenceManager - Rename BackgroundKref type to PresenceManager - Rename BackgroundKrefOptions to PresenceManagerOptions - Update all imports and references across affected packages - Update JSDoc comments to reflect new naming - All tests pass for kernel-browser-runtime, extension, omnium-gatherum Co-Authored-By: Claude <noreply@anthropic.com>
…nvertKrefsToStandins - Move convertKrefsToStandins from kernel-facade.ts to kref-presence.ts for better organization - Export convertKrefsToStandins for use by kernel-facade - Add comprehensive unit tests for convertKrefsToStandins (20 tests covering kref conversion, arrays, objects, primitives) - Add unit tests for makePresenceManager (3 tests for kref resolution and memoization) - Add integration test in kernel-facade.test.ts verifying kref conversion in queueMessage Co-Authored-By: Claude <noreply@anthropic.com>
9ab3158 to
84ed1b2
Compare
c7dd594 to
cbae7f9
Compare
84ed1b2 to
675ff3e
Compare
Part 4 of 4 in PR stack
Depends on: #753
Note
Enables E()-style calls on vat objects and improves test/runtime setup across packages.
kref-presenceutilities: newmakePresenceManagerandconvertKrefsToStandins; exported from@metamask/kernel-browser-runtime; unit and integration tests addedglobalThis.kernelto a promise, attaches CapTPPresenceManageronglobalThis.captp/omnium(exposesresolveKref/krefOf), pings kernel on action, and greets bootstrap vat after launching default subclusterqueueMessageconverts kref strings to standins;launchSubclusterhandler returns JSON-compatible result with nullablebootstrapResult; tests updated@metamask/kernel-shims/endoify-node(optional@libp2p/webrtcpeer) and packages/tests switched to it; remove old local endoify importstest:integrationscript; GitHub Actions runs build + integrationWritten by Cursor Bugbot for commit 8b56b6b. This will update automatically on new commits. Configure here.