@dfosco/storyboard 0.7.1 → 0.9.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/dist/storyboard-ui.css +1 -1
- package/dist/storyboard-ui.js +14128 -10953
- package/dist/storyboard-ui.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/dist/tiny-canvas.css +1 -1
- package/package.json +138 -128
- package/scaffold/AGENTS.md +9 -7
- package/scaffold/README.md +18 -0
- package/scaffold/deploy.yml +21 -0
- package/scaffold/gitignore +8 -14
- package/scaffold/preview.yml +40 -0
- package/scaffold/{manifest.json → scaffold.config.json} +73 -3
- package/scaffold/scripts/aggregate-artifacts.mjs +257 -0
- package/scaffold/skills/canvas/SKILL.md +1 -1
- package/scaffold/skills/migrate-0.5.0/SKILL.md +1 -1
- package/scaffold/skills/ship/SKILL.md +2 -2
- package/scaffold/skills/worktree/SKILL.md +1 -1
- package/scaffold/src/_prototype.jsx +17 -0
- package/scaffold/src/_story.jsx +13 -0
- package/scaffold/src/library/README.md +34 -0
- package/scaffold/src/library/_app.jsx +41 -0
- package/scaffold/src/library/_app.module.css +2 -0
- package/scaffold/src/library/create.jsx +10 -0
- package/scaffold/src/library/index.jsx +14 -0
- package/scaffold/src/library/mount.jsx +51 -0
- package/scaffold/src/library/prototypes-entry.jsx +57 -0
- package/scaffold/src/library/routes.jsx +205 -0
- package/scaffold/src/library/viewfinder.jsx +13 -0
- package/scaffold/src/library/workspace.jsx +17 -0
- package/scripts/aggregate-artifacts.mjs +257 -0
- package/src/canvas/style.css +16 -16
- package/src/core/artifact/operations.js +54 -15
- package/src/core/artifact/schemas/canvas.schema.json +7 -1
- package/src/core/autosync/server.test.js +1 -1
- package/src/core/canvas/hot-pool.js +21 -33
- package/src/core/canvas/materializer.js +39 -13
- package/src/core/canvas/selectedWidgets.js +1 -1
- package/src/core/canvas/server.js +376 -100
- package/src/core/canvas/server.test.js +472 -2
- package/src/core/canvas/terminal-server.js +144 -57
- package/src/core/canvas/undoRedo.js +174 -0
- package/src/core/canvas/undoRedo.test.js +250 -0
- package/src/core/cli/artifact.js +2 -0
- package/src/core/cli/buildManifest.js +34 -0
- package/src/core/cli/canvasRedo.js +44 -0
- package/src/core/cli/canvasUndo.js +40 -0
- package/src/core/cli/create.js +151 -23
- package/src/core/cli/dev.js +23 -35
- package/src/core/cli/index.js +21 -0
- package/src/core/cli/schemas.js +8 -4
- package/src/core/cli/serverUrl.js +24 -0
- package/src/core/cli/setup.js +14 -25
- package/src/core/cli/terminal-welcome.js +12 -6
- package/src/core/cli/updateVersion.js +42 -2
- package/src/core/cli/workleaf.js +140 -0
- package/src/core/comments/api.js +1 -1
- package/src/core/comments/queries.js +3 -0
- package/src/core/comments/ui/CommentWindow.jsx +3 -2
- package/src/core/comments/ui/comment-layout.css +14 -14
- package/src/core/data/artifactIndex.js +235 -0
- package/src/core/data/artifactIndex.test.js +203 -0
- package/src/core/data/artifactManifest.js +290 -0
- package/src/core/data/artifactManifest.test.js +207 -0
- package/src/core/data/viewfinder.js +47 -7
- package/src/core/index.js +24 -1
- package/src/core/inspector/highlighter.js +1 -1
- package/src/core/inspector/mouseMode.js +2 -2
- package/src/core/lib/components/ui/avatar/avatar-fallback.jsx +2 -2
- package/src/core/lib/components/ui/avatar/avatar-image.jsx +2 -2
- package/src/core/lib/components/ui/avatar/avatar.jsx +2 -2
- package/src/core/lib/components/ui/checkbox/checkbox.jsx +12 -9
- package/src/core/lib/components/ui/dialog/dialog-content.jsx +45 -31
- package/src/core/lib/components/ui/dialog/dialog-trigger.jsx +9 -5
- package/src/core/lib/components/ui/dialog/dialog.jsx +12 -3
- package/src/core/lib/components/ui/dialog/dialog.module.css +118 -0
- package/src/core/lib/components/ui/dialog/index.js +4 -34
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +3 -3
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +19 -9
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +8 -8
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +15 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +14 -7
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +8 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +4 -4
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +2 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +8 -2
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu.jsx +2 -2
- package/src/core/lib/components/ui/label/label.jsx +1 -2
- package/src/core/lib/components/ui/panel/panel-close.jsx +7 -4
- package/src/core/lib/components/ui/panel/panel-content.jsx +7 -9
- package/src/core/lib/components/ui/panel/panel-title.jsx +3 -3
- package/src/core/lib/components/ui/panel/panel.jsx +11 -2
- package/src/core/lib/components/ui/separator/separator.jsx +6 -4
- package/src/core/lib/components/ui/tooltip/tooltip-content.jsx +7 -6
- package/src/core/lib/components/ui/tooltip/tooltip-trigger.jsx +13 -6
- package/src/core/lib/components/ui/tooltip/tooltip.jsx +5 -5
- package/src/core/modes/modes.css +4 -4
- package/src/core/mountStoryboardCore.js +287 -83
- package/src/core/mountStoryboardCore.test.js +198 -0
- package/src/core/rename-watcher/config.json +1 -1
- package/src/core/rename-watcher/watcher.js +330 -37
- package/src/core/rename-watcher/watcher.test.js +253 -0
- package/src/core/scaffold/fragments.js +287 -0
- package/src/core/scaffold/fragments.test.js +401 -0
- package/src/core/scaffold/index.js +291 -0
- package/src/core/scaffold/migrateLegacyGitignore.js +157 -0
- package/src/core/scaffold/scaffold-integration.test.js +247 -0
- package/src/core/scaffold.js +4 -97
- package/src/core/stores/canvasInteractionStore.js +120 -0
- package/src/core/stores/canvasInteractionStore.test.js +126 -0
- package/src/core/stores/configSchema.js +64 -8
- package/src/core/stores/configSchema.test.js +3 -0
- package/src/core/stores/customerModeConfig.js +24 -3
- package/src/core/stores/customerModeConfig.test.js +46 -0
- package/src/core/stores/presentationStore.js +118 -0
- package/src/core/stores/presentationStore.test.js +114 -0
- package/src/core/stores/recentArtifacts.js +49 -2
- package/src/core/stores/recentArtifacts.test.js +59 -6
- package/src/core/stores/themeBootstrap.js +264 -0
- package/src/core/stores/themeBootstrap.test.js +211 -0
- package/src/core/stores/themeStore.test.js +154 -0
- package/src/core/stores/themeStore.ts +235 -220
- package/src/core/stores/uiConfig.js +10 -2
- package/src/core/styles/generateThemesCss.js +63 -0
- package/src/core/styles/tailwind.css +150 -94
- package/src/core/styles/workspace-chrome.css +13 -0
- package/src/core/tools/handlers/paletteTheme.js +11 -8
- package/src/core/ui/ActionMenuButton.jsx +2 -1
- package/src/core/ui/AutosyncMenuButton.css +7 -7
- package/src/core/ui/BranchSelect.module.css +5 -5
- package/src/core/ui/CanvasCreateMenu.jsx +1 -19
- package/src/core/ui/ChromeSlot.jsx +92 -0
- package/src/core/ui/ChromeSlot.test.jsx +140 -0
- package/src/core/ui/CoreUIBar.css +5 -5
- package/src/core/ui/CoreUIBar.jsx +170 -142
- package/src/core/ui/InspectorPanel.css +5 -5
- package/src/core/ui/InspectorPanel.jsx +9 -9
- package/src/core/ui/PwaInstallBanner.css +5 -5
- package/src/core/ui/PwaInstallBanner.jsx +5 -5
- package/src/core/ui/ThemeMenuButton.jsx +45 -30
- package/src/core/ui/core-ui-colors.css +28 -66
- package/src/core/ui/sidepanel.css +12 -12
- package/src/core/vite/server-plugin.js +13 -0
- package/src/core/workleaf/cleanup.js +102 -0
- package/src/core/workleaf/create.js +199 -0
- package/src/core/workleaf/delete.js +101 -0
- package/src/core/workleaf/list.js +57 -0
- package/src/core/workleaf/merge.js +238 -0
- package/src/core/workleaf/paths.js +146 -0
- package/src/core/workleaf/paths.test.js +230 -0
- package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +130 -34
- package/src/core/workshop/features/createFlow/server.js +5 -1
- package/src/core/workshop/features/createPrototype/server.js +5 -1
- package/src/core/workshop/features/templateIndex.js +28 -1
- package/src/core/worktree/port.js +48 -5
- package/src/core/worktree/port.test.js +42 -0
- package/src/internals/ArtifactForm/ArtifactForm.jsx +173 -112
- package/src/internals/ArtifactForm/ArtifactForm.module.css +51 -69
- package/src/internals/ArtifactForm/artifactSchemas.js +40 -5
- package/src/internals/AuthModal/AuthModal.module.css +34 -34
- package/src/internals/BaseUiForm/BaseUiForm.jsx +293 -0
- package/src/internals/BaseUiForm/BaseUiForm.module.css +542 -0
- package/src/internals/BranchBar/BranchBar.module.css +4 -4
- package/src/internals/BranchesDropdown/BranchesDropdown.jsx +69 -0
- package/src/internals/BranchesDropdown/BranchesDropdown.module.css +84 -0
- package/src/internals/CommandPalette/CommandPalette.jsx +41 -29
- package/src/internals/CommandPalette/CreateArtifactForm.jsx +150 -0
- package/src/internals/CommandPalette/CreateDialog.jsx +20 -110
- package/src/internals/CommandPalette/WidgetArtifactDialog.css +16 -16
- package/src/internals/CommandPalette/WidgetArtifactDialog.jsx +1 -1
- package/src/internals/CommandPalette/command-palette.css +14 -14
- package/src/internals/CommandPalette/createHelpers.js +30 -0
- package/src/internals/CreatePage/CreatePage.jsx +57 -0
- package/src/internals/CreatePage/CreatePage.module.css +34 -0
- package/src/internals/Dialog.jsx +51 -0
- package/src/internals/FlowError.module.css +5 -5
- package/src/internals/PrototypeErrorBoundary.module.css +15 -15
- package/src/internals/SimpleWorkspace/SimpleWorkspace.jsx +534 -0
- package/src/internals/SimpleWorkspace/SimpleWorkspace.module.css +323 -0
- package/src/internals/Tooltip.jsx +39 -0
- package/src/internals/Viewfinder.jsx +229 -64
- package/src/internals/Viewfinder.module.css +253 -182
- package/src/internals/canvas/CanvasControls.module.css +11 -11
- package/src/internals/canvas/CanvasPage.bridge.test.jsx +11 -37
- package/src/internals/canvas/CanvasPage.jsx +358 -217
- package/src/internals/canvas/CanvasPage.module.css +20 -19
- package/src/internals/canvas/CanvasPage.multiselect.test.jsx +39 -26
- package/src/internals/canvas/CanvasToolbar.module.css +11 -11
- package/src/internals/canvas/ConnectorLayer.jsx +39 -2
- package/src/internals/canvas/ConnectorLayer.module.css +10 -10
- package/src/internals/canvas/PageSelector.jsx +15 -1
- package/src/internals/canvas/PageSelector.module.css +41 -27
- package/src/internals/canvas/canvasApi.js +40 -5
- package/src/internals/canvas/canvasTheme.js +22 -111
- package/src/internals/canvas/isolation/createIsolationMiddleware.js +68 -0
- package/src/internals/canvas/isolation/mountIsolationApp.jsx +88 -0
- package/src/internals/canvas/isolation/prototypeRoutes.jsx +140 -0
- package/src/internals/canvas/isolation/prototypesEntry.jsx +28 -0
- package/src/internals/canvas/isolation/storiesEntry.jsx +20 -0
- package/src/internals/canvas/isolation/storyRoutes.jsx +55 -0
- package/src/internals/canvas/useUndoRedo.js +75 -60
- package/src/internals/canvas/useUndoRedo.test.js +46 -178
- package/src/internals/canvas/widgets/CodePenEmbed.jsx +16 -36
- package/src/internals/canvas/widgets/CodePenEmbed.module.css +12 -12
- package/src/internals/canvas/widgets/CropOverlay.module.css +23 -23
- package/src/internals/canvas/widgets/ExpandedPane.module.css +8 -8
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +1 -1
- package/src/internals/canvas/widgets/FigmaEmbed.jsx +15 -36
- package/src/internals/canvas/widgets/FigmaEmbed.module.css +15 -15
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.jsx +30 -21
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +5 -5
- package/src/internals/canvas/widgets/ImageWidget.jsx +7 -2
- package/src/internals/canvas/widgets/ImageWidget.module.css +3 -3
- package/src/internals/canvas/widgets/LinkPreview.module.css +79 -80
- package/src/internals/canvas/widgets/MarkdownBlock.module.css +31 -31
- package/src/internals/canvas/widgets/PromptWidget.jsx +2 -16
- package/src/internals/canvas/widgets/PromptWidget.module.css +33 -33
- package/src/internals/canvas/widgets/PrototypeEmbed.jsx +92 -17
- package/src/internals/canvas/widgets/PrototypeEmbed.module.css +58 -56
- package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +118 -4
- package/src/internals/canvas/widgets/ResizeHandle.module.css +4 -4
- package/src/internals/canvas/widgets/StorySetWidget.jsx +53 -25
- package/src/internals/canvas/widgets/StoryWidget.jsx +71 -56
- package/src/internals/canvas/widgets/StoryWidget.module.css +22 -20
- package/src/internals/canvas/widgets/TerminalReadWidget.jsx +13 -15
- package/src/internals/canvas/widgets/TerminalReadWidget.module.css +4 -4
- package/src/internals/canvas/widgets/TerminalWidget.jsx +56 -45
- package/src/internals/canvas/widgets/TerminalWidget.module.css +10 -10
- package/src/internals/canvas/widgets/TilesWidget.module.css +17 -17
- package/src/internals/canvas/widgets/WidgetChrome.jsx +1 -1
- package/src/internals/canvas/widgets/WidgetChrome.module.css +76 -61
- package/src/internals/canvas/widgets/WidgetWrapper.module.css +2 -2
- package/src/internals/canvas/widgets/embedOverlay.module.css +14 -4
- package/src/internals/canvas/widgets/embedTheme.js +12 -104
- package/src/internals/canvas/widgets/expandUtils.js +19 -19
- package/src/internals/canvas/widgets/normalizeLegacyEmbedSrc.js +74 -0
- package/src/internals/canvas/widgets/widgetConfig.js +5 -5
- package/src/internals/context.jsx +22 -1
- package/src/internals/context.test.jsx +47 -0
- package/src/internals/hooks/useArtifactIndex.js +31 -0
- package/src/internals/hooks/useArtifactIndex.test.js +45 -0
- package/src/internals/hooks/usePrototypeReloadGuard.js +14 -8
- package/src/internals/index.js +6 -0
- package/src/internals/loadConsumerWrapper.js +60 -0
- package/src/internals/story/ComponentSetPage.jsx +75 -34
- package/src/internals/story/ComponentSetPage.module.css +14 -14
- package/src/internals/story/StoryPage.jsx +16 -25
- package/src/internals/story/StoryPage.module.css +2 -2
- package/src/internals/vite/data-plugin.js +317 -149
- package/src/internals/vite/data-plugin.test.js +11 -11
- package/{scaffold/storyboard.config.json → storyboard.config.json} +25 -0
- package/terminal.config.json +1 -1
- package/src/core/lib/components/ui/card/card-action.jsx +0 -11
- package/src/core/lib/components/ui/card/card-content.jsx +0 -11
- package/src/core/lib/components/ui/card/card-description.jsx +0 -11
- package/src/core/lib/components/ui/card/card-footer.jsx +0 -11
- package/src/core/lib/components/ui/card/card-header.jsx +0 -19
- package/src/core/lib/components/ui/card/card-title.jsx +0 -11
- package/src/core/lib/components/ui/card/card.jsx +0 -17
- package/src/core/lib/components/ui/card/index.js +0 -25
- package/src/core/lib/components/ui/collapsible/collapsible-content.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/collapsible-trigger.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/collapsible.jsx +0 -7
- package/src/core/lib/components/ui/collapsible/index.js +0 -13
- package/src/core/lib/components/ui/dialog/dialog-close.jsx +0 -7
- package/src/core/lib/components/ui/dialog/dialog-description.jsx +0 -15
- package/src/core/lib/components/ui/dialog/dialog-footer.jsx +0 -23
- package/src/core/lib/components/ui/dialog/dialog-header.jsx +0 -11
- package/src/core/lib/components/ui/dialog/dialog-overlay.jsx +0 -15
- package/src/core/lib/components/ui/dialog/dialog-portal.jsx +0 -4
- package/src/core/lib/components/ui/dialog/dialog-title.jsx +0 -15
- package/src/core/lib/components/ui/popover/index.js +0 -28
- package/src/core/lib/components/ui/popover/popover-close.jsx +0 -7
- package/src/core/lib/components/ui/popover/popover-content.jsx +0 -22
- package/src/core/lib/components/ui/popover/popover-description.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-header.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-portal.jsx +0 -4
- package/src/core/lib/components/ui/popover/popover-title.jsx +0 -11
- package/src/core/lib/components/ui/popover/popover-trigger.jsx +0 -8
- package/src/core/lib/components/ui/popover/popover.jsx +0 -4
- package/src/core/lib/components/ui/select/index.js +0 -37
- package/src/core/lib/components/ui/select/select-content.jsx +0 -30
- package/src/core/lib/components/ui/select/select-group-heading.jsx +0 -17
- package/src/core/lib/components/ui/select/select-group.jsx +0 -15
- package/src/core/lib/components/ui/select/select-item.jsx +0 -26
- package/src/core/lib/components/ui/select/select-label.jsx +0 -11
- package/src/core/lib/components/ui/select/select-portal.jsx +0 -4
- package/src/core/lib/components/ui/select/select-scroll-down-button.jsx +0 -18
- package/src/core/lib/components/ui/select/select-scroll-up-button.jsx +0 -18
- package/src/core/lib/components/ui/select/select-separator.jsx +0 -15
- package/src/core/lib/components/ui/select/select-trigger.jsx +0 -25
- package/src/core/lib/components/ui/select/select.jsx +0 -4
- package/src/core/lib/components/ui/sheet/index.js +0 -34
- package/src/core/lib/components/ui/sheet/sheet-close.jsx +0 -7
- package/src/core/lib/components/ui/sheet/sheet-content.jsx +0 -35
- package/src/core/lib/components/ui/sheet/sheet-description.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-footer.jsx +0 -11
- package/src/core/lib/components/ui/sheet/sheet-header.jsx +0 -11
- package/src/core/lib/components/ui/sheet/sheet-overlay.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-portal.jsx +0 -4
- package/src/core/lib/components/ui/sheet/sheet-title.jsx +0 -15
- package/src/core/lib/components/ui/sheet/sheet-trigger.jsx +0 -7
- package/src/core/lib/components/ui/sheet/sheet.jsx +0 -4
- package/src/core/lib/components/ui/toggle/index.js +0 -8
- package/src/core/lib/components/ui/toggle/toggle.jsx +0 -36
- package/src/core/lib/components/ui/toggle-group/index.js +0 -10
- package/src/core/lib/components/ui/toggle-group/toggle-group-item.jsx +0 -29
- package/src/core/lib/components/ui/toggle-group/toggle-group.jsx +0 -43
- package/src/internals/canvas/StoryErrorBoundary.jsx +0 -47
- package/src/internals/canvas/WebGLContextPool.jsx +0 -291
- package/src/internals/canvas/WebGLContextPool.test.jsx +0 -165
- package/src/internals/canvas/componentIsolate.jsx +0 -144
- package/src/internals/canvas/componentSetIsolate.jsx +0 -300
- package/src/internals/canvas/widgets/ComponentSetWidget.module.css +0 -89
- package/src/internals/canvas/widgets/InlineStoryRenderer.jsx +0 -129
- package/src/internals/canvas/widgets/InlineStoryRenderer.test.jsx +0 -68
- package/src/internals/canvas/widgets/StorySetWidget.module.css +0 -89
- package/src/primer/ThemeSync.jsx +0 -73
- package/src/primer/index.js +0 -1
|
@@ -33,9 +33,9 @@ const bannerStyle = {
|
|
|
33
33
|
alignItems: 'center',
|
|
34
34
|
gap: '0.5rem',
|
|
35
35
|
padding: '0.75rem 1rem',
|
|
36
|
-
background: 'var(--
|
|
37
|
-
color: 'var(--
|
|
38
|
-
border: '1px solid var(--
|
|
36
|
+
background: 'var(--color-background, #0d1117)',
|
|
37
|
+
color: 'var(--color-foreground, #e6edf3)',
|
|
38
|
+
border: '1px solid var(--color-border, #30363d)',
|
|
39
39
|
borderRadius: '0.75rem',
|
|
40
40
|
fontFamily: '"Mona Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif',
|
|
41
41
|
fontSize: '0.8125rem',
|
|
@@ -53,14 +53,14 @@ const btnBase = {
|
|
|
53
53
|
|
|
54
54
|
const installBtnStyle = {
|
|
55
55
|
...btnBase,
|
|
56
|
-
background: 'var(--
|
|
56
|
+
background: 'var(--color-background-success-emphasis, #238636)',
|
|
57
57
|
color: '#fff',
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const dismissBtnStyle = {
|
|
61
61
|
...btnBase,
|
|
62
62
|
background: 'transparent',
|
|
63
|
-
color: 'var(--
|
|
63
|
+
color: 'var(--color-foreground-muted, #8d96a0)',
|
|
64
64
|
padding: '0.375rem',
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -2,7 +2,11 @@ import { useState, useEffect } from 'react'
|
|
|
2
2
|
import { TriggerButton } from '../lib/components/ui/trigger-button/index.js'
|
|
3
3
|
import * as DropdownMenu from '../lib/components/ui/dropdown-menu/index.js'
|
|
4
4
|
import Icon from './Icon.jsx'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
themeState, setTheme, getTheme,
|
|
7
|
+
surfaceSyncState, getSurfaceSync, setSurfaceSync,
|
|
8
|
+
} from '../index.js'
|
|
9
|
+
import { getConfig, subscribeToConfig } from '../stores/configStore.js'
|
|
6
10
|
|
|
7
11
|
export default function ThemeMenuButton({ config = {}, data: _data, localOnly: _localOnly, tabindex = -1 }) {
|
|
8
12
|
void _data
|
|
@@ -11,7 +15,8 @@ export default function ThemeMenuButton({ config = {}, data: _data, localOnly: _
|
|
|
11
15
|
const [settingsOpen, setSettingsOpen] = useState(false)
|
|
12
16
|
const [canvasActive, setCanvasActive] = useState(false)
|
|
13
17
|
const [theme, setThemeState] = useState(getTheme)
|
|
14
|
-
const [syncState, setSyncState] = useState(
|
|
18
|
+
const [syncState, setSyncState] = useState(getSurfaceSync)
|
|
19
|
+
const [themesCfg, setThemesCfg] = useState(() => getConfig('theming') || {})
|
|
15
20
|
|
|
16
21
|
useEffect(() => {
|
|
17
22
|
const unsub = themeState.subscribe(s => setThemeState(s.theme))
|
|
@@ -19,7 +24,13 @@ export default function ThemeMenuButton({ config = {}, data: _data, localOnly: _
|
|
|
19
24
|
}, [])
|
|
20
25
|
|
|
21
26
|
useEffect(() => {
|
|
22
|
-
const unsub =
|
|
27
|
+
const unsub = surfaceSyncState.subscribe(s => setSyncState({ ...s }))
|
|
28
|
+
return unsub
|
|
29
|
+
}, [])
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
// Re-derive registry on config HMR (e.g. user edits storyboard.config.json)
|
|
33
|
+
const unsub = subscribeToConfig(() => setThemesCfg(getConfig('theming') || {}))
|
|
23
34
|
return unsub
|
|
24
35
|
}, [])
|
|
25
36
|
|
|
@@ -61,9 +72,30 @@ export default function ThemeMenuButton({ config = {}, data: _data, localOnly: _
|
|
|
61
72
|
|
|
62
73
|
function handleSyncToggle(e, target) {
|
|
63
74
|
e.preventDefault()
|
|
64
|
-
|
|
75
|
+
setSurfaceSync(target, !syncState[target])
|
|
65
76
|
}
|
|
66
77
|
|
|
78
|
+
// Theme list — config-driven. "system" is a synthetic top entry not in
|
|
79
|
+
// the registry; surface it explicitly above the configured themes.
|
|
80
|
+
const themeEntries = Object.entries(themesCfg.themes || {})
|
|
81
|
+
const themeOptions = [
|
|
82
|
+
{ value: 'system', label: 'System' },
|
|
83
|
+
...themeEntries.map(([value, def]) => ({ value, label: def?.label || value })),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
// Surface list — config-driven. The "Apply theme to" sub-menu renders one
|
|
87
|
+
// checkbox per configured surface. The Canvas↔Prototype swap stays —
|
|
88
|
+
// when a canvas is mounted we show Canvas instead of Prototype so the
|
|
89
|
+
// user only sees the surface they're currently looking at.
|
|
90
|
+
const surfaces = themesCfg.surfaces || {}
|
|
91
|
+
const surfaceIds = Object.keys(surfaces)
|
|
92
|
+
const canvasShown = canvasActive && surfaceIds.includes('canvas')
|
|
93
|
+
const visibleSurfaces = surfaceIds.filter((id) => {
|
|
94
|
+
if (id === 'canvas') return canvasShown
|
|
95
|
+
if (id === 'prototype') return !canvasShown
|
|
96
|
+
return true
|
|
97
|
+
})
|
|
98
|
+
|
|
67
99
|
return (
|
|
68
100
|
<DropdownMenu.Root open={menuOpen} onOpenChange={handleMenuOpenChange}>
|
|
69
101
|
<DropdownMenu.Trigger>
|
|
@@ -87,13 +119,13 @@ export default function ThemeMenuButton({ config = {}, data: _data, localOnly: _
|
|
|
87
119
|
{config.label && <DropdownMenu.Label>{config.label}</DropdownMenu.Label>}
|
|
88
120
|
|
|
89
121
|
<DropdownMenu.RadioGroup value={theme}>
|
|
90
|
-
{
|
|
122
|
+
{themeOptions.map((option) => (
|
|
91
123
|
<DropdownMenu.RadioItem
|
|
92
124
|
key={option.value}
|
|
93
125
|
value={option.value}
|
|
94
126
|
onClick={() => handleSelect(option.value)}
|
|
95
127
|
>
|
|
96
|
-
{option.
|
|
128
|
+
{option.label}
|
|
97
129
|
</DropdownMenu.RadioItem>
|
|
98
130
|
))}
|
|
99
131
|
</DropdownMenu.RadioGroup>
|
|
@@ -104,36 +136,19 @@ export default function ThemeMenuButton({ config = {}, data: _data, localOnly: _
|
|
|
104
136
|
<DropdownMenu.SubTrigger>Theme settings</DropdownMenu.SubTrigger>
|
|
105
137
|
<DropdownMenu.SubContent className="min-w-[180px]">
|
|
106
138
|
<DropdownMenu.Label>Apply theme to</DropdownMenu.Label>
|
|
107
|
-
{
|
|
139
|
+
{visibleSurfaces.map((id) => (
|
|
108
140
|
<DropdownMenu.CheckboxItem
|
|
109
|
-
|
|
110
|
-
|
|
141
|
+
key={id}
|
|
142
|
+
checked={!!syncState[id]}
|
|
143
|
+
onSelect={(e) => handleSyncToggle(e, id)}
|
|
111
144
|
>
|
|
112
|
-
|
|
145
|
+
{surfaces[id]?.label || id}
|
|
113
146
|
</DropdownMenu.CheckboxItem>
|
|
114
|
-
)
|
|
115
|
-
<DropdownMenu.CheckboxItem
|
|
116
|
-
checked={syncState.prototype}
|
|
117
|
-
onSelect={(e) => handleSyncToggle(e, 'prototype')}
|
|
118
|
-
>
|
|
119
|
-
Prototype
|
|
120
|
-
</DropdownMenu.CheckboxItem>
|
|
121
|
-
)}
|
|
122
|
-
<DropdownMenu.CheckboxItem
|
|
123
|
-
checked={syncState.toolbar}
|
|
124
|
-
onSelect={(e) => handleSyncToggle(e, 'toolbar')}
|
|
125
|
-
>
|
|
126
|
-
Tools
|
|
127
|
-
</DropdownMenu.CheckboxItem>
|
|
128
|
-
<DropdownMenu.CheckboxItem
|
|
129
|
-
checked={syncState.codeBoxes}
|
|
130
|
-
onSelect={(e) => handleSyncToggle(e, 'codeBoxes')}
|
|
131
|
-
>
|
|
132
|
-
Code boxes
|
|
133
|
-
</DropdownMenu.CheckboxItem>
|
|
147
|
+
))}
|
|
134
148
|
</DropdownMenu.SubContent>
|
|
135
149
|
</DropdownMenu.Sub>
|
|
136
150
|
</DropdownMenu.Content>
|
|
137
151
|
</DropdownMenu.Root>
|
|
138
152
|
)
|
|
139
153
|
}
|
|
154
|
+
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
*
|
|
17
17
|
* TriggerButton uses the `trigger` button variant (no Tailwind dark:
|
|
18
18
|
* classes) so its scoped CSS has full control over background/color.
|
|
19
|
+
*
|
|
20
|
+
* Concrete color values are pinned (not aliased) so toolbar styling
|
|
21
|
+
* stays locked to its own scheme regardless of the global theme cascade
|
|
22
|
+
* defined in `core/styles/tailwind.css`.
|
|
19
23
|
*/
|
|
20
24
|
|
|
21
25
|
/* Default: light tokens */
|
|
@@ -27,43 +31,23 @@
|
|
|
27
31
|
[data-slot="dialog-overlay"] {
|
|
28
32
|
color-scheme: light;
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
--color-
|
|
32
|
-
--color-foreground:
|
|
33
|
-
--color-popover:
|
|
34
|
-
--color-popover-foreground:
|
|
35
|
-
--color-primary:
|
|
36
|
-
--color-primary-foreground:
|
|
37
|
-
--color-secondary:
|
|
38
|
-
--color-secondary-foreground:
|
|
39
|
-
--color-muted:
|
|
40
|
-
--color-muted-foreground:
|
|
41
|
-
--color-accent:
|
|
42
|
-
--color-accent-foreground:
|
|
43
|
-
--color-border:
|
|
44
|
-
--color-
|
|
45
|
-
|
|
46
|
-
--
|
|
47
|
-
--sb--color-foreground: hsl(222.2 84% 4.9%);
|
|
48
|
-
--sb--color-popover: hsl(0 0% 100%);
|
|
49
|
-
--sb--color-popover-foreground: hsl(222.2 84% 4.9%);
|
|
50
|
-
--sb--color-primary: hsl(222.2 47.4% 11.2%);
|
|
51
|
-
--sb--color-primary-foreground: hsl(210 40% 98%);
|
|
52
|
-
--sb--color-secondary: hsl(210 40% 96.1%);
|
|
53
|
-
--sb--color-secondary-foreground: hsl(222.2 47.4% 11.2%);
|
|
54
|
-
--sb--color-muted: hsl(210 40% 96.1%);
|
|
55
|
-
--sb--color-muted-foreground: hsl(215.4 16.3% 46.9%);
|
|
56
|
-
--sb--color-accent: hsl(210 40% 96.1%);
|
|
57
|
-
--sb--color-accent-foreground: hsl(222.2 47.4% 11.2%);
|
|
58
|
-
--sb--color-border: hsl(214.3 31.8% 91.4%);
|
|
59
|
-
--sb--color-input: hsl(214.3 31.8% 91.4%);
|
|
60
|
-
|
|
61
|
-
/* Primer token aliases used in side panel + inspector chrome */
|
|
62
|
-
--bgColor-default: #ffffff;
|
|
63
|
-
--fgColor-default: #1f2328;
|
|
64
|
-
--fgColor-muted: #656d76;
|
|
65
|
-
--borderColor-default: #d1d9e0;
|
|
66
|
-
--bgColor-neutral-muted: rgba(175, 184, 193, 0.2);
|
|
34
|
+
--color-background: #ffffff;
|
|
35
|
+
--color-foreground: #1f2328;
|
|
36
|
+
--color-foreground-muted: #59636e;
|
|
37
|
+
--color-popover: #ffffff;
|
|
38
|
+
--color-popover-foreground: #1f2328;
|
|
39
|
+
--color-primary: #1f2328;
|
|
40
|
+
--color-primary-foreground: #ffffff;
|
|
41
|
+
--color-secondary: #f6f8fa;
|
|
42
|
+
--color-secondary-foreground: #1f2328;
|
|
43
|
+
--color-muted: #f6f8fa;
|
|
44
|
+
--color-muted-foreground: #59636e;
|
|
45
|
+
--color-accent: #ddf4ff;
|
|
46
|
+
--color-accent-foreground: #0969da;
|
|
47
|
+
--color-border: #d1d9e0;
|
|
48
|
+
--color-border-muted: #d1d9e0b3;
|
|
49
|
+
--color-background-neutral-muted: rgba(175, 184, 193, 0.2);
|
|
50
|
+
--color-input: #d1d9e0;
|
|
67
51
|
|
|
68
52
|
/* Slate palette tokens — used by trigger buttons and canvas toolbar */
|
|
69
53
|
--color-slate-100: oklch(96.8% .007 247.896);
|
|
@@ -72,10 +56,7 @@
|
|
|
72
56
|
--color-slate-600: oklch(44.6% .043 257.281);
|
|
73
57
|
}
|
|
74
58
|
|
|
75
|
-
/* Dark tokens — applied when toolbar syncs with a dark theme.
|
|
76
|
-
* Uses Primer-aligned colors (matching base.css --sb-* dark tokens)
|
|
77
|
-
* instead of generic shadcn dark values.
|
|
78
|
-
*/
|
|
59
|
+
/* Dark tokens — applied when toolbar syncs with a dark theme. */
|
|
79
60
|
:root[data-sb-toolbar-theme^="dark"] [data-core-ui-bar],
|
|
80
61
|
:root[data-sb-toolbar-theme^="dark"] [data-sidepanel],
|
|
81
62
|
:root[data-sb-toolbar-theme^="dark"] [data-slot="dropdown-menu-content"],
|
|
@@ -86,6 +67,7 @@
|
|
|
86
67
|
|
|
87
68
|
--color-background: #161b22;
|
|
88
69
|
--color-foreground: #e6edf3;
|
|
70
|
+
--color-foreground-muted: #8b949e;
|
|
89
71
|
--color-popover: #161b22;
|
|
90
72
|
--color-popover-foreground: #e6edf3;
|
|
91
73
|
--color-primary: #e6edf3;
|
|
@@ -94,36 +76,16 @@
|
|
|
94
76
|
--color-secondary-foreground: #e6edf3;
|
|
95
77
|
--color-muted: #21262d;
|
|
96
78
|
--color-muted-foreground: #8b949e;
|
|
97
|
-
--color-accent: #
|
|
98
|
-
--color-accent-foreground: #
|
|
79
|
+
--color-accent: #388bfd1a;
|
|
80
|
+
--color-accent-foreground: #4493f8;
|
|
99
81
|
--color-border: #30363d;
|
|
82
|
+
--color-border-muted: #30363db3;
|
|
83
|
+
--color-background-neutral-muted: rgba(110, 118, 129, 0.2);
|
|
100
84
|
--color-input: #30363d;
|
|
101
85
|
|
|
102
|
-
--sb--color-background: #161b22;
|
|
103
|
-
--sb--color-foreground: #e6edf3;
|
|
104
|
-
--sb--color-popover: #161b22;
|
|
105
|
-
--sb--color-popover-foreground: #e6edf3;
|
|
106
|
-
--sb--color-primary: #e6edf3;
|
|
107
|
-
--sb--color-primary-foreground: #161b22;
|
|
108
|
-
--sb--color-secondary: #21262d;
|
|
109
|
-
--sb--color-secondary-foreground: #e6edf3;
|
|
110
|
-
--sb--color-muted: #21262d;
|
|
111
|
-
--sb--color-muted-foreground: #8b949e;
|
|
112
|
-
--sb--color-accent: #21262d;
|
|
113
|
-
--sb--color-accent-foreground: #e6edf3;
|
|
114
|
-
--sb--color-border: #30363d;
|
|
115
|
-
--sb--color-input: #30363d;
|
|
116
|
-
|
|
117
|
-
/* Primer token aliases used in side panel + inspector chrome */
|
|
118
|
-
--bgColor-default: #161b22;
|
|
119
|
-
--fgColor-default: #e6edf3;
|
|
120
|
-
--fgColor-muted: #8b949e;
|
|
121
|
-
--borderColor-default: #30363d;
|
|
122
|
-
--bgColor-neutral-muted: rgba(110, 118, 129, 0.2);
|
|
123
|
-
|
|
124
86
|
/* Slate palette tokens — dark equivalents */
|
|
125
87
|
--color-slate-100: oklch(20.8% .042 265.755);
|
|
126
88
|
--color-slate-300: oklch(29.3% .042 264.531);
|
|
127
89
|
--color-slate-400: oklch(44.6% .043 257.281);
|
|
128
|
-
--color-slate-600: oklch(
|
|
90
|
+
--color-slate-600: oklch(44.6% .043 257.281);
|
|
129
91
|
}
|
|
@@ -99,11 +99,11 @@ html.sb-sidepanel-open.sb-sidepanel-bottom .sb-mode-switch {
|
|
|
99
99
|
z-index: 9998;
|
|
100
100
|
display: flex;
|
|
101
101
|
flex-direction: column;
|
|
102
|
-
background-color: var(--
|
|
103
|
-
border-left: 1px solid var(--
|
|
102
|
+
background-color: var(--color-background, #ffffff);
|
|
103
|
+
border-left: 1px solid var(--color-border, #d0d7de);
|
|
104
104
|
box-shadow: -4px 0 24px rgba(0, 0, 0, 0.15);
|
|
105
105
|
font-family: "Mona Sans", -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
106
|
-
color: var(--
|
|
106
|
+
color: var(--color-foreground, #1f2328);
|
|
107
107
|
animation: sb-sidepanel-slide-in 0.25s ease;
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -115,7 +115,7 @@ html.sb-sidepanel-open.sb-sidepanel-bottom .sb-mode-switch {
|
|
|
115
115
|
width: 100% !important;
|
|
116
116
|
height: var(--sb--sidepanel-height, 300px);
|
|
117
117
|
border-left: none;
|
|
118
|
-
border-top: 1px solid var(--
|
|
118
|
+
border-top: 1px solid var(--color-border, #d0d7de);
|
|
119
119
|
box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.15);
|
|
120
120
|
animation: sb-sidepanel-slide-up 0.25s ease;
|
|
121
121
|
}
|
|
@@ -199,7 +199,7 @@ html.sb-sidepanel-open.sb-sidepanel-bottom .sb-mode-switch {
|
|
|
199
199
|
font-weight: 600;
|
|
200
200
|
text-transform: uppercase;
|
|
201
201
|
letter-spacing: 0.05em;
|
|
202
|
-
color: var(--
|
|
202
|
+
color: var(--color-foreground-muted, #656d76);
|
|
203
203
|
padding-left: 4px;
|
|
204
204
|
}
|
|
205
205
|
|
|
@@ -213,7 +213,7 @@ html.sb-sidepanel-open.sb-sidepanel-bottom .sb-mode-switch {
|
|
|
213
213
|
appearance: none;
|
|
214
214
|
border: none;
|
|
215
215
|
background: transparent;
|
|
216
|
-
color: var(--
|
|
216
|
+
color: var(--color-foreground-muted, #656d76);
|
|
217
217
|
cursor: pointer;
|
|
218
218
|
padding: 6px;
|
|
219
219
|
border-radius: 6px;
|
|
@@ -224,8 +224,8 @@ html.sb-sidepanel-open.sb-sidepanel-bottom .sb-mode-switch {
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
.sb-sidepanel-action-btn:hover {
|
|
227
|
-
background: var(--
|
|
228
|
-
color: var(--
|
|
227
|
+
background: var(--color-background-neutral-muted, rgba(110, 118, 129, 0.1));
|
|
228
|
+
color: var(--color-foreground, #1f2328);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
/* Body */
|
|
@@ -246,8 +246,8 @@ html.sb-sidepanel-open.sb-sidepanel-bottom .sb-mode-switch {
|
|
|
246
246
|
.sb-sidepanel-spinner {
|
|
247
247
|
width: 20px;
|
|
248
248
|
height: 20px;
|
|
249
|
-
border: 2px solid var(--
|
|
250
|
-
border-top-color: var(--
|
|
249
|
+
border: 2px solid var(--color-border, #d0d7de);
|
|
250
|
+
border-top-color: var(--color-foreground-muted, #656d76);
|
|
251
251
|
border-radius: 50%;
|
|
252
252
|
animation: sb-spin 0.6s linear infinite;
|
|
253
253
|
}
|
|
@@ -263,7 +263,7 @@ html.storyboard-mode-inspect .sb-sidepanel:not(.sb-sidepanel--bottom) {
|
|
|
263
263
|
top: 12px;
|
|
264
264
|
right: 12px;
|
|
265
265
|
bottom: 12px;
|
|
266
|
-
border-radius: var(--
|
|
266
|
+
border-radius: var(--radius);
|
|
267
267
|
border-left: none;
|
|
268
268
|
}
|
|
269
269
|
|
|
@@ -275,7 +275,7 @@ html.storyboard-mode-inspect .sb-sidepanel--bottom {
|
|
|
275
275
|
right: 12px;
|
|
276
276
|
bottom: 12px;
|
|
277
277
|
width: auto !important;
|
|
278
|
-
border-radius: var(--
|
|
278
|
+
border-radius: var(--radius);
|
|
279
279
|
border-top: none;
|
|
280
280
|
}
|
|
281
281
|
|
|
@@ -35,6 +35,8 @@ import { initDeliveryBridge } from '../messaging/delivery.js'
|
|
|
35
35
|
import { getHubsMap } from '../messaging/hub-manager.js'
|
|
36
36
|
import { startMaintenance, stopMaintenance } from '../messaging/hub-maintenance.js'
|
|
37
37
|
import { createArtifactRoutes } from '../artifact/routes.js'
|
|
38
|
+
import { buildArtifactManifest, resolveManifestEnv } from '../data/artifactManifest.js'
|
|
39
|
+
import { buildDataDiscovery } from '../../internals/vite/data-plugin.js'
|
|
38
40
|
|
|
39
41
|
const API_PREFIX = '/_storyboard/'
|
|
40
42
|
|
|
@@ -647,6 +649,17 @@ export default function storyboardServer() {
|
|
|
647
649
|
} catch { sendJsonLogged(res, 200, { branch: null }) }
|
|
648
650
|
})
|
|
649
651
|
|
|
652
|
+
// Per-branch artifact manifest parity route for local dev.
|
|
653
|
+
routeHandlers.set('artifacts.json', async (req, res) => {
|
|
654
|
+
try {
|
|
655
|
+
const discovery = buildDataDiscovery(root, { includeDraft: true })
|
|
656
|
+
const env = resolveManifestEnv({ env: { ...process.env, basePath: base || '/' }, cwd: root })
|
|
657
|
+
sendJsonLogged(res, 200, buildArtifactManifest({ discovery, env }))
|
|
658
|
+
} catch (err) {
|
|
659
|
+
sendJsonLogged(res, 500, { error: err.message || 'Failed to build artifacts manifest' })
|
|
660
|
+
}
|
|
661
|
+
})
|
|
662
|
+
|
|
650
663
|
// Watch toolbar.config.json for changes — trigger full reload so
|
|
651
664
|
// CoreUIBar.jsx picks up menu/mode config changes during dev
|
|
652
665
|
const toolbarConfigPath = path.resolve(
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared cleanup primitives for `workleaf merge` and `workleaf delete`.
|
|
3
|
+
*
|
|
4
|
+
* The two commands diverge only in whether they squash-merge first;
|
|
5
|
+
* everything below (stop server, remove worktree, delete branch,
|
|
6
|
+
* release port) is identical.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import * as p from '@clack/prompts'
|
|
10
|
+
import { execFileSync } from 'node:child_process'
|
|
11
|
+
import { existsSync, rmdirSync } from 'node:fs'
|
|
12
|
+
import { dirname } from 'node:path'
|
|
13
|
+
import { releasePort } from '../worktree/port.js'
|
|
14
|
+
import { findByWorktree, unregister } from '../worktree/serverRegistry.js'
|
|
15
|
+
import { dim } from '../cli/intro.js'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Send SIGTERM to every dev server registered for this workleaf branch,
|
|
19
|
+
* then unregister them. Best-effort — never throws.
|
|
20
|
+
*/
|
|
21
|
+
export function stopDevServer(branch) {
|
|
22
|
+
const servers = findByWorktree(branch)
|
|
23
|
+
for (const s of servers) {
|
|
24
|
+
try {
|
|
25
|
+
process.kill(s.pid, 'SIGTERM')
|
|
26
|
+
} catch (err) {
|
|
27
|
+
if (err.code !== 'ESRCH') {
|
|
28
|
+
p.log.warn(`Could not stop pid ${s.pid}: ${err.message}`)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
unregister(s.id)
|
|
32
|
+
}
|
|
33
|
+
return servers.length
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Remove the git worktree directory. Uses --force so uncommitted state
|
|
38
|
+
* in the workleaf doesn't block delete (callers should validate dirty
|
|
39
|
+
* state first). Also tries to remove the now-empty parent group dir
|
|
40
|
+
* (workleafs/<parent>/) for cosmetic cleanliness.
|
|
41
|
+
*/
|
|
42
|
+
export function removeWorktree(dir, root) {
|
|
43
|
+
if (!existsSync(dir)) return
|
|
44
|
+
try {
|
|
45
|
+
execFileSync('git', ['worktree', 'remove', '--force', dir], { cwd: root, stdio: 'pipe' })
|
|
46
|
+
} catch (err) {
|
|
47
|
+
p.log.warn(`git worktree remove failed: ${err.message}`)
|
|
48
|
+
p.log.info(dim(` Try: rm -rf ${dir} && git worktree prune`))
|
|
49
|
+
}
|
|
50
|
+
// Try to remove the empty parent group dir (workleafs/<parent>/) — best
|
|
51
|
+
// effort, silently no-ops if the dir still has siblings.
|
|
52
|
+
try {
|
|
53
|
+
rmdirSync(dirname(dir))
|
|
54
|
+
} catch { /* still has siblings or already gone */ }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Delete the workleaf branch. Uses -D to allow deleting unmerged branches
|
|
59
|
+
* (delete subcommand) — merge subcommand callers may want to verify
|
|
60
|
+
* merge-state first.
|
|
61
|
+
*/
|
|
62
|
+
export function deleteBranch(branch, root) {
|
|
63
|
+
try {
|
|
64
|
+
execFileSync('git', ['branch', '-D', branch], { cwd: root, stdio: 'pipe' })
|
|
65
|
+
} catch (err) {
|
|
66
|
+
p.log.warn(`git branch -D ${branch} failed: ${err.message}`)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Full cleanup sequence shared by merge + delete:
|
|
72
|
+
* 1. Stop & unregister dev server(s)
|
|
73
|
+
* 2. Remove the git worktree
|
|
74
|
+
* 3. Delete the branch
|
|
75
|
+
* 4. Release the port assignment
|
|
76
|
+
*/
|
|
77
|
+
export function cleanupWorkleaf({ branch, dir, root }) {
|
|
78
|
+
const stopped = stopDevServer(branch)
|
|
79
|
+
removeWorktree(dir, root)
|
|
80
|
+
deleteBranch(branch, root)
|
|
81
|
+
releasePort(branch)
|
|
82
|
+
return { stopped }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Read the current branch of a directory. */
|
|
86
|
+
export function currentBranch(cwd) {
|
|
87
|
+
try {
|
|
88
|
+
return execFileSync('git', ['branch', '--show-current'], { cwd, encoding: 'utf8' }).trim()
|
|
89
|
+
} catch {
|
|
90
|
+
return null
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Check for uncommitted state in a worktree. */
|
|
95
|
+
export function hasDirtyWorkingTree(cwd) {
|
|
96
|
+
try {
|
|
97
|
+
const out = execFileSync('git', ['status', '--porcelain'], { cwd, encoding: 'utf8' }).trim()
|
|
98
|
+
return out.length > 0
|
|
99
|
+
} catch {
|
|
100
|
+
return false
|
|
101
|
+
}
|
|
102
|
+
}
|