@1agh/maude 0.29.0 → 0.31.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.
Files changed (162) hide show
  1. package/README.md +6 -6
  2. package/apps/studio/acp/bridge.ts +285 -0
  3. package/apps/studio/acp/env.ts +48 -0
  4. package/apps/studio/acp/index.ts +132 -0
  5. package/apps/studio/acp/probe.ts +112 -0
  6. package/apps/studio/acp/transcript.ts +149 -0
  7. package/apps/studio/ai-banner.tsx +0 -1
  8. package/apps/studio/annotations-align.ts +149 -0
  9. package/apps/studio/annotations-bindings.ts +197 -0
  10. package/apps/studio/annotations-context-toolbar.tsx +436 -186
  11. package/apps/studio/annotations-groups.ts +270 -0
  12. package/apps/studio/annotations-layer.tsx +1714 -1661
  13. package/apps/studio/annotations-model.ts +2077 -0
  14. package/apps/studio/annotations-snap.ts +125 -0
  15. package/apps/studio/api.ts +433 -182
  16. package/apps/studio/bin/_png-playwright.mjs +1 -1
  17. package/apps/studio/bin/annotate.mjs +732 -0
  18. package/apps/studio/bin/annotate.sh +17 -0
  19. package/apps/studio/bin/chat-open.sh +44 -0
  20. package/apps/studio/bin/read-annotations.mjs +152 -17
  21. package/apps/studio/build.ts +1 -1
  22. package/apps/studio/canvas-arrowheads.ts +78 -9
  23. package/apps/studio/canvas-cursors.ts +2 -0
  24. package/apps/studio/canvas-edit.ts +257 -7
  25. package/apps/studio/canvas-icons.tsx +105 -0
  26. package/apps/studio/canvas-lib.tsx +112 -19
  27. package/apps/studio/canvas-list-watch.ts +177 -0
  28. package/apps/studio/canvas-shell.tsx +326 -9
  29. package/apps/studio/client/app.jsx +3579 -250
  30. package/apps/studio/client/canvas-url.js +5 -0
  31. package/apps/studio/client/github.js +99 -0
  32. package/apps/studio/client/index.html +1 -1
  33. package/apps/studio/client/panels/ChatPanel.jsx +770 -0
  34. package/apps/studio/client/panels/CollabModelInfographic.jsx +71 -0
  35. package/apps/studio/client/panels/CreateProject.jsx +334 -0
  36. package/apps/studio/client/panels/DiffView.jsx +590 -0
  37. package/apps/studio/client/panels/GitPanel.jsx +767 -0
  38. package/apps/studio/client/panels/IdentityBar.jsx +294 -0
  39. package/apps/studio/client/panels/OnboardingWizard.jsx +563 -0
  40. package/apps/studio/client/panels/RepoBranchSwitcher.jsx +349 -0
  41. package/apps/studio/client/panels/acp-runtime.js +286 -0
  42. package/apps/studio/client/panels/chat-markdown.jsx +138 -0
  43. package/apps/studio/client/panels/git-grouping.js +86 -0
  44. package/apps/studio/client/styles/0-reset.css +4 -0
  45. package/apps/studio/client/styles/3-shell-maude.css +1326 -14
  46. package/apps/studio/client/styles/4-components.css +39 -0
  47. package/apps/studio/client/styles/5-maude-overrides.css +41 -2
  48. package/apps/studio/client/styles/6-acp-chat.css +771 -0
  49. package/apps/studio/client/styles/_index.css +2 -0
  50. package/apps/studio/client/tour/collab-tour.js +61 -0
  51. package/apps/studio/client/tour/overlay.jsx +116 -18
  52. package/apps/studio/client/tour/usage-tour.js +23 -10
  53. package/apps/studio/client/whats-new.jsx +25 -10
  54. package/apps/studio/collab/registry.ts +13 -0
  55. package/apps/studio/collab/room.ts +36 -0
  56. package/apps/studio/commands/annotation-strokes-command.ts +1 -1
  57. package/apps/studio/commands/move-artboards-command.ts +1 -1
  58. package/apps/studio/comments-overlay.tsx +7 -5
  59. package/apps/studio/context-menu.tsx +4 -3
  60. package/apps/studio/contextual-toolbar.tsx +14 -0
  61. package/apps/studio/cursors-overlay.tsx +37 -21
  62. package/apps/studio/dist/client.bundle.js +31795 -1829
  63. package/apps/studio/dist/comment-mount.js +97 -9
  64. package/apps/studio/dist/styles.css +7938 -1599
  65. package/apps/studio/dom-selection.ts +115 -0
  66. package/apps/studio/export-dialog.tsx +3 -3
  67. package/apps/studio/git/endpoints.ts +338 -0
  68. package/apps/studio/git/service.ts +1334 -0
  69. package/apps/studio/git/watch.ts +97 -0
  70. package/apps/studio/github/endpoints.ts +358 -0
  71. package/apps/studio/github/service.ts +231 -0
  72. package/apps/studio/github/token.ts +53 -0
  73. package/apps/studio/history.ts +20 -3
  74. package/apps/studio/hmr-broadcast.ts +9 -2
  75. package/apps/studio/http.ts +508 -6
  76. package/apps/studio/input-router.tsx +7 -0
  77. package/apps/studio/inspect.ts +37 -8
  78. package/apps/studio/participants-chrome.tsx +70 -16
  79. package/apps/studio/paths.ts +12 -0
  80. package/apps/studio/scaffold-design.ts +57 -0
  81. package/apps/studio/server.ts +70 -4
  82. package/apps/studio/sync/agent.ts +311 -57
  83. package/apps/studio/sync/codec.ts +69 -0
  84. package/apps/studio/sync/cold-start.ts +198 -0
  85. package/apps/studio/sync/connection-state.ts +58 -2
  86. package/apps/studio/sync/hub-link.ts +137 -0
  87. package/apps/studio/sync/index.ts +563 -221
  88. package/apps/studio/sync/journal.ts +190 -0
  89. package/apps/studio/sync/migrate-seed.ts +202 -44
  90. package/apps/studio/sync/projection.ts +22 -3
  91. package/apps/studio/sync/status.ts +15 -4
  92. package/apps/studio/test/acp-bridge.test.ts +127 -0
  93. package/apps/studio/test/acp-env.test.ts +65 -0
  94. package/apps/studio/test/acp-origin-gate.test.ts +78 -0
  95. package/apps/studio/test/acp-transcript.test.ts +112 -0
  96. package/apps/studio/test/activity.test.ts +1 -7
  97. package/apps/studio/test/annotate-write.test.ts +184 -0
  98. package/apps/studio/test/annotations-align.test.ts +88 -0
  99. package/apps/studio/test/annotations-bindings.test.ts +124 -0
  100. package/apps/studio/test/annotations-groups.test.ts +231 -0
  101. package/apps/studio/test/annotations-snap.test.ts +79 -0
  102. package/apps/studio/test/canvas-create-api.test.ts +72 -0
  103. package/apps/studio/test/canvas-edit.test.ts +181 -1
  104. package/apps/studio/test/canvas-list-watch.test.ts +322 -0
  105. package/apps/studio/test/canvas-meta-api.test.ts +161 -27
  106. package/apps/studio/test/canvas-origin-gate.test.ts +43 -0
  107. package/apps/studio/test/chat-markdown.test.tsx +58 -0
  108. package/apps/studio/test/collab-bridge.test.ts +0 -2
  109. package/apps/studio/test/collab-room.test.ts +2 -7
  110. package/apps/studio/test/collab-session-survival.test.tsx +176 -0
  111. package/apps/studio/test/csp-canvas-shell.test.ts +5 -0
  112. package/apps/studio/test/csrf-write-guard.test.ts +78 -0
  113. package/apps/studio/test/editing-presence.test.ts +103 -0
  114. package/apps/studio/test/figjam-v3-model.test.ts +342 -0
  115. package/apps/studio/test/fixtures/figjam-v3-groups-bindings.svg +1 -0
  116. package/apps/studio/test/fixtures/mock-acp-agent.mjs +45 -0
  117. package/apps/studio/test/git-api.test.ts +0 -0
  118. package/apps/studio/test/git-branches.test.ts +106 -0
  119. package/apps/studio/test/git-grouping.test.ts +106 -0
  120. package/apps/studio/test/git-watch.test.ts +97 -0
  121. package/apps/studio/test/github-api.test.ts +465 -0
  122. package/apps/studio/test/hub-link.test.ts +69 -0
  123. package/apps/studio/test/participants-chrome.test.ts +36 -1
  124. package/apps/studio/test/shared-doc-migrate.test.ts +224 -14
  125. package/apps/studio/test/sync-agent.test.ts +272 -2
  126. package/apps/studio/test/sync-codec.test.ts +65 -0
  127. package/apps/studio/test/sync-cold-seed-dedup.test.ts +187 -0
  128. package/apps/studio/test/sync-cold-start.test.ts +304 -0
  129. package/apps/studio/test/sync-connection-state.test.ts +68 -0
  130. package/apps/studio/test/sync-hardening.test.ts +0 -8
  131. package/apps/studio/test/sync-hubs-config.test.ts +0 -1
  132. package/apps/studio/test/sync-incident-replay.test.ts +211 -0
  133. package/apps/studio/test/sync-journal.test.ts +176 -0
  134. package/apps/studio/test/sync-runtime.test.ts +360 -5
  135. package/apps/studio/test/sync-status.test.ts +66 -0
  136. package/apps/studio/test/tour-overlay.test.tsx +18 -0
  137. package/apps/studio/test/use-annotation-resize.test.ts +159 -0
  138. package/apps/studio/test/use-artboard-drag.test.ts +0 -1
  139. package/apps/studio/test/use-collab.test.ts +0 -0
  140. package/apps/studio/test/use-tool-mode.test.tsx +5 -2
  141. package/apps/studio/tool-palette.tsx +30 -11
  142. package/apps/studio/undo-hud.tsx +0 -1
  143. package/apps/studio/use-agent-presence.tsx +4 -2
  144. package/apps/studio/use-annotation-resize.tsx +484 -54
  145. package/apps/studio/use-annotation-selection.tsx +16 -4
  146. package/apps/studio/use-canvas-activity.tsx +2 -2
  147. package/apps/studio/use-chrome-visibility.tsx +66 -0
  148. package/apps/studio/use-collab.tsx +434 -202
  149. package/apps/studio/use-selection-set.tsx +9 -0
  150. package/apps/studio/use-tool-mode.tsx +5 -1
  151. package/apps/studio/whats-new.json +208 -10
  152. package/apps/studio/whats-new.schema.json +18 -2
  153. package/apps/studio/ws.ts +44 -1
  154. package/cli/commands/design-link.test.mjs +84 -0
  155. package/cli/commands/design.mjs +3 -1
  156. package/cli/commands/design.test.mjs +5 -1
  157. package/cli/lib/design-link.mjs +51 -1
  158. package/cli/lib/gitignore-block.mjs +16 -3
  159. package/cli/lib/gitignore-block.test.mjs +13 -1
  160. package/package.json +11 -9
  161. package/plugins/design/dependencies.json +17 -0
  162. package/plugins/design/templates/_shell.html +58 -12
