@1agh/maude 0.43.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/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 +396 -46
- package/apps/studio/api.ts +395 -2
- 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/_transcribe.mjs +419 -0
- package/apps/studio/bin/_transcribe.test.mjs +80 -0
- 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/photo-bg-remove.sh +119 -21
- package/apps/studio/bin/transcribe.sh +39 -0
- package/apps/studio/canvas-edit.ts +197 -2
- package/apps/studio/canvas-lib.tsx +115 -6
- package/apps/studio/client/app.jsx +1954 -685
- package/apps/studio/client/generate-dialog.jsx +352 -0
- package/apps/studio/client/github.js +14 -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/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/SettingsPanel.jsx +828 -0
- package/apps/studio/client/panels/SetupChecklist.jsx +223 -0
- package/apps/studio/client/photo-knobs.jsx +167 -172
- package/apps/studio/client/styles/3-shell-maude.css +334 -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/config.schema.json +70 -0
- package/apps/studio/context-menu.tsx +11 -2
- package/apps/studio/context.ts +16 -0
- package/apps/studio/design-setup-readiness.ts +115 -0
- package/apps/studio/dist/client.bundle.js +2097 -2088
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/draw/palette.ts +34 -0
- package/apps/studio/footage/schema.test.ts +92 -0
- package/apps/studio/footage/schema.ts +179 -1
- 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/service.ts +3 -1
- package/apps/studio/http.ts +867 -9
- package/apps/studio/media/intro.mp4 +0 -0
- package/apps/studio/media-commit-chain.ts +119 -0
- package/apps/studio/paths.ts +10 -0
- package/apps/studio/readiness.ts +108 -20
- package/apps/studio/scaffold-design.ts +1145 -0
- package/apps/studio/server.ts +13 -1
- package/apps/studio/test/_helpers.ts +15 -2
- package/apps/studio/test/acp-bridge.test.ts +34 -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/canvas-origin-gate.test.ts +37 -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/element-structural-edit.test.ts +108 -0
- package/apps/studio/test/fixtures/fake-claude-auth.mjs +13 -0
- package/apps/studio/test/generate-route.test.ts +106 -0
- 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/media-commit-chain.test.ts +210 -0
- package/apps/studio/test/photo-bg-remove-validation.test.ts +71 -0
- package/apps/studio/test/readiness.test.ts +13 -11
- package/apps/studio/test/scaffold-design.test.ts +122 -0
- package/apps/studio/test/tour-overlay.test.tsx +16 -0
- package/apps/studio/tool-palette.tsx +11 -6
- package/apps/studio/ui-prefs.ts +130 -0
- package/apps/studio/use-canvas-media-drop.tsx +4 -2
- package/apps/studio/use-chrome-visibility.tsx +8 -2
- package/apps/studio/whats-new.json +96 -0
- package/apps/studio/ws.ts +5 -0
- package/cli/bin/maude.mjs +6 -6
- package/cli/commands/design.mjs +33 -0
- package/cli/lib/gitignore-block.mjs +1 -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 +12 -10
- package/plugins/design/dependencies.json +18 -0
|
@@ -859,6 +859,12 @@
|
|
|
859
859
|
}
|
|
860
860
|
.help-modal-body::-webkit-scrollbar { width: 6px; }
|
|
861
861
|
.help-modal-body::-webkit-scrollbar-thumb { background: var(--u-border); }
|
|
862
|
+
|
|
863
|
+
/* Watch-the-intro player (DDR-166 Phase 1 / T2) — wider modal, no padding
|
|
864
|
+
around the video so it fills edge-to-edge. */
|
|
865
|
+
.help-modal--wide { width: min(960px, 100%); }
|
|
866
|
+
.intro-video-body { padding: 0; overflow: hidden; }
|
|
867
|
+
.intro-video-el { display: block; width: 100%; aspect-ratio: 16 / 9; background: #000; }
|
|
862
868
|
.help-modal-body details {
|
|
863
869
|
margin: 0 0 var(--u-s-2);
|
|
864
870
|
border-bottom: 1px solid var(--u-border-subtle);
|
|
@@ -1652,3 +1658,220 @@
|
|
|
1652
1658
|
background: var(--u-accent);
|
|
1653
1659
|
color: var(--u-accent-fg);
|
|
1654
1660
|
}
|
|
1661
|
+
|
|
1662
|
+
/* ── Settings — AI generation (feature-ai-media-generation, DDR-16x) ─────── */
|
|
1663
|
+
.st-settings-intro {
|
|
1664
|
+
font-size: var(--type-xs, 12px);
|
|
1665
|
+
color: var(--fg-3);
|
|
1666
|
+
line-height: 1.5;
|
|
1667
|
+
margin: 6px 0 12px;
|
|
1668
|
+
}
|
|
1669
|
+
.st-settings-intro code {
|
|
1670
|
+
font-family: var(--font-mono);
|
|
1671
|
+
font-size: 0.92em;
|
|
1672
|
+
color: var(--fg-2);
|
|
1673
|
+
}
|
|
1674
|
+
.st-provider-card {
|
|
1675
|
+
border: 1px solid var(--border-default);
|
|
1676
|
+
border-radius: var(--radius-sm);
|
|
1677
|
+
background: var(--bg-2);
|
|
1678
|
+
padding: 12px;
|
|
1679
|
+
margin-bottom: 10px;
|
|
1680
|
+
}
|
|
1681
|
+
.st-provider-hd {
|
|
1682
|
+
display: flex;
|
|
1683
|
+
align-items: center;
|
|
1684
|
+
gap: 8px;
|
|
1685
|
+
}
|
|
1686
|
+
.st-provider-name {
|
|
1687
|
+
font-family: var(--font-mono);
|
|
1688
|
+
font-size: var(--type-sm, 13px);
|
|
1689
|
+
color: var(--fg-1);
|
|
1690
|
+
font-weight: 600;
|
|
1691
|
+
}
|
|
1692
|
+
.st-provider-card .st-pill {
|
|
1693
|
+
display: inline-flex;
|
|
1694
|
+
align-items: center;
|
|
1695
|
+
gap: 3px;
|
|
1696
|
+
font-size: 10px;
|
|
1697
|
+
text-transform: uppercase;
|
|
1698
|
+
letter-spacing: 0.03em;
|
|
1699
|
+
color: var(--fg-3);
|
|
1700
|
+
border: 1px solid var(--border-default);
|
|
1701
|
+
border-radius: var(--radius-pill, 999px);
|
|
1702
|
+
padding: 1px 7px;
|
|
1703
|
+
}
|
|
1704
|
+
.st-provider-card .st-pill.is-local {
|
|
1705
|
+
color: var(--accent);
|
|
1706
|
+
border-color: var(--accent-muted, var(--accent));
|
|
1707
|
+
}
|
|
1708
|
+
.st-provider-configured {
|
|
1709
|
+
display: inline-flex;
|
|
1710
|
+
align-items: center;
|
|
1711
|
+
gap: 3px;
|
|
1712
|
+
margin-left: auto;
|
|
1713
|
+
font-size: 11px;
|
|
1714
|
+
color: var(--accent);
|
|
1715
|
+
}
|
|
1716
|
+
.st-provider-modalities {
|
|
1717
|
+
font-family: var(--font-mono);
|
|
1718
|
+
font-size: 11px;
|
|
1719
|
+
color: var(--fg-3);
|
|
1720
|
+
margin-top: 4px;
|
|
1721
|
+
}
|
|
1722
|
+
.st-provider-notes {
|
|
1723
|
+
font-size: 11px;
|
|
1724
|
+
color: var(--fg-3);
|
|
1725
|
+
line-height: 1.5;
|
|
1726
|
+
margin-top: 6px;
|
|
1727
|
+
}
|
|
1728
|
+
.st-provider-keylink {
|
|
1729
|
+
display: inline-flex;
|
|
1730
|
+
align-items: center;
|
|
1731
|
+
gap: 4px;
|
|
1732
|
+
font-size: 11px;
|
|
1733
|
+
color: var(--accent);
|
|
1734
|
+
text-decoration: none;
|
|
1735
|
+
margin-top: 6px;
|
|
1736
|
+
}
|
|
1737
|
+
.st-provider-keylink:hover {
|
|
1738
|
+
text-decoration: underline;
|
|
1739
|
+
}
|
|
1740
|
+
.st-provider-keyrow {
|
|
1741
|
+
display: flex;
|
|
1742
|
+
align-items: center;
|
|
1743
|
+
gap: 6px;
|
|
1744
|
+
margin-top: 10px;
|
|
1745
|
+
}
|
|
1746
|
+
.st-provider-keyinput {
|
|
1747
|
+
flex: 1;
|
|
1748
|
+
min-width: 0;
|
|
1749
|
+
}
|
|
1750
|
+
.st-provider-status {
|
|
1751
|
+
font-size: 11px;
|
|
1752
|
+
margin-top: 6px;
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
/* ── Transcription-engine selector (Task 2.6) ───────────────────────────── */
|
|
1756
|
+
.st-engine-radios {
|
|
1757
|
+
display: flex;
|
|
1758
|
+
flex-direction: column;
|
|
1759
|
+
gap: 6px;
|
|
1760
|
+
margin-top: 10px;
|
|
1761
|
+
}
|
|
1762
|
+
.st-engine-radio {
|
|
1763
|
+
display: flex;
|
|
1764
|
+
align-items: flex-start;
|
|
1765
|
+
gap: 9px;
|
|
1766
|
+
padding: 9px 11px;
|
|
1767
|
+
border: 1px solid var(--border-default);
|
|
1768
|
+
border-radius: var(--radius-sm);
|
|
1769
|
+
background: var(--bg-1);
|
|
1770
|
+
cursor: pointer;
|
|
1771
|
+
}
|
|
1772
|
+
.st-engine-radio.is-selected {
|
|
1773
|
+
border-color: var(--accent);
|
|
1774
|
+
background: var(--bg-2);
|
|
1775
|
+
}
|
|
1776
|
+
.st-engine-radio input {
|
|
1777
|
+
margin-top: 2px;
|
|
1778
|
+
accent-color: var(--accent);
|
|
1779
|
+
}
|
|
1780
|
+
.st-engine-radio-body {
|
|
1781
|
+
display: flex;
|
|
1782
|
+
flex-direction: column;
|
|
1783
|
+
gap: 2px;
|
|
1784
|
+
}
|
|
1785
|
+
.st-engine-radio-label {
|
|
1786
|
+
font-size: var(--type-sm, 13px);
|
|
1787
|
+
color: var(--fg-1);
|
|
1788
|
+
font-weight: 600;
|
|
1789
|
+
}
|
|
1790
|
+
.st-engine-radio-note {
|
|
1791
|
+
font-size: 11px;
|
|
1792
|
+
color: var(--fg-3);
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
/* ── Local whisper model download (Task 2.7) ────────────────────────────── */
|
|
1796
|
+
.st-model-list {
|
|
1797
|
+
display: flex;
|
|
1798
|
+
flex-direction: column;
|
|
1799
|
+
gap: 8px;
|
|
1800
|
+
margin-top: 10px;
|
|
1801
|
+
}
|
|
1802
|
+
.st-model-row {
|
|
1803
|
+
display: flex;
|
|
1804
|
+
align-items: flex-start;
|
|
1805
|
+
justify-content: space-between;
|
|
1806
|
+
gap: 10px;
|
|
1807
|
+
padding: 9px 11px;
|
|
1808
|
+
border: 1px solid var(--border-default);
|
|
1809
|
+
border-radius: var(--radius-sm);
|
|
1810
|
+
background: var(--bg-1);
|
|
1811
|
+
}
|
|
1812
|
+
.st-model-info {
|
|
1813
|
+
display: flex;
|
|
1814
|
+
flex-direction: column;
|
|
1815
|
+
gap: 3px;
|
|
1816
|
+
min-width: 0;
|
|
1817
|
+
}
|
|
1818
|
+
.st-model-label {
|
|
1819
|
+
display: flex;
|
|
1820
|
+
align-items: center;
|
|
1821
|
+
gap: 7px;
|
|
1822
|
+
flex-wrap: wrap;
|
|
1823
|
+
font-size: var(--type-sm, 13px);
|
|
1824
|
+
color: var(--fg-1);
|
|
1825
|
+
font-weight: 600;
|
|
1826
|
+
}
|
|
1827
|
+
.st-model-size {
|
|
1828
|
+
font-size: 11px;
|
|
1829
|
+
color: var(--fg-3);
|
|
1830
|
+
font-weight: 400;
|
|
1831
|
+
}
|
|
1832
|
+
.st-model-progress {
|
|
1833
|
+
font-size: 11px;
|
|
1834
|
+
color: var(--accent);
|
|
1835
|
+
font-variant-numeric: tabular-nums;
|
|
1836
|
+
}
|
|
1837
|
+
.st-model-actions {
|
|
1838
|
+
display: flex;
|
|
1839
|
+
align-items: center;
|
|
1840
|
+
gap: 8px;
|
|
1841
|
+
flex-shrink: 0;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
/* ── Generate dialog (feature-ai-media-generation, DDR-16x) ─────────────── */
|
|
1845
|
+
.st-gen-prompt {
|
|
1846
|
+
width: 100%;
|
|
1847
|
+
resize: vertical;
|
|
1848
|
+
min-height: 60px;
|
|
1849
|
+
font-family: var(--font-sans, system-ui, sans-serif);
|
|
1850
|
+
margin-bottom: 10px;
|
|
1851
|
+
}
|
|
1852
|
+
.st-gen-go {
|
|
1853
|
+
color: var(--accent);
|
|
1854
|
+
border-color: var(--accent-muted, var(--accent));
|
|
1855
|
+
}
|
|
1856
|
+
.st-gen-result {
|
|
1857
|
+
display: flex;
|
|
1858
|
+
gap: 10px;
|
|
1859
|
+
align-items: flex-start;
|
|
1860
|
+
margin-top: 12px;
|
|
1861
|
+
padding: 10px;
|
|
1862
|
+
border: 1px solid var(--border-default);
|
|
1863
|
+
border-radius: var(--radius-sm);
|
|
1864
|
+
background: var(--bg-2);
|
|
1865
|
+
}
|
|
1866
|
+
.st-gen-thumb {
|
|
1867
|
+
width: 96px;
|
|
1868
|
+
height: 96px;
|
|
1869
|
+
object-fit: cover;
|
|
1870
|
+
border-radius: var(--radius-sm);
|
|
1871
|
+
background: var(--bg-3);
|
|
1872
|
+
}
|
|
1873
|
+
.st-gen-result-actions {
|
|
1874
|
+
display: flex;
|
|
1875
|
+
flex-direction: column;
|
|
1876
|
+
gap: 6px;
|
|
1877
|
+
}
|
|
@@ -1181,7 +1181,93 @@
|
|
|
1181
1181
|
}
|
|
1182
1182
|
.rdy-copy:hover { color: var(--fg-0); background: var(--bg-3); }
|
|
1183
1183
|
.rdy-foot { display: flex; justify-content: flex-end; }
|
|
1184
|
+
/* DDR-166 T0c/T0d — verbatim install command + Sign-in action rows. */
|
|
1185
|
+
.rdy-cmd {
|
|
1186
|
+
margin-top: var(--space-2); display: flex; gap: var(--space-2);
|
|
1187
|
+
align-items: center; flex-wrap: wrap;
|
|
1188
|
+
}
|
|
1189
|
+
.rdy-cmd-tx {
|
|
1190
|
+
font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-0);
|
|
1191
|
+
background: var(--bg-3); padding: var(--space-1) var(--space-2);
|
|
1192
|
+
border-radius: var(--radius-xs); overflow-wrap: anywhere; flex: 1 1 auto;
|
|
1193
|
+
}
|
|
1194
|
+
.rdy-fix-tx--err { color: var(--status-error); }
|
|
1195
|
+
.rdy-fallback-label { display: block; margin-top: var(--space-2); color: var(--fg-3); }
|
|
1196
|
+
/* DDR-166 Decision 3 — the resolved-binary disclosure shown before Sign-in. */
|
|
1197
|
+
.rdy-resolved-path { display: block; margin-top: var(--space-2); color: var(--fg-3); word-break: break-all; }
|
|
1198
|
+
.rdy-resolved-path code { font-family: var(--font-mono); color: var(--fg-1); }
|
|
1199
|
+
.rdy-signin {
|
|
1200
|
+
flex-shrink: 0; cursor: pointer;
|
|
1201
|
+
font-size: var(--type-xs); font-weight: 600; color: var(--bg-0);
|
|
1202
|
+
background: var(--accent); border: 1px solid var(--accent);
|
|
1203
|
+
border-radius: var(--radius-xs); padding: 3px 10px;
|
|
1204
|
+
}
|
|
1205
|
+
.rdy-signin:hover { filter: brightness(1.08); }
|
|
1184
1206
|
/* Help ▸ Check AI editing readiness… modal (reuses .help-modal chrome). */
|
|
1185
1207
|
.rdy-modal { max-width: 520px; }
|
|
1186
1208
|
.rdy-modal-note { margin: 0 0 var(--space-3); color: var(--fg-2); font-size: var(--type-sm); line-height: var(--lh-md); }
|
|
1209
|
+
/* DDR-166 Decision 5 — auto-setup opt-out, mirrors .ob-crash-optin. */
|
|
1210
|
+
.rdy-autosetup-toggle { display: flex; align-items: flex-start; gap: var(--space-2); margin-top: var(--space-3); color: var(--fg-2); font-size: var(--type-xs); line-height: var(--lh-md); cursor: pointer; text-align: left; }
|
|
1211
|
+
.rdy-autosetup-toggle input { margin-top: 2px; flex: 0 0 auto; accent-color: var(--accent); cursor: pointer; }
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/* DDR-166 plan, Phase 2 (T7/T8) — design-setup checklist (SetupChecklist.jsx).
|
|
1215
|
+
Mirrors .rdy-* above (same present/missing two-state shape, no remediation
|
|
1216
|
+
copy — this probe never offers an automated fix, just progress). */
|
|
1217
|
+
@layer components {
|
|
1218
|
+
.setup-cl { display: flex; flex-direction: column; gap: var(--space-3); }
|
|
1219
|
+
.setup-cl-list {
|
|
1220
|
+
list-style: none; margin: 0; padding: 0;
|
|
1221
|
+
display: flex; flex-direction: column; gap: var(--space-2);
|
|
1222
|
+
}
|
|
1223
|
+
.setup-cl-row {
|
|
1224
|
+
display: flex; gap: var(--space-2); align-items: flex-start;
|
|
1225
|
+
padding: var(--space-2) var(--space-3);
|
|
1226
|
+
border: 1px solid var(--border-subtle); border-radius: var(--radius-sm);
|
|
1227
|
+
background: var(--bg-2); text-align: left;
|
|
1228
|
+
}
|
|
1229
|
+
.setup-cl-ic { flex-shrink: 0; margin-top: 1px; }
|
|
1230
|
+
.setup-cl-row--present .setup-cl-ic { color: var(--status-success); }
|
|
1231
|
+
.setup-cl-row--missing .setup-cl-ic { color: var(--fg-3); }
|
|
1232
|
+
.setup-cl-tx { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
1233
|
+
.setup-cl-label { font-size: var(--type-sm); font-weight: 600; color: var(--fg-0); }
|
|
1234
|
+
.setup-cl-detail { font-size: var(--type-xs); color: var(--fg-2); line-height: var(--lh-xs); }
|
|
1235
|
+
.setup-cl-foot { display: flex; justify-content: flex-end; gap: var(--space-2); flex-wrap: wrap; }
|
|
1236
|
+
.setup-cl-brand { text-decoration: none; }
|
|
1237
|
+
.setup-cl-modal { max-width: 520px; }
|
|
1238
|
+
.setup-cl-note { margin: 0 0 var(--space-3); color: var(--fg-2); font-size: var(--type-sm); line-height: var(--lh-md); }
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
/* T12 (DDR-173) — the in-app Brand-upload panel (BrandUploadPanel.jsx).
|
|
1242
|
+
Reuses .help-modal-* chrome; new rules cover the pick/result content only. */
|
|
1243
|
+
@layer components {
|
|
1244
|
+
.brand-up-modal { max-width: 480px; }
|
|
1245
|
+
.brand-up-note { margin: 0 0 var(--space-4); color: var(--fg-2); font-size: var(--type-sm); line-height: var(--lh-md); }
|
|
1246
|
+
.brand-up-pick { display: flex; justify-content: center; padding: var(--space-5) 0; }
|
|
1247
|
+
.brand-up-error { margin: var(--space-2) 0 0; color: var(--status-error); font-size: var(--type-sm); }
|
|
1248
|
+
.brand-up-empty { margin: 0; color: var(--fg-3); font-size: var(--type-xs); line-height: var(--lh-sm); }
|
|
1249
|
+
.brand-up-preview {
|
|
1250
|
+
display: block; max-width: 100%; max-height: 120px; margin: 0 auto var(--space-4);
|
|
1251
|
+
border: 1px solid var(--border-subtle); border-radius: var(--radius-sm); background: var(--bg-3);
|
|
1252
|
+
padding: var(--space-3);
|
|
1253
|
+
}
|
|
1254
|
+
.brand-up-sechd {
|
|
1255
|
+
margin: var(--space-4) 0 var(--space-2); font-size: var(--type-xs); font-weight: 600;
|
|
1256
|
+
text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--fg-2);
|
|
1257
|
+
}
|
|
1258
|
+
.brand-up-swatches { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
|
|
1259
|
+
.brand-up-swatch { display: flex; align-items: center; gap: var(--space-2); }
|
|
1260
|
+
.brand-up-swatch-chip {
|
|
1261
|
+
display: inline-block; width: 20px; height: 20px; border-radius: var(--radius-xs);
|
|
1262
|
+
border: 1px solid var(--border-default);
|
|
1263
|
+
}
|
|
1264
|
+
.brand-up-swatch-value { font-family: var(--font-mono); font-size: var(--type-xs); color: var(--fg-2); }
|
|
1265
|
+
.brand-up-fonts { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
|
|
1266
|
+
.brand-up-font-chip {
|
|
1267
|
+
padding: 2px var(--space-2); border-radius: var(--radius-pill); border: 1px solid var(--border-default);
|
|
1268
|
+
background: var(--bg-2); font-size: var(--type-xs); color: var(--fg-1);
|
|
1269
|
+
}
|
|
1270
|
+
.brand-up-nextstep { margin: var(--space-4) 0 0; font-size: var(--type-sm); color: var(--fg-1); line-height: var(--lh-md); }
|
|
1271
|
+
.brand-up-nextstep code { font-family: var(--font-mono); background: var(--bg-3); padding: 1px 4px; border-radius: var(--radius-xs); }
|
|
1272
|
+
.brand-up-actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
|
|
1187
1273
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// quick-setup-tour.js — DDR-166 plan, Phase 2 (T7). The "empty → design system
|
|
2
|
+
// → first canvas → first AI edit" journey, on the existing tour engine
|
|
3
|
+
// (overlay.jsx), never a fork — same convention as usage-tour.js/collab-tour.js.
|
|
4
|
+
//
|
|
5
|
+
// Native, no-terminal posture (DDR-126/128): this deck can't execute
|
|
6
|
+
// `/design:setup-ds` for the user (the canvas iframe is cross-origin — DDR-054 —
|
|
7
|
+
// and the shell has no terminal). It coach-marks the Assistant panel instead:
|
|
8
|
+
// point at it, tell the user what to type, let THEM send it. The terminal
|
|
9
|
+
// `/design:*` path stays the power-user route.
|
|
10
|
+
|
|
11
|
+
export const QUICK_SETUP_TOUR = [
|
|
12
|
+
{
|
|
13
|
+
// Centered, no target — the overview step.
|
|
14
|
+
title: "Let's get you set up",
|
|
15
|
+
body: 'Three short steps: a design system for your brand, a first canvas, then your first AI edit. Everything after this happens right here — no terminal.',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
target: "[data-tour='sidebar']",
|
|
19
|
+
title: 'Your canvases will live here',
|
|
20
|
+
body: "Empty for now. Once you have a design system, this fills up with real screens — click any one to open it.",
|
|
21
|
+
placement: 'right',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
target: "[data-testid='assistant-toggle']",
|
|
25
|
+
title: 'Ask the Assistant to build your design system',
|
|
26
|
+
body: 'Open the Assistant and describe your brand — colors, type, the vibe you want. It sets up a real design system for you. Already have one? Say so and it can bring it in.',
|
|
27
|
+
placement: 'left',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
target: "[data-tour='viewport']",
|
|
31
|
+
title: 'Your first canvas appears here',
|
|
32
|
+
body: "Once the design system is ready, ask for a first screen and watch it land right in this space, ready to edit.",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
// Centered — the close-out step.
|
|
36
|
+
title: "You're ready",
|
|
37
|
+
body: 'Hold ⌘ and click anything on a canvas to point at it, describe the change in the Assistant, and watch it update live. Restart this tour any time from Help ▸ Quick setup.',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
@@ -27,8 +27,18 @@ import { registerCommand } from '../undo-stack.ts';
|
|
|
27
27
|
* Push-once callable that submits a full `Stroke[]` to the server (or its
|
|
28
28
|
* test stub) AND updates the iframe's local strokes state. The
|
|
29
29
|
* annotations-layer `putStrokes` is the production binding.
|
|
30
|
+
*
|
|
31
|
+
* `before` is the baseline THIS command's `next` was computed from — passed
|
|
32
|
+
* through so the consumer can distinguish "an id `prev` still has that
|
|
33
|
+
* `before` already lacked too" (a genuinely concurrent addition, fold it in)
|
|
34
|
+
* from "an id `before` had that `next` deliberately dropped" (this command's
|
|
35
|
+
* own delete — must stay dropped even if React's rendered state hasn't
|
|
36
|
+
* caught up yet). See `reconcileCommit` in annotations-layer.tsx.
|
|
30
37
|
*/
|
|
31
|
-
export type StrokesPutFn = (
|
|
38
|
+
export type StrokesPutFn = (
|
|
39
|
+
next: readonly Stroke[],
|
|
40
|
+
before: readonly Stroke[]
|
|
41
|
+
) => void | Promise<void>;
|
|
32
42
|
|
|
33
43
|
export interface AnnotationStrokesPayload {
|
|
34
44
|
before: readonly Stroke[];
|
|
@@ -58,10 +68,10 @@ export function createAnnotationStrokesCommand(init: AnnotationStrokesCommandIni
|
|
|
58
68
|
kind,
|
|
59
69
|
label,
|
|
60
70
|
async do() {
|
|
61
|
-
await putFn(after.map(cloneStroke));
|
|
71
|
+
await putFn(after.map(cloneStroke), before.map(cloneStroke));
|
|
62
72
|
},
|
|
63
73
|
async undo() {
|
|
64
|
-
await putFn(before.map(cloneStroke));
|
|
74
|
+
await putFn(before.map(cloneStroke), after.map(cloneStroke));
|
|
65
75
|
},
|
|
66
76
|
};
|
|
67
77
|
}
|
|
@@ -231,6 +231,76 @@
|
|
|
231
231
|
}
|
|
232
232
|
},
|
|
233
233
|
"additionalProperties": false
|
|
234
|
+
},
|
|
235
|
+
"generation": {
|
|
236
|
+
"type": "object",
|
|
237
|
+
"description": "BYOK AI-media generation preferences (feature-ai-media-generation, DDR-16x). NON-SECRET ONLY — provider API keys are NEVER in this committed config; they live in the OS keychain (native) or ~/.config/maude/keys.json mode 0600 (browser). This block only carries routing/UI preferences. Hot-reloadable — Settings saves take effect without a server restart.",
|
|
238
|
+
"properties": {
|
|
239
|
+
"defaultImageProvider": {
|
|
240
|
+
"type": "string",
|
|
241
|
+
"description": "Provider id used when an image-generation request leaves the provider unspecified (e.g. 'gemini'). Must be a registered provider that supports the image modality.",
|
|
242
|
+
"default": "gemini"
|
|
243
|
+
},
|
|
244
|
+
"defaultAudioProvider": {
|
|
245
|
+
"type": "string",
|
|
246
|
+
"description": "Provider id used when an audio-generation request (music / sfx / voiceover) leaves the provider unspecified. Must be a registered provider that supports the audio modality (v1: 'elevenlabs').",
|
|
247
|
+
"default": "elevenlabs"
|
|
248
|
+
},
|
|
249
|
+
"defaultModels": {
|
|
250
|
+
"type": "object",
|
|
251
|
+
"description": "Per-provider default model id (e.g. { \"gemini\": \"gemini-2.5-flash-image\" }). Used when a request leaves the model unspecified.",
|
|
252
|
+
"additionalProperties": { "type": "string" },
|
|
253
|
+
"default": {}
|
|
254
|
+
},
|
|
255
|
+
"preferLocalWhenAvailable": {
|
|
256
|
+
"type": "boolean",
|
|
257
|
+
"description": "When a local runtime (Ollama / ComfyUI / Draw Things, post-v1) is detected on loopback, prefer it over a cloud provider for the same modality (free, offline, private). Inert until local engines ship (Phase 5).",
|
|
258
|
+
"default": false
|
|
259
|
+
},
|
|
260
|
+
"transcription": {
|
|
261
|
+
"type": "object",
|
|
262
|
+
"description": "Speech-to-text / subtitle engine preference (Task 2.6, DDR-164). The engine is an EXPLICIT user choice, never an automatic fallback: a chosen-but-unavailable engine errors clearly and Maude never silently switches to another. `maude design transcribe --provider` overrides this per-call.",
|
|
263
|
+
"properties": {
|
|
264
|
+
"provider": {
|
|
265
|
+
"type": "string",
|
|
266
|
+
"enum": ["whisper", "elevenlabs", "groq"],
|
|
267
|
+
"description": "Which engine transcribes when no --provider flag is given. `whisper` = local whisper.cpp (free, offline, no key); `elevenlabs` = ElevenLabs Scribe (cloud, key); `groq` = Groq Whisper (cloud, key). Absent ⇒ whisper.",
|
|
268
|
+
"default": "whisper"
|
|
269
|
+
},
|
|
270
|
+
"model": {
|
|
271
|
+
"type": "string",
|
|
272
|
+
"description": "Optional engine-specific model id override (e.g. a Groq 'whisper-large-v3-turbo', an ElevenLabs 'scribe_v1', or a local ggml model name). Absent ⇒ the engine's own default."
|
|
273
|
+
},
|
|
274
|
+
"whisperModel": {
|
|
275
|
+
"type": "string",
|
|
276
|
+
"enum": ["tiny", "base", "base.en", "small", "large-v3-turbo"],
|
|
277
|
+
"description": "Preferred managed local whisper.cpp model id (Task 2.7). Downloaded via Settings → Subtitles → 'Download model' into a per-machine cache; `maude design transcribe --provider whisper` auto-resolves it (no --model). Absent ⇒ any downloaded multilingual model. 'base' is the recommended default; '.en' variants are English-only."
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
"additionalProperties": false
|
|
281
|
+
},
|
|
282
|
+
"providers": {
|
|
283
|
+
"type": "object",
|
|
284
|
+
"description": "Per-provider non-secret toggles keyed by provider id. `enabled: false` hides a provider from the generate UI even if a key is present. `localEndpoint` overrides the default host:port for a local runtime.",
|
|
285
|
+
"additionalProperties": {
|
|
286
|
+
"type": "object",
|
|
287
|
+
"properties": {
|
|
288
|
+
"enabled": {
|
|
289
|
+
"type": "boolean",
|
|
290
|
+
"description": "Whether this provider is offered in the generate UI. Default true.",
|
|
291
|
+
"default": true
|
|
292
|
+
},
|
|
293
|
+
"localEndpoint": {
|
|
294
|
+
"type": "string",
|
|
295
|
+
"description": "Override host:port for a local runtime provider (e.g. '127.0.0.1:11434' for Ollama). Ignored for cloud providers."
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
"additionalProperties": false
|
|
299
|
+
},
|
|
300
|
+
"default": {}
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
"additionalProperties": false
|
|
234
304
|
}
|
|
235
305
|
}
|
|
236
306
|
}
|
|
@@ -216,10 +216,19 @@ const MENU_CSS = `
|
|
|
216
216
|
font: inherit;
|
|
217
217
|
color: inherit;
|
|
218
218
|
}
|
|
219
|
-
.dc-context-menu .dc-menu-item:hover
|
|
219
|
+
.dc-context-menu .dc-menu-item:hover {
|
|
220
|
+
background: color-mix(in oklab, var(--maude-chrome-fg-0, #1c1917) 8%, transparent);
|
|
221
|
+
}
|
|
220
222
|
.dc-context-menu .dc-menu-item:focus-visible {
|
|
223
|
+
/* fix-photo-editor-followup-debt Task 16 — was outline: none (an
|
|
224
|
+
~1.05:1-contrast, effectively invisible focus ring). Reuses
|
|
225
|
+
--maude-hud-accent (canvas-lib.tsx's own established focus-visible
|
|
226
|
+
token for this chrome family — artboard labels, zoom toolbar) rather
|
|
227
|
+
than inventing a new one; -2px inset offset matches that same
|
|
228
|
+
convention for a control inside a bordered container. */
|
|
221
229
|
background: color-mix(in oklab, var(--maude-chrome-fg-0, #1c1917) 8%, transparent);
|
|
222
|
-
outline:
|
|
230
|
+
outline: 2px solid var(--maude-hud-accent, #d63b1f);
|
|
231
|
+
outline-offset: -2px;
|
|
223
232
|
}
|
|
224
233
|
.dc-context-menu .dc-menu-item[disabled] {
|
|
225
234
|
opacity: 0.45;
|
package/apps/studio/context.ts
CHANGED
|
@@ -55,9 +55,25 @@ export interface DevServerConfig {
|
|
|
55
55
|
newCanvasDir: string;
|
|
56
56
|
newComponentDir: string;
|
|
57
57
|
linkedHub?: LinkedHub;
|
|
58
|
+
/**
|
|
59
|
+
* feature-ai-media-generation (DDR-16x) — BYOK generation preferences.
|
|
60
|
+
* NON-SECRET ONLY: provider keys live in the OS keychain / ~/.config/maude/
|
|
61
|
+
* keys.json (0600), NEVER here. Hot-reloadable via the full in-place cfg swap
|
|
62
|
+
* in reloadConfig (only designRoot + linkedHub are boot-pinned). See
|
|
63
|
+
* config.schema.json for the field contract.
|
|
64
|
+
*/
|
|
65
|
+
generation?: GenerationConfig;
|
|
58
66
|
_source: ConfigSource;
|
|
59
67
|
}
|
|
60
68
|
|
|
69
|
+
/** Non-secret AI-media generation preferences (DDR-16x). Keys are NOT here. */
|
|
70
|
+
export interface GenerationConfig {
|
|
71
|
+
defaultImageProvider?: string;
|
|
72
|
+
defaultModels?: Record<string, string>;
|
|
73
|
+
preferLocalWhenAvailable?: boolean;
|
|
74
|
+
providers?: Record<string, { enabled?: boolean; localEndpoint?: string }>;
|
|
75
|
+
}
|
|
76
|
+
|
|
61
77
|
const DEFAULT_CONFIG: Omit<DevServerConfig, '_source'> = {
|
|
62
78
|
name: 'Design',
|
|
63
79
|
projectLabel: null,
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Design-setup readiness probe (DDR-166 plan, Phase 2 / T6). Backs
|
|
2
|
+
// `GET /_api/setup-readiness`.
|
|
3
|
+
//
|
|
4
|
+
// Distinct from readiness.ts (which probes the AI-EDITING dependency chain —
|
|
5
|
+
// claude/maude/plugins on the user's machine). This probes the PROJECT's own
|
|
6
|
+
// setup progress: has it moved past the empty scaffold write_minimal_design()
|
|
7
|
+
// leaves behind, toward a project with a real design system, a first canvas,
|
|
8
|
+
// and brand assets. Read-only, mirrors probeReadiness()'s shape and posture —
|
|
9
|
+
// never installs or mutates anything.
|
|
10
|
+
|
|
11
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
import { findHtmlFiles } from './api.ts';
|
|
14
|
+
import type { Context } from './context.ts';
|
|
15
|
+
|
|
16
|
+
export type SetupReadinessStatus = 'present' | 'missing';
|
|
17
|
+
|
|
18
|
+
export interface SetupReadinessItem {
|
|
19
|
+
id: 'project' | 'design-system' | 'first-canvas' | 'brand-assets';
|
|
20
|
+
label: string;
|
|
21
|
+
status: SetupReadinessStatus;
|
|
22
|
+
detail: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface SetupReadinessReport {
|
|
26
|
+
/** True once every item is `present`. */
|
|
27
|
+
ready: boolean;
|
|
28
|
+
items: SetupReadinessItem[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** True when `dsDirAbs/preview/` has a `logo.*` specimen (DDR-141 Tier-0). */
|
|
32
|
+
function hasLogoSpecimen(dsDirAbs: string): boolean {
|
|
33
|
+
const previewDir = path.join(dsDirAbs, 'preview');
|
|
34
|
+
let entries: string[];
|
|
35
|
+
try {
|
|
36
|
+
entries = readdirSync(previewDir);
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return entries.some((f) => /^logo\./i.test(f));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Side-effect-free. `ctx.cfg` is already schema-clamped (context.ts
|
|
45
|
+
* `clampToDesignRoot`), so every `designSystems[].path`/`tokensCssRel` and
|
|
46
|
+
* `canvasGroups[].path` used here is guaranteed to resolve inside `designRoot`.
|
|
47
|
+
*/
|
|
48
|
+
export async function probeSetupReadiness(ctx: Context): Promise<SetupReadinessReport> {
|
|
49
|
+
const { cfg, paths } = ctx;
|
|
50
|
+
const items: SetupReadinessItem[] = [];
|
|
51
|
+
|
|
52
|
+
// A real, on-disk `.design/config.json` (vs. the in-memory defaults fallback
|
|
53
|
+
// `createContext()` uses when the file is missing/invalid) — the signal that
|
|
54
|
+
// this is a genuinely-initialized project, not just the Rust
|
|
55
|
+
// write_minimal_design() scaffold rendering an empty shell.
|
|
56
|
+
const hasRealConfig = cfg._source === '.design/config.json';
|
|
57
|
+
items.push({
|
|
58
|
+
id: 'project',
|
|
59
|
+
label: 'Project set up',
|
|
60
|
+
status: hasRealConfig ? 'present' : 'missing',
|
|
61
|
+
detail: hasRealConfig
|
|
62
|
+
? `“${cfg.name}” — a real .design/config.json is on disk.`
|
|
63
|
+
: 'No .design/config.json yet — this is the empty starter scaffold.',
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const designSystems = cfg.designSystems ?? [];
|
|
67
|
+
const dsWithTokens = designSystems.find((ds) => {
|
|
68
|
+
const rel = ds.tokensCssRel ?? path.posix.join(ds.path, 'colors_and_type.css');
|
|
69
|
+
return existsSync(path.join(paths.designRoot, rel));
|
|
70
|
+
});
|
|
71
|
+
items.push({
|
|
72
|
+
id: 'design-system',
|
|
73
|
+
label: 'Design system',
|
|
74
|
+
status: dsWithTokens ? 'present' : 'missing',
|
|
75
|
+
detail: dsWithTokens
|
|
76
|
+
? `“${dsWithTokens.name}” — tokens are on disk.`
|
|
77
|
+
: designSystems.length
|
|
78
|
+
? 'Declared in config, but the tokens file is missing.'
|
|
79
|
+
: 'None yet — ask the Assistant to set one up, or bring your own brand.',
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Any real canvas outside the DS specimen groups (canvasGroups whose path
|
|
83
|
+
// matches /system/i are DS preview specimens, not user canvases).
|
|
84
|
+
const canvasGroups = (cfg.canvasGroups ?? []).filter((g) => !/system/i.test(g.path));
|
|
85
|
+
let firstCanvas: string | null = null;
|
|
86
|
+
for (const g of canvasGroups) {
|
|
87
|
+
const groupAbs = path.join(paths.designRoot, g.path);
|
|
88
|
+
const groupRel = path.posix.join(paths.designRel, g.path);
|
|
89
|
+
const files = await findHtmlFiles(groupAbs, groupRel);
|
|
90
|
+
if (files.length) {
|
|
91
|
+
firstCanvas = files[0];
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
items.push({
|
|
96
|
+
id: 'first-canvas',
|
|
97
|
+
label: 'First canvas',
|
|
98
|
+
status: firstCanvas ? 'present' : 'missing',
|
|
99
|
+
detail: firstCanvas ? `${path.basename(firstCanvas)} is open for editing.` : 'No canvas yet.',
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const dsWithLogo = designSystems.find((ds) =>
|
|
103
|
+
hasLogoSpecimen(path.join(paths.designRoot, ds.path))
|
|
104
|
+
);
|
|
105
|
+
items.push({
|
|
106
|
+
id: 'brand-assets',
|
|
107
|
+
label: 'Brand assets',
|
|
108
|
+
status: dsWithLogo ? 'present' : 'missing',
|
|
109
|
+
detail: dsWithLogo
|
|
110
|
+
? `“${dsWithLogo.name}” has a stored logo specimen.`
|
|
111
|
+
: 'No logo/brand specimen on file yet.',
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return { ready: items.every((i) => i.status === 'present'), items };
|
|
115
|
+
}
|