pmx-canvas 0.4.4 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/Readme.md +52 -4
  3. package/dist/canvas/global.css +115 -11
  4. package/dist/canvas/index.js +93 -72
  5. package/dist/canvas/mermaid-entry.js +3563 -0
  6. package/dist/canvas/surface-theme.css +2 -2
  7. package/dist/json-render/index.css +1 -1
  8. package/dist/types/cli/agent.d.ts +1 -0
  9. package/dist/types/cli/commands/skills.d.ts +1 -1
  10. package/dist/types/cli/commands/smoke.d.ts +1 -0
  11. package/dist/types/client/mermaid-entry.d.ts +11 -0
  12. package/dist/types/client/nodes/DiffNode.d.ts +20 -0
  13. package/dist/types/client/nodes/ExtAppFrame.d.ts +0 -2
  14. package/dist/types/client/nodes/MermaidNode.d.ts +12 -0
  15. package/dist/types/client/state/intent-store.d.ts +6 -0
  16. package/dist/types/client/types.d.ts +2 -2
  17. package/dist/types/server/ax-state-manager.d.ts +5 -0
  18. package/dist/types/server/ax-state.d.ts +9 -3
  19. package/dist/types/server/canvas-db.d.ts +3 -2
  20. package/dist/types/server/canvas-provenance.d.ts +1 -1
  21. package/dist/types/server/canvas-state.d.ts +22 -1
  22. package/dist/types/server/canvas-validation.d.ts +34 -1
  23. package/dist/types/server/html-surface.d.ts +8 -0
  24. package/dist/types/server/index.d.ts +5 -0
  25. package/dist/types/server/operations/ops/ax-shared.d.ts +4 -1
  26. package/dist/types/server/operations/ops/nodes.d.ts +1 -1
  27. package/dist/types/server/operations/registry.d.ts +9 -1
  28. package/dist/types/server/workboard.d.ts +46 -0
  29. package/dist/types/shared/ax-intent.d.ts +6 -0
  30. package/dist/types/shared/ax-surface-protocol.d.ts +7 -0
  31. package/docs/cli.md +12 -0
  32. package/docs/environment.md +1 -0
  33. package/docs/http-api.md +12 -0
  34. package/docs/mcp.md +1 -1
  35. package/docs/node-types.md +2 -0
  36. package/docs/screenshot.png +0 -0
  37. package/docs/screenshots/amp-orb-portal.png +0 -0
  38. package/docs/screenshots/claude-code-desktop.png +0 -0
  39. package/docs/screenshots/codex-app.png +0 -0
  40. package/docs/screenshots/github-copilot-app.png +0 -0
  41. package/package.json +4 -3
  42. package/skills/pmx-canvas/SKILL.md +71 -24
  43. package/skills/pmx-canvas-orchestration/SKILL.md +82 -0
  44. package/skills/pmx-canvas-testing/SKILL.md +3 -0
  45. package/src/cli/agent.ts +2 -0
  46. package/src/cli/commands/ax.ts +28 -3
  47. package/src/cli/commands/skills.ts +1 -1
  48. package/src/cli/commands/smoke.ts +212 -0
  49. package/src/cli/index.ts +15 -2
  50. package/src/cli/shared.ts +1 -0
  51. package/src/client/canvas/CanvasNode.tsx +12 -1
  52. package/src/client/canvas/CanvasViewport.tsx +6 -0
  53. package/src/client/canvas/ExpandedNodeOverlay.tsx +10 -0
  54. package/src/client/canvas/IntentLayer.tsx +8 -6
  55. package/src/client/canvas/Minimap.tsx +2 -0
  56. package/src/client/canvas/auto-fit.ts +2 -0
  57. package/src/client/icons.tsx +4 -0
  58. package/src/client/mermaid-entry.ts +76 -0
  59. package/src/client/nodes/DiffNode.tsx +114 -0
  60. package/src/client/nodes/ExtAppFrame.tsx +259 -84
  61. package/src/client/nodes/MermaidNode.tsx +81 -0
  62. package/src/client/state/intent-bridge.ts +12 -3
  63. package/src/client/state/intent-store.ts +47 -2
  64. package/src/client/state/node-factory.ts +2 -0
  65. package/src/client/state/sse-bridge.ts +28 -0
  66. package/src/client/theme/global.css +115 -11
  67. package/src/client/theme/surface-theme.css +2 -2
  68. package/src/client/types.ts +6 -0
  69. package/src/mcp/server.ts +22 -6
  70. package/src/server/ax-interaction.ts +6 -0
  71. package/src/server/ax-state-manager.ts +27 -6
  72. package/src/server/ax-state.ts +36 -3
  73. package/src/server/canvas-db.ts +83 -60
  74. package/src/server/canvas-operations.ts +39 -9
  75. package/src/server/canvas-provenance.ts +2 -0
  76. package/src/server/canvas-schema.ts +33 -0
  77. package/src/server/canvas-state.ts +78 -6
  78. package/src/server/canvas-validation.ts +79 -0
  79. package/src/server/html-surface.ts +11 -0
  80. package/src/server/index.ts +25 -6
  81. package/src/server/intent-registry.ts +2 -0
  82. package/src/server/operations/composites.ts +3 -2
  83. package/src/server/operations/http.ts +5 -1
  84. package/src/server/operations/ops/ax-shared.ts +20 -1
  85. package/src/server/operations/ops/ax-state.ts +4 -7
  86. package/src/server/operations/ops/ax-timeline.ts +26 -3
  87. package/src/server/operations/ops/ax-work.ts +27 -1
  88. package/src/server/operations/ops/batch.ts +11 -1
  89. package/src/server/operations/ops/json-render.ts +44 -0
  90. package/src/server/operations/ops/nodes.ts +24 -2
  91. package/src/server/operations/ops/viewport.ts +8 -1
  92. package/src/server/operations/registry.ts +122 -1
  93. package/src/server/server.ts +58 -3
  94. package/src/server/workboard.ts +159 -0
  95. package/src/shared/ax-intent.ts +6 -0
  96. package/src/shared/ax-surface-protocol.ts +8 -0
  97. package/src/shared/surface.ts +2 -0
  98. package/src/shared/themes.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,112 @@
