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,4 +1,5 @@
1
- import { useCallback, useEffect, useMemo, useState } from 'preact/hooks';
1
+ import { createPortal } from 'preact/compat';
2
+ import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'preact/hooks';
2
3
  import { BarHint } from '../canvas/BarHint';
3
4
  import { IconPlusCircle, IconRefresh } from '../icons';
4
5
  import { delimiterForPath, parseDelimitedText } from '../../shared/delimited-text';
@@ -85,6 +86,10 @@ function TextFileNode({ node, expanded = false }: { node: CanvasNodeState; expan
85
86
  const [loading, setLoading] = useState(!cachedContent && !!filePath && !servesBytes);
86
87
  const [error, setError] = useState<string | null>(null);
87
88
  const [bytesVersion, setBytesVersion] = useState(0);
89
+ const [header, setHeader] = useState<Element | null>(null);
90
+ useLayoutEffect(() => {
91
+ setHeader(expanded ? null : document.querySelector(`[data-file-toolbar="${node.id}"]`));
92
+ }, [node.id, expanded]);
88
93
 
89
94
  // Load file content on mount or when path changes
90
95
  useEffect(() => {
@@ -202,106 +207,112 @@ function TextFileNode({ node, expanded = false }: { node: CanvasNodeState; expan
202
207
  return <div style={{ color: 'var(--c-dim)', fontStyle: 'italic', padding: '12px' }}>No file path set</div>;
203
208
  }
204
209
 
205
- return (
210
+ const toolbar = (
206
211
  <div
207
212
  style={{
208
213
  display: 'flex',
209
- flexDirection: 'column',
210
- height: '100%',
211
- fontFamily: 'var(--font-code)',
212
- fontSize: expanded ? '13px' : '11px',
214
+ alignItems: 'center',
215
+ gap: '8px',
216
+ minWidth: 0,
217
+ padding: expanded ? '6px 10px' : 0,
218
+ flexShrink: 0,
213
219
  }}
214
220
  >
215
- {/* Header bar */}
216
- <div
217
- style={{
218
- display: 'flex',
219
- alignItems: 'center',
220
- gap: '8px',
221
- padding: '6px 10px',
222
- borderBottom: '1px solid var(--c-line)',
223
- flexShrink: 0,
224
- }}
225
- >
221
+ <div class="file-toolbar-metadata">
226
222
  <span
227
223
  style={{
228
- fontSize: '9px',
224
+ fontSize: 'var(--fs-meta)',
229
225
  padding: '1px 5px',
230
- background: 'color-mix(in srgb, var(--c-accent) 12%, transparent)',
231
- color: 'var(--c-accent)',
232
- borderRadius: '3px',
226
+ background: 'var(--c-panel-soft)',
227
+ color: 'var(--c-muted)',
228
+ borderRadius: 'var(--r-control)',
233
229
  fontWeight: 600,
234
230
  }}
235
231
  >
236
232
  {lang}
237
233
  </span>
238
- <span
239
- style={{
240
- color: 'var(--c-text-soft)',
241
- fontSize: expanded ? '12px' : '10px',
242
- overflow: 'hidden',
243
- textOverflow: 'ellipsis',
244
- whiteSpace: 'nowrap',
245
- flex: 1,
246
- }}
247
- >
248
- {filePath}
249
- </span>
234
+ {(expanded || title !== filePath.split(/[\\/]/).pop()) && (
235
+ <span
236
+ style={{
237
+ color: 'var(--c-text-soft)',
238
+ fontSize: expanded ? 'var(--fs-ui)' : 'var(--fs-meta)',
239
+ overflow: 'hidden',
240
+ textOverflow: 'ellipsis',
241
+ whiteSpace: 'nowrap',
242
+ flex: 1,
243
+ }}
244
+ >
245
+ {expanded ? filePath : filePath.split(/[\\/]/).pop()}
246
+ </span>
247
+ )}
250
248
  {lineCount !== undefined && (
251
- <span style={{ color: 'var(--c-dim)', fontSize: '10px', flexShrink: 0 }}>{lineCount} lines</span>
249
+ <span style={{ color: 'var(--c-dim)', fontSize: 'var(--fs-meta)', flexShrink: 0 }}>{lineCount} lines</span>
252
250
  )}
253
- {updatedAt && (
254
- <span style={{ color: 'var(--c-dim)', fontSize: '10px', flexShrink: 0 }}>
251
+ {expanded && updatedAt && (
252
+ <span style={{ color: 'var(--c-dim)', fontSize: 'var(--fs-meta)', flexShrink: 0 }}>
255
253
  {new Date(updatedAt).toLocaleTimeString()}
256
254
  </span>
257
255
  )}
258
- <BarHint label="Mark this file as AX evidence" align="end" fitWithin=".node-content">
259
- <button
260
- type="button"
261
- class="ax-node-action"
262
- aria-label="Mark this file as AX evidence"
263
- onClick={(e) => {
264
- e.stopPropagation();
265
- void runNodeAxInteraction(
266
- node,
267
- 'ax.evidence.add',
268
- { kind: 'file', title: filePath.split('/').pop() || filePath, ref: filePath },
269
- 'Marked as evidence',
270
- );
271
- }}
272
- style={{
273
- background: 'none',
274
- border: 'none',
275
- color: 'var(--c-muted)',
276
- cursor: 'pointer',
277
- padding: '2px 4px',
278
- fontSize: '12px',
279
- flexShrink: 0,
280
- }}
281
- >
282
- <IconPlusCircle size={14} />
283
- </button>
284
- </BarHint>
285
- <BarHint label="Reload file" align="end" fitWithin=".node-content">
286
- <button
287
- type="button"
288
- onClick={handleReload}
289
- aria-label="Reload file"
290
- style={{
291
- background: 'none',
292
- border: 'none',
293
- color: 'var(--c-muted)',
294
- cursor: 'pointer',
295
- padding: '2px 4px',
296
- fontSize: '12px',
297
- flexShrink: 0,
298
- }}
299
- >
300
- <IconRefresh size={14} />
301
- </button>
302
- </BarHint>
303
256
  </div>
257
+ <BarHint label="Mark this file as AX evidence" align="end" fitWithin=".node-content">
258
+ <button
259
+ type="button"
260
+ class="ax-node-action"
261
+ aria-label="Mark this file as AX evidence"
262
+ onClick={(e) => {
263
+ e.stopPropagation();
264
+ void runNodeAxInteraction(
265
+ node,
266
+ 'ax.evidence.add',
267
+ { kind: 'file', title: filePath.split('/').pop() || filePath, ref: filePath },
268
+ 'Marked as evidence',
269
+ );
270
+ }}
271
+ style={{
272
+ background: 'none',
273
+ border: 'none',
274
+ color: 'var(--c-muted)',
275
+ cursor: 'pointer',
276
+ padding: '2px 4px',
277
+ fontSize: '12px',
278
+ flexShrink: 0,
279
+ }}
280
+ >
281
+ <IconPlusCircle size={14} />
282
+ </button>
283
+ </BarHint>
284
+ <BarHint label="Reload file" align="end" fitWithin=".node-content">
285
+ <button
286
+ type="button"
287
+ onClick={handleReload}
288
+ aria-label="Reload file"
289
+ style={{
290
+ background: 'none',
291
+ border: 'none',
292
+ color: 'var(--c-muted)',
293
+ cursor: 'pointer',
294
+ padding: '2px 4px',
295
+ fontSize: '12px',
296
+ flexShrink: 0,
297
+ }}
298
+ >
299
+ <IconRefresh size={14} />
300
+ </button>
301
+ </BarHint>
302
+ </div>
303
+ );
304
304
 
305
+ return (
306
+ <div
307
+ style={{
308
+ display: 'flex',
309
+ flexDirection: 'column',
310
+ height: '100%',
311
+ fontFamily: 'var(--font-code)',
312
+ fontSize: expanded ? '13px' : 'var(--fs-ui)',
313
+ }}
314
+ >
315
+ {header ? createPortal(toolbar, header) : toolbar}
305
316
  {/* Content area */}
306
317
  <div
307
318
  style={{
@@ -3,10 +3,11 @@ import { HTML_SURFACE_PUSH_SOURCE } from '../../shared/ax-surface-protocol.js';
3
3
  import { axSurfaceState, canvasTheme } from '../state/canvas-store';
4
4
  import type { CanvasNodeState } from '../types';
5
5
  import { nodeSurfaceUrl, surfaceContentHash } from './surface-url';
6
- import { RefreshingViewerFrame } from './McpAppNode';
6
+ import { RefreshingViewerFrame, waitForViewerPaint } from './ViewerFrame';
7
7
  import { useAxSurfaceBridge } from './use-ax-surface-bridge';
8
8
  import { useIframeContentHeight } from './use-iframe-content-height';
9
9
  import { useSurfaceFrame } from './use-surface-frame';
10
+ import { usePrimitiveJson } from './primitive-copy';
10
11
 
11
12
  export function shouldShowPresentationControls(node: CanvasNodeState): boolean {
12
13
  return node.type === 'html' && node.data.presentation === true;
@@ -36,8 +37,6 @@ export function HtmlNode({
36
37
  const iframeRef = useRef<HTMLIFrameElement>(null);
37
38
  const theme = canvasTheme.value;
38
39
  const axCapabilitySignature = htmlAxCapabilitySignature(node.data.axCapabilities);
39
- // Stable per-mount nonce that authorizes parent → iframe theme-update messages.
40
- const themeToken = useMemo(() => `theme-${crypto.randomUUID()}`, []);
41
40
  // Rotate the nonce when capabilities change: both the URL and injected srcdoc
42
41
  // change, rebootstrapping the bridge and rejecting emits from the old document.
43
42
  const axToken = useMemo(() => `ax-${crypto.randomUUID()}`, [axCapabilitySignature]);
@@ -50,6 +49,9 @@ export function HtmlNode({
50
49
  ? node.data.content
51
50
  : '';
52
51
  const v = useMemo(() => surfaceContentHash(html), [html]);
52
+ // A replacement must not answer a copy request with the old document's data.
53
+ const themeToken = useMemo(() => `theme-${crypto.randomUUID()}`, [html]);
54
+ usePrimitiveJson(node, themeToken, iframeRef, expanded);
53
55
 
54
56
  // The in-canvas iframe and the "Open as site" tab load the SAME server-rendered
55
57
  // surface URL (/api/canvas/surface/:id) — one render path, no content fork.
@@ -77,7 +79,7 @@ export function HtmlNode({
77
79
 
78
80
  // Grow the node to fit the surface's reported content height (grow-only, gated).
79
81
  // Never in the expanded overlay — there the surface fills the large overlay frame.
80
- useIframeContentHeight(node, iframeRef, expanded ? '' : frameToken);
82
+ const measureContent = useIframeContentHeight(node, iframeRef, expanded ? '' : frameToken);
81
83
 
82
84
  // Phase 3 HTML bridge — the shared sandboxed-surface trust boundary (M2).
83
85
  useAxSurfaceBridge({ enabled: true, token: axToken, nodeId: node.id, sourceSurface: 'html-node', iframeRef });
@@ -121,38 +123,8 @@ export function HtmlNode({
121
123
  return () => window.clearTimeout(id);
122
124
  }, [autoFocus, surfaceSrc]);
123
125
 
124
- const handleDocumentLoad = (frame: HTMLIFrameElement, signal: AbortSignal): Promise<boolean> => {
125
- if (signal.aborted) return Promise.resolve(false);
126
- return new Promise((resolve) => {
127
- const finish = (ready: boolean) => {
128
- clearTimeout(timer);
129
- window.removeEventListener('message', receive);
130
- signal.removeEventListener('abort', cancel);
131
- resolve(ready);
132
- };
133
- const cancel = () => finish(false);
134
- const receive = (event: MessageEvent) => {
135
- if (
136
- event.source !== frame.contentWindow ||
137
- event.data?.source !== HTML_SURFACE_PUSH_SOURCE ||
138
- event.data?.token !== themeToken
139
- )
140
- return;
141
- // A healthy offscreen frame can wait for paint without a deadline.
142
- if (event.data.type === 'mounted') clearTimeout(timer);
143
- if (event.data.type === 'ready') finish(true);
144
- };
145
- const timer = setTimeout(cancel, 10_000);
146
- window.addEventListener('message', receive);
147
- signal.addEventListener('abort', cancel, { once: true });
148
- frame.contentWindow?.postMessage(
149
- { source: HTML_SURFACE_PUSH_SOURCE, type: 'check-ready', token: themeToken },
150
- '*',
151
- );
152
- });
153
- };
154
-
155
126
  const handleFrameLoad = () => {
127
+ measureContent();
156
128
  iframeRef.current?.contentWindow?.postMessage(
157
129
  {
158
130
  source: HTML_SURFACE_PUSH_SOURCE,
@@ -205,7 +177,7 @@ export function HtmlNode({
205
177
  allow=""
206
178
  tabIndex={autoFocus ? 0 : undefined}
207
179
  onLoad={handleFrameLoad}
208
- onDocumentLoad={handleDocumentLoad}
180
+ onDocumentLoad={(frame, signal) => waitForViewerPaint(frame, themeToken, signal)}
209
181
  />
210
182
  );
211
183
  }
@@ -27,22 +27,36 @@ export function LedgerNode({ node }: { node: CanvasNodeState }) {
27
27
  <div style={{ display: 'flex', flexDirection: 'column', gap: '4px', fontSize: '12px' }}>
28
28
  {lines.length > 0 && (
29
29
  <div style={{ display: 'flex', flexDirection: 'column' }}>
30
- {lines.map((line, i) => (
31
- <div
32
- key={i}
33
- style={{
34
- padding: '3px 0',
35
- borderBottom: i < lines.length - 1 ? '1px solid rgba(45,55,90,0.3)' : 'none',
36
- color: 'var(--c-text)',
37
- fontFamily: 'var(--font-code)',
38
- fontSize: '11px',
39
- whiteSpace: 'pre-wrap',
40
- wordBreak: 'break-word',
41
- }}
42
- >
43
- {line}
44
- </div>
45
- ))}
30
+ {lines.map((line, i) => {
31
+ const timed = /^(\d{2}:\d{2}(?::\d{2})?)\s+(.+)$/.exec(line);
32
+ return (
33
+ <div
34
+ key={i}
35
+ style={{
36
+ display: 'grid',
37
+ gridTemplateColumns: timed ? '44px 1fr' : '1fr',
38
+ gap: '10px',
39
+ padding: '3px 0',
40
+ color: 'var(--c-text)',
41
+ fontFamily: 'var(--font-ui)',
42
+ fontSize: 'var(--fs-ui)',
43
+ whiteSpace: 'pre-wrap',
44
+ wordBreak: 'break-word',
45
+ }}
46
+ >
47
+ {timed ? (
48
+ <>
49
+ <span style={{ fontFamily: 'var(--font-code)', fontSize: 'var(--fs-meta)', color: 'var(--c-dim)' }}>
50
+ {timed[1]}
51
+ </span>
52
+ <span>{timed[2]}</span>
53
+ </>
54
+ ) : (
55
+ line
56
+ )}
57
+ </div>
58
+ );
59
+ })}
46
60
  </div>
47
61
  )}
48
62
  {entries.map(([key, value]) => (
@@ -53,7 +67,7 @@ export function LedgerNode({ node }: { node: CanvasNodeState }) {
53
67
  justifyContent: 'space-between',
54
68
  gap: '8px',
55
69
  padding: '3px 0',
56
- borderBottom: '1px solid rgba(45,55,90,0.3)',
70
+ borderBottom: '1px solid var(--c-line)',
57
71
  }}
58
72
  >
59
73
  <span style={{ color: 'var(--c-muted)', fontSize: '11px', flexShrink: 0 }}>
@@ -6,7 +6,7 @@ import { IconArrowLeft } from '../icons';
6
6
  import { expandNode, nodes, updateNodeData } from '../state/canvas-store';
7
7
  import { fetchFile, renderMarkdown, updateNodeFromClient } from '../state/intent-bridge';
8
8
  import type { CanvasNodeState } from '../types';
9
- import { activeBoard, setBoardReadme, openMemoryTarget, boardList } from '../state/boards-store';
9
+ import { openMemoryTarget, boardList } from '../state/boards-store';
10
10
  import { showToast } from '../state/attention-bridge';
11
11
  import { MdFormatBar } from './MdFormatBar';
12
12
  import { handleFormatShortcut, handleTab } from './md-format';
@@ -189,7 +189,6 @@ export async function waitForMarkdownSave(boardId: string | null, nodeId: string
189
189
  }
190
190
 
191
191
  export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState; expanded?: boolean }) {
192
- const board = activeBoard();
193
192
  const boardId = activeBoardId.value;
194
193
  const draftKey = JSON.stringify([boardId, node.id]);
195
194
  const draft = useMemo(() => {
@@ -277,10 +276,8 @@ export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState
277
276
  if (!renderingDraft && !draft.dirty.value) {
278
277
  latestMdRef.current = raw;
279
278
  setContent(raw);
280
- updateNodeData(node.id, { content: raw, rendered: html });
281
- } else if (nodes.value.get(node.id)?.data.content === raw) {
282
- // A pending save may already contain this text; cache only its HTML.
283
- updateNodeData(node.id, { rendered: html });
279
+ // The HTML cache is local. Publishing each preview redraws the whole board.
280
+ if (nodes.value.get(node.id)?.data.content !== raw) updateNodeData(node.id, { content: raw });
284
281
  }
285
282
  })();
286
283
  return () => {
@@ -304,10 +301,10 @@ export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState
304
301
 
305
302
  const persistContent = useCallback(
306
303
  async (newContent: string) => {
307
- // Human wins over already-observed work, not work arriving while this
308
- // particular attempt waits in the queue or for its rendered preview.
304
+ // A peer update cannot grant an older draft permission to overwrite it.
305
+ // Only our own successful saves advance the draft's revision.
309
306
  const incarnation = boardIncarnation;
310
- const attempt = { revision: nodes.value.get(node.id)?.contentRevision ?? 0 };
307
+ const attempt = { revision: editBase.current.revision };
311
308
  draft.nativeSaveAttempts.add(attempt);
312
309
  draft.pending.value++;
313
310
  // Order the complete save, including disk writes and rendering. A later
@@ -377,6 +374,7 @@ export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState
377
374
  if (result.ok && result.contentRevision !== undefined) {
378
375
  // Advance only through a successful predecessor in this board/card's
379
376
  // queue. An external revision or a refused save grants no retry.
377
+ editBase.current.revision = result.contentRevision;
380
378
  for (const queued of draft.nativeSaveAttempts) {
381
379
  if (queued.revision === expectedContentRevision) queued.revision = result.contentRevision;
382
380
  }
@@ -523,7 +521,7 @@ export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState
523
521
  <div
524
522
  style={{
525
523
  padding: '4px 8px',
526
- fontSize: '10px',
524
+ fontSize: 'var(--fs-meta)',
527
525
  background: 'color-mix(in srgb, var(--c-ok) 10%, transparent)',
528
526
  color: 'var(--c-ok)',
529
527
  borderBottom: '1px solid color-mix(in srgb, var(--c-ok) 20%, transparent)',
@@ -699,21 +697,13 @@ export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState
699
697
  {String((node.data.source as Record<string, unknown>).reference ?? 'Location not supplied')}
700
698
  </div>
701
699
  )}
702
- <div class="md-card-actions">
703
- {board && (
704
- <button
705
- type="button"
706
- class="md-readme-btn"
707
- aria-pressed={board.readmeNodeId === node.id}
708
- onClick={() => void setBoardReadme(board.id, board.readmeNodeId === node.id ? null : node.id)}
709
- >
710
- {board.readmeNodeId === node.id ? 'README' : 'Set as README'}
700
+ {node.data.display !== 'heading' && (
701
+ <div class="md-card-actions">
702
+ <button type="button" class="md-card-edit" onClick={() => expandNode(node.id)}>
703
+ Edit
711
704
  </button>
712
- )}
713
- <button type="button" class="md-card-edit" onClick={() => expandNode(node.id)}>
714
- Edit
715
- </button>
716
- </div>
705
+ </div>
706
+ )}
717
707
  </div>
718
708
  );
719
709
  }