pmx-canvas 0.6.4 → 0.7.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 +67 -3
- package/CHANGELOG.md +73 -0
- package/Readme.md +35 -5
- package/dist/canvas/global.css +498 -28
- package/dist/canvas/index.js +110 -95
- package/dist/canvas/mermaid-entry.js +258 -258
- package/dist/types/cli/agent.d.ts +4 -0
- package/dist/types/cli/commands/backup.d.ts +1 -0
- package/dist/types/cli/commands/boards.d.ts +1 -0
- package/dist/types/cli/commands/export.d.ts +1 -0
- package/dist/types/cli/commands/record.d.ts +12 -0
- package/dist/types/client/canvas/BoardCopyDialog.d.ts +5 -0
- package/dist/types/client/canvas/BoardFolderDialog.d.ts +7 -0
- package/dist/types/client/canvas/BoardLinkDialog.d.ts +3 -0
- package/dist/types/client/canvas/BoardSwitcher.d.ts +8 -0
- package/dist/types/client/canvas/ExportDialog.d.ts +7 -0
- package/dist/types/client/canvas/HomeView.d.ts +9 -0
- package/dist/types/client/canvas/Presentation.d.ts +13 -0
- package/dist/types/client/canvas/use-node-drag.d.ts +2 -1
- package/dist/types/client/nodes/AttachmentNode.d.ts +6 -0
- package/dist/types/client/nodes/BoardNode.d.ts +5 -0
- package/dist/types/client/nodes/McpAppNode.d.ts +24 -1
- package/dist/types/client/state/boards-store.d.ts +79 -0
- package/dist/types/client/state/canvas-store.d.ts +2 -0
- package/dist/types/client/state/intent-bridge.d.ts +1 -0
- package/dist/types/client/state/presentation.d.ts +3 -0
- package/dist/types/client/state/session-store.d.ts +7 -0
- package/dist/types/client/types.d.ts +2 -2
- package/dist/types/json-render/catalog.d.ts +3 -3
- package/dist/types/json-render/charts/definitions.d.ts +1 -1
- package/dist/types/json-render/server.d.ts +8 -0
- package/dist/types/mcp/canvas-access.d.ts +10 -3
- package/dist/types/mcp/context-uri-template.d.ts +6 -0
- package/dist/types/server/agent-presence.d.ts +1 -1
- package/dist/types/server/attribution.d.ts +11 -0
- package/dist/types/server/ax-context.d.ts +3 -1
- package/dist/types/server/ax-interaction.d.ts +2 -2
- package/dist/types/server/ax-state.d.ts +13 -3
- package/dist/types/server/backup.d.ts +36 -0
- package/dist/types/server/board-export.d.ts +45 -0
- package/dist/types/server/canvas-db.d.ts +65 -9
- package/dist/types/server/canvas-operations.d.ts +45 -0
- package/dist/types/server/canvas-provenance.d.ts +1 -1
- package/dist/types/server/canvas-schema.d.ts +1 -0
- package/dist/types/server/canvas-state.d.ts +146 -3
- package/dist/types/server/canvas-validation.d.ts +3 -0
- package/dist/types/server/context-brief.d.ts +111 -0
- package/dist/types/server/context-reads.d.ts +55 -0
- package/dist/types/server/document-import.d.ts +66 -0
- package/dist/types/server/html-surface.d.ts +1 -1
- package/dist/types/server/index.d.ts +107 -4
- package/dist/types/server/mutation-history.d.ts +1 -0
- package/dist/types/server/operations/invoker.d.ts +2 -0
- package/dist/types/server/operations/mcp.d.ts +7 -1
- package/dist/types/server/operations/ops/app.d.ts +2 -0
- package/dist/types/server/operations/ops/ax-shared.d.ts +2 -2
- package/dist/types/server/operations/ops/backup.d.ts +2 -0
- package/dist/types/server/operations/ops/boards.d.ts +10 -0
- package/dist/types/server/operations/ops/export.d.ts +2 -0
- package/dist/types/server/operations/ops/imports.d.ts +2 -0
- package/dist/types/server/operations/ops/json-render.d.ts +2 -0
- package/dist/types/server/operations/ops/nodes.d.ts +4 -2
- package/dist/types/server/operations/ops/query.d.ts +2 -0
- package/dist/types/server/operations/registry.d.ts +9 -1
- package/dist/types/server/operations/types.d.ts +1 -1
- package/dist/types/server/server.d.ts +1 -0
- package/dist/types/server/trace-manager.d.ts +7 -0
- package/dist/types/server/web-artifacts.d.ts +3 -0
- package/dist/types/server/webpage-node.d.ts +22 -1
- package/dist/types/server/workbench-auth.d.ts +3 -0
- package/dist/types/shared/boards.d.ts +6 -0
- package/dist/types/shared/tour.d.ts +72 -0
- package/docs/RELEASE.md +5 -0
- package/docs/cli.md +157 -0
- package/docs/http-api.md +277 -6
- package/docs/mcp.md +96 -7
- package/docs/node-types.md +106 -0
- package/docs/plans/plan-010-attributed-ask-answers.md +39 -0
- package/docs/plans/plan-011-context-read-instrumentation.md +54 -0
- package/docs/plans/plan-012-many-boards-stage-1.md +98 -0
- package/docs/plans/plan-013-static-board-export.md +47 -0
- package/docs/plans/plan-014-connected-board-memory.md +140 -0
- package/docs/product-vision-2026-09.md +118 -18
- package/docs/sdk.md +50 -0
- package/package.json +1 -1
- package/skills/pmx-canvas/SKILL.md +62 -5
- package/skills/pmx-canvas/references/full-reference.md +44 -8
- package/skills/pmx-canvas/references/github-copilot-app-adapter.md +3 -0
- package/skills/pmx-canvas/references/installing-pmx-canvas.md +4 -4
- package/skills/pmx-canvas-orchestration/SKILL.md +5 -0
- package/skills/pmx-canvas-testing/SKILL.md +4 -0
- package/src/cli/agent.ts +9 -0
- package/src/cli/commands/ax.ts +13 -0
- package/src/cli/commands/backup.ts +66 -0
- package/src/cli/commands/boards.ts +71 -0
- package/src/cli/commands/export.ts +30 -0
- package/src/cli/commands/nodes.ts +14 -1
- package/src/cli/commands/pins.ts +6 -2
- package/src/cli/commands/pump.ts +3 -0
- package/src/cli/commands/query.ts +33 -7
- package/src/cli/commands/record.ts +218 -0
- package/src/cli/commands/view.ts +7 -5
- package/src/cli/index.ts +21 -9
- package/src/client/App.tsx +28 -4
- package/src/client/canvas/AgentPresenceLayer.tsx +1 -1
- package/src/client/canvas/BoardCopyDialog.tsx +153 -0
- package/src/client/canvas/BoardFolderDialog.tsx +120 -0
- package/src/client/canvas/BoardLinkDialog.tsx +93 -0
- package/src/client/canvas/BoardSwitcher.tsx +149 -0
- package/src/client/canvas/CanvasNode.tsx +8 -0
- package/src/client/canvas/CanvasViewport.tsx +3 -0
- package/src/client/canvas/CommandPalette.tsx +107 -4
- package/src/client/canvas/ContextMenu.tsx +4 -0
- package/src/client/canvas/ExpandedNodeOverlay.tsx +3 -0
- package/src/client/canvas/ExportDialog.tsx +197 -0
- package/src/client/canvas/HomeView.tsx +277 -0
- package/src/client/canvas/IntentLayer.tsx +9 -2
- package/src/client/canvas/Presentation.tsx +108 -0
- package/src/client/canvas/SessionPanel.tsx +28 -1
- package/src/client/canvas/ToolRail.tsx +38 -3
- package/src/client/canvas/TopBar.tsx +49 -7
- package/src/client/canvas/import-files.ts +19 -1
- package/src/client/canvas/kind-colors.ts +1 -0
- package/src/client/canvas/use-node-drag.ts +8 -3
- package/src/client/icons.tsx +2 -0
- package/src/client/mermaid-entry.ts +39 -0
- package/src/client/nodes/AttachmentNode.tsx +148 -0
- package/src/client/nodes/BoardNode.tsx +35 -0
- package/src/client/nodes/FileNode.tsx +6 -0
- package/src/client/nodes/HtmlNode.tsx +12 -13
- package/src/client/nodes/MarkdownNode.tsx +47 -19
- package/src/client/nodes/McpAppNode.tsx +105 -13
- package/src/client/nodes/MermaidNode.tsx +3 -2
- package/src/client/nodes/ax-node-actions.ts +2 -5
- package/src/client/nodes/use-ax-surface-bridge.ts +1 -1
- package/src/client/state/boards-store.ts +167 -0
- package/src/client/state/canvas-store.ts +22 -0
- package/src/client/state/intent-bridge.ts +30 -2
- package/src/client/state/intent-store.ts +5 -1
- package/src/client/state/node-factory.ts +1 -0
- package/src/client/state/presentation.ts +7 -0
- package/src/client/state/session-store.ts +8 -0
- package/src/client/state/sse-bridge.ts +52 -5
- package/src/client/theme/global.css +498 -28
- package/src/client/types.ts +2 -0
- package/src/json-render/server.ts +45 -9
- package/src/mcp/canvas-access.ts +59 -22
- package/src/mcp/context-uri-template.ts +28 -0
- package/src/mcp/server.ts +122 -15
- package/src/server/agent-context.ts +116 -29
- package/src/server/agent-presence.ts +15 -9
- package/src/server/attribution.ts +29 -0
- package/src/server/ax-context.ts +4 -2
- package/src/server/ax-interaction.ts +1 -0
- package/src/server/ax-state-manager.ts +72 -3
- package/src/server/ax-state.ts +41 -0
- package/src/server/backup.ts +178 -0
- package/src/server/board-export.ts +686 -0
- package/src/server/canvas-db.ts +612 -105
- package/src/server/canvas-operations.ts +183 -31
- package/src/server/canvas-provenance.ts +1 -0
- package/src/server/canvas-schema.ts +22 -0
- package/src/server/canvas-state.ts +812 -48
- package/src/server/canvas-validation.ts +9 -1
- package/src/server/context-brief.ts +372 -0
- package/src/server/context-reads.ts +238 -0
- package/src/server/demo-state.json +670 -9
- package/src/server/document-import.ts +223 -0
- package/src/server/html-primitives.ts +199 -91
- package/src/server/html-surface.ts +8 -3
- package/src/server/index.ts +243 -5
- package/src/server/mutation-history.ts +10 -13
- package/src/server/operations/composites.ts +29 -5
- package/src/server/operations/http.ts +9 -3
- package/src/server/operations/index.ts +8 -0
- package/src/server/operations/invoker.ts +14 -3
- package/src/server/operations/mcp.ts +50 -11
- package/src/server/operations/ops/app.ts +15 -0
- package/src/server/operations/ops/ax-read.ts +10 -6
- package/src/server/operations/ops/ax-timeline.ts +75 -0
- package/src/server/operations/ops/backup.ts +134 -0
- package/src/server/operations/ops/batch.ts +20 -4
- package/src/server/operations/ops/boards.ts +351 -0
- package/src/server/operations/ops/export.ts +74 -0
- package/src/server/operations/ops/ext-app.ts +4 -0
- package/src/server/operations/ops/groups.ts +14 -7
- package/src/server/operations/ops/imports.ts +220 -0
- package/src/server/operations/ops/json-render.ts +37 -5
- package/src/server/operations/ops/nodes.ts +99 -21
- package/src/server/operations/ops/query.ts +206 -9
- package/src/server/operations/ops/viewport.ts +32 -0
- package/src/server/operations/registry.ts +129 -31
- package/src/server/operations/types.ts +1 -1
- package/src/server/scope-fence.ts +1 -1
- package/src/server/server.ts +155 -8
- package/src/server/spatial-analysis.ts +9 -17
- package/src/server/trace-manager.ts +19 -0
- package/src/server/web-artifacts.ts +11 -3
- package/src/server/webpage-node.ts +173 -13
- package/src/server/workbench-auth.ts +11 -0
- package/src/server/workboard.ts +3 -3
- package/src/shared/boards.ts +18 -0
- package/src/shared/node-sizes.ts +1 -0
- package/src/shared/tour.ts +87 -0
package/docs/cli.md
CHANGED
|
@@ -8,11 +8,109 @@ wins over `--port`, and both win over the environment variables). An invalid
|
|
|
8
8
|
value for either flag is a hard error — the CLI never falls back silently to
|
|
9
9
|
the default port.
|
|
10
10
|
|
|
11
|
+
Read commands accept `--board <board-id>` without switching the active board:
|
|
12
|
+
`layout` (including `--summary`), `status`, `spatial`, `pin --list`, and
|
|
13
|
+
`node get`. Writes and presence still target the board open in the workbench;
|
|
14
|
+
unknown board IDs fail rather than falling back to it.
|
|
15
|
+
|
|
16
|
+
An in-flight asynchronous write stops if the board changes; subsequent calls use
|
|
17
|
+
the newly open board. Batches stop rather than continuing on another board, and
|
|
18
|
+
already-completed entries remain applied.
|
|
19
|
+
|
|
20
|
+
On SIGINT or SIGTERM, the server saves before exiting. If saving fails, it reports
|
|
21
|
+
the error and stays running so the in-memory edits can be recovered. Fix the
|
|
22
|
+
storage failure and retry shutdown; a forced process kill can still lose edits.
|
|
23
|
+
|
|
11
24
|
```bash
|
|
12
25
|
pmx-canvas node list --port 4750 # target a non-default daemon
|
|
13
26
|
pmx-canvas --server-url http://127.0.0.1:4750 status # same, by URL
|
|
14
27
|
```
|
|
15
28
|
|
|
29
|
+
## Tour and presentation
|
|
30
|
+
|
|
31
|
+
This is the small tour slice of the [vision's “board is the presentation”](product-vision-2026-09.md#12-tours-the-board-is-the-presentation-m):
|
|
32
|
+
the existing cards remain the content, rather than being rebuilt as a separate deck.
|
|
33
|
+
The same stops and camera interpolation drive interactive presentation and optional capture.
|
|
34
|
+
A visual stop editor and carrying tours into static exports/share links are not implemented here.
|
|
35
|
+
|
|
36
|
+
Click **Present** in the top bar, or open `/workbench?present=1` for a chrome-free
|
|
37
|
+
embedded/capture view. Right/Down/Space advances, Left/Up goes back, Esc exits.
|
|
38
|
+
The camera is local to the viewer; board content continues updating over SSE.
|
|
39
|
+
Stops do not auto-advance. Missing targets show an error and can be skipped.
|
|
40
|
+
|
|
41
|
+
Save this as `tour.json` (replace the IDs with IDs from `pmx-canvas node list`):
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"stops": [
|
|
46
|
+
{ "target": { "nodeId": "overview-group" }, "duration": 1.5, "padding": 60 },
|
|
47
|
+
{ "target": { "nodeId": "detail-note" }, "duration": 2, "easing": "ease-in-out", "pullback": 0.7 },
|
|
48
|
+
{ "target": { "viewport": { "x": 80, "y": 100, "scale": 0.5 } }, "duration": 1 }
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pmx-canvas tour set --file tour.json
|
|
55
|
+
pmx-canvas tour get
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
A stop targets either a node ID (including a group ID) or an explicit viewport.
|
|
59
|
+
Viewport translation is screen-space: `screen = world * scale + offset`.
|
|
60
|
+
`duration` is transition time in seconds (default 1, zero jumps); `padding` is
|
|
61
|
+
screen pixels around a target (default 40). Easing is `linear`, `ease-in-out`
|
|
62
|
+
(default), or `ease-out`. Zoom interpolates logarithmically about the moving
|
|
63
|
+
world-space centre. `pullback` (0–4, default 0) subtracts a sinusoidal log-zoom
|
|
64
|
+
offset mid-move without changing endpoints. Tours allow at most 1000 stops.
|
|
65
|
+
|
|
66
|
+
Tours persist with the board and snapshots, participate in undo, and clear with
|
|
67
|
+
the board. A file containing `null` resets the tour: when none is saved, groups
|
|
68
|
+
are sorted by y, then x, then ID. A saved empty `stops` array deliberately has no
|
|
69
|
+
stops. SDK: `canvas.setTour(tourOrNull)` / `canvas.getTour()`.
|
|
70
|
+
|
|
71
|
+
### Optional capture of the same tour
|
|
72
|
+
|
|
73
|
+
`record` is an optional local utility, not a second presentation model. It reads
|
|
74
|
+
the saved/derived tour, or the identical tour JSON supplied with `--tour-file`.
|
|
75
|
+
Start the server first. Capture launches its own Bun.WebView Chrome session;
|
|
76
|
+
it does not replace a server automation session or move other viewers' cameras.
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Capture the saved/derived board tour
|
|
80
|
+
pmx-canvas record --mode deterministic --present --fps 30 --resolution 1920x1080 --output tour.mp4
|
|
81
|
+
|
|
82
|
+
# Try the same tour model from a file without changing the saved tour
|
|
83
|
+
pmx-canvas record --mode deterministic --tour-file tour.json --present --output frames
|
|
84
|
+
|
|
85
|
+
# Alternatively, sample the live presentation while agents update the board
|
|
86
|
+
pmx-canvas record --duration 10 --present --theme light --output activity.mp4
|
|
87
|
+
|
|
88
|
+
# Keep recording until SIGINT (Ctrl+C) or SIGTERM, then encode
|
|
89
|
+
pmx-canvas record --stop-on-signal --output live.mp4
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Options: `--mode realtime|deterministic` (default realtime), `--resolution WIDTHxHEIGHT`
|
|
93
|
+
(default 1280x720), `--fps` (1–120, default 30), `--theme`, `--present`,
|
|
94
|
+
`--duration SECONDS` or `--stop-on-signal` for realtime, `--tour-file FILE`
|
|
95
|
+
for deterministic mode, `--chrome-path PATH`, and required `--output PATH`.
|
|
96
|
+
Global `--port` / `--server-url` work here too. Existing output paths are refused.
|
|
97
|
+
|
|
98
|
+
An `.mp4` output uses ffmpeg/H.264; any other path is a PNG sequence directory.
|
|
99
|
+
Frames and `recording.json` are retained at `<output>.frames` even after video
|
|
100
|
+
encoding. If ffmpeg is missing, the command clearly reports the PNG fallback
|
|
101
|
+
and returns that directory. Encoding failures retain frames and exit nonzero.
|
|
102
|
+
|
|
103
|
+
Deterministic mode resolves target geometry once and writes
|
|
104
|
+
`max(1, ceil(duration × fps))` frames per stop, including each endpoint. It sets
|
|
105
|
+
the camera, waits for two animation frames, checks the applied camera, then
|
|
106
|
+
captures. Duplicate a target to hold it. This makes **camera timing** deterministic,
|
|
107
|
+
not animated iframe content, fonts loaded later, network assets, or concurrent
|
|
108
|
+
board edits. Realtime mode samples the live board; slow captures repeat frames
|
|
109
|
+
to preserve wall-clock speed, with the repeated-frame count in `recording.json`.
|
|
110
|
+
Capture has no audio. Chrome and a Bun runtime with WebView support are required.
|
|
111
|
+
Recording is a local CLI/file operation, not a remote HTTP/MCP file-writing API;
|
|
112
|
+
HTTP/MCP manage tours and retain their existing screenshot/automation surfaces.
|
|
113
|
+
|
|
16
114
|
## pump — reactive steering for CLI agents
|
|
17
115
|
|
|
18
116
|
`pmx-canvas pump` turns any CLI agent (Codex, Amp, a script) into a steerable
|
|
@@ -99,6 +197,10 @@ pmx-canvas node update <node-id> --width 840 --height 620
|
|
|
99
197
|
pmx-canvas node update <node-id> --title "Renamed" --full
|
|
100
198
|
```
|
|
101
199
|
|
|
200
|
+
Mermaid `node add` and `node update` accept `--fit contain|none`, stored as
|
|
201
|
+
`data.fit`. Contain is the default and shrinks only overflowing diagrams;
|
|
202
|
+
none keeps 100% with scrolling. [Sizing and readability](node-types.md#mermaid-nodes).
|
|
203
|
+
|
|
102
204
|
`--from-search` / `--to-search` must each resolve to exactly one node — broad
|
|
103
205
|
queries fail rather than guess. Use the full visible title.
|
|
104
206
|
|
|
@@ -173,6 +275,48 @@ pmx-canvas fit <id-a> <id-b> # Fit to just these nodes
|
|
|
173
275
|
`--width` / `--height`. After creating output a human should see, focus a single
|
|
174
276
|
node or fit the new ids — auto-placement is board-relative, not camera-relative.
|
|
175
277
|
|
|
278
|
+
## Boards
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
pmx-canvas board list # most recently opened first; activeBoardId null = Home
|
|
282
|
+
pmx-canvas board create "Q4 planning" # created, not opened
|
|
283
|
+
pmx-canvas board rename <board-id> "New name"
|
|
284
|
+
pmx-canvas board create "Q4 planning" --category Planning
|
|
285
|
+
pmx-canvas board category <board-id> "Planning/Quarterly" # nested folders; --clear unfiles it
|
|
286
|
+
pmx-canvas board from <source-id> "Follow-up" --preview
|
|
287
|
+
pmx-canvas board from <source-id> "Follow-up" --nodes id1,id2 --readme --structure
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Commands write to the board open in the workbench. Opening, switching and
|
|
291
|
+
deleting boards happens in the workbench (the human's call). `board from`
|
|
292
|
+
excludes `prompt`, `response`, `trace`, and `mcp-app` cards; selected reusable
|
|
293
|
+
cards get fresh IDs. `--structure` includes group frames; edges between copied
|
|
294
|
+
cards are retained automatically. `--readme` carries the designated README. The new board remains inactive and
|
|
295
|
+
does not inherit pins, AX state, or mutation history.
|
|
296
|
+
|
|
297
|
+
## Backup and restore
|
|
298
|
+
|
|
299
|
+
Boards save automatically. Backups are separate recovery copies of the whole library,
|
|
300
|
+
configured through the CLI or HTTP API rather than the Home screen. Scheduled backups
|
|
301
|
+
run while the server is running; scheduling is off until configured.
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
pmx-canvas backup # every board, now; into .pmx-canvas/backups
|
|
305
|
+
pmx-canvas backup --to ~/Backups/pmx --keep 14
|
|
306
|
+
pmx-canvas backup schedule --every 24h --keep 14 --to ~/Backups/pmx # run by the server
|
|
307
|
+
pmx-canvas backup schedule --off
|
|
308
|
+
pmx-canvas backup status
|
|
309
|
+
pmx-canvas restore ~/Backups/pmx/canvas-20260927T090000000Z.db # keeps canvas.db.before-restore
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Export
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
pmx-canvas export # the open board → .pmx-canvas/exports/<board>-<time>.html
|
|
316
|
+
pmx-canvas export --board <board-id> --out ~/Desktop/okrs.html
|
|
317
|
+
pmx-canvas export --include-files # include local file contents (left out by default)
|
|
318
|
+
```
|
|
319
|
+
|
|
176
320
|
## Snapshots
|
|
177
321
|
|
|
178
322
|
```bash
|
|
@@ -186,6 +330,18 @@ pmx-canvas diff <snapshot-id> # Compare the canvas against a snapshot
|
|
|
186
330
|
|
|
187
331
|
## AX context
|
|
188
332
|
|
|
333
|
+
The cross-board brief has its own compact command. Its budget is measured in
|
|
334
|
+
UTF-16 code units (default 16000, maximum 100000), not model tokens. `--consumer`
|
|
335
|
+
selects a durable cursor scoped to the open board; `--since` performs an
|
|
336
|
+
explicit pull without changing that cursor. With neither flag, every call starts
|
|
337
|
+
from the beginning. Use a stable, unique consumer ID per agent/adapter; changing
|
|
338
|
+
or sharing it loses or conflates delivery progress.
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
pmx-canvas context --consumer codex --budget 16000
|
|
342
|
+
pmx-canvas context --since 42 --budget 8000
|
|
343
|
+
```
|
|
344
|
+
|
|
189
345
|
AX commands expose the host-agnostic context contract used by adapters. Pins
|
|
190
346
|
remain the explicit human-curated context set; AX focus is the current
|
|
191
347
|
attention target and persists with canvas state and snapshots.
|
|
@@ -209,6 +365,7 @@ pmx-canvas ax event add --kind tool-start --summary "ran tests"
|
|
|
209
365
|
pmx-canvas ax steer "focus on the failing test first"
|
|
210
366
|
pmx-canvas ax evidence add --kind test-output --title "unit pass"
|
|
211
367
|
pmx-canvas ax timeline --limit 50
|
|
368
|
+
pmx-canvas ax reads --limit 50 # context read log: which context each agent read, pinned delivery
|
|
212
369
|
|
|
213
370
|
# Work items (canvas-bound)
|
|
214
371
|
pmx-canvas ax work add --title "Wire up auth" --status in-progress node-1
|
package/docs/http-api.md
CHANGED
|
@@ -9,14 +9,207 @@ bodies are treated as an empty request. As of 0.4.0 every error response is a
|
|
|
9
9
|
JSON envelope of that same shape (`{ ok: false, error }`, status unchanged) —
|
|
10
10
|
no plain-text errors remain.
|
|
11
11
|
|
|
12
|
+
Node-create responses include `sizeAdjustment` when a frame dimension was
|
|
13
|
+
defaulted or raised to its node type's readability floor. It contains the
|
|
14
|
+
`requested` dimensions (`null` when omitted), the final `applied` dimensions,
|
|
15
|
+
and a `reason` (`defaulted`, `clamped-to-minimum`, or
|
|
16
|
+
`defaulted-and-clamped-to-minimum`; groups also use `fit-to-children`). `strictSize: true`
|
|
17
|
+
still bypasses the readability clamp, but omitted dimensions are reported as
|
|
18
|
+
defaulted. MCP create actions return the same size report.
|
|
19
|
+
Updates preserve explicit dimensions without applying creation floors; their
|
|
20
|
+
returned node `size` is the applied size. Omitted update dimensions retain the
|
|
21
|
+
existing size and are not reported as defaulted adjustments.
|
|
22
|
+
|
|
23
|
+
Both group-create routes report defaults or final child-derived dimensions, including
|
|
24
|
+
when children override supplied width/height because x/y were omitted. Explicit manual
|
|
25
|
+
frames retain their existing semantics. Group child replacement reports `fit-to-children`
|
|
26
|
+
when it changes the frame; `group.add` reports the previous frame as `requested` and
|
|
27
|
+
the final frame as `applied`. Reports survive compact/full MCP and batch responses.
|
|
28
|
+
External MCP app creation and web-artifact builds that open a node report their default
|
|
29
|
+
frames too; reusing an existing app node or building without opening does not report a
|
|
30
|
+
creation default. These reports describe the synchronous operation, not later browser
|
|
31
|
+
content auto-height or indirect parent-group reflow after editing a child.
|
|
32
|
+
|
|
33
|
+
## Board tours
|
|
34
|
+
|
|
35
|
+
- `GET /api/canvas/tour` → `{ tour: { stops: [...] }, derived: boolean }`.
|
|
36
|
+
- `POST /api/canvas/tour` with `{ "tour": { "stops": [...] } }` persists the tour;
|
|
37
|
+
`{ "tour": null }` resets to derived group reading order. Returns `{ "ok": true }`.
|
|
38
|
+
- `GET /api/canvas/state` includes optional `tour`. Tour writes broadcast a layout
|
|
39
|
+
update and are included in snapshots/undo. They are board-wide writes under a scope fence.
|
|
40
|
+
|
|
41
|
+
The [tour model and recording walkthrough](cli.md#tour-and-presentation) describes
|
|
42
|
+
targets, duration, easing, padding, and pullback. Open `/workbench?present=1` to hide
|
|
43
|
+
chrome; camera movement is local to that viewer. Recording writes local files via
|
|
44
|
+
the CLI, not an HTTP job endpoint.
|
|
45
|
+
|
|
46
|
+
## Boards
|
|
47
|
+
|
|
48
|
+
A workspace holds many named boards; one is open at a time. Agent writes go to
|
|
49
|
+
the open board. While no board is open (Home), the first write opens the most
|
|
50
|
+
recently opened board, or creates one when the workspace has none;
|
|
51
|
+
`canvas.clear` on Home opens nothing. Only the trusted workbench opens or
|
|
52
|
+
deletes a board — HTTP calls require both `x-pmx-workbench: 1` and the
|
|
53
|
+
per-boot `x-pmx-workbench-token` embedded in the served `/workbench` HTML;
|
|
54
|
+
the marker alone is not authority. Public HTTP integrations must not open or
|
|
55
|
+
delete boards. In-process SDK embedding hosts retain authority to do so.
|
|
56
|
+
Every change emits a
|
|
57
|
+
`boards-changed` SSE frame with `{ activeBoardId, boards }`.
|
|
58
|
+
|
|
59
|
+
`category` is a folder path, for example `Engineering/Canvas/Decisions`.
|
|
60
|
+
Home renders nested, collapsible folders and searches board names and paths.
|
|
61
|
+
Paths support up to eight levels, each with 1–60 characters; surrounding spaces
|
|
62
|
+
are trimmed. Empty segments and `.`/`..` are rejected. `null` or `""` unfiles a
|
|
63
|
+
board. Folders are derived from boards, so empty folders do not persist. Moving
|
|
64
|
+
a board changes its path, not its ID or content.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# List boards (most recently opened first) and which is open (null = Home)
|
|
68
|
+
curl http://localhost:4313/api/canvas/boards
|
|
69
|
+
|
|
70
|
+
# Read one board
|
|
71
|
+
curl http://localhost:4313/api/canvas/boards/<board-id>
|
|
72
|
+
|
|
73
|
+
# Create a board (optionally in a category) — it is NOT opened
|
|
74
|
+
curl -X POST http://localhost:4313/api/canvas/boards \
|
|
75
|
+
-H "Content-Type: application/json" -d '{"name":"Q4 planning","category":"Planning"}'
|
|
76
|
+
|
|
77
|
+
# Preview/create an inactive copy from reusable cards (preview false creates)
|
|
78
|
+
curl -X POST http://localhost:4313/api/canvas/boards/from \
|
|
79
|
+
-H "Content-Type: application/json" \
|
|
80
|
+
-d '{"sourceBoardId":"board-source","name":"Follow-up","nodeIds":["node-1"],"includeReadme":true,"includeStructure":true,"preview":true}'
|
|
81
|
+
|
|
82
|
+
# Rename and/or file under a category on Home ("category": "" removes it)
|
|
83
|
+
curl -X PATCH http://localhost:4313/api/canvas/boards/<board-id> \
|
|
84
|
+
-H "Content-Type: application/json" -d '{"name":"Q4 planning (final)","category":"Planning"}'
|
|
85
|
+
|
|
86
|
+
# Designate a Markdown card on this board as its README (null clears it)
|
|
87
|
+
curl -X PATCH http://localhost:4313/api/canvas/boards/<board-id> \
|
|
88
|
+
-H "Content-Type: application/json" -d '{"readmeNodeId":"<markdown-node-id>"}'
|
|
89
|
+
|
|
90
|
+
# Open a board, or Home with {"id":null} — workbench only
|
|
91
|
+
curl -X POST http://localhost:4313/api/canvas/boards/open \
|
|
92
|
+
-H "Content-Type: application/json" -H "x-pmx-workbench: 1" \
|
|
93
|
+
-H "x-pmx-workbench-token: <token-from-served-workbench>" -d '{"id":"<board-id>"}'
|
|
94
|
+
|
|
95
|
+
# Delete a board and its snapshots — workbench only; deleting the open board returns to Home
|
|
96
|
+
curl -X DELETE http://localhost:4313/api/canvas/boards/<board-id> \
|
|
97
|
+
-H "x-pmx-workbench: 1" -H "x-pmx-workbench-token: <token-from-served-workbench>"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Backup and restore
|
|
101
|
+
|
|
102
|
+
A backup is one SQLite file holding every board, its snapshots and blobs,
|
|
103
|
+
written with `VACUUM INTO` (safe while the server runs) to
|
|
104
|
+
`canvas-<timestamp>.db` in the backup folder — by default `backups/` beside the
|
|
105
|
+
database (`.pmx-canvas/backups`). Keeping the newest `keep` (default 14)
|
|
106
|
+
removes older backups in that folder. The schedule is stored in the database
|
|
107
|
+
and runs inside the server. Not exposed over MCP.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Folder, schedule, last backup and the backups on disk
|
|
111
|
+
curl http://localhost:4313/api/canvas/backup
|
|
112
|
+
|
|
113
|
+
# Back up now (optional folder and keep)
|
|
114
|
+
curl -X POST http://localhost:4313/api/canvas/backup \
|
|
115
|
+
-H "Content-Type: application/json" -d '{"to":"/Users/me/Backups/pmx","keep":14}'
|
|
116
|
+
|
|
117
|
+
# Back up every 24h ("30m", "7d"; at least once a minute; "off" stops it)
|
|
118
|
+
curl -X POST http://localhost:4313/api/canvas/backup/schedule \
|
|
119
|
+
-H "Content-Type: application/json" -d '{"every":"24h","keep":14,"to":"/Users/me/Backups/pmx"}'
|
|
120
|
+
|
|
121
|
+
# Replace every board with a backup; the current file is kept as canvas.db.before-restore.
|
|
122
|
+
# Refuses files that are not PMX Canvas databases, and the live database itself.
|
|
123
|
+
curl -X POST http://localhost:4313/api/canvas/backup/restore \
|
|
124
|
+
-H "Content-Type: application/json" -d '{"file":"/Users/me/Backups/pmx/canvas-20260927T090000000Z.db"}'
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Static board export
|
|
128
|
+
|
|
129
|
+
One self-contained, read-only HTML file of one board (pan, zoom, expand) that
|
|
130
|
+
opens with no server or install. Cards render as escaped text; html cards,
|
|
131
|
+
charts, diagrams and built apps run in sandboxed iframes, with viewer bundles
|
|
132
|
+
stored once per file. Live MCP apps become placeholders; local file contents
|
|
133
|
+
are left out unless `includeFiles` is true. Files are written to `exports/`
|
|
134
|
+
beside the database. Built-app files are only embedded when they are regular,
|
|
135
|
+
bounded-size files inside the board's owned `.pmx-canvas/artifacts/` directory.
|
|
136
|
+
The preview manifest lists card links, remote images, and statically visible
|
|
137
|
+
network destinations in embedded HTML. Imported source-linked Markdown is also
|
|
138
|
+
excluded unless `includeDerivedText=true`, independently of `includeFiles`;
|
|
139
|
+
editing it does not remove that classification. Original attachment bytes are
|
|
140
|
+
never embedded in v1. Embedded scripts can make additional
|
|
141
|
+
network requests that cannot be inventoried in advance. Not exposed over MCP —
|
|
142
|
+
sharing is the human's act.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# What the file would contain (defaults to the open board; ?board=<id> for another)
|
|
146
|
+
curl "http://localhost:4313/api/canvas/export/preview?includeFiles=false&includeDerivedText=false"
|
|
147
|
+
|
|
148
|
+
# Write it → { path, url, bytes, manifest }
|
|
149
|
+
curl -X POST http://localhost:4313/api/canvas/export \
|
|
150
|
+
-H "Content-Type: application/json" \
|
|
151
|
+
-d '{"board":"<board-id>","includeFiles":false,"includeDerivedText":false}'
|
|
152
|
+
|
|
153
|
+
# Serve a written export (opaque-origin sandbox; ?download=1 as an attachment)
|
|
154
|
+
curl "http://localhost:4313/api/canvas/exports/<file>.html?download=1" -o board.html
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Agent-assisted document imports
|
|
158
|
+
|
|
159
|
+
PDF and Office uploads are raw bytes, not JSON. Upload requires the trusted
|
|
160
|
+
workbench token, an active captured board, a non-empty body of at most 20 MiB,
|
|
161
|
+
and creates both an original file card and an `attached` import. The original
|
|
162
|
+
remains board-owned until board deletion; snapshot restore does not remove it,
|
|
163
|
+
and whole-database backups include it.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
curl -X POST \
|
|
167
|
+
"http://localhost:4313/api/canvas/attachments?boardId=<board-id>&name=report.pdf&mime=application/pdf&x=40&y=40" \
|
|
168
|
+
-H "x-pmx-workbench-token: <token>" --data-binary @report.pdf
|
|
169
|
+
|
|
170
|
+
# Human-only: explicit consent asks the connected agent; captured board must be open
|
|
171
|
+
curl -X POST http://localhost:4313/api/canvas/imports/<import-id>/request \
|
|
172
|
+
-H "Content-Type: application/json" -H "x-pmx-workbench: 1" \
|
|
173
|
+
-H "x-pmx-workbench-token: <token>" \
|
|
174
|
+
-d '{"consent":true}'
|
|
175
|
+
|
|
176
|
+
# Agent reads metadata and a controlled byte path; inline=true adds base64 only <=2 MiB
|
|
177
|
+
curl "http://localhost:4313/api/canvas/imports/<import-id>?inline=true"
|
|
178
|
+
curl http://localhost:4313/api/canvas/attachments/<attachment-id>/bytes -o source.bin
|
|
179
|
+
|
|
180
|
+
# Agent submits a reviewable draft (allowed even if another board is active)
|
|
181
|
+
curl -X POST http://localhost:4313/api/canvas/imports/<import-id>/submit \
|
|
182
|
+
-H "Content-Type: application/json" \
|
|
183
|
+
-d '{"sections":[{"title":"Summary","markdown":"...","reference":"page 1"}],"warnings":[],"agentDescription":"Extracted with the connected host PDF reader"}'
|
|
184
|
+
|
|
185
|
+
# Human-only review/commit; the original captured board must be open
|
|
186
|
+
curl -X POST http://localhost:4313/api/canvas/imports/<import-id>/commit \
|
|
187
|
+
-H "x-pmx-workbench: 1" -H "x-pmx-workbench-token: <token>"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`GET /api/canvas/imports?boardId=...` lists jobs. An agent that cannot access or
|
|
191
|
+
interpret the source posts `{ "reason": "..." }` to
|
|
192
|
+
`/api/canvas/imports/:id/unavailable`; a human may later request a new attempt.
|
|
193
|
+
Humans can cancel requested or drafted jobs at `/cancel`. There is no bundled
|
|
194
|
+
converter, OCR, automatic agent launch, or guarantee for charts, scans, and
|
|
195
|
+
host-specific formats. A remote agent may need the human/host to transfer the
|
|
196
|
+
bytes before it can submit a draft.
|
|
197
|
+
|
|
12
198
|
## Canvas state
|
|
13
199
|
|
|
200
|
+
Read endpoints accept an optional `board=<board-id>` query parameter without
|
|
201
|
+
opening that board or changing where writes go. This is supported by
|
|
202
|
+
`/api/canvas/state`, `/api/canvas/node/:id`, `/api/canvas/summary`,
|
|
203
|
+
`/api/canvas/spatial-context`, and `/api/canvas/pinned-context`. Unknown boards
|
|
204
|
+
return 404. Omit `board` to read the active board. Live AX session/delivery reads
|
|
205
|
+
and fixed MCP resources continue to describe the open board.
|
|
206
|
+
|
|
14
207
|
```bash
|
|
15
208
|
# Get canvas state
|
|
16
209
|
curl http://localhost:4313/api/canvas/state
|
|
17
210
|
|
|
18
|
-
# Search
|
|
19
|
-
curl "http://localhost:4313/api/canvas/search?q=auth&limit=10"
|
|
211
|
+
# Search the library (omit scope for the active board)
|
|
212
|
+
curl "http://localhost:4313/api/canvas/search?q=auth&limit=10&scope=library"
|
|
20
213
|
|
|
21
214
|
# Validate the current layout
|
|
22
215
|
curl http://localhost:4313/api/canvas/validate
|
|
@@ -35,6 +228,10 @@ curl -X POST http://localhost:4313/api/canvas/json-render \
|
|
|
35
228
|
-H "Content-Type: application/json" \
|
|
36
229
|
-d '{"title":"Panel","nodeHeight":280,"spec":{"root":"card","elements":{"card":{"type":"Card","props":{"title":"Live"},"children":[]}}}}'
|
|
37
230
|
|
|
231
|
+
# For graph nodes, `height` is the chart's plot height, not the node frame.
|
|
232
|
+
# Set the frame with `nodeHeight` (`heightPx` in the SDK). A graph request that
|
|
233
|
+
# supplies only `height` gets the default frame height and a response warning.
|
|
234
|
+
|
|
38
235
|
# Validate an HTML primitive without creating a node
|
|
39
236
|
curl -X POST http://localhost:4313/api/canvas/schema/validate \
|
|
40
237
|
-H "Content-Type: application/json" \
|
|
@@ -70,6 +267,16 @@ A node creation request must resolve a `type` — pass it in the body (`{ "type"
|
|
|
70
267
|
... }`) or as a `?type=` query param. An empty / type-less body returns `400`
|
|
71
268
|
rather than silently creating a markdown node.
|
|
72
269
|
|
|
270
|
+
An optional `boardId` on node creation is a captured-board precondition, not a
|
|
271
|
+
switch command: if it no longer matches the active board, the request returns
|
|
272
|
+
`409` without creating a node or opening a board from Home. The file-drop UI
|
|
273
|
+
uses this to prevent delayed uploads from landing on a different board.
|
|
274
|
+
|
|
275
|
+
Mermaid nodes accept `data: { "fit": "contain" | "none" }` on both
|
|
276
|
+
`POST /api/canvas/node` and `PATCH /api/canvas/node/:id`. The default, `contain`,
|
|
277
|
+
shrinks overflowing diagrams without changing aspect ratio; `none` keeps 100%
|
|
278
|
+
with scrolling. [Mermaid sizing and readability](node-types.md#mermaid-nodes).
|
|
279
|
+
|
|
73
280
|
### File node content and bytes
|
|
74
281
|
|
|
75
282
|
A `file` node reads its file server-side. Text is stored on the node as
|
|
@@ -145,6 +352,31 @@ curl -X DELETE http://localhost:4313/api/canvas/annotation/ann-123
|
|
|
145
352
|
Agent-readable context reports annotation IDs, targets, and bounds. Use WebView
|
|
146
353
|
inspection or screenshots when the drawn shape matters.
|
|
147
354
|
|
|
355
|
+
## Viewport
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
# Set the camera transform (screen = world * scale + {x,y})
|
|
359
|
+
curl -X POST http://localhost:4313/api/canvas/viewport \
|
|
360
|
+
-H "Content-Type: application/json" \
|
|
361
|
+
-d '{"x":64,"y":96,"scale":0.8}'
|
|
362
|
+
|
|
363
|
+
# Fit selected nodes (omit nodeIds to fit the whole canvas)
|
|
364
|
+
curl -X POST http://localhost:4313/api/canvas/fit \
|
|
365
|
+
-H "Content-Type: application/json" \
|
|
366
|
+
-d '{"nodeIds":["node-1"],"width":1200,"height":700}'
|
|
367
|
+
|
|
368
|
+
# Focus without moving the camera
|
|
369
|
+
curl -X POST http://localhost:4313/api/canvas/focus \
|
|
370
|
+
-H "Content-Type: application/json" \
|
|
371
|
+
-d '{"id":"node-1","noPan":true}'
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Viewport `x`/`y`, fit `width`/`height`, and fit padding are interpreted against
|
|
375
|
+
the **canvas area**, excluding the tool rail, top bar, and other surrounding
|
|
376
|
+
page chrome—not the full browser window. Camera, fit, and focus-only requests
|
|
377
|
+
do not create or refresh agent writer presence. Use the explicit presence API
|
|
378
|
+
when an agent should publish a cursor or `focusNodeId`.
|
|
379
|
+
|
|
148
380
|
## Pins
|
|
149
381
|
|
|
150
382
|
```bash
|
|
@@ -155,14 +387,30 @@ curl -X POST http://localhost:4313/api/canvas/context-pins \
|
|
|
155
387
|
|
|
156
388
|
# Get pinned context
|
|
157
389
|
curl http://localhost:4313/api/canvas/pinned-context
|
|
390
|
+
|
|
391
|
+
# Cross-board brief. budget is a UTF-16 character ceiling (default 16000, max 100000).
|
|
392
|
+
# Without since, the board/consumer cursor advances through only fully delivered revisions.
|
|
393
|
+
curl 'http://localhost:4313/api/canvas/context?consumer=codex&budget=16000'
|
|
158
394
|
```
|
|
159
395
|
|
|
396
|
+
`consumer` is optional. Supply a stable unique value only for a durable,
|
|
397
|
+
board-scoped cursor; without `consumer` or `since`, each request starts from the
|
|
398
|
+
beginning. An explicit `since` never advances a cursor. The brief prioritizes
|
|
399
|
+
pins, then relevant current-board changes and asks, then compact linked or
|
|
400
|
+
same-folder board context. Every item carries source board/card IDs. If card text
|
|
401
|
+
is clipped, use those IDs with the board/node read route rather than guessing
|
|
402
|
+
from the excerpt. Reading inactive boards does not open them.
|
|
403
|
+
|
|
160
404
|
## AX context and focus
|
|
161
405
|
|
|
162
406
|
AX context is the host-agnostic agent-experience layer. It combines existing
|
|
163
407
|
context pins with a persisted focus node set that adapters can inject into
|
|
164
408
|
their native prompt/context hooks.
|
|
165
409
|
|
|
410
|
+
The context response includes `boardId` (`null` on Home), captured with its content
|
|
411
|
+
and pins. Adapters should send that ID when recording a proxied context read, rather
|
|
412
|
+
than looking up whichever board is active after delivery.
|
|
413
|
+
|
|
166
414
|
```bash
|
|
167
415
|
# Get persisted AX state
|
|
168
416
|
curl http://localhost:4313/api/canvas/ax
|
|
@@ -208,6 +456,22 @@ curl -X POST http://localhost:4313/api/canvas/ax/evidence \
|
|
|
208
456
|
# Timeline — read the bounded timeline (default limit 50, max 200)
|
|
209
457
|
curl "http://localhost:4313/api/canvas/ax/timeline?limit=50"
|
|
210
458
|
|
|
459
|
+
# Context reads — which canvas context each agent read, and whether its pinned
|
|
460
|
+
# nodes were in what came back (newest first, default 50, max 500; the per-consumer
|
|
461
|
+
# summary covers the whole retained log of 5,000 reads). Agent reads of pinned
|
|
462
|
+
# context, AX context, AX state, summary, spatial context and layout are recorded
|
|
463
|
+
# automatically; the workbench's own reads are not.
|
|
464
|
+
curl "http://localhost:4313/api/canvas/ax/context-reads?limit=50"
|
|
465
|
+
|
|
466
|
+
# Context reads — a proxy (an MCP server attached to this daemon, a host adapter)
|
|
467
|
+
# records the read its agent actually made. Its own fetches send
|
|
468
|
+
# `x-pmx-proxied-read: 1` so they are not recorded twice.
|
|
469
|
+
# Pass boardId captured at read time (null for Home); omitting it uses the
|
|
470
|
+
# currently open board. MCP bytes measure the final formatted text response.
|
|
471
|
+
curl -X POST http://localhost:4313/api/canvas/ax/context-reads \
|
|
472
|
+
-H "Content-Type: application/json" \
|
|
473
|
+
-d '{"channel":"adapter","resource":"copilot:prompt-context","consumer":"copilot","pinnedNodeIds":["node-1"],"deliveredNodeIds":["node-1"],"bytes":2048}'
|
|
474
|
+
|
|
211
475
|
# Canvas-bound — add / update a work item
|
|
212
476
|
curl -X POST http://localhost:4313/api/canvas/ax/work \
|
|
213
477
|
-H "Content-Type: application/json" \
|
|
@@ -341,13 +605,20 @@ When that session ends (`attached: false`, `session-end`, or the idle expiry)
|
|
|
341
605
|
the stream carries one `agent-session-ended` frame:
|
|
342
606
|
|
|
343
607
|
```json
|
|
344
|
-
{ "label": "Copilot", "
|
|
608
|
+
{ "label": "Copilot", "parentAgentId": null, "endedAt": "…", "endedBy": "agent",
|
|
609
|
+
"unchanged": false, "counts": { "items": 4, "done": 3, "cancelled": 1, "rejected": 0, "held": 0 },
|
|
345
610
|
"snapshot": { "id": "…", "name": "Before session · Copilot · 14:00" } }
|
|
346
611
|
```
|
|
347
612
|
|
|
348
|
-
`items`/`done` count the work items on the board;
|
|
349
|
-
|
|
350
|
-
empty at attach
|
|
613
|
+
`items`/`done` count the work items on the board; cancelled items, rejected
|
|
614
|
+
gates, and held gates have separate counts. `snapshot` is null when the board was
|
|
615
|
+
empty at attach or unchanged at end (the redundant snapshot is removed).
|
|
616
|
+
The browser shows a receipt only for a changed top-level session: `unchanged: true`
|
|
617
|
+
and worker endings (`parentAgentId` set) never open or replace a popup. An empty
|
|
618
|
+
board that stays empty is unchanged too. This only filters the popup: session-end
|
|
619
|
+
events, timeline records, and changed-session snapshots remain available.
|
|
620
|
+
There is at most one receipt, replaced by the next qualifying ending and kept until
|
|
621
|
+
dismissed so restore/diff actions do not disappear on a timer. Its *View
|
|
351
622
|
diff* is `GET /api/canvas/snapshots/<id>/diff` against that snapshot, and
|
|
352
623
|
restoring the snapshot undoes the session. Adapters should end their session
|
|
353
624
|
explicitly so the human gets the receipt promptly rather than after the idle
|