3
3
  All notable changes to `pmx-canvas` are documented here. This project follows
4
4
  [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [0.4.6] - 2026-08-08
7
+
8
+ ### Added
9
+
10
+ - A `pmx-canvas smoke` command: one-command check that a running canvas works
11
+ in the current environment — server health + workspace, CLI/server version
12
+ skew, MCP initialize handshake, a temporary node create/search/remove
13
+ round-trip, and board validation. JSON report, exit 1 on failure.
14
+ - The `/health` endpoint now reports the server's package `version`, so tools
15
+ can detect version skew between a CLI and the daemon it targets.
16
+ - The CLI now accepts `--agent-id` on `ax work add/update` and `ax event add`,
17
+ and `--agent-id` / `--target` on `ax steer`; the SDK's work, event, and
18
+ steering methods accept the same identity fields.
19
+ - The skill now teaches in-view placement and content sizing: focus or fit
20
+ newly created user-facing nodes, use per-type default sizes, and keep AX
21
+ state reads lean.
22
+ - A new `diff` node type: unified diffs render with per-file headers, hunk
23
+ rows, and colored added/removed lines instead of a plain code fence.
24
+ - A new `mermaid` node type: flowcharts, sequence and state diagrams render
25
+ client-side from mermaid text — no hosted app needed; Excalidraw remains
26
+ for interactive drawing.
27
+ - A live work-item board: `canvas_render { action: "workboard" }` (HTTP
28
+ `POST /api/canvas/workboard`) materializes one board node showing all AX
29
+ work items by status, and it refreshes automatically whenever work items
30
+ change.
31
+
32
+ ### Changed
33
+
34
+ - **Nodes created with unreadably small explicit sizes are now clamped up to a
35
+ per-type minimum.** A request for e.g. 200x100 now yields a readable
36
+ default-ish size instead; pass `strictSize: true` to keep a genuinely small
37
+ fixed frame. `validate` reports any undersized nodes as advisory size
38
+ warnings. Agents doing their own layout arithmetic should read back the
39
+ created size (or set `strictSize`).
40
+ - The README's MCP and Amp orb setup guides now cover portable configs: pin
41
+ the package version in orb setup scripts and avoid hard-coding an absolute
42
+ `PMX_CANVAS_WORKSPACE_ROOT` in committed MCP configs.
43
+ - Focus margins are now screen-space and zoom-aware, so a focused node clears
44
+ the floating toolbar at any scale.
45
+
46
+ ### Fixed
47
+
48
+ - A browser panel left open across a `pmx-canvas` upgrade now reloads itself
49
+ once on reconnect instead of silently running the old client bundle (which
50
+ hid new client behavior such as the auto-ghost minimum dwell).
51
+ - A batch that pins nodes now updates the browser's pin state immediately —
52
+ the context menu no longer shows a stale "Pin as context" until reload.
53
+ - The MCP stdio server now exits when its client closes the connection instead
54
+ of remaining as an orphaned process.
55
+ - Black app tiles in WebKit host panels (e.g. the GitHub Copilot app): hosted
56
+ app frames now boot one at a time, confirm they actually painted via a paint
57
+ probe, and recover automatically when they did not — soft resize, then
58
+ remount, then an explicit Retry button instead of a silent black tile. The
59
+ loading overlay stays up until the paint is confirmed.
60
+
61
+ ## [0.4.5] - 2026-08-07
62
+
63
+ ### Added
64
+
65
+ - A third bundled skill, `pmx-canvas-orchestration`: the choreography for
66
+ multi-agent orchestration ON a canvas board — the agent host executes, the
67
+ canvas is the shared graph, state, human-steering surface, and audit trail.
68
+ It ships in the package's `skills/`; `pmx-canvas skills sync --yes` refreshes
69
+ installed copies of it like the others (sync never creates a copy — install
70
+ one the way your agent layout expects first).
71
+ - Per-agent identity for orchestration: work items, timeline events, and
72
+ steering messages accept an optional `agentId` (who within the host), on
73
+ top of the coarse `source` host label.
74
+ - Addressed steering: a steer can carry a `target` agent id — a consumer
75
+ claiming deliveries only sees steers addressed to it or broadcast steers.
76
+ - Work-item status now mirrors onto linked canvas nodes automatically (an
77
+ `axWorkStatus` chip on the node), so the board reflects step state without
78
+ double-writing.
79
+ - Running as an Amp orb service now binds the portal-assigned `$PORT`
80
+ automatically, so the service command is just `pmx-canvas --no-open` — no
81
+ port flags or `$PORT` interpolation. Honored only when `AMP_ORB` is set, so
82
+ a stray `PORT` in normal shells never changes the default. The README now
83
+ carries the full zero-config orb recipe (setup + services.yaml).
84
+ - Auto-ghost: agent mutations that arrive without an explicit `canvas_intent`
85
+ signal now synthesize a short ghost that settles the moment the mutation
86
+ lands, so agent activity is visible even when the caller doesn't signal.
87
+ Auto-ghosts render lighter (dimmer, dotted, no veto) than a deliberate
88
+ signal; human actions in the browser and `canvas_batch` churn never ghost.
89
+ Disable with `PMX_CANVAS_AUTO_INTENT=0`.
90
+ - Ghost minimum dwell: a ghost now stays visible for a perceptible floor
91
+ (~0.65s) even when its mutation settles within milliseconds.
92
+ - The `amp` AX source label, for Amp host adapters and steering loop
93
+ prevention.
94
+
95
+ ### Changed
96
+
97
+ - The `volt` theme's accent was retuned from coral to the Amp app's cream
98
+ (`#DFDFC1`).
99
+ - Marking an AX delivery is now compare-and-set: `delivered:true` only on the
100
+ actual undelivered→delivered transition, so racing adapters can detect lost
101
+ claims.
102
+ - The WebView-automation unavailable error now names the running Bun version
103
+ and clarifies that the canvas itself keeps working — only automation and
104
+ screenshots need Bun >= 1.3.12.
105
+
106
+ ### Fixed
107
+
108
+ - File nodes are no longer created as content-less slivers: they get a real
109
+ code-preview default size, and untitled file nodes show their filename in
110
+ the title bar instead of a bare "FILE" chip.
111
+
6
112
  ## [0.4.4] - 2026-08-06
7
113
 
8
114
  ### Fixed
@@ -2938,6 +3044,8 @@ otherwise have to discover by trial and error.
2938
3044
  - Regression coverage for snapshot flat-`id` aliases on both MCP and
2939
3045
  HTTP surfaces, plus async / top-level-`await` WebView script bodies.
2940
3046
 
3047
+ [0.4.6]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.6
3048
+ [0.4.5]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.5
2941
3049
  [0.4.4]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.4
2942
3050
  [0.4.3]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.3
2943
3051
  [0.4.2]: https://github.com/pskoett/pmx-canvas/releases/tag/v0.4.2
package/Readme.md CHANGED
@@ -128,6 +128,16 @@ surfaces (the core never imports a host SDK).
128
128
  </p>
129
129
  <p align="center"><sub>The live PMX workbench in the Codex in-app Browser.</sub></p>
130
130
 
131
+ <p align="center">
132
+ <img src="docs/screenshots/claude-code-desktop.png" alt="PMX Canvas in the Claude Code desktop app's built-in browser pane, driven over MCP" width="100%" />
133
+ </p>
134
+ <p align="center"><sub>Claude Code desktop: the workbench in the built-in browser pane, mutated live over MCP.</sub></p>
135
+
136
+ <p align="center">
137
+ <img src="docs/screenshots/amp-orb-portal.png" alt="PMX Canvas running as an Amp orb service, viewed through the Amp portal in the Volt theme" width="100%" />
138
+ </p>
139
+ <p align="center"><sub>AMPCode: the canvas as an orb service through the Amp portal (Volt theme).</sub></p>
140
+
131
141
  - **GitHub Copilot app** — a committed project canvas extension
132
142
  (`.github/extensions/pmx-canvas/`) opens the live PMX workbench in a native
133
143
  Copilot panel (light-themed by default to match the app, via the `?theme=`
@@ -158,7 +168,6 @@ surfaces (the core never imports a host SDK).
158
168
  either behavior when diagnosing). Non-orb buffering proxies get the same
159
169
  protections via runtime detection: an SSE watchdog that falls back to
160
170
  polling, and the boot-time iframe probe.
161
- <!-- screenshot: docs/screenshots/amp-orb-portal.png — PMX Canvas live inside the Amp portal (to be added) -->
162
171
 
163
172
  Any other app browser (the ChatGPT desktop app, an IDE webview, …) works the
164
173
  same zero-adapter way: open the workbench URL, and add `?theme=<name|auto>` to
@@ -219,7 +228,21 @@ Add to your agent's MCP config:
219
228
  }
