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.
Files changed (343) hide show
  1. package/.github/extensions/pmx-canvas/extension.mjs +3 -1
  2. package/.github/extensions/pmx-canvas/runtime.json +1 -1
  3. package/.github/extensions/pmx-canvas/tools.json +688 -128
  4. package/CHANGELOG.md +69 -0
  5. package/dist/amp-plugin/pmx-canvas/LICENSE +21 -0
  6. package/dist/amp-plugin/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
  7. package/dist/amp-plugin/pmx-canvas/index.js +5445 -0
  8. package/dist/amp-plugin/pmx-canvas/runtime.json +3 -0
  9. package/dist/amp-plugin/pmx-canvas/shared-runtime.mjs +194 -0
  10. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/SKILL.md +251 -0
  11. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/evals.json +1086 -0
  12. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/jwt.ts +17 -0
  13. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/login.ts +12 -0
  14. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/middleware.ts +13 -0
  15. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/routes/auth.ts +13 -0
  16. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/investigation-board/src/handlers/users.ts +27 -0
  17. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/mcp.json +36 -0
  18. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/ax-html-control-surface.md +101 -0
  19. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/codex-app-adapter.md +151 -0
  20. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/excalidraw-diagram-authoring.md +150 -0
  21. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/full-reference.md +1785 -0
  22. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/github-copilot-app-adapter.md +223 -0
  23. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/html-primitives.md +139 -0
  24. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/importing-context.md +132 -0
  25. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/installing-pmx-canvas.md +251 -0
  26. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/tours-and-recording.md +111 -0
  27. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/workbench-workflows.md +900 -0
  28. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas-orchestration/SKILL.md +141 -0
  29. package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas-testing/SKILL.md +266 -0
  30. package/dist/amp-plugin/pmx-canvas/start-mcp.mjs +14857 -0
  31. package/dist/amp-plugin/pmx-canvas/tools.json +10963 -0
  32. package/dist/canvas/chunks/abnfDiagram-N423BO3Z-cwtsds5d.js +1 -0
  33. package/dist/canvas/chunks/architecture-TIHT7OUA-x63cwejs.js +1 -0
  34. package/dist/canvas/chunks/architectureDiagram-T3A2C74G-b4xc9tpz.js +36 -0
  35. package/dist/canvas/chunks/blockDiagram-VBNYF7ZC-ahp3yxxs.js +132 -0
  36. package/dist/canvas/chunks/c4Diagram-5PPSVZJV-nappnay7.js +10 -0
  37. package/dist/canvas/chunks/classDiagram-JCYQIIEL-k1j2xc1t.js +1 -0
  38. package/dist/canvas/chunks/classDiagram-v2-OCEON4UE-33x08xf2.js +1 -0
  39. package/dist/canvas/chunks/cose-bilkent-JH36ORCC-a428syda.js +1 -0
  40. package/dist/canvas/chunks/cynefin-VYW2F7L2-8v6jxfz8.js +1 -0
  41. package/dist/canvas/chunks/cynefinDiagram-MW4NZA55-nspsqebj.js +62 -0
  42. package/dist/canvas/chunks/dagre-VZM6K2ZE-8y6177fh.js +4 -0
  43. package/dist/canvas/chunks/diagram-7IWD3JNH-vym028wn.js +30 -0
  44. package/dist/canvas/chunks/diagram-B4RE2ZJO-jddqb8sy.js +3 -0
  45. package/dist/canvas/chunks/diagram-LBJQPF4R-bjwbpkrn.js +24 -0
  46. package/dist/canvas/chunks/diagram-Q27KOJAE-j6ph6hcx.js +24 -0
  47. package/dist/canvas/chunks/diagram-UB23O5K3-p09w8jej.js +41 -0
  48. package/dist/canvas/chunks/ebnfDiagram-BXEA7PRR-j975ycq5.js +1 -0
  49. package/dist/canvas/chunks/erDiagram-JOGREHBK-sxp6hjn8.js +85 -0
  50. package/dist/canvas/chunks/eventmodeling-45OFAUF4-xzfgn6xg.js +1 -0
  51. package/dist/canvas/chunks/flowDiagram-UKHOOZJN-2nsmkskb.js +1 -0
  52. package/dist/canvas/chunks/ganttDiagram-PKOTCBZU-4tv230y2.js +292 -0
  53. package/dist/canvas/chunks/gitGraph-TEB2WS4Q-macbhand.js +1 -0
  54. package/dist/canvas/chunks/gitGraphDiagram-DS77QQ5N-mqgmnw9g.js +106 -0
  55. package/dist/canvas/chunks/index-037z5dz2.js +232 -0
  56. package/dist/canvas/chunks/index-081n3har.js +207 -0
  57. package/dist/canvas/chunks/index-5n03dmb9.js +2 -0
  58. package/dist/canvas/chunks/index-5tv8v1hk.js +1 -0
  59. package/dist/canvas/chunks/index-60pgzdqe.js +157 -0
  60. package/dist/canvas/chunks/index-6ceya556.js +332 -0
  61. package/dist/canvas/chunks/index-8g1vb57n.js +2 -0
  62. package/dist/canvas/chunks/index-8rjes9r6.js +2 -0
  63. package/dist/canvas/chunks/index-9022d1n9.js +16 -0
  64. package/dist/canvas/chunks/index-9b02042t.js +2 -0
  65. package/dist/canvas/chunks/index-ap4q4vez.js +2 -0
  66. package/dist/canvas/chunks/index-dyp2nhd3.js +2 -0
  67. package/dist/canvas/chunks/index-frvta4tm.js +2 -0
  68. package/dist/canvas/chunks/index-gf4e0et4.js +2 -0
  69. package/dist/canvas/chunks/index-h9ycj8n2.js +2 -0
  70. package/dist/canvas/chunks/index-hj99nz1f.js +1 -0
  71. package/dist/canvas/chunks/index-mergmj97.js +2 -0
  72. package/dist/canvas/chunks/index-nwsya6dj.js +301 -0
  73. package/dist/canvas/chunks/index-nz8qbd1p.js +2 -0
  74. package/dist/canvas/chunks/index-qhfrazv3.js +2 -0
  75. package/dist/canvas/chunks/index-v119nznk.js +4 -0
  76. package/dist/canvas/chunks/index-vpt37m3d.js +89 -0
  77. package/dist/canvas/chunks/index-y9ma6azy.js +2 -0
  78. package/dist/canvas/chunks/index-zx0j3a2z.js +179 -0
  79. package/dist/canvas/chunks/info-DKCQHKI2-a0ykzs9z.js +1 -0
  80. package/dist/canvas/chunks/infoDiagram-6WML65LV-qv97qq6a.js +2 -0
  81. package/dist/canvas/chunks/ishikawaDiagram-WSZJBQD7-p9306gh0.js +70 -0
  82. package/dist/canvas/chunks/journeyDiagram-NVQOT4AX-sv67zats.js +139 -0
  83. package/dist/canvas/chunks/kanban-definition-27J2QSJJ-k2pfam6p.js +89 -0
  84. package/dist/canvas/chunks/katex-dmg8k4zm.js +257 -0
  85. package/dist/canvas/chunks/mermaid.core-83r0fdce.js +12 -0
  86. package/dist/canvas/chunks/mindmap-definition-FAOFIHXS-vg2newm1.js +96 -0
  87. package/dist/canvas/chunks/packet-7NZHBO7P-tqnabcdv.js +1 -0
  88. package/dist/canvas/chunks/pegDiagram-VL7TDLO6-k2h7zc5n.js +1 -0
  89. package/dist/canvas/chunks/pie-RZYD4A2V-wke6gyhe.js +1 -0
  90. package/dist/canvas/chunks/pieDiagram-7S7Q4E2Y-hg169p1v.js +39 -0
  91. package/dist/canvas/chunks/quadrantDiagram-CIZ2JOQS-bxtvsq0b.js +7 -0
  92. package/dist/canvas/chunks/radar-I7S5WNFK-w7ka0drw.js +1 -0
  93. package/dist/canvas/chunks/railroad-3IZDKUUU-y3vg318x.js +1 -0
  94. package/dist/canvas/chunks/railroad-abnf-AHOZXSZD-6hqvcz3c.js +1 -0
  95. package/dist/canvas/chunks/railroad-ebnf-EBAXGLYW-vcae260m.js +1 -0
  96. package/dist/canvas/chunks/railroad-peg-LSFZ7HO6-0dbyme23.js +1 -0
  97. package/dist/canvas/chunks/railroadDiagram-AXF67PYL-njyhcp4p.js +1 -0
  98. package/dist/canvas/chunks/requirementDiagram-LRYGKXZP-2z6v09gm.js +84 -0
  99. package/dist/canvas/chunks/sankeyDiagram-W5VNT64P-15mzam0e.js +40 -0
  100. package/dist/canvas/chunks/sequenceDiagram-SI44F4Z6-rbshyd2c.js +162 -0
  101. package/dist/canvas/chunks/sizeCapture-X5ZJPWSS-sg26xwts.js +1 -0
  102. package/dist/canvas/chunks/stateDiagram-OKZ733FA-6eahp98e.js +1 -0
  103. package/dist/canvas/chunks/stateDiagram-v2-UEYNNEHI-tty0ggn5.js +1 -0
  104. package/dist/canvas/chunks/swimlanes-SLNWSIFB-ze5db10t.js +1 -0
  105. package/dist/canvas/chunks/swimlanesDiagram-ULZ7WXOC-thze75gq.js +8 -0
  106. package/dist/canvas/chunks/timeline-definition-Z64GVDOM-vnp7jyy8.js +120 -0
  107. package/dist/canvas/chunks/treeView-QDETBFTQ-6ysffnm6.js +1 -0
  108. package/dist/canvas/chunks/treemap-6X3UGDF4-m3h9p066.js +1 -0
  109. package/dist/canvas/chunks/vennDiagram-T6HMQDX7-0qrnb7mj.js +34 -0
  110. package/dist/canvas/chunks/wardley-OPB4EBWU-dp37drwx.js +1 -0
  111. package/dist/canvas/chunks/wardleyDiagram-T6FBY63Y-8nxg8wqt.js +78 -0
  112. package/dist/canvas/chunks/xychartDiagram-ELKLHX3M-nj921e7s.js +7 -0
  113. package/dist/canvas/global.css +483 -230
  114. package/dist/canvas/index.js +158 -219
  115. package/dist/canvas/mcp-app.html +4301 -548
  116. package/dist/canvas/mermaid-entry.js +338 -338
  117. package/dist/canvas/surface-theme.css +6 -6
  118. package/dist/json-render/index.css +1 -1
  119. package/dist/json-render/index.js +49 -49
  120. package/dist/types/client/canvas/BarHint.d.ts +5 -3
  121. package/dist/types/client/canvas/BoardMoveDialog.d.ts +2 -0
  122. package/dist/types/client/canvas/CanvasNode.d.ts +0 -11
  123. package/dist/types/client/canvas/EdgeEditor.d.ts +19 -0
  124. package/dist/types/client/canvas/EdgeLayer.d.ts +1 -2
  125. package/dist/types/client/canvas/GroupNavigation.d.ts +2 -0
  126. package/dist/types/client/canvas/TextPrompt.d.ts +4 -0
  127. package/dist/types/client/canvas/auto-fit.d.ts +4 -5
  128. package/dist/types/client/mermaid-entry.d.ts +1 -2
  129. package/dist/types/client/mermaid-render.d.ts +1 -0
  130. package/dist/types/client/nodes/BoardNode.d.ts +1 -1
  131. package/dist/types/client/nodes/ExtAppFrame.d.ts +7 -90
  132. package/dist/types/client/nodes/McpAppNode.d.ts +1 -25
  133. package/dist/types/client/nodes/MermaidNode.d.ts +1 -8
  134. package/dist/types/client/nodes/PromptNode.d.ts +1 -0
  135. package/dist/types/client/nodes/ViewerFrame.d.ts +29 -0
  136. package/dist/types/client/nodes/ViewerHost.d.ts +6 -0
  137. package/dist/types/client/nodes/WorkCard.d.ts +7 -0
  138. package/dist/types/client/nodes/iframe-document-url.d.ts +3 -9
  139. package/dist/types/client/nodes/primitive-copy.d.ts +5 -0
  140. package/dist/types/client/nodes/use-ax-surface-bridge.d.ts +1 -0
  141. package/dist/types/client/nodes/use-iframe-content-height.d.ts +1 -1
  142. package/dist/types/client/nodes/use-surface-frame.d.ts +4 -6
  143. package/dist/types/client/nodes/viewer-runtime-state.d.ts +2 -1
  144. package/dist/types/client/state/canvas-store.d.ts +18 -1
  145. package/dist/types/client/state/human-store.d.ts +2 -0
  146. package/dist/types/client/state/intent-bridge.d.ts +5 -2
  147. package/dist/types/client/state/presentation.d.ts +17 -6
  148. package/dist/types/client/state/relation-store.d.ts +11 -0
  149. package/dist/types/client/types.d.ts +1 -1
  150. package/dist/types/json-render/catalog.d.ts +2 -2
  151. package/dist/types/json-render/server.d.ts +2 -1
  152. package/dist/types/server/agent-presence.d.ts +1 -0
  153. package/dist/types/server/ax-interaction.d.ts +1 -0
  154. package/dist/types/server/ax-state-manager.d.ts +10 -2
  155. package/dist/types/server/board-local.d.ts +4 -0
  156. package/dist/types/server/board-move.d.ts +38 -0
  157. package/dist/types/server/canvas-db.d.ts +12 -2
  158. package/dist/types/server/canvas-operations.d.ts +5 -6
  159. package/dist/types/server/canvas-provenance.d.ts +1 -1
  160. package/dist/types/server/canvas-serialization.d.ts +1 -0
  161. package/dist/types/server/canvas-state.d.ts +86 -20
  162. package/dist/types/server/card-relocation.d.ts +6 -0
  163. package/dist/types/server/context-reads.d.ts +3 -1
  164. package/dist/types/server/human-presence.d.ts +1 -1
  165. package/dist/types/server/index.d.ts +26 -10
  166. package/dist/types/server/intent-registry.d.ts +8 -4
  167. package/dist/types/server/knowledge-lifecycle.d.ts +4 -2
  168. package/dist/types/server/mutation-history.d.ts +7 -5
  169. package/dist/types/server/operations/ops/boards.d.ts +0 -1
  170. package/dist/types/server/operations/registry.d.ts +2 -0
  171. package/dist/types/server/tour-control.d.ts +13 -3
  172. package/dist/types/server/trace-manager.d.ts +1 -0
  173. package/dist/types/shared/ax-kinds.d.ts +6 -0
  174. package/dist/types/shared/ax-surface-protocol.d.ts +8 -9
  175. package/dist/types/shared/human-presence.d.ts +1 -0
  176. package/dist/types/shared/lifecycle-status.d.ts +2 -0
  177. package/dist/types/shared/tour.d.ts +8 -0
  178. package/docs/RELEASE.md +21 -14
  179. package/docs/agent-plugin.md +16 -2
  180. package/docs/amp-plugin.md +271 -0
  181. package/docs/cli.md +42 -3
  182. package/docs/design/Chrome.dc.html +32 -6
  183. package/docs/design/GuestName.dc.html +50 -0
  184. package/docs/design/PluginLogo.svg +7 -0
  185. package/docs/design/Types1.dc.html +3 -2
  186. package/docs/design/Types2.dc.html +1 -1
  187. package/docs/design/Types3.dc.html +1 -1
  188. package/docs/design/WorkCards.dc.html +39 -0
  189. package/docs/design/Zoom.dc.html +37 -60
  190. package/docs/design/canvas.json +17 -1
  191. package/docs/design/plugin-logo.png +0 -0
  192. package/docs/design.md +280 -12
  193. package/docs/evals/agents-md-sections.md +38 -0
  194. package/docs/http-api.md +179 -11
  195. package/docs/mcp.md +69 -9
  196. package/docs/node-types.md +109 -4
  197. package/docs/plans/plan-009-tech-debt-backlog.md +3 -3
  198. package/docs/plans/plan-019-post-0.9-roadmap.md +327 -31
  199. package/docs/plans/plan-020-wave-5-work-planning.md +553 -0
  200. package/docs/product-vision-2026-09.md +42 -17
  201. package/docs/sdk.md +18 -0
  202. package/package.json +7 -4
  203. package/plugins/pmx-canvas/assets/preview.png +0 -0
  204. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/extension.mjs +3 -1
  205. package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
  206. package/plugins/pmx-canvas/plugin.json +2 -2
  207. package/plugins/pmx-canvas/runtime.json +1 -1
  208. package/plugins/pmx-canvas/tools.json +688 -128
  209. package/skills/data-analysis/SKILL.md +13 -26
  210. package/skills/frontend-design/LICENSE.txt +177 -0
  211. package/skills/frontend-design/SKILL.md +3 -0
  212. package/skills/pmx-canvas/SKILL.md +232 -849
  213. package/skills/pmx-canvas/evals/evals.json +26 -3
  214. package/skills/pmx-canvas/references/full-reference.md +89 -24
  215. package/skills/pmx-canvas/references/html-primitives.md +7 -0
  216. package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
  217. package/skills/pmx-canvas/references/tours-and-recording.md +29 -2
  218. package/skills/pmx-canvas/references/workbench-workflows.md +900 -0
  219. package/skills/pmx-canvas-testing/SKILL.md +7 -5
  220. package/skills/published-consumer-e2e/SKILL.md +25 -8
  221. package/skills/published-consumer-e2e/scripts/run-published-consumer-e2e.sh +51 -77
  222. package/skills/web-artifacts-builder/LICENSE.txt +202 -0
  223. package/skills/web-artifacts-builder/SKILL.md +6 -0
  224. package/skills/web-artifacts-builder/scripts/init-artifact.sh +2 -2
  225. package/src/cli/commands/apps.ts +1 -0
  226. package/src/cli/commands/boards.ts +30 -0
  227. package/src/client/App.tsx +20 -4
  228. package/src/client/canvas/AttentionHistory.tsx +10 -2
  229. package/src/client/canvas/BarHint.tsx +6 -3
  230. package/src/client/canvas/BoardMoveDialog.tsx +225 -0
  231. package/src/client/canvas/CanvasNode.tsx +79 -49
  232. package/src/client/canvas/CanvasViewport.tsx +42 -14
  233. package/src/client/canvas/ContextMenu.tsx +97 -15
  234. package/src/client/canvas/EdgeEditor.tsx +149 -0
  235. package/src/client/canvas/EdgeLayer.tsx +441 -174
  236. package/src/client/canvas/ExpandedNodeOverlay.tsx +5 -2
  237. package/src/client/canvas/GroupNavigation.tsx +85 -0
  238. package/src/client/canvas/Presentation.tsx +53 -3
  239. package/src/client/canvas/RelationsPanel.tsx +9 -0
  240. package/src/client/canvas/SelectionBar.tsx +21 -0
  241. package/src/client/canvas/SessionPanel.tsx +35 -1
  242. package/src/client/canvas/TextPrompt.tsx +18 -1
  243. package/src/client/canvas/TopBar.tsx +54 -9
  244. package/src/client/canvas/auto-fit.ts +9 -11
  245. package/src/client/canvas/canvas-area.ts +2 -2
  246. package/src/client/canvas/use-focus-trap.ts +6 -1
  247. package/src/client/mermaid-entry.ts +6 -20
  248. package/src/client/mermaid-render.ts +39 -0
  249. package/src/client/nodes/AxStepControls.tsx +45 -69
  250. package/src/client/nodes/BoardNode.tsx +65 -9
  251. package/src/client/nodes/ContextNode.tsx +88 -396
  252. package/src/client/nodes/ExtAppFrame.tsx +302 -1465
  253. package/src/client/nodes/FileNode.tsx +92 -81
  254. package/src/client/nodes/HtmlNode.tsx +8 -36
  255. package/src/client/nodes/LedgerNode.tsx +31 -17
  256. package/src/client/nodes/MarkdownNode.tsx +14 -24
  257. package/src/client/nodes/McpAppNode.tsx +48 -154
  258. package/src/client/nodes/MermaidNode.tsx +80 -69
  259. package/src/client/nodes/PromptNode.tsx +44 -17
  260. package/src/client/nodes/ResponseNode.tsx +8 -6
  261. package/src/client/nodes/StatusNode.tsx +34 -7
  262. package/src/client/nodes/StatusSummary.tsx +16 -3
  263. package/src/client/nodes/TraceNode.tsx +8 -8
  264. package/src/client/nodes/ViewerFrame.tsx +273 -0
  265. package/src/client/nodes/ViewerHost.tsx +41 -0
  266. package/src/client/nodes/WebpageNode.tsx +22 -24
  267. package/src/client/nodes/WorkCard.tsx +175 -0
  268. package/src/client/nodes/iframe-document-url.ts +20 -27
  269. package/src/client/nodes/primitive-copy.ts +97 -0
  270. package/src/client/nodes/use-ax-surface-bridge.ts +18 -14
  271. package/src/client/nodes/use-iframe-content-height.ts +34 -10
  272. package/src/client/nodes/use-surface-frame.ts +22 -11
  273. package/src/client/nodes/viewer-runtime-state.ts +41 -35
  274. package/src/client/state/attention-bridge.ts +5 -0
  275. package/src/client/state/attention-store.ts +1 -0
  276. package/src/client/state/canvas-store.ts +202 -26
  277. package/src/client/state/human-store.ts +22 -2
  278. package/src/client/state/intent-bridge.ts +20 -5
  279. package/src/client/state/presentation.ts +135 -15
  280. package/src/client/state/relation-store.ts +127 -1
  281. package/src/client/state/sse-bridge.ts +18 -19
  282. package/src/client/theme/global.css +483 -230
  283. package/src/client/theme/surface-theme.css +6 -6
  284. package/src/client/types.ts +1 -0
  285. package/src/json-render/charts/tufte-components.tsx +44 -2
  286. package/src/json-render/renderer/index.css +62 -2
  287. package/src/json-render/renderer/index.tsx +31 -7
  288. package/src/json-render/server.ts +3 -2
  289. package/src/mcp/server.ts +13 -3
  290. package/src/server/agent-presence.ts +43 -23
  291. package/src/server/ax-flow-loop.ts +6 -0
  292. package/src/server/ax-gate-ttl.ts +8 -1
  293. package/src/server/ax-interaction.ts +16 -10
  294. package/src/server/ax-state-manager.ts +17 -4
  295. package/src/server/ax-wait.ts +20 -6
  296. package/src/server/board-export.ts +54 -30
  297. package/src/server/board-local.ts +20 -0
  298. package/src/server/board-move.ts +297 -0
  299. package/src/server/canvas-db.ts +249 -158
  300. package/src/server/canvas-geometry.ts +1 -0
  301. package/src/server/canvas-operations.ts +139 -109
  302. package/src/server/canvas-schema.ts +21 -0
  303. package/src/server/canvas-serialization.ts +2 -0
  304. package/src/server/canvas-state.ts +797 -159
  305. package/src/server/card-relocation.ts +53 -0
  306. package/src/server/code-graph.ts +4 -3
  307. package/src/server/context-reads.ts +83 -55
  308. package/src/server/demo-state.json +140 -114
  309. package/src/server/file-watcher.ts +30 -10
  310. package/src/server/html-primitives.ts +3 -9
  311. package/src/server/html-surface.ts +8 -0
  312. package/src/server/human-presence.ts +18 -5
  313. package/src/server/index.ts +54 -24
  314. package/src/server/intent-registry.ts +43 -5
  315. package/src/server/knowledge-lifecycle.ts +32 -9
  316. package/src/server/lifecycle-status.ts +29 -1
  317. package/src/server/mcp-app-runtime.ts +26 -7
  318. package/src/server/mutation-history.ts +37 -8
  319. package/src/server/operations/composites.ts +6 -3
  320. package/src/server/operations/mcp-contracts.ts +32 -2
  321. package/src/server/operations/mcp.ts +36 -9
  322. package/src/server/operations/ops/annotation.ts +22 -1
  323. package/src/server/operations/ops/ax-await.ts +1 -0
  324. package/src/server/operations/ops/ax-timeline.ts +28 -2
  325. package/src/server/operations/ops/batch.ts +25 -11
  326. package/src/server/operations/ops/boards.ts +45 -6
  327. package/src/server/operations/ops/nodes.ts +70 -0
  328. package/src/server/operations/ops/query.ts +32 -3
  329. package/src/server/operations/ops/snapshots.ts +1 -0
  330. package/src/server/operations/ops/viewport.ts +11 -9
  331. package/src/server/operations/registry.ts +49 -4
  332. package/src/server/server.ts +69 -75
  333. package/src/server/tour-control.ts +97 -12
  334. package/src/server/trace-manager.ts +4 -0
  335. package/src/server/web-artifacts/scripts/init-artifact.sh +2 -2
  336. package/src/shared/agent-context.ts +7 -1
  337. package/src/shared/auto-arrange.ts +5 -4
  338. package/src/shared/ax-kinds.ts +13 -0
  339. package/src/shared/ax-surface-protocol.ts +20 -9
  340. package/src/shared/content-height-reporter.ts +4 -3
  341. package/src/shared/human-presence.ts +1 -0
  342. package/src/shared/lifecycle-status.ts +2 -0
  343. package/src/shared/tour.ts +8 -0
