pmx-canvas 0.11.0 → 0.12.1
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 +4 -1
- package/.github/extensions/pmx-canvas/runtime.json +1 -1
- package/.github/extensions/pmx-canvas/tools.json +440 -18
- package/CHANGELOG.md +51 -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 +267 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/evals.json +1168 -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 +1839 -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 +301 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/tours-and-recording.md +117 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/workbench-workflows.md +908 -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 +22 -2
- package/docs/amp-plugin.md +270 -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 +4 -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 +248 -842
- package/skills/pmx-canvas/evals/evals.json +110 -5
- package/skills/pmx-canvas/references/full-reference.md +142 -28
- package/skills/pmx-canvas/references/html-primitives.md +7 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +61 -11
- package/skills/pmx-canvas/references/tours-and-recording.md +39 -6
- package/skills/pmx-canvas/references/workbench-workflows.md +908 -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/bundle-artifact.sh +2 -2
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +8 -8
- 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 +262 -160
- 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/bundle-artifact.sh +2 -2
- package/src/server/web-artifacts/scripts/init-artifact.sh +8 -8
- 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
|
@@ -38,6 +38,10 @@ import {
|
|
|
38
38
|
} from '../state/session-store';
|
|
39
39
|
import { formatCountdown, gateRemainingMs } from '../../shared/approval-gates.js';
|
|
40
40
|
import { agentSessionsEnabled } from '../state/workspace-settings';
|
|
41
|
+
import { humanName, setHumanName } from '../state/human-store';
|
|
42
|
+
import { tabAgentKey } from '../state/intent-bridge';
|
|
43
|
+
import { HUMAN_NAME_MAX_LENGTH } from '../../shared/human-presence.js';
|
|
44
|
+
import { askText } from './TextPrompt';
|
|
41
45
|
|
|
42
46
|
const PRESENT_DESCRIPTION = (
|
|
43
47
|
<span style={{ whiteSpace: 'pre-line' }}>
|
|
@@ -536,6 +540,32 @@ export function TopBar() {
|
|
|
536
540
|
<TopBarMore boardOpen={!!activeBoardId.value} onFit={handleFit} />
|
|
537
541
|
</>
|
|
538
542
|
)}
|
|
543
|
+
{!isHostedWorkbench() && !tabAgentKey && (
|
|
544
|
+
<span class="human-name-control">
|
|
545
|
+
<BarHint label="Your name" body={`Shown on your cursor: ${humanName.value}`} align="end">
|
|
546
|
+
<button
|
|
547
|
+
type="button"
|
|
548
|
+
class="top-bar-btn human-name-button"
|
|
549
|
+
aria-label={`Your name: ${humanName.value}`}
|
|
550
|
+
aria-haspopup="dialog"
|
|
551
|
+
onClick={async (event) => {
|
|
552
|
+
const button = event.currentTarget;
|
|
553
|
+
const name = await askText('Your name on this canvas', 'e.g. Alex', {
|
|
554
|
+
initial: humanName.value,
|
|
555
|
+
confirm: 'Save name',
|
|
556
|
+
maxLength: HUMAN_NAME_MAX_LENGTH,
|
|
557
|
+
description:
|
|
558
|
+
'Shown on your cursor. Self-reported, not a verified identity or an access grant. Saved in this browser.',
|
|
559
|
+
});
|
|
560
|
+
if (name !== null) setHumanName(name);
|
|
561
|
+
button.focus({ preventScroll: true });
|
|
562
|
+
}}
|
|
563
|
+
>
|
|
564
|
+
{writerInitial(humanName.value)}
|
|
565
|
+
</button>
|
|
566
|
+
</BarHint>
|
|
567
|
+
</span>
|
|
568
|
+
)}
|
|
539
569
|
</div>
|
|
540
570
|
</div>
|
|
541
571
|
);
|
|
@@ -60,7 +60,7 @@ export function canvasFitInsets(): CanvasFitInsets {
|
|
|
60
60
|
try {
|
|
61
61
|
const area = canvasArea();
|
|
62
62
|
const areaBottom = area.top + area.height;
|
|
63
|
-
for (const selector of ['.lifecycle-filters', '.relation-legend']) {
|
|
63
|
+
for (const selector of ['.lifecycle-filters', '.relation-legend', '.group-breadcrumbs']) {
|
|
64
64
|
const el = document.querySelector(selector);
|
|
65
65
|
if (!(el instanceof HTMLElement) || !el.isConnected) continue;
|
|
66
66
|
const rect = el.getBoundingClientRect();
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
AX_SURFACE_ACK_SOURCE,
|
|
12
12
|
AX_SURFACE_EMIT_SOURCE,
|
|
13
13
|
HTML_SURFACE_PUSH_SOURCE,
|
|
14
|
+
MCP_SURFACE_METHOD,
|
|
15
|
+
surfaceNotification,
|
|
14
16
|
} from '../../shared/ax-surface-protocol.js';
|
|
15
17
|
import { extAppToolResultsMatch } from '../../shared/ext-app-tool-result.js';
|
|
16
18
|
import { DEFAULT_EXT_APP_SANDBOX } from '../../shared/surface.js';
|
|
@@ -57,17 +59,24 @@ export function buildExtAppAxBridgeScript(axToken: string, nodeId: string): stri
|
|
|
57
59
|
(function () {
|
|
58
60
|
const PMX_AX_TOKEN = ${JSON.stringify(axToken)};
|
|
59
61
|
const PMX_AX_NODE_ID = ${JSON.stringify(nodeId)};
|
|
60
|
-
|
|
62
|
+
const notify = function (params) {
|
|
63
|
+
parent.postMessage({ jsonrpc: '2.0', method: '${MCP_SURFACE_METHOD}', params: params }, '*');
|
|
64
|
+
};
|
|
65
|
+
const read = function (event) {
|
|
61
66
|
const m = event.data;
|
|
67
|
+
return event.source === parent && m && m.jsonrpc === '2.0' && m.method === '${MCP_SURFACE_METHOD}' && !('id' in m) ? m.params : null;
|
|
68
|
+
};
|
|
69
|
+
window.addEventListener('message', function (event) {
|
|
70
|
+
const m = read(event);
|
|
62
71
|
if (event.source !== parent || !m || m.source !== 'pmx-viewer-theme' || m.token !== PMX_AX_TOKEN) return;
|
|
63
72
|
for (const [name, value] of Object.entries(m.variables)) document.documentElement.style.setProperty(name, value);
|
|
64
73
|
});
|
|
65
74
|
window.addEventListener('message', function (event) {
|
|
66
|
-
const m = event
|
|
75
|
+
const m = read(event);
|
|
67
76
|
if (event.source !== parent || !m || m.source !== '${HTML_SURFACE_PUSH_SOURCE}' || m.token !== PMX_AX_TOKEN || m.type !== 'check-ready') return;
|
|
68
|
-
|
|
77
|
+
notify({ source: '${HTML_SURFACE_PUSH_SOURCE}', type: 'mounted', token: PMX_AX_TOKEN });
|
|
69
78
|
requestAnimationFrame(function () { requestAnimationFrame(function () {
|
|
70
|
-
|
|
79
|
+
notify({ source: '${HTML_SURFACE_PUSH_SOURCE}', type: 'ready', token: PMX_AX_TOKEN });
|
|
71
80
|
}); });
|
|
72
81
|
});
|
|
73
82
|
window.PMX_AX = window.PMX_AX || {};
|
|
@@ -83,18 +92,18 @@ export function buildExtAppAxBridgeScript(axToken: string, nodeId: string): stri
|
|
|
83
92
|
resolve({ ok: false, status: 504, code: 'ax-ack-timeout', error: 'ax-ack-timeout' });
|
|
84
93
|
}, 10000);
|
|
85
94
|
pending.set(correlationId, function (result) { clearTimeout(timer); resolve(result); });
|
|
86
|
-
|
|
95
|
+
notify({
|
|
87
96
|
source: '${AX_SURFACE_EMIT_SOURCE}', token: PMX_AX_TOKEN, nodeId: PMX_AX_NODE_ID,
|
|
88
97
|
correlationId: correlationId,
|
|
89
98
|
interaction: { type: String(type), payload: payload && typeof payload === 'object' ? payload : {} },
|
|
90
|
-
}
|
|
99
|
+
});
|
|
91
100
|
});
|
|
92
101
|
};
|
|
93
102
|
window.PMX_AX.on = function (eventType, cb) {
|
|
94
103
|
if (eventType === 'ack' && typeof cb === 'function') ackListeners.push(cb);
|
|
95
104
|
};
|
|
96
105
|
window.addEventListener('message', function (event) {
|
|
97
|
-
const m = event
|
|
106
|
+
const m = read(event);
|
|
98
107
|
if (event.source !== window.parent || !m || m.source !== '${AX_SURFACE_ACK_SOURCE}' || m.token !== PMX_AX_TOKEN) return;
|
|
99
108
|
const result = m.result || { ok: false };
|
|
100
109
|
const resolver = m.correlationId ? pending.get(m.correlationId) : undefined;
|
|
@@ -194,7 +203,14 @@ export function ExtAppFrame({ node, expanded = false }: { node: CanvasNodeState;
|
|
|
194
203
|
buildExtAppSurfaceBaseStyles() + buildExtAppAxBridgeScript(axToken, node.id),
|
|
195
204
|
);
|
|
196
205
|
const frameDocument = useIframeDocument(documentHtml, DEFAULT_EXT_APP_SANDBOX);
|
|
197
|
-
useAxSurfaceBridge({
|
|
206
|
+
useAxSurfaceBridge({
|
|
207
|
+
enabled: axEnabled,
|
|
208
|
+
token: axToken,
|
|
209
|
+
nodeId: node.id,
|
|
210
|
+
sourceSurface: 'mcp-app',
|
|
211
|
+
iframeRef,
|
|
212
|
+
jsonRpc: true,
|
|
213
|
+
});
|
|
198
214
|
|
|
199
215
|
const sessionMessage =
|
|
200
216
|
node.data.sessionStatus === 'error'
|
|
@@ -265,7 +281,7 @@ export function ExtAppFrame({ node, expanded = false }: { node: CanvasNodeState;
|
|
|
265
281
|
const sendContext = () => {
|
|
266
282
|
if (disposed) return;
|
|
267
283
|
iframe.contentWindow?.postMessage(
|
|
268
|
-
{ source: 'pmx-viewer-theme', token: axToken, variables: canvasVariables() },
|
|
284
|
+
surfaceNotification({ source: 'pmx-viewer-theme', token: axToken, variables: canvasVariables() }),
|
|
269
285
|
'*',
|
|
270
286
|
);
|
|
271
287
|
if (!initialized) return;
|
|
@@ -409,7 +425,7 @@ export function ExtAppFrame({ node, expanded = false }: { node: CanvasNodeState;
|
|
|
409
425
|
const connection = connections.current.get(frame);
|
|
410
426
|
if (!connection || !(await connection.loaded()) || signal.aborted) return false;
|
|
411
427
|
connection.theme();
|
|
412
|
-
return waitForViewerPaint(frame, axToken, signal);
|
|
428
|
+
return waitForViewerPaint(frame, axToken, signal, true);
|
|
413
429
|
}}
|
|
414
430
|
onOpen={expanded ? undefined : () => expandNode(node.id)}
|
|
415
431
|
sandbox={DEFAULT_EXT_APP_SANDBOX}
|
|
@@ -276,10 +276,8 @@ export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState
|
|
|
276
276
|
if (!renderingDraft && !draft.dirty.value) {
|
|
277
277
|
latestMdRef.current = raw;
|
|
278
278
|
setContent(raw);
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
// A pending save may already contain this text; cache only its HTML.
|
|
282
|
-
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 });
|
|
283
281
|
}
|
|
284
282
|
})();
|
|
285
283
|
return () => {
|
|
@@ -303,10 +301,10 @@ export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState
|
|
|
303
301
|
|
|
304
302
|
const persistContent = useCallback(
|
|
305
303
|
async (newContent: string) => {
|
|
306
|
-
//
|
|
307
|
-
//
|
|
304
|
+
// A peer update cannot grant an older draft permission to overwrite it.
|
|
305
|
+
// Only our own successful saves advance the draft's revision.
|
|
308
306
|
const incarnation = boardIncarnation;
|
|
309
|
-
const attempt = { revision:
|
|
307
|
+
const attempt = { revision: editBase.current.revision };
|
|
310
308
|
draft.nativeSaveAttempts.add(attempt);
|
|
311
309
|
draft.pending.value++;
|
|
312
310
|
// Order the complete save, including disk writes and rendering. A later
|
|
@@ -376,6 +374,7 @@ export function MarkdownNode({ node, expanded = false }: { node: CanvasNodeState
|
|
|
376
374
|
if (result.ok && result.contentRevision !== undefined) {
|
|
377
375
|
// Advance only through a successful predecessor in this board/card's
|
|
378
376
|
// queue. An external revision or a refused save grants no retry.
|
|
377
|
+
editBase.current.revision = result.contentRevision;
|
|
379
378
|
for (const queued of draft.nativeSaveAttempts) {
|
|
380
379
|
if (queued.revision === expectedContentRevision) queued.revision = result.contentRevision;
|
|
381
380
|
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
|
|
1
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'preact/hooks';
|
|
2
2
|
import { IconClose } from '../icons';
|
|
3
|
+
import { activeBoardId } from '../state/boards-store';
|
|
3
4
|
import { updateNodeData } from '../state/canvas-store';
|
|
4
5
|
import { fetchSlashCommands, renderMarkdown, submitCanvasPrompt, submitThreadReply } from '../state/intent-bridge';
|
|
5
6
|
import type { CanvasNodeState } from '../types';
|
|
6
7
|
import { sanitizeMarkdownHtml } from './markdown-sanitize';
|
|
7
8
|
|
|
9
|
+
// Multiple inline/focus renderers may own inputs for the same qualified card.
|
|
10
|
+
const unsentInputs = new Set<{ boardId: string | null; nodeId: string; draft: string; reply: string }>();
|
|
11
|
+
export function hasUnsavedPrompt(boardId: string, nodeId: string): boolean {
|
|
12
|
+
return [...unsentInputs].some((input) => input.boardId === boardId && input.nodeId === nodeId);
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
// Cached slash commands — fetched once on first use.
|
|
9
16
|
let cachedCommands: Array<{ name: string; description: string }> | null = null;
|
|
10
17
|
async function getCommands() {
|
|
@@ -117,8 +124,30 @@ export function PromptNode({ node, expanded = false }: { node: CanvasNodeState;
|
|
|
117
124
|
const isStreaming = threadStatus === 'streaming';
|
|
118
125
|
const isAnswered = threadStatus === 'answered';
|
|
119
126
|
|
|
120
|
-
const [draft,
|
|
121
|
-
const [replyDraft,
|
|
127
|
+
const [draft, updateDraft] = useState('');
|
|
128
|
+
const [replyDraft, updateReplyDraft] = useState('');
|
|
129
|
+
const boardId = activeBoardId.value;
|
|
130
|
+
const input = useMemo(() => ({ boardId, nodeId: node.id, draft: '', reply: '' }), [boardId, node.id]);
|
|
131
|
+
const remember = () => {
|
|
132
|
+
if (input.draft || input.reply) unsentInputs.add(input);
|
|
133
|
+
else unsentInputs.delete(input);
|
|
134
|
+
};
|
|
135
|
+
const setDraft = (text: string) => {
|
|
136
|
+
input.draft = text;
|
|
137
|
+
remember();
|
|
138
|
+
updateDraft(text);
|
|
139
|
+
};
|
|
140
|
+
const setReplyDraft = (text: string) => {
|
|
141
|
+
input.reply = text;
|
|
142
|
+
remember();
|
|
143
|
+
updateReplyDraft(text);
|
|
144
|
+
};
|
|
145
|
+
useEffect(
|
|
146
|
+
() => () => {
|
|
147
|
+
unsentInputs.delete(input);
|
|
148
|
+
},
|
|
149
|
+
[input],
|
|
150
|
+
);
|
|
122
151
|
const [error, setError] = useState<string | null>(null);
|
|
123
152
|
const [renderedTurns, setRenderedTurns] = useState<Map<number, string>>(new Map());
|
|
124
153
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { PHASE_COLORS } from '../theme/tokens';
|
|
2
2
|
import type { CanvasNodeState } from '../types';
|
|
3
|
+
import { isWorkCardState } from '../../shared/ax-kinds.js';
|
|
4
|
+
import { WorkCard } from './WorkCard';
|
|
3
5
|
|
|
4
6
|
export function getStatusDisplayPhase(node: CanvasNodeState): string {
|
|
5
7
|
const phase = typeof node.data.phase === 'string' && node.data.phase.trim().length > 0 ? node.data.phase.trim() : '';
|
|
@@ -13,6 +15,16 @@ export function getStatusDisplayPhase(node: CanvasNodeState): string {
|
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
export function StatusNode({ node }: { node: CanvasNodeState }) {
|
|
18
|
+
if (typeof node.data.workItemId === 'string' && node.data.liveWorkAvailable === false) {
|
|
19
|
+
return (
|
|
20
|
+
<div class="work-card">
|
|
21
|
+
<div class="work-card-error">⚠ Task unavailable</div>
|
|
22
|
+
<div>The linked task is no longer on this board.</div>
|
|
23
|
+
<div class="work-card-live">Read-only · removing this card does not cancel work.</div>
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
if (isWorkCardState(node.data.workState)) return <WorkCard node={node} state={node.data.workState} />;
|
|
16
28
|
const phase = getStatusDisplayPhase(node);
|
|
17
29
|
const detail = (node.data.detail as string) || '';
|
|
18
30
|
const message = (node.data.message as string) || '';
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { PHASE_COLORS } from '../theme/tokens';
|
|
2
2
|
import type { CanvasNodeState } from '../types';
|
|
3
3
|
import { getStatusDisplayPhase } from './StatusNode';
|
|
4
|
+
import { isWorkCardState, WORK_CARD_STATES } from '../../shared/ax-kinds.js';
|
|
4
5
|
|
|
5
6
|
export function StatusSummary({ node }: { node: CanvasNodeState }) {
|
|
7
|
+
if (typeof node.data.workItemId === 'string' && node.data.liveWorkAvailable === false)
|
|
8
|
+
return <span class="work-card-error">⚠ Task unavailable</span>;
|
|
9
|
+
if (isWorkCardState(node.data.workState)) {
|
|
10
|
+
const state = WORK_CARD_STATES[node.data.workState];
|
|
11
|
+
return (
|
|
12
|
+
<span class={`work-card-state work-card-${node.data.workState}`}>
|
|
13
|
+
<span aria-hidden="true">{state.glyph}</span> {state.label}
|
|
14
|
+
</span>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
6
17
|
const phase = getStatusDisplayPhase(node);
|
|
7
18
|
const activeTool = node.data.activeTool as string | null;
|
|
8
19
|
const subagent = node.data.subagent as { state: string; name: string } | undefined;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { JSX, RefObject } from 'preact';
|
|
2
2
|
import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
HTML_SURFACE_PUSH_SOURCE,
|
|
5
|
+
readSurfaceNotification,
|
|
6
|
+
surfaceNotification,
|
|
7
|
+
} from '../../shared/ax-surface-protocol.js';
|
|
4
8
|
|
|
5
9
|
export const VIEWER_LOAD_DEADLINE_MS = 10_000;
|
|
6
10
|
export type ViewerSource = { src?: string; srcdoc?: string; error?: boolean; retry?: () => void };
|
|
@@ -12,7 +16,12 @@ type Entry = { key: string; source: ViewerSource; attempt: number; load?: LoadDo
|
|
|
12
16
|
type MountFrame = (frame: HTMLIFrameElement, fail: () => void) => () => void;
|
|
13
17
|
|
|
14
18
|
/** The document acknowledges mounting before its frame-gated paint signal. */
|
|
15
|
-
export function waitForViewerPaint(
|
|
19
|
+
export function waitForViewerPaint(
|
|
20
|
+
frame: HTMLIFrameElement,
|
|
21
|
+
token: string,
|
|
22
|
+
signal: AbortSignal,
|
|
23
|
+
jsonRpc = false,
|
|
24
|
+
): Promise<boolean> {
|
|
16
25
|
if (signal.aborted) return Promise.resolve(false);
|
|
17
26
|
return new Promise((resolve) => {
|
|
18
27
|
const finish = (ready: boolean) => {
|
|
@@ -23,21 +32,23 @@ export function waitForViewerPaint(frame: HTMLIFrameElement, token: string, sign
|
|
|
23
32
|
};
|
|
24
33
|
const cancel = () => finish(false);
|
|
25
34
|
const receive = (event: MessageEvent) => {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
35
|
+
const data = (jsonRpc ? readSurfaceNotification(event.data) : event.data) as {
|
|
36
|
+
source?: string;
|
|
37
|
+
token?: string;
|
|
38
|
+
type?: string;
|
|
39
|
+
} | null;
|
|
40
|
+
if (event.source !== frame.contentWindow || data?.source !== HTML_SURFACE_PUSH_SOURCE || data?.token !== token)
|
|
31
41
|
return;
|
|
32
|
-
if (
|
|
42
|
+
if (data.type === 'mounted') {
|
|
33
43
|
clearTimeout(timer);
|
|
34
44
|
}
|
|
35
|
-
if (
|
|
45
|
+
if (data.type === 'ready') finish(true);
|
|
36
46
|
};
|
|
37
47
|
const timer = setTimeout(cancel, VIEWER_LOAD_DEADLINE_MS);
|
|
38
48
|
window.addEventListener('message', receive);
|
|
39
49
|
signal.addEventListener('abort', cancel, { once: true });
|
|
40
|
-
|
|
50
|
+
const message = { source: HTML_SURFACE_PUSH_SOURCE, type: 'check-ready', token };
|
|
51
|
+
frame.contentWindow?.postMessage(jsonRpc ? surfaceNotification(message) : message, '*');
|
|
41
52
|
});
|
|
42
53
|
}
|
|
43
54
|
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { signal, type Signal } from '@preact/signals';
|
|
2
|
+
import { useMemo } from 'preact/hooks';
|
|
3
|
+
import { WORK_CARD_STATES, type AxWorkItemStatus } from '../../shared/ax-kinds.js';
|
|
4
|
+
import { activeBoardId } from '../state/boards-store';
|
|
5
|
+
import { updateNodeFromClient } from '../state/intent-bridge';
|
|
6
|
+
import type { CanvasNodeState } from '../types';
|
|
7
|
+
|
|
8
|
+
type WorkDraft = {
|
|
9
|
+
title: string;
|
|
10
|
+
state: AxWorkItemStatus;
|
|
11
|
+
detail: string;
|
|
12
|
+
progress: string;
|
|
13
|
+
boardId: string | null;
|
|
14
|
+
revision: number;
|
|
15
|
+
saving: boolean;
|
|
16
|
+
error: string;
|
|
17
|
+
};
|
|
18
|
+
// Like Markdown drafts, these belong to the qualified card, not its inline/focus renderer.
|
|
19
|
+
const drafts = new Map<string, Signal<WorkDraft | null>>();
|
|
20
|
+
|
|
21
|
+
export function hasUnsavedWorkCard(boardId: string, nodeId: string): boolean {
|
|
22
|
+
return !!drafts.get(JSON.stringify([boardId, nodeId]))?.value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function WorkCard({ node, state }: { node: CanvasNodeState; state: AxWorkItemStatus }) {
|
|
26
|
+
const key = JSON.stringify([activeBoardId.value, node.id]);
|
|
27
|
+
const editing = useMemo(() => drafts.get(key) ?? signal<WorkDraft | null>(null), [key]);
|
|
28
|
+
const draft = editing.value;
|
|
29
|
+
const saving = draft?.saving ?? false;
|
|
30
|
+
const error = draft?.error ?? '';
|
|
31
|
+
const setDraft = (next: WorkDraft | null) => {
|
|
32
|
+
if (next) drafts.set(key, editing);
|
|
33
|
+
else drafts.delete(key);
|
|
34
|
+
editing.value = next;
|
|
35
|
+
};
|
|
36
|
+
const detail = typeof node.data.detail === 'string' ? node.data.detail : '';
|
|
37
|
+
const progress = typeof node.data.progress === 'number' ? node.data.progress : null;
|
|
38
|
+
|
|
39
|
+
const edit = () => {
|
|
40
|
+
setDraft({
|
|
41
|
+
title: typeof node.data.title === 'string' ? node.data.title : '',
|
|
42
|
+
state,
|
|
43
|
+
detail,
|
|
44
|
+
progress: progress === null ? '' : String(progress),
|
|
45
|
+
boardId: activeBoardId.value,
|
|
46
|
+
revision: node.contentRevision ?? 0,
|
|
47
|
+
saving: false,
|
|
48
|
+
error: '',
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
const save = async () => {
|
|
52
|
+
if (!draft || saving) return;
|
|
53
|
+
setDraft({ ...draft, saving: true, error: '' });
|
|
54
|
+
const result = await updateNodeFromClient(node.id, {
|
|
55
|
+
title: draft.title.trim(),
|
|
56
|
+
data: {
|
|
57
|
+
workState: draft.state,
|
|
58
|
+
detail: draft.detail,
|
|
59
|
+
progress: draft.progress === '' ? null : Number(draft.progress),
|
|
60
|
+
},
|
|
61
|
+
expectedBoardId: draft.boardId,
|
|
62
|
+
expectedContentRevision: draft.revision,
|
|
63
|
+
});
|
|
64
|
+
if (result.ok) setDraft(null);
|
|
65
|
+
else
|
|
66
|
+
setDraft({
|
|
67
|
+
...draft,
|
|
68
|
+
saving: false,
|
|
69
|
+
error: 'Could not save. Your draft is still here. Check the connection or whether the card changed.',
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (draft) {
|
|
74
|
+
return (
|
|
75
|
+
<form
|
|
76
|
+
class="work-card-editor"
|
|
77
|
+
onSubmit={(event) => {
|
|
78
|
+
event.preventDefault();
|
|
79
|
+
void save();
|
|
80
|
+
}}
|
|
81
|
+
onKeyDown={(event) => {
|
|
82
|
+
event.stopPropagation();
|
|
83
|
+
if (event.key === 'Escape' && !saving) {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
setDraft(null);
|
|
86
|
+
}
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
<fieldset disabled={saving}>
|
|
90
|
+
<label>
|
|
91
|
+
Title
|
|
92
|
+
<input required value={draft.title} onInput={(e) => setDraft({ ...draft, title: e.currentTarget.value })} />
|
|
93
|
+
</label>
|
|
94
|
+
<label>
|
|
95
|
+
Work state
|
|
96
|
+
<select
|
|
97
|
+
value={draft.state}
|
|
98
|
+
onChange={(e) => setDraft({ ...draft, state: e.currentTarget.value as AxWorkItemStatus })}
|
|
99
|
+
>
|
|
100
|
+
{Object.entries(WORK_CARD_STATES).map(([value, item]) => (
|
|
101
|
+
<option key={value} value={value}>
|
|
102
|
+
{item.label}
|
|
103
|
+
</option>
|
|
104
|
+
))}
|
|
105
|
+
</select>
|
|
106
|
+
</label>
|
|
107
|
+
<label>
|
|
108
|
+
Detail
|
|
109
|
+
<textarea value={draft.detail} onInput={(e) => setDraft({ ...draft, detail: e.currentTarget.value })} />
|
|
110
|
+
</label>
|
|
111
|
+
<label>
|
|
112
|
+
Progress (%) · optional
|
|
113
|
+
<input
|
|
114
|
+
type="number"
|
|
115
|
+
min="0"
|
|
116
|
+
max="100"
|
|
117
|
+
step="any"
|
|
118
|
+
value={draft.progress}
|
|
119
|
+
onInput={(e) => setDraft({ ...draft, progress: e.currentTarget.value })}
|
|
120
|
+
/>
|
|
121
|
+
</label>
|
|
122
|
+
{error && (
|
|
123
|
+
<div class="work-card-error" role="alert">
|
|
124
|
+
{error}
|
|
125
|
+
</div>
|
|
126
|
+
)}
|
|
127
|
+
<footer>
|
|
128
|
+
<button type="button" onClick={() => setDraft(null)}>
|
|
129
|
+
Cancel
|
|
130
|
+
</button>
|
|
131
|
+
<button class="work-card-save" type="submit">
|
|
132
|
+
{saving ? 'Saving…' : 'Save'}
|
|
133
|
+
</button>
|
|
134
|
+
</footer>
|
|
135
|
+
</fieldset>
|
|
136
|
+
</form>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div class={`work-card work-card-${state}`}>
|
|
142
|
+
{typeof node.data.workItemId === 'string' && (
|
|
143
|
+
<div class="work-card-live">
|
|
144
|
+
↗ Live task{node.data.liveWorkSource ? ` · ${node.data.liveWorkSource}` : ''} · Read-only
|
|
145
|
+
</div>
|
|
146
|
+
)}
|
|
147
|
+
<div class="work-card-state">
|
|
148
|
+
<span aria-hidden="true">{WORK_CARD_STATES[state].glyph}</span> {WORK_CARD_STATES[state].label}
|
|
149
|
+
</div>
|
|
150
|
+
{detail && <div class="work-card-detail">{detail}</div>}
|
|
151
|
+
{progress !== null && (
|
|
152
|
+
<div class="work-card-progress">
|
|
153
|
+
<span>{progress}% complete</span>
|
|
154
|
+
<div
|
|
155
|
+
class="status-progress"
|
|
156
|
+
role="progressbar"
|
|
157
|
+
aria-label="Progress"
|
|
158
|
+
aria-valuemin={0}
|
|
159
|
+
aria-valuemax={100}
|
|
160
|
+
aria-valuenow={progress}
|
|
161
|
+
>
|
|
162
|
+
<div style={{ width: `${progress}%`, background: 'currentColor' }} />
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
166
|
+
{typeof node.data.workItemId !== 'string' && (
|
|
167
|
+
<footer>
|
|
168
|
+
<button type="button" onClick={edit}>
|
|
169
|
+
Edit
|
|
170
|
+
</button>
|
|
171
|
+
</footer>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { RefObject } from 'preact';
|
|
2
2
|
import { useLayoutEffect } from 'preact/hooks';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
AX_SURFACE_ACK_SOURCE,
|
|
5
|
+
AX_SURFACE_EMIT_SOURCE,
|
|
6
|
+
readSurfaceNotification,
|
|
7
|
+
surfaceNotification,
|
|
8
|
+
} from '../../shared/ax-surface-protocol.js';
|
|
4
9
|
import { showToast } from '../state/attention-bridge';
|
|
5
10
|
import { submitAxInteractionFromClient } from '../state/intent-bridge';
|
|
6
11
|
|
|
@@ -23,8 +28,9 @@ export function useAxSurfaceBridge(options: {
|
|
|
23
28
|
nodeId: string;
|
|
24
29
|
sourceSurface: AxSurfaceBridgeSurface;
|
|
25
30
|
iframeRef: RefObject<HTMLIFrameElement>;
|
|
31
|
+
jsonRpc?: boolean;
|
|
26
32
|
}): void {
|
|
27
|
-
const { enabled, token, nodeId, sourceSurface, iframeRef } = options;
|
|
33
|
+
const { enabled, token, nodeId, sourceSurface, iframeRef, jsonRpc = false } = options;
|
|
28
34
|
// Register before paint: a fast iframe can accept input before passive effects
|
|
29
35
|
// run, and its first emit must not be lost in that gap.
|
|
30
36
|
useLayoutEffect(() => {
|
|
@@ -33,7 +39,7 @@ export function useAxSurfaceBridge(options: {
|
|
|
33
39
|
// Bind to THIS node's own iframe; the nonce + nodeId are a second gate,
|
|
34
40
|
// not the only one.
|
|
35
41
|
if (event.source !== iframeRef.current?.contentWindow) return;
|
|
36
|
-
const data = event.data as {
|
|
42
|
+
const data = (jsonRpc ? readSurfaceNotification(event.data) : event.data) as {
|
|
37
43
|
source?: string;
|
|
38
44
|
token?: string;
|
|
39
45
|
nodeId?: string;
|
|
@@ -54,20 +60,18 @@ export function useAxSurfaceBridge(options: {
|
|
|
54
60
|
}).then((res) => {
|
|
55
61
|
// A refusal is toasted by the bridge with the server's reason.
|
|
56
62
|
if (res.ok) showToast('context', 'AX interaction', interactionType, [nodeId]);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
'*',
|
|
66
|
-
);
|
|
63
|
+
const message = {
|
|
64
|
+
source: AX_SURFACE_ACK_SOURCE,
|
|
65
|
+
token,
|
|
66
|
+
...(data.correlationId ? { correlationId: data.correlationId } : {}),
|
|
67
|
+
interaction: { type: interactionType },
|
|
68
|
+
result: res,
|
|
69
|
+
};
|
|
70
|
+
iframeRef.current?.contentWindow?.postMessage(jsonRpc ? surfaceNotification(message) : message, '*');
|
|
67
71
|
});
|
|
68
72
|
}
|
|
69
73
|
window.addEventListener('message', onAxMessage);
|
|
70
74
|
return () => window.removeEventListener('message', onAxMessage);
|
|
71
75
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
|
-
}, [enabled, token, nodeId, sourceSurface]);
|
|
76
|
+
}, [enabled, token, nodeId, sourceSurface, jsonRpc]);
|
|
73
77
|
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type SseMessage,
|
|
10
10
|
} from '../../shared/semantic-attention.js';
|
|
11
11
|
import {
|
|
12
|
+
attentionHistoryOpen,
|
|
12
13
|
pushAttentionHistory,
|
|
13
14
|
resetAttentionState,
|
|
14
15
|
setAttentionPulse,
|
|
@@ -291,6 +292,10 @@ function entryFromEvent(event: SemanticWatchEvent): AttentionEntry | null {
|
|
|
291
292
|
}
|
|
292
293
|
|
|
293
294
|
function flushToastQueue(): void {
|
|
295
|
+
if (attentionHistoryOpen.value) {
|
|
296
|
+
toastQueue = [];
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
294
299
|
if (toastTimer !== null) return;
|
|
295
300
|
const next = toastQueue.shift() ?? null;
|
|
296
301
|
if (!next) {
|