@1agh/maude 0.39.1 → 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 (137) hide show
  1. package/README.md +1 -1
  2. package/apps/studio/ai-banner.tsx +2 -2
  3. package/apps/studio/annotations-context-toolbar.tsx +44 -1
  4. package/apps/studio/annotations-layer.tsx +306 -5
  5. package/apps/studio/annotations-model.ts +107 -6
  6. package/apps/studio/api.ts +1316 -67
  7. package/apps/studio/artboard-marquee.tsx +1 -1
  8. package/apps/studio/bin/_canvas-rects-playwright.mjs +55 -0
  9. package/apps/studio/bin/_canvas-rects-static.mjs +166 -0
  10. package/apps/studio/bin/_fetch-asset.mjs +556 -0
  11. package/apps/studio/bin/_html-playwright.mjs +9 -1
  12. package/apps/studio/bin/_pdf-playwright.mjs +8 -1
  13. package/apps/studio/bin/_png-playwright.mjs +8 -1
  14. package/apps/studio/bin/_pw-launch.mjs +54 -0
  15. package/apps/studio/bin/_svg-playwright.mjs +8 -1
  16. package/apps/studio/bin/_video-playwright.mjs +452 -0
  17. package/apps/studio/bin/annotate.mjs +576 -34
  18. package/apps/studio/bin/canvas-rects.sh +152 -0
  19. package/apps/studio/bin/fetch-asset.sh +34 -0
  20. package/apps/studio/bin/prep.sh +8 -1
  21. package/apps/studio/bin/read-annotations.mjs +138 -7
  22. package/apps/studio/bin/smoke.sh +42 -6
  23. package/apps/studio/build.ts +21 -0
  24. package/apps/studio/canvas-comment-mount.tsx +138 -4
  25. package/apps/studio/canvas-edit.ts +2625 -111
  26. package/apps/studio/canvas-lib.tsx +238 -2
  27. package/apps/studio/canvas-list-watch.ts +6 -2
  28. package/apps/studio/canvas-shell.tsx +514 -20
  29. package/apps/studio/client/app.jsx +2480 -52
  30. package/apps/studio/client/comments-overlay.css +130 -126
  31. package/apps/studio/client/github.js +15 -0
  32. package/apps/studio/client/panels/TimelinePanel.jsx +860 -0
  33. package/apps/studio/client/panels/timeline-parse.js +229 -0
  34. package/apps/studio/client/panels/timeline-snap.js +55 -0
  35. package/apps/studio/client/styles/3-shell-maude.css +155 -0
  36. package/apps/studio/comments-overlay.tsx +148 -41
  37. package/apps/studio/config.schema.json +14 -0
  38. package/apps/studio/context-menu.tsx +16 -6
  39. package/apps/studio/context.ts +113 -1
  40. package/apps/studio/contextual-toolbar.tsx +262 -4
  41. package/apps/studio/cursors-overlay.tsx +4 -4
  42. package/apps/studio/dist/client.bundle.js +89 -17
  43. package/apps/studio/dist/comment-mount.js +59 -1
  44. package/apps/studio/dist/runtime/.min-sizes.json +11 -1
  45. package/apps/studio/dist/runtime/@remotion_media.js +491 -0
  46. package/apps/studio/dist/runtime/@remotion_player.js +56 -0
  47. package/apps/studio/dist/runtime/@remotion_transitions.js +300 -0
  48. package/apps/studio/dist/runtime/@remotion_transitions_clock-wipe.js +1 -0
  49. package/apps/studio/dist/runtime/@remotion_transitions_fade.js +1 -0
  50. package/apps/studio/dist/runtime/@remotion_transitions_flip.js +1 -0
  51. package/apps/studio/dist/runtime/@remotion_transitions_none.js +1 -0
  52. package/apps/studio/dist/runtime/@remotion_transitions_slide.js +1 -0
  53. package/apps/studio/dist/runtime/@remotion_transitions_wipe.js +1 -0
  54. package/apps/studio/dist/runtime/REMOTION-LICENSE.md +28 -0
  55. package/apps/studio/dist/runtime/remotion.js +42 -0
  56. package/apps/studio/dist/styles.css +1 -1
  57. package/apps/studio/dom-selection.ts +127 -1
  58. package/apps/studio/drag-state.ts +24 -0
  59. package/apps/studio/equal-spacing-detector.ts +205 -0
  60. package/apps/studio/export-dialog.tsx +1 -1
  61. package/apps/studio/exporters/_browser-bundles.ts +117 -0
  62. package/apps/studio/exporters/_runtime.ts +69 -0
  63. package/apps/studio/exporters/html.ts +4 -3
  64. package/apps/studio/exporters/index.ts +28 -2
  65. package/apps/studio/exporters/pdf.ts +4 -3
  66. package/apps/studio/exporters/png.ts +5 -3
  67. package/apps/studio/exporters/pptx.ts +6 -4
  68. package/apps/studio/exporters/svg.ts +9 -5
  69. package/apps/studio/exporters/video-encode-lib.ts +200 -0
  70. package/apps/studio/exporters/video-render-lib.ts +108 -0
  71. package/apps/studio/exporters/video.ts +184 -0
  72. package/apps/studio/history.ts +47 -1
  73. package/apps/studio/http.ts +758 -27
  74. package/apps/studio/input-router.tsx +19 -1
  75. package/apps/studio/marquee-overlay.tsx +1 -1
  76. package/apps/studio/measure-overlay.tsx +241 -0
  77. package/apps/studio/participants-chrome.tsx +3 -3
  78. package/apps/studio/runtime-bundle.ts +30 -0
  79. package/apps/studio/server.ts +34 -9
  80. package/apps/studio/sizing-mode.ts +117 -0
  81. package/apps/studio/spacing-handles.ts +166 -0
  82. package/apps/studio/test/annotate-write.test.ts +890 -0
  83. package/apps/studio/test/annotations-roundtrip.test.ts +47 -0
  84. package/apps/studio/test/camera-reveal.test.tsx +173 -0
  85. package/apps/studio/test/canvas-create-api.test.ts +76 -0
  86. package/apps/studio/test/canvas-edit.test.ts +140 -0
  87. package/apps/studio/test/canvas-list-watch.test.ts +49 -0
  88. package/apps/studio/test/canvas-media-drop.test.ts +30 -1
  89. package/apps/studio/test/canvas-origin-gate.test.ts +54 -0
  90. package/apps/studio/test/canvas-rects.test.ts +198 -0
  91. package/apps/studio/test/clip-addressing.test.ts +732 -0
  92. package/apps/studio/test/comments-overlay.test.ts +117 -0
  93. package/apps/studio/test/config-reload.test.ts +230 -0
  94. package/apps/studio/test/dns-rebinding-guard.test.ts +74 -0
  95. package/apps/studio/test/dom-selection.test.ts +130 -0
  96. package/apps/studio/test/edit-css-occurrence.test.ts +81 -0
  97. package/apps/studio/test/edit-persistence.test.ts +91 -0
  98. package/apps/studio/test/edit-scope-api.test.ts +115 -0
  99. package/apps/studio/test/element-resize.test.ts +136 -0
  100. package/apps/studio/test/element-structural-api.test.ts +360 -0
  101. package/apps/studio/test/element-structural-edit.test.ts +233 -0
  102. package/apps/studio/test/equal-spacing-detector.test.ts +165 -1
  103. package/apps/studio/test/exporters/runtime.test.ts +59 -0
  104. package/apps/studio/test/file-lock.test.ts +84 -0
  105. package/apps/studio/test/fixtures/video-comp-fixture.tsx +82 -0
  106. package/apps/studio/test/history-rollback.test.ts +26 -0
  107. package/apps/studio/test/knob-props-authored.test.ts +87 -0
  108. package/apps/studio/test/read-annotations.test.ts +154 -0
  109. package/apps/studio/test/sizing-mode.test.ts +102 -0
  110. package/apps/studio/test/spacing-handles.test.ts +138 -0
  111. package/apps/studio/test/specimen-select.test.ts +88 -0
  112. package/apps/studio/test/timeline-parse.test.ts +127 -0
  113. package/apps/studio/test/timeline-snap.test.ts +85 -0
  114. package/apps/studio/test/tool-palette-insert-anchor.test.ts +84 -0
  115. package/apps/studio/test/undo-sequence-byte-compare.test.ts +211 -0
  116. package/apps/studio/test/video-asset.test.ts +163 -0
  117. package/apps/studio/test/video-comp-fixture.test.ts +50 -0
  118. package/apps/studio/test/video-comp.test.ts +168 -0
  119. package/apps/studio/test/video-render-bridge.test.ts +149 -0
  120. package/apps/studio/tool-palette.tsx +122 -2
  121. package/apps/studio/undo-hud.tsx +2 -2
  122. package/apps/studio/use-annotation-resize.tsx +6 -3
  123. package/apps/studio/use-canvas-media-drop.tsx +66 -4
  124. package/apps/studio/use-element-resize.tsx +732 -0
  125. package/apps/studio/use-keyboard-discipline.tsx +205 -15
  126. package/apps/studio/use-selection-set.tsx +14 -0
  127. package/apps/studio/use-spacing-handles.tsx +388 -0
  128. package/apps/studio/video-comp.tsx +444 -0
  129. package/apps/studio/whats-new.json +55 -0
  130. package/apps/studio/ws.ts +5 -0
  131. package/cli/commands/design.mjs +6 -1
  132. package/cli/commands/design.test.mjs +49 -1
  133. package/cli/lib/fetch-asset.test.mjs +213 -0
  134. package/package.json +8 -8
  135. package/plugins/design/dependencies.json +10 -2
  136. package/plugins/design/templates/_shell.html +25 -2
  137. package/plugins/design/templates/design-system-inspiration/_MAPPING.md +1 -1