@@ -1,14 +1,23 @@
1
1
  import { signal } from '@preact/signals';
2
- import { interpolateCamera, resolveStop, type TourStop } from '../../shared/tour.js';
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 { animateCameraPath, nodes, viewport } from './canvas-store';
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
- const target = resolveStop(stop, [...nodes.value.values()], area.width, area.height);
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
- * Move the server's shared tour cursor. The `canvas-tour-step` echo does the
63
- * animating, here and in every other presenting viewer, so a human's keys and
64
- * an agent's `tour.go` always agree on where the tour is.
65
- */
66
- export async function stepTour(to: { stop: number } | { step: 'next' | 'previous' }): Promise<void> {
67
- const result = await requestJson<{ ok: boolean; error?: string }>(
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
- if (!result.ok) presentationError.value = result.error ?? 'Could not change the tour stop.';
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
- await stepTour({ stop: typeof at === 'number' ? at : 0 });
191
+ if (run !== presentationRun || !isCurrentPresenter(presenter)) return;
192
+ await stepTour({ stop: typeof at === 'number' ? at : 0 }, presenter);
88
193
  }
89
194
 
90
- export function endPresentation(): void {
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 { activeNodeId, edges, nodes, selectedNodeIds } from './canvas-store';
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 { ownsCamera, playStop, presentationError, presenting, presentStop, recordingCamera } from './presentation';
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
- if (recordingCamera.value) return;
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
- if (recordingCamera.value) return;
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 {