pmx-canvas 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/extensions/pmx-canvas/extension.mjs +3 -1
- package/.github/extensions/pmx-canvas/runtime.json +1 -1
- package/.github/extensions/pmx-canvas/tools.json +688 -128
- package/CHANGELOG.md +69 -0
- package/dist/amp-plugin/pmx-canvas/LICENSE +21 -0
- package/dist/amp-plugin/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
- package/dist/amp-plugin/pmx-canvas/index.js +5445 -0
- package/dist/amp-plugin/pmx-canvas/runtime.json +3 -0
- package/dist/amp-plugin/pmx-canvas/shared-runtime.mjs +194 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/SKILL.md +251 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/evals.json +1086 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/jwt.ts +17 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/login.ts +12 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/middleware.ts +13 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/routes/auth.ts +13 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/investigation-board/src/handlers/users.ts +27 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/mcp.json +36 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/ax-html-control-surface.md +101 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/codex-app-adapter.md +151 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/excalidraw-diagram-authoring.md +150 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/full-reference.md +1785 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/github-copilot-app-adapter.md +223 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/html-primitives.md +139 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/importing-context.md +132 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/installing-pmx-canvas.md +251 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/tours-and-recording.md +111 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/workbench-workflows.md +900 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas-orchestration/SKILL.md +141 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas-testing/SKILL.md +266 -0
- package/dist/amp-plugin/pmx-canvas/start-mcp.mjs +14857 -0
- package/dist/amp-plugin/pmx-canvas/tools.json +10963 -0
- package/dist/canvas/chunks/abnfDiagram-N423BO3Z-cwtsds5d.js +1 -0
- package/dist/canvas/chunks/architecture-TIHT7OUA-x63cwejs.js +1 -0
- package/dist/canvas/chunks/architectureDiagram-T3A2C74G-b4xc9tpz.js +36 -0
- package/dist/canvas/chunks/blockDiagram-VBNYF7ZC-ahp3yxxs.js +132 -0
- package/dist/canvas/chunks/c4Diagram-5PPSVZJV-nappnay7.js +10 -0
- package/dist/canvas/chunks/classDiagram-JCYQIIEL-k1j2xc1t.js +1 -0
- package/dist/canvas/chunks/classDiagram-v2-OCEON4UE-33x08xf2.js +1 -0
- package/dist/canvas/chunks/cose-bilkent-JH36ORCC-a428syda.js +1 -0
- package/dist/canvas/chunks/cynefin-VYW2F7L2-8v6jxfz8.js +1 -0
- package/dist/canvas/chunks/cynefinDiagram-MW4NZA55-nspsqebj.js +62 -0
- package/dist/canvas/chunks/dagre-VZM6K2ZE-8y6177fh.js +4 -0
- package/dist/canvas/chunks/diagram-7IWD3JNH-vym028wn.js +30 -0
- package/dist/canvas/chunks/diagram-B4RE2ZJO-jddqb8sy.js +3 -0
- package/dist/canvas/chunks/diagram-LBJQPF4R-bjwbpkrn.js +24 -0
- package/dist/canvas/chunks/diagram-Q27KOJAE-j6ph6hcx.js +24 -0
- package/dist/canvas/chunks/diagram-UB23O5K3-p09w8jej.js +41 -0
- package/dist/canvas/chunks/ebnfDiagram-BXEA7PRR-j975ycq5.js +1 -0
- package/dist/canvas/chunks/erDiagram-JOGREHBK-sxp6hjn8.js +85 -0
- package/dist/canvas/chunks/eventmodeling-45OFAUF4-xzfgn6xg.js +1 -0
- package/dist/canvas/chunks/flowDiagram-UKHOOZJN-2nsmkskb.js +1 -0
- package/dist/canvas/chunks/ganttDiagram-PKOTCBZU-4tv230y2.js +292 -0
- package/dist/canvas/chunks/gitGraph-TEB2WS4Q-macbhand.js +1 -0
- package/dist/canvas/chunks/gitGraphDiagram-DS77QQ5N-mqgmnw9g.js +106 -0
- package/dist/canvas/chunks/index-037z5dz2.js +232 -0
- package/dist/canvas/chunks/index-081n3har.js +207 -0
- package/dist/canvas/chunks/index-5n03dmb9.js +2 -0
- package/dist/canvas/chunks/index-5tv8v1hk.js +1 -0
- package/dist/canvas/chunks/index-60pgzdqe.js +157 -0
- package/dist/canvas/chunks/index-6ceya556.js +332 -0
- package/dist/canvas/chunks/index-8g1vb57n.js +2 -0
- package/dist/canvas/chunks/index-8rjes9r6.js +2 -0
- package/dist/canvas/chunks/index-9022d1n9.js +16 -0
- package/dist/canvas/chunks/index-9b02042t.js +2 -0
- package/dist/canvas/chunks/index-ap4q4vez.js +2 -0
- package/dist/canvas/chunks/index-dyp2nhd3.js +2 -0
- package/dist/canvas/chunks/index-frvta4tm.js +2 -0
- package/dist/canvas/chunks/index-gf4e0et4.js +2 -0
- package/dist/canvas/chunks/index-h9ycj8n2.js +2 -0
- package/dist/canvas/chunks/index-hj99nz1f.js +1 -0
- package/dist/canvas/chunks/index-mergmj97.js +2 -0
- package/dist/canvas/chunks/index-nwsya6dj.js +301 -0
- package/dist/canvas/chunks/index-nz8qbd1p.js +2 -0
- package/dist/canvas/chunks/index-qhfrazv3.js +2 -0
- package/dist/canvas/chunks/index-v119nznk.js +4 -0
- package/dist/canvas/chunks/index-vpt37m3d.js +89 -0
- package/dist/canvas/chunks/index-y9ma6azy.js +2 -0
- package/dist/canvas/chunks/index-zx0j3a2z.js +179 -0
- package/dist/canvas/chunks/info-DKCQHKI2-a0ykzs9z.js +1 -0
- package/dist/canvas/chunks/infoDiagram-6WML65LV-qv97qq6a.js +2 -0
- package/dist/canvas/chunks/ishikawaDiagram-WSZJBQD7-p9306gh0.js +70 -0
- package/dist/canvas/chunks/journeyDiagram-NVQOT4AX-sv67zats.js +139 -0
- package/dist/canvas/chunks/kanban-definition-27J2QSJJ-k2pfam6p.js +89 -0
- package/dist/canvas/chunks/katex-dmg8k4zm.js +257 -0
- package/dist/canvas/chunks/mermaid.core-83r0fdce.js +12 -0
- package/dist/canvas/chunks/mindmap-definition-FAOFIHXS-vg2newm1.js +96 -0
- package/dist/canvas/chunks/packet-7NZHBO7P-tqnabcdv.js +1 -0
- package/dist/canvas/chunks/pegDiagram-VL7TDLO6-k2h7zc5n.js +1 -0
- package/dist/canvas/chunks/pie-RZYD4A2V-wke6gyhe.js +1 -0
- package/dist/canvas/chunks/pieDiagram-7S7Q4E2Y-hg169p1v.js +39 -0
- package/dist/canvas/chunks/quadrantDiagram-CIZ2JOQS-bxtvsq0b.js +7 -0
- package/dist/canvas/chunks/radar-I7S5WNFK-w7ka0drw.js +1 -0
- package/dist/canvas/chunks/railroad-3IZDKUUU-y3vg318x.js +1 -0
- package/dist/canvas/chunks/railroad-abnf-AHOZXSZD-6hqvcz3c.js +1 -0
- package/dist/canvas/chunks/railroad-ebnf-EBAXGLYW-vcae260m.js +1 -0
- package/dist/canvas/chunks/railroad-peg-LSFZ7HO6-0dbyme23.js +1 -0
- package/dist/canvas/chunks/railroadDiagram-AXF67PYL-njyhcp4p.js +1 -0
- package/dist/canvas/chunks/requirementDiagram-LRYGKXZP-2z6v09gm.js +84 -0
- package/dist/canvas/chunks/sankeyDiagram-W5VNT64P-15mzam0e.js +40 -0
- package/dist/canvas/chunks/sequenceDiagram-SI44F4Z6-rbshyd2c.js +162 -0
- package/dist/canvas/chunks/sizeCapture-X5ZJPWSS-sg26xwts.js +1 -0
- package/dist/canvas/chunks/stateDiagram-OKZ733FA-6eahp98e.js +1 -0
- package/dist/canvas/chunks/stateDiagram-v2-UEYNNEHI-tty0ggn5.js +1 -0
- package/dist/canvas/chunks/swimlanes-SLNWSIFB-ze5db10t.js +1 -0
- package/dist/canvas/chunks/swimlanesDiagram-ULZ7WXOC-thze75gq.js +8 -0
- package/dist/canvas/chunks/timeline-definition-Z64GVDOM-vnp7jyy8.js +120 -0
- package/dist/canvas/chunks/treeView-QDETBFTQ-6ysffnm6.js +1 -0
- package/dist/canvas/chunks/treemap-6X3UGDF4-m3h9p066.js +1 -0
- package/dist/canvas/chunks/vennDiagram-T6HMQDX7-0qrnb7mj.js +34 -0
- package/dist/canvas/chunks/wardley-OPB4EBWU-dp37drwx.js +1 -0
- package/dist/canvas/chunks/wardleyDiagram-T6FBY63Y-8nxg8wqt.js +78 -0
- package/dist/canvas/chunks/xychartDiagram-ELKLHX3M-nj921e7s.js +7 -0
- package/dist/canvas/global.css +483 -230
- package/dist/canvas/index.js +158 -219
- package/dist/canvas/mcp-app.html +4301 -548
- package/dist/canvas/mermaid-entry.js +338 -338
- package/dist/canvas/surface-theme.css +6 -6
- package/dist/json-render/index.css +1 -1
- package/dist/json-render/index.js +49 -49
- package/dist/types/client/canvas/BarHint.d.ts +5 -3
- package/dist/types/client/canvas/BoardMoveDialog.d.ts +2 -0
- package/dist/types/client/canvas/CanvasNode.d.ts +0 -11
- package/dist/types/client/canvas/EdgeEditor.d.ts +19 -0
- package/dist/types/client/canvas/EdgeLayer.d.ts +1 -2
- package/dist/types/client/canvas/GroupNavigation.d.ts +2 -0
- package/dist/types/client/canvas/TextPrompt.d.ts +4 -0
- package/dist/types/client/canvas/auto-fit.d.ts +4 -5
- package/dist/types/client/mermaid-entry.d.ts +1 -2
- package/dist/types/client/mermaid-render.d.ts +1 -0
- package/dist/types/client/nodes/BoardNode.d.ts +1 -1
- package/dist/types/client/nodes/ExtAppFrame.d.ts +7 -90
- package/dist/types/client/nodes/McpAppNode.d.ts +1 -25
- package/dist/types/client/nodes/MermaidNode.d.ts +1 -8
- package/dist/types/client/nodes/PromptNode.d.ts +1 -0
- package/dist/types/client/nodes/ViewerFrame.d.ts +29 -0
- package/dist/types/client/nodes/ViewerHost.d.ts +6 -0
- package/dist/types/client/nodes/WorkCard.d.ts +7 -0
- package/dist/types/client/nodes/iframe-document-url.d.ts +3 -9
- package/dist/types/client/nodes/primitive-copy.d.ts +5 -0
- package/dist/types/client/nodes/use-ax-surface-bridge.d.ts +1 -0
- package/dist/types/client/nodes/use-iframe-content-height.d.ts +1 -1
- package/dist/types/client/nodes/use-surface-frame.d.ts +4 -6
- package/dist/types/client/nodes/viewer-runtime-state.d.ts +2 -1
- package/dist/types/client/state/canvas-store.d.ts +18 -1
- package/dist/types/client/state/human-store.d.ts +2 -0
- package/dist/types/client/state/intent-bridge.d.ts +5 -2
- package/dist/types/client/state/presentation.d.ts +17 -6
- package/dist/types/client/state/relation-store.d.ts +11 -0
- package/dist/types/client/types.d.ts +1 -1
- package/dist/types/json-render/catalog.d.ts +2 -2
- package/dist/types/json-render/server.d.ts +2 -1
- package/dist/types/server/agent-presence.d.ts +1 -0
- package/dist/types/server/ax-interaction.d.ts +1 -0
- package/dist/types/server/ax-state-manager.d.ts +10 -2
- package/dist/types/server/board-local.d.ts +4 -0
- package/dist/types/server/board-move.d.ts +38 -0
- package/dist/types/server/canvas-db.d.ts +12 -2
- package/dist/types/server/canvas-operations.d.ts +5 -6
- package/dist/types/server/canvas-provenance.d.ts +1 -1
- package/dist/types/server/canvas-serialization.d.ts +1 -0
- package/dist/types/server/canvas-state.d.ts +86 -20
- package/dist/types/server/card-relocation.d.ts +6 -0
- package/dist/types/server/context-reads.d.ts +3 -1
- package/dist/types/server/human-presence.d.ts +1 -1
- package/dist/types/server/index.d.ts +26 -10
- package/dist/types/server/intent-registry.d.ts +8 -4
- package/dist/types/server/knowledge-lifecycle.d.ts +4 -2
- package/dist/types/server/mutation-history.d.ts +7 -5
- package/dist/types/server/operations/ops/boards.d.ts +0 -1
- package/dist/types/server/operations/registry.d.ts +2 -0
- package/dist/types/server/tour-control.d.ts +13 -3
- package/dist/types/server/trace-manager.d.ts +1 -0
- package/dist/types/shared/ax-kinds.d.ts +6 -0
- package/dist/types/shared/ax-surface-protocol.d.ts +8 -9
- package/dist/types/shared/human-presence.d.ts +1 -0
- package/dist/types/shared/lifecycle-status.d.ts +2 -0
- package/dist/types/shared/tour.d.ts +8 -0
- package/docs/RELEASE.md +21 -14
- package/docs/agent-plugin.md +16 -2
- package/docs/amp-plugin.md +271 -0
- package/docs/cli.md +42 -3
- package/docs/design/Chrome.dc.html +32 -6
- package/docs/design/GuestName.dc.html +50 -0
- package/docs/design/PluginLogo.svg +7 -0
- package/docs/design/Types1.dc.html +3 -2
- package/docs/design/Types2.dc.html +1 -1
- package/docs/design/Types3.dc.html +1 -1
- package/docs/design/WorkCards.dc.html +39 -0
- package/docs/design/Zoom.dc.html +37 -60
- package/docs/design/canvas.json +17 -1
- package/docs/design/plugin-logo.png +0 -0
- package/docs/design.md +280 -12
- package/docs/evals/agents-md-sections.md +38 -0
- package/docs/http-api.md +179 -11
- package/docs/mcp.md +69 -9
- package/docs/node-types.md +109 -4
- package/docs/plans/plan-009-tech-debt-backlog.md +3 -3
- package/docs/plans/plan-019-post-0.9-roadmap.md +327 -31
- package/docs/plans/plan-020-wave-5-work-planning.md +553 -0
- package/docs/product-vision-2026-09.md +42 -17
- package/docs/sdk.md +18 -0
- package/package.json +7 -4
- package/plugins/pmx-canvas/assets/preview.png +0 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/extension.mjs +3 -1
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/plugin.json +2 -2
- package/plugins/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/tools.json +688 -128
- package/skills/data-analysis/SKILL.md +13 -26
- package/skills/frontend-design/LICENSE.txt +177 -0
- package/skills/frontend-design/SKILL.md +3 -0
- package/skills/pmx-canvas/SKILL.md +232 -849
- package/skills/pmx-canvas/evals/evals.json +26 -3
- package/skills/pmx-canvas/references/full-reference.md +89 -24
- package/skills/pmx-canvas/references/html-primitives.md +7 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
- package/skills/pmx-canvas/references/tours-and-recording.md +29 -2
- package/skills/pmx-canvas/references/workbench-workflows.md +900 -0
- package/skills/pmx-canvas-testing/SKILL.md +7 -5
- package/skills/published-consumer-e2e/SKILL.md +25 -8
- package/skills/published-consumer-e2e/scripts/run-published-consumer-e2e.sh +51 -77
- package/skills/web-artifacts-builder/LICENSE.txt +202 -0
- package/skills/web-artifacts-builder/SKILL.md +6 -0
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +2 -2
- package/src/cli/commands/apps.ts +1 -0
- package/src/cli/commands/boards.ts +30 -0
- package/src/client/App.tsx +20 -4
- package/src/client/canvas/AttentionHistory.tsx +10 -2
- package/src/client/canvas/BarHint.tsx +6 -3
- package/src/client/canvas/BoardMoveDialog.tsx +225 -0
- package/src/client/canvas/CanvasNode.tsx +79 -49
- package/src/client/canvas/CanvasViewport.tsx +42 -14
- package/src/client/canvas/ContextMenu.tsx +97 -15
- package/src/client/canvas/EdgeEditor.tsx +149 -0
- package/src/client/canvas/EdgeLayer.tsx +441 -174
- package/src/client/canvas/ExpandedNodeOverlay.tsx +5 -2
- package/src/client/canvas/GroupNavigation.tsx +85 -0
- package/src/client/canvas/Presentation.tsx +53 -3
- package/src/client/canvas/RelationsPanel.tsx +9 -0
- package/src/client/canvas/SelectionBar.tsx +21 -0
- package/src/client/canvas/SessionPanel.tsx +35 -1
- package/src/client/canvas/TextPrompt.tsx +18 -1
- package/src/client/canvas/TopBar.tsx +54 -9
- package/src/client/canvas/auto-fit.ts +9 -11
- package/src/client/canvas/canvas-area.ts +2 -2
- package/src/client/canvas/use-focus-trap.ts +6 -1
- package/src/client/mermaid-entry.ts +6 -20
- package/src/client/mermaid-render.ts +39 -0
- package/src/client/nodes/AxStepControls.tsx +45 -69
- package/src/client/nodes/BoardNode.tsx +65 -9
- package/src/client/nodes/ContextNode.tsx +88 -396
- package/src/client/nodes/ExtAppFrame.tsx +302 -1465
- package/src/client/nodes/FileNode.tsx +92 -81
- package/src/client/nodes/HtmlNode.tsx +8 -36
- package/src/client/nodes/LedgerNode.tsx +31 -17
- package/src/client/nodes/MarkdownNode.tsx +14 -24
- package/src/client/nodes/McpAppNode.tsx +48 -154
- package/src/client/nodes/MermaidNode.tsx +80 -69
- package/src/client/nodes/PromptNode.tsx +44 -17
- package/src/client/nodes/ResponseNode.tsx +8 -6
- package/src/client/nodes/StatusNode.tsx +34 -7
- package/src/client/nodes/StatusSummary.tsx +16 -3
- package/src/client/nodes/TraceNode.tsx +8 -8
- package/src/client/nodes/ViewerFrame.tsx +273 -0
- package/src/client/nodes/ViewerHost.tsx +41 -0
- package/src/client/nodes/WebpageNode.tsx +22 -24
- package/src/client/nodes/WorkCard.tsx +175 -0
- package/src/client/nodes/iframe-document-url.ts +20 -27
- package/src/client/nodes/primitive-copy.ts +97 -0
- package/src/client/nodes/use-ax-surface-bridge.ts +18 -14
- package/src/client/nodes/use-iframe-content-height.ts +34 -10
- package/src/client/nodes/use-surface-frame.ts +22 -11
- package/src/client/nodes/viewer-runtime-state.ts +41 -35
- package/src/client/state/attention-bridge.ts +5 -0
- package/src/client/state/attention-store.ts +1 -0
- package/src/client/state/canvas-store.ts +202 -26
- package/src/client/state/human-store.ts +22 -2
- package/src/client/state/intent-bridge.ts +20 -5
- package/src/client/state/presentation.ts +135 -15
- package/src/client/state/relation-store.ts +127 -1
- package/src/client/state/sse-bridge.ts +18 -19
- package/src/client/theme/global.css +483 -230
- package/src/client/theme/surface-theme.css +6 -6
- package/src/client/types.ts +1 -0
- package/src/json-render/charts/tufte-components.tsx +44 -2
- package/src/json-render/renderer/index.css +62 -2
- package/src/json-render/renderer/index.tsx +31 -7
- package/src/json-render/server.ts +3 -2
- package/src/mcp/server.ts +13 -3
- package/src/server/agent-presence.ts +43 -23
- package/src/server/ax-flow-loop.ts +6 -0
- package/src/server/ax-gate-ttl.ts +8 -1
- package/src/server/ax-interaction.ts +16 -10
- package/src/server/ax-state-manager.ts +17 -4
- package/src/server/ax-wait.ts +20 -6
- package/src/server/board-export.ts +54 -30
- package/src/server/board-local.ts +20 -0
- package/src/server/board-move.ts +297 -0
- package/src/server/canvas-db.ts +249 -158
- package/src/server/canvas-geometry.ts +1 -0
- package/src/server/canvas-operations.ts +139 -109
- package/src/server/canvas-schema.ts +21 -0
- package/src/server/canvas-serialization.ts +2 -0
- package/src/server/canvas-state.ts +797 -159
- package/src/server/card-relocation.ts +53 -0
- package/src/server/code-graph.ts +4 -3
- package/src/server/context-reads.ts +83 -55
- package/src/server/demo-state.json +140 -114
- package/src/server/file-watcher.ts +30 -10
- package/src/server/html-primitives.ts +3 -9
- package/src/server/html-surface.ts +8 -0
- package/src/server/human-presence.ts +18 -5
- package/src/server/index.ts +54 -24
- package/src/server/intent-registry.ts +43 -5
- package/src/server/knowledge-lifecycle.ts +32 -9
- package/src/server/lifecycle-status.ts +29 -1
- package/src/server/mcp-app-runtime.ts +26 -7
- package/src/server/mutation-history.ts +37 -8
- package/src/server/operations/composites.ts +6 -3
- package/src/server/operations/mcp-contracts.ts +32 -2
- package/src/server/operations/mcp.ts +36 -9
- package/src/server/operations/ops/annotation.ts +22 -1
- package/src/server/operations/ops/ax-await.ts +1 -0
- package/src/server/operations/ops/ax-timeline.ts +28 -2
- package/src/server/operations/ops/batch.ts +25 -11
- package/src/server/operations/ops/boards.ts +45 -6
- package/src/server/operations/ops/nodes.ts +70 -0
- package/src/server/operations/ops/query.ts +32 -3
- package/src/server/operations/ops/snapshots.ts +1 -0
- package/src/server/operations/ops/viewport.ts +11 -9
- package/src/server/operations/registry.ts +49 -4
- package/src/server/server.ts +69 -75
- package/src/server/tour-control.ts +97 -12
- package/src/server/trace-manager.ts +4 -0
- package/src/server/web-artifacts/scripts/init-artifact.sh +2 -2
- package/src/shared/agent-context.ts +7 -1
- package/src/shared/auto-arrange.ts +5 -4
- package/src/shared/ax-kinds.ts +13 -0
- package/src/shared/ax-surface-protocol.ts +20 -9
- package/src/shared/content-height-reporter.ts +4 -3
- package/src/shared/human-presence.ts +1 -0
- package/src/shared/lifecycle-status.ts +2 -0
- package/src/shared/tour.ts +8 -0
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { signal } from '@preact/signals';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
interpolateCamera,
|
|
4
|
+
resolveStop,
|
|
5
|
+
tourStopSchema,
|
|
6
|
+
type TourPresenter,
|
|
7
|
+
type TourStop,
|
|
8
|
+
} from '../../shared/tour.js';
|
|
3
9
|
import { canvasArea } from '../canvas/canvas-area';
|
|
4
10
|
import type { ViewportState } from '../types';
|
|
5
|
-
import {
|
|
11
|
+
import { boardGeneration, catalogEpoch } from './boards-store';
|
|
12
|
+
import { animateCameraPath, cancelViewportAnimation, nodes, viewport } from './canvas-store';
|
|
6
13
|
import { requestBestEffort, requestJson } from './intent-bridge';
|
|
7
14
|
|
|
8
15
|
export const presenting = signal(false);
|
|
9
16
|
export const recordingCamera = signal(false);
|
|
10
17
|
/** Why the current stop cannot be shown (missing target, no stops, server unreachable). */
|
|
11
18
|
export const presentationError = signal('');
|
|
19
|
+
/** Read-only mirror of the server's shared cursor, never advanced optimistically. */
|
|
20
|
+
export const presentationCursor = signal<{ index: number; total: number } | null>(null);
|
|
12
21
|
|
|
13
22
|
export function ownsCamera(): boolean {
|
|
14
23
|
return presenting.value || recordingCamera.value;
|
|
@@ -24,7 +33,21 @@ function prefersReducedMotion(): boolean {
|
|
|
24
33
|
*/
|
|
25
34
|
export function playStop(stop: TourStop, onDone?: (end: ViewportState) => void): void {
|
|
26
35
|
const area = canvasArea();
|
|
27
|
-
|
|
36
|
+
let target: ViewportState;
|
|
37
|
+
if (presenting.value && !recordingCamera.value && !('viewport' in stop.target)) {
|
|
38
|
+
const padding = stop.padding ?? 40;
|
|
39
|
+
const controls = document.querySelector('.presentation-controls')?.getBoundingClientRect();
|
|
40
|
+
const top = Math.max(padding, controls ? controls.bottom - area.top + 12 : 0);
|
|
41
|
+
target = resolveStop(
|
|
42
|
+
{ ...stop, padding: 0 },
|
|
43
|
+
[...nodes.value.values()],
|
|
44
|
+
area.width - 2 * padding,
|
|
45
|
+
area.height - top - padding,
|
|
46
|
+
);
|
|
47
|
+
target = { ...target, x: target.x + padding, y: target.y + top };
|
|
48
|
+
} else {
|
|
49
|
+
target = resolveStop(stop, [...nodes.value.values()], area.width, area.height);
|
|
50
|
+
}
|
|
28
51
|
const from = { ...viewport.value };
|
|
29
52
|
const duration = prefersReducedMotion() ? 0 : (stop.duration ?? 1) * 1000;
|
|
30
53
|
animateCameraPath(
|
|
@@ -35,6 +58,7 @@ export function playStop(stop: TourStop, onDone?: (end: ViewportState) => void):
|
|
|
35
58
|
}
|
|
36
59
|
|
|
37
60
|
let stepSeq = 0;
|
|
61
|
+
let presentationRun = 0;
|
|
38
62
|
|
|
39
63
|
/**
|
|
40
64
|
* Show a tour stop, entering presentation if needed. Entering hides the
|
|
@@ -58,41 +82,137 @@ export function presentStop(stop: TourStop): void {
|
|
|
58
82
|
else play();
|
|
59
83
|
}
|
|
60
84
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
85
|
+
let requestSeq = 0;
|
|
86
|
+
const presenterId = crypto.randomUUID();
|
|
87
|
+
let lastDelivery: { catalogEpoch: string; sequence: number; applied: boolean } | null = null;
|
|
88
|
+
|
|
89
|
+
function nextPresenter(): TourPresenter | null {
|
|
90
|
+
if (catalogEpoch === null || boardGeneration === null) {
|
|
91
|
+
presentationError.value = 'The board is still connecting. Try presenting again when it is ready.';
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
return { clientId: presenterId, intent: ++requestSeq, catalogEpoch, boardGeneration };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isCurrentPresenter(presenter: TourPresenter): boolean {
|
|
98
|
+
return (
|
|
99
|
+
presenter.intent === requestSeq &&
|
|
100
|
+
presenter.catalogEpoch === catalogEpoch &&
|
|
101
|
+
presenter.boardGeneration === boardGeneration
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function acceptDelivery(data: Record<string, unknown>, apply: boolean): boolean {
|
|
106
|
+
if (
|
|
107
|
+
typeof data.catalogEpoch !== 'string' ||
|
|
108
|
+
data.catalogEpoch !== catalogEpoch ||
|
|
109
|
+
data.boardGeneration !== boardGeneration ||
|
|
110
|
+
typeof data.sequence !== 'number' ||
|
|
111
|
+
(lastDelivery?.catalogEpoch === catalogEpoch &&
|
|
112
|
+
(data.sequence < lastDelivery.sequence ||
|
|
113
|
+
(data.sequence === lastDelivery.sequence && (!apply || lastDelivery.applied))))
|
|
114
|
+
)
|
|
115
|
+
return false;
|
|
116
|
+
lastDelivery = { catalogEpoch: data.catalogEpoch, sequence: data.sequence, applied: apply };
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Apply either delivery of the server's shared cursor, without replaying its echo. */
|
|
121
|
+
export function applyTourStep(data: Record<string, unknown>): void {
|
|
122
|
+
if (recordingCamera.value) return;
|
|
123
|
+
const stop = tourStopSchema.safeParse(data.stop);
|
|
124
|
+
const display = presenting.value || data.present === true;
|
|
125
|
+
// Observe hidden steps too. The same operation's HTTP acknowledgement may
|
|
126
|
+
// authorize local presentation later, but an older acknowledgement must not.
|
|
127
|
+
if (!stop.success || !acceptDelivery(data, display) || !display) return;
|
|
128
|
+
if (typeof data.index === 'number' && typeof data.total === 'number') {
|
|
129
|
+
presentationCursor.value = { index: data.index, total: data.total };
|
|
130
|
+
}
|
|
131
|
+
presentStop(stop.data);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function applyTourExit(data: Record<string, unknown>): void {
|
|
135
|
+
if (!recordingCamera.value && acceptDelivery(data, true)) hidePresentation();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Move the shared cursor. A successful response also works while events are delayed or disconnected. */
|
|
139
|
+
export async function stepTour(
|
|
140
|
+
to: { stop: number } | { step: 'next' | 'previous' },
|
|
141
|
+
presenter = nextPresenter(),
|
|
142
|
+
): Promise<void> {
|
|
143
|
+
if (!presenter) return;
|
|
144
|
+
const run = presentationRun;
|
|
145
|
+
const previous = lastDelivery;
|
|
146
|
+
const result = await requestJson<
|
|
147
|
+
| {
|
|
148
|
+
ok: true;
|
|
149
|
+
catalogEpoch: string;
|
|
150
|
+
boardGeneration: number;
|
|
151
|
+
sequence: number;
|
|
152
|
+
index: number;
|
|
153
|
+
total: number;
|
|
154
|
+
stop: TourStop;
|
|
155
|
+
}
|
|
156
|
+
| { ok: true; superseded: true }
|
|
157
|
+
| { ok: false; error?: string }
|
|
158
|
+
>(
|
|
68
159
|
'step tour',
|
|
69
160
|
'/api/canvas/tour/go',
|
|
70
161
|
{ ok: false, error: 'Could not reach the canvas server.' },
|
|
71
162
|
{
|
|
72
163
|
method: 'POST',
|
|
73
164
|
headers: { 'Content-Type': 'application/json' },
|
|
74
|
-
body: JSON.stringify({ ...to, present: false }),
|
|
165
|
+
body: JSON.stringify({ ...to, present: false, presenter }),
|
|
75
166
|
},
|
|
76
167
|
);
|
|
77
|
-
|
|
168
|
+
// Only a local cancellation invalidates this intent. Remote steps/exits are
|
|
169
|
+
// ordered by the server stamp, even if an older exit hid the pending restart.
|
|
170
|
+
if (run !== presentationRun || !isCurrentPresenter(presenter)) return;
|
|
171
|
+
if (result.ok) {
|
|
172
|
+
if ('superseded' in result) {
|
|
173
|
+
if (previous === lastDelivery)
|
|
174
|
+
presentationError.value = 'The presentation request was superseded. Exit and present again.';
|
|
175
|
+
} else applyTourStep({ ...result, present: true });
|
|
176
|
+
} else if (previous === lastDelivery) presentationError.value = result.error ?? 'Could not change the tour stop.';
|
|
78
177
|
}
|
|
79
178
|
|
|
80
179
|
/** Present from the first stop, or resume where the tour already is (`?present=1`). */
|
|
81
180
|
export async function startPresentation(resume = false): Promise<void> {
|
|
181
|
+
const run = ++presentationRun;
|
|
82
182
|
presenting.value = true;
|
|
83
183
|
presentationError.value = '';
|
|
184
|
+
presentationCursor.value = null;
|
|
185
|
+
// Reserve the gesture before the read: an older resume cannot overtake Next.
|
|
186
|
+
const presenter = nextPresenter();
|
|
187
|
+
if (!presenter) return;
|
|
84
188
|
const at = resume
|
|
85
189
|
? (await requestJson<{ position?: number | null }>('read tour', '/api/canvas/tour', {})).position
|
|
86
190
|
: null;
|
|
87
|
-
|
|
191
|
+
if (run !== presentationRun || !isCurrentPresenter(presenter)) return;
|
|
192
|
+
await stepTour({ stop: typeof at === 'number' ? at : 0 }, presenter);
|
|
88
193
|
}
|
|
89
194
|
|
|
90
|
-
|
|
195
|
+
function hidePresentation(): void {
|
|
196
|
+
stepSeq++;
|
|
197
|
+
cancelViewportAnimation();
|
|
91
198
|
presenting.value = false;
|
|
92
199
|
presentationError.value = '';
|
|
200
|
+
presentationCursor.value = null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Local cancellation also fences pending requests from this presentation. */
|
|
204
|
+
export function dismissPresentation(): void {
|
|
205
|
+
presentationRun++;
|
|
206
|
+
hidePresentation();
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function endPresentation(): void {
|
|
210
|
+
dismissPresentation();
|
|
211
|
+
const presenter = nextPresenter();
|
|
212
|
+
if (!presenter) return;
|
|
93
213
|
void requestBestEffort('exit tour', '/api/canvas/tour/exit', {
|
|
94
214
|
method: 'POST',
|
|
95
215
|
headers: { 'Content-Type': 'application/json' },
|
|
96
|
-
body:
|
|
216
|
+
body: JSON.stringify({ presenter }),
|
|
97
217
|
});
|
|
98
218
|
}
|
|
@@ -1,9 +1,123 @@
|
|
|
1
1
|
import { computed, effect, signal } from '@preact/signals';
|
|
2
2
|
import { relationKind, relationPreset, relationSourceEnd } from '../../shared/relations.js';
|
|
3
|
+
import { memoryKey } from '../../shared/memory-graph.js';
|
|
3
4
|
import { activeBoard, activeBoardId } from './boards-store';
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
activeNodeId,
|
|
7
|
+
edges,
|
|
8
|
+
nodes,
|
|
9
|
+
selectedNodeIds,
|
|
10
|
+
focusNode,
|
|
11
|
+
collapseExpandedNode,
|
|
12
|
+
canvasInteractionEpoch,
|
|
13
|
+
} from './canvas-store';
|
|
14
|
+
import { cardQualification } from './knowledge-store';
|
|
15
|
+
import type { CanvasEdge } from '../types';
|
|
5
16
|
|
|
6
17
|
export const relationFilter = signal<{ boardId: string; kind: string } | null>(null);
|
|
18
|
+
const inspection = signal<{ boardId: string; nodeId: string; mode: 'lineage' | 'connections'; epoch: number } | null>(
|
|
19
|
+
null,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export function showRelationsOnCanvas(nodeId: string, mode: 'lineage' | 'connections'): void {
|
|
23
|
+
const boardId = activeBoardId.value;
|
|
24
|
+
if (!boardId) return;
|
|
25
|
+
collapseExpandedNode();
|
|
26
|
+
selectedNodeIds.value = new Set();
|
|
27
|
+
relationFilter.value = null;
|
|
28
|
+
focusNode(nodeId, { recordHistory: false, persistStacking: false });
|
|
29
|
+
activeNodeId.value = nodeId;
|
|
30
|
+
inspection.value = { boardId, nodeId, mode, epoch: canvasInteractionEpoch.value };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
effect(() => {
|
|
34
|
+
const value = inspection.value;
|
|
35
|
+
if (
|
|
36
|
+
value &&
|
|
37
|
+
(value.boardId !== activeBoardId.value ||
|
|
38
|
+
value.nodeId !== activeNodeId.value ||
|
|
39
|
+
value.epoch !== canvasInteractionEpoch.value ||
|
|
40
|
+
relationFilter.value)
|
|
41
|
+
)
|
|
42
|
+
inspection.value = null;
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
/** Only qualified dependency/lineage sources warn; citations and illustrated loops never do. */
|
|
46
|
+
export function relationWarning(edge: CanvasEdge): string[] {
|
|
47
|
+
const boardId = activeBoardId.value;
|
|
48
|
+
const kind = relationKind(edge);
|
|
49
|
+
if (!boardId || !['depends-on', 'derived-from'].includes(kind)) return [];
|
|
50
|
+
const from = { boardId, cardId: edge.from };
|
|
51
|
+
const to = { boardId: edge.toBoardId ?? boardId, cardId: edge.to };
|
|
52
|
+
const source = relationSourceEnd(edge) === 'from' ? from : to;
|
|
53
|
+
const dependent = relationSourceEnd(edge) === 'from' ? to : from;
|
|
54
|
+
if (dependent.boardId !== boardId) return [];
|
|
55
|
+
return (
|
|
56
|
+
cardQualification(dependent.cardId)?.sourceWarnings?.[
|
|
57
|
+
JSON.stringify([boardId, edge.id, kind, memoryKey(source)])
|
|
58
|
+
] ?? []
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const dependencyAnalysis = computed(() => {
|
|
63
|
+
const links = [...edges.value.values()].filter((edge) => !edge.toBoardId && relationKind(edge) === 'depends-on');
|
|
64
|
+
const forward = new Map<string, Set<string>>();
|
|
65
|
+
const reverse = new Map<string, Set<string>>();
|
|
66
|
+
for (const edge of links) {
|
|
67
|
+
if (!forward.has(edge.from)) forward.set(edge.from, new Set());
|
|
68
|
+
if (!forward.has(edge.to)) forward.set(edge.to, new Set());
|
|
69
|
+
if (!reverse.has(edge.from)) reverse.set(edge.from, new Set());
|
|
70
|
+
if (!reverse.has(edge.to)) reverse.set(edge.to, new Set());
|
|
71
|
+
forward.get(edge.from)!.add(edge.to);
|
|
72
|
+
reverse.get(edge.to)!.add(edge.from);
|
|
73
|
+
}
|
|
74
|
+
// Iterative strongly connected components: one count per cyclic dependency cluster.
|
|
75
|
+
const visited = new Set<string>();
|
|
76
|
+
const order: string[] = [];
|
|
77
|
+
for (const root of forward.keys()) {
|
|
78
|
+
const stack: Array<[string, boolean]> = [[root, false]];
|
|
79
|
+
while (stack.length) {
|
|
80
|
+
const [id, done] = stack.pop()!;
|
|
81
|
+
if (done) {
|
|
82
|
+
order.push(id);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (visited.has(id)) continue;
|
|
86
|
+
visited.add(id);
|
|
87
|
+
stack.push([id, true]);
|
|
88
|
+
for (const next of forward.get(id) ?? []) if (!visited.has(next)) stack.push([next, false]);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const assigned = new Set<string>();
|
|
92
|
+
const cyclic = new Map<string, number>();
|
|
93
|
+
let cycles = 0;
|
|
94
|
+
for (const root of order.reverse()) {
|
|
95
|
+
if (assigned.has(root)) continue;
|
|
96
|
+
const component = new Set<string>([root]);
|
|
97
|
+
assigned.add(root);
|
|
98
|
+
for (const id of component)
|
|
99
|
+
for (const next of reverse.get(id) ?? []) {
|
|
100
|
+
if (assigned.has(next)) continue;
|
|
101
|
+
assigned.add(next);
|
|
102
|
+
component.add(next);
|
|
103
|
+
}
|
|
104
|
+
if (component.size > 1 || forward.get(root)?.has(root)) {
|
|
105
|
+
cycles++;
|
|
106
|
+
for (const id of component) cyclic.set(id, cycles);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const cycleEdges = new Set(
|
|
110
|
+
links
|
|
111
|
+
.filter((edge) => cyclic.has(edge.from) && cyclic.get(edge.from) === cyclic.get(edge.to))
|
|
112
|
+
.map((edge) => edge.id),
|
|
113
|
+
);
|
|
114
|
+
const roots = new Set(selectedNodeIds.value);
|
|
115
|
+
if (activeNodeId.value) roots.add(activeNodeId.value);
|
|
116
|
+
const affected = new Set(roots);
|
|
117
|
+
for (const id of affected) for (const next of reverse.get(id) ?? []) affected.add(next);
|
|
118
|
+
for (const id of roots) affected.delete(id);
|
|
119
|
+
return { cycles, cycleEdges, affected, focused: roots.size > 0, hasDependencies: links.length > 0 };
|
|
120
|
+
});
|
|
7
121
|
|
|
8
122
|
effect(() => {
|
|
9
123
|
const filter = relationFilter.value;
|
|
@@ -40,6 +154,18 @@ export const relationHighlight = computed(() => {
|
|
|
40
154
|
cards.add(edge.from);
|
|
41
155
|
cards.add(edge.to);
|
|
42
156
|
};
|
|
157
|
+
const view = inspection.value;
|
|
158
|
+
if (view && view.boardId === activeBoardId.value && view.nodeId === focus && !kind) {
|
|
159
|
+
if (view.mode === 'connections') {
|
|
160
|
+
for (const edge of list) if (edge.from === focus || edge.to === focus) add(edge);
|
|
161
|
+
} else {
|
|
162
|
+
for (const id of cards)
|
|
163
|
+
for (const edge of list)
|
|
164
|
+
if (['derived-from', 'depends-on'].includes(relationKind(edge)) && (edge.from === id || edge.to === id))
|
|
165
|
+
add(edge);
|
|
166
|
+
}
|
|
167
|
+
return { cards, links };
|
|
168
|
+
}
|
|
43
169
|
if (!kind) for (const edge of list) if (focusedCards.has(edge.from) && focusedCards.has(edge.to)) add(edge);
|
|
44
170
|
if (kind) {
|
|
45
171
|
for (const edge of list) if (relationKind(edge) === kind) add(edge);
|
|
@@ -2,7 +2,7 @@ import { findOpenCanvasPosition } from '../utils/placement.js';
|
|
|
2
2
|
import { refreshKnowledge } from './knowledge-store';
|
|
3
3
|
import { applyWorkspaceSettings } from './workspace-settings';
|
|
4
4
|
import { cameraSchema, tourStopSchema } from '../../shared/tour.js';
|
|
5
|
-
import {
|
|
5
|
+
import { applyTourExit, applyTourStep, ownsCamera, playStop, presenting, recordingCamera } from './presentation';
|
|
6
6
|
import { isHostedWorkbench, workbenchFetch } from './workbench-transport';
|
|
7
7
|
import { normalizeExtAppToolResult } from '../utils/ext-app-tool-result.js';
|
|
8
8
|
import type { CanvasAnnotation, CanvasEdge, CanvasNodeState, NodeActor } from '../types';
|
|
@@ -176,7 +176,7 @@ function ensureMarkdownNode(path: string, title: string): void {
|
|
|
176
176
|
const node = makeNode(id, 'markdown', { path, title, content: '', rendered: '' });
|
|
177
177
|
node.position = placement;
|
|
178
178
|
addNode(node);
|
|
179
|
-
focusNode(id);
|
|
179
|
+
focusNode(id, { persistStacking: false });
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
182
|
|
|
@@ -199,7 +199,7 @@ function ensureMcpAppNode(data: Record<string, unknown>): void {
|
|
|
199
199
|
updateNodeData(id, data);
|
|
200
200
|
} else {
|
|
201
201
|
addNode(makeNode(id, 'mcp-app', data));
|
|
202
|
-
focusNode(id);
|
|
202
|
+
focusNode(id, { persistStacking: false });
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
|
|
@@ -260,7 +260,7 @@ function ensureExtAppNode(data: Record<string, unknown>): void {
|
|
|
260
260
|
),
|
|
261
261
|
);
|
|
262
262
|
addNode(node);
|
|
263
|
-
focusNode(id, { recordHistory: false });
|
|
263
|
+
focusNode(id, { recordHistory: false, persistStacking: false });
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
function findExtAppNodeId(toolCallId: string): string | null {
|
|
@@ -849,7 +849,7 @@ function handleCanvasPromptCreated(data: Record<string, unknown>): void {
|
|
|
849
849
|
),
|
|
850
850
|
),
|
|
851
851
|
);
|
|
852
|
-
focusNode(nodeId);
|
|
852
|
+
focusNode(nodeId, { persistStacking: false });
|
|
853
853
|
}
|
|
854
854
|
|
|
855
855
|
// Add flow edge from parent → prompt if parent exists
|
|
@@ -888,7 +888,7 @@ function handleCanvasResponseStart(data: Record<string, unknown>): void {
|
|
|
888
888
|
threadStatus: 'streaming',
|
|
889
889
|
_activeResponseId: responseNodeId,
|
|
890
890
|
});
|
|
891
|
-
focusNode(promptNodeId);
|
|
891
|
+
focusNode(promptNodeId, { persistStacking: false });
|
|
892
892
|
return;
|
|
893
893
|
}
|
|
894
894
|
|
|
@@ -921,7 +921,7 @@ function handleCanvasResponseStart(data: Record<string, unknown>): void {
|
|
|
921
921
|
});
|
|
922
922
|
}
|
|
923
923
|
|
|
924
|
-
focusNode(responseNodeId);
|
|
924
|
+
focusNode(responseNodeId, { persistStacking: false });
|
|
925
925
|
}
|
|
926
926
|
|
|
927
927
|
function handleCanvasResponseDelta(data: Record<string, unknown>): void {
|
|
@@ -1078,10 +1078,10 @@ function handleCanvasFocusNode(data: Record<string, unknown>): void {
|
|
|
1078
1078
|
const nodeId = data.nodeId as string;
|
|
1079
1079
|
if (nodeId && nodes.value.has(nodeId)) {
|
|
1080
1080
|
if (data.noPan === true) {
|
|
1081
|
-
bringToFront(nodeId);
|
|
1081
|
+
bringToFront(nodeId, false);
|
|
1082
1082
|
return;
|
|
1083
1083
|
}
|
|
1084
|
-
focusNode(nodeId);
|
|
1084
|
+
focusNode(nodeId, { persistStacking: false });
|
|
1085
1085
|
}
|
|
1086
1086
|
}
|
|
1087
1087
|
|
|
@@ -1093,6 +1093,12 @@ function handleCanvasViewportUpdate(data: Record<string, unknown>): void {
|
|
|
1093
1093
|
const x = typeof viewport.x === 'number' ? viewport.x : 0;
|
|
1094
1094
|
const y = typeof viewport.y === 'number' ? viewport.y : 0;
|
|
1095
1095
|
const scale = typeof viewport.scale === 'number' ? viewport.scale : 1;
|
|
1096
|
+
// The catalog may still be holding the initial layout. Its older camera
|
|
1097
|
+
// must not overwrite this later event when the board identity arrives.
|
|
1098
|
+
const pendingLayout = pendingBoardLayout?.layout as Record<string, unknown> | undefined;
|
|
1099
|
+
if (pendingLayout) {
|
|
1100
|
+
pendingBoardLayout = { ...pendingBoardLayout, layout: { ...pendingLayout, viewport: { x, y, scale } } };
|
|
1101
|
+
}
|
|
1096
1102
|
cancelViewportAnimation();
|
|
1097
1103
|
replaceViewport({ x, y, scale });
|
|
1098
1104
|
}
|
|
@@ -1100,18 +1106,11 @@ function handleCanvasViewportUpdate(data: Record<string, unknown>): void {
|
|
|
1100
1106
|
// Tour steps and camera moves animate locally; a deterministic capture owns
|
|
1101
1107
|
// its camera outright and ignores both.
|
|
1102
1108
|
function handleCanvasTourStep(data: Record<string, unknown>): void {
|
|
1103
|
-
|
|
1104
|
-
// A human stepping in one tab moves tabs already presenting; only a
|
|
1105
|
-
// `present` step (the agent's default) starts presenting elsewhere.
|
|
1106
|
-
if (!presenting.value && data.present !== true) return;
|
|
1107
|
-
const stop = tourStopSchema.safeParse(data.stop);
|
|
1108
|
-
if (stop.success) presentStop(stop.data);
|
|
1109
|
+
applyTourStep(data);
|
|
1109
1110
|
}
|
|
1110
1111
|
|
|
1111
|
-
function handleCanvasTourExit(): void {
|
|
1112
|
-
|
|
1113
|
-
presenting.value = false;
|
|
1114
|
-
presentationError.value = '';
|
|
1112
|
+
function handleCanvasTourExit(data: Record<string, unknown>): void {
|
|
1113
|
+
applyTourExit(data);
|
|
1115
1114
|
}
|
|
1116
1115
|
|
|
1117
1116
|
function handleCanvasCameraMove(data: Record<string, unknown>): void {
|