@1agh/maude 0.42.0 → 0.44.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/apps/studio/.ai/cache/_stats.json +7 -0
- package/apps/studio/acp/bootstrap-brief.ts +12 -2
- package/apps/studio/acp/bridge.ts +44 -10
- package/apps/studio/acp/env.ts +23 -0
- package/apps/studio/acp/login-state.ts +263 -0
- package/apps/studio/acp/plugin-bootstrap.ts +31 -25
- package/apps/studio/acp/probe.ts +152 -1
- package/apps/studio/annotations-layer.tsx +1451 -324
- package/apps/studio/annotations-model.ts +58 -0
- package/apps/studio/api.ts +568 -24
- package/apps/studio/bin/_audio-search.mjs +140 -0
- package/apps/studio/bin/_import-asset-pdf-worker.mjs +34 -0
- package/apps/studio/bin/_import-asset.mjs +815 -0
- package/apps/studio/bin/_import-brand.mjs +635 -0
- package/apps/studio/bin/_import-tokens-alias-resolver.mjs +95 -0
- package/apps/studio/bin/_import-tokens.mjs +1201 -0
- package/apps/studio/bin/_ingest-footage.mjs +386 -0
- package/apps/studio/bin/_probe-footage-playwright.mjs +269 -0
- package/apps/studio/bin/_transcribe.mjs +419 -0
- package/apps/studio/bin/_transcribe.test.mjs +80 -0
- package/apps/studio/bin/_video-playwright.mjs +141 -71
- package/apps/studio/bin/audio-search.sh +28 -0
- package/apps/studio/bin/generate.sh +154 -0
- package/apps/studio/bin/import-asset.sh +34 -0
- package/apps/studio/bin/import-brand.sh +29 -0
- package/apps/studio/bin/import-tokens.sh +33 -0
- package/apps/studio/bin/ingest-footage.sh +27 -0
- package/apps/studio/bin/photo-adjust.sh +163 -0
- package/apps/studio/bin/photo-bg-remove.sh +258 -0
- package/apps/studio/bin/probe-footage.sh +28 -0
- package/apps/studio/bin/read-annotations.mjs +125 -2
- package/apps/studio/bin/transcribe.sh +39 -0
- package/apps/studio/canvas-edit.ts +656 -12
- package/apps/studio/canvas-lib.tsx +637 -10
- package/apps/studio/canvas-pipeline.ts +65 -7
- package/apps/studio/canvas-shell.tsx +156 -16
- package/apps/studio/client/app.jsx +2385 -699
- package/apps/studio/client/export-center.jsx +35 -1
- package/apps/studio/client/generate-dialog.jsx +352 -0
- package/apps/studio/client/github.js +18 -0
- package/apps/studio/client/inspector-controls.jsx +781 -0
- package/apps/studio/client/panels/BrandUploadPanel.jsx +233 -0
- package/apps/studio/client/panels/ChatPanel.jsx +15 -33
- package/apps/studio/client/panels/GitPanel.jsx +8 -0
- package/apps/studio/client/panels/IntroVideoDialog.jsx +44 -0
- package/apps/studio/client/panels/OnboardingWizard.jsx +12 -0
- package/apps/studio/client/panels/ReadinessList.jsx +227 -7
- package/apps/studio/client/panels/RepoBranchSwitcher.jsx +133 -21
- package/apps/studio/client/panels/SettingsPanel.jsx +828 -0
- package/apps/studio/client/panels/SetupChecklist.jsx +223 -0
- package/apps/studio/client/panels/StickerPicker.jsx +160 -0
- package/apps/studio/client/panels/TimelinePanel.jsx +15 -2
- package/apps/studio/client/photo-knobs.jsx +432 -0
- package/apps/studio/client/styles/3-shell-maude.css +376 -28
- package/apps/studio/client/styles/4-components.css +223 -0
- package/apps/studio/client/styles/6-acp-chat.css +86 -0
- package/apps/studio/client/tour/quick-setup-tour.js +39 -0
- package/apps/studio/commands/annotation-strokes-command.ts +13 -3
- package/apps/studio/commands/edit-source-command.ts +31 -4
- package/apps/studio/config.schema.json +70 -0
- package/apps/studio/context-menu.tsx +42 -8
- package/apps/studio/context.ts +16 -0
- package/apps/studio/design-setup-readiness.ts +115 -0
- package/apps/studio/dist/client.bundle.js +5572 -21
- package/apps/studio/dist/comment-mount.js +2 -2
- package/apps/studio/dist/runtime/.min-sizes.json +1 -0
- package/apps/studio/dist/runtime/@imgly_background-removal.js +5543 -0
- package/apps/studio/dist/runtime/pixi-js.js +519 -519
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/dom-selection.ts +25 -0
- package/apps/studio/draw/palette.ts +34 -0
- package/apps/studio/exporters/jobs.ts +47 -5
- package/apps/studio/exporters/video.ts +24 -4
- package/apps/studio/footage/schema.test.ts +287 -0
- package/apps/studio/footage/schema.ts +662 -0
- package/apps/studio/footage-store.ts +235 -0
- package/apps/studio/fs-watch.ts +10 -0
- package/apps/studio/generation/adapters/elevenlabs.ts +370 -0
- package/apps/studio/generation/adapters/gemini.ts +542 -0
- package/apps/studio/generation/adapters/groq.test.ts +80 -0
- package/apps/studio/generation/adapters/groq.ts +247 -0
- package/apps/studio/generation/audio-library.test.ts +95 -0
- package/apps/studio/generation/audio-library.ts +156 -0
- package/apps/studio/generation/captions.test.ts +78 -0
- package/apps/studio/generation/captions.ts +132 -0
- package/apps/studio/generation/download.ts +76 -0
- package/apps/studio/generation/elevenlabs.test.ts +223 -0
- package/apps/studio/generation/gemini.test.ts +350 -0
- package/apps/studio/generation/jobs.test.ts +128 -0
- package/apps/studio/generation/jobs.ts +243 -0
- package/apps/studio/generation/keys.test.ts +75 -0
- package/apps/studio/generation/keys.ts +162 -0
- package/apps/studio/generation/prefs.test.ts +95 -0
- package/apps/studio/generation/prefs.ts +82 -0
- package/apps/studio/generation/registry.ts +88 -0
- package/apps/studio/generation/types.test.ts +123 -0
- package/apps/studio/generation/types.ts +266 -0
- package/apps/studio/generation/whisper-models.test.ts +152 -0
- package/apps/studio/generation/whisper-models.ts +257 -0
- package/apps/studio/generation/whisper-spike-results.md +61 -0
- package/apps/studio/git/endpoints.ts +68 -7
- package/apps/studio/git/service.ts +199 -21
- package/apps/studio/github/service.ts +67 -0
- package/apps/studio/handoff.ts +3 -2
- package/apps/studio/http.ts +1039 -22
- package/apps/studio/input-router.tsx +10 -0
- package/apps/studio/inspect.ts +53 -1
- package/apps/studio/media/intro.mp4 +0 -0
- package/apps/studio/media-commit-chain.ts +119 -0
- package/apps/studio/paths.ts +20 -0
- package/apps/studio/photo/filters.ts +285 -0
- package/apps/studio/photo/pipeline.ts +607 -0
- package/apps/studio/photo/schema.ts +367 -0
- package/apps/studio/photo-store.ts +154 -0
- package/apps/studio/readiness.ts +108 -20
- package/apps/studio/runtime-bundle.ts +29 -6
- package/apps/studio/scaffold-design.ts +1145 -0
- package/apps/studio/server.ts +18 -2
- package/apps/studio/stickers/figjam-doodle/manifest.json +104 -0
- package/apps/studio/stickers/figjam-doodle/slice1.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice10.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice11.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice12.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice13.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice14.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice15.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice16.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice17.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice18.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice19.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice2.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice20.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice21.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice22.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice23.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice24.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice3.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice4.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice5.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice6.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice7.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice8.png +0 -0
- package/apps/studio/stickers/figjam-doodle/slice9.png +0 -0
- package/apps/studio/stickers/life-style/best.png +0 -0
- package/apps/studio/stickers/life-style/come-on.png +0 -0
- package/apps/studio/stickers/life-style/cut.png +0 -0
- package/apps/studio/stickers/life-style/detox.png +0 -0
- package/apps/studio/stickers/life-style/just.png +0 -0
- package/apps/studio/stickers/life-style/manifest.json +68 -0
- package/apps/studio/stickers/life-style/mirror.png +0 -0
- package/apps/studio/stickers/life-style/nice.png +0 -0
- package/apps/studio/stickers/life-style/objects.png +0 -0
- package/apps/studio/stickers/life-style/ok.png +0 -0
- package/apps/studio/stickers/life-style/queen.png +0 -0
- package/apps/studio/stickers/life-style/star.png +0 -0
- package/apps/studio/stickers/life-style/sun.png +0 -0
- package/apps/studio/stickers/life-style/water.png +0 -0
- package/apps/studio/stickers/life-style/yeah.png +0 -0
- package/apps/studio/stickers/life-style/you-can.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/check-the-deets.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/cut-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/dope.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/fresh.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/hot.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/idea.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/keep-exploring.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/killed-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/love-it.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/manifest.json +88 -0
- package/apps/studio/stickers/opposing-thoughts/not-sure.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/ok.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/pure-gold.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/save-for-later.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/steal-this.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/take-a-peek.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/this-or-that.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/thoughts.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/vibes.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/winner.png +0 -0
- package/apps/studio/stickers/opposing-thoughts/wip.png +0 -0
- package/apps/studio/stickers/project-status/group-100.png +0 -0
- package/apps/studio/stickers/project-status/group-101.png +0 -0
- package/apps/studio/stickers/project-status/group-102.png +0 -0
- package/apps/studio/stickers/project-status/group-103.png +0 -0
- package/apps/studio/stickers/project-status/group-104.png +0 -0
- package/apps/studio/stickers/project-status/group-105.png +0 -0
- package/apps/studio/stickers/project-status/group-106.png +0 -0
- package/apps/studio/stickers/project-status/group-107.png +0 -0
- package/apps/studio/stickers/project-status/group-108.png +0 -0
- package/apps/studio/stickers/project-status/group-109.png +0 -0
- package/apps/studio/stickers/project-status/group-110.png +0 -0
- package/apps/studio/stickers/project-status/group-111.png +0 -0
- package/apps/studio/stickers/project-status/group-112.png +0 -0
- package/apps/studio/stickers/project-status/group-113.png +0 -0
- package/apps/studio/stickers/project-status/group-114.png +0 -0
- package/apps/studio/stickers/project-status/group-115.png +0 -0
- package/apps/studio/stickers/project-status/group-117.png +0 -0
- package/apps/studio/stickers/project-status/group-118.png +0 -0
- package/apps/studio/stickers/project-status/group-119.png +0 -0
- package/apps/studio/stickers/project-status/group-120.png +0 -0
- package/apps/studio/stickers/project-status/group-121.png +0 -0
- package/apps/studio/stickers/project-status/group-122.png +0 -0
- package/apps/studio/stickers/project-status/group-41.png +0 -0
- package/apps/studio/stickers/project-status/group-42.png +0 -0
- package/apps/studio/stickers/project-status/group-43.png +0 -0
- package/apps/studio/stickers/project-status/group-44.png +0 -0
- package/apps/studio/stickers/project-status/group-45.png +0 -0
- package/apps/studio/stickers/project-status/group-46.png +0 -0
- package/apps/studio/stickers/project-status/group-47.png +0 -0
- package/apps/studio/stickers/project-status/group-48.png +0 -0
- package/apps/studio/stickers/project-status/group-49.png +0 -0
- package/apps/studio/stickers/project-status/group-50.png +0 -0
- package/apps/studio/stickers/project-status/group-51.png +0 -0
- package/apps/studio/stickers/project-status/group-52.png +0 -0
- package/apps/studio/stickers/project-status/group-53.png +0 -0
- package/apps/studio/stickers/project-status/group-54.png +0 -0
- package/apps/studio/stickers/project-status/group-55.png +0 -0
- package/apps/studio/stickers/project-status/group-56.png +0 -0
- package/apps/studio/stickers/project-status/group-57.png +0 -0
- package/apps/studio/stickers/project-status/group-58.png +0 -0
- package/apps/studio/stickers/project-status/group-59.png +0 -0
- package/apps/studio/stickers/project-status/group-60.png +0 -0
- package/apps/studio/stickers/project-status/group-61.png +0 -0
- package/apps/studio/stickers/project-status/group-62.png +0 -0
- package/apps/studio/stickers/project-status/group-63.png +0 -0
- package/apps/studio/stickers/project-status/group-64.png +0 -0
- package/apps/studio/stickers/project-status/group-65.png +0 -0
- package/apps/studio/stickers/project-status/group-66.png +0 -0
- package/apps/studio/stickers/project-status/group-67.png +0 -0
- package/apps/studio/stickers/project-status/group-68.png +0 -0
- package/apps/studio/stickers/project-status/group-69.png +0 -0
- package/apps/studio/stickers/project-status/group-70.png +0 -0
- package/apps/studio/stickers/project-status/group-71.png +0 -0
- package/apps/studio/stickers/project-status/group-72.png +0 -0
- package/apps/studio/stickers/project-status/group-73.png +0 -0
- package/apps/studio/stickers/project-status/group-74.png +0 -0
- package/apps/studio/stickers/project-status/group-75.png +0 -0
- package/apps/studio/stickers/project-status/group-76.png +0 -0
- package/apps/studio/stickers/project-status/group-77.png +0 -0
- package/apps/studio/stickers/project-status/group-78.png +0 -0
- package/apps/studio/stickers/project-status/group-79.png +0 -0
- package/apps/studio/stickers/project-status/group-80.png +0 -0
- package/apps/studio/stickers/project-status/group-81.png +0 -0
- package/apps/studio/stickers/project-status/group-82.png +0 -0
- package/apps/studio/stickers/project-status/group-83.png +0 -0
- package/apps/studio/stickers/project-status/group-84.png +0 -0
- package/apps/studio/stickers/project-status/group-85.png +0 -0
- package/apps/studio/stickers/project-status/group-86.png +0 -0
- package/apps/studio/stickers/project-status/group-87.png +0 -0
- package/apps/studio/stickers/project-status/group-88.png +0 -0
- package/apps/studio/stickers/project-status/group-89.png +0 -0
- package/apps/studio/stickers/project-status/group-90.png +0 -0
- package/apps/studio/stickers/project-status/group-91.png +0 -0
- package/apps/studio/stickers/project-status/group-92.png +0 -0
- package/apps/studio/stickers/project-status/group-93.png +0 -0
- package/apps/studio/stickers/project-status/group-94.png +0 -0
- package/apps/studio/stickers/project-status/group-96.png +0 -0
- package/apps/studio/stickers/project-status/group-97.png +0 -0
- package/apps/studio/stickers/project-status/group-98.png +0 -0
- package/apps/studio/stickers/project-status/group-99.png +0 -0
- package/apps/studio/stickers/project-status/manifest.json +328 -0
- package/apps/studio/test/_helpers.ts +15 -2
- package/apps/studio/test/acp-bootstrap-brief.test.ts +11 -0
- package/apps/studio/test/acp-bridge.test.ts +34 -1
- package/apps/studio/test/acp-commands.test.ts +2 -1
- package/apps/studio/test/acp-env.test.ts +30 -0
- package/apps/studio/test/acp-plugin-bootstrap.test.ts +23 -57
- package/apps/studio/test/acp-session-plugins.test.ts +72 -1
- package/apps/studio/test/annotation-strokes-command.test.ts +17 -0
- package/apps/studio/test/annotations-layer.test.ts +174 -0
- package/apps/studio/test/asset-api.test.ts +3 -3
- package/apps/studio/test/canvas-edit.test.ts +17 -6
- package/apps/studio/test/canvas-origin-gate.test.ts +50 -0
- package/apps/studio/test/csp-canvas-shell.test.ts +11 -0
- package/apps/studio/test/csrf-write-guard.test.ts +23 -1
- package/apps/studio/test/design-setup-readiness.test.ts +155 -0
- package/apps/studio/test/dynamic-text-edit.test.ts +162 -0
- package/apps/studio/test/edit-source-command.test.ts +23 -0
- package/apps/studio/test/element-structural-edit.test.ts +154 -0
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +13 -0
- package/apps/studio/test/footage-store.test.ts +100 -0
- package/apps/studio/test/generate-route.test.ts +106 -0
- package/apps/studio/test/git-branches.test.ts +97 -0
- package/apps/studio/test/github-api.test.ts +56 -1
- package/apps/studio/test/import-asset-browser.test.ts +64 -0
- package/apps/studio/test/import-asset-route.test.ts +71 -0
- package/apps/studio/test/import-asset.test.ts +399 -0
- package/apps/studio/test/import-brand-browser.test.ts +88 -0
- package/apps/studio/test/import-brand-route.test.ts +120 -0
- package/apps/studio/test/import-brand.test.ts +206 -0
- package/apps/studio/test/import-tokens.test.ts +722 -0
- package/apps/studio/test/input-router.test.ts +33 -0
- package/apps/studio/test/inspect-script-syntax.test.ts +53 -0
- package/apps/studio/test/media-commit-chain.test.ts +210 -0
- package/apps/studio/test/photo-bg-remove-validation.test.ts +71 -0
- package/apps/studio/test/photo-canvas-bundle.test.ts +61 -0
- package/apps/studio/test/photo-edit-api.test.ts +201 -0
- package/apps/studio/test/photo-filters.test.ts +149 -0
- package/apps/studio/test/photo-pipeline.test.ts +106 -0
- package/apps/studio/test/photo-taxonomy.test.ts +96 -0
- package/apps/studio/test/read-annotations.test.ts +164 -0
- package/apps/studio/test/readiness.test.ts +13 -11
- package/apps/studio/test/scaffold-design.test.ts +122 -0
- package/apps/studio/test/shell-importmap.test.ts +49 -0
- package/apps/studio/test/text-editability-stamp.test.ts +131 -0
- package/apps/studio/test/timeline-parse.test.ts +57 -0
- package/apps/studio/test/tool-palette-insert-anchor.test.ts +5 -3
- package/apps/studio/test/tour-overlay.test.tsx +16 -0
- package/apps/studio/test/undo-stack.test.ts +33 -0
- package/apps/studio/test/video-asset.test.ts +5 -5
- package/apps/studio/test/video-render-bridge.test.ts +23 -1
- package/apps/studio/text-caret.ts +239 -0
- package/apps/studio/tool-palette.tsx +49 -21
- package/apps/studio/ui-prefs.ts +130 -0
- package/apps/studio/undo-stack.ts +94 -2
- package/apps/studio/use-annotation-resize.tsx +4 -4
- package/apps/studio/use-canvas-media-drop.tsx +40 -1
- package/apps/studio/use-chrome-visibility.tsx +8 -2
- package/apps/studio/use-selection-set.tsx +21 -0
- package/apps/studio/video-comp.tsx +48 -7
- package/apps/studio/whats-new.json +149 -0
- package/apps/studio/ws.ts +5 -0
- package/cli/bin/maude.mjs +6 -6
- package/cli/commands/design.mjs +67 -3
- package/cli/lib/gitignore-block.mjs +2 -0
- package/cli/lib/pkg-root.mjs +107 -0
- package/cli/lib/pkg-root.test.mjs +79 -0
- package/cli/lib/reconstruct-toolset.test.mjs +194 -0
- package/cli/lib/update-check.mjs +8 -0
- package/package.json +13 -11
- package/plugins/design/dependencies.json +18 -0
- package/plugins/design/templates/_shell.html +1 -0
|
@@ -42,9 +42,15 @@ export function ChromeVisibilityProvider({
|
|
|
42
42
|
children: ReactNode;
|
|
43
43
|
initial?: Partial<ChromeVisibilityState>;
|
|
44
44
|
}) {
|
|
45
|
+
// Defaults MUST match the app-shell's own default view-prefs (app.jsx
|
|
46
|
+
// MINIMAP_STORE / ZOOMCTL_STORE both default false) — otherwise a freshly
|
|
47
|
+
// loaded canvas shows the minimap/zoom before (or instead of, when the seed
|
|
48
|
+
// races the early inline-script `dgn:'loaded'`) the shell's OFF state is
|
|
49
|
+
// applied, so a user with both toggled off still sees them. `present` is a
|
|
50
|
+
// transient overlay, never persisted, so it stays false.
|
|
45
51
|
const [state, setState] = useState<ChromeVisibilityState>({
|
|
46
|
-
minimap: initial?.minimap ??
|
|
47
|
-
zoom: initial?.zoom ??
|
|
52
|
+
minimap: initial?.minimap ?? false,
|
|
53
|
+
zoom: initial?.zoom ?? false,
|
|
48
54
|
present: initial?.present ?? false,
|
|
49
55
|
});
|
|
50
56
|
const setChrome = useCallback((patch: Partial<ChromeVisibilityState>) => {
|
|
@@ -84,6 +84,27 @@ export interface Selection {
|
|
|
84
84
|
* block child. Absent for a detached node / no parent. */
|
|
85
85
|
parentDisplay?: string;
|
|
86
86
|
parentFlexDirection?: string;
|
|
87
|
+
/** feature-photo-editor (Task 14) — set at selection resolution when the hit is
|
|
88
|
+
* a content-addressed photo. `artboard-img` = an `<img src="assets/<sha8>.<ext>">`
|
|
89
|
+
* authored in artboard TSX; `annotation-image` is threaded separately (the
|
|
90
|
+
* annotation model has no data-cd-id, so it never rides this DOM-selection
|
|
91
|
+
* path — see app.jsx's `edit-annotation-photo-request` handler). Absent for a
|
|
92
|
+
* non-photo element or an `<img>` whose src isn't content-addressed. */
|
|
93
|
+
photoKind?: 'artboard-img' | 'annotation-image';
|
|
94
|
+
/** The resolved `assets/<sha8>.<ext>` source, when `photoKind` is set — the key
|
|
95
|
+
* the Photo tab passes to `/_api/photo-edit`. */
|
|
96
|
+
photoAsset?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** feature-photo-editor — pull the content-addressed `assets/<sha8>.<ext>` out of
|
|
100
|
+
* an image src (relative, absolute, or embedded in an outerHTML excerpt). Returns
|
|
101
|
+
* null for a non-content-addressed src (external URL, SVG icon, data: URI) — those
|
|
102
|
+
* aren't editable by the sidecar-keyed photo pipeline. Exported so both the
|
|
103
|
+
* selection resolver and the Inspector's fallback derivation share one regex. */
|
|
104
|
+
export function photoAssetFromString(s: string | null | undefined): string | null {
|
|
105
|
+
if (!s) return null;
|
|
106
|
+
const m = /assets\/[0-9a-f]{8}\.[a-z0-9]+/i.exec(s);
|
|
107
|
+
return m ? m[0] : null;
|
|
87
108
|
}
|
|
88
109
|
|
|
89
110
|
interface SelectionSetValue {
|
|
@@ -116,6 +116,18 @@ function registry(): Map<string, CompEntry> {
|
|
|
116
116
|
return w.__maudeVideoComps;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
// rca/issue-video-artboard-frame-reset-on-edit — the LAST live-preview frame
|
|
120
|
+
// per comp, hoisted above every remount boundary (module scope, mirrors
|
|
121
|
+
// canvas-lib.tsx's `liveViewport`). A canvas edit (ACP/agent/inspector/text)
|
|
122
|
+
// remounts the canvas subtree (canvas-comment-mount.tsx `key={attempt}`), and
|
|
123
|
+
// video-comp.tsx's own module survives that remount — so a fresh VideoComp
|
|
124
|
+
// mount can read the Timeline's last position here instead of always opening
|
|
125
|
+
// on the static `posterFrame`. A full page load clears it — correct; the
|
|
126
|
+
// shell re-seeds via the `timeline-comps` re-announce (app.jsx) once the new
|
|
127
|
+
// Player registers. Never touched during capture (`hideChrome()` forces the
|
|
128
|
+
// deterministic frame 0 / render-shim frame regardless of this mirror).
|
|
129
|
+
const liveTimelineFrame = new Map<string, number>();
|
|
130
|
+
|
|
119
131
|
function clamp(n: number, lo: number, hi: number): number {
|
|
120
132
|
return Math.max(lo, Math.min(hi, n));
|
|
121
133
|
}
|
|
@@ -226,7 +238,7 @@ export interface VideoCompProps extends VideoCompMeta {
|
|
|
226
238
|
/** Show the Player's own transport chrome in PREVIEW. Auto-hidden during
|
|
227
239
|
* capture/export (the `?hide-chrome=1` shell flag). Default true. */
|
|
228
240
|
controls?: boolean;
|
|
229
|
-
/** Loop preview playback. Default
|
|
241
|
+
/** Loop preview playback. Default false — the user opts in via the Timeline. */
|
|
230
242
|
loop?: boolean;
|
|
231
243
|
/**
|
|
232
244
|
* Autoplay in preview. Default: play unless the viewer prefers reduced motion
|
|
@@ -281,7 +293,7 @@ export function VideoComp({
|
|
|
281
293
|
id,
|
|
282
294
|
inputProps,
|
|
283
295
|
controls,
|
|
284
|
-
loop =
|
|
296
|
+
loop = false,
|
|
285
297
|
autoPlay,
|
|
286
298
|
}: VideoCompProps) {
|
|
287
299
|
const ref = useRef<PlayerRef | null>(null);
|
|
@@ -301,9 +313,15 @@ export function VideoComp({
|
|
|
301
313
|
// autoplay; capture never autoplays (the shim drives frames). Opens on a
|
|
302
314
|
// poster frame ~35% in so a paused comp shows content, not an empty frame 0.
|
|
303
315
|
const play = (autoPlay ?? false) && !capturing;
|
|
304
|
-
const
|
|
316
|
+
const maxFrame = Math.max(0, durationInFrames - 1);
|
|
317
|
+
const posterFrame = capturing ? 0 : Math.min(maxFrame, Math.round(durationInFrames * 0.35));
|
|
318
|
+
// rca/issue-video-artboard-frame-reset-on-edit — reopen on the Timeline's
|
|
319
|
+
// last known frame for this comp (survives the remount that tore this
|
|
320
|
+
// instance down), not the fixed poster-frame formula. Falls back to
|
|
321
|
+
// posterFrame on a genuinely first-ever mount (nothing recorded yet).
|
|
322
|
+
const initialFrame = capturing
|
|
305
323
|
? 0
|
|
306
|
-
:
|
|
324
|
+
: clamp(liveTimelineFrame.get(compId) ?? posterFrame, 0, maxFrame);
|
|
307
325
|
|
|
308
326
|
// Register with the seek bridge for the lifetime of this mount.
|
|
309
327
|
useEffect(() => {
|
|
@@ -353,8 +371,10 @@ export function VideoComp({
|
|
|
353
371
|
if (!p) return;
|
|
354
372
|
try {
|
|
355
373
|
if (m.dgn === 'timeline-seek' && typeof m.frame === 'number') {
|
|
374
|
+
const f = clamp(Math.round(m.frame), 0, Math.max(0, durationInFrames - 1));
|
|
356
375
|
p.pause();
|
|
357
|
-
p.seekTo(
|
|
376
|
+
p.seekTo(f);
|
|
377
|
+
liveTimelineFrame.set(compId, f);
|
|
358
378
|
} else if (m.dgn === 'timeline-play') {
|
|
359
379
|
p.play();
|
|
360
380
|
} else if (m.dgn === 'timeline-pause') {
|
|
@@ -382,7 +402,9 @@ export function VideoComp({
|
|
|
382
402
|
if (!p) return;
|
|
383
403
|
const onFrame = () => {
|
|
384
404
|
try {
|
|
385
|
-
|
|
405
|
+
const f = p.getCurrentFrame();
|
|
406
|
+
liveTimelineFrame.set(compId, f);
|
|
407
|
+
postToShell({ dgn: 'timeline-frame', id: compId, frame: f });
|
|
386
408
|
} catch {
|
|
387
409
|
/* ignore */
|
|
388
410
|
}
|
|
@@ -397,6 +419,25 @@ export function VideoComp({
|
|
|
397
419
|
};
|
|
398
420
|
}, [compId]);
|
|
399
421
|
|
|
422
|
+
// iframe → shell: with loop off (now the default), the Player stops itself
|
|
423
|
+
// at the last frame — nothing else tells the Timeline panel's Play/Pause
|
|
424
|
+
// button to flip back to Play, so it reads "still playing" forever. Mirror
|
|
425
|
+
// the Player's own `ended` event so the shell can resync (rca/issue-video-
|
|
426
|
+
// artboard-loop-defaults-on).
|
|
427
|
+
useEffect(() => {
|
|
428
|
+
const p = ref.current;
|
|
429
|
+
if (!p) return;
|
|
430
|
+
const onEnded = () => postToShell({ dgn: 'timeline-ended', id: compId });
|
|
431
|
+
p.addEventListener('ended', onEnded);
|
|
432
|
+
return () => {
|
|
433
|
+
try {
|
|
434
|
+
p.removeEventListener('ended', onEnded);
|
|
435
|
+
} catch {
|
|
436
|
+
/* ignore */
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
}, [compId]);
|
|
440
|
+
|
|
400
441
|
const style = useMemo(() => ({ width: '100%', height: '100%', display: 'block' as const }), []);
|
|
401
442
|
|
|
402
443
|
return (
|
|
@@ -416,7 +457,7 @@ export function VideoComp({
|
|
|
416
457
|
controls={showControls}
|
|
417
458
|
loop={loopState}
|
|
418
459
|
autoPlay={play}
|
|
419
|
-
initialFrame={
|
|
460
|
+
initialFrame={initialFrame}
|
|
420
461
|
// Clicking the artboard must NOT toggle playback — it selects elements
|
|
421
462
|
// for editing (the whole point of a canvas). Play only via the explicit
|
|
422
463
|
// transport button (Player controls / Timeline panel). Same for the
|
|
@@ -1,6 +1,155 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./whats-new.schema.json",
|
|
3
3
|
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"id": "bring-your-brand",
|
|
6
|
+
"version": "0.44.0",
|
|
7
|
+
"date": "2026-07-14",
|
|
8
|
+
"kind": "feature",
|
|
9
|
+
"title": "Bring your existing brand into Maude",
|
|
10
|
+
"summary": "Have a logo already? Upload it from the Quick setup checklist and Maude pulls out its color palette (and any recognizable font names) to seed a new design system — nothing is applied automatically, you confirm every choice during setup. Works with SVG logos; safety-checked before anything touches your project.",
|
|
11
|
+
"surface": "design-ui",
|
|
12
|
+
"tour": [
|
|
13
|
+
{
|
|
14
|
+
"target": "[data-testid=\"onboarding-bring-brand\"]",
|
|
15
|
+
"title": "Bring my existing brand",
|
|
16
|
+
"body": "Upload a logo SVG to seed a new design system's colors and fonts from it."
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "inspector-designer-mode",
|
|
22
|
+
"version": "0.44.0",
|
|
23
|
+
"date": "2026-07-14",
|
|
24
|
+
"kind": "feature",
|
|
25
|
+
"title": "A Figma-friendly view of the CSS panel",
|
|
26
|
+
"summary": "The Inspector now speaks two languages. Advanced keeps the real CSS property names; Designer regroups the exact same controls into Figma-familiar sections — Fill, Stroke, Corner radius, Auto layout, Effects, Opacity, Text — and relabels the rows, so you can style without thinking in CSS. Flip between them from the small toggle in the panel's top-right corner, or set a default in Settings → Appearance. Same live edits underneath, and a value set in one view reads back correctly in the other. New in both views: Blur and Blend controls, plus a single 9-point pad for auto-layout alignment.",
|
|
27
|
+
"surface": "design-ui",
|
|
28
|
+
"tour": [
|
|
29
|
+
{
|
|
30
|
+
"target": "[data-tour=\"cp-mode\"]",
|
|
31
|
+
"title": "Advanced or Designer",
|
|
32
|
+
"body": "Toggle the CSS panel between raw property names and Figma-style vocabulary. Your choice is remembered — you can also set it in Settings → Appearance.",
|
|
33
|
+
"placement": "left",
|
|
34
|
+
"inspector": true,
|
|
35
|
+
"tab": "css",
|
|
36
|
+
"requireSelection": true
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "watch-the-intro",
|
|
42
|
+
"version": "0.44.0",
|
|
43
|
+
"date": "2026-07-14",
|
|
44
|
+
"kind": "feature",
|
|
45
|
+
"title": "Watch the intro, right inside Maude",
|
|
46
|
+
"summary": "There's now a short product showreel (about a minute and a half) you can watch without leaving the app — Help → Watch the intro, or the same button on the welcome screen the first time you open Maude. It walks through the whole loop: a design system built from a conversation, the infinite canvas, pointing and commenting to direct an AI edit, live multiplayer, and shipping the result. Also lands as its own canvas (Maude Explainer) if you want to open it in the canvas browser like anything else.",
|
|
47
|
+
"surface": "design-ui",
|
|
48
|
+
"tour": [
|
|
49
|
+
{
|
|
50
|
+
"target": "[data-tour=\"help\"]",
|
|
51
|
+
"title": "Watch the intro",
|
|
52
|
+
"body": "Help → Watch the intro plays the full showreel without leaving Maude."
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"id": "bulk-media-insert",
|
|
58
|
+
"version": "0.44.0",
|
|
59
|
+
"date": "2026-07-14",
|
|
60
|
+
"kind": "feature",
|
|
61
|
+
"title": "Insert several photos at once",
|
|
62
|
+
"summary": "The media picker now supports multi-select — pick several photos (or a mix of photos, videos, and audio) in one go instead of one at a time. Choose whether they land inside your artboard or float on the canvas as annotations; the picker figures out the sensible default (video and audio always go on the canvas, since only images can drop into an artboard) and lets you switch. Dragging several files from Finder onto the canvas at once is also more reliable now — every dropped file lands, even in a large batch.",
|
|
63
|
+
"surface": "design-ui"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "ai-video-generation",
|
|
67
|
+
"version": "0.44.0",
|
|
68
|
+
"date": "2026-07-14",
|
|
69
|
+
"kind": "feature",
|
|
70
|
+
"title": "Generate video clips for your reels",
|
|
71
|
+
"summary": "The BYOK generator now makes video. Bring your own Google key and generate a clip with Veo — a text prompt (\"slow drone push over an alpine lake at dawn\"), or seed it from a still you already generated so the clip matches your hero's look. The clip lands in your assets like any other footage, and Maude treats it as first-class: when you build a reel it watches the generated clip alongside your real footage and places it as a beat, so you can fill a missing shot without hand-sourcing one. Video takes a few minutes and runs in the background — you'll get the finished clip when it's ready. Add your key under File → Settings — AI generation (⌘,); it stays on your machine.",
|
|
72
|
+
"surface": "design-ui"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"id": "ai-audio-generation",
|
|
76
|
+
"version": "0.44.0",
|
|
77
|
+
"date": "2026-07-14",
|
|
78
|
+
"kind": "feature",
|
|
79
|
+
"title": "Generate music, voiceover & subtitles",
|
|
80
|
+
"summary": "The BYOK generator now does audio. Bring your own ElevenLabs key and generate a music bed, sound effects, or a text-to-speech voiceover — one key covers the whole stack — and the track lands in your assets ready to drop under a reel. Before you spend credits on a music or SFX track, Maude searches audio you've already made (and your own ElevenLabs history — re-downloading it costs nothing) and offers a match to reuse. Subtitles are free and need no key at all: `maude design transcribe` runs whisper.cpp locally on any clip and writes word-timed SRT/VTT captions. Local setup is one click — Settings → Subtitles → Download model — and Maude auto-converts video containers (no ffmpeg wrangling) and picks the model for you. You pick the subtitle engine — local whisper, ElevenLabs Scribe, or Groq — in Settings; it's an explicit choice, so Maude never silently switches to a paid cloud engine behind your back. In a reel, generated music/voiceover become layered audio tracks (the music ducks under the voice) and the subtitles become a caption track that renders right on the video. Add your keys under File → Settings — AI generation (⌘,); they're stored only on your machine.",
|
|
81
|
+
"surface": "design-ui"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"id": "ai-media-generation",
|
|
85
|
+
"version": "0.44.0",
|
|
86
|
+
"date": "2026-07-14",
|
|
87
|
+
"kind": "feature",
|
|
88
|
+
"title": "Generate images with your own AI key",
|
|
89
|
+
"summary": "Bring your own Google (Nano Banana) API key and generate images right inside Maude — and the image lands straight on your canvas, not in a dead-end dialog. Use the Generate action (⌘K → \"Generate with AI\"), the command line, or just ask in the chat panel (\"generate a hero image of a mountain lake\"); the finished picture drops onto the artboard you're looking at. Add your key under File → Settings — AI generation (⌘,); it's stored only on your machine, sent straight to the provider, and never touches a canvas or your git history. Want to change a generated image? Ask to edit it (\"make the sky purple\") for a fresh AI-edited version, or fine-tune it in the Photo tab — every result is a normal asset you can place, edit, and export. Audio and video generation are on the way.",
|
|
90
|
+
"surface": "design-ui",
|
|
91
|
+
"tour": [
|
|
92
|
+
{
|
|
93
|
+
"target": "[data-tour=\"menubar-file\"]",
|
|
94
|
+
"title": "AI generation settings",
|
|
95
|
+
"body": "Open File → Settings — AI generation (⌘,) to add your provider key, then Generate with AI from the ⌘K palette.",
|
|
96
|
+
"placement": "bottom"
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "photo-editor",
|
|
102
|
+
"version": "0.43.0",
|
|
103
|
+
"date": "2026-07-10",
|
|
104
|
+
"kind": "feature",
|
|
105
|
+
"title": "Edit photos right on the canvas",
|
|
106
|
+
"summary": "A new Photo tab in the Inspector lets you tune any photo on your canvas — brightness, contrast, saturation, exposure, hue, sepia, grayscale, duotone, grain, pattern overlays, and vignette/reveal masks — with a live preview, whether it's an image you placed in an artboard or one you dropped/pasted onto the canvas. One click removes the background entirely (runs in your browser, no upload). Reach it from the Inspector's Photo tab or right-click \"Edit Photo…\". Every edit is also scriptable headlessly via /design:photo, so an agent can tune a photo without touching a slider.",
|
|
107
|
+
"surface": "design-ui",
|
|
108
|
+
"tour": [
|
|
109
|
+
{
|
|
110
|
+
"target": "[data-tour=\"inspector-tabs\"]",
|
|
111
|
+
"title": "Photo tab",
|
|
112
|
+
"body": "Select any photo on the canvas and a Photo tab appears here — adjustments, duotone, grain, pattern, masks, and one-click background removal.",
|
|
113
|
+
"placement": "bottom"
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "footage-analysis-director-reel",
|
|
119
|
+
"version": "0.43.0",
|
|
120
|
+
"date": "2026-07-10",
|
|
121
|
+
"kind": "feature",
|
|
122
|
+
"title": "Turn a folder of clips into a cut — Maude watches your footage first",
|
|
123
|
+
"summary": "New /design:reel: point Maude at a folder of raw video (or the clips already on your canvas) and it actually WATCHES the footage first — pulling keyframes from each clip to find the good shots and read its character — then directs them like an editor into a graphics-laden cut with titles and transitions, ready to scrub on the Timeline and export to MP4. It can use several moments from one clip, orders them so they tell a story, and needs no extra install (frames are decoded in the browser, no ffmpeg). Analysis is vision-only; drop in a music track and it rides under the finished cut.",
|
|
124
|
+
"surface": "design-ui"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"id": "ssh-remote-publish-and-pr-flow",
|
|
128
|
+
"version": "0.43.0",
|
|
129
|
+
"date": "2026-07-10",
|
|
130
|
+
"kind": "feature",
|
|
131
|
+
"title": "Share to a protected branch — via a pull request",
|
|
132
|
+
"summary": "On a GitHub project, \"Add to Shared version\" now pushes your draft and opens a pull request into main, so it works even when main is protected and a direct push would be rejected — the pull-request link opens right from the dialog. Publishing and getting the latest now work on SSH remotes too, and a blue \"Get latest\" button appears in the dock the moment a teammate's work is ahead, so you're nudged to pull without hunting for it.",
|
|
133
|
+
"surface": "design-ui"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "unified-text-editing",
|
|
137
|
+
"version": "0.43.0",
|
|
138
|
+
"date": "2026-07-10",
|
|
139
|
+
"kind": "feature",
|
|
140
|
+
"title": "Edit any text on the canvas, inline",
|
|
141
|
+
"summary": "Every kind of text on the canvas now edits the same predictable way — click to place a blinking caret, type, Enter to confirm, Shift+Enter for a new line — across an element's copy, shape and sticky labels, standalone text, and section titles. Text that's filled in from a list or variable (like cards built from data) is now editable in place too: double-click and change the words directly, and it's traced back to the right source. Only genuinely computed text still sends you to chat or /design:edit.",
|
|
142
|
+
"surface": "design-ui"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"id": "whiteboard-annotation-improvements",
|
|
146
|
+
"version": "0.43.0",
|
|
147
|
+
"date": "2026-07-10",
|
|
148
|
+
"kind": "feature",
|
|
149
|
+
"title": "Bulk resize, sticky authors & fun stickers",
|
|
150
|
+
"summary": "Select several stickies, shapes or images together and resize the whole group proportionally with live corner handles, instead of one at a time. Sticky notes now show who drew them with a name badge. Text editing got a real pass: a visible blinking caret everywhere you edit text, double-click places the caret where you clicked instead of selecting everything, hovering text shows a text cursor, and a new shape or sticky auto-focuses so you can start typing immediately. Also new: a searchable, FigJam-style sticker picker with genuinely fun (not emoji) bundled sticker packs, and /design:board now understands generation requests like \"make me a team sprint retro\" directly.",
|
|
151
|
+
"surface": "design-ui"
|
|
152
|
+
},
|
|
4
153
|
{
|
|
5
154
|
"id": "background-export-notification-center",
|
|
6
155
|
"version": "0.42.0",
|
package/apps/studio/ws.ts
CHANGED
|
@@ -222,6 +222,11 @@ export function createWs(
|
|
|
222
222
|
// clients only — same privileged-data class as the rest of this feed.
|
|
223
223
|
ctx.bus.on('export:job', (job: unknown) => broadcast({ type: 'export:job', payload: job }));
|
|
224
224
|
|
|
225
|
+
// feature-ai-media-generation (DDR-16x) — generation job queue state changes
|
|
226
|
+
// (queued → running → done/failed). Same privileged-data class + snapshot
|
|
227
|
+
// shape as export:job; the notification center reuses the export-center chrome.
|
|
228
|
+
ctx.bus.on('generate:job', (job: unknown) => broadcast({ type: 'generate:job', payload: job }));
|
|
229
|
+
|
|
225
230
|
// HMR broadcaster — turns fs:any change events into `canvas-hmr` messages.
|
|
226
231
|
// The iframe-side client (in _shell.html) decides reload strategy from `mode`.
|
|
227
232
|
// Uses broadcastHmr so the segregated canvas origin's HMR-only sockets get it.
|
package/cli/bin/maude.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
|
-
import {
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { resolvePkgRoot } from '../lib/pkg-root.mjs';
|
|
4
5
|
// maude — Maude CLI. Scaffold .ai workspace, run dev servers, manage config.
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { runUpdateCheck } from '../lib/update-check.mjs';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const PKG_ROOT =
|
|
8
|
+
// DDR-166 T0b — real-disk resolution, safe inside a `bun build --compile`
|
|
9
|
+
// standalone binary (see pkg-root.mjs's own doc comment for why the previous
|
|
10
|
+
// `dirname(fileURLToPath(import.meta.url))` walk-up broke there).
|
|
11
|
+
const PKG_ROOT = resolvePkgRoot();
|
|
12
12
|
|
|
13
13
|
const COMMANDS = {
|
|
14
14
|
init: () => import('../commands/init.mjs'),
|
package/cli/commands/design.mjs
CHANGED
|
@@ -47,6 +47,51 @@ const BIN_VERBS = new Set([
|
|
|
47
47
|
'chat-open',
|
|
48
48
|
'ensure-browser',
|
|
49
49
|
'fetch-asset',
|
|
50
|
+
// DDR-167 (Phase 3 / T10). `import-asset` is the LOCAL-file sibling of the
|
|
51
|
+
// URL-only `fetch-asset`: hardened SVG ingestion (allowlist DOM-sanitize +
|
|
52
|
+
// a real-browser execution canary). PDF import is wired but not yet
|
|
53
|
+
// available — see the DDR's addendum on why the planned rasterization
|
|
54
|
+
// mechanism doesn't work under browser automation.
|
|
55
|
+
'import-asset',
|
|
56
|
+
// DDR-172 (Phase 3 / T11). `import-tokens` is the token-file sibling of
|
|
57
|
+
// `import-asset`: parses W3C design-tokens / Style-Dictionary JSON or raw
|
|
58
|
+
// CSS custom properties, maps recognized tokens onto the DS CSS-variable
|
|
59
|
+
// contract, and patches (theme-block-scoped) or scaffolds the target
|
|
60
|
+
// design system. CLI-only — no HTTP route, no in-app panel.
|
|
61
|
+
'import-tokens',
|
|
62
|
+
// DDR-173 (Phase 3 / T12). `import-brand` extracts typed palette/font
|
|
63
|
+
// cues + a hardened logo asset from an already-DDR-167-sanitized SVG for
|
|
64
|
+
// `/design:setup-ds --from-brand` — never re-reads or re-sanitizes the
|
|
65
|
+
// original brand file (Decision 2: no parallel, ungated read path).
|
|
66
|
+
'import-brand',
|
|
67
|
+
// feature-photo-editor (Stage G). `photo-adjust` is the thin non-browser
|
|
68
|
+
// parametric verb (curl → /_api/photo-edit). `photo-bg-remove` is the
|
|
69
|
+
// client-side @imgly ML harness (throwaway proof canvas + agent-browser
|
|
70
|
+
// attribute poll — see photo-bg-remove.sh's header for why).
|
|
71
|
+
'photo-adjust',
|
|
72
|
+
'photo-bg-remove',
|
|
73
|
+
// feature-footage-analysis-director. `ingest-footage` copies a folder of raw
|
|
74
|
+
// clips into assets/ (content-addressed, magic-byte sniffed). `probe-footage`
|
|
75
|
+
// decodes ONE clip in headless Chromium → keyframe PNGs for the footage-analyst's
|
|
76
|
+
// vision pass. Neither boots the dev server (probe is server-independent — it
|
|
77
|
+
// reads the clip as a file:// resource).
|
|
78
|
+
'ingest-footage',
|
|
79
|
+
'probe-footage',
|
|
80
|
+
// feature-ai-media-generation (Phase 0, DDR-16x). `generate` is the thin
|
|
81
|
+
// non-browser BYOK verb (curl → /_api/generate-jobs → poll → print the
|
|
82
|
+
// produced /assets/<sha8>.<ext>). The provider call happens server-side (the
|
|
83
|
+
// sidecar resolves the key from the keychain / ~/.config/maude/keys.json).
|
|
84
|
+
'generate',
|
|
85
|
+
// feature-ai-media-generation (Phase 2, DDR-164). `transcribe` is the local,
|
|
86
|
+
// no-key subtitle verb: spawn whisper.cpp on an audio/video file → SRT/VTT via
|
|
87
|
+
// the shared captions.ts reflow. No dev server; whisper.cpp is a SOFT dep with
|
|
88
|
+
// ElevenLabs Scribe / Groq Whisper as the cloud fallback.
|
|
89
|
+
'transcribe',
|
|
90
|
+
// feature-ai-media-generation (Task 2.5, DDR-164). `audio-search` is the
|
|
91
|
+
// reuse-before-you-pay verb: search the project's own generated audio + the
|
|
92
|
+
// user's ElevenLabs history before spending credits on a new music/SFX/VO
|
|
93
|
+
// track. Runs server-side (key resolved by the sidecar); needs a dev server.
|
|
94
|
+
'audio-search',
|
|
50
95
|
]);
|
|
51
96
|
|
|
52
97
|
// Bin verbs that boot the dev-server (directly, or by shelling into server-up.sh).
|
|
@@ -140,7 +185,8 @@ Dev-tooling (dispatch to the dev-server bash helpers — DDR-062):
|
|
|
140
185
|
screenshot · server-up · prep · slug · bootstrap-check · runtime-health
|
|
141
186
|
smoke · canvas-edit · handoff · asset-sweep · visual-sanity · fetch-asset
|
|
142
187
|
draw-build · draw-proof · svg-optimize · to-lottie · read-annotations · annotate
|
|
143
|
-
canvas-rects
|
|
188
|
+
canvas-rects · ingest-footage · probe-footage
|
|
189
|
+
generate · transcribe · audio-search
|
|
144
190
|
Invoke the bundled helper of the same name. maude resolves it from its
|
|
145
191
|
own package root and sets CLAUDE_PLUGIN_ROOT for the child; stdout,
|
|
146
192
|
stderr, and exit code pass straight through (so command-substitution
|
|
@@ -453,7 +499,22 @@ async function runExport({ args }) {
|
|
|
453
499
|
}
|
|
454
500
|
|
|
455
501
|
const format = positional[0];
|
|
456
|
-
|
|
502
|
+
// Includes the temporal formats (DDR-148): mp4/webm/gif render through the
|
|
503
|
+
// capture spine, same POST /_api/export the UI ⌘E dialog uses. Video export
|
|
504
|
+
// is always artboard-scoped (the comp's registered meta drives fps/duration).
|
|
505
|
+
const VALID_FORMATS = new Set([
|
|
506
|
+
'png',
|
|
507
|
+
'pdf',
|
|
508
|
+
'svg',
|
|
509
|
+
'html',
|
|
510
|
+
'pptx',
|
|
511
|
+
'canva',
|
|
512
|
+
'zip',
|
|
513
|
+
'mp4',
|
|
514
|
+
'webm',
|
|
515
|
+
'gif',
|
|
516
|
+
]);
|
|
517
|
+
const VIDEO_FORMATS = new Set(['mp4', 'webm', 'gif']);
|
|
457
518
|
if (!format || !VALID_FORMATS.has(format)) {
|
|
458
519
|
process.stderr.write(
|
|
459
520
|
`maude design export: missing or unknown <format>. Try one of: ${Array.from(VALID_FORMATS).join(', ')}\n`
|
|
@@ -461,7 +522,10 @@ async function runExport({ args }) {
|
|
|
461
522
|
process.exit(2);
|
|
462
523
|
}
|
|
463
524
|
|
|
464
|
-
|
|
525
|
+
// Video formats default to artboard scope (the only scope video supports —
|
|
526
|
+
// scope.ts resolves the artboard under the active canvas); other formats keep
|
|
527
|
+
// the canvas-as-separate default.
|
|
528
|
+
const scope = flags.scope ?? (VIDEO_FORMATS.has(format) ? 'artboard' : 'canvas-as-separate');
|
|
465
529
|
const VALID_SCOPES = new Set(['selection', 'artboard', 'canvas-as-separate', 'project-raw']);
|
|
466
530
|
if (!VALID_SCOPES.has(scope)) {
|
|
467
531
|
process.stderr.write(`maude design export: unknown --scope "${scope}"\n`);
|
|
@@ -38,12 +38,14 @@ export function buildBlock(designRel = '.design') {
|
|
|
38
38
|
`${root}/_preflight.json`,
|
|
39
39
|
`${root}/_locator.json`, // regenerable slug→path index
|
|
40
40
|
`${root}/_export-history.json`,
|
|
41
|
+
`${root}/_generate-history.json`, // AI-media generation job ledger (regenerable — feature-ai-media-generation, DDR-16x)
|
|
41
42
|
// Per-machine / per-user dirs.
|
|
42
43
|
`${root}/_export-jobs/`, // background-export job byte store (regenerable — feature-background-export-notification-center)
|
|
43
44
|
`${root}/_state/`, // binary CRDT logs (regenerable from hub)
|
|
44
45
|
`${root}/_history/`,
|
|
45
46
|
`${root}/_trash/`, // soft-deleted canvases (recoverable locally — Phase 22 delete)
|
|
46
47
|
`${root}/_draw/`, // draw-agent proof canvases (regenerable — Phase 25)
|
|
48
|
+
`${root}/_photo/`, // photo-bg-remove headless proof canvases (regenerable — feature-photo-editor)
|
|
47
49
|
`${root}/_smoke/`, // batch-screenshot output (regenerable — DDR-021)
|
|
48
50
|
`${root}/_canvas-state/`, // per-machine canvas scratch + camera (`*.view.json`, DDR-115)
|
|
49
51
|
`${root}/_chat/`, // ACP transcripts (per-machine)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// pkg-root.mjs — real-disk `maude` package-root resolution, safe inside a
|
|
2
|
+
// `bun build --compile` standalone binary (DDR-166 T0b).
|
|
3
|
+
//
|
|
4
|
+
// `cli/bin/maude.mjs` originally computed PKG_ROOT via
|
|
5
|
+
// `dirname(fileURLToPath(import.meta.url))` walk-up — correct for the plain
|
|
6
|
+
// npm/node install, but the exact DDR-045 trap: inside a compiled binary,
|
|
7
|
+
// `import.meta.url` resolves to Bun's virtual filesystem (`/$bunfs/root` on
|
|
8
|
+
// POSIX, `B:/~BUN/root` on Windows), not the real on-disk location. Two
|
|
9
|
+
// dev-server releases (v0.18.0/v0.18.1) shipped broken because of this exact
|
|
10
|
+
// bug class before DDR-045 fixed it there. This module mirrors that fix
|
|
11
|
+
// (`apps/studio/paths.ts` `resolveDevServerRoot`) for the CLI, independently
|
|
12
|
+
// — not by importing paths.ts directly, to keep the CLI's compiled binary
|
|
13
|
+
// decoupled from the dev-server's module graph.
|
|
14
|
+
|
|
15
|
+
import { existsSync, realpathSync } from 'node:fs';
|
|
16
|
+
import { dirname, join } from 'node:path';
|
|
17
|
+
import { fileURLToPath } from 'node:url';
|
|
18
|
+
|
|
19
|
+
function isVirtualBunfsPath(p) {
|
|
20
|
+
return p !== null && (p.startsWith('/$bunfs') || p.startsWith('B:/~BUN'));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** True inside a `bun build --compile` standalone binary. Mirrors `apps/studio/paths.ts`'s `IS_COMPILED_BINARY`. */
|
|
24
|
+
export function isCompiledBinary() {
|
|
25
|
+
return isVirtualBunfsPath(getImportMetaDir());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getImportMetaDir() {
|
|
29
|
+
try {
|
|
30
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Anchor: `apps/studio/bin/screenshot.sh` is present in every real maude
|
|
38
|
+
* package root (dev tree, npm tarball, and the Tauri desktop `Resources/`
|
|
39
|
+
* bundle all ship it) and nowhere else — unique enough to identify the
|
|
40
|
+
* package root without also requiring `package.json` (npm tarballs can drop
|
|
41
|
+
* nested workspace `package.json` files, the exact false-negative DDR-045's
|
|
42
|
+
* own retro already documents for the dev-server's analogous check).
|
|
43
|
+
*/
|
|
44
|
+
export function isPkgRoot(dir) {
|
|
45
|
+
// Both anchors, not just one: `apps/studio/bin/screenshot.sh` ALONE is a
|
|
46
|
+
// false-positive inside the Tauri desktop build — `stage-resources.mjs`
|
|
47
|
+
// stages a full working copy of `apps/studio` (dev-server + bin scripts)
|
|
48
|
+
// into `target/debug/apps/studio/` for the sidecar's own runtime
|
|
49
|
+
// resolution, but that staged copy has no `cli/` — walking up from a
|
|
50
|
+
// compiled `maude` binary placed at `target/debug/maude` matched THAT
|
|
51
|
+
// copy first and stopped one level too early (caught by live testing
|
|
52
|
+
// against the real Tauri build, not a synthetic path). `cli/commands/
|
|
53
|
+
// design.mjs` only exists in a genuine package root.
|
|
54
|
+
return (
|
|
55
|
+
existsSync(join(dir, 'apps', 'studio', 'bin', 'screenshot.sh')) &&
|
|
56
|
+
existsSync(join(dir, 'cli', 'commands', 'design.mjs'))
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
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).
|
|
69
|
+
*/
|
|
70
|
+
export function resolvePkgRoot() {
|
|
71
|
+
const override = process.env.MAUDE_PKG_ROOT;
|
|
72
|
+
if (override && !isVirtualBunfsPath(override) && isPkgRoot(override)) return override;
|
|
73
|
+
|
|
74
|
+
const importDir = getImportMetaDir();
|
|
75
|
+
if (importDir && !isVirtualBunfsPath(importDir)) {
|
|
76
|
+
// Dev-mode: cli/bin/maude.mjs is 2 levels under the package root.
|
|
77
|
+
const candidate = join(importDir, '..', '..');
|
|
78
|
+
if (isPkgRoot(candidate)) return candidate;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// `process.execPath` is the path AS INVOKED — when launched through a
|
|
82
|
+
// symlink (DDR-166 T0b stages exactly this: sidecar.rs's narrow bin-link
|
|
83
|
+
// dir), it's the symlink's own path, not the real target, and walking up
|
|
84
|
+
// from there (e.g. ~/Library/Caches/…/bin-link/) never reaches the repo
|
|
85
|
+
// root. Dereference first. Falls back to the raw path if the file somehow
|
|
86
|
+
// doesn't exist (shouldn't happen — we ARE that running process).
|
|
87
|
+
let cur;
|
|
88
|
+
try {
|
|
89
|
+
cur = dirname(realpathSync(process.execPath));
|
|
90
|
+
} catch {
|
|
91
|
+
cur = dirname(process.execPath);
|
|
92
|
+
}
|
|
93
|
+
for (let i = 0; i < 10; i++) {
|
|
94
|
+
if (isPkgRoot(cur)) return cur;
|
|
95
|
+
const parent = dirname(cur);
|
|
96
|
+
if (parent === cur) break;
|
|
97
|
+
cur = parent;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Final fallback for unanchored test contexts — callers should expect
|
|
101
|
+
// existsSync-based lookups to fail and surface a clear error, same
|
|
102
|
+
// contract as paths.ts's own resolver. Never join a VIRTUAL importDir here
|
|
103
|
+
// (`/$bunfs/root/../..` collapses to `/` via path.join — a real bug an
|
|
104
|
+
// earlier draft of this function had, caught by testing against an
|
|
105
|
+
// unanchored compile output before wiring this into Tauri).
|
|
106
|
+
return dirname(process.execPath);
|
|
107
|
+
}
|