@dfosco/storyboard-core 4.2.0-beta.2 → 4.2.0-beta.21
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/commandpalette.config.json +109 -24
- package/dist/storyboard-ui.css +1 -1
- package/dist/storyboard-ui.js +17379 -28568
- package/dist/storyboard-ui.js.map +1 -1
- package/dist/tailwind.css +1 -1
- package/package.json +5 -2
- package/scaffold/agents/prompt-agent.agent.md +181 -0
- package/scaffold/agents/terminal-agent.agent.md +351 -0
- package/scaffold/codex/config.toml +246 -0
- package/scaffold/manifest.json +5 -0
- package/scaffold/skills/canvas/SKILL.md +5 -4
- package/scaffold/skills/ship/SKILL.md +1 -1
- package/scaffold/storyboard.config.json +14 -1
- package/scaffold/toolbar.config.json +1 -1
- package/src/ActionMenuButton.jsx +100 -0
- package/src/AutosyncMenuButton.css +67 -0
- package/src/AutosyncMenuButton.jsx +241 -0
- package/src/BranchSelect.jsx +29 -0
- package/src/BranchSelect.module.css +30 -0
- package/src/CanvasAgentsMenu.jsx +87 -0
- package/src/CanvasCreateMenu.jsx +609 -0
- package/src/CanvasSnap.css +27 -0
- package/src/CanvasSnap.jsx +51 -0
- package/src/CanvasUndoRedo.css +36 -0
- package/src/CanvasUndoRedo.jsx +62 -0
- package/src/CanvasZoomControl.css +53 -0
- package/src/CanvasZoomControl.jsx +49 -0
- package/src/CanvasZoomToFit.css +18 -0
- package/src/CanvasZoomToFit.jsx +26 -0
- package/src/CommandMenu.css +8 -0
- package/src/CommandMenu.jsx +286 -0
- package/src/CommandPalette.jsx +35 -0
- package/src/CommandPaletteTrigger.jsx +25 -0
- package/src/CommentsMenuButton.jsx +38 -0
- package/src/CoreUIBar.css +47 -0
- package/src/CoreUIBar.jsx +855 -0
- package/src/CreateMenuButton.jsx +116 -0
- package/src/HideChromeTrigger.jsx +40 -0
- package/src/InspectorPanel.css +109 -0
- package/src/InspectorPanel.jsx +629 -0
- package/src/PwaInstallBanner.css +42 -0
- package/src/PwaInstallBanner.jsx +124 -0
- package/src/SidePanel.jsx +260 -0
- package/src/ThemeMenuButton.jsx +136 -0
- package/src/autosync/server.js +202 -5
- package/src/autosync/server.test.js +112 -0
- package/src/canvas/__tests__/agent-integration.test.js +593 -0
- package/src/canvas/__tests__/helpers/browser.js +95 -0
- package/src/canvas/__tests__/helpers/canvas-api.js +129 -0
- package/src/canvas/__tests__/helpers/perf.js +118 -0
- package/src/canvas/__tests__/helpers/setup.js +176 -0
- package/src/canvas/__tests__/helpers/tmux.js +130 -0
- package/src/canvas/__tests__/helpers/transcript.js +129 -0
- package/src/canvas/__tests__/terminal-integration.test.js +175 -0
- package/src/canvas/hot-pool.js +757 -0
- package/src/canvas/materializer.js +31 -0
- package/src/canvas/materializer.test.js +56 -0
- package/src/canvas/selectedWidgets.js +65 -7
- package/src/canvas/server.js +1801 -22
- package/src/canvas/server.test.js +239 -0
- package/src/canvas/terminal-config.js +331 -0
- package/src/canvas/terminal-registry.js +38 -0
- package/src/canvas/terminal-server.js +1037 -29
- package/src/canvas/writeGuard.js +51 -3
- package/src/canvasConfig.js +67 -1
- package/src/canvasConfig.test.js +79 -1
- package/src/cli/agent.js +85 -0
- package/src/cli/branch.js +232 -0
- package/src/cli/canvasAdd.js +59 -12
- package/src/cli/canvasBatch.js +98 -0
- package/src/cli/canvasBounds.js +1 -1
- package/src/cli/canvasRead.js +1 -1
- package/src/cli/canvasUpdate.js +179 -0
- package/src/cli/create.js +38 -14
- package/src/cli/dev.js +157 -83
- package/src/cli/exit.js +23 -24
- package/src/cli/index.js +55 -2
- package/src/cli/proxy.js +96 -37
- package/src/cli/schemas.js +22 -4
- package/src/cli/server.js +148 -25
- package/src/cli/serverUrl.js +8 -3
- package/src/cli/sessions.js +131 -5
- package/src/cli/setup.js +109 -11
- package/src/cli/terminal-commands.js +16 -8
- package/src/cli/terminal-messaging.js +231 -0
- package/src/cli/terminal-welcome.js +365 -33
- package/src/commandActions.js +1 -0
- package/src/commandPaletteConfig.js +9 -0
- package/src/comments/auth.js +2 -1
- package/src/comments/ui/AuthModal.jsx +114 -0
- package/src/comments/ui/CommentWindow.jsx +329 -0
- package/src/comments/ui/CommentsDrawer.jsx +102 -0
- package/src/comments/ui/Composer.jsx +64 -0
- package/src/comments/ui/authModal.test.js +1 -1
- package/src/comments/ui/commentWindow.js +16 -17
- package/src/comments/ui/commentsDrawer.js +25 -26
- package/src/comments/ui/composer.js +23 -24
- package/src/comments/ui/index.js +2 -3
- package/src/configSchema.js +59 -1
- package/src/configStore.js +161 -0
- package/src/core-ui-colors.css +12 -0
- package/src/devtools.js +17 -19
- package/src/devtools.test.js +18 -9
- package/src/featureFlags.js +12 -5
- package/src/fuzzySearch.test.js +10 -0
- package/src/index.js +14 -2
- package/src/lib/components/ui/alert/alert-action.jsx +11 -0
- package/src/lib/components/ui/alert/alert-description.jsx +11 -0
- package/src/lib/components/ui/alert/alert-title.jsx +11 -0
- package/src/lib/components/ui/alert/alert.jsx +25 -0
- package/src/lib/components/ui/alert/index.js +15 -15
- package/src/lib/components/ui/avatar/avatar-badge.jsx +22 -0
- package/src/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
- package/src/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
- package/src/lib/components/ui/avatar/avatar-group.jsx +19 -0
- package/src/lib/components/ui/avatar/avatar-image.jsx +15 -0
- package/src/lib/components/ui/avatar/avatar.jsx +19 -0
- package/src/lib/components/ui/avatar/index.js +20 -20
- package/src/lib/components/ui/badge/badge.jsx +31 -0
- package/src/lib/components/ui/badge/index.js +2 -2
- package/src/lib/components/ui/button/button.jsx +100 -0
- package/src/lib/components/ui/button/index.js +9 -9
- package/src/lib/components/ui/card/card-action.jsx +11 -0
- package/src/lib/components/ui/card/card-content.jsx +11 -0
- package/src/lib/components/ui/card/card-description.jsx +11 -0
- package/src/lib/components/ui/card/card-footer.jsx +11 -0
- package/src/lib/components/ui/card/card-header.jsx +19 -0
- package/src/lib/components/ui/card/card-title.jsx +11 -0
- package/src/lib/components/ui/card/card.jsx +17 -0
- package/src/lib/components/ui/card/index.js +23 -23
- package/src/lib/components/ui/checkbox/checkbox.jsx +29 -0
- package/src/lib/components/ui/checkbox/index.js +5 -5
- package/src/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
- package/src/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
- package/src/lib/components/ui/collapsible/collapsible.jsx +7 -0
- package/src/lib/components/ui/collapsible/index.js +11 -11
- package/src/lib/components/ui/dialog/dialog-close.jsx +7 -0
- package/src/lib/components/ui/dialog/dialog-content.jsx +34 -0
- package/src/lib/components/ui/dialog/dialog-description.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-footer.jsx +23 -0
- package/src/lib/components/ui/dialog/dialog-header.jsx +11 -0
- package/src/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-portal.jsx +4 -0
- package/src/lib/components/ui/dialog/dialog-title.jsx +15 -0
- package/src/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
- package/src/lib/components/ui/dialog/dialog.jsx +4 -0
- package/src/lib/components/ui/dialog/index.js +32 -32
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
- package/src/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
- package/src/lib/components/ui/dropdown-menu/index.js +52 -52
- package/src/lib/components/ui/input/index.js +5 -5
- package/src/lib/components/ui/input/input.jsx +19 -0
- package/src/lib/components/ui/label/index.js +5 -5
- package/src/lib/components/ui/label/label.jsx +19 -0
- package/src/lib/components/ui/panel/index.js +21 -21
- package/src/lib/components/ui/panel/panel-body.jsx +11 -0
- package/src/lib/components/ui/panel/panel-close.jsx +16 -0
- package/src/lib/components/ui/panel/panel-content.jsx +29 -0
- package/src/lib/components/ui/panel/panel-footer.jsx +11 -0
- package/src/lib/components/ui/panel/panel-header.jsx +11 -0
- package/src/lib/components/ui/panel/panel-title.jsx +12 -0
- package/src/lib/components/ui/panel/panel.jsx +4 -0
- package/src/lib/components/ui/popover/index.js +26 -26
- package/src/lib/components/ui/popover/popover-close.jsx +7 -0
- package/src/lib/components/ui/popover/popover-content.jsx +22 -0
- package/src/lib/components/ui/popover/popover-description.jsx +11 -0
- package/src/lib/components/ui/popover/popover-header.jsx +11 -0
- package/src/lib/components/ui/popover/popover-portal.jsx +4 -0
- package/src/lib/components/ui/popover/popover-title.jsx +11 -0
- package/src/lib/components/ui/popover/popover-trigger.jsx +8 -0
- package/src/lib/components/ui/popover/popover.jsx +4 -0
- package/src/lib/components/ui/searchable-list.jsx +159 -0
- package/src/lib/components/ui/select/index.js +35 -35
- package/src/lib/components/ui/select/select-content.jsx +30 -0
- package/src/lib/components/ui/select/select-group-heading.jsx +17 -0
- package/src/lib/components/ui/select/select-group.jsx +15 -0
- package/src/lib/components/ui/select/select-item.jsx +26 -0
- package/src/lib/components/ui/select/select-label.jsx +11 -0
- package/src/lib/components/ui/select/select-portal.jsx +4 -0
- package/src/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
- package/src/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
- package/src/lib/components/ui/select/select-separator.jsx +15 -0
- package/src/lib/components/ui/select/select-trigger.jsx +25 -0
- package/src/lib/components/ui/select/select.jsx +4 -0
- package/src/lib/components/ui/separator/index.js +5 -5
- package/src/lib/components/ui/separator/separator.jsx +22 -0
- package/src/lib/components/ui/sheet/index.js +32 -32
- package/src/lib/components/ui/sheet/sheet-close.jsx +7 -0
- package/src/lib/components/ui/sheet/sheet-content.jsx +35 -0
- package/src/lib/components/ui/sheet/sheet-description.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-footer.jsx +11 -0
- package/src/lib/components/ui/sheet/sheet-header.jsx +11 -0
- package/src/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-portal.jsx +4 -0
- package/src/lib/components/ui/sheet/sheet-title.jsx +15 -0
- package/src/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
- package/src/lib/components/ui/sheet/sheet.jsx +4 -0
- package/src/lib/components/ui/textarea/index.js +5 -5
- package/src/lib/components/ui/textarea/textarea.jsx +18 -0
- package/src/lib/components/ui/toggle/index.js +6 -9
- package/src/lib/components/ui/toggle/toggle.jsx +36 -0
- package/src/lib/components/ui/toggle-group/index.js +8 -8
- package/src/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
- package/src/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
- package/src/lib/components/ui/tooltip/index.js +3 -3
- package/src/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
- package/src/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
- package/src/lib/components/ui/tooltip/tooltip.jsx +11 -0
- package/src/lib/components/ui/trigger-button/index.js +3 -3
- package/src/lib/components/ui/trigger-button/trigger-button.css +38 -0
- package/src/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
- package/src/logger/devLogger.js +238 -0
- package/src/logger/devLogger.test.js +193 -0
- package/src/modes.test.js +4 -4
- package/src/mountStoryboardCore.js +123 -27
- package/src/paletteProviders.js +3 -0
- package/src/paletteProviders.test.js +2 -2
- package/src/server/index.js +98 -36
- package/src/sidepanel.css +214 -0
- package/src/styles/tailwind.css +1 -1
- package/src/svelte-plugin-ui/__tests__/ModeSwitch.test.ts +8 -8
- package/src/svelte-plugin-ui/__tests__/ToolbarShell.test.ts +11 -10
- package/src/svelte-plugin-ui/components/Icon.css +11 -0
- package/src/svelte-plugin-ui/components/Icon.jsx +281 -0
- package/src/svelte-plugin-ui/components/ModeSwitch.css +90 -0
- package/src/svelte-plugin-ui/components/ModeSwitch.jsx +47 -0
- package/src/svelte-plugin-ui/components/ToolbarShell.css +80 -0
- package/src/svelte-plugin-ui/components/ToolbarShell.jsx +84 -0
- package/src/svelte-plugin-ui/components/Viewfinder.css +412 -0
- package/src/svelte-plugin-ui/components/Viewfinder.jsx +512 -0
- package/src/svelte-plugin-ui/mount.ts +12 -16
- package/src/toolRegistry.js +4 -4
- package/src/toolbarConfigStore.js +30 -0
- package/src/tools/handlers/autosync.js +1 -1
- package/src/tools/handlers/canvasAddWidget.js +1 -1
- package/src/tools/handlers/canvasAgents.js +19 -0
- package/src/tools/handlers/canvasToolbar.js +8 -8
- package/src/tools/handlers/commandPalette.js +9 -0
- package/src/tools/handlers/comments.js +1 -1
- package/src/tools/handlers/create.js +1 -1
- package/src/tools/handlers/devtools.js +16 -0
- package/src/tools/handlers/devtools.test.js +38 -0
- package/src/tools/handlers/flows.js +1 -1
- package/src/tools/handlers/hideChrome.js +9 -0
- package/src/tools/handlers/paletteTheme.js +35 -0
- package/src/tools/handlers/theme.js +1 -1
- package/src/tools/registry.js +4 -1
- package/src/tools/surfaces/commandList.js +3 -3
- package/src/tools/surfaces/mainToolbar.js +3 -3
- package/src/tools/surfaces/registry.js +4 -4
- package/src/ui/design-modes.ts +2 -2
- package/src/ui/viewfinder.ts +1 -1
- package/src/vite/server-plugin.js +242 -60
- package/src/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
- package/src/workshop/features/createCanvas/index.js +1 -1
- package/src/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
- package/src/workshop/features/createFlow/index.js +1 -1
- package/src/workshop/features/createPage/CreatePageForm.jsx +304 -0
- package/src/workshop/features/createPage/index.js +1 -1
- package/src/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
- package/src/workshop/features/createPrototype/index.js +1 -1
- package/src/workshop/features/createPrototype/server.js +98 -0
- package/src/workshop/features/createStory/CreateStoryForm.jsx +208 -0
- package/src/workshop/features/createStory/index.js +1 -1
- package/src/workshop/ui/WorkshopPanel.jsx +98 -0
- package/src/workshop/ui/mount.ts +1 -1
- package/src/worktree/port.js +48 -0
- package/src/worktree/serverRegistry.js +120 -0
- package/toolbar.config.json +93 -42
- package/widgets.config.json +580 -12
- package/src/ActionMenuButton.svelte +0 -119
- package/src/AutosyncMenuButton.svelte +0 -397
- package/src/CanvasCreateMenu.svelte +0 -295
- package/src/CanvasSnap.svelte +0 -87
- package/src/CanvasUndoRedo.svelte +0 -108
- package/src/CanvasZoomControl.svelte +0 -111
- package/src/CanvasZoomToFit.svelte +0 -52
- package/src/CommandMenu.svelte +0 -249
- package/src/CommandPalette.svelte +0 -33
- package/src/CommentsMenuButton.svelte +0 -53
- package/src/CoreUIBar.svelte +0 -847
- package/src/CreateMenuButton.svelte +0 -133
- package/src/DocPanel.svelte +0 -299
- package/src/InspectorPanel.svelte +0 -745
- package/src/PwaInstallBanner.svelte +0 -124
- package/src/SidePanel.svelte +0 -480
- package/src/ThemeMenuButton.svelte +0 -132
- package/src/comments/ui/AuthModal.svelte +0 -108
- package/src/comments/ui/CommentWindow.svelte +0 -333
- package/src/comments/ui/CommentsDrawer.svelte +0 -96
- package/src/comments/ui/Composer.svelte +0 -65
- package/src/lib/components/ui/alert/alert-action.svelte +0 -19
- package/src/lib/components/ui/alert/alert-description.svelte +0 -22
- package/src/lib/components/ui/alert/alert-title.svelte +0 -22
- package/src/lib/components/ui/alert/alert.svelte +0 -38
- package/src/lib/components/ui/avatar/avatar-badge.svelte +0 -25
- package/src/lib/components/ui/avatar/avatar-fallback.svelte +0 -20
- package/src/lib/components/ui/avatar/avatar-group-count.svelte +0 -22
- package/src/lib/components/ui/avatar/avatar-group.svelte +0 -22
- package/src/lib/components/ui/avatar/avatar-image.svelte +0 -17
- package/src/lib/components/ui/avatar/avatar.svelte +0 -24
- package/src/lib/components/ui/badge/badge.svelte +0 -44
- package/src/lib/components/ui/button/button.svelte +0 -108
- package/src/lib/components/ui/card/card-action.svelte +0 -21
- package/src/lib/components/ui/card/card-content.svelte +0 -19
- package/src/lib/components/ui/card/card-description.svelte +0 -19
- package/src/lib/components/ui/card/card-footer.svelte +0 -18
- package/src/lib/components/ui/card/card-header.svelte +0 -21
- package/src/lib/components/ui/card/card-title.svelte +0 -14
- package/src/lib/components/ui/card/card.svelte +0 -21
- package/src/lib/components/ui/checkbox/checkbox.svelte +0 -39
- package/src/lib/components/ui/collapsible/collapsible-content.svelte +0 -7
- package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +0 -7
- package/src/lib/components/ui/collapsible/collapsible.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog-close.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog-content.svelte +0 -42
- package/src/lib/components/ui/dialog/dialog-description.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-footer.svelte +0 -29
- package/src/lib/components/ui/dialog/dialog-header.svelte +0 -19
- package/src/lib/components/ui/dialog/dialog-overlay.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-portal.svelte +0 -7
- package/src/lib/components/ui/dialog/dialog-title.svelte +0 -17
- package/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -11
- package/src/lib/components/ui/dialog/dialog.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -16
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -40
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -18
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -24
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -20
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -34
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -19
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -17
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -27
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
- package/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -7
- package/src/lib/components/ui/input/input.svelte +0 -40
- package/src/lib/components/ui/label/label.svelte +0 -20
- package/src/lib/components/ui/panel/panel-body.svelte +0 -13
- package/src/lib/components/ui/panel/panel-close.svelte +0 -16
- package/src/lib/components/ui/panel/panel-content.svelte +0 -33
- package/src/lib/components/ui/panel/panel-footer.svelte +0 -13
- package/src/lib/components/ui/panel/panel-header.svelte +0 -16
- package/src/lib/components/ui/panel/panel-title.svelte +0 -14
- package/src/lib/components/ui/panel/panel.svelte +0 -15
- package/src/lib/components/ui/popover/popover-close.svelte +0 -7
- package/src/lib/components/ui/popover/popover-content.svelte +0 -27
- package/src/lib/components/ui/popover/popover-description.svelte +0 -19
- package/src/lib/components/ui/popover/popover-header.svelte +0 -19
- package/src/lib/components/ui/popover/popover-portal.svelte +0 -7
- package/src/lib/components/ui/popover/popover-title.svelte +0 -19
- package/src/lib/components/ui/popover/popover-trigger.svelte +0 -17
- package/src/lib/components/ui/popover/popover.svelte +0 -7
- package/src/lib/components/ui/select/select-content.svelte +0 -40
- package/src/lib/components/ui/select/select-group-heading.svelte +0 -19
- package/src/lib/components/ui/select/select-group.svelte +0 -17
- package/src/lib/components/ui/select/select-item.svelte +0 -38
- package/src/lib/components/ui/select/select-label.svelte +0 -18
- package/src/lib/components/ui/select/select-portal.svelte +0 -7
- package/src/lib/components/ui/select/select-scroll-down-button.svelte +0 -20
- package/src/lib/components/ui/select/select-scroll-up-button.svelte +0 -20
- package/src/lib/components/ui/select/select-separator.svelte +0 -17
- package/src/lib/components/ui/select/select-trigger.svelte +0 -27
- package/src/lib/components/ui/select/select.svelte +0 -11
- package/src/lib/components/ui/separator/separator.svelte +0 -23
- package/src/lib/components/ui/sheet/sheet-close.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet-content.svelte +0 -43
- package/src/lib/components/ui/sheet/sheet-description.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-footer.svelte +0 -18
- package/src/lib/components/ui/sheet/sheet-header.svelte +0 -19
- package/src/lib/components/ui/sheet/sheet-overlay.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-portal.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet-title.svelte +0 -17
- package/src/lib/components/ui/sheet/sheet-trigger.svelte +0 -7
- package/src/lib/components/ui/sheet/sheet.svelte +0 -7
- package/src/lib/components/ui/textarea/textarea.svelte +0 -21
- package/src/lib/components/ui/toggle/toggle.svelte +0 -45
- package/src/lib/components/ui/toggle-group/toggle-group-item.svelte +0 -35
- package/src/lib/components/ui/toggle-group/toggle-group.svelte +0 -63
- package/src/lib/components/ui/tooltip/tooltip-content.svelte +0 -24
- package/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -27
- package/src/lib/components/ui/tooltip/tooltip.svelte +0 -9
- package/src/lib/components/ui/trigger-button/trigger-button.svelte +0 -106
- package/src/svelte-plugin-ui/components/Icon.svelte +0 -181
- package/src/svelte-plugin-ui/components/ModeSwitch.svelte +0 -121
- package/src/svelte-plugin-ui/components/ToolbarShell.svelte +0 -150
- package/src/svelte-plugin-ui/components/Viewfinder.svelte +0 -1001
- package/src/tools/handlers/docs.js +0 -11
- package/src/workshop/features/createCanvas/CreateCanvasForm.svelte +0 -139
- package/src/workshop/features/createFlow/CreateFlowForm.svelte +0 -314
- package/src/workshop/features/createPage/CreatePageForm.svelte +0 -249
- package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +0 -287
- package/src/workshop/features/createStory/CreateStoryForm.svelte +0 -161
- package/src/workshop/ui/WorkshopPanel.svelte +0 -97
|
@@ -19,11 +19,57 @@ import { initPlugins } from './plugins.js'
|
|
|
19
19
|
import { initUIConfig } from './uiConfig.js'
|
|
20
20
|
import { initCanvasConfig } from './canvasConfig.js'
|
|
21
21
|
import { initCommandPaletteConfig } from './commandPaletteConfig.js'
|
|
22
|
-
import { initToolbarConfig } from './toolbarConfigStore.js'
|
|
22
|
+
import { initToolbarConfig, consumeClientToolbarOverrides } from './toolbarConfigStore.js'
|
|
23
23
|
import { initCustomerModeConfig } from './customerModeConfig.js'
|
|
24
|
+
import { getConfig } from './configStore.js'
|
|
24
25
|
|
|
25
26
|
let _mounted = false
|
|
26
27
|
|
|
28
|
+
const CHROME_HIDDEN_KEY = 'sb-chrome-hidden'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Migrate localStorage keys renamed in 4.3.0.
|
|
32
|
+
* Runs once at startup, idempotent: only copies if new key doesn't exist yet.
|
|
33
|
+
*/
|
|
34
|
+
function migrateLocalStorageKeys() {
|
|
35
|
+
if (typeof localStorage === 'undefined') return
|
|
36
|
+
const renames = [
|
|
37
|
+
['sb-viewfinder-starred', 'sb-workspace-starred'],
|
|
38
|
+
['sb-viewfinder-recent', 'sb-workspace-recent'],
|
|
39
|
+
['sb-viewfinder-group-folders', 'sb-workspace-group-folders'],
|
|
40
|
+
]
|
|
41
|
+
for (const [oldKey, newKey] of renames) {
|
|
42
|
+
if (localStorage.getItem(newKey) === null && localStorage.getItem(oldKey) !== null) {
|
|
43
|
+
localStorage.setItem(newKey, localStorage.getItem(oldKey))
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Restore the saved chrome-hidden state immediately, before React mounts.
|
|
50
|
+
* Prevents a flash of toolbars appearing then disappearing.
|
|
51
|
+
*/
|
|
52
|
+
function applyEarlyChromeState() {
|
|
53
|
+
if (typeof document === 'undefined' || typeof localStorage === 'undefined') return
|
|
54
|
+
const hidden = localStorage.getItem(CHROME_HIDDEN_KEY) === '1'
|
|
55
|
+
if (hidden) {
|
|
56
|
+
document.documentElement.classList.add('storyboard-chrome-hidden')
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Watch for changes to the storyboard-chrome-hidden class and persist to
|
|
62
|
+
* localStorage. Works regardless of which code path toggles the class.
|
|
63
|
+
*/
|
|
64
|
+
function installChromeStatePersistence() {
|
|
65
|
+
if (typeof document === 'undefined' || typeof localStorage === 'undefined') return
|
|
66
|
+
const observer = new MutationObserver(() => {
|
|
67
|
+
const hidden = document.documentElement.classList.contains('storyboard-chrome-hidden')
|
|
68
|
+
localStorage.setItem(CHROME_HIDDEN_KEY, hidden ? '1' : '0')
|
|
69
|
+
})
|
|
70
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] })
|
|
71
|
+
}
|
|
72
|
+
|
|
27
73
|
/**
|
|
28
74
|
* Apply the saved theme to Primer CSS attributes immediately, before
|
|
29
75
|
* React or Svelte mount. This prevents a flash of wrong-theme content.
|
|
@@ -138,6 +184,12 @@ export async function mountStoryboardCore(config = {}, options = {}) {
|
|
|
138
184
|
const basePath = options.basePath || '/'
|
|
139
185
|
const customHandlers = options.handlers || {}
|
|
140
186
|
|
|
187
|
+
// Migrate renamed localStorage keys (4.3.0: viewfinder → workspace)
|
|
188
|
+
migrateLocalStorageKeys()
|
|
189
|
+
|
|
190
|
+
// Apply saved chrome-hidden state immediately — before React mount
|
|
191
|
+
applyEarlyChromeState()
|
|
192
|
+
|
|
141
193
|
// Apply saved theme to DOM immediately — before Svelte/React mount
|
|
142
194
|
applyEarlyTheme()
|
|
143
195
|
|
|
@@ -145,60 +197,104 @@ export async function mountStoryboardCore(config = {}, options = {}) {
|
|
|
145
197
|
installHideParamListener()
|
|
146
198
|
installHistorySync()
|
|
147
199
|
installBodyClassSync()
|
|
200
|
+
installChromeStatePersistence()
|
|
148
201
|
|
|
149
|
-
// Initialize config-driven systems
|
|
150
|
-
|
|
202
|
+
// Initialize config-driven systems.
|
|
203
|
+
// The unified config store is already seeded by the virtual module's initConfig().
|
|
204
|
+
// Individual stores are initialized here for backward compatibility — consumers
|
|
205
|
+
// that import directly from these stores still work.
|
|
206
|
+
const uc = getConfig()
|
|
207
|
+
|
|
208
|
+
if (uc.featureFlags && Object.keys(uc.featureFlags).length > 0) {
|
|
209
|
+
initFeatureFlags(uc.featureFlags)
|
|
210
|
+
} else if (config.featureFlags) {
|
|
151
211
|
initFeatureFlags(config.featureFlags)
|
|
152
212
|
}
|
|
153
213
|
|
|
154
|
-
if (
|
|
214
|
+
if (uc.plugins && Object.keys(uc.plugins).length > 0) {
|
|
215
|
+
initPlugins(uc.plugins)
|
|
216
|
+
} else if (config.plugins) {
|
|
155
217
|
initPlugins(config.plugins)
|
|
156
218
|
}
|
|
157
219
|
|
|
158
|
-
if (
|
|
220
|
+
if (uc.ui && Object.keys(uc.ui).length > 0) {
|
|
221
|
+
initUIConfig(uc.ui)
|
|
222
|
+
} else if (config.ui) {
|
|
159
223
|
initUIConfig(config.ui)
|
|
160
224
|
}
|
|
161
225
|
|
|
162
|
-
if (
|
|
226
|
+
if (uc.canvas && Object.keys(uc.canvas).length > 0) {
|
|
227
|
+
initCanvasConfig(uc.canvas)
|
|
228
|
+
} else if (config.canvas) {
|
|
163
229
|
initCanvasConfig(config.canvas)
|
|
164
230
|
}
|
|
165
231
|
|
|
166
232
|
// Load and merge command palette config.
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
const
|
|
170
|
-
if (
|
|
171
|
-
|
|
172
|
-
initCommandPaletteConfig(deepMergeCp(defaultCmdPaletteConfig, config.commandPalette))
|
|
233
|
+
// If the unified store has commandPalette data, use it directly.
|
|
234
|
+
// Otherwise fall back to legacy merging with bundled defaults.
|
|
235
|
+
const ucCmdPalette = uc.commandPalette
|
|
236
|
+
if (ucCmdPalette && Object.keys(ucCmdPalette).length > 0) {
|
|
237
|
+
initCommandPaletteConfig(ucCmdPalette)
|
|
173
238
|
} else {
|
|
174
|
-
|
|
239
|
+
const defaultCmdPaletteConfig = (await import('../commandpalette.config.json')).default
|
|
240
|
+
if (config.commandPalette) {
|
|
241
|
+
const merged = { ...defaultCmdPaletteConfig, ...config.commandPalette }
|
|
242
|
+
if (config.commandPalette.sections && defaultCmdPaletteConfig.sections) {
|
|
243
|
+
const clientIds = new Set(config.commandPalette.sections.map(s => s.id))
|
|
244
|
+
const preserved = defaultCmdPaletteConfig.sections.filter(s => !clientIds.has(s.id))
|
|
245
|
+
merged.sections = [...config.commandPalette.sections, ...preserved]
|
|
246
|
+
}
|
|
247
|
+
initCommandPaletteConfig(merged)
|
|
248
|
+
} else {
|
|
249
|
+
initCommandPaletteConfig({ ...defaultCmdPaletteConfig })
|
|
250
|
+
}
|
|
175
251
|
}
|
|
176
252
|
|
|
177
253
|
// Initialize customer mode config
|
|
178
|
-
if (
|
|
254
|
+
if (uc.customerMode && Object.keys(uc.customerMode).length > 0) {
|
|
255
|
+
initCustomerModeConfig(uc.customerMode)
|
|
256
|
+
} else if (config.customerMode) {
|
|
179
257
|
initCustomerModeConfig(config.customerMode)
|
|
180
258
|
}
|
|
181
259
|
|
|
182
260
|
// Initialize comments config (framework-agnostic)
|
|
183
|
-
|
|
184
|
-
|
|
261
|
+
const commentsConfig = uc.comments && Object.keys(uc.comments).length > 0 ? uc.comments : config.comments
|
|
262
|
+
if (commentsConfig) {
|
|
263
|
+
initCommentsConfig({ ...config, comments: commentsConfig }, { basePath })
|
|
185
264
|
}
|
|
186
265
|
|
|
187
266
|
// Inject compiled UI styles (await to prevent late restyle / FOUC)
|
|
188
267
|
await injectUIStyles()
|
|
189
268
|
|
|
190
|
-
// Load
|
|
191
|
-
//
|
|
192
|
-
//
|
|
269
|
+
// Load toolbar config from the unified store.
|
|
270
|
+
// The unified store already has core defaults merged with client overrides.
|
|
271
|
+
// Fall back to legacy merging if unified store wasn't seeded.
|
|
193
272
|
const { deepMerge } = await import('./loader.js')
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const
|
|
273
|
+
let toolbarConfig = uc.toolbar && Object.keys(uc.toolbar).length > 0
|
|
274
|
+
? { ...uc.toolbar }
|
|
275
|
+
: null
|
|
276
|
+
|
|
277
|
+
if (!toolbarConfig) {
|
|
278
|
+
// Legacy path: unified store not seeded, merge manually
|
|
279
|
+
const defaultConfig = (await import('../toolbar.config.json')).default
|
|
280
|
+
const clientOverrides = consumeClientToolbarOverrides()
|
|
281
|
+
const explicitToolbar = config.toolbar
|
|
282
|
+
|
|
283
|
+
if (explicitToolbar && clientOverrides) {
|
|
284
|
+
toolbarConfig = deepMerge(deepMerge(defaultConfig, clientOverrides), explicitToolbar)
|
|
285
|
+
} else if (explicitToolbar) {
|
|
286
|
+
toolbarConfig = deepMerge(defaultConfig, explicitToolbar)
|
|
287
|
+
} else if (clientOverrides) {
|
|
288
|
+
toolbarConfig = deepMerge(defaultConfig, clientOverrides)
|
|
289
|
+
} else {
|
|
290
|
+
toolbarConfig = { ...defaultConfig }
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Inject repository URL into the toolbar config
|
|
295
|
+
const repo = uc.repository || config.repository
|
|
296
|
+
if (repo?.owner && repo?.name) {
|
|
297
|
+
const repoUrl = `https://github.com/${repo.owner}/${repo.name}`
|
|
202
298
|
|
|
203
299
|
// New tools schema
|
|
204
300
|
if (toolbarConfig.tools?.repository) {
|
package/src/paletteProviders.js
CHANGED
|
@@ -55,6 +55,9 @@ export function buildCommandItems(mode, basePath) {
|
|
|
55
55
|
if (state === 'disabled' || state === 'hidden') continue
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// Skip items hidden from search
|
|
59
|
+
if (action.hideFromCommandPaletteSearch) continue
|
|
60
|
+
|
|
58
61
|
if (action.type === 'submenu') {
|
|
59
62
|
// Flatten submenu children into individual items
|
|
60
63
|
const children = getActionChildren(action.id)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest'
|
|
2
2
|
|
|
3
|
-
// Mock loader and
|
|
3
|
+
// Mock loader and workspace before importing providers
|
|
4
4
|
vi.mock('./loader.js', () => ({
|
|
5
5
|
listStories: vi.fn(() => ['button', 'card']),
|
|
6
6
|
getStoryData: vi.fn((name) => ({
|
|
@@ -34,7 +34,7 @@ vi.mock('./loader.js', () => ({
|
|
|
34
34
|
|
|
35
35
|
vi.mock('./commandActions.js', () => ({
|
|
36
36
|
getActionsForMode: vi.fn(() => [
|
|
37
|
-
{ id: 'core/
|
|
37
|
+
{ id: 'core/workspace', label: 'Go to Workspace', type: 'link', url: '/', toolKey: 'workspace' },
|
|
38
38
|
{ id: 'core/docs', label: 'Documentation', type: 'default', toolKey: 'docs' },
|
|
39
39
|
{ id: 'core/devtools', label: 'DevTools', type: 'submenu', toolKey: 'devtools' },
|
|
40
40
|
{ type: 'header', label: 'Command Menu' },
|
package/src/server/index.js
CHANGED
|
@@ -16,9 +16,11 @@ import http from 'node:http'
|
|
|
16
16
|
import { spawn } from 'node:child_process'
|
|
17
17
|
import { existsSync, readFileSync, mkdirSync } from 'node:fs'
|
|
18
18
|
import { resolve, join, dirname } from 'node:path'
|
|
19
|
-
import { getPort,
|
|
19
|
+
import { getPort, releasePort, repoRoot, worktreeDir, listWorktrees } from '../worktree/port.js'
|
|
20
20
|
import { generateCaddyfile, generateRouteConfig, upsertCaddyRoute, isCaddyRunning, reloadCaddy, readDevDomain } from '../cli/proxy.js'
|
|
21
21
|
import { compactAll } from '../canvas/compact.js'
|
|
22
|
+
import { register, unregister, generateId, list, findByWorktree } from '../worktree/serverRegistry.js'
|
|
23
|
+
import { createDevLogger } from '../logger/devLogger.js'
|
|
22
24
|
|
|
23
25
|
const SERVER_PORT_BASE = 4100
|
|
24
26
|
|
|
@@ -46,6 +48,12 @@ const processes = new Map()
|
|
|
46
48
|
/** Route handlers: prefix → handler function */
|
|
47
49
|
const routeHandlers = new Map()
|
|
48
50
|
|
|
51
|
+
// ─── Dev Logger ───
|
|
52
|
+
|
|
53
|
+
let _currentBranch = null
|
|
54
|
+
try { _currentBranch = (await import('node:child_process')).execSync('git branch --show-current', { encoding: 'utf8', cwd: repoRoot() }).trim() } catch {}
|
|
55
|
+
const devLogger = createDevLogger({ root: repoRoot(), devDomain: DEV_DOMAIN.replace('.localhost', ''), branch: _currentBranch })
|
|
56
|
+
|
|
49
57
|
// ─── JSON helpers ───
|
|
50
58
|
|
|
51
59
|
function sendJson(res, status, data) {
|
|
@@ -54,6 +62,21 @@ function sendJson(res, status, data) {
|
|
|
54
62
|
res.end(body)
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
function sendJsonLogged(res, status, data) {
|
|
66
|
+
sendJson(res, status, data)
|
|
67
|
+
if (status >= 400) {
|
|
68
|
+
const ctx = res.__sbLogCtx || {}
|
|
69
|
+
devLogger.logResponse({
|
|
70
|
+
status,
|
|
71
|
+
method: ctx.method || 'UNKNOWN',
|
|
72
|
+
url: ctx.url || '',
|
|
73
|
+
route: ctx.route || null,
|
|
74
|
+
subRoute: ctx.subRoute || null,
|
|
75
|
+
error: data?.error || null,
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
57
80
|
async function parseBody(req) {
|
|
58
81
|
const chunks = []
|
|
59
82
|
for await (const chunk of req) chunks.push(chunk)
|
|
@@ -117,15 +140,23 @@ function spawnVite(branch) {
|
|
|
117
140
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
118
141
|
})
|
|
119
142
|
|
|
120
|
-
const entry = { child, port, status: 'starting', cwd, branch }
|
|
143
|
+
const entry = { child, port, status: 'starting', cwd, branch, serverId: generateId() }
|
|
121
144
|
processes.set(branch, entry)
|
|
122
145
|
|
|
146
|
+
// Register in persistent server registry
|
|
147
|
+
register({ id: entry.serverId, worktree: branch, pid: child.pid, port, background: true })
|
|
148
|
+
|
|
123
149
|
// Detect ready state from stdout
|
|
124
150
|
child.stdout.on('data', (data) => {
|
|
125
151
|
const text = data.toString()
|
|
126
152
|
const portMatch = text.match(/localhost:(\d+)/)
|
|
127
153
|
if (portMatch) {
|
|
128
|
-
|
|
154
|
+
const actualPort = Number(portMatch[1])
|
|
155
|
+
if (actualPort !== entry.port) {
|
|
156
|
+
entry.port = actualPort
|
|
157
|
+
// Re-register with the actual port Vite bound to
|
|
158
|
+
register({ id: entry.serverId, worktree: branch, pid: child.pid, port: actualPort, background: true })
|
|
159
|
+
}
|
|
129
160
|
}
|
|
130
161
|
if (text.includes('ready in')) {
|
|
131
162
|
entry.status = 'ready'
|
|
@@ -138,6 +169,8 @@ function spawnVite(branch) {
|
|
|
138
169
|
child.on('exit', (code) => {
|
|
139
170
|
entry.status = 'stopped'
|
|
140
171
|
processes.delete(branch)
|
|
172
|
+
unregister(entry.serverId)
|
|
173
|
+
releasePort(branch)
|
|
141
174
|
})
|
|
142
175
|
|
|
143
176
|
return entry
|
|
@@ -167,13 +200,13 @@ function registerCaddyRoute(branch, port) {
|
|
|
167
200
|
// POST /_storyboard/switch-branch
|
|
168
201
|
routeHandlers.set('switch-branch', async (req, res, ctx) => {
|
|
169
202
|
if (ctx.method !== 'POST') {
|
|
170
|
-
|
|
203
|
+
sendJsonLogged(res, 405, { error: 'POST required' })
|
|
171
204
|
return
|
|
172
205
|
}
|
|
173
206
|
|
|
174
207
|
const { branch } = ctx.body
|
|
175
208
|
if (!branch) {
|
|
176
|
-
|
|
209
|
+
sendJsonLogged(res, 400, { error: 'branch is required' })
|
|
177
210
|
return
|
|
178
211
|
}
|
|
179
212
|
|
|
@@ -188,59 +221,76 @@ routeHandlers.set('switch-branch', async (req, res, ctx) => {
|
|
|
188
221
|
if (existing && existing.status === 'ready') {
|
|
189
222
|
const alive = await isPortReady(existing.port)
|
|
190
223
|
if (alive) {
|
|
191
|
-
|
|
224
|
+
sendJsonLogged(res, 200, { url: targetUrl, status: 'already_running' })
|
|
192
225
|
return
|
|
193
226
|
}
|
|
194
227
|
// Stale entry — remove it
|
|
195
228
|
processes.delete(branch)
|
|
196
229
|
}
|
|
197
230
|
|
|
198
|
-
// Check if Vite is already running
|
|
231
|
+
// Check if Vite is already running in this server's process map
|
|
199
232
|
const port = getPort(branch)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
233
|
+
const existingInRegistry = findByWorktree(branch)
|
|
234
|
+
if (existingInRegistry.length > 0) {
|
|
235
|
+
const latest = existingInRegistry.reduce((a, b) =>
|
|
236
|
+
(a.startedAt || '') >= (b.startedAt || '') ? a : b
|
|
237
|
+
)
|
|
238
|
+
if (await isPortReady(latest.port)) {
|
|
239
|
+
registerCaddyRoute(branch, latest.port)
|
|
240
|
+
sendJsonLogged(res, 200, { url: targetUrl, status: 'already_running' })
|
|
241
|
+
return
|
|
242
|
+
}
|
|
204
243
|
}
|
|
205
244
|
|
|
206
245
|
// Check worktree exists
|
|
207
246
|
const cwd = resolveWorktreeCwd(branch)
|
|
208
247
|
if (!cwd) {
|
|
209
|
-
|
|
248
|
+
sendJsonLogged(res, 404, { error: `Worktree not found: ${branch}. Create it with: npx storyboard dev ${branch}` })
|
|
210
249
|
return
|
|
211
250
|
}
|
|
212
251
|
|
|
213
252
|
// Spawn Vite
|
|
214
253
|
const entry = spawnVite(branch)
|
|
215
254
|
|
|
216
|
-
// Wait for ready
|
|
217
|
-
|
|
255
|
+
// Wait for Vite to report ready via stdout (not TCP polling, which
|
|
256
|
+
// can false-positive on occupied ports from other processes)
|
|
257
|
+
const ready = await (async () => {
|
|
258
|
+
const start = Date.now()
|
|
259
|
+
while (Date.now() - start < HEALTH_TIMEOUT) {
|
|
260
|
+
if (entry.status === 'ready') return true
|
|
261
|
+
await new Promise(r => setTimeout(r, 300))
|
|
262
|
+
}
|
|
263
|
+
return false
|
|
264
|
+
})()
|
|
218
265
|
if (!ready) {
|
|
219
266
|
stopVite(branch)
|
|
220
|
-
|
|
267
|
+
sendJsonLogged(res, 504, { error: `Vite server for ${branch} did not become ready in time` })
|
|
221
268
|
return
|
|
222
269
|
}
|
|
223
270
|
|
|
224
|
-
|
|
271
|
+
sendJsonLogged(res, 200, { url: targetUrl, status: 'started' })
|
|
225
272
|
} catch (err) {
|
|
226
|
-
|
|
273
|
+
sendJsonLogged(res, 500, { error: err.message })
|
|
227
274
|
}
|
|
228
275
|
})
|
|
229
276
|
|
|
230
277
|
// GET /_storyboard/worktrees
|
|
231
278
|
routeHandlers.set('worktrees', async (req, res) => {
|
|
232
279
|
try {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
running: processes.has(name) ? processes.get(name).status : null,
|
|
280
|
+
// Use the server registry (live processes) instead of stale ports.json
|
|
281
|
+
const servers = list()
|
|
282
|
+
const branches = servers.map(srv => ({
|
|
283
|
+
branch: srv.worktree,
|
|
284
|
+
folder: srv.worktree === 'main' ? '' : `branch--${srv.worktree}/`,
|
|
285
|
+
port: srv.port,
|
|
286
|
+
running: processes.has(srv.worktree) ? processes.get(srv.worktree).status : 'background',
|
|
241
287
|
}))
|
|
242
|
-
|
|
243
|
-
|
|
288
|
+
// Always include main even if no server is registered for it
|
|
289
|
+
if (!branches.some(b => b.branch === 'main')) {
|
|
290
|
+
branches.unshift({ branch: 'main', folder: '', port: 1234, running: null })
|
|
291
|
+
}
|
|
292
|
+
sendJsonLogged(res, 200, branches)
|
|
293
|
+
} catch { sendJsonLogged(res, 200, []) }
|
|
244
294
|
})
|
|
245
295
|
|
|
246
296
|
// GET /_storyboard/server/status
|
|
@@ -250,10 +300,10 @@ routeHandlers.set('server', async (req, res, ctx) => {
|
|
|
250
300
|
for (const [branch, entry] of processes) {
|
|
251
301
|
active.push({ branch, port: entry.port, status: entry.status })
|
|
252
302
|
}
|
|
253
|
-
|
|
303
|
+
sendJsonLogged(res, 200, { active, serverPort: SERVER_PORT })
|
|
254
304
|
return
|
|
255
305
|
}
|
|
256
|
-
|
|
306
|
+
sendJsonLogged(res, 404, { error: 'Unknown server route' })
|
|
257
307
|
})
|
|
258
308
|
|
|
259
309
|
// ─── HTTP Server ───
|
|
@@ -280,6 +330,9 @@ const server = http.createServer(async (req, res) => {
|
|
|
280
330
|
const prefix = slashIdx === -1 ? after : after.slice(0, slashIdx)
|
|
281
331
|
const restPath = slashIdx === -1 ? '/' : after.slice(slashIdx)
|
|
282
332
|
|
|
333
|
+
// Attach route context for the logging sendJson wrapper
|
|
334
|
+
res.__sbLogCtx = { method: req.method, url: req.url, route: prefix, subRoute: restPath }
|
|
335
|
+
|
|
283
336
|
const handler = routeHandlers.get(prefix)
|
|
284
337
|
if (handler) {
|
|
285
338
|
let body = {}
|
|
@@ -289,8 +342,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
289
342
|
try {
|
|
290
343
|
await handler(req, res, { body, path: restPath, method: req.method })
|
|
291
344
|
} catch (err) {
|
|
292
|
-
|
|
293
|
-
sendJson(res, 500, { error: err.message })
|
|
345
|
+
sendJsonLogged(res, 500, { error: err.message })
|
|
294
346
|
}
|
|
295
347
|
return
|
|
296
348
|
}
|
|
@@ -298,18 +350,28 @@ const server = http.createServer(async (req, res) => {
|
|
|
298
350
|
|
|
299
351
|
// Health check
|
|
300
352
|
if (pathname === '/health') {
|
|
301
|
-
|
|
353
|
+
sendJsonLogged(res, 200, { ok: true, devDomain: DEV_DOMAIN })
|
|
302
354
|
return
|
|
303
355
|
}
|
|
304
356
|
|
|
305
|
-
|
|
357
|
+
// Set context for catch-all 404
|
|
358
|
+
res.__sbLogCtx = { method: req.method, url: req.url, route: null, subRoute: null }
|
|
359
|
+
sendJsonLogged(res, 404, { error: 'Not found' })
|
|
306
360
|
})
|
|
307
361
|
|
|
308
362
|
export function startServer(port = SERVER_PORT) {
|
|
309
|
-
|
|
310
|
-
|
|
363
|
+
return new Promise((resolve, reject) => {
|
|
364
|
+
server.on('error', (err) => {
|
|
365
|
+
if (err.code === 'EADDRINUSE') {
|
|
366
|
+
reject(Object.assign(new Error(`Port ${port} already in use`), { code: 'EADDRINUSE' }))
|
|
367
|
+
return
|
|
368
|
+
}
|
|
369
|
+
reject(err)
|
|
370
|
+
})
|
|
371
|
+
server.listen(port, () => {
|
|
372
|
+
resolve(server)
|
|
373
|
+
})
|
|
311
374
|
})
|
|
312
|
-
return server
|
|
313
375
|
}
|
|
314
376
|
|
|
315
377
|
/** Public API for spawning Vite from CLI (with stdout piping) */
|