@@ -22,19 +22,32 @@ export const END_MARKER = '# maude:end';
22
22
  */
23
23
  export function buildBlock(designRel = '.design') {
24
24
  const root = designRel.replace(/\/+$/, '');
25
+ // The canonical IGNORED set is the DDR-115 runtime-state taxonomy — kept in
26
+ // lockstep with `apps/studio/git/service.ts` (isMaudeRuntimeState backstop)
27
+ // and the repo's own `.gitignore`. VERSIONED content (canvases, `.meta.json`,
28
+ // `*.annotations.svg`, `system/**`, `config.json`) is deliberately absent.
25
29
  const lines = [
26
30
  BEGIN_MARKER,
27
- '# Maude design plugin runtime — gitignored even in linked mode (DDR-056).',
28
- `${root}/_state/`, // binary CRDT logs (regenerable from hub)
31
+ '# Maude design plugin runtime — gitignored even in linked mode (DDR-056/DDR-115).',
32
+ // Per-machine runtime JSON.
29
33
  `${root}/_server.json`,
30
34
  `${root}/_server.log`,
35
+ `${root}/_server.lock`,
31
36
  `${root}/_active.json`,
32
37
  `${root}/_sync.json`, // linked-mode offline/sync status (Task 8)
38
+ `${root}/_preflight.json`,
39
+ `${root}/_locator.json`, // regenerable slug→path index
40
+ `${root}/_export-history.json`,
41
+ // Per-machine / per-user dirs.
42
+ `${root}/_state/`, // binary CRDT logs (regenerable from hub)
33
43
  `${root}/_history/`,
34
44
  `${root}/_trash/`, // soft-deleted canvases (recoverable locally — Phase 22 delete)
35
45
  `${root}/_draw/`, // draw-agent proof canvases (regenerable — Phase 25)
36
- `${root}/_canvas-state/`, // per-machine canvas undo/redo + scratch state
46
+ `${root}/_smoke/`, // batch-screenshot output (regenerable DDR-021)
47
+ `${root}/_canvas-state/`, // per-machine canvas scratch + camera (`*.view.json`, DDR-115)
37
48
  `${root}/_chat/`, // ACP transcripts (per-machine)
49
+ `${root}/_untrusted/`, // hub-synced untrusted file mirror (DDR-054)
50
+ `${root}/_comments/`, // hub-sync-only collab comments (DDR-102/DDR-115 — never git)
38
51
  END_MARKER,
39
52
  ];
40
53
  return `${lines.join('\n')}\n`;
@@ -31,17 +31,29 @@ test('buildBlock includes the runtime paths and is marker-wrapped', () => {
31
31
  for (const p of [
32
32
  '.design/_state/',
33
33
  '.design/_server.json',
34
+ '.design/_server.log',
35
+ '.design/_server.lock',
34
36
  '.design/_active.json',
35
37
  '.design/_sync.json',
38
+ '.design/_preflight.json',
39
+ '.design/_locator.json',
40
+ '.design/_export-history.json',
36
41
  '.design/_history/',
42
+ '.design/_trash/',
37
43
  '.design/_draw/',
44
+ '.design/_smoke/',
45
+ '.design/_canvas-state/', // covers the DDR-115 `<slug>.view.json` camera
38
46
  '.design/_chat/',
47
+ '.design/_untrusted/',
48
+ '.design/_comments/', // hub-sync-only (DDR-115)
39
49
  ]) {
40
50
  assert.ok(block.includes(p), `missing ${p}`);
41
51
  }
42
- // Committed artifacts must NOT be ignored.
52
+ // VERSIONED content must NOT be ignored (DDR-115 taxonomy).
43
53
  assert.ok(!block.includes('.design/config.json'));
44
54
  assert.ok(!/\.design\/\*\.html/.test(block));
55
+ // Annotations are versioned — never in the ignore block.
56
+ assert.ok(!/annotations\.svg/.test(block), 'annotations must stay versioned');
45
57
  });
46
58
 
47
59
  test('buildBlock honors a custom design root', () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1agh/maude",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "description": "Marketplace of Claude Code plugins by Michal Dovrtěl: `design` (canvas-first design iteration) + `flow` (generic agentic workflow loop with .ai second brain). Ships the `maude` CLI (with `mdcc` legacy alias) to scaffold workspace, run the design dev server, and manage configs.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -20,7 +20,9 @@
20
20
  "start": "bun run apps/studio/server.ts",
21
21
  "dev": "bun run apps/studio/server.ts --port 4555",
22
22
  "dev:site": "pnpm --filter @maude/site dev --port 4398",
23
- "build": "pnpm -r --if-present run build",
23
+ "dev:desktop": "PATH=\"$HOME/.cargo/bin:$PATH\" pnpm --filter @maude/desktop tauri dev",
24
+ "build:desktop": "PATH=\"$HOME/.cargo/bin:$PATH\" pnpm --filter @maude/desktop tauri build",
25
+ "build": "pnpm -r --if-present --filter '!@maude/desktop' run build",
24
26
  "build:binary": "bun run apps/studio/build.ts --release",
25
27
  "test": "node --test --test-reporter=spec cli/**/*.test.mjs",
26
28
  "test:dev-server": "cd apps/studio && bun test",
@@ -41,13 +43,13 @@
41
43
  "prepublishOnly": "bash scripts/check-version-parity.sh && bash apps/studio/bin/check-runtime-bundles.sh"
42
44
  },
43
45
  "optionalDependencies": {
44
- "@1agh/maude-darwin-arm64": "0.29.0",
45
- "@1agh/maude-darwin-x64": "0.29.0",
46
- "@1agh/maude-linux-arm64": "0.29.0",
47
- "@1agh/maude-linux-arm64-musl": "0.29.0",
48
- "@1agh/maude-linux-x64": "0.29.0",
49
- "@1agh/maude-linux-x64-musl": "0.29.0",
50
- "@1agh/maude-win32-x64": "0.29.0"
46
+ "@1agh/maude-darwin-arm64": "0.31.0",
47
+ "@1agh/maude-darwin-x64": "0.31.0",
48
+ "@1agh/maude-linux-arm64": "0.31.0",
49
+ "@1agh/maude-linux-arm64-musl": "0.31.0",
50
+ "@1agh/maude-linux-x64": "0.31.0",
51
+ "@1agh/maude-linux-x64-musl": "0.31.0",
52
+ "@1agh/maude-win32-x64": "0.31.0"
51
53
  },
52
54
  "files": [
53
55
  "cli",
@@ -170,6 +170,23 @@
170
170
  "fallbackBehavior": "Discovery + critic-panel rounds fall back to numbered-prose chat. Slower, fewer options per round, no preview side-pane.",
171
171
  "usedBy": ["skills/design-system/SKILL.md", "commands/setup-ds.md", "commands/new.md"],
172
172
  "docsUrl": "https://docs.claude.com/en/docs/claude-code"
173
+ },
174
+ {
175
+ "id": "claude",
176
+ "type": "cli",
177
+ "hardness": "soft",
178
+ "check": {
179
+ "command": "claude --version",
180
+ "expectExit": 0
181
+ },
182
+ "install": {
183
+ "preferred": "npm i -g @anthropic-ai/claude-code",
184
+ "darwin": "brew install --cask claude-code"
185
+ },
186
+ "autoInstall": false,
187
+ "fallbackBehavior": "Phase 31 (DDR-123) — the native ACP chat sidepanel drives the user's OWN installed `claude` CLI on their Pro/Max subscription (never API billing). Without it the panel shows the not-connected explainer ('run `claude` in a terminal and `/login`'); every other design surface is unaffected.",
188
+ "usedBy": ["dev-server/acp/probe.ts", "dev-server/acp/bridge.ts"],
189
+ "docsUrl": "https://docs.claude.com/en/docs/claude-code"
173
190
  }
174
191
  ]