@@ -0,0 +1,198 @@
1
+ // canvas-rects.test.ts — feature-whiteboard-ai-toolkit. Unit + fixture
2
+ // coverage for the STATIC (no-browser) fallback shim behind
3
+ // `maude design canvas-rects`. The LIVE lane (window.__maudeCanvasRects,
4
+ // canvas-lib.tsx) is verified via a real render (agent-browser), not here —
5
+ // this file covers the deterministic offline path: JSX seed harvesting, the
6
+ // default-grid layout, and the meta.json position merge, which together must
7
+ // mirror DesignCanvasInner's `initialArtboards()` (canvas-lib.tsx) exactly so
8
+ // the static fallback never disagrees with what the browser would compute.
9
+
10
+ import { describe, expect, test } from 'bun:test';
11
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
12
+ import { tmpdir } from 'node:os';
13
+ import { join } from 'node:path';
14
+
15
+ import { harvestSeeds, resolveArtboards, synthDefaultGrid } from '../bin/_canvas-rects-static.mjs';
16
+
17
+ describe('harvestSeeds', () => {
18
+ test('extracts id/width/height in document order', () => {
19
+ const source = `
20
+ <DCArtboard id="hero" label="Hero" width={1200} height={800}>x</DCArtboard>
21
+ <DCArtboard id="footer" label="Footer" width={1200} height={400}>y</DCArtboard>
22
+ `;
23
+ expect(harvestSeeds(source)).toEqual([
24
+ { id: 'hero', w: 1200, h: 800 },
25
+ { id: 'footer', w: 1200, h: 400 },
26
+ ]);
27
+ });
28
+
29
+ test('defaults width/height to VP_GRID (1280x820) when absent', () => {
30
+ const source = `<DCArtboard id="bare" label="Bare">x</DCArtboard>`;
31
+ expect(harvestSeeds(source)).toEqual([{ id: 'bare', w: 1280, h: 820 }]);
32
+ });
33
+
34
+ test('mints __ab_N when id is missing', () => {
35
+ const source = `<DCArtboard label="No id" width={100} height={100}>x</DCArtboard>`;
36
+ expect(harvestSeeds(source)).toEqual([{ id: '__ab_0', w: 100, h: 100 }]);
37
+ });
38
+
39
+ test('is robust to attribute order', () => {
40
+ const source = `<DCArtboard height={500} width={900} id="reordered">x</DCArtboard>`;
41
+ expect(harvestSeeds(source)).toEqual([{ id: 'reordered', w: 900, h: 500 }]);
42
+ });
43
+
44
+ test('empty source yields no seeds', () => {
45
+ expect(harvestSeeds('')).toEqual([]);
46
+ });
47
+ });
48
+
49
+ describe('synthDefaultGrid', () => {
50
+ test('mirrors canvas-lib.tsx VP_GRID (3 cols, 80px gutter, cell = max dims)', () => {
51
+ const seeds = [
52
+ { id: 'a', w: 1200, h: 800 },
53
+ { id: 'b', w: 1440, h: 900 }, // largest — sets the cell size
54
+ { id: 'c', w: 1200, h: 800 },
55
+ { id: 'd', w: 1200, h: 800 }, // wraps to row 1 (col 0)
56
+ ];
57
+ const rects = synthDefaultGrid(seeds);
58
+ expect(rects).toEqual([
59
+ { id: 'a', x: 0, y: 0, w: 1200, h: 800 },
60
+ { id: 'b', x: 1440 + 80, y: 0, w: 1440, h: 900 },
61
+ { id: 'c', x: (1440 + 80) * 2, y: 0, w: 1200, h: 800 },
62
+ { id: 'd', x: 0, y: 900 + 80, w: 1200, h: 800 },
63
+ ]);
64
+ });
65
+
66
+ test('empty seeds yields no rects', () => {
67
+ expect(synthDefaultGrid([])).toEqual([]);
68
+ });
69
+ });
70
+
71
+ describe('resolveArtboards', () => {
72
+ const source = `
73
+ <DCArtboard id="a" label="A" width={1200} height={800}>x</DCArtboard>
74
+ <DCArtboard id="b" label="B" width={1200} height={800}>y</DCArtboard>
75
+ `;
76
+
77
+ test('no meta layout — falls back to the default grid entirely', () => {
78
+ expect(resolveArtboards(source, [])).toEqual([
79
+ { id: 'a', x: 0, y: 0, w: 1200, h: 800 },
80
+ { id: 'b', x: 1280, w: 1200, h: 800, y: 0 },
81
+ ]);
82
+ });
83
+
84
+ test('meta layout overrides x/y but JSX width/height stays authoritative (DDR-027)', () => {
85
+ const layout = [{ id: 'a', x: 5000, y: 3000 }];
86
+ const out = resolveArtboards(source, layout);
87
+ expect(out[0]).toEqual({ id: 'a', x: 5000, y: 3000, w: 1200, h: 800 });
88
+ // 'b' has no matching layout entry — stays on the default grid.
89
+ expect(out[1]).toEqual({ id: 'b', x: 1280, y: 0, w: 1200, h: 800 });
90
+ });
91
+
92
+ test('a legacy meta w/h wins over the JSX default (back-compat tolerance)', () => {
93
+ const layout = [{ id: 'a', x: 10, y: 20, w: 999, h: 555 }];
94
+ expect(resolveArtboards(source, layout)[0]).toEqual({ id: 'a', x: 10, y: 20, w: 999, h: 555 });
95
+ });
96
+
97
+ test('non-finite / zero meta values fall back to the default', () => {
98
+ const layout = [{ id: 'a', x: Number.NaN, y: 20, w: 0, h: -5 }];
99
+ expect(resolveArtboards(source, layout)[0]).toEqual({ id: 'a', x: 0, y: 20, w: 1200, h: 800 });
100
+ });
101
+ });
102
+
103
+ describe('canvas-rects.sh static fallback (fixture, no browser)', () => {
104
+ test('emits a manifest matching the canvas fixture, elements always empty', () => {
105
+ const root = mkdtempSync(join(tmpdir(), 'maude-canvas-rects-fixture-'));
106
+ try {
107
+ mkdirSync(join(root, '.design', 'ui'), { recursive: true });
108
+ writeFileSync(
109
+ join(root, '.design', 'ui', 'Fixture.tsx'),
110
+ `export default function Fixture() {
111
+ return (
112
+ <DesignCanvas>
113
+ <DCArtboard id="one" label="One" width={1000} height={600} />
114
+ </DesignCanvas>
115
+ );
116
+ }
117
+ `
118
+ );
119
+ writeFileSync(
120
+ join(root, '.design', 'ui', 'Fixture.meta.json'),
121
+ JSON.stringify({ layout: { artboards: [{ id: 'one', x: 42, y: 7 }] } })
122
+ );
123
+
124
+ const proc = Bun.spawnSync([
125
+ 'node',
126
+ new URL('../bin/_canvas-rects-static.mjs', import.meta.url).pathname,
127
+ '--rel',
128
+ 'ui/Fixture.tsx',
129
+ '--root',
130
+ root,
131
+ ]);
132
+ const manifest = JSON.parse(proc.stdout.toString().trim());
133
+ expect(manifest).toEqual({
134
+ artboards: [{ id: 'one', x: 42, y: 7, w: 1000, h: 600 }],
135
+ elements: [],
136
+ elementsTruncated: false,
137
+ });
138
+ expect(proc.stderr.toString()).toMatch(/no live dev server/);
139
+ } finally {
140
+ rmSync(root, { recursive: true, force: true });
141
+ }
142
+ });
143
+
144
+ test('a missing canvas file emits an empty manifest, not an error', () => {
145
+ const root = mkdtempSync(join(tmpdir(), 'maude-canvas-rects-fixture-'));
146
+ try {
147
+ mkdirSync(join(root, '.design'), { recursive: true });
148
+ const proc = Bun.spawnSync([
149
+ 'node',
150
+ new URL('../bin/_canvas-rects-static.mjs', import.meta.url).pathname,
151
+ '--rel',
152
+ 'ui/Nope.tsx',
153
+ '--root',
154
+ root,
155
+ ]);
156
+ expect(JSON.parse(proc.stdout.toString().trim())).toEqual({
157
+ artboards: [],
158
+ elements: [],
159
+ elementsTruncated: false,
160
+ });
161
+ } finally {
162
+ rmSync(root, { recursive: true, force: true });
163
+ }
164
+ });
165
+
166
+ // Security regression (feature-whiteboard-ai-toolkit review, F-path-traversal):
167
+ // --rel used to be joined straight into designRoot with no containment
168
+ // check — a `../` value could read anything readable by the process,
169
+ // unlike the sibling read-annotations.mjs/annotate.mjs lookups (which
170
+ // route the same rel-path shape through fileSlug() flattening). --rel here
171
+ // must stay a real nested path (it locates the actual .tsx on disk), so
172
+ // the fix is a resolve()+startsWith() containment assert instead.
173
+ test('--rel that resolves outside designRoot is rejected, not read', () => {
174
+ const root = mkdtempSync(join(tmpdir(), 'maude-canvas-rects-traversal-'));
175
+ try {
176
+ mkdirSync(join(root, '.design', 'ui'), { recursive: true });
177
+ // A secret OUTSIDE .design that a traversal would try to reach.
178
+ writeFileSync(join(root, 'secret.tsx'), 'export default function Secret(){return null}');
179
+
180
+ const proc = Bun.spawnSync([
181
+ 'node',
182
+ new URL('../bin/_canvas-rects-static.mjs', import.meta.url).pathname,
183
+ '--rel',
184
+ '../secret.tsx',
185
+ '--root',
186
+ root,
187
+ ]);
188
+ expect(JSON.parse(proc.stdout.toString().trim())).toEqual({
189
+ artboards: [],
190
+ elements: [],
191
+ elementsTruncated: false,
192
+ });
193
+ expect(proc.stderr.toString()).toMatch(/escapes designRoot/);
194
+ } finally {
195
+ rmSync(root, { recursive: true, force: true });
196
+ }
197
+ });
198
+ });