@1agh/maude 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +3 -1
  2. package/apps/studio/acp/index.ts +43 -7
  3. package/apps/studio/annotations-layer.tsx +191 -116
  4. package/apps/studio/annotations-model.ts +39 -0
  5. package/apps/studio/annotations-sync.ts +50 -0
  6. package/apps/studio/api.ts +732 -38
  7. package/apps/studio/bin/annotate.mjs +3 -1
  8. package/apps/studio/bin/server-up.sh +17 -2
  9. package/apps/studio/canvas-build.ts +49 -8
  10. package/apps/studio/canvas-edit.ts +468 -7
  11. package/apps/studio/canvas-lib.tsx +82 -18
  12. package/apps/studio/canvas-list-watch.ts +33 -2
  13. package/apps/studio/canvas-notice-message.ts +16 -0
  14. package/apps/studio/canvas-notifications.tsx +19 -0
  15. package/apps/studio/canvas-shell.tsx +57 -6
  16. package/apps/studio/client/app.jsx +783 -245
  17. package/apps/studio/client/apply-edit-request.ts +55 -0
  18. package/apps/studio/client/canvas-url.js +39 -1
  19. package/apps/studio/client/export-center.jsx +111 -61
  20. package/apps/studio/client/github.js +38 -1
  21. package/apps/studio/client/index-loader.ts +76 -0
  22. package/apps/studio/client/panels/CloudBar.jsx +52 -6
  23. package/apps/studio/client/panels/GitPanel.jsx +103 -0
  24. package/apps/studio/client/panels/OnboardingWizard.jsx +36 -7
  25. package/apps/studio/client/panels/RepoBranchSwitcher.jsx +92 -27
  26. package/apps/studio/client/panels/SourceConflictPanel.jsx +166 -0
  27. package/apps/studio/client/panels/SyncPanel.jsx +113 -0
  28. package/apps/studio/client/panels/TeamProjects.jsx +376 -0
  29. package/apps/studio/client/panels/file-deep-link-dialog.jsx +54 -0
  30. package/apps/studio/client/photo-knobs.jsx +3 -0
  31. package/apps/studio/client/share-dialog.jsx +91 -0
  32. package/apps/studio/client/share-link.js +94 -0
  33. package/apps/studio/client/styles/3-shell-maude.css +36 -18
  34. package/apps/studio/client/styles/4-components.css +18 -1
  35. package/apps/studio/client/tree-row-menu.jsx +48 -3
  36. package/apps/studio/client/whats-new.jsx +26 -32
  37. package/apps/studio/cloud/endpoints.ts +132 -0
  38. package/apps/studio/collab/awareness-bridge.ts +65 -14
  39. package/apps/studio/collab/index.ts +4 -0
  40. package/apps/studio/collab/persistence.ts +5 -1
  41. package/apps/studio/collab/registry.ts +9 -3
  42. package/apps/studio/collab/room.ts +13 -2
  43. package/apps/studio/context.ts +59 -0
  44. package/apps/studio/dist/client.bundle.js +1594 -1562
  45. package/apps/studio/dist/comment-mount.js +2 -2
  46. package/apps/studio/dist/runtime/.min-sizes.json +1 -0
  47. package/apps/studio/dist/runtime/sonner.js +1 -0
  48. package/apps/studio/dist/styles.css +1 -1
  49. package/apps/studio/git/accepted-guard.ts +36 -0
  50. package/apps/studio/hmr-broadcast.ts +34 -1
  51. package/apps/studio/http.ts +300 -18
  52. package/apps/studio/inspect.ts +19 -0
  53. package/apps/studio/managed-projects.ts +172 -0
  54. package/apps/studio/notifications.tsx +292 -0
  55. package/apps/studio/runtime-bundle.ts +2 -0
  56. package/apps/studio/server.ts +59 -3
  57. package/apps/studio/sync/accepted-cold-start.ts +225 -0
  58. package/apps/studio/sync/accepted-link.ts +320 -0
  59. package/apps/studio/sync/action-stage.ts +343 -0
  60. package/apps/studio/sync/agent.ts +12 -60
  61. package/apps/studio/sync/cell-file-events.ts +3 -0
  62. package/apps/studio/sync/codec.ts +73 -6
  63. package/apps/studio/sync/ctl-provider.ts +15 -2
  64. package/apps/studio/sync/document-discovery.ts +81 -0
  65. package/apps/studio/sync/file-membership.ts +10 -2
  66. package/apps/studio/sync/file-plane.ts +309 -26
  67. package/apps/studio/sync/index.ts +1174 -21
  68. package/apps/studio/sync/migrate-seed.ts +110 -19
  69. package/apps/studio/sync/poke.ts +4 -2
  70. package/apps/studio/sync/presentation.ts +315 -2
  71. package/apps/studio/sync/projection.ts +820 -23
  72. package/apps/studio/sync/repeated-module.ts +73 -0
  73. package/apps/studio/sync/revision-barrier.ts +129 -0
  74. package/apps/studio/sync/seed-repair.ts +46 -0
  75. package/apps/studio/sync/source-merge.ts +100 -0
  76. package/apps/studio/sync/source-ops.ts +289 -0
  77. package/apps/studio/sync/source-recovery.ts +70 -0
  78. package/apps/studio/sync/source-validation.ts +56 -0
  79. package/apps/studio/sync/status.ts +83 -1
  80. package/apps/studio/sync/transaction-client.ts +486 -0
  81. package/apps/studio/sync/writer-registry.ts +236 -0
  82. package/apps/studio/text-caret.ts +35 -0
  83. package/apps/studio/undo-hud.tsx +9 -87
  84. package/apps/studio/use-canvas-media-drop.tsx +4 -39
  85. package/apps/studio/use-tool-mode.tsx +44 -0
  86. package/apps/studio/whats-new.json +137 -0
  87. package/cli/lib/harness/codex-runtime.mjs +4 -1
  88. package/package.json +9 -8
  89. package/plugins/design/dependencies.json +3 -3
  90. package/plugins/design/templates/_shell.html +95 -7
  91. package/plugins/flow/dependencies.json +3 -3
