feat(page)!: page-as-extension direct rewrite - dispatcher, 38 client-bodied verbs, catalog-derived CLI (#269) - #284
Merged
Conversation
omridevk
added a commit
that referenced
this pull request
Aug 6, 2026
Its mutating tool call now round-trips through callToolApproved (dce879f), pushing it near the 60s vitest default on loaded CI runners (PR #275 shard-4, PR #284 shard-4). Bump only this test to 120000ms; fixture size and other tests are untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
omridevk
added a commit
that referenced
this pull request
Aug 7, 2026
…242) (#268) * feat(extensions): whiteboard tools declare through the tool registry (#242) All twenty-two whiteboard defs gain outputSchema, catalog meta with honest per-tool mutating flags, and declared errors where a real failure mode exists (INVALID_SVG, DIAGRAM_TOO_LARGE, EXPORT_TIMEOUT, COMMIT_TIMEOUT, COMMENT_NOT_FOUND, PIN_NOT_FOUND), so they auto-register into the one tool registry at mount and appear in catalog.list() with real summaries under the whiteboard category. Server handlers throw those codes as toolError instead of bare Error, a new IT proves the catalog carries every declaration with its mutating flag, and AGENTS.md records the standing rule that the whiteboard suite is CI-only, never run locally. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(extensions): approve mutating whiteboard tool calls in tests and honest anchor output schema The registry move flagged thirteen whiteboard tools mutating, which routes their code-mode calls through the permission gate (gatedToolRun awaits gate.decide, ASK_TIMEOUT_MS 120s). The ITs still called them through the non-approving caller, so every first mutating call hung past the 60s test timeout on CI shard-5. Mutating calls now go through callToolApproved, matching the tanstack precedent. anchor.resolve's catalog output schema stops promising anchor/candidates/diff on every status (the handler returns bare {status:'orphaned'} for an unparseable anchor), and the catalog IT's declared-errors oracle now covers every declared code, so dropping or misspelling DIAGRAM_TOO_LARGE, EXPORT_TIMEOUT, COMMIT_TIMEOUT, COMMENT_NOT_FOUND or PIN_NOT_FOUND fails the suite. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(whiteboard): raise timeout on the many-subpath svg capping test Its mutating tool call now round-trips through callToolApproved (dce879f), pushing it near the 60s vitest default on loaded CI runners (PR #275 shard-4, PR #284 shard-4). Bump only this test to 120000ms; fixture size and other tests are untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(whiteboard): strengthen the tool-catalog IT oracle to set-equality and real output shapes Set-equality on catalog names (a 23rd tool that skips declaration now fails instead of silently passing), per-tool exact declared-error sets (extras and missing both fail; the other 11 tools assert zero errors), a per-tool output JSON-schema shape table derived from each def.ts outputSchema (catches catalog drift instead of one substring check on canvas.svg), and one executable error-path case (comment.read on a nonexistent cid surfaces COMMENT_NOT_FOUND through the real code-mode call path). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…re, extension-page verbs, CLI catalog derivation Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tension-page browser suite, bootConnect embed IT Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ibuted failures Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d never crosses the wire, CLI honors declared positionals and fails structurally offline Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… drift guard, honest narrow inputs, dom stale refs, verb behavior coverage Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…actories The page and tanstack extensions declare tools through local factories (pageTool, verbTool) whose defineTool name is a template literal, so the hardened guard harvested nothing from them. The harvest now detects such a factory from the source itself (prefix read from the template, spec field from the interpolation) and harvests its call sites. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
omridevk
force-pushed
the
page-chain-269
branch
from
August 7, 2026 07:26
afeb2a4 to
37f92cc
Compare
Closed
8 tasks
Merged
This was referenced Aug 8, 2026
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.
Stacked on #275 -> #268; retarget after they merge.
The page-as-extension DIRECT rewrite chain (#255 epic): page stops being a special case. Every page verb is a
defineTool().client(body)declaration in@conciv/extension-page, dispatched by name through the registry over one wire, gated through the samedecide()path as every extension.Scope map
Dispatcher, final form —
packages/page/src/page-tool-dispatcher.ts: instance-scoped name ->__clientExecutelookup off client tools passed as an argument tomakeDomPageDriver/startPagePlane; per-callClientToolCtx(document, lazytarget(locator)with mirror-on-resolve per declaration meta, non-throwingresolve,addRef/resetRefs, console reader); zero module-level state.page-driver.tsis dispatcher-only;DOM_HANDLERS/page-handlers.tsare gone.Final wire —
PageQuerySchemais{requestId, name, input}(protocolpage-types.ts); no kind enum, no field-bag, no legacy union. The bus timeout budget peeksinput.timeout.All 38 verbs — 37 declarations in
packages/extensions/page/src/shared/defs.ts, browser bodies insrc/client/bodies.tscalling@conciv/pageprimitives (react bridge, snapshot/refs, dehydrate, render tracker stay put).effectcarries as the documented stub, catalog-honest. The 38th (ext) died with the vocabulary.locateis server-wraps-client (P6): the client body returns raw frames, the server half (src/server.ts) symbolicates viasymbolicateFramesthreaded into mount deps. Core always mounts the page server extension; the embed always prepends the page client extension, so every host keeps page capability with no per-host wiring.One registration ratchet —
isRegistryDeclaredcovers client-bodied tools (binding + meta/outputSchema); registration reads mount SURVIVORS (createInstancesdrops a throwing__client(); the driver collects tools offrouter.options.context.instances). The spike'sregisterExtensionClientToolsshape is unified intoregisterExtensionTools.Vocabulary deleted —
PAGE_QUERY_KINDS,PageQueryInputSchema,MUTATING_KINDS/MIRROR_KINDS+ helpers,page.run(rpc + contract),extkind,PageVerbMap/definePageVerbs/page-verb-registry.ts/bindExtensionPageVerbs,scopedPageCaller,BUILTIN_PAGE_TOOLS. Widget action cards and running titles read labels/icons from the declaration metadata (@conciv/extension-page/defs); mutating/mirror/journal are meta-driven everywhere (journal entries now carry full tool names, e.g.page.fill).CLI re-derives (P3) —
rpc.registry.catalog(signatures incl. JSON-schema inputs) +rpc.registry.callreplacerpc.page.run;conciv tools page/conciv tools reactbuild their command trees at runtime from the catalog (packages/cli/src/page.ts,wireToolCommand).decide() on every surface — chat:
conciv_pagecalls with a mutating verb (per registry meta) prompt through the run gate; code-mode: page tools are registry capabilities, already gated bygatedToolRun; CLI: the blanketconciv tools*Bash allow is gone, replaced by catalog-derived read-only allows, so a mutating CLI page command surfaces the Approve/Deny card.TanStack (P8) — the 14
pageVerbsare.client()tools (tanstack.detect...tanstack.back,src/shared/verb-defs.tswith real zod result schemas mirroringframework-types); the framework adapter reaches its own browser tools throughserver.tools.call(registry threaded into mount deps);callPageVerb/PageCallerdied.ServerApinow carriespage.call(raw browser ask),tools.call(registry), andsymbolicate.conciv_open (noted in #275's report): verified NOT redundant as a surface — it is the chat-facing tool the system prompts name, while registry
openserves code-mode/rpc. The duplicate execution path IS gone:conciv_opennow executes throughregistry.call('open', ...).Grep proofs (all zero)
Verification
turbo run typecheck build --filter='!@conciv/extension-whiteboard'— 107/107 greenturbo run test --concurrency=1(VITEST_MAX_FORKS=1, whiteboard excluded per repo rule) — green; bootNormal (page-plane.it) AND bootConnect (page-dispatch-boot.it) ITs green against the prebuilt embed; the moved page behavior suite runs inpackages/extensions/page/testin a real browser; whiteboard verifies in CIpnpm lint,pnpm format:check— greenfallow audit --changed-since origin/registry-cleanup-232— verdict pass, zero INTRODUCEDCloses #269
🤖 Generated with Claude Code