175
192
  }
@@ -170,32 +170,53 @@
170
170
  // Phase 13.1 / DDR-077 — error-resilient HMR while an agent edits. Hoisted
171
171
  // here so the HMR client (below) can soft-reload the canvas module instead
172
172
  // of location.reload()-ing into a half-saved (broken) build.
173
- const canvasUrl = canvasRel ? ('/' + designRel + '/' + canvasRel) : null;
173
+ // Phase 27 (E2) DiffView "before" pane. `?sha=<ref>` renders the canvas
174
+ // AT a past version (the dev-server's serveHistoricalCanvas builds from
175
+ // `git show <sha>:<path>`). Baked into the module URL so both the initial
176
+ // import and the HMR soft-reload carry it.
177
+ const shaParam = params.get('sha');
178
+ const canvasQuery = shaParam ? ('?sha=' + encodeURIComponent(shaParam)) : '';
179
+ const canvasUrl = canvasRel ? ('/' + designRel + '/' + canvasRel + canvasQuery) : null;
174
180
  const myFileKey = canvasRel ? (designRel + '/' + canvasRel) : null;
175
181
  // True while an `ai-activity` entry is live for THIS canvas (an agent is
176
182
  // running /design:edit|new on it). Mirrors ai-banner's gate: parent relays
177
183
  // ai-activity via postMessage when embedded; the own-WS path (standalone /
