@1agh/maude 0.40.0 → 0.41.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 (73) hide show
  1. package/apps/studio/ai-banner.tsx +2 -2
  2. package/apps/studio/annotations-layer.tsx +53 -2
  3. package/apps/studio/api.ts +504 -3
  4. package/apps/studio/artboard-marquee.tsx +1 -1
  5. package/apps/studio/bin/_canvas-rects-playwright.mjs +55 -0
  6. package/apps/studio/bin/_canvas-rects-static.mjs +166 -0
  7. package/apps/studio/bin/_fetch-asset.mjs +556 -0
  8. package/apps/studio/bin/annotate.mjs +576 -34
  9. package/apps/studio/bin/canvas-rects.sh +152 -0
  10. package/apps/studio/bin/fetch-asset.sh +34 -0
  11. package/apps/studio/bin/read-annotations.mjs +138 -7
  12. package/apps/studio/bin/smoke.sh +42 -6
  13. package/apps/studio/build.ts +21 -0
  14. package/apps/studio/canvas-comment-mount.tsx +138 -4
  15. package/apps/studio/canvas-edit.ts +744 -11
  16. package/apps/studio/canvas-lib.tsx +219 -2
  17. package/apps/studio/canvas-shell.tsx +487 -20
  18. package/apps/studio/client/app.jsx +1451 -22
  19. package/apps/studio/client/comments-overlay.css +130 -126
  20. package/apps/studio/client/github.js +8 -0
  21. package/apps/studio/client/styles/3-shell-maude.css +48 -0
  22. package/apps/studio/comments-overlay.tsx +148 -41
  23. package/apps/studio/context-menu.tsx +15 -5
  24. package/apps/studio/contextual-toolbar.tsx +262 -4
  25. package/apps/studio/cursors-overlay.tsx +4 -4
  26. package/apps/studio/dist/client.bundle.js +20 -20
  27. package/apps/studio/dist/comment-mount.js +59 -1
  28. package/apps/studio/dist/styles.css +1 -1
  29. package/apps/studio/dom-selection.ts +127 -1
  30. package/apps/studio/drag-state.ts +24 -0
  31. package/apps/studio/equal-spacing-detector.ts +205 -0
  32. package/apps/studio/export-dialog.tsx +1 -1
  33. package/apps/studio/history.ts +47 -1
  34. package/apps/studio/http.ts +223 -0
  35. package/apps/studio/input-router.tsx +12 -0
  36. package/apps/studio/marquee-overlay.tsx +1 -1
  37. package/apps/studio/measure-overlay.tsx +241 -0
  38. package/apps/studio/participants-chrome.tsx +3 -3
  39. package/apps/studio/sizing-mode.ts +117 -0
  40. package/apps/studio/spacing-handles.ts +166 -0
  41. package/apps/studio/test/annotate-write.test.ts +890 -0
  42. package/apps/studio/test/camera-reveal.test.tsx +173 -0
  43. package/apps/studio/test/canvas-edit.test.ts +50 -0
  44. package/apps/studio/test/canvas-origin-gate.test.ts +18 -0
  45. package/apps/studio/test/canvas-rects.test.ts +198 -0
  46. package/apps/studio/test/comments-overlay.test.ts +117 -0
  47. package/apps/studio/test/dom-selection.test.ts +130 -0
  48. package/apps/studio/test/edit-css-occurrence.test.ts +81 -0
  49. package/apps/studio/test/edit-scope-api.test.ts +115 -0
  50. package/apps/studio/test/element-resize.test.ts +136 -0
  51. package/apps/studio/test/element-structural-api.test.ts +360 -0
  52. package/apps/studio/test/element-structural-edit.test.ts +233 -0
  53. package/apps/studio/test/equal-spacing-detector.test.ts +165 -1
  54. package/apps/studio/test/history-rollback.test.ts +26 -0
  55. package/apps/studio/test/knob-props-authored.test.ts +87 -0
  56. package/apps/studio/test/read-annotations.test.ts +154 -0
  57. package/apps/studio/test/sizing-mode.test.ts +102 -0
  58. package/apps/studio/test/spacing-handles.test.ts +138 -0
  59. package/apps/studio/test/specimen-select.test.ts +88 -0
  60. package/apps/studio/test/tool-palette-insert-anchor.test.ts +84 -0
  61. package/apps/studio/test/undo-sequence-byte-compare.test.ts +211 -0
  62. package/apps/studio/tool-palette.tsx +122 -2
  63. package/apps/studio/undo-hud.tsx +2 -2
  64. package/apps/studio/use-element-resize.tsx +732 -0
  65. package/apps/studio/use-keyboard-discipline.tsx +205 -15
  66. package/apps/studio/use-selection-set.tsx +14 -0
  67. package/apps/studio/use-spacing-handles.tsx +388 -0
  68. package/apps/studio/whats-new.json +28 -0
  69. package/cli/commands/design.mjs +6 -1
  70. package/cli/commands/design.test.mjs +49 -1
  71. package/cli/lib/fetch-asset.test.mjs +213 -0
  72. package/package.json +8 -8
  73. package/plugins/design/dependencies.json +10 -2
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ // _canvas-rects-static.mjs — offline, artboard-only fallback for the geometry
3
+ // manifest (feature-whiteboard-ai-toolkit). Used by canvas-rects.sh when no
4
+ // live dev server is reachable to drive a real render.
5
+ //
6
+ // Mirrors DesignCanvasInner's `initialArtboards()` merge (canvas-lib.tsx):
7
+ // JSX `width`/`height` props are size-authoritative (DDR-027); `.meta.json`
8
+ // `layout.artboards[]` only overrides x/y (a legacy entry that still carries
9
+ // w/h wins over the JSX default too — the same back-compat tolerance the
10
+ // client keeps for pre-4.2 files). Artboards are seeded in JSX render order
11
+ // (`harvestArtboards`), then laid out via the identical 3-col default-grid
12
+ // algorithm (`synthDefaultGrid`) when no stored position exists.
13
+ //
14
+ // No browser here, so there are NO element rects — `elements: []` with a
15
+ // stderr note. Regex-over-known-vocabulary (no AST parse), mirroring the
16
+ // discipline of read-annotations.mjs / sanitizeAnnotationSvg — this repo's
17
+ // house style for a headless reader of a small, fixed JSX vocabulary.
18
+ //
19
+ // Usage: _canvas-rects-static.mjs --rel <path-relative-to-designRoot> --root <repo>
20
+
21
+ import { existsSync, readFileSync } from 'node:fs';
22
+ import { resolve, sep } from 'node:path';
23
+ import { pathToFileURL } from 'node:url';
24
+ import { resolveDesignRoot } from './read-annotations.mjs';
25
+
26
+ // Mirrors VP_GRID in canvas-lib.tsx — kept literal here so this shim stays a
27
+ // standalone Node script (no bundler, no TS import).
28
+ const VP_GRID = { cols: 3, w: 1280, h: 820, gutter: 80 };
29
+
30
+ function parseArgv(argv) {
31
+ const out = { rel: null, root: null };
32
+ for (let i = 0; i < argv.length; i += 1) {
33
+ if (argv[i] === '--rel') out.rel = argv[i + 1];
34
+ else if (argv[i] === '--root') out.root = argv[i + 1];
35
+ }
36
+ return out;
37
+ }
38
+
39
+ function attr(tag, name) {
40
+ const strMatch = tag.match(new RegExp(`\\b${name}\\s*=\\s*"([^"]*)"`));
41
+ if (strMatch) return strMatch[1];
42
+ const exprMatch = tag.match(new RegExp(`\\b${name}\\s*=\\s*\\{\\s*(-?\\d+(?:\\.\\d+)?)\\s*\\}`));
43
+ return exprMatch ? exprMatch[1] : null;
44
+ }
45
+
46
+ /** Harvest `<DCArtboard id=".." width={N} height={N}>` in document order — the
47
+ * same render-order seeding `harvestArtboards()` does in canvas-lib.tsx. */
48
+ function harvestSeeds(source) {
49
+ const seeds = [];
50
+ const re = /<DCArtboard\b([^>]*)>/g;
51
+ let auto = 0;
52
+ let m = re.exec(source);
53
+ while (m !== null) {
54
+ const tag = m[1] ?? '';
55
+ const id = attr(tag, 'id') || `__ab_${auto}`;
56
+ const w = Number.parseFloat(attr(tag, 'width') ?? '') || VP_GRID.w;
57
+ const h = Number.parseFloat(attr(tag, 'height') ?? '') || VP_GRID.h;
58
+ seeds.push({ id, w, h });
59
+ auto += 1;
60
+ m = re.exec(source);
61
+ }
62
+ return seeds;
63
+ }
64
+
65
+ function synthDefaultGrid(seeds) {
66
+ if (seeds.length === 0) return [];
67
+ const cellW = seeds.reduce((mx, s) => Math.max(mx, s.w), 0) || VP_GRID.w;
68
+ const cellH = seeds.reduce((mx, s) => Math.max(mx, s.h), 0) || VP_GRID.h;
69
+ return seeds.map((seed, i) => {
70
+ const col = i % VP_GRID.cols;
71
+ const row = Math.floor(i / VP_GRID.cols);
72
+ return {
73
+ id: seed.id,
74
+ x: col * (cellW + VP_GRID.gutter),
75
+ y: row * (cellH + VP_GRID.gutter),
76
+ w: seed.w,
77
+ h: seed.h,
78
+ };
79
+ });
80
+ }
81
+
82
+ function loadMetaLayout(metaAbs) {
83
+ if (!existsSync(metaAbs)) return [];
84
+ try {
85
+ const meta = JSON.parse(readFileSync(metaAbs, 'utf8'));
86
+ const arr = meta?.layout?.artboards;
87
+ return Array.isArray(arr) ? arr : [];
88
+ } catch {
89
+ return [];
90
+ }
91
+ }
92
+
93
+ function emptyManifest() {
94
+ return { artboards: [], elements: [], elementsTruncated: false };
95
+ }
96
+
97
+ /**
98
+ * The core merge — JSX seeds (render order + authoritative w/h) laid out by
99
+ * the default grid, then x/y (or a legacy w/h) overridden per id from a
100
+ * `.meta.json` `layout.artboards[]` array. Pure + exported so
101
+ * `canvas-rects.test.ts` can assert it directly without touching disk.
102
+ */
103
+ function resolveArtboards(source, layout) {
104
+ const seeds = harvestSeeds(source);
105
+ const defaults = synthDefaultGrid(seeds);
106
+ const byId = new Map(
107
+ (Array.isArray(layout) ? layout : [])
108
+ .filter((r) => r && typeof r.id === 'string')
109
+ .map((r) => [r.id, r])
110
+ );
111
+ return defaults.map((d) => {
112
+ const m = byId.get(d.id);
113
+ if (!m) return d;
114
+ return {
115
+ id: d.id,
116
+ x: Number.isFinite(m.x) ? m.x : d.x,
117
+ y: Number.isFinite(m.y) ? m.y : d.y,
118
+ w: typeof m.w === 'number' && m.w > 0 ? m.w : d.w,
119
+ h: typeof m.h === 'number' && m.h > 0 ? m.h : d.h,
120
+ };
121
+ });
122
+ }
123
+
124
+ function main() {
125
+ const args = parseArgv(process.argv.slice(2));
126
+ if (!args.rel) {
127
+ process.stderr.write('canvas-rects (static): missing --rel\n');
128
+ process.exit(2);
129
+ }
130
+ const repoRoot = args.root ? args.root : process.cwd();
131
+ const { designRoot } = resolveDesignRoot(repoRoot);
132
+ // Security (feature-whiteboard-ai-toolkit review): --rel can carry an
133
+ // origin-checked-but-untrusted value forwarded from `_active.json` (the
134
+ // canvas can set its own `.active`, per inspect.ts's own containment note)
135
+ // — reject anything that resolves outside designRoot, mirroring inspect.ts's
136
+ // mtimeFor() containment check, before the file even reaches existsSync.
137
+ const designRootAbs = resolve(designRoot);
138
+ const canvasAbs = resolve(designRoot, args.rel);
139
+ if (canvasAbs !== designRootAbs && !canvasAbs.startsWith(designRootAbs + sep)) {
140
+ process.stderr.write(`canvas-rects (static): --rel escapes designRoot: ${args.rel}\n`);
141
+ process.stdout.write(`${JSON.stringify(emptyManifest())}\n`);
142
+ return;
143
+ }
144
+ if (!existsSync(canvasAbs)) {
145
+ process.stderr.write(`canvas-rects (static): canvas not found: ${canvasAbs}\n`);
146
+ process.stdout.write(`${JSON.stringify(emptyManifest())}\n`);
147
+ return;
148
+ }
149
+
150
+ const source = readFileSync(canvasAbs, 'utf8');
151
+ const metaAbs = canvasAbs.replace(/\.(tsx|html)$/i, '.meta.json');
152
+ const artboards = resolveArtboards(source, loadMetaLayout(metaAbs));
153
+
154
+ process.stderr.write(
155
+ 'canvas-rects (static): no live dev server — artboard positions/sizes only, elements: [] ' +
156
+ '(run `maude design server-up` first for element context)\n'
157
+ );
158
+ process.stdout.write(
159
+ `${JSON.stringify({ artboards, elements: [], elementsTruncated: false })}\n`
160
+ );
161
+ }
162
+
163
+ export { harvestSeeds, resolveArtboards, synthDefaultGrid };
164
+
165
+ const isMain = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
166
+ if (isMain) main();