-
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: main
Are you sure you want to change the base?
Conversation
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>
9ab3158 to
84ed1b2
Compare
c7dd594 to
cbae7f9
Compare
84ed1b2 to
675ff3e
Compare
e0d8b07 to
bc6e395
Compare
Adds an actual caplet implementation, the echo caplet, and enables installing it and retrieving a reference to its root object from the extension's background console. The returned object is not actually a usable presence, but we implement this in #754. In detail: - Adds echo caplet - Store and retrieve caplet root krefs from the kernel API - Add caplet manifest loading and installation - Return subcluster id, root kref, and bootstrap result from `launchSubcluster()` - Add `omnium.caplet.load()` for dynamic caplet loading **Part 3 of 4 in PR stack** Depends on: #752 Followed by: #754 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Introduces caplet plumbing and updates kernel launch semantics to return identifiers needed to reference caplet roots. > > - **Kernel API**: `launchSubcluster()` now returns `SubclusterLaunchResult` `{ subclusterId, bootstrapRootKref, bootstrapResult }`; `SubclusterManager` and `Kernel` updated; types exported > - **Kernel browser facade/CapTP**: facade `launchSubcluster` now returns `{ subclusterId, rootKref }`; added `getVatRoot(krefString)`; CapTP/RPC handler/spec updated to return structured result and normalize `bootstrapResult` undefined→null > - **Omnium (extension)**: added **Echo caplet** (bundle + manifest) and static copy in build; background exposes `omnium.caplet.load()`; CapletController now stores `rootKref`, supports `getCapletRoot()`, and uses kernel facade `launchSubcluster`/`getVatRoot`; integration tests added > - **Tests/fixtures**: updated across kernel, browser-runtime, node helpers, and persistence/tests to consume new launch result and root krefs > - **Tooling**: ESLint allows caplet JS under `src/**/caplets`; build script bundles caplets > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit bc6e395. 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>
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>
b95fd28 to
657dc09
Compare
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
…kref strings Previously, sendToKernel only converted top-level presence objects in arguments to kref strings, leaving nested presences unhandled. This created an asymmetry with convertKrefsToStandins, which recursively converts kref strings on the kernel side. Add convertPresencesToKrefs function that recursively converts presences to kref strings, mirroring the behavior of convertKrefsToStandins. Use it in sendToKernel to handle nested presences in objects and arrays. Add comprehensive unit tests covering: - Top-level presence conversion - Nested presences in objects - Presences in arrays - Deeply nested presences - Mixed primitive and presence arguments Co-Authored-By: Claude <noreply@anthropic.com>
This adds a comprehensive e2e test demonstrating third-party capability handoff in the nodejs package using external E() calls on vat root objects. Key additions: - Three test vats (alice-vat, bob-vat, carol-vat) that demonstrate handoff - Test cases for both vat-internal and external orchestration patterns - KernelFacadeAdapter that wraps the local kernel for use with PresenceManager - Exports of PresenceManager from nodejs package Fixes: - Updated sendToKernel in kref-presence to convert presence arguments to standin objects (via kslot) which the kernel's queueMessage expects - Updated corresponding unit tests to expect standins instead of strings - Added LaunchResult export from kernel-browser-runtime Co-Authored-By: Claude <noreply@anthropic.com>
…o-standin conversions Simplify the serialization flow in sendToKernel by combining the two-step conversion (presence → kref string → standin) into a single step that goes directly from presence → standin using kslot(). This reduces unnecessary intermediate string conversions while maintaining the same behavior. The presenceToKref WeakMap lookup is now used directly with kslot() to create standins. Also update test descriptions to accurately reflect the new behavior. Co-Authored-By: Claude <noreply@anthropic.com>
Move kref-presence.ts and its tests from kernel-browser-runtime to ocap-kernel as the module is not browser-specific and is used across nodejs, extension, and omnium-gatherum packages. - Move kref-presence.ts to ocap-kernel/src/ - Move kref-presence.test.ts to ocap-kernel/src/ - Add KernelLike type for platform-agnostic kernel interface - Export makePresenceManager and convertKrefsToStandins from ocap-kernel - Update all imports across codebase to use @MetaMask/ocap-kernel - Remove @metamask/kernel-browser-runtime from nodejs dependencies - Re-export from nodejs for backward compatibility - Remove kref-presence exports from kernel-browser-runtime - Remove makePresenceManager from kernel-browser-runtime exports test Co-Authored-By: Claude <noreply@anthropic.com>
|
@cursor review |
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.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
| if (typeof value === 'object' && value !== null) { | ||
| const kref = presenceToKref.get(value); | ||
| if (kref !== undefined) { | ||
| return kslot(kref); |
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.
Presence standins don't survive CapTP serialization correctly
High Severity
The convertPresencesToStandins function returns kslot(kref) (a remotable object) instead of the kref string. When these standins are passed through CapTP via E(kernel).queueMessage(), they become CapTP presences on the kernel worker side. The kernel's kser() function then tries to call krefOf() on these CapTP presences, which synchronously accesses getKref() - but CapTP presences don't have local methods. This causes serialization to fail in production when the presence manager is used with a remote kernel through CapTP.
Part 4 of 4 in PR stack
Depends on: #753
Note
Introduces a host-side presence layer and Node.js endoify to support clean E()-style calls to vat objects across process boundaries, and wires it through the extension and tools.
kref-presence.tswithmakePresenceManager,convertKrefsToStandins, and exports from@metamask/ocap-kernel; comprehensive unit testsqueueMessage; exportLaunchResult; adjust tests accordinglyglobalThis.kernel(promise), attachcaptppresence manager (resolveKref,krefOf), greet bootstrap vat via presence; update globals/types and e2e tests@metamask/kernel-shims/endoify-node(imports@libp2p/webrtcpre-lockdown); migrate Node workers/tests/configs to use it and remove legacy endoify importsWritten by Cursor Bugbot for commit e28f868. This will update automatically on new commits. Configure here.