@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.
- package/README.md +1 -1
- package/apps/studio/ai-banner.tsx +2 -2
- package/apps/studio/annotations-context-toolbar.tsx +44 -1
- package/apps/studio/annotations-layer.tsx +306 -5
- package/apps/studio/annotations-model.ts +107 -6
- package/apps/studio/api.ts +1316 -67
- package/apps/studio/artboard-marquee.tsx +1 -1
- package/apps/studio/bin/_canvas-rects-playwright.mjs +55 -0
- package/apps/studio/bin/_canvas-rects-static.mjs +166 -0
- package/apps/studio/bin/_fetch-asset.mjs +556 -0
- package/apps/studio/bin/_html-playwright.mjs +9 -1
- package/apps/studio/bin/_pdf-playwright.mjs +8 -1
- package/apps/studio/bin/_png-playwright.mjs +8 -1
- package/apps/studio/bin/_pw-launch.mjs +54 -0
- package/apps/studio/bin/_svg-playwright.mjs +8 -1
- package/apps/studio/bin/_video-playwright.mjs +452 -0
- package/apps/studio/bin/annotate.mjs +576 -34
- package/apps/studio/bin/canvas-rects.sh +152 -0
- package/apps/studio/bin/fetch-asset.sh +34 -0
- package/apps/studio/bin/prep.sh +8 -1
- package/apps/studio/bin/read-annotations.mjs +138 -7
- package/apps/studio/bin/smoke.sh +42 -6
- package/apps/studio/build.ts +21 -0
- package/apps/studio/canvas-comment-mount.tsx +138 -4
- package/apps/studio/canvas-edit.ts +2625 -111
- package/apps/studio/canvas-lib.tsx +238 -2
- package/apps/studio/canvas-list-watch.ts +6 -2
- package/apps/studio/canvas-shell.tsx +514 -20
- package/apps/studio/client/app.jsx +2480 -52
- package/apps/studio/client/comments-overlay.css +130 -126
- package/apps/studio/client/github.js +15 -0
- package/apps/studio/client/panels/TimelinePanel.jsx +860 -0
- package/apps/studio/client/panels/timeline-parse.js +229 -0
- package/apps/studio/client/panels/timeline-snap.js +55 -0
- package/apps/studio/client/styles/3-shell-maude.css +155 -0
- package/apps/studio/comments-overlay.tsx +148 -41
- package/apps/studio/config.schema.json +14 -0
- package/apps/studio/context-menu.tsx +16 -6
- package/apps/studio/context.ts +113 -1
- package/apps/studio/contextual-toolbar.tsx +262 -4
- package/apps/studio/cursors-overlay.tsx +4 -4
- package/apps/studio/dist/client.bundle.js +89 -17
- package/apps/studio/dist/comment-mount.js +59 -1
- package/apps/studio/dist/runtime/.min-sizes.json +11 -1
- package/apps/studio/dist/runtime/@remotion_media.js +491 -0
- package/apps/studio/dist/runtime/@remotion_player.js +56 -0
- package/apps/studio/dist/runtime/@remotion_transitions.js +300 -0
- package/apps/studio/dist/runtime/@remotion_transitions_clock-wipe.js +1 -0
- package/apps/studio/dist/runtime/@remotion_transitions_fade.js +1 -0
- package/apps/studio/dist/runtime/@remotion_transitions_flip.js +1 -0
- package/apps/studio/dist/runtime/@remotion_transitions_none.js +1 -0
- package/apps/studio/dist/runtime/@remotion_transitions_slide.js +1 -0
- package/apps/studio/dist/runtime/@remotion_transitions_wipe.js +1 -0
- package/apps/studio/dist/runtime/REMOTION-LICENSE.md +28 -0
- package/apps/studio/dist/runtime/remotion.js +42 -0
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/dom-selection.ts +127 -1
- package/apps/studio/drag-state.ts +24 -0
- package/apps/studio/equal-spacing-detector.ts +205 -0
- package/apps/studio/export-dialog.tsx +1 -1
- package/apps/studio/exporters/_browser-bundles.ts +117 -0
- package/apps/studio/exporters/_runtime.ts +69 -0
- package/apps/studio/exporters/html.ts +4 -3
- package/apps/studio/exporters/index.ts +28 -2
- package/apps/studio/exporters/pdf.ts +4 -3
- package/apps/studio/exporters/png.ts +5 -3
- package/apps/studio/exporters/pptx.ts +6 -4
- package/apps/studio/exporters/svg.ts +9 -5
- package/apps/studio/exporters/video-encode-lib.ts +200 -0
- package/apps/studio/exporters/video-render-lib.ts +108 -0
- package/apps/studio/exporters/video.ts +184 -0
- package/apps/studio/history.ts +47 -1
- package/apps/studio/http.ts +758 -27
- package/apps/studio/input-router.tsx +19 -1
- package/apps/studio/marquee-overlay.tsx +1 -1
- package/apps/studio/measure-overlay.tsx +241 -0
- package/apps/studio/participants-chrome.tsx +3 -3
- package/apps/studio/runtime-bundle.ts +30 -0
- package/apps/studio/server.ts +34 -9
- package/apps/studio/sizing-mode.ts +117 -0
- package/apps/studio/spacing-handles.ts +166 -0
- package/apps/studio/test/annotate-write.test.ts +890 -0
- package/apps/studio/test/annotations-roundtrip.test.ts +47 -0
- package/apps/studio/test/camera-reveal.test.tsx +173 -0
- package/apps/studio/test/canvas-create-api.test.ts +76 -0
- package/apps/studio/test/canvas-edit.test.ts +140 -0
- package/apps/studio/test/canvas-list-watch.test.ts +49 -0
- package/apps/studio/test/canvas-media-drop.test.ts +30 -1
- package/apps/studio/test/canvas-origin-gate.test.ts +54 -0
- package/apps/studio/test/canvas-rects.test.ts +198 -0
- package/apps/studio/test/clip-addressing.test.ts +732 -0
- package/apps/studio/test/comments-overlay.test.ts +117 -0
- package/apps/studio/test/config-reload.test.ts +230 -0
- package/apps/studio/test/dns-rebinding-guard.test.ts +74 -0
- package/apps/studio/test/dom-selection.test.ts +130 -0
- package/apps/studio/test/edit-css-occurrence.test.ts +81 -0
- package/apps/studio/test/edit-persistence.test.ts +91 -0
- package/apps/studio/test/edit-scope-api.test.ts +115 -0
- package/apps/studio/test/element-resize.test.ts +136 -0
- package/apps/studio/test/element-structural-api.test.ts +360 -0
- package/apps/studio/test/element-structural-edit.test.ts +233 -0
- package/apps/studio/test/equal-spacing-detector.test.ts +165 -1
- package/apps/studio/test/exporters/runtime.test.ts +59 -0
- package/apps/studio/test/file-lock.test.ts +84 -0
- package/apps/studio/test/fixtures/video-comp-fixture.tsx +82 -0
- package/apps/studio/test/history-rollback.test.ts +26 -0
- package/apps/studio/test/knob-props-authored.test.ts +87 -0
- package/apps/studio/test/read-annotations.test.ts +154 -0
- package/apps/studio/test/sizing-mode.test.ts +102 -0
- package/apps/studio/test/spacing-handles.test.ts +138 -0
- package/apps/studio/test/specimen-select.test.ts +88 -0
- package/apps/studio/test/timeline-parse.test.ts +127 -0
- package/apps/studio/test/timeline-snap.test.ts +85 -0
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +84 -0
- package/apps/studio/test/undo-sequence-byte-compare.test.ts +211 -0
- package/apps/studio/test/video-asset.test.ts +163 -0
- package/apps/studio/test/video-comp-fixture.test.ts +50 -0
- package/apps/studio/test/video-comp.test.ts +168 -0
- package/apps/studio/test/video-render-bridge.test.ts +149 -0
- package/apps/studio/tool-palette.tsx +122 -2
- package/apps/studio/undo-hud.tsx +2 -2
- package/apps/studio/use-annotation-resize.tsx +6 -3
- package/apps/studio/use-canvas-media-drop.tsx +66 -4
- package/apps/studio/use-element-resize.tsx +732 -0
- package/apps/studio/use-keyboard-discipline.tsx +205 -15
- package/apps/studio/use-selection-set.tsx +14 -0
- package/apps/studio/use-spacing-handles.tsx +388 -0
- package/apps/studio/video-comp.tsx +444 -0
- package/apps/studio/whats-new.json +55 -0
- package/apps/studio/ws.ts +5 -0
- package/cli/commands/design.mjs +6 -1
- package/cli/commands/design.test.mjs +49 -1
- package/cli/lib/fetch-asset.test.mjs +213 -0
- package/package.json +8 -8
- package/plugins/design/dependencies.json +10 -2
- package/plugins/design/templates/_shell.html +25 -2
- package/plugins/design/templates/design-system-inspiration/_MAPPING.md +1 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
// DDR-147 § Security follow-up item 1 — the hardened `maude design fetch-asset`
|
|
2
|
+
// helper (apps/studio/bin/_fetch-asset.mjs). This suite locks the SECURITY CORE
|
|
3
|
+
// that the untrusted-fetch rails promise: the resolved-IP SSRF classifier
|
|
4
|
+
// (reject loopback / link-local / RFC-1918 / CGNAT / multicast / reserved, v4 +
|
|
5
|
+
// v6 incl. IPv4-mapped + NAT64), https-only URL parsing, the png/jpg/gif/webp
|
|
6
|
+
// magic sniff (SVG/HTML rejected), the content-addressed name contract, and the
|
|
7
|
+
// realpath containment assertion. Runs under `pnpm test` (node --test cli/**).
|
|
8
|
+
//
|
|
9
|
+
// The network path (curl) is exercised by the manual smoke in the RCA/PR; these
|
|
10
|
+
// are the offline, deterministic guards a regression would trip.
|
|
11
|
+
|
|
12
|
+
import assert from 'node:assert/strict';
|
|
13
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
14
|
+
import { dirname, resolve } from 'node:path';
|
|
15
|
+
import { test } from 'node:test';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
|
|
18
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const REPO = resolve(HERE, '..', '..');
|
|
20
|
+
const MOD = resolve(REPO, 'apps', 'studio', 'bin', '_fetch-asset.mjs');
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
classifyAddress,
|
|
24
|
+
parseIPv4,
|
|
25
|
+
parseIPv6,
|
|
26
|
+
parseHttpsTarget,
|
|
27
|
+
sniffImageExt,
|
|
28
|
+
assetName,
|
|
29
|
+
containedAssetPath,
|
|
30
|
+
FetchAssetError,
|
|
31
|
+
} = await import(MOD);
|
|
32
|
+
|
|
33
|
+
// ── SSRF classifier: BLOCKED addresses ───────────────────────────────────────
|
|
34
|
+
test('classifyAddress blocks private / loopback / link-local / reserved IPv4', () => {
|
|
35
|
+
const blocked = [
|
|
36
|
+
'127.0.0.1',
|
|
37
|
+
'127.9.9.9',
|
|
38
|
+
'10.0.0.1',
|
|
39
|
+
'10.255.255.255',
|
|
40
|
+
'172.16.0.1',
|
|
41
|
+
'172.31.255.255',
|
|
42
|
+
'192.168.1.1',
|
|
43
|
+
'169.254.169.254', // AWS/GCP IMDS
|
|
44
|
+
'169.254.0.1',
|
|
45
|
+
'100.64.0.1', // CGNAT
|
|
46
|
+
'100.127.255.255',
|
|
47
|
+
'0.0.0.0',
|
|
48
|
+
'224.0.0.1', // multicast
|
|
49
|
+
'239.255.255.255',
|
|
50
|
+
'240.0.0.1', // reserved
|
|
51
|
+
'255.255.255.255',
|
|
52
|
+
'198.18.0.1', // benchmark
|
|
53
|
+
'192.0.2.5', // TEST-NET-1
|
|
54
|
+
'192.0.0.1', // IETF
|
|
55
|
+
];
|
|
56
|
+
for (const ip of blocked) {
|
|
57
|
+
assert.ok(classifyAddress(ip), `expected ${ip} to be BLOCKED but it was allowed`);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('classifyAddress allows genuine public IPv4 (incl. just-outside-range boundaries)', () => {
|
|
62
|
+
const allowed = [
|
|
63
|
+
'8.8.8.8',
|
|
64
|
+
'1.1.1.1',
|
|
65
|
+
'93.184.216.34', // example.com
|
|
66
|
+
'172.15.255.255', // just below 172.16/12
|
|
67
|
+
'172.32.0.1', // just above 172.31
|
|
68
|
+
'100.63.255.255', // just below CGNAT
|
|
69
|
+
'100.128.0.1', // just above CGNAT
|
|
70
|
+
'169.253.255.255', // just below link-local
|
|
71
|
+
'11.0.0.1',
|
|
72
|
+
'192.167.255.255',
|
|
73
|
+
'192.169.0.1',
|
|
74
|
+
'223.255.255.255', // just below multicast
|
|
75
|
+
];
|
|
76
|
+
for (const ip of allowed) {
|
|
77
|
+
assert.equal(classifyAddress(ip), null, `expected ${ip} to be ALLOWED but it was blocked`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('classifyAddress blocks loopback / link-local / ULA / multicast + embedded-v4 IPv6', () => {
|
|
82
|
+
const blocked = [
|
|
83
|
+
'::1', // loopback
|
|
84
|
+
'::', // unspecified
|
|
85
|
+
'fe80::1', // link-local
|
|
86
|
+
'fe80::abcd:1234',
|
|
87
|
+
'fc00::1', // ULA
|
|
88
|
+
'fd12:3456::1', // ULA
|
|
89
|
+
'ff02::1', // multicast
|
|
90
|
+
'::ffff:127.0.0.1', // IPv4-mapped loopback
|
|
91
|
+
'::ffff:10.0.0.1', // IPv4-mapped private
|
|
92
|
+
'::ffff:169.254.169.254', // IPv4-mapped IMDS
|
|
93
|
+
'64:ff9b::127.0.0.1', // NAT64 → loopback
|
|
94
|
+
'64:ff9b::192.168.0.1', // NAT64 → private
|
|
95
|
+
];
|
|
96
|
+
for (const ip of blocked) {
|
|
97
|
+
assert.ok(classifyAddress(ip), `expected ${ip} to be BLOCKED but it was allowed`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('classifyAddress allows genuine public IPv6 (incl. IPv4-mapped public)', () => {
|
|
102
|
+
const allowed = [
|
|
103
|
+
'2001:4860:4860::8888', // Google DNS
|
|
104
|
+
'2606:4700:4700::1111', // Cloudflare DNS
|
|
105
|
+
'::ffff:8.8.8.8', // IPv4-mapped PUBLIC → allowed via embedded classify
|
|
106
|
+
'2a00:1450:4001:81b::200e',
|
|
107
|
+
];
|
|
108
|
+
for (const ip of allowed) {
|
|
109
|
+
assert.equal(classifyAddress(ip), null, `expected ${ip} to be ALLOWED but it was blocked`);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('classifyAddress fail-closes on non-IP / garbage input', () => {
|
|
114
|
+
for (const bad of ['not-an-ip', 'example.com', '', '999.999.999.999', 'gggg::1']) {
|
|
115
|
+
assert.ok(classifyAddress(bad), `expected ${JSON.stringify(bad)} to be treated as blocked`);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// ── IP parsers ───────────────────────────────────────────────────────────────
|
|
120
|
+
test('parseIPv4 rejects malformed dotted-quads', () => {
|
|
121
|
+
for (const bad of ['1.2.3', '1.2.3.4.5', '256.1.1.1', '01.2.3.4', '1.2.3.a', '', '-1.2.3.4']) {
|
|
122
|
+
assert.equal(parseIPv4(bad), null, `expected ${JSON.stringify(bad)} to fail parse`);
|
|
123
|
+
}
|
|
124
|
+
assert.deepEqual([...parseIPv4('1.2.3.4')], [1, 2, 3, 4]);
|
|
125
|
+
assert.deepEqual([...parseIPv4('255.255.255.255')], [255, 255, 255, 255]);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test('parseIPv6 handles ::, embedded IPv4, zone id; rejects malformed', () => {
|
|
129
|
+
assert.ok(parseIPv6('::1'));
|
|
130
|
+
assert.ok(parseIPv6('::'));
|
|
131
|
+
assert.ok(parseIPv6('fe80::1%en0')); // zone id stripped
|
|
132
|
+
assert.ok(parseIPv6('2001:db8::1'));
|
|
133
|
+
assert.ok(parseIPv6('::ffff:1.2.3.4'));
|
|
134
|
+
for (const bad of ['gggg::', '1::2::3', '12345::', '1.2.3.4', '']) {
|
|
135
|
+
assert.equal(parseIPv6(bad), null, `expected ${JSON.stringify(bad)} to fail parse`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// ── URL target ───────────────────────────────────────────────────────────────
|
|
140
|
+
test('parseHttpsTarget accepts https and extracts host/port', () => {
|
|
141
|
+
assert.deepEqual(parseHttpsTarget('https://example.com/a.png'), {
|
|
142
|
+
host: 'example.com',
|
|
143
|
+
port: 443,
|
|
144
|
+
});
|
|
145
|
+
assert.deepEqual(parseHttpsTarget('https://cdn.example.com:8443/x'), {
|
|
146
|
+
host: 'cdn.example.com',
|
|
147
|
+
port: 8443,
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('parseHttpsTarget rejects non-https, credentials, and hostless URLs', () => {
|
|
152
|
+
const bad = [
|
|
153
|
+
'http://example.com/a.png',
|
|
154
|
+
'ftp://example.com/a.png',
|
|
155
|
+
'file:///etc/passwd',
|
|
156
|
+
'https://user:pass@example.com/a.png',
|
|
157
|
+
'not a url',
|
|
158
|
+
];
|
|
159
|
+
for (const u of bad) {
|
|
160
|
+
assert.throws(() => parseHttpsTarget(u), FetchAssetError, `expected ${u} to throw`);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// ── image sniff ──────────────────────────────────────────────────────────────
|
|
165
|
+
test('sniffImageExt recognises png/jpg/gif/webp and rejects SVG/HTML/empty', () => {
|
|
166
|
+
const png = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0, 0]);
|
|
167
|
+
const jpg = Buffer.from([0xff, 0xd8, 0xff, 0xe0, 0, 0]);
|
|
168
|
+
const gif = Buffer.from([0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0, 0]);
|
|
169
|
+
const webp = Buffer.from([0x52, 0x49, 0x46, 0x46, 0, 0, 0, 0, 0x57, 0x45, 0x42, 0x50]);
|
|
170
|
+
assert.equal(sniffImageExt(png), 'png');
|
|
171
|
+
assert.equal(sniffImageExt(jpg), 'jpg');
|
|
172
|
+
assert.equal(sniffImageExt(gif), 'gif');
|
|
173
|
+
assert.equal(sniffImageExt(webp), 'webp');
|
|
174
|
+
assert.equal(sniffImageExt(Buffer.from('<svg xmlns="...')), null);
|
|
175
|
+
assert.equal(sniffImageExt(Buffer.from('<!DOCTYPE html>')), null);
|
|
176
|
+
assert.equal(sniffImageExt(Buffer.from([])), null);
|
|
177
|
+
// RIFF that is NOT webp (e.g. wav) must not sniff as an image.
|
|
178
|
+
assert.equal(
|
|
179
|
+
sniffImageExt(Buffer.from([0x52, 0x49, 0x46, 0x46, 0, 0, 0, 0, 0x57, 0x41, 0x56, 0x45])),
|
|
180
|
+
null
|
|
181
|
+
);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// ── naming + containment ─────────────────────────────────────────────────────
|
|
185
|
+
test('assetName is content-addressed <sha8>.<ext> and deterministic', () => {
|
|
186
|
+
const bytes = Buffer.from('hello world');
|
|
187
|
+
const n1 = assetName(bytes, 'png');
|
|
188
|
+
const n2 = assetName(bytes, 'png');
|
|
189
|
+
assert.equal(n1, n2);
|
|
190
|
+
assert.match(n1, /^[a-f0-9]{8}\.png$/);
|
|
191
|
+
assert.notEqual(assetName(Buffer.from('other'), 'jpg'), n1);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('containedAssetPath resolves under <root>/<designRoot>/assets and rejects escape', () => {
|
|
195
|
+
const { assetsDir, fileAbs } = containedAssetPath('/repo', '.design', 'a1b2c3d4.png');
|
|
196
|
+
assert.equal(assetsDir, resolve('/repo/.design/assets'));
|
|
197
|
+
assert.equal(fileAbs, resolve('/repo/.design/assets/a1b2c3d4.png'));
|
|
198
|
+
// A traversal name escapes → throws.
|
|
199
|
+
assert.throws(() => containedAssetPath('/repo', '.design', '../../etc/passwd'), FetchAssetError);
|
|
200
|
+
// A design-root that climbs out of the repo → throws.
|
|
201
|
+
assert.throws(() => containedAssetPath('/repo', '../../etc', 'a1b2c3d4.png'), FetchAssetError);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
// ── wiring: verb registered + helper files ship ──────────────────────────────
|
|
205
|
+
test('fetch-asset is a registered `maude design` bin verb with both helper files present', () => {
|
|
206
|
+
assert.ok(existsSync(resolve(REPO, 'apps/studio/bin/fetch-asset.sh')), 'fetch-asset.sh missing');
|
|
207
|
+
assert.ok(
|
|
208
|
+
existsSync(resolve(REPO, 'apps/studio/bin/_fetch-asset.mjs')),
|
|
209
|
+
'_fetch-asset.mjs missing'
|
|
210
|
+
);
|
|
211
|
+
const design = readFileSync(resolve(REPO, 'cli/commands/design.mjs'), 'utf8');
|
|
212
|
+
assert.match(design, /'fetch-asset'/, "'fetch-asset' not in design.mjs BIN_VERBS");
|
|
213
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1agh/maude",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.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": {
|
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
"test:e2e:desktop:onboarding": "pnpm --filter @maude/desktop-e2e e2e:onboarding"
|
|
51
51
|
},
|
|
52
52
|
"optionalDependencies": {
|
|
53
|
-
"@1agh/maude-darwin-arm64": "0.
|
|
54
|
-
"@1agh/maude-darwin-x64": "0.
|
|
55
|
-
"@1agh/maude-linux-arm64": "0.
|
|
56
|
-
"@1agh/maude-linux-arm64-musl": "0.
|
|
57
|
-
"@1agh/maude-linux-x64": "0.
|
|
58
|
-
"@1agh/maude-linux-x64-musl": "0.
|
|
59
|
-
"@1agh/maude-win32-x64": "0.
|
|
53
|
+
"@1agh/maude-darwin-arm64": "0.41.0",
|
|
54
|
+
"@1agh/maude-darwin-x64": "0.41.0",
|
|
55
|
+
"@1agh/maude-linux-arm64": "0.41.0",
|
|
56
|
+
"@1agh/maude-linux-arm64-musl": "0.41.0",
|
|
57
|
+
"@1agh/maude-linux-x64": "0.41.0",
|
|
58
|
+
"@1agh/maude-linux-x64-musl": "0.41.0",
|
|
59
|
+
"@1agh/maude-win32-x64": "0.41.0"
|
|
60
60
|
},
|
|
61
61
|
"files": [
|
|
62
62
|
"cli",
|
|
@@ -74,8 +74,10 @@
|
|
|
74
74
|
"commands/new.md",
|
|
75
75
|
"commands/edit.md",
|
|
76
76
|
"commands/smoke.md",
|
|
77
|
+
"commands/board.md",
|
|
77
78
|
"dev-server/bin/screenshot.sh",
|
|
78
79
|
"dev-server/bin/smoke.sh",
|
|
80
|
+
"dev-server/bin/canvas-rects.sh",
|
|
79
81
|
"agents/design-critic.md",
|
|
80
82
|
"agents/graphic-design-critic.md",
|
|
81
83
|
"agents/a11y-critic.md"
|
|
@@ -104,7 +106,9 @@
|
|
|
104
106
|
"dev-server/bin/_html-playwright.mjs",
|
|
105
107
|
"dev-server/bin/_pptx-playwright.mjs",
|
|
106
108
|
"dev-server/bin/_enumerate-artboards-playwright.mjs",
|
|
107
|
-
"dev-server/bin/screenshot.sh"
|
|
109
|
+
"dev-server/bin/screenshot.sh",
|
|
110
|
+
"dev-server/bin/_canvas-rects-playwright.mjs",
|
|
111
|
+
"dev-server/bin/canvas-rects.sh"
|
|
108
112
|
],
|
|
109
113
|
"docsUrl": "https://playwright.dev"
|
|
110
114
|
},
|
|
@@ -157,7 +161,11 @@
|
|
|
157
161
|
},
|
|
158
162
|
"autoInstall": false,
|
|
159
163
|
"fallbackBehavior": "Slash commands' bash blocks that read .ai/workflows.config.json via jq degrade to inline node one-liners; harder to read but functional.",
|
|
160
|
-
"usedBy": [
|
|
164
|
+
"usedBy": [
|
|
165
|
+
"dev-server/bin/bootstrap-check.sh",
|
|
166
|
+
"dev-server/bin/server-up.sh",
|
|
167
|
+
"dev-server/bin/canvas-rects.sh"
|
|
168
|
+
]
|
|
161
169
|
},
|
|
162
170
|
{
|
|
163
171
|
"id": "askuserquestion-mcp",
|
|
@@ -141,7 +141,17 @@
|
|
|
141
141
|
"y-protocols/sync": "/_canvas-runtime/y-protocols_sync.js",
|
|
142
142
|
"y-protocols/awareness": "/_canvas-runtime/y-protocols_awareness.js",
|
|
143
143
|
"lib0/decoding": "/_canvas-runtime/lib0_decoding.js",
|
|
144
|
-
"lib0/encoding": "/_canvas-runtime/lib0_encoding.js"
|
|
144
|
+
"lib0/encoding": "/_canvas-runtime/lib0_encoding.js",
|
|
145
|
+
"remotion": "/_canvas-runtime/remotion.js",
|
|
146
|
+
"@remotion/media": "/_canvas-runtime/@remotion_media.js",
|
|
147
|
+
"@remotion/player": "/_canvas-runtime/@remotion_player.js",
|
|
148
|
+
"@remotion/transitions": "/_canvas-runtime/@remotion_transitions.js",
|
|
149
|
+
"@remotion/transitions/fade": "/_canvas-runtime/@remotion_transitions_fade.js",
|
|
150
|
+
"@remotion/transitions/slide": "/_canvas-runtime/@remotion_transitions_slide.js",
|
|
151
|
+
"@remotion/transitions/wipe": "/_canvas-runtime/@remotion_transitions_wipe.js",
|
|
152
|
+
"@remotion/transitions/flip": "/_canvas-runtime/@remotion_transitions_flip.js",
|
|
153
|
+
"@remotion/transitions/clock-wipe": "/_canvas-runtime/@remotion_transitions_clock-wipe.js",
|
|
154
|
+
"@remotion/transitions/none": "/_canvas-runtime/@remotion_transitions_none.js"
|
|
145
155
|
}
|
|
146
156
|
}
|
|
147
157
|
</script>
|
|
@@ -350,7 +360,20 @@
|
|
|
350
360
|
// skipped. Mirrors the meta echo-guard below.
|
|
351
361
|
if (msg.mode === 'module') {
|
|
352
362
|
// read the parent-verified local (NOT a canvas-writable global)
|
|
353
|
-
|
|
363
|
+
//
|
|
364
|
+
// VIDEO-COMP EXCEPTION (DDR-150 dogfood): on a canvas with a
|
|
365
|
+
// mounted Remotion comp the optimistic DOM style CANNOT hold —
|
|
366
|
+
// the Player re-renders styles from the (old) module on every
|
|
367
|
+
// frame, wiping the edit at the next play-through. Skipping the
|
|
368
|
+
// module reload here left the OLD color playing until a manual
|
|
369
|
+
// Cmd+R even though the new value was on disk. So: skip the
|
|
370
|
+
// redundant reload only on comp-less canvases. (Reading the
|
|
371
|
+
// comp registry off `window` is canvas-influenced, but a canvas
|
|
372
|
+
// lying "I have comps" can only FORCE a reload — the safe
|
|
373
|
+
// direction; it can never suppress one.)
|
|
374
|
+
var hasComps = false;
|
|
375
|
+
try { hasComps = !!(window.__maude_comps__ && window.__maude_comps__().length); } catch (err) { hasComps = false; }
|
|
376
|
+
if (!hasComps && Date.now() - lastCssOptimisticAt < 1500) return;
|
|
354
377
|
}
|
|
355
378
|
// Phase 30 (F4) — prefer an in-place hot-swap for ANY canvas-body
|
|
356
379
|
// (`module`) change whenever the canvas runtime is mounted: the
|
|
@@ -170,7 +170,7 @@ The agent may also propose treatments outside this catalog — when it does, it
|
|
|
170
170
|
| `expressive` | `paired \| chromatic-3` | accent-tinted, gradients OK | `gradient-mesh`, `chromatic-blocks`, `frosted-blur` | `aesthetic` |
|
|
171
171
|
| `maximalist` | `chromatic-N` | bold, colour-as-structure | `chromatic-blocks`, `gradient-mesh`, `body-pattern` | `full` |
|
|
172
172
|
|
|
173
|
-
**Anti-funnel invariant:** absence of a clear brand-character signal does NOT mean `restrained` — it means low confidence, so Stage
|
|
173
|
+
**Anti-funnel invariant:** absence of a clear brand-character signal does NOT mean `restrained` — it means low confidence, so the flow surfaces the full scale to the user (on the multi-tile path the Stage-3 direction pick shows the ambition poles rendered; on the degraded-to-1 path the Stage-4 refinement ASKS across the full scale, incl. a multi-colour palette option — DDR-147). High-confidence skip is legitimate only when the character is unambiguous, at **both** ends of the scale. Q10 hard-NOs still override (e.g. "no gradients" disables `gradient-mesh`).
|
|
174
174
|
|
|
175
175
|
### Q10 hard NOs — sub-agent guardrails
|
|
176
176
|
|