pmx-canvas 0.11.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 +440 -18
- package/CHANGELOG.md +37 -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-p8dtp6va.js → abnfDiagram-N423BO3Z-cwtsds5d.js} +1 -1
- package/dist/canvas/chunks/architecture-TIHT7OUA-x63cwejs.js +1 -0
- package/dist/canvas/chunks/{architectureDiagram-T3A2C74G-5jhmxrzf.js → architectureDiagram-T3A2C74G-b4xc9tpz.js} +3 -3
- package/dist/canvas/chunks/{blockDiagram-VBNYF7ZC-pw1fa9yb.js → blockDiagram-VBNYF7ZC-ahp3yxxs.js} +7 -7
- package/dist/canvas/chunks/{c4Diagram-5PPSVZJV-x07nq0tt.js → c4Diagram-5PPSVZJV-nappnay7.js} +4 -4
- 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-nm39npq0.js → cose-bilkent-JH36ORCC-a428syda.js} +1 -1
- package/dist/canvas/chunks/cynefin-VYW2F7L2-8v6jxfz8.js +1 -0
- package/dist/canvas/chunks/{cynefinDiagram-MW4NZA55-vdxrwahz.js → cynefinDiagram-MW4NZA55-nspsqebj.js} +1 -1
- package/dist/canvas/chunks/{dagre-VZM6K2ZE-bqdm7wpd.js → dagre-VZM6K2ZE-8y6177fh.js} +2 -2
- package/dist/canvas/chunks/{diagram-7IWD3JNH-gs5gpr93.js → diagram-7IWD3JNH-vym028wn.js} +4 -4
- package/dist/canvas/chunks/{diagram-B4RE2ZJO-cgwjg47s.js → diagram-B4RE2ZJO-jddqb8sy.js} +1 -1
- package/dist/canvas/chunks/{diagram-LBJQPF4R-w3vahpav.js → diagram-LBJQPF4R-bjwbpkrn.js} +1 -1
- package/dist/canvas/chunks/{diagram-Q27KOJAE-42837z6h.js → diagram-Q27KOJAE-j6ph6hcx.js} +2 -2
- package/dist/canvas/chunks/{diagram-UB23O5K3-4fz83q59.js → diagram-UB23O5K3-p09w8jej.js} +1 -1
- package/dist/canvas/chunks/{ebnfDiagram-BXEA7PRR-zphtgegj.js → ebnfDiagram-BXEA7PRR-j975ycq5.js} +1 -1
- package/dist/canvas/chunks/{erDiagram-JOGREHBK-zvbbdxp4.js → erDiagram-JOGREHBK-sxp6hjn8.js} +5 -5
- 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-282jzycm.js → ganttDiagram-PKOTCBZU-4tv230y2.js} +2 -2
- package/dist/canvas/chunks/gitGraph-TEB2WS4Q-macbhand.js +1 -0
- package/dist/canvas/chunks/{gitGraphDiagram-DS77QQ5N-vqqy6p1b.js → gitGraphDiagram-DS77QQ5N-mqgmnw9g.js} +1 -1
- package/dist/canvas/chunks/{index-wgv7en21.js → index-037z5dz2.js} +2 -2
- package/dist/canvas/chunks/{index-w2mra17t.js → index-081n3har.js} +1 -1
- package/dist/canvas/chunks/{index-353m7b0p.js → index-5n03dmb9.js} +1 -1
- package/dist/canvas/chunks/{index-yw8h9vha.js → index-60pgzdqe.js} +1 -1
- package/dist/canvas/chunks/index-8g1vb57n.js +2 -0
- package/dist/canvas/chunks/{index-vv56h019.js → index-8rjes9r6.js} +1 -1
- package/dist/canvas/chunks/{index-nprm96xp.js → index-9022d1n9.js} +1 -1
- package/dist/canvas/chunks/{index-194m3hc3.js → index-9b02042t.js} +1 -1
- package/dist/canvas/chunks/{index-0rk4gp1g.js → index-ap4q4vez.js} +1 -1
- package/dist/canvas/chunks/{index-rh7nv68n.js → index-dyp2nhd3.js} +1 -1
- package/dist/canvas/chunks/index-frvta4tm.js +2 -0
- package/dist/canvas/chunks/{index-s4j678gj.js → index-h9ycj8n2.js} +1 -1
- package/dist/canvas/chunks/{index-fjtdggjn.js → index-mergmj97.js} +2 -2
- package/dist/canvas/chunks/index-nwsya6dj.js +301 -0
- package/dist/canvas/chunks/{index-3cy1bzwh.js → index-nz8qbd1p.js} +1 -1
- package/dist/canvas/chunks/{index-d3b3gqe9.js → index-qhfrazv3.js} +1 -1
- package/dist/canvas/chunks/{index-6qmsnxwy.js → index-v119nznk.js} +4 -4
- package/dist/canvas/chunks/{index-r2fyc9w1.js → index-vpt37m3d.js} +6 -6
- package/dist/canvas/chunks/{index-qj8fxwsf.js → index-y9ma6azy.js} +1 -1
- package/dist/canvas/chunks/{index-tb1wf525.js → index-zx0j3a2z.js} +26 -26
- package/dist/canvas/chunks/info-DKCQHKI2-a0ykzs9z.js +1 -0
- package/dist/canvas/chunks/{infoDiagram-6WML65LV-v1yvggqj.js → infoDiagram-6WML65LV-qv97qq6a.js} +2 -2
- package/dist/canvas/chunks/ishikawaDiagram-WSZJBQD7-p9306gh0.js +70 -0
- package/dist/canvas/chunks/{journeyDiagram-NVQOT4AX-zjcffveh.js → journeyDiagram-NVQOT4AX-sv67zats.js} +5 -5
- package/dist/canvas/chunks/{kanban-definition-27J2QSJJ-dakqtfp1.js → kanban-definition-27J2QSJJ-k2pfam6p.js} +1 -1
- package/dist/canvas/chunks/{mermaid.core-j2geswrd.js → mermaid.core-83r0fdce.js} +4 -4
- package/dist/canvas/chunks/{mindmap-definition-FAOFIHXS-142xhr3k.js → mindmap-definition-FAOFIHXS-vg2newm1.js} +1 -1
- package/dist/canvas/chunks/packet-7NZHBO7P-tqnabcdv.js +1 -0
- package/dist/canvas/chunks/{pegDiagram-VL7TDLO6-5wvk7vsd.js → pegDiagram-VL7TDLO6-k2h7zc5n.js} +1 -1
- package/dist/canvas/chunks/pie-RZYD4A2V-wke6gyhe.js +1 -0
- package/dist/canvas/chunks/{pieDiagram-7S7Q4E2Y-ztdhwycc.js → pieDiagram-7S7Q4E2Y-hg169p1v.js} +2 -2
- package/dist/canvas/chunks/{quadrantDiagram-CIZ2JOQS-c5p9gmg6.js → quadrantDiagram-CIZ2JOQS-bxtvsq0b.js} +5 -5
- 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-xkmqkjwf.js → railroadDiagram-AXF67PYL-njyhcp4p.js} +1 -1
- package/dist/canvas/chunks/{requirementDiagram-LRYGKXZP-9wm2dyaw.js → requirementDiagram-LRYGKXZP-2z6v09gm.js} +4 -4
- package/dist/canvas/chunks/{sankeyDiagram-W5VNT64P-2w19etgb.js → sankeyDiagram-W5VNT64P-15mzam0e.js} +1 -1
- package/dist/canvas/chunks/{sequenceDiagram-SI44F4Z6-0jn0vwmz.js → sequenceDiagram-SI44F4Z6-rbshyd2c.js} +12 -12
- package/dist/canvas/chunks/{sizeCapture-X5ZJPWSS-x75epwdq.js → sizeCapture-X5ZJPWSS-sg26xwts.js} +1 -1
- package/dist/canvas/chunks/{stateDiagram-OKZ733FA-schjpy6d.js → stateDiagram-OKZ733FA-6eahp98e.js} +1 -1
- package/dist/canvas/chunks/stateDiagram-v2-UEYNNEHI-tty0ggn5.js +1 -0
- package/dist/canvas/chunks/{swimlanes-SLNWSIFB-gkw4xce3.js → swimlanes-SLNWSIFB-ze5db10t.js} +1 -1
- package/dist/canvas/chunks/swimlanesDiagram-ULZ7WXOC-thze75gq.js +8 -0
- package/dist/canvas/chunks/{timeline-definition-Z64GVDOM-x7nkcy01.js → timeline-definition-Z64GVDOM-vnp7jyy8.js} +3 -3
- 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-t1j52t9r.js → wardleyDiagram-T6FBY63Y-8nxg8wqt.js} +4 -4
- package/dist/canvas/chunks/{xychartDiagram-ELKLHX3M-38t16pme.js → xychartDiagram-ELKLHX3M-nj921e7s.js} +5 -5
- package/dist/canvas/global.css +94 -1
- package/dist/canvas/index.js +154 -145
- package/dist/canvas/mcp-app.html +600 -498
- package/dist/json-render/index.css +1 -1
- package/dist/types/client/canvas/BoardMoveDialog.d.ts +2 -0
- package/dist/types/client/canvas/EdgeEditor.d.ts +19 -0
- package/dist/types/client/canvas/GroupNavigation.d.ts +2 -0
- package/dist/types/client/canvas/TextPrompt.d.ts +4 -0
- package/dist/types/client/nodes/PromptNode.d.ts +1 -0
- package/dist/types/client/nodes/ViewerFrame.d.ts +1 -1
- package/dist/types/client/nodes/WorkCard.d.ts +7 -0
- package/dist/types/client/nodes/use-ax-surface-bridge.d.ts +1 -0
- package/dist/types/client/state/canvas-store.d.ts +15 -0
- package/dist/types/client/state/human-store.d.ts +2 -0
- package/dist/types/client/state/intent-bridge.d.ts +4 -2
- 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/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 +84 -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 +16 -5
- 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/registry.d.ts +2 -0
- 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 -0
- package/dist/types/shared/human-presence.d.ts +1 -0
- package/dist/types/shared/lifecycle-status.d.ts +2 -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/GuestName.dc.html +50 -0
- package/docs/design/PluginLogo.svg +7 -0
- package/docs/design/WorkCards.dc.html +39 -0
- package/docs/design/canvas.json +16 -0
- package/docs/design/plugin-logo.png +0 -0
- package/docs/design.md +111 -8
- package/docs/evals/agents-md-sections.md +38 -0
- package/docs/http-api.md +128 -10
- package/docs/mcp.md +61 -9
- package/docs/node-types.md +71 -1
- package/docs/plans/plan-009-tech-debt-backlog.md +1 -1
- package/docs/plans/plan-019-post-0.9-roadmap.md +44 -20
- package/docs/plans/plan-020-wave-5-work-planning.md +553 -0
- package/docs/product-vision-2026-09.md +33 -17
- package/docs/sdk.md +18 -0
- package/package.json +6 -3
- 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 +440 -18
- 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 -842
- package/skills/pmx-canvas/evals/evals.json +26 -3
- package/skills/pmx-canvas/references/full-reference.md +80 -20
- 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 -75
- 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/BoardMoveDialog.tsx +225 -0
- package/src/client/canvas/CanvasNode.tsx +45 -2
- package/src/client/canvas/CanvasViewport.tsx +38 -9
- package/src/client/canvas/ContextMenu.tsx +34 -12
- package/src/client/canvas/EdgeEditor.tsx +149 -0
- package/src/client/canvas/EdgeLayer.tsx +87 -16
- package/src/client/canvas/ExpandedNodeOverlay.tsx +4 -0
- package/src/client/canvas/GroupNavigation.tsx +85 -0
- 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 +30 -0
- package/src/client/canvas/canvas-area.ts +1 -1
- package/src/client/nodes/ExtAppFrame.tsx +26 -10
- package/src/client/nodes/MarkdownNode.tsx +6 -7
- package/src/client/nodes/PromptNode.tsx +32 -3
- package/src/client/nodes/StatusNode.tsx +12 -0
- package/src/client/nodes/StatusSummary.tsx +11 -0
- package/src/client/nodes/ViewerFrame.tsx +21 -10
- package/src/client/nodes/WorkCard.tsx +175 -0
- package/src/client/nodes/use-ax-surface-bridge.ts +18 -14
- 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 +185 -15
- package/src/client/state/human-store.ts +22 -2
- package/src/client/state/intent-bridge.ts +19 -5
- package/src/client/state/relation-store.ts +127 -1
- package/src/client/theme/global.css +94 -1
- package/src/client/types.ts +1 -0
- 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 +19 -6
- 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-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 +792 -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 +35 -15
- package/src/server/file-watcher.ts +30 -10
- package/src/server/human-presence.ts +18 -5
- package/src/server/index.ts +35 -15
- 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 +15 -0
- 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 +44 -3
- 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/registry.ts +49 -4
- package/src/server/server.ts +62 -16
- package/src/server/tour-control.ts +37 -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 +22 -0
- package/src/shared/human-presence.ts +1 -0
- package/src/shared/lifecycle-status.ts +2 -0
- package/dist/canvas/chunks/architecture-TIHT7OUA-9tffvpsv.js +0 -1
- package/dist/canvas/chunks/classDiagram-JCYQIIEL-nc6g5x1r.js +0 -1
- package/dist/canvas/chunks/classDiagram-v2-OCEON4UE-0qnbpwvh.js +0 -1
- package/dist/canvas/chunks/cynefin-VYW2F7L2-ys8p46ts.js +0 -1
- package/dist/canvas/chunks/eventmodeling-45OFAUF4-v9q6dn4c.js +0 -1
- package/dist/canvas/chunks/flowDiagram-UKHOOZJN-yrr5z8tc.js +0 -1
- package/dist/canvas/chunks/gitGraph-TEB2WS4Q-kdwb8m0a.js +0 -1
- package/dist/canvas/chunks/index-1r72hdzb.js +0 -301
- package/dist/canvas/chunks/index-g3pwnqeb.js +0 -2
- package/dist/canvas/chunks/index-rft2hcz5.js +0 -2
- package/dist/canvas/chunks/info-DKCQHKI2-wpzs6sz3.js +0 -1
- package/dist/canvas/chunks/ishikawaDiagram-WSZJBQD7-5hnq1a9p.js +0 -70
- package/dist/canvas/chunks/packet-7NZHBO7P-xn439f0s.js +0 -1
- package/dist/canvas/chunks/pie-RZYD4A2V-0kf16rwh.js +0 -1
- package/dist/canvas/chunks/radar-I7S5WNFK-0g2pz36t.js +0 -1
- package/dist/canvas/chunks/railroad-3IZDKUUU-fcaran6j.js +0 -1
- package/dist/canvas/chunks/railroad-abnf-AHOZXSZD-wgdya41q.js +0 -1
- package/dist/canvas/chunks/railroad-ebnf-EBAXGLYW-gy07a4ka.js +0 -1
- package/dist/canvas/chunks/railroad-peg-LSFZ7HO6-ewk6wtkh.js +0 -1
- package/dist/canvas/chunks/stateDiagram-v2-UEYNNEHI-k8sfp2e7.js +0 -1
- package/dist/canvas/chunks/swimlanesDiagram-ULZ7WXOC-nqysw67j.js +0 -8
- package/dist/canvas/chunks/treeView-QDETBFTQ-cesw6gp0.js +0 -1
- package/dist/canvas/chunks/treemap-6X3UGDF4-zdv4knp9.js +0 -1
- package/dist/canvas/chunks/vennDiagram-T6HMQDX7-x8dqn9yf.js +0 -34
- package/dist/canvas/chunks/wardley-OPB4EBWU-44pdddez.js +0 -1
|
@@ -849,6 +849,31 @@ body,
|
|
|
849
849
|
color: var(--c-text-soft);
|
|
850
850
|
}
|
|
851
851
|
|
|
852
|
+
/* In-card editing is view state, never a persisted resize. */
|
|
853
|
+
.canvas-node:has(.work-card-editor) { height: auto !important; }
|
|
854
|
+
.canvas-node:has(.work-card-editor) .node-body { flex: none; overflow: visible; }
|
|
855
|
+
.work-card { display: flex; flex-direction: column; gap: 12px; }
|
|
856
|
+
.work-card-state { color: var(--c-text); font-weight: 600; }
|
|
857
|
+
.work-card-blocked .work-card-state, .work-card-state.work-card-blocked, .work-card-error { color: var(--c-warn); }
|
|
858
|
+
.work-card-done .work-card-state, .work-card-state.work-card-done { color: var(--c-ok); }
|
|
859
|
+
.work-card-cancelled .work-card-state, .work-card-state.work-card-cancelled { color: var(--c-muted); }
|
|
860
|
+
.work-card-detail { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
861
|
+
.work-card-live { color: var(--c-muted); font-size: var(--fs-meta); overflow-wrap: anywhere; }
|
|
862
|
+
.work-card-progress { color: var(--c-muted); font-size: var(--fs-meta); }
|
|
863
|
+
.work-card footer, .work-card-editor footer { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px; }
|
|
864
|
+
.work-card button, .work-card-editor button, .work-card-editor input, .work-card-editor select, .work-card-editor textarea {
|
|
865
|
+
font: inherit; color: var(--c-text); background: var(--c-input-bg); border: 1px solid var(--c-line); border-radius: var(--r-control); padding: 8px;
|
|
866
|
+
}
|
|
867
|
+
.work-card button, .work-card-editor button { cursor: pointer; }
|
|
868
|
+
.work-card button:hover, .work-card-editor button:hover { border-color: var(--c-text-soft); }
|
|
869
|
+
.work-card-editor fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
|
|
870
|
+
.work-card-editor label { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
|
|
871
|
+
.work-card-editor input, .work-card-editor select, .work-card-editor textarea { width: 100%; box-sizing: border-box; }
|
|
872
|
+
.work-card-editor textarea { min-height: 80px; resize: vertical; }
|
|
873
|
+
.work-card-editor .work-card-save { background: var(--c-accent); color: var(--c-contrast-fg); }
|
|
874
|
+
.work-card-editor :disabled { cursor: wait; opacity: 0.65; }
|
|
875
|
+
.work-card-editor :focus-visible, .work-card button:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
|
|
876
|
+
|
|
852
877
|
/* Markdown rendered content inside nodes */
|
|
853
878
|
.canvas-node .node-body h1,
|
|
854
879
|
.canvas-node .node-body h2,
|
|
@@ -1297,6 +1322,18 @@ body,
|
|
|
1297
1322
|
border-color: var(--c-line);
|
|
1298
1323
|
}
|
|
1299
1324
|
|
|
1325
|
+
.human-name-control { order: 4; flex-shrink: 0; }
|
|
1326
|
+
.human-name-button {
|
|
1327
|
+
width: 28px;
|
|
1328
|
+
height: 28px;
|
|
1329
|
+
padding: 0;
|
|
1330
|
+
border-color: var(--c-line);
|
|
1331
|
+
border-radius: var(--r-pill);
|
|
1332
|
+
background: var(--c-panel-soft);
|
|
1333
|
+
color: var(--c-text-soft);
|
|
1334
|
+
font: 600 12px var(--font-ui);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1300
1337
|
.top-bar-zoom-label {
|
|
1301
1338
|
min-width: 38px;
|
|
1302
1339
|
text-align: center;
|
|
@@ -1852,6 +1889,19 @@ body,
|
|
|
1852
1889
|
flex: 1;
|
|
1853
1890
|
min-width: 0;
|
|
1854
1891
|
}
|
|
1892
|
+
.session-show-work {
|
|
1893
|
+
margin-top: 8px;
|
|
1894
|
+
padding: 4px 8px;
|
|
1895
|
+
font: inherit;
|
|
1896
|
+
color: var(--c-text);
|
|
1897
|
+
background: var(--c-input-bg);
|
|
1898
|
+
border: 1px solid var(--c-line);
|
|
1899
|
+
border-radius: var(--r-control);
|
|
1900
|
+
cursor: pointer;
|
|
1901
|
+
}
|
|
1902
|
+
.session-show-work:hover { border-color: var(--c-text-soft); }
|
|
1903
|
+
.session-show-work:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
|
|
1904
|
+
.session-show-work:disabled { cursor: wait; opacity: 0.65; }
|
|
1855
1905
|
.session-item-title {
|
|
1856
1906
|
display: block;
|
|
1857
1907
|
width: 100%;
|
|
@@ -4772,7 +4822,7 @@ html.is-node-resizing .ext-app-preview-catcher {
|
|
|
4772
4822
|
background: var(--c-input-bg);
|
|
4773
4823
|
color: var(--c-text);
|
|
4774
4824
|
}
|
|
4775
|
-
.relation-legend { position: absolute; top: 8px; left: 12px; right: 12px; display: flex; flex-wrap: wrap; align-content: flex-start; gap: 6px; max-height: min(180px, 25%); overflow-x: hidden; overflow-y: auto; }
|
|
4825
|
+
.relation-legend { position: absolute; top: 8px; left: 12px; right: 12px; display: flex; flex-wrap: wrap; align-content: flex-start; gap: 6px; max-height: min(180px, 25%); overflow-x: hidden; overflow-y: auto; pointer-events: none; }
|
|
4776
4826
|
.lifecycle-filters ~ .relation-legend { top: 48px; }
|
|
4777
4827
|
.relation-legend > * { pointer-events: auto; flex-shrink: 0; max-width: 100%; height: 24px; box-sizing: border-box; border: 1px solid var(--c-line); border-radius: var(--r-control); background: var(--c-panel); color: var(--c-text); font: 500 11px var(--font-ui); padding: 0 9px; cursor: pointer; }
|
|
4778
4828
|
.relation-legend select { background: var(--c-panel-soft); font-weight: 600; padding: 0 10px; }
|
|
@@ -4780,6 +4830,31 @@ html.is-node-resizing .ext-app-preview-catcher {
|
|
|
4780
4830
|
.relation-legend button[aria-pressed="true"] { border-color: var(--relation-ink); }
|
|
4781
4831
|
.relation-swatch { width: 14px; height: 2.5px; border-radius: 2px; background: var(--relation-ink); }
|
|
4782
4832
|
.relation-count { color: var(--c-muted); font-variant-numeric: tabular-nums; }
|
|
4833
|
+
.relation-legend > span { display: flex; align-items: center; cursor: default; }
|
|
4834
|
+
.relation-legend .relation-warning { color: var(--c-warn); }
|
|
4835
|
+
.edge-editor { position: fixed; z-index: 1000; box-sizing: border-box; padding: 3px; border: 1px solid var(--c-line); border-radius: 8px; background: var(--c-panel); color: var(--c-text); box-shadow: var(--e-1); font: 500 11px var(--font-ui); }
|
|
4836
|
+
.edge-editor fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
|
|
4837
|
+
.edge-editor-tools { display: flex; gap: 3px; }
|
|
4838
|
+
.edge-editor-tools select { flex: 1; min-width: 0; }
|
|
4839
|
+
.edge-editor button, .edge-editor select, .relation-navigation button, .group-breadcrumbs button { min-height: 24px; border: 1px solid var(--c-line); border-radius: var(--r-control); padding: 3px 7px; background: var(--c-panel-soft); color: var(--c-text); font: inherit; cursor: pointer; }
|
|
4840
|
+
.edge-editor button:hover, .group-breadcrumbs button:hover, .relation-navigation button:hover { background: var(--c-hover); }
|
|
4841
|
+
.edge-editor-field { display: grid; gap: 8px; padding: 8px; }
|
|
4842
|
+
.edge-editor-field label { display: grid; gap: 4px; }
|
|
4843
|
+
.edge-editor input { box-sizing: border-box; width: 100%; min-width: 0; padding: 6px; border: 1px solid var(--c-line); border-radius: var(--r-control); color: var(--c-text); background: var(--c-input-bg); font: inherit; }
|
|
4844
|
+
.edge-editor p { margin: 6px; color: var(--c-warn); }
|
|
4845
|
+
.relation-navigation { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
|
|
4846
|
+
.group-breadcrumbs { position: absolute; top: 8px; left: 12px; right: 12px; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; max-height: 64px; overflow: auto; pointer-events: auto; color: var(--c-muted); font: 500 11px var(--font-ui); }
|
|
4847
|
+
.group-breadcrumbs button[aria-current] { color: var(--c-text); cursor: default; }
|
|
4848
|
+
.group-breadcrumbs > button:last-child { margin-left: auto; }
|
|
4849
|
+
.canvas-region:has(.group-breadcrumbs) .relation-legend { top: 80px; }
|
|
4850
|
+
.canvas-region:has(.group-breadcrumbs) .lifecycle-filters { top: 80px; }
|
|
4851
|
+
.canvas-region:has(.group-breadcrumbs) .lifecycle-filters ~ .relation-legend { top: 120px; }
|
|
4852
|
+
.group-inside-frame { position: absolute; border: 1px dashed var(--c-line); border-radius: 12px; pointer-events: none; box-sizing: border-box; z-index: -6; }
|
|
4853
|
+
.group-inside-frame > span { position: absolute; top: -9px; left: 12px; padding: 0 6px; background: var(--c-bg); color: var(--c-muted); font: 500 12px var(--font-ui); }
|
|
4854
|
+
.group-outside-endpoint { position: absolute; width: 170px; height: 60px; z-index: 2; }
|
|
4855
|
+
.group-outside-label { position: absolute; top: -24px; color: var(--c-muted); font: 500 12px var(--font-ui); }
|
|
4856
|
+
.group-outside-stub { width: 100%; height: 100%; box-sizing: border-box; padding: 8px 12px; border: 1px dashed var(--c-line); border-radius: 10px; text-align: left; background: var(--c-panel); color: var(--c-text); font: 600 12px var(--font-ui); cursor: pointer; overflow: hidden; }
|
|
4857
|
+
.group-outside-stub span { display: block; margin-top: 4px; color: var(--c-muted); font: 11px var(--font-ui); }
|
|
4783
4858
|
.expanded-content-row { display: flex; flex: 1; min-height: 0; }
|
|
4784
4859
|
.expanded-content-row > .expanded-body { flex: 1; min-width: 0; }
|
|
4785
4860
|
.relations-panel {
|
|
@@ -5294,6 +5369,11 @@ html.is-node-resizing .ext-app-preview-catcher {
|
|
|
5294
5369
|
font-weight: 600;
|
|
5295
5370
|
color: var(--c-text);
|
|
5296
5371
|
}
|
|
5372
|
+
.text-prompt-description {
|
|
5373
|
+
font-size: 12px;
|
|
5374
|
+
line-height: 1.4;
|
|
5375
|
+
color: var(--c-muted);
|
|
5376
|
+
}
|
|
5297
5377
|
.text-prompt-input {
|
|
5298
5378
|
width: 100%;
|
|
5299
5379
|
padding: 8px 10px;
|
|
@@ -8830,6 +8910,19 @@ html.is-node-dragging .intent-line-layer {
|
|
|
8830
8910
|
cursor: pointer;
|
|
8831
8911
|
}
|
|
8832
8912
|
}
|
|
8913
|
+
.board-move-backdrop { padding: 20px 0; align-items: center; }
|
|
8914
|
+
.board-move-dialog {
|
|
8915
|
+
width: min(540px, calc(100% - 32px));
|
|
8916
|
+
max-height: calc(100% - 40px);
|
|
8917
|
+
overflow-y: auto;
|
|
8918
|
+
box-sizing: border-box;
|
|
8919
|
+
}
|
|
8920
|
+
.board-move-dialog form { display: flex; flex-direction: column; gap: 8px; }
|
|
8921
|
+
.board-move-dialog h2 { margin: 0 0 12px; font-size: 17px; }
|
|
8922
|
+
.board-move-dialog p { margin: 0; font-size: 12px; line-height: 1.5; color: var(--c-text-soft); }
|
|
8923
|
+
.board-move-dialog .board-move-warning { color: var(--c-warn); font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }
|
|
8924
|
+
.board-move-cards { margin: 0; max-height: 100px; overflow-y: auto; font-size: 12px; }
|
|
8925
|
+
.board-move-dialog .text-prompt-actions { margin-top: 8px; }
|
|
8833
8926
|
.board-copy-dialog,
|
|
8834
8927
|
.board-link-dialog {
|
|
8835
8928
|
width: min(540px, calc(100vw - 32px));
|
package/src/client/types.ts
CHANGED
|
@@ -115,6 +115,7 @@ export const TYPE_LABELS: Record<CanvasNodeState['type'], string> = {
|
|
|
115
115
|
/** Node types that support the full-viewport expand/focus overlay. */
|
|
116
116
|
export const EXPANDABLE_TYPES = new Set<CanvasNodeState['type']>([
|
|
117
117
|
'markdown',
|
|
118
|
+
'status',
|
|
118
119
|
'mcp-app',
|
|
119
120
|
'webpage',
|
|
120
121
|
'json-render',
|
package/src/mcp/server.ts
CHANGED
|
@@ -200,6 +200,8 @@ export function createMcpServer(): McpServer {
|
|
|
200
200
|
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
|
|
201
201
|
outputSchema: interactionResult,
|
|
202
202
|
inputSchema: {
|
|
203
|
+
targetBoardId: z.string().optional(),
|
|
204
|
+
agentId: z.string().optional(),
|
|
203
205
|
type: z
|
|
204
206
|
.enum(AX_INTERACTION_TYPES)
|
|
205
207
|
.describe('Interaction type, e.g. ax.work.create, ax.evidence.add, ax.focus.set.'),
|
|
@@ -213,13 +215,15 @@ export function createMcpServer(): McpServer {
|
|
|
213
215
|
source: z.enum(AX_SOURCES).optional().describe('Optional host/source label. Defaults to mcp.'),
|
|
214
216
|
},
|
|
215
217
|
},
|
|
216
|
-
async ({ type, sourceNodeId, payload, sourceSurface, correlationId, source }, extra) => {
|
|
218
|
+
async ({ type, sourceNodeId, payload, sourceSurface, correlationId, source, targetBoardId, agentId }, extra) => {
|
|
217
219
|
try {
|
|
218
220
|
const c = await ensureCanvas();
|
|
219
221
|
extra.signal.throwIfAborted();
|
|
220
222
|
const result = await c.invoker().invoke(
|
|
221
223
|
'ax.interaction.submit',
|
|
222
224
|
{
|
|
225
|
+
targetBoardId,
|
|
226
|
+
agentId,
|
|
223
227
|
type,
|
|
224
228
|
sourceNodeId,
|
|
225
229
|
...(payload ? { payload } : {}),
|
|
@@ -269,6 +273,8 @@ export function createMcpServer(): McpServer {
|
|
|
269
273
|
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
270
274
|
outputSchema: activityResult,
|
|
271
275
|
inputSchema: {
|
|
276
|
+
targetBoardId: z.string().optional(),
|
|
277
|
+
agentId: z.string().optional(),
|
|
272
278
|
kind: z.enum([
|
|
273
279
|
'tool-start',
|
|
274
280
|
'tool-result',
|
|
@@ -327,13 +333,15 @@ export function createMcpServer(): McpServer {
|
|
|
327
333
|
source: z.enum(AX_SOURCES).optional(),
|
|
328
334
|
},
|
|
329
335
|
},
|
|
330
|
-
async ({ kind, title, summary, outcome, ref, nodeIds, data, reactions, source }, extra) => {
|
|
336
|
+
async ({ kind, title, summary, outcome, ref, nodeIds, data, reactions, source, targetBoardId, agentId }, extra) => {
|
|
331
337
|
try {
|
|
332
338
|
const c = await ensureCanvas();
|
|
333
339
|
extra.signal.throwIfAborted();
|
|
334
340
|
const result = await c.invoker().invoke(
|
|
335
341
|
'ax.activity.ingest',
|
|
336
342
|
{
|
|
343
|
+
targetBoardId,
|
|
344
|
+
agentId,
|
|
337
345
|
kind,
|
|
338
346
|
title,
|
|
339
347
|
...(summary !== undefined ? { summary } : {}),
|
|
@@ -389,6 +397,7 @@ export function createMcpServer(): McpServer {
|
|
|
389
397
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
390
398
|
outputSchema: screenshotResult,
|
|
391
399
|
inputSchema: {
|
|
400
|
+
targetBoardId: z.string().optional().describe('Not supported: screenshots inspect the shared WebView.'),
|
|
392
401
|
format: z
|
|
393
402
|
.enum(['png', 'jpeg', 'webp'])
|
|
394
403
|
.optional()
|
|
@@ -396,8 +405,9 @@ export function createMcpServer(): McpServer {
|
|
|
396
405
|
quality: z.number().optional().describe('Optional quality for lossy formats'),
|
|
397
406
|
},
|
|
398
407
|
},
|
|
399
|
-
async ({ format, quality }, extra) => {
|
|
408
|
+
async ({ format, quality, targetBoardId }, extra) => {
|
|
400
409
|
try {
|
|
410
|
+
if (targetBoardId !== undefined) throw new Error('Screenshots inspect the shared WebView, not a scoped board.');
|
|
401
411
|
const c = await ensureCanvas();
|
|
402
412
|
extra.signal.throwIfAborted();
|
|
403
413
|
const bytes = await c.screenshotAutomationWebView(
|
|
@@ -203,6 +203,8 @@ export const PRESENCE_SET_SHAPE = {
|
|
|
203
203
|
const presenceSetSchema = z.object(PRESENCE_SET_SHAPE);
|
|
204
204
|
|
|
205
205
|
interface StoredPresence extends AgentPresence {
|
|
206
|
+
spatialBoardId: string | null;
|
|
207
|
+
sessionBoardId: string | null;
|
|
206
208
|
lastSeenMs: number;
|
|
207
209
|
/** Last explicit phase report; cursor/focus heartbeats must not keep a stale phase alive. */
|
|
208
210
|
phaseSetMs: number;
|
|
@@ -296,7 +298,7 @@ type SessionEndListener = (
|
|
|
296
298
|
export class AgentPresenceRegistry {
|
|
297
299
|
private readonly presences = new Map<string, StoredPresence>();
|
|
298
300
|
/** Newest first; bounded. Survives a writer fading — the feed is history, the writer list is presence. */
|
|
299
|
-
private activity: AgentActivityEntry
|
|
301
|
+
private activity: Array<AgentActivityEntry & { boardId: string | null }> = [];
|
|
300
302
|
private activitySeq = 0;
|
|
301
303
|
private emit: PresenceEmitter = () => {};
|
|
302
304
|
/** Single slots (like the emitter): server.ts owns the pre-session snapshot + receipt. */
|
|
@@ -435,6 +437,8 @@ export class AgentPresenceRegistry {
|
|
|
435
437
|
}
|
|
436
438
|
const existing = this.presences.get(key);
|
|
437
439
|
const stored: StoredPresence = existing ?? {
|
|
440
|
+
spatialBoardId: canvasState.activeBoardId,
|
|
441
|
+
sessionBoardId: canvasState.activeBoardId,
|
|
438
442
|
sessionId: key,
|
|
439
443
|
source: input.source,
|
|
440
444
|
agentId: input.agentId?.trim() || null,
|
|
@@ -458,6 +462,9 @@ export class AgentPresenceRegistry {
|
|
|
458
462
|
touchesCache: null,
|
|
459
463
|
};
|
|
460
464
|
const wasAttached = stored.attached;
|
|
465
|
+
if (input.op || input.cursor !== undefined || input.focusNodeId !== undefined)
|
|
466
|
+
stored.spatialBoardId = canvasState.activeBoardId;
|
|
467
|
+
if (stored.attached && stored.sessionBoardId === null) stored.sessionBoardId = canvasState.activeBoardId;
|
|
461
468
|
stored.lastSeenMs = now;
|
|
462
469
|
stored.lastSeenAt = new Date(now).toISOString();
|
|
463
470
|
if (input.label) stored.label = input.label;
|
|
@@ -466,6 +473,7 @@ export class AgentPresenceRegistry {
|
|
|
466
473
|
if (input.activity?.summary) {
|
|
467
474
|
this.activitySeq += 1;
|
|
468
475
|
this.activity.unshift({
|
|
476
|
+
boardId: canvasState.activeBoardId,
|
|
469
477
|
id: `act-${this.activitySeq}`,
|
|
470
478
|
at: stored.lastSeenAt,
|
|
471
479
|
sessionId: key,
|
|
@@ -480,6 +488,7 @@ export class AgentPresenceRegistry {
|
|
|
480
488
|
}
|
|
481
489
|
if (input.attached !== undefined) stored.attached = input.attached;
|
|
482
490
|
if (!wasAttached && input.attached === true) {
|
|
491
|
+
stored.sessionBoardId = canvasState.activeBoardId;
|
|
483
492
|
// *Start agent session* with one agent-less writer already on the board
|
|
484
493
|
// adopts that writer — the human is claiming the agent they can see.
|
|
485
494
|
if (stored.source === 'browser') {
|
|
@@ -539,13 +548,7 @@ export class AgentPresenceRegistry {
|
|
|
539
548
|
captureBaseline(stored.startBoards, stored.startedAt);
|
|
540
549
|
}
|
|
541
550
|
if (input.attached === false) {
|
|
542
|
-
if (wasAttached)
|
|
543
|
-
this.onSessionEnd(
|
|
544
|
-
this.publicView(stored, now),
|
|
545
|
-
stored.startSnapshotId,
|
|
546
|
-
input.endedBy ?? 'agent',
|
|
547
|
-
stored.startedAt,
|
|
548
|
-
);
|
|
551
|
+
if (wasAttached) this.endSession(stored, input.endedBy ?? 'agent', now);
|
|
549
552
|
// An explicit detach always removes the presence. In particular, a
|
|
550
553
|
// worker that reports attached:false must not be refreshed into another
|
|
551
554
|
// full activity TTL as an external writer.
|
|
@@ -690,13 +693,21 @@ export class AgentPresenceRegistry {
|
|
|
690
693
|
}
|
|
691
694
|
|
|
692
695
|
/** Remove a writer (session-end). */
|
|
696
|
+
private endSession(stored: StoredPresence, endedBy: 'human' | 'agent' | 'idle-timeout', now: number): void {
|
|
697
|
+
const id = stored.sessionBoardId;
|
|
698
|
+
if (id && !canvasState.listBoards().some((board) => board.id === id)) return;
|
|
699
|
+
const finish = () =>
|
|
700
|
+
this.onSessionEnd(this.publicView(stored, now), stored.startSnapshotId, endedBy, stored.startedAt);
|
|
701
|
+
if (id) canvasState.withBoard(id, finish);
|
|
702
|
+
else canvasState.withVisibleBoard(finish);
|
|
703
|
+
}
|
|
704
|
+
|
|
693
705
|
detach(sessionId: string): boolean {
|
|
694
706
|
const stored = this.presences.get(sessionId);
|
|
695
707
|
const removed = this.presences.delete(sessionId);
|
|
696
708
|
if (removed) {
|
|
697
709
|
this.dropAliasesTo(sessionId);
|
|
698
|
-
if (stored?.attached)
|
|
699
|
-
this.onSessionEnd(this.publicView(stored, Date.now()), stored.startSnapshotId, 'agent', stored.startedAt);
|
|
710
|
+
if (stored?.attached) this.endSession(stored, 'agent', Date.now());
|
|
700
711
|
this.scheduleEmit();
|
|
701
712
|
}
|
|
702
713
|
this.maybeStopSweeper();
|
|
@@ -709,7 +720,10 @@ export class AgentPresenceRegistry {
|
|
|
709
720
|
return {
|
|
710
721
|
presences,
|
|
711
722
|
sessionActive: isSessionActive(presences),
|
|
712
|
-
activity: this.activity.map((entry) => ({
|
|
723
|
+
activity: this.activity.map(({ boardId, ...entry }) => ({
|
|
724
|
+
...entry,
|
|
725
|
+
nodeId: boardId === canvasState.activeBoardId ? entry.nodeId : null,
|
|
726
|
+
})),
|
|
713
727
|
};
|
|
714
728
|
}
|
|
715
729
|
|
|
@@ -744,6 +758,8 @@ export class AgentPresenceRegistry {
|
|
|
744
758
|
startBoards: _startBoards,
|
|
745
759
|
touchesCache: _touchesCache,
|
|
746
760
|
lastActivityNodeId,
|
|
761
|
+
spatialBoardId,
|
|
762
|
+
sessionBoardId: _sessionBoardId,
|
|
747
763
|
...presence
|
|
748
764
|
} = stored;
|
|
749
765
|
if (withTouches) {
|
|
@@ -764,11 +780,15 @@ export class AgentPresenceRegistry {
|
|
|
764
780
|
// Park-at fallback (joint-gaps #3): an attached-but-focusless writer is
|
|
765
781
|
// invisible everywhere — fall back to the last node its activity touched.
|
|
766
782
|
if (!presence.focusNodeId && lastActivityNodeId) presence.focusNodeId = lastActivityNodeId;
|
|
783
|
+
if (spatialBoardId !== canvasState.activeBoardId) {
|
|
784
|
+
presence.focusNodeId = null;
|
|
785
|
+
presence.cursor = null;
|
|
786
|
+
}
|
|
767
787
|
// An attached session blocked on a human decision reads as waiting — the
|
|
768
788
|
// gate itself lives in the AX state, this is only the presence view of it.
|
|
769
789
|
// It overrides tooling too: the gate REQUEST is itself a write, and the
|
|
770
790
|
// human's decision is the state that matters while it is pending.
|
|
771
|
-
if (presence.attached && this.hasPendingGate()) {
|
|
791
|
+
if (presence.attached && spatialBoardId === canvasState.activeBoardId && this.hasPendingGate()) {
|
|
772
792
|
phase = 'waiting-approval';
|
|
773
793
|
detail = null;
|
|
774
794
|
}
|
|
@@ -824,13 +844,7 @@ export class AgentPresenceRegistry {
|
|
|
824
844
|
if (presence.lastSeenMs + ttl <= now) {
|
|
825
845
|
this.presences.delete(key);
|
|
826
846
|
this.dropAliasesTo(key);
|
|
827
|
-
if (presence.attached)
|
|
828
|
-
this.onSessionEnd(
|
|
829
|
-
this.publicView(presence, now),
|
|
830
|
-
presence.startSnapshotId,
|
|
831
|
-
'idle-timeout',
|
|
832
|
-
presence.startedAt,
|
|
833
|
-
);
|
|
847
|
+
if (presence.attached) this.endSession(presence, 'idle-timeout', now);
|
|
834
848
|
changed = true;
|
|
835
849
|
continue;
|
|
836
850
|
}
|
|
@@ -866,14 +880,16 @@ export class AgentPresenceRegistry {
|
|
|
866
880
|
if (this.emitTimer) return;
|
|
867
881
|
this.emitTimer = setTimeout(() => {
|
|
868
882
|
this.emitTimer = null;
|
|
869
|
-
|
|
883
|
+
canvasState.withVisibleBoard(() =>
|
|
884
|
+
this.emit('agent-presence', this.snapshot() as unknown as Record<string, unknown>),
|
|
885
|
+
);
|
|
870
886
|
}, 50);
|
|
871
887
|
(this.emitTimer as { unref?: () => void }).unref?.();
|
|
872
888
|
}
|
|
873
889
|
|
|
874
890
|
private ensureSweeper(): void {
|
|
875
891
|
if (this.sweepTimer || this.presences.size === 0) return;
|
|
876
|
-
this.sweepTimer = setInterval(() => this.sweep(), 1000);
|
|
892
|
+
this.sweepTimer = setInterval(() => canvasState.withVisibleBoard(() => this.sweep()), 1000);
|
|
877
893
|
(this.sweepTimer as { unref?: () => void }).unref?.();
|
|
878
894
|
}
|
|
879
895
|
|
|
@@ -894,10 +910,14 @@ export const agentPresence = new AgentPresenceRegistry();
|
|
|
894
910
|
// the operation registry are covered too.
|
|
895
911
|
// The live lens also follows card content (a person's edit takes a card out of
|
|
896
912
|
// the agent's session) and the open board — but not moves, so a drag stays quiet.
|
|
897
|
-
let lastBoardId = canvasState.
|
|
913
|
+
let lastBoardId = canvasState.visibleBoardId;
|
|
898
914
|
let lastRevision = canvasState.getContentRevision().revision;
|
|
899
915
|
canvasState.onChange((type) => {
|
|
900
|
-
|
|
916
|
+
if (canvasState.isBackgroundBoard) {
|
|
917
|
+
agentPresence.refresh();
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
const boardId = canvasState.visibleBoardId;
|
|
901
921
|
const revision = canvasState.getContentRevision().revision;
|
|
902
922
|
if (boardId !== lastBoardId) agentPresence.boardOpened();
|
|
903
923
|
else if (type === 'ax' || type === 'pins' || revision !== lastRevision) agentPresence.refresh();
|
|
@@ -111,4 +111,10 @@ export function advanceAxFlowLoops(): void {
|
|
|
111
111
|
canvasState.setWorkItemsChangedListener(() => {
|
|
112
112
|
refreshWorkboardNodes();
|
|
113
113
|
advanceAxFlowLoops();
|
|
114
|
+
// Task title/detail changes also repaint explicitly presented live cards.
|
|
115
|
+
if (
|
|
116
|
+
canvasState.getLayout().nodes.some((node) => node.type === 'status' && typeof node.data.workItemId === 'string')
|
|
117
|
+
) {
|
|
118
|
+
emitCanvasLayoutUpdate();
|
|
119
|
+
}
|
|
114
120
|
});
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { formatCountdown } from '../shared/approval-gates.js';
|
|
13
13
|
import { canvasState } from './canvas-state.js';
|
|
14
|
+
import { withCurrentActor } from './attribution.js';
|
|
14
15
|
|
|
15
16
|
type GateEmitter = (event: string, payload: Record<string, unknown>) => void;
|
|
16
17
|
|
|
@@ -50,7 +51,13 @@ export function sweepExpiredGates(now = Date.now()): string[] {
|
|
|
50
51
|
export function startGateTtlSweeper(emitter: GateEmitter): void {
|
|
51
52
|
emit = emitter;
|
|
52
53
|
if (sweepTimer) return;
|
|
53
|
-
sweepTimer = setInterval(
|
|
54
|
+
sweepTimer = setInterval(
|
|
55
|
+
() =>
|
|
56
|
+
withCurrentActor({ actor: 'system', source: 'system' }, () => {
|
|
57
|
+
canvasState.forEachLiveBoard(() => sweepExpiredGates());
|
|
58
|
+
}),
|
|
59
|
+
1000,
|
|
60
|
+
);
|
|
54
61
|
(sweepTimer as { unref?: () => void }).unref?.();
|
|
55
62
|
}
|
|
56
63
|
|
|
@@ -379,6 +379,7 @@ const PAYLOAD_SCHEMAS: Record<string, z.ZodType> = {
|
|
|
379
379
|
* Injected so this module stays free of a runtime canvas-state import.
|
|
380
380
|
*/
|
|
381
381
|
export interface AxInteractionManager {
|
|
382
|
+
readonly boardIdentity: object;
|
|
382
383
|
getNode(id: string): CanvasNodeState | undefined;
|
|
383
384
|
/** Canvas read for `ax.flow.materialize` (placement obstacles + stale flow sweep). */
|
|
384
385
|
getLayout(): CanvasLayout;
|
|
@@ -722,22 +723,27 @@ function materializeFlow(
|
|
|
722
723
|
*/
|
|
723
724
|
// ── ax.work.create idempotency window ─────────────
|
|
724
725
|
const WORK_CREATE_DEDUPE_MS = 2_500;
|
|
725
|
-
const recentWorkCreates = new Map<string, { item: PmxAxWorkItem; at: number }
|
|
726
|
+
const recentWorkCreates = new WeakMap<object, Map<string, { item: PmxAxWorkItem; at: number }>>();
|
|
726
727
|
|
|
727
|
-
function recentWorkCreate(sourceNodeId: string, title: string): PmxAxWorkItem | null {
|
|
728
|
+
function recentWorkCreate(owner: object, sourceNodeId: string, title: string): PmxAxWorkItem | null {
|
|
728
729
|
const key = `${sourceNodeId}\u0000${title}`;
|
|
729
|
-
const hit = recentWorkCreates.get(key);
|
|
730
|
+
const hit = recentWorkCreates.get(owner)?.get(key);
|
|
730
731
|
if (hit && Date.now() - hit.at <= WORK_CREATE_DEDUPE_MS) return hit.item;
|
|
731
732
|
return null;
|
|
732
733
|
}
|
|
733
734
|
|
|
734
|
-
function rememberWorkCreate(sourceNodeId: string, title: string, item: PmxAxWorkItem): void {
|
|
735
|
+
function rememberWorkCreate(owner: object, sourceNodeId: string, title: string, item: PmxAxWorkItem): void {
|
|
735
736
|
const key = `${sourceNodeId}\u0000${title}`;
|
|
736
|
-
|
|
737
|
-
if (
|
|
737
|
+
let entries = recentWorkCreates.get(owner);
|
|
738
|
+
if (!entries) {
|
|
739
|
+
entries = new Map();
|
|
740
|
+
recentWorkCreates.set(owner, entries);
|
|
741
|
+
}
|
|
742
|
+
entries.set(key, { item, at: Date.now() });
|
|
743
|
+
if (entries.size > 64) {
|
|
738
744
|
const now = Date.now();
|
|
739
|
-
for (const [k, v] of
|
|
740
|
-
if (now - v.at > WORK_CREATE_DEDUPE_MS)
|
|
745
|
+
for (const [k, v] of entries) {
|
|
746
|
+
if (now - v.at > WORK_CREATE_DEDUPE_MS) entries.delete(k);
|
|
741
747
|
}
|
|
742
748
|
}
|
|
743
749
|
}
|
|
@@ -851,7 +857,7 @@ export function applyAxInteraction(
|
|
|
851
857
|
// booked two identical work items ~1s apart): the SAME node creating a
|
|
852
858
|
// work item with the SAME title inside the window gets the first item
|
|
853
859
|
// back instead of a duplicate.
|
|
854
|
-
const dupe = recentWorkCreate(sourceNodeId, p.title);
|
|
860
|
+
const dupe = recentWorkCreate(manager.boardIdentity, sourceNodeId, p.title);
|
|
855
861
|
if (dupe) return accept(type, sourceNodeId, dupe, 'ax-state-changed', { workItem: dupe });
|
|
856
862
|
const workItem = manager.addWorkItem(
|
|
857
863
|
{
|
|
@@ -862,7 +868,7 @@ export function applyAxInteraction(
|
|
|
862
868
|
},
|
|
863
869
|
opts,
|
|
864
870
|
);
|
|
865
|
-
rememberWorkCreate(sourceNodeId, p.title, workItem);
|
|
871
|
+
rememberWorkCreate(manager.boardIdentity, sourceNodeId, p.title, workItem);
|
|
866
872
|
return withLayoutBroadcast(accept(type, sourceNodeId, workItem, 'ax-state-changed', { workItem }), manager, [
|
|
867
873
|
workItem,
|
|
868
874
|
]);
|
|
@@ -137,9 +137,18 @@ function logAxStateWarning(action: string, error: unknown, details?: Record<stri
|
|
|
137
137
|
|
|
138
138
|
export class AxStateManager {
|
|
139
139
|
private _axState: PmxAxState = createEmptyAxState();
|
|
140
|
-
private _axHostCapability: PmxAxHostCapability | null = null;
|
|
141
140
|
|
|
142
|
-
constructor(
|
|
141
|
+
constructor(
|
|
142
|
+
private readonly deps: AxStateManagerDeps,
|
|
143
|
+
private readonly host: { capability: PmxAxHostCapability | null } = { capability: null },
|
|
144
|
+
) {}
|
|
145
|
+
|
|
146
|
+
private get _axHostCapability() {
|
|
147
|
+
return this.host.capability;
|
|
148
|
+
}
|
|
149
|
+
private set _axHostCapability(value: PmxAxHostCapability | null) {
|
|
150
|
+
this.host.capability = value;
|
|
151
|
+
}
|
|
143
152
|
|
|
144
153
|
// ── Normalization (against the owner's current node set) ──────────
|
|
145
154
|
private normalizeForCurrentNodes(state: unknown): PmxAxState {
|
|
@@ -1088,7 +1097,9 @@ export class AxStateManager {
|
|
|
1088
1097
|
* whose source equals the consumer to prevent delivery loops (e.g. Copilot
|
|
1089
1098
|
* should not be handed back steering it originated).
|
|
1090
1099
|
*/
|
|
1091
|
-
getPendingSteering(
|
|
1100
|
+
getPendingSteering(
|
|
1101
|
+
options: { consumer?: string; limit?: number; addressedOnly?: boolean; offset?: number } = {},
|
|
1102
|
+
): PmxAxSteeringMessage[] {
|
|
1092
1103
|
const db = this.deps.getDb();
|
|
1093
1104
|
return db ? loadPendingAxSteeringFromDB(db, options) : [];
|
|
1094
1105
|
}
|
|
@@ -1098,7 +1109,9 @@ export class AxStateManager {
|
|
|
1098
1109
|
* #57) — so a fresh steer is visible even behind a long backlog. Loop-safe like
|
|
1099
1110
|
* getPendingSteering, but ordered DESC instead of the FIFO ASC delivery queue.
|
|
1100
1111
|
*/
|
|
1101
|
-
getPendingSteeringForContext(
|
|
1112
|
+
getPendingSteeringForContext(
|
|
1113
|
+
options: { consumer?: string; limit?: number; addressedOnly?: boolean; offset?: number } = {},
|
|
1114
|
+
): PmxAxSteeringMessage[] {
|
|
1102
1115
|
const db = this.deps.getDb();
|
|
1103
1116
|
return db ? loadNewestPendingAxSteeringFromDB(db, options) : [];
|
|
1104
1117
|
}
|
package/src/server/ax-wait.ts
CHANGED
|
@@ -24,7 +24,8 @@ export async function waitForAxResolution<T extends { status: string }>(opts: {
|
|
|
24
24
|
signal?: AbortSignal;
|
|
25
25
|
}): Promise<AxWaitResult<T>> {
|
|
26
26
|
opts.signal?.throwIfAborted();
|
|
27
|
-
const
|
|
27
|
+
const read = canvasState.bindBoard(opts.read);
|
|
28
|
+
const { isResolved } = opts;
|
|
28
29
|
const timeoutMs = Math.max(0, Math.min(opts.timeoutMs, AX_WAIT_MAX_MS));
|
|
29
30
|
const pendingOf = (v: T | null): boolean => (v ? !isResolved(v) : false);
|
|
30
31
|
|
|
@@ -40,13 +41,18 @@ export async function waitForAxResolution<T extends { status: string }>(opts: {
|
|
|
40
41
|
done = true;
|
|
41
42
|
clearTimeout(timer);
|
|
42
43
|
dispose();
|
|
44
|
+
disposeOwner();
|
|
43
45
|
opts.signal?.removeEventListener('abort', onAbort);
|
|
44
46
|
if (opts.signal?.aborted) {
|
|
45
47
|
reject(opts.signal.reason);
|
|
46
48
|
return;
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
try {
|
|
51
|
+
const v = read();
|
|
52
|
+
resolve({ value: v, pending: pendingOf(v) });
|
|
53
|
+
} catch (error) {
|
|
54
|
+
reject(error);
|
|
55
|
+
}
|
|
50
56
|
};
|
|
51
57
|
const onAbort = finish;
|
|
52
58
|
const check = (type: string): void => {
|
|
@@ -56,6 +62,9 @@ export async function waitForAxResolution<T extends { status: string }>(opts: {
|
|
|
56
62
|
};
|
|
57
63
|
const timer = setTimeout(finish, timeoutMs);
|
|
58
64
|
const dispose = canvasState.onChange(check);
|
|
65
|
+
const disposeOwner = canvasState.onBoardDispose(() => {
|
|
66
|
+
finish();
|
|
67
|
+
});
|
|
59
68
|
opts.signal?.addEventListener('abort', onAbort, { once: true });
|
|
60
69
|
if (opts.signal?.aborted) finish();
|
|
61
70
|
});
|
|
@@ -77,7 +86,8 @@ export async function waitForAxCondition(opts: {
|
|
|
77
86
|
}): Promise<void> {
|
|
78
87
|
opts.signal?.throwIfAborted();
|
|
79
88
|
const timeoutMs = Math.max(0, Math.min(opts.timeoutMs, AX_WAIT_MAX_MS));
|
|
80
|
-
|
|
89
|
+
const ready = canvasState.bindBoard(opts.ready);
|
|
90
|
+
if (timeoutMs === 0 || ready()) return;
|
|
81
91
|
const channel = opts.channel ?? 'ax-timeline';
|
|
82
92
|
await new Promise<void>((resolve, reject) => {
|
|
83
93
|
let done = false;
|
|
@@ -86,6 +96,7 @@ export async function waitForAxCondition(opts: {
|
|
|
86
96
|
done = true;
|
|
87
97
|
clearTimeout(timer);
|
|
88
98
|
dispose();
|
|
99
|
+
disposeOwner();
|
|
89
100
|
opts.signal?.removeEventListener('abort', finish);
|
|
90
101
|
if (opts.signal?.aborted) {
|
|
91
102
|
reject(opts.signal.reason);
|
|
@@ -94,10 +105,13 @@ export async function waitForAxCondition(opts: {
|
|
|
94
105
|
resolve();
|
|
95
106
|
};
|
|
96
107
|
const check = (type: string): void => {
|
|
97
|
-
if (type === channel &&
|
|
108
|
+
if (type === channel && ready()) finish();
|
|
98
109
|
};
|
|
99
110
|
const timer = setTimeout(finish, timeoutMs);
|
|
100
|
-
|
|
111
|
+
// Steering is workspace-wide and can be sent from another board. Keep
|
|
112
|
+
// ready() bound to its owner but listen outside the board-specific filter.
|
|
113
|
+
const dispose = canvasState.withVisibleBoard(() => canvasState.onChange(check));
|
|
114
|
+
const disposeOwner = canvasState.onBoardDispose(finish);
|
|
101
115
|
opts.signal?.addEventListener('abort', finish, { once: true });
|
|
102
116
|
if (opts.signal?.aborted) finish();
|
|
103
117
|
});
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { existsSync, mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs';
|
|
13
13
|
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
14
14
|
import { Marked, Renderer, type RendererThis, type Tokens } from 'marked';
|
|
15
|
+
import { isWorkCardState, WORK_CARD_STATES } from '../shared/ax-kinds.js';
|
|
15
16
|
import { canvasThemeScheme, normalizeCanvasThemeName, type CanvasThemeName } from '../shared/themes.js';
|
|
16
17
|
import { delimiterForPath, parseDelimitedText } from '../shared/delimited-text.js';
|
|
17
18
|
import { buildJsonRenderViewerHtml, escapeInlineScriptSource, readJsonRenderBundle } from '../json-render/server.js';
|
|
@@ -281,12 +282,24 @@ async function collect(
|
|
|
281
282
|
card.html = `<div class="md">${await markdown.parse(text(data.content))}</div>`;
|
|
282
283
|
break;
|
|
283
284
|
case 'status':
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
285
|
+
if (typeof data.workItemId === 'string' && data.liveWorkAvailable === false) {
|
|
286
|
+
placeholder('Task unavailable. The linked task is no longer on this board.');
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
card.html = isWorkCardState(data.workState)
|
|
290
|
+
? rows([
|
|
291
|
+
['Task view', typeof data.workItemId === 'string' ? 'Read-only snapshot of linked task' : undefined],
|
|
292
|
+
['Task source', typeof data.workItemId === 'string' ? data.liveWorkSource : undefined],
|
|
293
|
+
['Work state', WORK_CARD_STATES[data.workState].label],
|
|
294
|
+
['Detail', data.detail],
|
|
295
|
+
['Progress', typeof data.progress === 'number' ? `${data.progress}%` : undefined],
|
|
296
|
+
])
|
|
297
|
+
: rows([
|
|
298
|
+
['Phase', text(data.phase).trim() || text(data.content).trim() || text(data.status).trim() || 'idle'],
|
|
299
|
+
['Message', data.message],
|
|
300
|
+
['Detail', data.detail],
|
|
301
|
+
['Active tool', data.activeTool],
|
|
302
|
+
]);
|
|
290
303
|
break;
|
|
291
304
|
case 'context': {
|
|
292
305
|
const items = Array.isArray(data.cards) ? (data.cards as Array<Record<string, unknown>>) : [];
|