Replaces orchestrator-sub-agent.ts's Phase 1 stub (which only
logged and errored on `<op_tool>` output) with a real apply path:
- element-tools-dispatcher.ts: dispatchElementToolCall(shape, ctx)
runs the full pass inside one startBatch/endBatch pair so a
generation collapses to a single undo entry. Routes element-tool
calls through the shim registry; falls back to /api/mcp/exec-tool
HTTP when shim misses. Validates parent_id existence, rejects
filePath unless it is the "live://canvas" sentinel, rejects
pageId that diverges from the active page, rejects stale
defaultParentId — all with structured failure messages instead
of silent drops with "applied" reports.
- element-tool-shims/: 10-tool registry backed by pen-core
element-builders. wrap<T>() strips parent_id/pageId/filePath
before invoking the builder and surfaces them on ElementShimResult
so the dispatcher can honor them during insert. Same pen-core
builders the server-side pen-mcp handler uses — drift impossible.
- orchestrator-sub-agent.ts: invokes dispatcher with
defaultParentId = subtask.parentFrameId ?? plan.rootFrame.id,
mirroring StreamingDesignRenderer's construction so rootless
payloads land inside the generation's target frame. DispatchResult
carries insertedNodes[] and the orchestrator uses them to update
progressEntry.nodeCount / progress.totalNodes / onApplyPartial
so a successful element-tool subtask does not look like a failure
to upstream accounting.
- Dispatcher uses insertStreamingNode (not raw addNode) so element
tool output goes through the same canonical path the streaming
renderer uses: id collision guard, parent remap, layout-aware
child normalization, phone-placeholder guards, append semantics,
and auto expandRootFrameHeight.
13 tests lock invariants: batch wrap fires exactly once per
dispatch (including back-to-back), applied/failed/unsupported
return shapes, parent_id / pageId / filePath / defaultParentId
validation branches, shim-hit success, HTTP fallback path under
fetch failure, "stale default + valid payload parent_id" payload-wins
precedence.