@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
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
// BrandUploadPanel — T12 (DDR-173). The in-app "Bring my existing brand"
|
|
2
|
+
// panel: upload a logo file → DDR-167 sanitize (`POST /_api/import-asset`)
|
|
3
|
+
// → DDR-173 typed-cue extraction (`POST /_api/import-brand`) → show the
|
|
4
|
+
// palette/fonts/logo the user can carry into `/design:setup-ds --from-brand`.
|
|
5
|
+
//
|
|
6
|
+
// Client never sends a filesystem PATH to either route — only bytes (native:
|
|
7
|
+
// via the existing `pick_media_file` Tauri command, which reads the file in
|
|
8
|
+
// Rust and returns bytes over IPC, mirroring app.jsx's `openFilePickerNative`;
|
|
9
|
+
// browser: via a plain `<input type=file>` + FileReader). This mirrors
|
|
10
|
+
// DDR-167's own entry-point trust table: "no server-side path resolution at
|
|
11
|
+
// all — the client never sends a path string, only bytes over loopback HTTP."
|
|
12
|
+
|
|
13
|
+
import { useRef, useState } from 'react';
|
|
14
|
+
import { isNativeApp, pickMediaFile } from '../github.js';
|
|
15
|
+
|
|
16
|
+
async function readFileAsArrayBuffer(file) {
|
|
17
|
+
return new Promise((resolvePromise, reject) => {
|
|
18
|
+
const reader = new FileReader();
|
|
19
|
+
reader.onload = () => resolvePromise(reader.result);
|
|
20
|
+
reader.onerror = () => reject(reader.error || new Error('file read failed'));
|
|
21
|
+
reader.readAsArrayBuffer(file);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Upload + extract. Returns `{ palette, fonts, logoRef, logoRasterRef, hadWordmarkText }` or throws. */
|
|
26
|
+
async function ingestBrandFile(bytes) {
|
|
27
|
+
const importAssetRes = await fetch('/_api/import-asset', {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: { 'X-Import-Kind': 'svg' },
|
|
30
|
+
body: bytes,
|
|
31
|
+
});
|
|
32
|
+
const importAssetBody = await importAssetRes.json().catch(() => ({}));
|
|
33
|
+
if (!importAssetRes.ok || !importAssetBody.ok) {
|
|
34
|
+
throw new Error(importAssetBody.error || `import failed (HTTP ${importAssetRes.status})`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const importBrandRes = await fetch('/_api/import-brand', {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'Content-Type': 'application/json' },
|
|
40
|
+
body: JSON.stringify({ assetPath: importAssetBody.path }),
|
|
41
|
+
});
|
|
42
|
+
const importBrandBody = await importBrandRes.json().catch(() => ({}));
|
|
43
|
+
if (!importBrandRes.ok || !importBrandBody.ok) {
|
|
44
|
+
throw new Error(importBrandBody.error || `extraction failed (HTTP ${importBrandRes.status})`);
|
|
45
|
+
}
|
|
46
|
+
return importBrandBody;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function PaletteSwatches({ palette }) {
|
|
50
|
+
if (!palette?.length) {
|
|
51
|
+
return <p className="brand-up-empty">No color values could be extracted from this file.</p>;
|
|
52
|
+
}
|
|
53
|
+
return (
|
|
54
|
+
<ul className="brand-up-swatches" data-testid="brand-up-palette">
|
|
55
|
+
{palette.map((color) => (
|
|
56
|
+
<li key={color} className="brand-up-swatch" title={color}>
|
|
57
|
+
<span className="brand-up-swatch-chip" style={{ background: color }} aria-hidden="true" />
|
|
58
|
+
<span className="brand-up-swatch-value">{color}</span>
|
|
59
|
+
</li>
|
|
60
|
+
))}
|
|
61
|
+
</ul>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function FontList({ fonts }) {
|
|
66
|
+
if (!fonts?.length) {
|
|
67
|
+
return (
|
|
68
|
+
<p className="brand-up-empty">
|
|
69
|
+
No recognized font names found — this is normal (font names inside the logo's own text are
|
|
70
|
+
stripped for safety before extraction; the design system's typography will still be
|
|
71
|
+
researched from your brief).
|
|
72
|
+
</p>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return (
|
|
76
|
+
<ul className="brand-up-fonts" data-testid="brand-up-fonts">
|
|
77
|
+
{fonts.map((f) => (
|
|
78
|
+
<li key={f} className="brand-up-font-chip">
|
|
79
|
+
{f}
|
|
80
|
+
</li>
|
|
81
|
+
))}
|
|
82
|
+
</ul>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default function BrandUploadPanel({ open, onClose }) {
|
|
87
|
+
const [busy, setBusy] = useState(false);
|
|
88
|
+
const [err, setErr] = useState(null);
|
|
89
|
+
const [result, setResult] = useState(null); // ingestBrandFile() response
|
|
90
|
+
const fileInputRef = useRef(null);
|
|
91
|
+
|
|
92
|
+
const runIngest = async (bytes) => {
|
|
93
|
+
setBusy(true);
|
|
94
|
+
setErr(null);
|
|
95
|
+
setResult(null);
|
|
96
|
+
try {
|
|
97
|
+
const r = await ingestBrandFile(bytes);
|
|
98
|
+
setResult(r);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
setErr(e?.message || 'upload failed');
|
|
101
|
+
} finally {
|
|
102
|
+
setBusy(false);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const pickNative = async () => {
|
|
107
|
+
setBusy(true);
|
|
108
|
+
setErr(null);
|
|
109
|
+
try {
|
|
110
|
+
const picked = await pickMediaFile();
|
|
111
|
+
if (!picked?.bytes) {
|
|
112
|
+
setBusy(false);
|
|
113
|
+
return; // user cancelled
|
|
114
|
+
}
|
|
115
|
+
await runIngest(new Blob([new Uint8Array(picked.bytes)]));
|
|
116
|
+
} catch (e) {
|
|
117
|
+
setErr(e?.message || 'open failed');
|
|
118
|
+
setBusy(false);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const pickBrowser = () => fileInputRef.current?.click();
|
|
123
|
+
|
|
124
|
+
const onBrowserFileChosen = async (e) => {
|
|
125
|
+
const file = e.target.files?.[0];
|
|
126
|
+
e.target.value = ''; // allow re-picking the same file
|
|
127
|
+
if (!file) return;
|
|
128
|
+
const buf = await readFileAsArrayBuffer(file);
|
|
129
|
+
await runIngest(new Blob([buf]));
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
if (!open) return null;
|
|
133
|
+
|
|
134
|
+
return (
|
|
135
|
+
<div
|
|
136
|
+
className="help-modal-backdrop"
|
|
137
|
+
role="presentation"
|
|
138
|
+
onMouseDown={(e) => {
|
|
139
|
+
if (e.target === e.currentTarget) onClose();
|
|
140
|
+
}}
|
|
141
|
+
>
|
|
142
|
+
<div
|
|
143
|
+
className="help-modal brand-up-modal"
|
|
144
|
+
role="dialog"
|
|
145
|
+
aria-modal="true"
|
|
146
|
+
aria-labelledby="brand-up-modal-title"
|
|
147
|
+
>
|
|
148
|
+
<header className="help-modal-hd">
|
|
149
|
+
<span className="title" id="brand-up-modal-title">
|
|
150
|
+
Bring my existing brand
|
|
151
|
+
</span>
|
|
152
|
+
<button type="button" className="help-modal-close" aria-label="Close (Esc)" onClick={onClose}>
|
|
153
|
+
×
|
|
154
|
+
</button>
|
|
155
|
+
</header>
|
|
156
|
+
<div className="help-modal-body">
|
|
157
|
+
<p className="brand-up-note">
|
|
158
|
+
Upload your logo (SVG) and Maude will pull out its color palette to seed your design
|
|
159
|
+
system — nothing here is final, you'll confirm every choice during setup.
|
|
160
|
+
</p>
|
|
161
|
+
|
|
162
|
+
{!result && (
|
|
163
|
+
<div className="brand-up-pick">
|
|
164
|
+
<button
|
|
165
|
+
type="button"
|
|
166
|
+
className="btn btn--primary btn--sm"
|
|
167
|
+
data-testid="brand-up-pick-file"
|
|
168
|
+
disabled={busy}
|
|
169
|
+
onClick={isNativeApp() ? pickNative : pickBrowser}
|
|
170
|
+
>
|
|
171
|
+
{busy ? 'Working…' : 'Choose logo file…'}
|
|
172
|
+
</button>
|
|
173
|
+
<input
|
|
174
|
+
ref={fileInputRef}
|
|
175
|
+
type="file"
|
|
176
|
+
accept="image/svg+xml,.svg"
|
|
177
|
+
style={{ display: 'none' }}
|
|
178
|
+
onChange={onBrowserFileChosen}
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
)}
|
|
182
|
+
|
|
183
|
+
{err && (
|
|
184
|
+
<p className="brand-up-error" data-testid="brand-up-error" role="alert">
|
|
185
|
+
{err}
|
|
186
|
+
</p>
|
|
187
|
+
)}
|
|
188
|
+
|
|
189
|
+
{result && (
|
|
190
|
+
<div className="brand-up-result" data-testid="brand-up-result">
|
|
191
|
+
<img
|
|
192
|
+
className="brand-up-preview"
|
|
193
|
+
src={`/${result.logoRasterRef || result.logoRef}`}
|
|
194
|
+
alt="Uploaded logo preview"
|
|
195
|
+
/>
|
|
196
|
+
<h4 className="brand-up-sechd">Palette</h4>
|
|
197
|
+
<PaletteSwatches palette={result.palette} />
|
|
198
|
+
<h4 className="brand-up-sechd">Fonts</h4>
|
|
199
|
+
<FontList fonts={result.fonts} />
|
|
200
|
+
<p className="brand-up-nextstep">
|
|
201
|
+
Next: run <code>/design:setup-ds --from-brand {result.logoRef}</code> in the AI chat
|
|
202
|
+
(or your terminal) to build a design system seeded from this upload.
|
|
203
|
+
</p>
|
|
204
|
+
<div className="brand-up-actions">
|
|
205
|
+
<button
|
|
206
|
+
type="button"
|
|
207
|
+
className="btn btn--primary btn--sm"
|
|
208
|
+
data-testid="brand-up-copy-command"
|
|
209
|
+
onClick={() =>
|
|
210
|
+
navigator.clipboard?.writeText(`/design:setup-ds --from-brand ${result.logoRef}`)
|
|
211
|
+
}
|
|
212
|
+
>
|
|
213
|
+
Copy command
|
|
214
|
+
</button>
|
|
215
|
+
<button
|
|
216
|
+
type="button"
|
|
217
|
+
className="btn btn--ghost btn--sm"
|
|
218
|
+
data-testid="brand-up-again"
|
|
219
|
+
onClick={() => {
|
|
220
|
+
setResult(null);
|
|
221
|
+
setErr(null);
|
|
222
|
+
}}
|
|
223
|
+
>
|
|
224
|
+
Upload a different file
|
|
225
|
+
</button>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
)}
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
@@ -870,7 +870,7 @@ function Composer({
|
|
|
870
870
|
);
|
|
871
871
|
|
|
872
872
|
return (
|
|
873
|
-
<div className="chat-composer">
|
|
873
|
+
<div className="chat-composer" data-testid="chat-composer">
|
|
874
874
|
<ThreadPrimitive.If running={false}>
|
|
875
875
|
{/* Context attachment chip (feature-acp-context-hardening) — the visible
|
|
876
876
|
reveal of the fenced <maude-context> block the send will prepend
|
|
@@ -986,37 +986,32 @@ function Composer({
|
|
|
986
986
|
);
|
|
987
987
|
}
|
|
988
988
|
|
|
989
|
-
|
|
989
|
+
// DDR-166 T0f — the guided, button-driven cold start. Every actionable step
|
|
990
|
+
// (install command, Sign in) now lives in ReadinessList itself; this shell no
|
|
991
|
+
// longer carries its own terminal-instruction copy, so there's nothing here to
|
|
992
|
+
// go stale relative to what the rows actually offer.
|
|
993
|
+
function NotConnected({ reason, readiness, readinessLoading, onRecheck }) {
|
|
990
994
|
return (
|
|
991
|
-
<div className="chat-disabled">
|
|
995
|
+
<div className="chat-disabled" data-testid="acp-not-connected">
|
|
992
996
|
<span className="chat-disabled-mark">
|
|
993
997
|
<Spark size={28} />
|
|
994
998
|
</span>
|
|
995
999
|
<div className="chat-disabled-title">AI editing isn't ready yet</div>
|
|
996
1000
|
<div className="chat-disabled-sub">
|
|
997
1001
|
{reason ? <p>{reason}</p> : null}
|
|
998
|
-
|
|
999
|
-
<p>AI editing pairs with a Claude Code you have installed. Here's what it still needs:</p>
|
|
1000
|
-
) : claudeMissing ? (
|
|
1001
|
-
<p>
|
|
1002
|
-
Install it with <code>npm i -g @anthropic-ai/claude-code</code>, then run{' '}
|
|
1003
|
-
<code>claude</code> and <code>/login</code> in a terminal.
|
|
1004
|
-
</p>
|
|
1005
|
-
) : (
|
|
1006
|
-
<p>
|
|
1007
|
-
Open a terminal, run <code>claude</code> and <code>/login</code>, then reopen this panel.
|
|
1008
|
-
</p>
|
|
1009
|
-
)}
|
|
1002
|
+
<p>AI editing pairs with a Claude Code you have installed. Here's what it still needs:</p>
|
|
1010
1003
|
</div>
|
|
1011
1004
|
{readiness ? (
|
|
1012
1005
|
<ReadinessList report={readiness} loading={readinessLoading} refresh={onRecheck} />
|
|
1013
|
-
) :
|
|
1006
|
+
) : (
|
|
1007
|
+
<p className="chat-disabled-sub">Checking what's needed…</p>
|
|
1008
|
+
)}
|
|
1014
1009
|
<div className="chat-trust">
|
|
1015
1010
|
<div className="chat-trust-row">
|
|
1016
1011
|
<Check /> Runs on your Pro/Max subscription
|
|
1017
1012
|
</div>
|
|
1018
1013
|
<div className="chat-trust-row">
|
|
1019
|
-
<Check />
|
|
1014
|
+
<Check /> Signs in via Claude Code's own login — Maude never sees your credentials
|
|
1020
1015
|
</div>
|
|
1021
1016
|
<div className="chat-trust-row">
|
|
1022
1017
|
<Check /> Never metered API billing
|
|
@@ -1200,25 +1195,13 @@ export default function ChatPanel({
|
|
|
1200
1195
|
}, [effort]);
|
|
1201
1196
|
|
|
1202
1197
|
// Availability is global (is claude installed) — a single probe, no connection.
|
|
1203
|
-
const [status, setStatus] = useState({ available: null, reason: undefined
|
|
1198
|
+
const [status, setStatus] = useState({ available: null, reason: undefined });
|
|
1204
1199
|
const probeStatus = useCallback(
|
|
1205
1200
|
() =>
|
|
1206
1201
|
fetch('/_api/acp/status')
|
|
1207
1202
|
.then((r) => r.json())
|
|
1208
|
-
.then((d) =>
|
|
1209
|
-
|
|
1210
|
-
available: d.available,
|
|
1211
|
-
reason: d.reason,
|
|
1212
|
-
claudeMissing: !!d.adapterEntry && !d.claudePath,
|
|
1213
|
-
})
|
|
1214
|
-
)
|
|
1215
|
-
.catch(() =>
|
|
1216
|
-
setStatus({
|
|
1217
|
-
available: false,
|
|
1218
|
-
reason: 'Could not reach the Claude bridge.',
|
|
1219
|
-
claudeMissing: false,
|
|
1220
|
-
})
|
|
1221
|
-
),
|
|
1203
|
+
.then((d) => setStatus({ available: d.available, reason: d.reason }))
|
|
1204
|
+
.catch(() => setStatus({ available: false, reason: 'Could not reach the Claude bridge.' })),
|
|
1222
1205
|
[]
|
|
1223
1206
|
);
|
|
1224
1207
|
useEffect(() => {
|
|
@@ -1509,7 +1492,6 @@ export default function ChatPanel({
|
|
|
1509
1492
|
{status.available === false ? (
|
|
1510
1493
|
<NotConnected
|
|
1511
1494
|
reason={status.reason}
|
|
1512
|
-
claudeMissing={status.claudeMissing}
|
|
1513
1495
|
readiness={readiness}
|
|
1514
1496
|
readinessLoading={readinessLoading}
|
|
1515
1497
|
onRecheck={recheck}
|
|
@@ -364,6 +364,14 @@ export default function GitPanel({
|
|
|
364
364
|
getLatest: true,
|
|
365
365
|
}
|
|
366
366
|
);
|
|
367
|
+
else if (kind === 'publish' && /protected branch|GH006/i.test(res.error || ''))
|
|
368
|
+
// A protected default branch rejects a direct Publish — point at the PR flow
|
|
369
|
+
// (DDR-162): the way to add work to a protected branch is a draft + a pull request.
|
|
370
|
+
setBanner({
|
|
371
|
+
variant: 'warn',
|
|
372
|
+
title: 'This branch is protected',
|
|
373
|
+
text: 'It needs a pull request. Switch to a draft, then use “Add to Shared version” to open one.',
|
|
374
|
+
});
|
|
367
375
|
else setBanner({ variant: 'error', text: res.error || 'Something went wrong.' });
|
|
368
376
|
return res;
|
|
369
377
|
} finally {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// The "Watch the intro" player (DDR-166 Phase 1 / T2). Plays the bundled
|
|
2
|
+
// showreel — served from Maude's OWN /_media/ route (paths.ts MEDIA_DIR,
|
|
3
|
+
// DDR-045), never the served project's .design/assets/ — so it's available
|
|
4
|
+
// identically whether a project is open or not. Reuses the shared help-modal
|
|
5
|
+
// chrome (backdrop + header + body), same as ReadinessDialog / What's New.
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
|
|
8
|
+
export default function IntroVideoDialog({ open, onClose }) {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (!open) return undefined;
|
|
11
|
+
const onKey = (e) => e.key === 'Escape' && onClose();
|
|
12
|
+
window.addEventListener('keydown', onKey);
|
|
13
|
+
return () => window.removeEventListener('keydown', onKey);
|
|
14
|
+
}, [open, onClose]);
|
|
15
|
+
if (!open) return null;
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
className="help-modal-backdrop"
|
|
19
|
+
role="presentation"
|
|
20
|
+
onMouseDown={(e) => {
|
|
21
|
+
if (e.target === e.currentTarget) onClose();
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
<div
|
|
25
|
+
className="help-modal help-modal--wide"
|
|
26
|
+
role="dialog"
|
|
27
|
+
aria-modal="true"
|
|
28
|
+
aria-labelledby="intro-video-title"
|
|
29
|
+
>
|
|
30
|
+
<header className="help-modal-hd">
|
|
31
|
+
<span className="title" id="intro-video-title">
|
|
32
|
+
Watch the intro
|
|
33
|
+
</span>
|
|
34
|
+
<button type="button" className="help-modal-close" aria-label="Close (Esc)" onClick={onClose}>
|
|
35
|
+
×
|
|
36
|
+
</button>
|
|
37
|
+
</header>
|
|
38
|
+
<div className="help-modal-body intro-video-body">
|
|
39
|
+
<video className="intro-video-el" src="/_media/intro.mp4" controls autoPlay playsInline />
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { useEffect, useRef, useState } from 'react';
|
|
14
14
|
|
|
15
15
|
import ReadinessList, { useReadiness } from './ReadinessList.jsx';
|
|
16
|
+
import IntroVideoDialog from './IntroVideoDialog.jsx';
|
|
16
17
|
import {
|
|
17
18
|
cloneRepo,
|
|
18
19
|
createProject,
|
|
@@ -51,6 +52,7 @@ function Icon({ name, size = 16, className }) {
|
|
|
51
52
|
external: (<><path d="M6 3.5H3.2A.7.7 0 0 0 2.5 4.2v8.6a.7.7 0 0 0 .7.7h8.6a.7.7 0 0 0 .7-.7V10" /><line x1="8" y1="8" x2="13" y2="3" /><polyline points="9.5 3 13 3 13 6.5" /></>),
|
|
52
53
|
back: <polyline points="10 3.5 5.5 8 10 12.5" />,
|
|
53
54
|
spinner: <path d="M8 2.2a5.8 5.8 0 1 0 5.8 5.8" />,
|
|
55
|
+
play: <polygon points="5 3.2 12.8 8 5 12.8" fill="currentColor" stroke="none" />,
|
|
54
56
|
}[name];
|
|
55
57
|
return (
|
|
56
58
|
<svg className={className} width={size} height={size} viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
@@ -179,13 +181,23 @@ function AiReadiness() {
|
|
|
179
181
|
|
|
180
182
|
// ── A · Welcome (door picker) ────────────────────────────────────────────────
|
|
181
183
|
function Welcome({ onGithub, onLocal, onHub, signing, signedIn, identity }) {
|
|
184
|
+
const [introOpen, setIntroOpen] = useState(false);
|
|
182
185
|
return (
|
|
183
186
|
<main className="ob-main">
|
|
184
187
|
<header className="ob-head">
|
|
185
188
|
<span className="ob-eyebrow">Welcome</span>
|
|
186
189
|
<h1>How would you like to start?</h1>
|
|
187
190
|
<p>{signedIn ? `You're signed in as @${identity?.login || 'GitHub'}. Open a project, or start a new one.` : "Most people sign in with GitHub — it's the simplest way to work with a team."}</p>
|
|
191
|
+
<button
|
|
192
|
+
type="button"
|
|
193
|
+
data-testid="onboarding-watch-intro"
|
|
194
|
+
className="ob-watch-intro"
|
|
195
|
+
onClick={() => setIntroOpen(true)}
|
|
196
|
+
>
|
|
197
|
+
<Icon name="play" size={13} /> Watch the intro
|
|
198
|
+
</button>
|
|
188
199
|
</header>
|
|
200
|
+
<IntroVideoDialog open={introOpen} onClose={() => setIntroOpen(false)} />
|
|
189
201
|
<div className="ob-doors">
|
|
190
202
|
<button type="button" data-testid="ob-door-github" className="ob-door ob-door--primary" aria-label="Continue with GitHub — recommended" onClick={onGithub} disabled={signing}>
|
|
191
203
|
<span className="ob-door-icon ob-door-icon--gh"><GitHubMark size={26} /></span>
|