178
184
  // same-origin inspector socket) is handled in connectHmr below.
179
185
  let agentEditing = false;
186
+ // SECURITY (ethical-hacker A1) — the CSS-panel optimistic-reload-skip
187
+ // timestamp lives HERE, in the shell-script closure, NOT a window global:
188
+ // the canvas module shares this realm, so a window global would let
189
+ // untrusted canvas JS pin it and suppress reloads to desync view/source.
190
+ // It's set ONLY from the parent-gated message below (a canvas self-post
191
+ // can't reach it), and the HMR echo-guard reads this local, not window.*.
192
+ let lastCssOptimisticAt = 0;
180
193
  window.addEventListener('message', (e) => {
181
194
  // DDR-078 security follow-up: only the trusted embedding parent relays
182
- // ai-activity. Reject canvas self-posts (which could flip the HMR gate)
183
- // and any non-parent source. Standalone gets it via its own WS below.
195
+ // ai-activity / apply-style. Reject canvas self-posts (which could flip
196
+ // the HMR gate) and any non-parent source. Standalone gets it via its WS.
184
197
  if (e.source !== window.parent || window.parent === window) return;
185
198
  const m = e && e.data;
186
- if (!m || typeof m !== 'object' || m.dgn !== 'ai-activity') return;
187
- if (myFileKey && m.file === myFileKey) agentEditing = !!m.entry;
199
+ if (!m || typeof m !== 'object') return;
200
+ if (m.dgn === 'ai-activity') {
201
+ if (myFileKey && m.file === myFileKey) agentEditing = !!m.entry;
202
+ } else if (m.dgn === 'apply-style') {
203
+ // The panel just optimistically applied an edit → skip the redundant
204
+ // follow-up module reload (set here, parent-verified).
205
+ lastCssOptimisticAt = Date.now();
206
+ }
188
207
  });
