@1agh/maude 0.45.1 → 0.46.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 (91) hide show
  1. package/apps/studio/acp/bridge.ts +628 -74
  2. package/apps/studio/acp/index.ts +172 -23
  3. package/apps/studio/acp/probe.ts +31 -7
  4. package/apps/studio/acp/transcript.ts +91 -5
  5. package/apps/studio/annotations-snap.ts +50 -10
  6. package/apps/studio/api.ts +344 -14
  7. package/apps/studio/artboard-guides-overlay.tsx +270 -0
  8. package/apps/studio/bin/_import-asset.mjs +35 -5
  9. package/apps/studio/bin/_pdf-playwright.mjs +35 -4
  10. package/apps/studio/bin/_png-playwright.mjs +38 -4
  11. package/apps/studio/bin/_pw-launch.mjs +52 -0
  12. package/apps/studio/bin/_pw-launch.test.mjs +90 -0
  13. package/apps/studio/bin/_smart-frames.mjs +419 -0
  14. package/apps/studio/bin/_smart-frames.test.mjs +140 -0
  15. package/apps/studio/bin/smart-frames.sh +30 -0
  16. package/apps/studio/canvas-edit.ts +302 -3
  17. package/apps/studio/canvas-lib.tsx +203 -11
  18. package/apps/studio/canvas-shell.tsx +167 -28
  19. package/apps/studio/client/app.jsx +678 -176
  20. package/apps/studio/client/panels/CapabilityBar.jsx +101 -0
  21. package/apps/studio/client/panels/ChatPanel.jsx +846 -133
  22. package/apps/studio/client/panels/ElicitationPrompt.jsx +429 -0
  23. package/apps/studio/client/panels/PermissionPrompt.jsx +119 -0
  24. package/apps/studio/client/panels/ReadinessList.jsx +17 -3
  25. package/apps/studio/client/panels/SettingsPanel.jsx +211 -0
  26. package/apps/studio/client/panels/ToolGroup.jsx +79 -0
  27. package/apps/studio/client/panels/acp-capabilities.js +82 -0
  28. package/apps/studio/client/panels/acp-elicitation.js +194 -0
  29. package/apps/studio/client/panels/acp-runtime.js +248 -9
  30. package/apps/studio/client/panels/acp-usage.js +65 -0
  31. package/apps/studio/client/panels/transcript-view.js +36 -0
  32. package/apps/studio/client/styles/6-acp-chat.css +689 -11
  33. package/apps/studio/dist/client.bundle.js +1738 -1736
  34. package/apps/studio/dist/comment-mount.js +2 -2
  35. package/apps/studio/dist/styles.css +1 -1
  36. package/apps/studio/dom-selection.ts +20 -0
  37. package/apps/studio/export-dialog.tsx +138 -18
  38. package/apps/studio/exporters/pdf.ts +332 -18
  39. package/apps/studio/exporters/png.ts +45 -3
  40. package/apps/studio/footage/schema.ts +17 -1
  41. package/apps/studio/generation/gemma-models.ts +224 -0
  42. package/apps/studio/generation/prefs.ts +43 -0
  43. package/apps/studio/generation/whisper-models.test.ts +28 -1
  44. package/apps/studio/generation/whisper-models.ts +22 -7
  45. package/apps/studio/http.ts +246 -9
  46. package/apps/studio/print/marks.ts +113 -0
  47. package/apps/studio/print/units.ts +269 -0
  48. package/apps/studio/print-overlay-content.tsx +132 -0
  49. package/apps/studio/test/acp-bridge.test.ts +11 -6
  50. package/apps/studio/test/acp-capabilities.test.ts +123 -0
  51. package/apps/studio/test/acp-caps-bridge.test.ts +274 -0
  52. package/apps/studio/test/acp-elicitation-bridge.test.ts +475 -0
  53. package/apps/studio/test/acp-elicitation.test.ts +251 -0
  54. package/apps/studio/test/acp-mode-banner.test.ts +45 -0
  55. package/apps/studio/test/acp-permission-prompt.test.ts +77 -0
  56. package/apps/studio/test/acp-permission.test.ts +262 -0
  57. package/apps/studio/test/acp-session-allowed-tools.test.ts +91 -0
  58. package/apps/studio/test/acp-toolgroup.test.ts +76 -0
  59. package/apps/studio/test/acp-transcript-view.test.ts +71 -0
  60. package/apps/studio/test/acp-transcript.test.ts +75 -2
  61. package/apps/studio/test/acp-usage-bridge.test.ts +136 -0
  62. package/apps/studio/test/acp-usage.test.ts +143 -0
  63. package/apps/studio/test/annotations-snap.test.ts +56 -0
  64. package/apps/studio/test/artboard-guides-overlay.test.tsx +152 -0
  65. package/apps/studio/test/artboard-kinds.test.tsx +83 -0
  66. package/apps/studio/test/artboard-selection-attrs.test.ts +69 -0
  67. package/apps/studio/test/canvas-meta-api.test.ts +167 -0
  68. package/apps/studio/test/element-structural-edit.test.ts +250 -0
  69. package/apps/studio/test/exporters/png.test.ts +49 -1
  70. package/apps/studio/test/fixtures/mock-acp-agent-caps.mjs +158 -0
  71. package/apps/studio/test/fixtures/mock-acp-agent-elicit-flood.mjs +46 -0
  72. package/apps/studio/test/fixtures/mock-acp-agent-elicit-url.mjs +42 -0
  73. package/apps/studio/test/fixtures/mock-acp-agent-elicit.mjs +63 -0
  74. package/apps/studio/test/fixtures/mock-acp-agent-permission-flood.mjs +51 -0
  75. package/apps/studio/test/fixtures/mock-acp-agent-permission.mjs +50 -0
  76. package/apps/studio/test/fixtures/mock-acp-agent-usage.mjs +56 -0
  77. package/apps/studio/test/import-asset.test.ts +31 -3
  78. package/apps/studio/test/pdf-print-boxes.test.ts +272 -0
  79. package/apps/studio/test/print-marks.test.ts +113 -0
  80. package/apps/studio/test/print-units.test.ts +173 -0
  81. package/apps/studio/test/use-snap-guides.test.ts +81 -0
  82. package/apps/studio/use-chrome-visibility.tsx +19 -0
  83. package/apps/studio/use-element-resize.tsx +21 -2
  84. package/apps/studio/use-snap-guides.tsx +73 -5
  85. package/apps/studio/use-spacing-handles.tsx +9 -5
  86. package/apps/studio/whats-new.json +62 -0
  87. package/cli/commands/design.mjs +116 -3
  88. package/cli/lib/pkg-root.mjs +42 -10
  89. package/cli/lib/pkg-root.test.mjs +33 -1
  90. package/package.json +11 -9
  91. package/plugins/design/dependencies.json +35 -0