220
229
  ```
221
230
 
222
- The canvas auto-starts on first tool call.
231
+ The canvas auto-starts on first tool call. Keep the config portable: commit it
232
+ to the repo and let the workspace default to the launch directory — hard-coding
233
+ an absolute `PMX_CANVAS_WORKSPACE_ROOT` breaks other checkouts and machines.
234
+ Set that env var only when your host spawns the MCP server from an incidental
235
+ directory (e.g. `~/.copilot`) instead of the project root.
236
+
237
+ Verify any environment in one command against a running server:
238
+
239
+ ```bash
240
+ bunx pmx-canvas smoke
241
+ ```
242
+
243
+ It checks server health + workspace, CLI/server version skew, the MCP stdio
244
+ initialize handshake, a temp-node create/search/remove round-trip, and board
245
+ validation — JSON report, exit 1 on failure.
223
246
 
224
247
  ### Use inside the GitHub Copilot app
225
248
 
@@ -253,14 +276,39 @@ the full workflow and live-test checklist.
253
276
 
254
277
  Amp needs no adapter either. Run `pmx-canvas` as an orb service (the orb sets
255
278
  `AMP_ORB` in the environment automatically) and open the workbench through the
256
- thread's portal URL. The canvas detects the orb and the portal's nested-iframe
279
+ thread's portal URL. The zero-config recipe for the repo the orb runs in:
280
+
281
+ ```yaml
282
+ # .amp/services.yaml — supervised portal service
283
+ services:
284
+ pmx-canvas:
285
+ command: pmx-canvas --no-open
286
+ portal: true
287
+ health: /health
288
+ ```
289
+
290
+ ```bash
291
+ # .agents/setup — install the CLI (pin the exact version: a fresh orb running
292
+ # @latest can silently pick up a newer release than the one you validated)
293
+ npm install -g pmx-canvas@0.4.5
294
+ ```
295
+
296
+ The server binds the portal-assigned `$PORT` automatically (gated on the
297
+ `AMP_ORB` env the orb always sets, so a stray `PORT` elsewhere never changes
298
+ the default), restores `.pmx-canvas/canvas.db`, and the portal manifest picks
299
+ it up — no port flags or `$PORT` interpolation in the service command. One
300
+ caveat: WebView automation (`pmx-canvas screenshot`) needs Bun >= 1.3.12 in
301
+ the orb image; the canvas itself runs fine without it and says so in the
302
+ error. The canvas detects the orb and the portal's nested-iframe
257
303
  embed on its own: live updates arrive over the proxy-safe polling transport,
258
304
  and iframe-backed nodes (HTML, graph, json-render, web artifacts) render
259
305
  inline via `srcdoc` with their theme styling included. Cross-origin hosted
260
306
  apps (e.g. the hosted Excalidraw MCP app) cannot be inlined and may stay
261
307
  blocked by the portal embed — everything served from the canvas itself works.
262
308
  Debug overrides: `/workbench?transport=poll|sse` and
263
- `?iframe-mode=srcdoc|src`.
309
+ `?iframe-mode=srcdoc|src`. Once the service is up, `pmx-canvas smoke` verifies
310
+ the whole stack (health, versions, MCP handshake, node lifecycle, validation)
311
+ in one command.
264
312
 
265
313
  ### Install the agent skill (recommended)
266
314
 
@@ -456,7 +456,7 @@
456
456
  --c-text-soft: #CBD3CA;
457
457
  --c-muted: #9CA49C;
458
458
  --c-dim: #626962;
459
- --c-accent: #F34E3F;
459
+ --c-accent: #DFDFC1;
460
460
  --c-ok: #52C880;
461
461
  --c-warn: #E4C465;
462
462
  --c-warn-alt: #FFB300;
@@ -465,22 +465,22 @@
465
465
  --c-thinking: #BC8FB4;
466
466
  --c-subagent: #6CA0E0;
467
467
  --c-input-bg: #111311;
468
- --c-dot-grid: rgba(243, 78, 63, 0.08);
468
+ --c-dot-grid: rgba(223, 223, 193, 0.08);
469
469
  --c-panel-overlay: rgba(11, 13, 11, 0.6);
470
470
  --c-panel-glass: rgba(23, 26, 23, 0.92);
471
471
  --c-shadow: rgba(0, 0, 0, 0.3);
472
472
  --c-shadow-heavy: rgba(0, 0, 0, 0.5);
473
- --c-glow-accent: rgba(243, 78, 63, 0.15);
473
+ --c-glow-accent: rgba(223, 223, 193, 0.15);
474
474
  --c-surface-hover: rgba(255, 255, 255, 0.06);
475
475
  --c-surface-subtle: rgba(255, 255, 255, 0.03);
476
476
  --c-surface-th: rgba(255, 255, 255, 0.04);
477
- --c-accent-8: rgba(243, 78, 63, 0.08);
478
- --c-accent-10: rgba(243, 78, 63, 0.1);
479
- --c-accent-12: rgba(243, 78, 63, 0.12);
480
- --c-accent-15: rgba(243, 78, 63, 0.15);
481
- --c-accent-25: rgba(243, 78, 63, 0.25);
482
- --c-accent-30: rgba(243, 78, 63, 0.3);
483
- --c-accent-40: rgba(243, 78, 63, 0.4);
477
+ --c-accent-8: rgba(223, 223, 193, 0.08);
478
+ --c-accent-10: rgba(223, 223, 193, 0.1);
479
+ --c-accent-12: rgba(223, 223, 193, 0.12);
480
+ --c-accent-15: rgba(223, 223, 193, 0.15);
481
+ --c-accent-25: rgba(223, 223, 193, 0.25);
482
+ --c-accent-30: rgba(223, 223, 193, 0.3);
483
+ --c-accent-40: rgba(223, 223, 193, 0.4);
484
484
  --c-ok-10: rgba(82, 200, 128, 0.1);
485
485
  --c-ok-12: rgba(82, 200, 128, 0.12);
486
486
  --c-ok-20: rgba(82, 200, 128, 0.2);
@@ -495,7 +495,7 @@
495
495
  --c-danger-12: rgba(214, 118, 112, 0.12);
496
496
  --c-line-30: rgba(39, 42, 39, 0.3);
497
497
  --c-contrast-fg: #0B0D0B;
498
- --c-accent-hover: #F8695B;
498
+ --c-accent-hover: #EDEDDB;
499
499
  --c-warn-hover: #EBD087;
500
500
  --c-canvas-wash: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(0, 0, 0, 0));
501
501
  --c-annotation: #F1F7F0;
@@ -669,6 +669,29 @@ body,
669
669
  flex-shrink: 0;
670
670
  }
671
671
 
672
+ .canvas-node .node-ax-status {
673
+ font-size: calc(9px * var(--node-chrome-scale, 1));
674
+ padding: calc(1px * var(--node-chrome-scale, 1)) calc(6px * var(--node-chrome-scale, 1));
675
+ border-radius: calc(4px * var(--node-chrome-scale, 1));
676
+ background: var(--c-panel-overlay);
677
+ color: var(--c-muted);
678
+ text-transform: uppercase;
679
+ letter-spacing: 0.04em;
680
+ flex-shrink: 0;
681
+ }
682
+
683
+ .canvas-node .node-ax-status-in-progress {
684
+ color: var(--c-accent);
685
+ }
686
+
687
+ .canvas-node .node-ax-status-done {
688
+ color: var(--c-ok);
689
+ }
690
+
691
+ .canvas-node .node-ax-status-blocked {
692
+ color: var(--c-warn);
693
+ }
694
+
672
695
  .canvas-node .node-controls {
673
696
  display: flex;
674
697
  align-items: center;
@@ -1872,6 +1895,74 @@ html.is-node-resizing .ext-app-preview-catcher {
1872
1895
  }
1873
1896
  }
1874
1897
 
1898
+ /* Diff nodes — unified diff viewer with per-file sections */
1899
+ .diff-node {
1900
+ display: flex;
1901
+ flex-direction: column;
1902
+ gap: 10px;
1903
+ height: 100%;
1904
+ overflow: auto;
1905
+ font-family: var(--mono);
1906
+ font-size: 12px;
1907
+ color: var(--c-text);
1908
+ }
1909
+
1910
+ .diff-node.diff-node-empty {
1911
+ align-items: center;
1912
+ justify-content: center;
1913
+ color: var(--c-muted);
1914
+ }
1915
+
1916
+ .diff-node .diff-file {
1917
+ border: 1px solid var(--c-line);
1918
+ border-radius: 6px;
1919
+ overflow: hidden;
1920
+ flex-shrink: 0;
1921
+ }
1922
+
1923
+ .diff-node .diff-file-header {
1924
+ padding: 4px 8px;
1925
+ background: var(--c-panel-overlay);
1926
+ border-bottom: 1px solid var(--c-line);
1927
+ color: var(--c-text-soft);
1928
+ font-weight: 600;
1929
+ white-space: nowrap;
1930
+ overflow: hidden;
1931
+ text-overflow: ellipsis;
1932
+ }
1933
+
1934
+ .diff-node .diff-lines {
1935
+ margin: 0;
1936
+ padding: 4px 0;
1937
+ overflow-x: auto;
1938
+ font-family: inherit;
1939
+ font-size: inherit;
1940
+ line-height: 1.5;
1941
+ }
1942
+
1943
+ .diff-node .diff-lines > div {
1944
+ padding: 0 8px;
1945
+ white-space: pre;
1946
+ }
1947
+
1948
+ .diff-node .diff-hunk {
1949
+ color: var(--c-muted);
1950
+ }
1951
+
1952
+ .diff-node .diff-line-add {
1953
+ color: var(--c-ok);
1954
+ background: var(--c-ok-10);
1955
+ }
1956
+
1957
+ .diff-node .diff-line-remove {
1958
+ color: var(--c-danger);
1959
+ background: var(--c-danger-12);
1960
+ }
1961
+
1962
+ .diff-node .diff-line-context {
1963
+ color: var(--c-text-soft);
1964
+ }
1965
+
1875
1966
  /* Docked node — compact toolbar-flanking panel */
1876
1967
  .docked-node {
1877
1968
  min-width: 200px;
@@ -3955,6 +4046,19 @@ button.welcome-hint:hover {
3955
4046
  display: contents;
3956
4047
  }
3957
4048
 
4049
+ /* Auto-ghosts (server-synthesized for unlinked agent mutations) read lighter
4050
+ than a deliberate canvas_intent signal: desaturated, dotted, no veto —
4051
+ the opacity drop lives in ghostOpacity() (inline style). */
4052
+ .intent-ghost.is-auto {
4053
+ filter: saturate(0.7);
4054
+ border-style: dotted;
4055
+ }
4056
+
4057
+ .intent-ghost.is-auto .intent-ghost-titlebar,
4058
+ .intent-ghost.is-auto .intent-chip {
4059
+ border-style: dotted;
4060
+ }
4061
+
3958
4062
  .intent-ghost {
3959
4063
  position: absolute;
3960
4064
  pointer-events: none;