@@ -1242,7 +1242,9 @@ async function main() {
1242
1242
  const res = await fetch(`${base}/_api/annotations`, {
1243
1243
  method: 'PUT',
1244
1244
  headers: { 'Content-Type': 'application/json' },
1245
- body: JSON.stringify({ file: `${designRel}/${relPath}`, svg: merged }),
1245
+ // `base` — the SVG this edit was merged onto, so a peer's strokes
1246
+ // that landed meanwhile are merged, not replaced (DDR-241).
1247
+ body: JSON.stringify({ file: `${designRel}/${relPath}`, svg: merged, base: svg }),
1246
1248
  signal: AbortSignal.timeout(3000),
1247
1249
  });
1248
1250
  if (res.ok) via = 'server';
@@ -145,9 +145,24 @@ NEEDS_START=1
145
145
  if [ -f "$STATE" ]; then
146
146
  PID=$(read_pid)
147
147
  PORT=$(read_port)
148
+ # Sandboxed agents may reach Studio while kill -0 returns EPERM. Verify the
149
+ # server's identity over HTTP instead of mistaking denied signalling for death.
150
+ HEALTH=""
151
+ if [ -n "$PORT" ]; then
152
+ HEALTH=$(curl -fs --max-time 2 "http://localhost:$PORT/_health" 2>/dev/null || true)
153
+ fi
148
154
  if [ -n "$PID" ] && [ -n "$PORT" ] \
149
- && kill -0 "$PID" 2>/dev/null \
150
- && curl -fs "http://localhost:$PORT/_health" >/dev/null 2>&1; then
155
+ && printf '%s' "$HEALTH" | node -e '
156
+ try {
157
+ const fs = require("node:fs");
158
+ const h = JSON.parse(fs.readFileSync(0, "utf8"));
159
+ const root = fs.realpathSync(process.argv[2]);
160
+ const id = require("node:crypto").createHash("sha256").update(root).digest("hex").slice(0, 12);
161
+ process.exit(h.ok === true && h.app === "design" &&
162
+ Number(h.pid) === Number(process.argv[1]) &&
163
+ (h.rootId === undefined || h.rootId === id) ? 0 : 1);
164
+ } catch { process.exit(1); }
165
+ ' "$PID" "$REPO"; then
151
166
  echo "✓ server alive pid=$PID port=$PORT" >&2
152
167
  echo "$PORT"
153
168
  exit 0
@@ -22,7 +22,7 @@
22
22
  // serves the resulting JS at /<designRel>/ui/<slug>.tsx with Content-Type
23
23
  // `application/javascript`.
24
24
 
25
- import { existsSync } from 'node:fs';
25
+ import { existsSync, realpathSync } from 'node:fs';
26
26
  import path from 'node:path';
27
27
 
28
28
  import { canvasLibPath, canvasLibResolver } from './canvas-lib-resolver.ts';
@@ -129,6 +129,10 @@ export async function buildCanvasModule(
129
129
  // needed; RUNTIME_PACKAGES already lists every specifier the importmap covers.
130
130
  const externalSpecifiers = new Set<string>(RUNTIME_PACKAGES);
131
131
  const denials: Array<{ specifier: string; reason: string }> = [];
132
+ // Every stylesheet the canvas pulls in by relative import — they are inlined
133
+ // (below), so the open canvas has no <link> to swap when one changes; the
134
+ // injector records them for the iframe's HMR client (see buildCssInjector).
135
+ const cssSources = new Set<string>();
132
136
 
133
137
  const built = await Bun.build({
134
138
  entrypoints: [canvasAbsPath],
@@ -151,6 +155,17 @@ export async function buildCanvasModule(
151
155
  'process.env.NODE_ENV': '"production"',
152
156
  },
153
157
  plugins: [
158
+ {
159
+ name: 'css-sources',
160
+ setup(builder) {
161
+ builder.onResolve({ filter: /\.css$/ }, (args: { path: string; importer: string }) => {
162
+ if (args.path.startsWith('.') && args.importer) {
163
+ cssSources.add(path.resolve(path.dirname(args.importer), args.path));
164
+ }
165
+ return null; // record only — resolution continues as before
166
+ });
167
+ },
168
+ },
154
169
  // Resolve `@maude/canvas-lib` BEFORE exact-externals — we want the bare
155
170
  // specifier to map to the dev-server-bundled lib, not get marked external.
156
171
  canvasLibResolver(),
@@ -217,7 +232,26 @@ export async function buildCanvasModule(
217
232
  for (const a of cssAssets) css += await a.text();
218
233
  if (css.trim().length > 0) {
219
234
  const slug = canvasAbsPath.split('/').pop() ?? 'canvas';
220
- js = buildCssInjector(slug, css) + js;
235
+ const root = options.designRoot ?? options.restrictImportsTo;
236
+ // Real paths on both sides: the bundler reports importers by their REAL
237
+ // path, and a design root reached through a symlink (macOS `/var` →
238
+ // `/private/var`, where every temp dir lives) made each source look like
239
+ // `../../private/…` — filtered out, so nothing was ever named and the
240
+ // open canvas never restyled.
241
+ const real = (p: string) => {
242
+ try {
243
+ return realpathSync(p);
244
+ } catch {
245
+ return p;
246
+ }
247
+ };
248
+ const realRoot = root ? real(root) : null;
249
+ const sources = realRoot
250
+ ? [...cssSources]
251
+ .map((abs) => path.relative(realRoot, real(abs)).split(path.sep).join('/'))
252
+ .filter((rel) => rel && !rel.startsWith('..'))
253
+ : [];
254
+ js = buildCssInjector(slug, css, sources) + js;
221
255
  }
222
256
  }
223
257
 
@@ -227,16 +261,23 @@ export async function buildCanvasModule(
227
261
 
228
262
  /**
229
263
  * Synthesize a module-init prologue that creates a `<style data-canvas-css>`
230
- * tag with the bundled CSS text. Idempotent per-slug — duplicate mounts of
231
- * the same canvas don't re-inject. Run at top-level so it executes before
232
- * the React component does its first render.
264
+ * tag with the bundled CSS text. One tag per slug — a duplicate mount reuses
265
+ * it, and a RE-IMPORT (the iframe's soft reload after a stylesheet changed)
266
+ * replaces its text, so a changed import actually reaches the page. Run at
267
+ * top-level so it executes before the React component does its first render.
268
+ *
269
+ * `sources` — the design-root-relative stylesheets inlined here — lands on the
270
+ * tag as `data-canvas-css-sources` (`|`-separated): the iframe's HMR client
271
+ * reloads when one of them changes, since there is no <link> to swap (plan
272
+ * T31/L16: a canvas importing `../system/<ds>/tokens.css` never restyled).
233
273
  */
234
- function buildCssInjector(slug: string, css: string): string {
274
+ function buildCssInjector(slug: string, css: string, sources: readonly string[] = []): string {
235
275
  // JSON-encode the CSS text so we don't need to worry about backticks,
236
276
  // backslashes, or embedded `</style>` (which would break a raw template).
237
277
  const enc = JSON.stringify(css);
238
- const id = `canvas-css-${slug.replace(/[^a-zA-Z0-9-]/g, '_')}`;
239
- return `// canvas-build: inject bundled sibling CSS so the canvas is self-contained.\n(function(){if(typeof document==="undefined")return;if(document.getElementById(${JSON.stringify(id)}))return;var s=document.createElement("style");s.id=${JSON.stringify(id)};s.dataset.canvasCss="bundled";s.textContent=${enc};document.head.appendChild(s);})();\n`;
278
+ const id = JSON.stringify(`canvas-css-${slug.replace(/[^a-zA-Z0-9-]/g, '_')}`);
279
+ const src = JSON.stringify(sources.join('|'));
280
+ return `// canvas-build: inject bundled sibling CSS so the canvas is self-contained.\n(function(){if(typeof document==="undefined")return;var s=document.getElementById(${id});if(!s){s=document.createElement("style");s.id=${id};s.dataset.canvasCss="bundled";document.head.appendChild(s);}s.dataset.canvasCssSources=${src};if(s.textContent!==${enc})s.textContent=${enc};})();\n`;
240
281
  }
241
282
 
242
283
  /**