pmx-canvas 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/extensions/pmx-canvas/extension.mjs +3 -1
- package/.github/extensions/pmx-canvas/runtime.json +1 -1
- package/.github/extensions/pmx-canvas/tools.json +688 -128
- package/CHANGELOG.md +69 -0
- package/dist/amp-plugin/pmx-canvas/LICENSE +21 -0
- package/dist/amp-plugin/pmx-canvas/THIRD_PARTY_LICENSES.txt +331 -0
- package/dist/amp-plugin/pmx-canvas/index.js +5445 -0
- package/dist/amp-plugin/pmx-canvas/runtime.json +3 -0
- package/dist/amp-plugin/pmx-canvas/shared-runtime.mjs +194 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/SKILL.md +251 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/evals.json +1086 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/jwt.ts +17 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/login.ts +12 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/auth/middleware.ts +13 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/code-exploration/src/routes/auth.ts +13 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/evals/fixtures/investigation-board/src/handlers/users.ts +27 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/mcp.json +36 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/ax-html-control-surface.md +101 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/codex-app-adapter.md +151 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/excalidraw-diagram-authoring.md +150 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/full-reference.md +1785 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/github-copilot-app-adapter.md +223 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/html-primitives.md +139 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/importing-context.md +132 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/installing-pmx-canvas.md +251 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/tours-and-recording.md +111 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas/references/workbench-workflows.md +900 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas-orchestration/SKILL.md +141 -0
- package/dist/amp-plugin/pmx-canvas/skills/pmx-canvas-testing/SKILL.md +266 -0
- package/dist/amp-plugin/pmx-canvas/start-mcp.mjs +14857 -0
- package/dist/amp-plugin/pmx-canvas/tools.json +10963 -0
- package/dist/canvas/chunks/abnfDiagram-N423BO3Z-cwtsds5d.js +1 -0
- package/dist/canvas/chunks/architecture-TIHT7OUA-x63cwejs.js +1 -0
- package/dist/canvas/chunks/architectureDiagram-T3A2C74G-b4xc9tpz.js +36 -0
- package/dist/canvas/chunks/blockDiagram-VBNYF7ZC-ahp3yxxs.js +132 -0
- package/dist/canvas/chunks/c4Diagram-5PPSVZJV-nappnay7.js +10 -0
- package/dist/canvas/chunks/classDiagram-JCYQIIEL-k1j2xc1t.js +1 -0
- package/dist/canvas/chunks/classDiagram-v2-OCEON4UE-33x08xf2.js +1 -0
- package/dist/canvas/chunks/cose-bilkent-JH36ORCC-a428syda.js +1 -0
- package/dist/canvas/chunks/cynefin-VYW2F7L2-8v6jxfz8.js +1 -0
- package/dist/canvas/chunks/cynefinDiagram-MW4NZA55-nspsqebj.js +62 -0
- package/dist/canvas/chunks/dagre-VZM6K2ZE-8y6177fh.js +4 -0
- package/dist/canvas/chunks/diagram-7IWD3JNH-vym028wn.js +30 -0
- package/dist/canvas/chunks/diagram-B4RE2ZJO-jddqb8sy.js +3 -0
- package/dist/canvas/chunks/diagram-LBJQPF4R-bjwbpkrn.js +24 -0
- package/dist/canvas/chunks/diagram-Q27KOJAE-j6ph6hcx.js +24 -0
- package/dist/canvas/chunks/diagram-UB23O5K3-p09w8jej.js +41 -0
- package/dist/canvas/chunks/ebnfDiagram-BXEA7PRR-j975ycq5.js +1 -0
- package/dist/canvas/chunks/erDiagram-JOGREHBK-sxp6hjn8.js +85 -0
- package/dist/canvas/chunks/eventmodeling-45OFAUF4-xzfgn6xg.js +1 -0
- package/dist/canvas/chunks/flowDiagram-UKHOOZJN-2nsmkskb.js +1 -0
- package/dist/canvas/chunks/ganttDiagram-PKOTCBZU-4tv230y2.js +292 -0
- package/dist/canvas/chunks/gitGraph-TEB2WS4Q-macbhand.js +1 -0
- package/dist/canvas/chunks/gitGraphDiagram-DS77QQ5N-mqgmnw9g.js +106 -0
- package/dist/canvas/chunks/index-037z5dz2.js +232 -0
- package/dist/canvas/chunks/index-081n3har.js +207 -0
- package/dist/canvas/chunks/index-5n03dmb9.js +2 -0
- package/dist/canvas/chunks/index-5tv8v1hk.js +1 -0
- package/dist/canvas/chunks/index-60pgzdqe.js +157 -0
- package/dist/canvas/chunks/index-6ceya556.js +332 -0
- package/dist/canvas/chunks/index-8g1vb57n.js +2 -0
- package/dist/canvas/chunks/index-8rjes9r6.js +2 -0
- package/dist/canvas/chunks/index-9022d1n9.js +16 -0
- package/dist/canvas/chunks/index-9b02042t.js +2 -0
- package/dist/canvas/chunks/index-ap4q4vez.js +2 -0
- package/dist/canvas/chunks/index-dyp2nhd3.js +2 -0
- package/dist/canvas/chunks/index-frvta4tm.js +2 -0
- package/dist/canvas/chunks/index-gf4e0et4.js +2 -0
- package/dist/canvas/chunks/index-h9ycj8n2.js +2 -0
- package/dist/canvas/chunks/index-hj99nz1f.js +1 -0
- package/dist/canvas/chunks/index-mergmj97.js +2 -0
- package/dist/canvas/chunks/index-nwsya6dj.js +301 -0
- package/dist/canvas/chunks/index-nz8qbd1p.js +2 -0
- package/dist/canvas/chunks/index-qhfrazv3.js +2 -0
- package/dist/canvas/chunks/index-v119nznk.js +4 -0
- package/dist/canvas/chunks/index-vpt37m3d.js +89 -0
- package/dist/canvas/chunks/index-y9ma6azy.js +2 -0
- package/dist/canvas/chunks/index-zx0j3a2z.js +179 -0
- package/dist/canvas/chunks/info-DKCQHKI2-a0ykzs9z.js +1 -0
- package/dist/canvas/chunks/infoDiagram-6WML65LV-qv97qq6a.js +2 -0
- package/dist/canvas/chunks/ishikawaDiagram-WSZJBQD7-p9306gh0.js +70 -0
- package/dist/canvas/chunks/journeyDiagram-NVQOT4AX-sv67zats.js +139 -0
- package/dist/canvas/chunks/kanban-definition-27J2QSJJ-k2pfam6p.js +89 -0
- package/dist/canvas/chunks/katex-dmg8k4zm.js +257 -0
- package/dist/canvas/chunks/mermaid.core-83r0fdce.js +12 -0
- package/dist/canvas/chunks/mindmap-definition-FAOFIHXS-vg2newm1.js +96 -0
- package/dist/canvas/chunks/packet-7NZHBO7P-tqnabcdv.js +1 -0
- package/dist/canvas/chunks/pegDiagram-VL7TDLO6-k2h7zc5n.js +1 -0
- package/dist/canvas/chunks/pie-RZYD4A2V-wke6gyhe.js +1 -0
- package/dist/canvas/chunks/pieDiagram-7S7Q4E2Y-hg169p1v.js +39 -0
- package/dist/canvas/chunks/quadrantDiagram-CIZ2JOQS-bxtvsq0b.js +7 -0
- package/dist/canvas/chunks/radar-I7S5WNFK-w7ka0drw.js +1 -0
- package/dist/canvas/chunks/railroad-3IZDKUUU-y3vg318x.js +1 -0
- package/dist/canvas/chunks/railroad-abnf-AHOZXSZD-6hqvcz3c.js +1 -0
- package/dist/canvas/chunks/railroad-ebnf-EBAXGLYW-vcae260m.js +1 -0
- package/dist/canvas/chunks/railroad-peg-LSFZ7HO6-0dbyme23.js +1 -0
- package/dist/canvas/chunks/railroadDiagram-AXF67PYL-njyhcp4p.js +1 -0
- package/dist/canvas/chunks/requirementDiagram-LRYGKXZP-2z6v09gm.js +84 -0
- package/dist/canvas/chunks/sankeyDiagram-W5VNT64P-15mzam0e.js +40 -0
- package/dist/canvas/chunks/sequenceDiagram-SI44F4Z6-rbshyd2c.js +162 -0
- package/dist/canvas/chunks/sizeCapture-X5ZJPWSS-sg26xwts.js +1 -0
- package/dist/canvas/chunks/stateDiagram-OKZ733FA-6eahp98e.js +1 -0
- package/dist/canvas/chunks/stateDiagram-v2-UEYNNEHI-tty0ggn5.js +1 -0
- package/dist/canvas/chunks/swimlanes-SLNWSIFB-ze5db10t.js +1 -0
- package/dist/canvas/chunks/swimlanesDiagram-ULZ7WXOC-thze75gq.js +8 -0
- package/dist/canvas/chunks/timeline-definition-Z64GVDOM-vnp7jyy8.js +120 -0
- package/dist/canvas/chunks/treeView-QDETBFTQ-6ysffnm6.js +1 -0
- package/dist/canvas/chunks/treemap-6X3UGDF4-m3h9p066.js +1 -0
- package/dist/canvas/chunks/vennDiagram-T6HMQDX7-0qrnb7mj.js +34 -0
- package/dist/canvas/chunks/wardley-OPB4EBWU-dp37drwx.js +1 -0
- package/dist/canvas/chunks/wardleyDiagram-T6FBY63Y-8nxg8wqt.js +78 -0
- package/dist/canvas/chunks/xychartDiagram-ELKLHX3M-nj921e7s.js +7 -0
- package/dist/canvas/global.css +483 -230
- package/dist/canvas/index.js +158 -219
- package/dist/canvas/mcp-app.html +4301 -548
- package/dist/canvas/mermaid-entry.js +338 -338
- package/dist/canvas/surface-theme.css +6 -6
- package/dist/json-render/index.css +1 -1
- package/dist/json-render/index.js +49 -49
- package/dist/types/client/canvas/BarHint.d.ts +5 -3
- package/dist/types/client/canvas/BoardMoveDialog.d.ts +2 -0
- package/dist/types/client/canvas/CanvasNode.d.ts +0 -11
- package/dist/types/client/canvas/EdgeEditor.d.ts +19 -0
- package/dist/types/client/canvas/EdgeLayer.d.ts +1 -2
- package/dist/types/client/canvas/GroupNavigation.d.ts +2 -0
- package/dist/types/client/canvas/TextPrompt.d.ts +4 -0
- package/dist/types/client/canvas/auto-fit.d.ts +4 -5
- package/dist/types/client/mermaid-entry.d.ts +1 -2
- package/dist/types/client/mermaid-render.d.ts +1 -0
- package/dist/types/client/nodes/BoardNode.d.ts +1 -1
- package/dist/types/client/nodes/ExtAppFrame.d.ts +7 -90
- package/dist/types/client/nodes/McpAppNode.d.ts +1 -25
- package/dist/types/client/nodes/MermaidNode.d.ts +1 -8
- package/dist/types/client/nodes/PromptNode.d.ts +1 -0
- package/dist/types/client/nodes/ViewerFrame.d.ts +29 -0
- package/dist/types/client/nodes/ViewerHost.d.ts +6 -0
- package/dist/types/client/nodes/WorkCard.d.ts +7 -0
- package/dist/types/client/nodes/iframe-document-url.d.ts +3 -9
- package/dist/types/client/nodes/primitive-copy.d.ts +5 -0
- package/dist/types/client/nodes/use-ax-surface-bridge.d.ts +1 -0
- package/dist/types/client/nodes/use-iframe-content-height.d.ts +1 -1
- package/dist/types/client/nodes/use-surface-frame.d.ts +4 -6
- package/dist/types/client/nodes/viewer-runtime-state.d.ts +2 -1
- package/dist/types/client/state/canvas-store.d.ts +18 -1
- package/dist/types/client/state/human-store.d.ts +2 -0
- package/dist/types/client/state/intent-bridge.d.ts +5 -2
- package/dist/types/client/state/presentation.d.ts +17 -6
- package/dist/types/client/state/relation-store.d.ts +11 -0
- package/dist/types/client/types.d.ts +1 -1
- package/dist/types/json-render/catalog.d.ts +2 -2
- package/dist/types/json-render/server.d.ts +2 -1
- package/dist/types/server/agent-presence.d.ts +1 -0
- package/dist/types/server/ax-interaction.d.ts +1 -0
- package/dist/types/server/ax-state-manager.d.ts +10 -2
- package/dist/types/server/board-local.d.ts +4 -0
- package/dist/types/server/board-move.d.ts +38 -0
- package/dist/types/server/canvas-db.d.ts +12 -2
- package/dist/types/server/canvas-operations.d.ts +5 -6
- package/dist/types/server/canvas-provenance.d.ts +1 -1
- package/dist/types/server/canvas-serialization.d.ts +1 -0
- package/dist/types/server/canvas-state.d.ts +86 -20
- package/dist/types/server/card-relocation.d.ts +6 -0
- package/dist/types/server/context-reads.d.ts +3 -1
- package/dist/types/server/human-presence.d.ts +1 -1
- package/dist/types/server/index.d.ts +26 -10
- package/dist/types/server/intent-registry.d.ts +8 -4
- package/dist/types/server/knowledge-lifecycle.d.ts +4 -2
- package/dist/types/server/mutation-history.d.ts +7 -5
- package/dist/types/server/operations/ops/boards.d.ts +0 -1
- package/dist/types/server/operations/registry.d.ts +2 -0
- package/dist/types/server/tour-control.d.ts +13 -3
- package/dist/types/server/trace-manager.d.ts +1 -0
- package/dist/types/shared/ax-kinds.d.ts +6 -0
- package/dist/types/shared/ax-surface-protocol.d.ts +8 -9
- package/dist/types/shared/human-presence.d.ts +1 -0
- package/dist/types/shared/lifecycle-status.d.ts +2 -0
- package/dist/types/shared/tour.d.ts +8 -0
- package/docs/RELEASE.md +21 -14
- package/docs/agent-plugin.md +16 -2
- package/docs/amp-plugin.md +271 -0
- package/docs/cli.md +42 -3
- package/docs/design/Chrome.dc.html +32 -6
- package/docs/design/GuestName.dc.html +50 -0
- package/docs/design/PluginLogo.svg +7 -0
- package/docs/design/Types1.dc.html +3 -2
- package/docs/design/Types2.dc.html +1 -1
- package/docs/design/Types3.dc.html +1 -1
- package/docs/design/WorkCards.dc.html +39 -0
- package/docs/design/Zoom.dc.html +37 -60
- package/docs/design/canvas.json +17 -1
- package/docs/design/plugin-logo.png +0 -0
- package/docs/design.md +280 -12
- package/docs/evals/agents-md-sections.md +38 -0
- package/docs/http-api.md +179 -11
- package/docs/mcp.md +69 -9
- package/docs/node-types.md +109 -4
- package/docs/plans/plan-009-tech-debt-backlog.md +3 -3
- package/docs/plans/plan-019-post-0.9-roadmap.md +327 -31
- package/docs/plans/plan-020-wave-5-work-planning.md +553 -0
- package/docs/product-vision-2026-09.md +42 -17
- package/docs/sdk.md +18 -0
- package/package.json +7 -4
- package/plugins/pmx-canvas/assets/preview.png +0 -0
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/extension.mjs +3 -1
- package/plugins/pmx-canvas/com.github.copilot/extensions/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/plugin.json +2 -2
- package/plugins/pmx-canvas/runtime.json +1 -1
- package/plugins/pmx-canvas/tools.json +688 -128
- package/skills/data-analysis/SKILL.md +13 -26
- package/skills/frontend-design/LICENSE.txt +177 -0
- package/skills/frontend-design/SKILL.md +3 -0
- package/skills/pmx-canvas/SKILL.md +232 -849
- package/skills/pmx-canvas/evals/evals.json +26 -3
- package/skills/pmx-canvas/references/full-reference.md +89 -24
- package/skills/pmx-canvas/references/html-primitives.md +7 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +6 -6
- package/skills/pmx-canvas/references/tours-and-recording.md +29 -2
- package/skills/pmx-canvas/references/workbench-workflows.md +900 -0
- package/skills/pmx-canvas-testing/SKILL.md +7 -5
- package/skills/published-consumer-e2e/SKILL.md +25 -8
- package/skills/published-consumer-e2e/scripts/run-published-consumer-e2e.sh +51 -77
- package/skills/web-artifacts-builder/LICENSE.txt +202 -0
- package/skills/web-artifacts-builder/SKILL.md +6 -0
- package/skills/web-artifacts-builder/scripts/init-artifact.sh +2 -2
- package/src/cli/commands/apps.ts +1 -0
- package/src/cli/commands/boards.ts +30 -0
- package/src/client/App.tsx +20 -4
- package/src/client/canvas/AttentionHistory.tsx +10 -2
- package/src/client/canvas/BarHint.tsx +6 -3
- package/src/client/canvas/BoardMoveDialog.tsx +225 -0
- package/src/client/canvas/CanvasNode.tsx +79 -49
- package/src/client/canvas/CanvasViewport.tsx +42 -14
- package/src/client/canvas/ContextMenu.tsx +97 -15
- package/src/client/canvas/EdgeEditor.tsx +149 -0
- package/src/client/canvas/EdgeLayer.tsx +441 -174
- package/src/client/canvas/ExpandedNodeOverlay.tsx +5 -2
- package/src/client/canvas/GroupNavigation.tsx +85 -0
- package/src/client/canvas/Presentation.tsx +53 -3
- package/src/client/canvas/RelationsPanel.tsx +9 -0
- package/src/client/canvas/SelectionBar.tsx +21 -0
- package/src/client/canvas/SessionPanel.tsx +35 -1
- package/src/client/canvas/TextPrompt.tsx +18 -1
- package/src/client/canvas/TopBar.tsx +54 -9
- package/src/client/canvas/auto-fit.ts +9 -11
- package/src/client/canvas/canvas-area.ts +2 -2
- package/src/client/canvas/use-focus-trap.ts +6 -1
- package/src/client/mermaid-entry.ts +6 -20
- package/src/client/mermaid-render.ts +39 -0
- package/src/client/nodes/AxStepControls.tsx +45 -69
- package/src/client/nodes/BoardNode.tsx +65 -9
- package/src/client/nodes/ContextNode.tsx +88 -396
- package/src/client/nodes/ExtAppFrame.tsx +302 -1465
- package/src/client/nodes/FileNode.tsx +92 -81
- package/src/client/nodes/HtmlNode.tsx +8 -36
- package/src/client/nodes/LedgerNode.tsx +31 -17
- package/src/client/nodes/MarkdownNode.tsx +14 -24
- package/src/client/nodes/McpAppNode.tsx +48 -154
- package/src/client/nodes/MermaidNode.tsx +80 -69
- package/src/client/nodes/PromptNode.tsx +44 -17
- package/src/client/nodes/ResponseNode.tsx +8 -6
- package/src/client/nodes/StatusNode.tsx +34 -7
- package/src/client/nodes/StatusSummary.tsx +16 -3
- package/src/client/nodes/TraceNode.tsx +8 -8
- package/src/client/nodes/ViewerFrame.tsx +273 -0
- package/src/client/nodes/ViewerHost.tsx +41 -0
- package/src/client/nodes/WebpageNode.tsx +22 -24
- package/src/client/nodes/WorkCard.tsx +175 -0
- package/src/client/nodes/iframe-document-url.ts +20 -27
- package/src/client/nodes/primitive-copy.ts +97 -0
- package/src/client/nodes/use-ax-surface-bridge.ts +18 -14
- package/src/client/nodes/use-iframe-content-height.ts +34 -10
- package/src/client/nodes/use-surface-frame.ts +22 -11
- package/src/client/nodes/viewer-runtime-state.ts +41 -35
- package/src/client/state/attention-bridge.ts +5 -0
- package/src/client/state/attention-store.ts +1 -0
- package/src/client/state/canvas-store.ts +202 -26
- package/src/client/state/human-store.ts +22 -2
- package/src/client/state/intent-bridge.ts +20 -5
- package/src/client/state/presentation.ts +135 -15
- package/src/client/state/relation-store.ts +127 -1
- package/src/client/state/sse-bridge.ts +18 -19
- package/src/client/theme/global.css +483 -230
- package/src/client/theme/surface-theme.css +6 -6
- package/src/client/types.ts +1 -0
- package/src/json-render/charts/tufte-components.tsx +44 -2
- package/src/json-render/renderer/index.css +62 -2
- package/src/json-render/renderer/index.tsx +31 -7
- package/src/json-render/server.ts +3 -2
- package/src/mcp/server.ts +13 -3
- package/src/server/agent-presence.ts +43 -23
- package/src/server/ax-flow-loop.ts +6 -0
- package/src/server/ax-gate-ttl.ts +8 -1
- package/src/server/ax-interaction.ts +16 -10
- package/src/server/ax-state-manager.ts +17 -4
- package/src/server/ax-wait.ts +20 -6
- package/src/server/board-export.ts +54 -30
- package/src/server/board-local.ts +20 -0
- package/src/server/board-move.ts +297 -0
- package/src/server/canvas-db.ts +249 -158
- package/src/server/canvas-geometry.ts +1 -0
- package/src/server/canvas-operations.ts +139 -109
- package/src/server/canvas-schema.ts +21 -0
- package/src/server/canvas-serialization.ts +2 -0
- package/src/server/canvas-state.ts +797 -159
- package/src/server/card-relocation.ts +53 -0
- package/src/server/code-graph.ts +4 -3
- package/src/server/context-reads.ts +83 -55
- package/src/server/demo-state.json +140 -114
- package/src/server/file-watcher.ts +30 -10
- package/src/server/html-primitives.ts +3 -9
- package/src/server/html-surface.ts +8 -0
- package/src/server/human-presence.ts +18 -5
- package/src/server/index.ts +54 -24
- package/src/server/intent-registry.ts +43 -5
- package/src/server/knowledge-lifecycle.ts +32 -9
- package/src/server/lifecycle-status.ts +29 -1
- package/src/server/mcp-app-runtime.ts +26 -7
- package/src/server/mutation-history.ts +37 -8
- package/src/server/operations/composites.ts +6 -3
- package/src/server/operations/mcp-contracts.ts +32 -2
- package/src/server/operations/mcp.ts +36 -9
- package/src/server/operations/ops/annotation.ts +22 -1
- package/src/server/operations/ops/ax-await.ts +1 -0
- package/src/server/operations/ops/ax-timeline.ts +28 -2
- package/src/server/operations/ops/batch.ts +25 -11
- package/src/server/operations/ops/boards.ts +45 -6
- package/src/server/operations/ops/nodes.ts +70 -0
- package/src/server/operations/ops/query.ts +32 -3
- package/src/server/operations/ops/snapshots.ts +1 -0
- package/src/server/operations/ops/viewport.ts +11 -9
- package/src/server/operations/registry.ts +49 -4
- package/src/server/server.ts +69 -75
- package/src/server/tour-control.ts +97 -12
- package/src/server/trace-manager.ts +4 -0
- package/src/server/web-artifacts/scripts/init-artifact.sh +2 -2
- package/src/shared/agent-context.ts +7 -1
- package/src/shared/auto-arrange.ts +5 -4
- package/src/shared/ax-kinds.ts +13 -0
- package/src/shared/ax-surface-protocol.ts +20 -9
- package/src/shared/content-height-reporter.ts +4 -3
- package/src/shared/human-presence.ts +1 -0
- package/src/shared/lifecycle-status.ts +2 -0
- package/src/shared/tour.ts +8 -0
package/src/server/canvas-db.ts
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import { Database } from 'bun:sqlite';
|
|
9
9
|
import type { ActorAttribution } from './attribution.js';
|
|
10
10
|
import { CONTEXT_READS_SCHEMA_SQL } from './context-reads.js';
|
|
11
|
+
import { OperationError } from './operations/types.js';
|
|
12
|
+
import { boardMoveBoundary } from './card-relocation.js';
|
|
11
13
|
import { MIGRATED_SNAPSHOT_FOLDER, normalizeBoardFolder } from '../shared/boards.js';
|
|
12
14
|
import { wikiLinksFromData } from '../shared/memory-graph.js';
|
|
13
15
|
import { relationVocabularySchema, type RelationDefinition } from '../shared/relations.js';
|
|
@@ -56,6 +58,20 @@ export function normalizeCanvasTheme(value: unknown, fallback: CanvasTheme = 'ha
|
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
const SCHEMA_SQL = `
|
|
61
|
+
CREATE TABLE IF NOT EXISTS board_moves (
|
|
62
|
+
request_id TEXT PRIMARY KEY, fingerprint TEXT NOT NULL, result TEXT NOT NULL, created_at TEXT NOT NULL
|
|
63
|
+
);
|
|
64
|
+
CREATE TABLE IF NOT EXISTS board_move_boundaries (
|
|
65
|
+
board_id TEXT PRIMARY KEY, request_id TEXT NOT NULL
|
|
66
|
+
);
|
|
67
|
+
CREATE TABLE IF NOT EXISTS card_relocations (
|
|
68
|
+
sequence INTEGER PRIMARY KEY AUTOINCREMENT, request_id TEXT NOT NULL, node_id TEXT NOT NULL,
|
|
69
|
+
from_board TEXT NOT NULL, to_board TEXT NOT NULL,
|
|
70
|
+
review_after INTEGER NOT NULL, review_through INTEGER NOT NULL,
|
|
71
|
+
read_after INTEGER NOT NULL, read_through INTEGER NOT NULL
|
|
72
|
+
);
|
|
73
|
+
CREATE INDEX IF NOT EXISTS relocation_destination ON card_relocations(to_board, node_id, sequence);
|
|
74
|
+
CREATE INDEX IF NOT EXISTS relocation_source ON card_relocations(from_board, node_id, sequence);
|
|
59
75
|
CREATE TABLE IF NOT EXISTS node_creation_requests (
|
|
60
76
|
request_id TEXT PRIMARY KEY, board_id TEXT NOT NULL, fingerprint TEXT NOT NULL, node TEXT NOT NULL
|
|
61
77
|
);
|
|
@@ -357,6 +373,10 @@ function parsePersistedAxState(raw: string | null | undefined): PmxAxState {
|
|
|
357
373
|
// ── Persisted State Interface ───────────────────────────────────
|
|
358
374
|
|
|
359
375
|
export interface PersistedCanvasState {
|
|
376
|
+
/** Optimistic storage baseline, independent of content/read/review clocks. New boards start at zero. */
|
|
377
|
+
storageVersion?: number;
|
|
378
|
+
/** Snapshot restore boundary, not an authored content version. */
|
|
379
|
+
moveBoundary?: string | null;
|
|
360
380
|
tour?: Tour;
|
|
361
381
|
version: number;
|
|
362
382
|
theme?: CanvasTheme;
|
|
@@ -513,6 +533,28 @@ export function openCanvasDb(dbPath: string, options: OpenCanvasDbOptions = {}):
|
|
|
513
533
|
ensureColumn(db, 'snapshot_edges', 'revision', 'revision INTEGER NOT NULL DEFAULT 0');
|
|
514
534
|
ensureColumn(db, 'snapshot_edges', 'attribution', "attribution TEXT NOT NULL DEFAULT '{}'");
|
|
515
535
|
ensureColumn(db, 'document_imports', 'committed_node_ids', 'committed_node_ids TEXT');
|
|
536
|
+
ensureColumn(db, 'boards', 'storage_version', 'storage_version INTEGER NOT NULL DEFAULT 0');
|
|
537
|
+
// Cover direct writers as well as full-state saves. A relocation updates both
|
|
538
|
+
// board baselines; a stale source or destination payload must never recreate it.
|
|
539
|
+
for (const table of ['nodes', 'edges', 'annotations', 'context_pins', 'ax_state']) {
|
|
540
|
+
db.exec(`
|
|
541
|
+
CREATE TRIGGER IF NOT EXISTS ${table}_storage_insert AFTER INSERT ON ${table} BEGIN
|
|
542
|
+
UPDATE boards SET storage_version = storage_version + 1 WHERE id = NEW.board_id;
|
|
543
|
+
END;
|
|
544
|
+
CREATE TRIGGER IF NOT EXISTS ${table}_storage_delete AFTER DELETE ON ${table} BEGIN
|
|
545
|
+
UPDATE boards SET storage_version = storage_version + 1 WHERE id = OLD.board_id;
|
|
546
|
+
END;
|
|
547
|
+
CREATE TRIGGER IF NOT EXISTS ${table}_storage_update AFTER UPDATE ON ${table} BEGIN
|
|
548
|
+
UPDATE boards SET storage_version = storage_version + 1 WHERE id IN (OLD.board_id, NEW.board_id);
|
|
549
|
+
END;
|
|
550
|
+
`);
|
|
551
|
+
}
|
|
552
|
+
db.exec(`
|
|
553
|
+
CREATE TRIGGER IF NOT EXISTS boards_storage_view
|
|
554
|
+
AFTER UPDATE OF viewport_x, viewport_y, viewport_scale, tour ON boards BEGIN
|
|
555
|
+
UPDATE boards SET storage_version = storage_version + 1 WHERE id = NEW.id;
|
|
556
|
+
END;
|
|
557
|
+
`);
|
|
516
558
|
|
|
517
559
|
// Set schema version if not present
|
|
518
560
|
const row = db.query<{ value: string }, [string]>('SELECT value FROM meta WHERE key = ?').get('schema_version');
|
|
@@ -762,9 +804,26 @@ export function readThemeFromDB(db: Database): CanvasTheme | undefined {
|
|
|
762
804
|
return value ? normalizeCanvasTheme(value) : undefined;
|
|
763
805
|
}
|
|
764
806
|
|
|
765
|
-
|
|
766
|
-
|
|
807
|
+
export function boardStorageVersion(db: Database, boardId: string): number {
|
|
808
|
+
const board = db
|
|
809
|
+
.query<{ storage_version: number }, [string]>('SELECT storage_version FROM boards WHERE id = ?')
|
|
810
|
+
.get(boardId);
|
|
811
|
+
if (!board) throw new OperationError(`Board "${boardId}" not found.`, 404);
|
|
812
|
+
return board.storage_version;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
export function assertBoardStorageVersion(db: Database, boardId: string, expected: number): void {
|
|
816
|
+
if (boardStorageVersion(db, boardId) !== expected)
|
|
817
|
+
throw new OperationError(
|
|
818
|
+
`Board "${boardId}" changed in another writer. Unsaved edits have been retained; reconcile them before saving.`,
|
|
819
|
+
409,
|
|
820
|
+
);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/** Save one board, returning its new baseline. Publish the baseline only after the outer transaction commits. */
|
|
824
|
+
export function saveStateToDB(db: Database, boardId: string, state: PersistedCanvasState): number {
|
|
767
825
|
const transaction = db.transaction(() => {
|
|
826
|
+
assertBoardStorageVersion(db, boardId, state.storageVersion ?? 0);
|
|
768
827
|
// Rows are upserted only when a column actually differs, and rows that are
|
|
769
828
|
// gone are deleted by id. This used to be DELETE-all + INSERT-all, which
|
|
770
829
|
// rewrote every row on every debounced save: dragging one node rewrote the
|
|
@@ -920,157 +979,164 @@ export function saveStateToDB(db: Database, boardId: string, state: PersistedCan
|
|
|
920
979
|
WHERE value IS NOT excluded.value`,
|
|
921
980
|
[boardId, 'revision', JSON.stringify(state.revisionState ?? { revision: 0, floor: 0, tombstones: [] })],
|
|
922
981
|
);
|
|
982
|
+
return boardStorageVersion(db, boardId);
|
|
923
983
|
});
|
|
924
984
|
|
|
925
|
-
transaction();
|
|
985
|
+
return transaction.immediate();
|
|
926
986
|
}
|
|
927
987
|
|
|
928
988
|
/** Loads one board (the open board when `boardId` is omitted); null when there is no such board. */
|
|
929
989
|
export function loadStateFromDB(db: Database, boardId?: string): PersistedCanvasState | null {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
scale: board.viewport_scale || 1,
|
|
947
|
-
};
|
|
948
|
-
const theme = readThemeFromDB(db);
|
|
990
|
+
return db.transaction(() => {
|
|
991
|
+
const id = boardId ?? getActiveBoardIdFromDB(db);
|
|
992
|
+
if (!id) return null;
|
|
993
|
+
interface BoardRow {
|
|
994
|
+
viewport_x: number;
|
|
995
|
+
viewport_y: number;
|
|
996
|
+
viewport_scale: number;
|
|
997
|
+
tour: string;
|
|
998
|
+
storage_version: number;
|
|
999
|
+
}
|
|
1000
|
+
const board = db
|
|
1001
|
+
.query<BoardRow, [string]>(
|
|
1002
|
+
'SELECT viewport_x, viewport_y, viewport_scale, tour, storage_version FROM boards WHERE id = ?',
|
|
1003
|
+
)
|
|
1004
|
+
.get(id);
|
|
1005
|
+
if (!board) return null;
|
|
949
1006
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
pos_x: number;
|
|
955
|
-
pos_y: number;
|
|
956
|
-
width: number;
|
|
957
|
-
height: number;
|
|
958
|
-
z_index: number;
|
|
959
|
-
collapsed: number;
|
|
960
|
-
pinned: number;
|
|
961
|
-
data: string;
|
|
962
|
-
attribution: string;
|
|
963
|
-
content_revision: number;
|
|
964
|
-
links_revision: number;
|
|
965
|
-
}
|
|
966
|
-
const nodeRows = db.query<NodeRow, [string]>('SELECT * FROM nodes WHERE board_id = ?').all(id);
|
|
967
|
-
const nodes: CanvasNodeState[] = nodeRows.map((row) => {
|
|
968
|
-
const attribution = JSON.parse(row.attribution || '{}') as Partial<
|
|
969
|
-
Pick<CanvasNodeState, 'createdBy' | 'lastEditedBy' | 'contentChangedAt' | 'freshnessStartedAt'>
|
|
970
|
-
>;
|
|
971
|
-
return {
|
|
972
|
-
id: row.id,
|
|
973
|
-
type: row.type as CanvasNodeState['type'],
|
|
974
|
-
position: { x: row.pos_x, y: row.pos_y },
|
|
975
|
-
size: { width: row.width, height: row.height },
|
|
976
|
-
zIndex: row.z_index,
|
|
977
|
-
collapsed: row.collapsed === 1,
|
|
978
|
-
pinned: row.pinned === 1,
|
|
979
|
-
data: JSON.parse(row.data) as Record<string, unknown>,
|
|
980
|
-
createdBy: attribution.createdBy,
|
|
981
|
-
lastEditedBy: attribution.lastEditedBy,
|
|
982
|
-
contentChangedAt: attribution.contentChangedAt,
|
|
983
|
-
freshnessStartedAt: attribution.freshnessStartedAt,
|
|
984
|
-
contentRevision: row.content_revision,
|
|
985
|
-
linksRevision: row.links_revision,
|
|
1007
|
+
const viewport: ViewportState = {
|
|
1008
|
+
x: board.viewport_x,
|
|
1009
|
+
y: board.viewport_y,
|
|
1010
|
+
scale: board.viewport_scale || 1,
|
|
986
1011
|
};
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1012
|
+
const theme = readThemeFromDB(db);
|
|
1013
|
+
|
|
1014
|
+
// Load nodes
|
|
1015
|
+
interface NodeRow {
|
|
1016
|
+
id: string;
|
|
1017
|
+
type: string;
|
|
1018
|
+
pos_x: number;
|
|
1019
|
+
pos_y: number;
|
|
1020
|
+
width: number;
|
|
1021
|
+
height: number;
|
|
1022
|
+
z_index: number;
|
|
1023
|
+
collapsed: number;
|
|
1024
|
+
pinned: number;
|
|
1025
|
+
data: string;
|
|
1026
|
+
attribution: string;
|
|
1027
|
+
content_revision: number;
|
|
1028
|
+
links_revision: number;
|
|
1029
|
+
}
|
|
1030
|
+
const nodeRows = db.query<NodeRow, [string]>('SELECT * FROM nodes WHERE board_id = ?').all(id);
|
|
1031
|
+
const nodes: CanvasNodeState[] = nodeRows.map((row) => {
|
|
1032
|
+
const attribution = JSON.parse(row.attribution || '{}') as Partial<
|
|
1033
|
+
Pick<CanvasNodeState, 'createdBy' | 'lastEditedBy' | 'contentChangedAt' | 'freshnessStartedAt'>
|
|
1034
|
+
>;
|
|
1035
|
+
return {
|
|
1036
|
+
id: row.id,
|
|
1037
|
+
type: row.type as CanvasNodeState['type'],
|
|
1038
|
+
position: { x: row.pos_x, y: row.pos_y },
|
|
1039
|
+
size: { width: row.width, height: row.height },
|
|
1040
|
+
zIndex: row.z_index,
|
|
1041
|
+
collapsed: row.collapsed === 1,
|
|
1042
|
+
pinned: row.pinned === 1,
|
|
1043
|
+
data: JSON.parse(row.data) as Record<string, unknown>,
|
|
1044
|
+
createdBy: attribution.createdBy,
|
|
1045
|
+
lastEditedBy: attribution.lastEditedBy,
|
|
1046
|
+
contentChangedAt: attribution.contentChangedAt,
|
|
1047
|
+
freshnessStartedAt: attribution.freshnessStartedAt,
|
|
1048
|
+
contentRevision: row.content_revision,
|
|
1049
|
+
linksRevision: row.links_revision,
|
|
1050
|
+
};
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
// Load edges
|
|
1054
|
+
interface EdgeRow {
|
|
1055
|
+
id: string;
|
|
1056
|
+
from_node: string;
|
|
1057
|
+
to_node: string;
|
|
1058
|
+
to_board_id: string | null;
|
|
1059
|
+
type: string;
|
|
1060
|
+
kind: string | null;
|
|
1061
|
+
reason: string | null;
|
|
1062
|
+
label: string | null;
|
|
1063
|
+
style: string | null;
|
|
1064
|
+
animated: number;
|
|
1065
|
+
revision: number;
|
|
1066
|
+
attribution: string;
|
|
1067
|
+
}
|
|
1068
|
+
const edgeRows = db.query<EdgeRow, [string]>('SELECT * FROM edges WHERE board_id = ?').all(id);
|
|
1069
|
+
const edges: CanvasEdge[] = edgeRows.map((row) => ({
|
|
1070
|
+
id: row.id,
|
|
1071
|
+
from: row.from_node,
|
|
1072
|
+
to: row.to_node,
|
|
1073
|
+
...(row.to_board_id ? { toBoardId: row.to_board_id } : {}),
|
|
1074
|
+
type: row.type as CanvasEdge['type'],
|
|
1075
|
+
...(row.kind ? { kind: row.kind } : {}),
|
|
1076
|
+
...(row.reason ? { reason: row.reason } : {}),
|
|
1077
|
+
...(row.label ? { label: row.label } : {}),
|
|
1078
|
+
...(row.style ? { style: row.style as CanvasEdge['style'] } : {}),
|
|
1079
|
+
...(row.animated ? { animated: true } : {}),
|
|
1080
|
+
...(row.revision ? { revision: row.revision } : {}),
|
|
1081
|
+
...(JSON.parse(row.attribution || '{}') as EdgeAttribution),
|
|
1082
|
+
}));
|
|
1083
|
+
|
|
1084
|
+
// Load annotations
|
|
1085
|
+
interface AnnotationRow {
|
|
1086
|
+
id: string;
|
|
1087
|
+
type: string;
|
|
1088
|
+
points: string;
|
|
1089
|
+
bounds: string;
|
|
1090
|
+
color: string;
|
|
1091
|
+
width: number;
|
|
1092
|
+
text: string | null;
|
|
1093
|
+
label: string | null;
|
|
1094
|
+
created_at: string;
|
|
1095
|
+
}
|
|
1096
|
+
const annotationRows = db.query<AnnotationRow, [string]>('SELECT * FROM annotations WHERE board_id = ?').all(id);
|
|
1097
|
+
const annotations: CanvasAnnotation[] = annotationRows.map((row) => ({
|
|
1098
|
+
id: row.id,
|
|
1099
|
+
type: row.type as CanvasAnnotation['type'],
|
|
1100
|
+
points: JSON.parse(row.points),
|
|
1101
|
+
bounds: JSON.parse(row.bounds),
|
|
1102
|
+
color: row.color,
|
|
1103
|
+
width: row.width,
|
|
1104
|
+
...(row.text ? { text: row.text } : {}),
|
|
1105
|
+
...(row.label ? { label: row.label } : {}),
|
|
1106
|
+
createdAt: row.created_at,
|
|
1107
|
+
}));
|
|
1108
|
+
|
|
1109
|
+
// Load context pins
|
|
1110
|
+
interface PinRow {
|
|
1111
|
+
node_id: string;
|
|
1112
|
+
meta: string | null;
|
|
1113
|
+
}
|
|
1114
|
+
const pinRows = db.query<PinRow, [string]>('SELECT node_id, meta FROM context_pins WHERE board_id = ?').all(id);
|
|
1115
|
+
const contextPins = pinRows.map((row) => row.node_id);
|
|
1116
|
+
const contextPinMeta = pinMetaFromRows(pinRows);
|
|
1053
1117
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1118
|
+
const axRow = db
|
|
1119
|
+
.query<{ value: string }, [string, string]>('SELECT value FROM ax_state WHERE board_id = ? AND key = ?')
|
|
1120
|
+
.get(id, 'state');
|
|
1057
1121
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1122
|
+
const revisionRaw = db
|
|
1123
|
+
.query<{ value: string }, [string, string]>('SELECT value FROM ax_state WHERE board_id = ? AND key = ?')
|
|
1124
|
+
.get(id, 'revision')?.value;
|
|
1125
|
+
return {
|
|
1126
|
+
storageVersion: board.storage_version,
|
|
1127
|
+
version: 1,
|
|
1128
|
+
theme,
|
|
1129
|
+
tour: readTour(board.tour),
|
|
1130
|
+
viewport,
|
|
1131
|
+
nodes,
|
|
1132
|
+
edges,
|
|
1133
|
+
annotations,
|
|
1134
|
+
contextPins,
|
|
1135
|
+
contextPinMeta,
|
|
1136
|
+
ax: parsePersistedAxState(axRow?.value),
|
|
1137
|
+
revisionState: revisionRaw ? (JSON.parse(revisionRaw) as PersistedRevisionState) : undefined,
|
|
1138
|
+
};
|
|
1139
|
+
})();
|
|
1074
1140
|
}
|
|
1075
1141
|
|
|
1076
1142
|
// ── Boards ──────────────────────────────────────────────────────
|
|
@@ -1387,6 +1453,7 @@ export function saveSnapshotToDB(
|
|
|
1387
1453
|
state: PersistedCanvasState,
|
|
1388
1454
|
): void {
|
|
1389
1455
|
const transaction = db.transaction(() => {
|
|
1456
|
+
assertBoardStorageVersion(db, boardId, state.storageVersion ?? 0);
|
|
1390
1457
|
// Insert snapshot metadata
|
|
1391
1458
|
db.run('INSERT INTO snapshots (id, board_id, name, created_at, node_count, edge_count) VALUES (?, ?, ?, ?, ?, ?)', [
|
|
1392
1459
|
snapshot.id,
|
|
@@ -1402,6 +1469,11 @@ export function saveSnapshotToDB(
|
|
|
1402
1469
|
'tour',
|
|
1403
1470
|
JSON.stringify(state.tour ?? null),
|
|
1404
1471
|
]);
|
|
1472
|
+
db.run('INSERT INTO snapshot_meta (snapshot_id, key, value) VALUES (?, ?, ?)', [
|
|
1473
|
+
snapshot.id,
|
|
1474
|
+
'move_boundary',
|
|
1475
|
+
boardMoveBoundary(db, boardId) ?? '',
|
|
1476
|
+
]);
|
|
1405
1477
|
// Insert snapshot viewport meta
|
|
1406
1478
|
db.run('INSERT INTO snapshot_meta (snapshot_id, key, value) VALUES (?, ?, ?)', [
|
|
1407
1479
|
snapshot.id,
|
|
@@ -1508,7 +1580,7 @@ export function saveSnapshotToDB(
|
|
|
1508
1580
|
]);
|
|
1509
1581
|
});
|
|
1510
1582
|
|
|
1511
|
-
transaction();
|
|
1583
|
+
transaction.immediate();
|
|
1512
1584
|
}
|
|
1513
1585
|
|
|
1514
1586
|
/** By id or name (most recent match) on `boardId`. */
|
|
@@ -1679,6 +1751,7 @@ export function loadSnapshotFromDB(
|
|
|
1679
1751
|
return {
|
|
1680
1752
|
snapshot,
|
|
1681
1753
|
state: {
|
|
1754
|
+
moveBoundary: metaMap.get('move_boundary') || null,
|
|
1682
1755
|
version: 1,
|
|
1683
1756
|
tour: readTour(metaMap.get('tour')),
|
|
1684
1757
|
viewport,
|
|
@@ -2019,28 +2092,37 @@ export function loadAxSteeringFromDB(
|
|
|
2019
2092
|
|
|
2020
2093
|
export function loadPendingAxSteeringFromDB(
|
|
2021
2094
|
db: Database,
|
|
2022
|
-
options: { consumer?: string; limit?: number } = {},
|
|
2095
|
+
options: { consumer?: string; limit?: number; addressedOnly?: boolean; offset?: number } = {},
|
|
2023
2096
|
): PmxAxSteeringMessage[] {
|
|
2097
|
+
if (options.addressedOnly && !options.consumer) return [];
|
|
2024
2098
|
// FIFO (oldest undelivered first); exclude the consumer's own steering (loop
|
|
2025
2099
|
// prevention) and any steering addressed to a DIFFERENT consumer (target scoping)
|
|
2026
2100
|
// in SQL so the LIMIT is applied AFTER both filters, not before.
|
|
2027
2101
|
const limit = clampTimelineLimit(options.limit);
|
|
2028
2102
|
const rows = options.consumer
|
|
2029
2103
|
? db
|
|
2030
|
-
.query<AxSteeringRow, [string, string, string, string, string, number]>(
|
|
2104
|
+
.query<AxSteeringRow, [string, string, string, string, string, number, number]>(
|
|
2031
2105
|
// A broadcast stays pending PER CONSUMER: it leaves this consumer's
|
|
2032
2106
|
// queue only once THIS consumer marked it (or an anonymous global ack
|
|
2033
2107
|
// set delivered).
|
|
2034
|
-
|
|
2108
|
+
`SELECT * FROM ax_steering s WHERE s.delivered = 0 AND (s.source IS NULL OR s.source != ?) AND (s.agent_id IS NULL OR s.agent_id != ?) AND (s.target IS NULL OR s.target = ?) ${options.addressedOnly ? 'AND s.target IS NOT NULL' : ''} AND (s.target IS NOT NULL OR s.created_at > ?) AND NOT EXISTS (SELECT 1 FROM ax_steering_deliveries d WHERE d.steering_id = s.id AND d.consumer = ?) ORDER BY s.seq ASC LIMIT ? OFFSET ?`,
|
|
2109
|
+
)
|
|
2110
|
+
.all(
|
|
2111
|
+
options.consumer,
|
|
2112
|
+
options.consumer,
|
|
2113
|
+
options.consumer,
|
|
2114
|
+
broadcastCutoffIso(),
|
|
2115
|
+
options.consumer,
|
|
2116
|
+
limit,
|
|
2117
|
+
options.offset ?? 0,
|
|
2035
2118
|
)
|
|
2036
|
-
.all(options.consumer, options.consumer, options.consumer, broadcastCutoffIso(), options.consumer, limit)
|
|
2037
2119
|
: db
|
|
2038
|
-
.query<AxSteeringRow, [string, number]>(
|
|
2120
|
+
.query<AxSteeringRow, [string, number, number]>(
|
|
2039
2121
|
// No consumer given: only broadcasts — addressed steering is claimable
|
|
2040
2122
|
// solely by the consumer it names.
|
|
2041
|
-
'SELECT * FROM ax_steering WHERE delivered = 0 AND target IS NULL AND created_at > ? ORDER BY seq ASC LIMIT ?',
|
|
2123
|
+
'SELECT * FROM ax_steering WHERE delivered = 0 AND target IS NULL AND created_at > ? ORDER BY seq ASC LIMIT ? OFFSET ?',
|
|
2042
2124
|
)
|
|
2043
|
-
.all(broadcastCutoffIso(), limit);
|
|
2125
|
+
.all(broadcastCutoffIso(), limit, options.offset ?? 0);
|
|
2044
2126
|
return rows.map(mapAxSteeringRow).filter((s): s is PmxAxSteeringMessage => s !== null);
|
|
2045
2127
|
}
|
|
2046
2128
|
|
|
@@ -2054,20 +2136,29 @@ export function loadPendingAxSteeringFromDB(
|
|
|
2054
2136
|
*/
|
|
2055
2137
|
export function loadNewestPendingAxSteeringFromDB(
|
|
2056
2138
|
db: Database,
|
|
2057
|
-
options: { consumer?: string; limit?: number } = {},
|
|
2139
|
+
options: { consumer?: string; limit?: number; addressedOnly?: boolean; offset?: number } = {},
|
|
2058
2140
|
): PmxAxSteeringMessage[] {
|
|
2141
|
+
if (options.addressedOnly && !options.consumer) return [];
|
|
2059
2142
|
const limit = clampTimelineLimit(options.limit);
|
|
2060
2143
|
const rows = options.consumer
|
|
2061
2144
|
? db
|
|
2062
|
-
.query<AxSteeringRow, [string, string, string, string, string, number]>(
|
|
2063
|
-
|
|
2145
|
+
.query<AxSteeringRow, [string, string, string, string, string, number, number]>(
|
|
2146
|
+
`SELECT * FROM ax_steering s WHERE s.delivered = 0 AND (s.source IS NULL OR s.source != ?) AND (s.agent_id IS NULL OR s.agent_id != ?) AND (s.target IS NULL OR s.target = ?) ${options.addressedOnly ? 'AND s.target IS NOT NULL' : ''} AND (s.target IS NOT NULL OR s.created_at > ?) AND NOT EXISTS (SELECT 1 FROM ax_steering_deliveries d WHERE d.steering_id = s.id AND d.consumer = ?) ORDER BY s.seq DESC LIMIT ? OFFSET ?`,
|
|
2147
|
+
)
|
|
2148
|
+
.all(
|
|
2149
|
+
options.consumer,
|
|
2150
|
+
options.consumer,
|
|
2151
|
+
options.consumer,
|
|
2152
|
+
broadcastCutoffIso(),
|
|
2153
|
+
options.consumer,
|
|
2154
|
+
limit,
|
|
2155
|
+
options.offset ?? 0,
|
|
2064
2156
|
)
|
|
2065
|
-
.all(options.consumer, options.consumer, options.consumer, broadcastCutoffIso(), options.consumer, limit)
|
|
2066
2157
|
: db
|
|
2067
|
-
.query<AxSteeringRow, [number]>(
|
|
2068
|
-
'SELECT * FROM ax_steering WHERE delivered = 0 AND target IS NULL ORDER BY seq DESC LIMIT ?',
|
|
2158
|
+
.query<AxSteeringRow, [number, number]>(
|
|
2159
|
+
'SELECT * FROM ax_steering WHERE delivered = 0 AND target IS NULL ORDER BY seq DESC LIMIT ? OFFSET ?',
|
|
2069
2160
|
)
|
|
2070
|
-
.all(limit);
|
|
2161
|
+
.all(limit, options.offset ?? 0);
|
|
2071
2162
|
return rows.map(mapAxSteeringRow).filter((s): s is PmxAxSteeringMessage => s !== null);
|
|
2072
2163
|
}
|
|
2073
2164
|
|
|
@@ -58,6 +58,7 @@ export function validCanvasNodeUpdates(input: unknown): CanvasNodeUpdate[] {
|
|
|
58
58
|
return (
|
|
59
59
|
typeof update.id === 'string' &&
|
|
60
60
|
(update.collapsed === undefined || typeof update.collapsed === 'boolean') &&
|
|
61
|
+
(update.zIndex === undefined || finite(update.zIndex) !== undefined) &&
|
|
61
62
|
validateCanvasNodePatch(update) === null
|
|
62
63
|
);
|
|
63
64
|
});
|