feat(plasmic-mcp): hostless component reachability fix + screenshot renderer + test coverage#170
Merged
Conversation
…rior specs Clear completed specs (ep-studio-lockdown, websocket-live-sync, websocket-presence) and reset IMPLEMENTATION_PLAN.md for the new task. Add spec for fixing hostless package component reachability bugs (gaps #26, #29) that block node.add, update-props, and slot children on hostless components. Update PROMPT_plan.md to be generic.
…f + dependency address verification (#170) Addresses the P0 blocker where node.add and node.update-props targeting hostless package components could trigger "Unreachable instance" errors from FastBundler.assertFastBundleInvariants(). The root cause: when dependency instances (Component, PropParam) are missing from the bundler's _uid2addr map, mkRefAndMaybeVisit() creates addresses with the project UUID instead of the dependency package UUID, causing __ref instead of __xref classification. Three-part fix (all within packages/plasmic-mcp/, zero upstream changes): 1. bundler-helpers.ts (NEW): ensureDependencyAddresses() walks new Tpl trees after studioElementSchemaToTpl() and verifies all dependency instance references have correct bundler addresses. makeIsExternalRef() creates a callback matching Studio's StudioCtx pattern. 2. change-tracker.ts: ChangeRecorder now receives isExternalRef callback (auto-detected from session), telling it to skip deep MobX observation of dependency package instances. This matches Studio's behavior and prevents wasteful observation of the entire dependency tree. 3. edit-tools.ts: plasmicElementToTpl() calls ensureDependencyAddresses() after creating Tpl trees, logging warnings if any dependency instances lack proper bundler registration. Also adds _uid2addr and _addr2inst to the FastBundler type declarations (they are intentionally public in upstream source). 23 new tests covering: address verification for Components/Params/Slots, nested hostless components in slots, cross-package references, isExternalRef classification, ChangeTracker integration. All 1,911 tests pass. Zero regressions.
…s Playwright rendering Add headless canvas screenshot capture that navigates to the dev host's PlasmicCanvasHost page in headless Chromium, converts the component's TreeNode JSON to React elements using the dev host's own React instance (window.__Sub), and calls setPlasmicRootNode() to render. Code components registered in the dev host are resolved from __PlasmicComponentRegistry. New files: - headless-canvas.ts: Playwright orchestration (~200 lines) - __tests__/headless-canvas.test.ts: 32 unit tests Modified: - server.ts: capture-screenshot wired into inspect tool (11 actions now) - IMPLEMENTATION_PLAN.md: Item 2 marked complete, counts updated
…s 7 modules Add 35 new tests covering critical gaps in the rebase engine, undo manager, change tracker, update queue, batch manager, and cross-module integration: - rebase-engine: undoChangesAndResolveConflicts return value usage (3 tests), dep pkg unbundle failure handling and continuation (2 tests) - undo-manager: concurrent undo during save (2 tests), CRITICAL log on rollback failure (1 test), getStack/replaceStack rebase API (3 tests) - change-tracker: getRecorder identity (3 tests), withRecording error propagation (1 test), isExternalRef session integration (2 tests) - update-queue: enqueue+stop race condition (1 test), isProcessing flag (3 tests), handler error + concurrent enqueue (1 test) - batch-manager: rollback failure during endBatch with CRITICAL log (1 test), replaceAccumulatedChanges for rebase (3 tests), sequential batch independence (2 tests) - cross-module-integration (new file): rebase+undo stack rebuild (1 test), rebase+batch replace (1 test), rebase+undo+batch ordering (1 test), UpdateQueue+save gating (1 test), self-update echo filtering (1 test), batch→save→undo flow (1 test), session state during rebase (1 test) All 1,955 unit tests pass. TypeScript compiles clean.
field123
added a commit
that referenced
this pull request
Mar 7, 2026
…lidation (#171) * chore(ralph): add hostless component reachability spec and clean up prior specs Clear completed specs (ep-studio-lockdown, websocket-live-sync, websocket-presence) and reset IMPLEMENTATION_PLAN.md for the new task. Add spec for fixing hostless package component reachability bugs (gaps #26, #29) that block node.add, update-props, and slot children on hostless components. Update PROMPT_plan.md to be generic. * feat(plasmic-mcp): hostless component reachability fix — isExternalRef + dependency address verification (#170) Addresses the P0 blocker where node.add and node.update-props targeting hostless package components could trigger "Unreachable instance" errors from FastBundler.assertFastBundleInvariants(). The root cause: when dependency instances (Component, PropParam) are missing from the bundler's _uid2addr map, mkRefAndMaybeVisit() creates addresses with the project UUID instead of the dependency package UUID, causing __ref instead of __xref classification. Three-part fix (all within packages/plasmic-mcp/, zero upstream changes): 1. bundler-helpers.ts (NEW): ensureDependencyAddresses() walks new Tpl trees after studioElementSchemaToTpl() and verifies all dependency instance references have correct bundler addresses. makeIsExternalRef() creates a callback matching Studio's StudioCtx pattern. 2. change-tracker.ts: ChangeRecorder now receives isExternalRef callback (auto-detected from session), telling it to skip deep MobX observation of dependency package instances. This matches Studio's behavior and prevents wasteful observation of the entire dependency tree. 3. edit-tools.ts: plasmicElementToTpl() calls ensureDependencyAddresses() after creating Tpl trees, logging warnings if any dependency instances lack proper bundler registration. Also adds _uid2addr and _addr2inst to the FastBundler type declarations (they are intentionally public in upstream source). 23 new tests covering: address verification for Components/Params/Slots, nested hostless components in slots, cross-package references, isExternalRef classification, ChangeTracker integration. All 1,911 tests pass. Zero regressions. * feat(plasmic-mcp): add inspect.capture-screenshot action with headless Playwright rendering Add headless canvas screenshot capture that navigates to the dev host's PlasmicCanvasHost page in headless Chromium, converts the component's TreeNode JSON to React elements using the dev host's own React instance (window.__Sub), and calls setPlasmicRootNode() to render. Code components registered in the dev host are resolved from __PlasmicComponentRegistry. New files: - headless-canvas.ts: Playwright orchestration (~200 lines) - __tests__/headless-canvas.test.ts: 32 unit tests Modified: - server.ts: capture-screenshot wired into inspect tool (11 actions now) - IMPLEMENTATION_PLAN.md: Item 2 marked complete, counts updated * test(plasmic-mcp): close WebSocket subsystem test coverage gaps across 7 modules Add 35 new tests covering critical gaps in the rebase engine, undo manager, change tracker, update queue, batch manager, and cross-module integration: - rebase-engine: undoChangesAndResolveConflicts return value usage (3 tests), dep pkg unbundle failure handling and continuation (2 tests) - undo-manager: concurrent undo during save (2 tests), CRITICAL log on rollback failure (1 test), getStack/replaceStack rebase API (3 tests) - change-tracker: getRecorder identity (3 tests), withRecording error propagation (1 test), isExternalRef session integration (2 tests) - update-queue: enqueue+stop race condition (1 test), isProcessing flag (3 tests), handler error + concurrent enqueue (1 test) - batch-manager: rollback failure during endBatch with CRITICAL log (1 test), replaceAccumulatedChanges for rebase (3 tests), sequential batch independence (2 tests) - cross-module-integration (new file): rebase+undo stack rebuild (1 test), rebase+batch replace (1 test), rebase+undo+batch ordering (1 test), UpdateQueue+save gating (1 test), self-update echo filtering (1 test), batch→save→undo flow (1 test), session state during rebase (1 test) All 1,955 unit tests pass. TypeScript compiles clean. * fix(plasmic-mcp): reject partial-parse expressions in validateJsExpression to prevent codegen corruption acorn.parseExpressionAt silently succeeds on partial input (e.g. "expr:$props.imageSrc" parses "expr" as a valid identifier, ignoring the rest). The full post-$ string was then stored as CustomCode, producing invalid JS in codegen output. Now checks that the entire string is consumed by comparing node.end to the input length.
5 tasks
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.
Summary
isExternalRefcallback to ChangeRecorder (matching Studio's StudioCtx behavior) andensureDependencyAddresses()verification for hostless Component/PropParam/SlotParam references. PreventsfastBundle()from misclassifying dependency instances as project-internal, which caused "Unreachable instance" errors onnode.addandnode.update-propsfor hostless package components (gaps _26, _29).inspect.capture-screenshotaction with headless Playwright rendering via dev host iframe. Converts tree-reader JSON to React elements using the dev host's own React instance.All changes contained within
packages/plasmic-mcp/— zero upstream WAB modifications.Test plan