@@ -1,11 +1,21 @@
1
1
  import { execSync, spawn, spawnSync } from 'node:child_process';
2
- import { chmodSync, existsSync, readFileSync } from 'node:fs';
2
+ import {
3
+ chmodSync,
4
+ existsSync,
5
+ mkdirSync,
6
+ mkdtempSync,
7
+ readFileSync,
8
+ rmSync,
9
+ writeFileSync,
10
+ } from 'node:fs';
3
11
  import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
4
12
  import { createRequire } from 'node:module';
13
+ import { homedir } from 'node:os';
5
14
  import { basename, dirname, join, resolve } from 'node:path';
6
15
  import { parseArgs } from '../lib/argv.mjs';
7
16
  import { runAdopt, runLink, runStatus, runUnlink } from '../lib/design-link.mjs';
8
17
  import { writeGitignoreBlock } from '../lib/gitignore-block.mjs';
18
+ import { isCompiledBinary } from '../lib/pkg-root.mjs';
9
19
 
10
20
  const SUBCOMMANDS = new Set([
11
21
  'serve',
@@ -77,6 +87,14 @@ const BIN_VERBS = new Set([
77
87
  // reads the clip as a file:// resource).
78
88
  'ingest-footage',
79
89
  'probe-footage',
90
+ // feature-scene-aware-keyframes. `smart-frames` is the scene-AWARE sibling of
91
+ // `probe-footage`: it selects keyframes at scene cuts + semantic action beats +
92
+ // endpoints (three tiers, auto-detected — gemma scout / ffmpeg scene-detect /
93
+ // blind Chromium floor) instead of a blind frame rate, and emits a SUPERSET of
94
+ // probe-footage's manifest (drop-in for the footage-analyst). No dev server.
95
+ // Owned by skill `footage-keyframes`; --engine auto self-detects deps so it
96
+ // works standalone as a terminal video analyzer.
97
+ 'smart-frames',
80
98
  // feature-ai-media-generation (Phase 0, DDR-16x). `generate` is the thin
81
99
  // non-browser BYOK verb (curl → /_api/generate-jobs → poll → print the
82
100
  // produced /assets/<sha8>.<ext>). The provider call happens server-side (the
@@ -133,6 +151,89 @@ export async function run({ args, pkgRoot }) {
133
151
  // pass straight through — preserves `$(maude design slug …)` capture,
134
152
  // `eval "$(maude design prep --shell-export …)"`, and non-zero gating idioms.
135
153
  // maude writes nothing of its own on this path (no banner on stdout).
154
+ /** True if a `bun` executable is reachable on the given PATH string (POSIX). */
155
+ function bunOnPath(pathStr) {
156
+ for (const dir of (pathStr || '').split(':')) {
157
+ if (dir && existsSync(join(dir, 'bun'))) return true;
158
+ }
159
+ return false;
160
+ }
161
+
162
+ /** A bun-capable compiled binary to borrow as `bun` (RCA G3), or null.
163
+ * Prefer the dev-server binary the sidecar hands us, else our own compiled
164
+ * self (the `maude` CLI is `bun --compile`d too), else a resolvable server bin. */
165
+ function resolveBunnable(pkgRoot) {
166
+ const dev = process.env.MAUDE_DEV_SERVER_BIN;
167
+ if (dev && existsSync(dev)) return dev;
168
+ if (isCompiledBinary()) return process.execPath;
169
+ const server = resolveServerBinary({ pkgRoot });
170
+ if (server && existsSync(server)) return server;
171
+ return null;
172
+ }
173
+
174
+ /**
175
+ * Ensure the design helpers' `command -v bun` / `exec bun run` resolve, even on a
176
+ * machine with NO standalone `bun` (RCA G3 — the desktop `.app` and the npm
177
+ * package ship compiled Bun BINARIES, never a `bun` CLI). The compiled binaries
178
+ * ARE Bun: run with `BUN_BE_BUN=1` a `bun --compile` executable behaves as the
179
+ * `bun` CLI. So if no real `bun` is on PATH, stage a tiny `bun` shim
180
+ * (→ `BUN_BE_BUN=1 <compiled-binary> "$@"`) in a per-user cache dir (0700) and
181
+ * PREPEND it to the child's PATH. No-op when a real `bun` is already present (dev)
182
+ * or no compiled binary exists to borrow (pure-source dev without bun — where a
183
+ * real `bun` is expected anyway). Returns the (possibly PATH-augmented) env.
184
+ */
185
+ /** POSIX single-quote escape: wrap in '…' and encode embedded quotes as '\''.
186
+ * Neutralizes $, backticks, ${}, and every other sh metachar — unlike
187
+ * JSON.stringify, which leaves them live inside sh double-quotes. */
188
+ function shSingleQuote(s) {
189
+ return `'${String(s).replace(/'/g, "'\\''")}'`;
190
+ }
191
+
192
+ /**
193
+ * Provide a `bun` to a design helper that has none (RCA G3), then have the caller
194
+ * REMOVE it after the spawn. Returns `{ env, shimDir }` — `shimDir` is a fresh
195
+ * dir the caller must `rmSync` once the helper exits (null when no shim was made).
196
+ *
197
+ * Security (ethical-hacker review, DDR-177 addendum): the shim goes in a fresh,
198
+ * unpredictable, owner-only `mkdtemp` dir created PER SPAWN and torn down right
199
+ * after — NEVER a stable, guessable `~/.cache/maude/bun-shim/bun`. A stable path
200
+ * on a child's PATH with an unqualified `bun` lookup is the exact PATH-shadow
201
+ * primitive `sidecar.rs` deliberately refuses (Attacker-F4/DDR-168): an untrusted
202
+ * SAME-UID actor (in scope per DDR-054 — a poisoned dependency in an opened
203
+ * project, a prompt-injected agent's Bash tool) could pre-plant/symlink/race a
204
+ * stable shim and hijack the interpreter of every future helper. A per-spawn
205
+ * mkdtemp dir has no pre-existing entry to symlink-follow and no guessable name to
206
+ * race, and is gone before the next spawn. Fails CLOSED with no HOME (never plants
207
+ * an executable in world-writable /tmp).
208
+ */
209
+ function ensureBunOnPath(childEnv, pkgRoot) {
210
+ if (bunOnPath(childEnv.PATH)) return { env: childEnv, shimDir: null };
211
+ const bunnable = resolveBunnable(pkgRoot);
212
+ if (!bunnable) return { env: childEnv, shimDir: null }; // helper's own guard reports the miss
213
+ const home = homedir();
214
+ if (!home) return { env: childEnv, shimDir: null }; // fail closed — no /tmp fallback for an executable
215
+ try {
216
+ const cacheParent = join(home, '.cache', 'maude');
217
+ mkdirSync(cacheParent, { recursive: true, mode: 0o700 });
218
+ // Fresh + unpredictable + 0700, one per spawn. mkdtemp guarantees a brand-new
219
+ // dir (fails if it exists), so there's nothing to symlink-follow on the write.
220
+ const shimDir = mkdtempSync(join(cacheParent, 'bun-shim-'));
221
+ const shim = join(shimDir, 'bun');
222
+ // Single-quote the binary path (NOT JSON.stringify — that leaves $/backticks
223
+ // live inside sh double-quotes, so a binary path with shell metacharacters
224
+ // would run command substitution when the shim executes).
225
+ writeFileSync(
226
+ shim,
227
+ `#!/bin/sh\n# maude bun shim (RCA G3) — the bundled compiled binary IS Bun;\n# BUN_BE_BUN=1 makes it act as the \`bun\` CLI so design helpers run with no\n# user-installed bun. Ephemeral: written per-spawn, removed after (design.mjs).\nBUN_BE_BUN=1 exec ${shSingleQuote(bunnable)} "$@"\n`,
228
+ { mode: 0o755 }
229
+ );
230
+ chmodSync(shim, 0o755);
231
+ return { env: { ...childEnv, PATH: `${shimDir}:${childEnv.PATH || ''}` }, shimDir };
232
+ } catch {
233
+ return { env: childEnv, shimDir: null }; // best-effort; the helper reports the miss
234
+ }
235
+ }
236
+
136
237
  function runBinDispatch(verb, { args, pkgRoot }) {
137
238
  if (!BIN_VERBS.has(verb)) {
138
239
  process.stderr.write(`maude design: "${verb}" is not a dev-tooling verb.\n${usage()}`);
@@ -164,10 +265,22 @@ function runBinDispatch(verb, { args, pkgRoot }) {
164
265
  const bin = resolveServerBinary({ pkgRoot });
165
266
  if (bin) childEnv.MAUDE_DEV_SERVER_BIN = bin;
166
267
  }
268
+ // RCA G3 — make `bun` resolvable to the helper from the bundled compiled binary
269
+ // when no standalone `bun` is installed (desktop / npm). No-op in dev. The shim
270
+ // dir is ephemeral (per-spawn mkdtemp) — remove it as soon as the helper exits,
271
+ // so nothing bun-named lingers on a guessable path (ethical-hacker review).
272
+ const { env: finalEnv, shimDir } = ensureBunOnPath(childEnv, pkgRoot);
167
273
  const child = spawnSync('bash', [script, ...rest], {
168
274
  stdio: 'inherit',
169
- env: childEnv,
275
+ env: finalEnv,
170
276
  });
277
+ if (shimDir) {
278
+ try {
279
+ rmSync(shimDir, { recursive: true, force: true });
280
+ } catch {
281
+ /* best-effort cleanup */
282
+ }
283
+ }
171
284
  if (child.error) {
172
285
  process.stderr.write(`maude design ${verb}: ${child.error.message}\n`);
173
286
  process.exit(1);
@@ -185,7 +298,7 @@ Dev-tooling (dispatch to the dev-server bash helpers — DDR-062):
185
298
  screenshot · server-up · prep · slug · bootstrap-check · runtime-health
186
299
  smoke · canvas-edit · handoff · asset-sweep · visual-sanity · fetch-asset
187
300
  draw-build · draw-proof · svg-optimize · to-lottie · read-annotations · annotate
188
- canvas-rects · ingest-footage · probe-footage
301
+ canvas-rects · ingest-footage · probe-footage · smart-frames
189
302
  generate · transcribe · audio-search
190
303
  Invoke the bundled helper of the same name. maude resolves it from its
191
304
  own package root and sets CLAUDE_PLUGIN_ROOT for the child; stdout,
@@ -59,14 +59,41 @@ export function isPkgRoot(dir) {
59
59
 
60
60
  /**
61
61
  * Resolve maude's own package root — real disk path, safe inside a compiled
62
- * binary. Priority: (0) explicit override, (1) dev-mode `import.meta.url`
63
- * (plain `node`/`bun run cli/bin/maude.mjs`), (2) compiled-binary walk-up
64
- * from `process.execPath` (matches the npm-install layout: binary at
65
- * `@1agh/maude-<platform>/maude` walks up to `@1agh/maude/`, which ships
66
- * `apps/studio/` via `package.json` `files`; matches the Tauri desktop layout
67
- * too, where the bundled `maude` binary and the `Resources/apps/studio`
68
- * bundle share a common ancestor within the walk-up depth).
62
+ * binary. Priority: (0) explicit `MAUDE_PKG_ROOT` override (sidecar.rs sets this
63
+ * on the desktop), (1) dev-mode `import.meta.url` (plain `node`/`bun run
64
+ * cli/bin/maude.mjs`), (2) compiled-binary walk-up from `process.execPath`
65
+ * (matches the npm-install layout: binary at `@1agh/maude-<platform>/maude`
66
+ * walks up to `@1agh/maude/`, which ships `apps/studio/` via `package.json`
67
+ * `files`), (3) the Tauri **`.app` sibling probe** below.
68
+ *
69
+ * Why (3) exists: in a packaged `Maude.app` the bundled `maude` binary lives in
70
+ * `Contents/MacOS/` but the staged package tree (`apps/studio/`, `cli/`,
71
+ * `package.json`) lives in the SIBLING `Contents/Resources/` — NOT an ancestor
72
+ * of the binary, so the walk-up in (2) never reaches it and used to fall through
73
+ * to `dirname(execPath)` = `Contents/MacOS/`, breaking every `maude design
74
+ * <verb>` with "helper not found" (RCA issue-acp-panel-hangs-on-nodeless-machine
75
+ * G2, reproduced on the shipped v0.45.1 `.app`). The earlier claim that the
76
+ * binary + `Resources/apps/studio` "share a common ancestor within the walk-up
77
+ * depth" was WRONG — `Contents/` is the common ancestor but `apps/studio` sits
78
+ * under `Contents/Resources/`, not `Contents/`, and `cli/` isn't in the ancestry
79
+ * at all. We probe the known Tauri resource-dir siblings explicitly instead.
69
80
  */
81
+ /**
82
+ * Probe the Tauri packaged-app resource dir relative to the binary's own dir.
83
+ * From `<app>/Contents/MacOS/maude`, the staged package tree is at the SIBLING
84
+ * `<app>/Contents/Resources`. Covers macOS (`Resources`), the lower-cased
85
+ * resource dir other Tauri targets use, and a binary co-located with a
86
+ * `resources/` dir (dev staging). Returns the first valid pkgRoot, or null.
87
+ * Exported so the RCA-G2 fix is unit-testable without spawning a real `.app`.
88
+ */
89
+ export function resolveTauriResourcePkgRoot(execDir) {
90
+ for (const rel of [['..', 'Resources'], ['..', 'resources'], ['resources']]) {
91
+ const cand = join(execDir, ...rel);
92
+ if (isPkgRoot(cand)) return cand;
93
+ }
94
+ return null;
95
+ }
96
+
70
97
  export function resolvePkgRoot() {
71
98
  const override = process.env.MAUDE_PKG_ROOT;
72
99
  if (override && !isVirtualBunfsPath(override) && isPkgRoot(override)) return override;
@@ -84,12 +111,13 @@ export function resolvePkgRoot() {
84
111
  // from there (e.g. ~/Library/Caches/…/bin-link/) never reaches the repo
85
112
  // root. Dereference first. Falls back to the raw path if the file somehow
86
113
  // doesn't exist (shouldn't happen — we ARE that running process).
87
- let cur;
114
+ let execDir;
88
115
  try {
89
- cur = dirname(realpathSync(process.execPath));
116
+ execDir = dirname(realpathSync(process.execPath));
90
117
  } catch {
91
- cur = dirname(process.execPath);
118
+ execDir = dirname(process.execPath);
92
119
  }
120
+ let cur = execDir;
93
121
  for (let i = 0; i < 10; i++) {
94
122
  if (isPkgRoot(cur)) return cur;
95
123
  const parent = dirname(cur);
@@ -97,6 +125,10 @@ export function resolvePkgRoot() {
97
125
  cur = parent;
98
126
  }
99
127
 
128
+ // (3) Tauri `.app` sibling probe — the packaged layout the walk-up can't reach.
129
+ const sibling = resolveTauriResourcePkgRoot(execDir);
130
+ if (sibling) return sibling;
131
+
100
132
  // Final fallback for unanchored test contexts — callers should expect
101
133
  // existsSync-based lookups to fail and surface a clear error, same
102
134
  // contract as paths.ts's own resolver. Never join a VIRTUAL importDir here
@@ -16,7 +16,7 @@ import { tmpdir } from 'node:os';
16
16
  import { join } from 'node:path';
17
17
  import { test } from 'node:test';
18
18
 
19
- import { isPkgRoot, resolvePkgRoot } from './pkg-root.mjs';
19
+ import { isPkgRoot, resolvePkgRoot, resolveTauriResourcePkgRoot } from './pkg-root.mjs';
20
20
 
21
21
  function makeRealRoot(base) {
22
22
  mkdirSync(join(base, 'apps', 'studio', 'bin'), { recursive: true });
@@ -52,6 +52,38 @@ test('isPkgRoot requires BOTH anchors — the staged-resources false-positive is
52
52
  }
53
53
  });
54
54
 
55
+ test('resolveTauriResourcePkgRoot finds the .app sibling Resources tree (RCA G2)', () => {
56
+ // Mirror the packaged macOS layout: binary in Contents/MacOS, staged tree in
57
+ // the SIBLING Contents/Resources — NOT an ancestor of the binary, which is why
58
+ // the plain walk-up misses it and every `maude design <verb>` broke.
59
+ const app = mkdtempSync(join(tmpdir(), 'maude-app-'));
60
+ try {
61
+ const macosDir = join(app, 'Contents', 'MacOS');
62
+ const resources = join(app, 'Contents', 'Resources');
63
+ mkdirSync(macosDir, { recursive: true });
64
+ makeRealRoot(resources); // stages apps/studio/bin/screenshot.sh + cli/commands/design.mjs
65
+
66
+ // From the binary's own dir, the sibling probe must find Resources.
67
+ assert.equal(resolveTauriResourcePkgRoot(macosDir), resources);
68
+
69
+ // Regression guard: Resources WITHOUT cli/ (the shipped-broken v0.45.1 shape)
70
+ // must NOT resolve — that's exactly the false-positive isPkgRoot rejects.
71
+ const broken = mkdtempSync(join(tmpdir(), 'maude-app-broken-'));
72
+ try {
73
+ const bMacos = join(broken, 'Contents', 'MacOS');
74
+ const bRes = join(broken, 'Contents', 'Resources', 'apps', 'studio', 'bin');
75
+ mkdirSync(bMacos, { recursive: true });
76
+ mkdirSync(bRes, { recursive: true });
77
+ writeFileSync(join(bRes, 'screenshot.sh'), '#!/bin/sh\n'); // no cli/ staged
78
+ assert.equal(resolveTauriResourcePkgRoot(bMacos), null);
79
+ } finally {
80
+ rmSync(broken, { recursive: true, force: true });
81
+ }
82
+ } finally {
83
+ rmSync(app, { recursive: true, force: true });
84
+ }
85
+ });
86
+
55
87
  test('resolvePkgRoot honors MAUDE_PKG_ROOT only when it actually satisfies both anchors', () => {
56
88
  const real = mkdtempSync(join(tmpdir(), 'maude-pkgroot-real-'));
57
89
  const fake = mkdtempSync(join(tmpdir(), 'maude-pkgroot-fake-'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1agh/maude",
3
- "version": "0.45.1",
3
+ "version": "0.46.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": {
@@ -51,13 +51,13 @@
51
51
  "test:e2e:desktop:acp-cold-start": "pnpm --filter @maude/desktop-e2e e2e:acp-cold-start"
52
52
  },
53
53
  "optionalDependencies": {
54
- "@1agh/maude-darwin-arm64": "0.45.1",
55
- "@1agh/maude-darwin-x64": "0.45.1",
56
- "@1agh/maude-linux-arm64": "0.45.1",
57
- "@1agh/maude-linux-arm64-musl": "0.45.1",
58
- "@1agh/maude-linux-x64": "0.45.1",
59
- "@1agh/maude-linux-x64-musl": "0.45.1",
60
- "@1agh/maude-win32-x64": "0.45.1"
54
+ "@1agh/maude-darwin-arm64": "0.46.0",
55
+ "@1agh/maude-darwin-x64": "0.46.0",
56
+ "@1agh/maude-linux-arm64": "0.46.0",
57
+ "@1agh/maude-linux-arm64-musl": "0.46.0",
58
+ "@1agh/maude-linux-x64": "0.46.0",
59
+ "@1agh/maude-linux-x64-musl": "0.46.0",
60
+ "@1agh/maude-win32-x64": "0.46.0"
61
61
  },
62
62
  "files": [
63
63
  "cli",
@@ -102,6 +102,8 @@
102
102
  },
103
103
  "dependencies": {
104
104
  "ajv": "^8.20.0",
105
- "ajv-formats": "^3.0.1"
105
+ "ajv-formats": "^3.0.1",
106
+ "happy-dom": "20.10.6",
107
+ "svgo": "^4.0.1"
106
108
  }
107
109
  }
@@ -213,6 +213,41 @@
213
213
  "fallbackBehavior": "feature-ai-media-generation Phase 2 (DDR-164) — `maude design transcribe` uses whisper.cpp for local, no-key, word-timestamped subtitles (the DEFAULT subtitle path). Without it, transcription falls back to cloud STT (ElevenLabs Scribe / Groq Whisper) via a provider key. whisper.cpp also needs a ggml model file (--model / $MAUDE_WHISPER_MODEL); it ships no default and does not auto-download — see https://huggingface.co/ggerganov/whisper.cpp (e.g. ggml-large-v3-turbo.bin).",
214
214
  "usedBy": ["dev-server/bin/transcribe.sh", "dev-server/bin/_transcribe.mjs"],
215
215
  "docsUrl": "https://github.com/ggml-org/whisper.cpp"
216
+ },
217
+ {
218
+ "id": "ffmpeg",
219
+ "type": "cli",
220
+ "hardness": "soft",
221
+ "check": {
222
+ "command": "ffmpeg -version",
223
+ "expectExit": 0
224
+ },
225
+ "install": {
226
+ "darwin": "brew install ffmpeg",
227
+ "linux": "apt-get install -y ffmpeg || dnf install -y ffmpeg",
228
+ "preferred": "https://ffmpeg.org/download.html"
229
+ },
230
+ "autoInstall": false,
231
+ "fallbackBehavior": "feature-scene-aware-keyframes — the `ffmpeg` tier of `maude design smart-frames` (skill footage-keyframes) uses ffmpeg scene-detection to pick keyframes at real shot cuts. Without it, the extractor falls back to the blind Chromium tier (probe-footage, even-spaced) — still works, just not scene-aware.",
232
+ "usedBy": ["dev-server/bin/smart-frames.sh", "dev-server/bin/_smart-frames.mjs"],
233
+ "docsUrl": "https://ffmpeg.org"
234
+ },
235
+ {
236
+ "id": "mlx-vlm",
237
+ "type": "cli",
238
+ "hardness": "soft",
239
+ "check": {
240
+ "command": "python3 -c \"import mlx_vlm\"",
241
+ "expectExit": 0
242
+ },
243
+ "install": {
244
+ "darwin": "pip install mlx-vlm",
245
+ "preferred": "https://github.com/Blaizzy/mlx-vlm"
246
+ },
247
+ "autoInstall": false,
248
+ "fallbackBehavior": "feature-scene-aware-keyframes — OPT-IN. The `gemma` tier of `maude design smart-frames` runs a local Gemma-4 MLX scout (Apple Silicon only) to flag semantic action beats. Without it, smart-frames uses the ffmpeg or blind tier — no model download required. The scout also needs a Gemma-4 MLX model (--engine gemma / $MAUDE_GEMMA_MODEL, one-click in Studio Settings → Scene-aware keyframes).",
249
+ "usedBy": ["dev-server/bin/_smart-frames.mjs"],
250
+ "docsUrl": "https://github.com/Blaizzy/mlx-vlm"
216
251
  }
217
252
  ]
218
253
  }