189
208
 
190
209
  // Soft reload — re-import the canvas module (cache-busted) and swap it in
191
210
  // via the runtime, holding the last good render on a build/import error
192
- // (no white flash). Only used when an agent is editing; manual edits keep
193
- // the plain location.reload() below.
211
+ // (no white flash). Phase 30 (F4): used for EVERY canvas-body change while
212
+ // the runtime is mounted — agent edits, manual edits, AND cross-peer synced
213
+ // writes — so presence + in-canvas state survive. Falls back to the plain
214
+ // location.reload() below only when no runtime is present.
194
215
  function softReload(version) {
195
216
  if (!canvasUrl) { location.reload(); return; }
196
217
  const rt = window.__maudeCanvasRuntime;
197
218
  if (!rt || !rt.remount) { location.reload(); return; }
198
- import(canvasUrl + '?v=' + (version || Date.now()))
219
+ import(canvasUrl + (canvasUrl.includes('?') ? '&' : '?') + 'v=' + (version || Date.now()))
199
220
  .then((mod) => {
200
221
  if (mod && typeof mod.default === 'function') {
201
222
  rt.remount(mod.default);
@@ -320,10 +341,35 @@
320
341
  } else if (msg.mode === 'module' || msg.mode === 'hard') {
321
342
  // Only reload when the change touches *this* canvas (or `_lib`).
322
343
  if (msg.mode === 'hard' || !msg.file || (canvasRel && msg.file === canvasRel)) {
323
- // Phase 13.1 / DDR-077 when an agent is live-editing, soft-
324
- // reload (hold last good on a broken intermediate). Manual edits
325
- // (or no runtime yet) keep the plain, immediate hard reload.
326
- if (agentEditing && window.__maudeCanvasRuntime && window.__maudeCanvasRuntime.remount) {
344
+ // Phase 12.3 CSS-panel echo guard. The panel applies each
345
+ // edit optimistically to the live DOM (dgn:'apply-style'), so a
346
+ // `module` reload for THIS canvas's own edit is redundant churn:
347
+ // it remounts the canvas, drops the selection halo, and flickers
348
+ // the iframe. Skip it within a short window of a self-applied
349
+ // optimistic style. `hard` (_lib rebuild) is global — never
350
+ // skipped. Mirrors the meta echo-guard below.
351
+ if (msg.mode === 'module') {
352
+ // read the parent-verified local (NOT a canvas-writable global)
353
+ if (Date.now() - lastCssOptimisticAt < 1500) return;
354
+ }
355
+ // Phase 30 (F4) — prefer an in-place hot-swap for ANY canvas-body
356
+ // (`module`) change whenever the canvas runtime is mounted: the
357
+ // soft-reload re-imports the module and remounts only the canvas
358
+ // content, KEEPING the iframe — and thus the live CollabProvider
359
+ // + presence cursors/avatars — mounted (the collab session is a
360
+ // module-level singleton that survives the remount, use-collab.tsx).
361
+ // This covers cross-peer SYNCED writes, which arrive as a `module`
362
+ // change with NO `ai-activity` entry: a teammate's edit must update
363
+ // seamlessly, never blink everyone's presence (and scroll / tool
364
+ // mode / undo survive too). It also keeps the Phase 13.1 / DDR-077
365
+ // hold-last-good behaviour for agent edits. (`agentEditing` is still
366
+ // tracked from ai-activity above but no longer gates the swap — any
367
+ // module change to the live canvas hot-swaps.) `hard` (_lib rebuild)
368
+ // is global and ALWAYS full-reloads. With no runtime (gallery
369
+ // thumbnails / ?comments=0) we full-reload; softReload itself also
370
+ // falls back to location.reload() when the re-import yields no usable
371
+ // default export.
372
+ if (msg.mode === 'module' && window.__maudeCanvasRuntime && window.__maudeCanvasRuntime.remount) {
327
373
  softReload(msg.version);
328
374
  } else {
329
375
  location.reload();