@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
|
@@ -14,14 +14,17 @@ import fs from 'node:fs'
|
|
|
14
14
|
import path from 'node:path'
|
|
15
15
|
import { parse as parseJsonc } from 'jsonc-parser'
|
|
16
16
|
import { getConfig } from '../configSchema.js'
|
|
17
|
+
import { createDevLogger, setDevLogger } from '../logger/devLogger.js'
|
|
17
18
|
import { serverFeatures as workshopFeatures } from '../workshop/features/registry-server.js'
|
|
18
19
|
import { docsHandler, collectFiles } from './docs-handler.js'
|
|
19
20
|
import { createCanvasHandler } from '../canvas/server.js'
|
|
20
21
|
import { setupSelectedWidgets } from '../canvas/selectedWidgets.js'
|
|
22
|
+
import { HotPoolManager } from '../canvas/hot-pool.js'
|
|
21
23
|
import { createAutosyncHandler } from '../autosync/server.js'
|
|
22
24
|
import { setupTerminalServer } from '../canvas/terminal-server.js'
|
|
23
|
-
import { listSessions, detachSession, killSession, orphanSession } from '../canvas/terminal-registry.js'
|
|
25
|
+
import { listSessions, detachSession, killSession, orphanSession, bulkCleanup, getSessionStats } from '../canvas/terminal-registry.js'
|
|
24
26
|
import { execSync as cpExecSync } from 'node:child_process'
|
|
27
|
+
import { list as listRunningServers } from '../worktree/serverRegistry.js'
|
|
25
28
|
|
|
26
29
|
const API_PREFIX = '/_storyboard/'
|
|
27
30
|
|
|
@@ -49,6 +52,27 @@ function sendJson(res, status, data) {
|
|
|
49
52
|
res.end(JSON.stringify(data))
|
|
50
53
|
}
|
|
51
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Create a logging wrapper around sendJson.
|
|
57
|
+
* Reads per-request route context from res.__sbLogCtx (set by middleware).
|
|
58
|
+
*/
|
|
59
|
+
function createLoggedSendJson(logger) {
|
|
60
|
+
return function sendJsonLogged(res, status, data) {
|
|
61
|
+
sendJson(res, status, data)
|
|
62
|
+
if (status >= 400 && logger) {
|
|
63
|
+
const ctx = res.__sbLogCtx || {}
|
|
64
|
+
logger.logResponse({
|
|
65
|
+
status,
|
|
66
|
+
method: ctx.method || 'UNKNOWN',
|
|
67
|
+
url: ctx.url || '',
|
|
68
|
+
route: ctx.route || null,
|
|
69
|
+
subRoute: ctx.subRoute || null,
|
|
70
|
+
error: data?.error || null,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
52
76
|
/**
|
|
53
77
|
* Read storyboard.config.json from the project root and apply defaults.
|
|
54
78
|
*/
|
|
@@ -100,11 +124,17 @@ export default function storyboardServer() {
|
|
|
100
124
|
},
|
|
101
125
|
|
|
102
126
|
configureServer(server) {
|
|
103
|
-
// ---
|
|
104
|
-
// Suppress full-reloads and HMR updates for clients
|
|
105
|
-
//
|
|
106
|
-
//
|
|
107
|
-
//
|
|
127
|
+
// --- Reload guard ----------------------------------------------------------
|
|
128
|
+
// Suppress full-reloads and HMR updates for guarded clients.
|
|
129
|
+
//
|
|
130
|
+
// Two guard channels:
|
|
131
|
+
// 1. Canvas guard — canvas pages send heartbeats via storyboard:canvas-hmr-guard.
|
|
132
|
+
// Controlled by the "canvas-auto-reload" feature flag (default: false = guard ON).
|
|
133
|
+
// 2. Prototype guard — all pages send heartbeats via storyboard:prototype-reload-guard.
|
|
134
|
+
// Controlled by the "prototype-auto-reload" feature flag (default: true = guard OFF).
|
|
135
|
+
//
|
|
136
|
+
// Both guards auto-expire 5s after the last heartbeat so closed tabs never
|
|
137
|
+
// leave them stuck. Custom storyboard events always pass through.
|
|
108
138
|
{
|
|
109
139
|
let recentCanvasMutationAt = 0
|
|
110
140
|
const CANVAS_WINDOW_MS = 1500
|
|
@@ -119,29 +149,46 @@ export default function storyboardServer() {
|
|
|
119
149
|
server.watcher.on('add', markCanvasMutation)
|
|
120
150
|
server.watcher.on('unlink', markCanvasMutation)
|
|
121
151
|
|
|
122
|
-
const
|
|
152
|
+
const canvasGuardedClients = new Map()
|
|
153
|
+
const prototypeGuardedClients = new Map()
|
|
123
154
|
|
|
124
155
|
server.hot.on('storyboard:canvas-hmr-guard', (data, client) => {
|
|
125
|
-
if (data.active
|
|
126
|
-
|
|
156
|
+
if (data.active) {
|
|
157
|
+
canvasGuardedClients.set(client, Date.now() + GUARD_TTL_MS)
|
|
158
|
+
} else {
|
|
159
|
+
canvasGuardedClients.delete(client)
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
server.hot.on('storyboard:prototype-reload-guard', (data, client) => {
|
|
164
|
+
if (data.active) {
|
|
165
|
+
prototypeGuardedClients.set(client, Date.now() + GUARD_TTL_MS)
|
|
127
166
|
} else {
|
|
128
|
-
|
|
167
|
+
prototypeGuardedClients.delete(client)
|
|
129
168
|
}
|
|
130
169
|
})
|
|
131
170
|
|
|
132
171
|
const cleanup = setInterval(() => {
|
|
133
172
|
const now = Date.now()
|
|
134
|
-
for (const [client, until] of
|
|
173
|
+
for (const [client, until] of canvasGuardedClients) {
|
|
135
174
|
if (now > until || !server.ws.clients.has(client)) {
|
|
136
|
-
|
|
175
|
+
canvasGuardedClients.delete(client)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
for (const [client, until] of prototypeGuardedClients) {
|
|
179
|
+
if (now > until || !server.ws.clients.has(client)) {
|
|
180
|
+
prototypeGuardedClients.delete(client)
|
|
137
181
|
}
|
|
138
182
|
}
|
|
139
183
|
}, 10000)
|
|
140
184
|
server.httpServer?.on('close', () => clearInterval(cleanup))
|
|
141
185
|
|
|
142
186
|
function isClientGuarded(client) {
|
|
143
|
-
const
|
|
144
|
-
|
|
187
|
+
const cu = canvasGuardedClients.get(client)
|
|
188
|
+
if (cu != null && Date.now() < cu) return true
|
|
189
|
+
const pu = prototypeGuardedClients.get(client)
|
|
190
|
+
if (pu != null && Date.now() < pu) return true
|
|
191
|
+
return false
|
|
145
192
|
}
|
|
146
193
|
|
|
147
194
|
const originalSend = server.ws.send.bind(server.ws)
|
|
@@ -156,7 +203,7 @@ export default function storyboardServer() {
|
|
|
156
203
|
}
|
|
157
204
|
|
|
158
205
|
// No guarded clients → broadcast normally
|
|
159
|
-
if (
|
|
206
|
+
if (canvasGuardedClients.size === 0 && prototypeGuardedClients.size === 0) {
|
|
160
207
|
return originalSend(payload, ...rest)
|
|
161
208
|
}
|
|
162
209
|
|
|
@@ -174,7 +221,28 @@ export default function storyboardServer() {
|
|
|
174
221
|
return originalSend(payload, ...rest)
|
|
175
222
|
}
|
|
176
223
|
}
|
|
177
|
-
// --- End
|
|
224
|
+
// --- End reload guard ------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
// Initialize dev logger for structured o11y logging
|
|
227
|
+
const devDomain = config.devDomain || null
|
|
228
|
+
let currentBranch = null
|
|
229
|
+
try { currentBranch = cpExecSync('git branch --show-current', { encoding: 'utf8', cwd: root }).trim() } catch {}
|
|
230
|
+
const logVerbose = config.featureFlags?.['dev-logs'] || false
|
|
231
|
+
const devLogger = createDevLogger({ root, devDomain, branch: currentBranch, verbose: logVerbose })
|
|
232
|
+
setDevLogger(devLogger) // make available to all server-side modules via devLog()
|
|
233
|
+
const sendJsonLogged = createLoggedSendJson(devLogger)
|
|
234
|
+
|
|
235
|
+
// Listen for browser-side console errors forwarded via HMR
|
|
236
|
+
server.hot.on('storyboard:client-error', (data) => {
|
|
237
|
+
devLogger.logEvent(data.level || 'error', data.message || 'Unknown browser error', {
|
|
238
|
+
source: 'browser',
|
|
239
|
+
url: data.url || null,
|
|
240
|
+
line: data.line || null,
|
|
241
|
+
col: data.col || null,
|
|
242
|
+
stack: data.stack || null,
|
|
243
|
+
route: data.route || null,
|
|
244
|
+
})
|
|
245
|
+
})
|
|
178
246
|
|
|
179
247
|
const workshopConfig = config.workshop || {}
|
|
180
248
|
const enabledFeatures = workshopConfig.features || {}
|
|
@@ -184,7 +252,7 @@ export default function storyboardServer() {
|
|
|
184
252
|
for (const [featureName, featureModule] of Object.entries(workshopFeatures)) {
|
|
185
253
|
if (enabledFeatures[featureName] === false) continue
|
|
186
254
|
if (featureModule.serverSetup) {
|
|
187
|
-
workshopHandlers.push(featureModule.serverSetup({ root, sendJson, workshopConfig }))
|
|
255
|
+
workshopHandlers.push(featureModule.serverSetup({ root, sendJson: sendJsonLogged, workshopConfig }))
|
|
188
256
|
}
|
|
189
257
|
}
|
|
190
258
|
if (workshopHandlers.length > 0) {
|
|
@@ -193,15 +261,24 @@ export default function storyboardServer() {
|
|
|
193
261
|
await handler(req, res, ctx)
|
|
194
262
|
if (res.writableEnded) return
|
|
195
263
|
}
|
|
196
|
-
|
|
264
|
+
sendJsonLogged(res, 404, { error: `Unknown workshop route: ${ctx.method} ${ctx.path}` })
|
|
197
265
|
})
|
|
198
266
|
}
|
|
199
267
|
|
|
200
268
|
// Wire docs API routes (always enabled — serves README + source files)
|
|
201
|
-
routeHandlers.set('docs', docsHandler({ root, sendJson }))
|
|
269
|
+
routeHandlers.set('docs', docsHandler({ root, sendJson: sendJsonLogged }))
|
|
270
|
+
|
|
271
|
+
// Create shared hot pool manager (per-type pre-warmed sessions)
|
|
272
|
+
const hotPoolConfig = config.hotPool || {}
|
|
273
|
+
const agentsConfig = config.canvas?.agents || {}
|
|
274
|
+
const wsSend = server.ws.send.bind(server.ws)
|
|
275
|
+
const hotPool = new HotPoolManager({ root, config: hotPoolConfig, agentsConfig, wsSend })
|
|
276
|
+
hotPool.start().catch((err) => {
|
|
277
|
+
devLogger.logEvent('error', 'Hot pool failed to start', { error: err.message })
|
|
278
|
+
})
|
|
202
279
|
|
|
203
280
|
// Wire canvas API routes (always enabled — CRUD for .canvas.jsonl files)
|
|
204
|
-
routeHandlers.set('canvas', createCanvasHandler({ root, sendJson }))
|
|
281
|
+
routeHandlers.set('canvas', createCanvasHandler({ root, sendJson: sendJsonLogged, hotPool }))
|
|
205
282
|
|
|
206
283
|
// Selected widgets bridge — writes .selectedwidgets.json for Copilot context
|
|
207
284
|
setupSelectedWidgets(server, root)
|
|
@@ -212,15 +289,16 @@ export default function storyboardServer() {
|
|
|
212
289
|
try {
|
|
213
290
|
branch = cpExecSync('git branch --show-current', { encoding: 'utf8', cwd: root }).trim()
|
|
214
291
|
} catch {}
|
|
215
|
-
setupTerminalServer(server.httpServer, base, branch)
|
|
292
|
+
setupTerminalServer(server.httpServer, base, branch, hotPool)
|
|
216
293
|
}
|
|
217
294
|
|
|
218
295
|
// Ignore assets/canvas/ so image/snapshot writes don't trigger reloads
|
|
219
296
|
server.watcher.unwatch(path.join(root, 'assets', 'canvas', 'images'))
|
|
220
297
|
server.watcher.unwatch(path.join(root, 'assets', 'canvas', 'snapshots'))
|
|
298
|
+
server.watcher.unwatch(path.join(root, 'assets', '.storyboard-public', 'terminal-snapshots'))
|
|
221
299
|
|
|
222
300
|
// Wire autosync API routes (always enabled — git automation for dev)
|
|
223
|
-
routeHandlers.set('autosync', createAutosyncHandler({ root, sendJson }))
|
|
301
|
+
routeHandlers.set('autosync', createAutosyncHandler({ root, sendJson: sendJsonLogged }))
|
|
224
302
|
|
|
225
303
|
// Terminal sessions API — list, detach, kill sessions
|
|
226
304
|
routeHandlers.set('terminal', async (req, res, ctx) => {
|
|
@@ -232,7 +310,37 @@ export default function storyboardServer() {
|
|
|
232
310
|
if (ctx.method === 'GET' && (subpath === 'sessions' || subpath === 'sessions/')) {
|
|
233
311
|
const url = new URL(req.url, 'http://localhost')
|
|
234
312
|
const filterBranch = url.searchParams.get('branch') || null
|
|
235
|
-
|
|
313
|
+
sendJsonLogged(res, 200, { sessions: listSessions(filterBranch) })
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// GET /sessions/stats — quick session counts by status
|
|
318
|
+
if (ctx.method === 'GET' && subpath === 'sessions/stats') {
|
|
319
|
+
sendJsonLogged(res, 200, getSessionStats())
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// POST /sessions/cleanup — bulk remove sessions by status
|
|
324
|
+
if (ctx.method === 'POST' && subpath === 'sessions/cleanup') {
|
|
325
|
+
let body = ''
|
|
326
|
+
for await (const chunk of req) body += chunk
|
|
327
|
+
try {
|
|
328
|
+
const { statuses } = JSON.parse(body)
|
|
329
|
+
const allowed = new Set(['archived', 'background'])
|
|
330
|
+
if (!Array.isArray(statuses) || statuses.length === 0) {
|
|
331
|
+
sendJsonLogged(res, 400, { error: 'statuses must be a non-empty array' })
|
|
332
|
+
return
|
|
333
|
+
}
|
|
334
|
+
const invalid = statuses.filter(s => !allowed.has(s))
|
|
335
|
+
if (invalid.length > 0) {
|
|
336
|
+
sendJsonLogged(res, 400, { error: `Invalid statuses: ${invalid.join(', ')}. Allowed: archived, background` })
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
const result = bulkCleanup({ statuses })
|
|
340
|
+
sendJsonLogged(res, 200, { success: true, ...result })
|
|
341
|
+
} catch {
|
|
342
|
+
sendJsonLogged(res, 400, { error: 'Invalid JSON body' })
|
|
343
|
+
}
|
|
236
344
|
return
|
|
237
345
|
}
|
|
238
346
|
|
|
@@ -242,10 +350,10 @@ export default function storyboardServer() {
|
|
|
242
350
|
const tmuxName = decodeURIComponent(detachMatch[1])
|
|
243
351
|
const entry = detachSession(tmuxName)
|
|
244
352
|
if (!entry) {
|
|
245
|
-
|
|
353
|
+
sendJsonLogged(res, 404, { error: 'Session not found' })
|
|
246
354
|
return
|
|
247
355
|
}
|
|
248
|
-
|
|
356
|
+
sendJsonLogged(res, 200, { success: true, session: entry })
|
|
249
357
|
return
|
|
250
358
|
}
|
|
251
359
|
|
|
@@ -254,7 +362,7 @@ export default function storyboardServer() {
|
|
|
254
362
|
if (ctx.method === 'POST' && orphanMatch) {
|
|
255
363
|
const tmuxName = decodeURIComponent(orphanMatch[1])
|
|
256
364
|
orphanSession(tmuxName)
|
|
257
|
-
|
|
365
|
+
sendJsonLogged(res, 200, { success: true })
|
|
258
366
|
return
|
|
259
367
|
}
|
|
260
368
|
|
|
@@ -263,44 +371,76 @@ export default function storyboardServer() {
|
|
|
263
371
|
if (ctx.method === 'DELETE' && deleteMatch) {
|
|
264
372
|
const tmuxName = decodeURIComponent(deleteMatch[1])
|
|
265
373
|
killSession(tmuxName)
|
|
266
|
-
|
|
374
|
+
sendJsonLogged(res, 200, { success: true })
|
|
267
375
|
return
|
|
268
376
|
}
|
|
269
377
|
|
|
270
|
-
|
|
378
|
+
// ── Hot Pool routes (/terminal/hot-pool/*) ──────────────
|
|
379
|
+
|
|
380
|
+
// GET /hot-pool — pool status
|
|
381
|
+
if (ctx.method === 'GET' && subpath === 'hot-pool') {
|
|
382
|
+
sendJsonLogged(res, 200, hotPool.status())
|
|
383
|
+
return
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// PUT /hot-pool — reconfigure pool
|
|
387
|
+
if (ctx.method === 'PUT' && subpath === 'hot-pool') {
|
|
388
|
+
hotPool.reconfigure(ctx.body || {})
|
|
389
|
+
sendJsonLogged(res, 200, hotPool.status())
|
|
390
|
+
return
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// POST /hot-pool/acquire — acquire a warm session from a specific pool
|
|
394
|
+
if (ctx.method === 'POST' && subpath === 'hot-pool/acquire') {
|
|
395
|
+
const poolId = ctx.body?.poolId || 'terminal'
|
|
396
|
+
const session = hotPool.acquire(poolId)
|
|
397
|
+
if (!session) {
|
|
398
|
+
sendJsonLogged(res, 200, { acquired: false, poolId, session: null })
|
|
399
|
+
return
|
|
400
|
+
}
|
|
401
|
+
sendJsonLogged(res, 200, { acquired: true, poolId, session: { id: session.id, tmuxName: session.tmuxName, poolId: session.poolId } })
|
|
402
|
+
return
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
sendJsonLogged(res, 404, { error: 'Not found' })
|
|
271
406
|
})
|
|
272
407
|
|
|
273
|
-
// Worktrees API — lists
|
|
408
|
+
// Worktrees API — lists running worktrees/branches from server registry
|
|
274
409
|
routeHandlers.set('worktrees', async (req, res) => {
|
|
275
410
|
try {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const candidate = path.join(dir, '.worktrees', 'ports.json')
|
|
281
|
-
if (fs.existsSync(candidate)) { portsPath = candidate; break }
|
|
282
|
-
// Check if ports.json is a sibling (we're inside a worktree)
|
|
283
|
-
const parentCandidate = path.join(path.dirname(dir), 'ports.json')
|
|
284
|
-
if (fs.existsSync(parentCandidate)) { portsPath = parentCandidate; break }
|
|
285
|
-
const parent = path.dirname(dir)
|
|
286
|
-
if (parent === dir) break
|
|
287
|
-
dir = parent
|
|
288
|
-
}
|
|
289
|
-
if (!portsPath) { sendJson(res, 200, []); return }
|
|
290
|
-
const ports = JSON.parse(fs.readFileSync(portsPath, 'utf8'))
|
|
291
|
-
const branches = Object.keys(ports).map(name => ({
|
|
292
|
-
branch: name,
|
|
293
|
-
folder: name === 'main' ? '' : `branch--${name}/`,
|
|
411
|
+
const servers = listRunningServers()
|
|
412
|
+
const branches = servers.map(srv => ({
|
|
413
|
+
branch: srv.worktree,
|
|
414
|
+
folder: srv.worktree === 'main' ? '' : `branch--${srv.worktree}/`,
|
|
294
415
|
}))
|
|
295
|
-
|
|
296
|
-
|
|
416
|
+
// Always include main
|
|
417
|
+
if (!branches.some(b => b.branch === 'main')) {
|
|
418
|
+
branches.unshift({ branch: 'main', folder: '' })
|
|
419
|
+
}
|
|
420
|
+
sendJsonLogged(res, 200, branches)
|
|
421
|
+
} catch { sendJsonLogged(res, 200, []) }
|
|
422
|
+
})
|
|
423
|
+
|
|
424
|
+
// Git user — return git config user name and GitHub login (via gh CLI)
|
|
425
|
+
routeHandlers.set('git-user', async (req, res) => {
|
|
426
|
+
try {
|
|
427
|
+
const { execSync } = await import('node:child_process')
|
|
428
|
+
const name = execSync('git config user.name', { cwd: root, encoding: 'utf8' }).trim()
|
|
429
|
+
let login = null
|
|
430
|
+
try {
|
|
431
|
+
const status = execSync('gh auth status 2>&1', { cwd: root, encoding: 'utf8' })
|
|
432
|
+
const m = status.match(/Logged in to github\.com account (\S+)/) || status.match(/Logged in to github\.com as (\S+)/)
|
|
433
|
+
if (m) login = m[1]
|
|
434
|
+
} catch { /* gh not installed or not logged in */ }
|
|
435
|
+
sendJsonLogged(res, 200, { name, login })
|
|
436
|
+
} catch { sendJsonLogged(res, 200, { name: null, login: null }) }
|
|
297
437
|
})
|
|
298
438
|
|
|
299
439
|
// Switch branch — proxy to storyboard server which manages worktree
|
|
300
440
|
// dev servers. The server port is derived from the devDomain.
|
|
301
441
|
routeHandlers.set('switch-branch', async (req, res, ctx) => {
|
|
302
442
|
if (ctx.method !== 'POST') {
|
|
303
|
-
|
|
443
|
+
sendJsonLogged(res, 405, { error: 'POST required' })
|
|
304
444
|
return
|
|
305
445
|
}
|
|
306
446
|
try {
|
|
@@ -319,16 +459,16 @@ export default function storyboardServer() {
|
|
|
319
459
|
body: JSON.stringify(ctx.body),
|
|
320
460
|
})
|
|
321
461
|
const data = await proxyRes.json()
|
|
322
|
-
|
|
462
|
+
sendJsonLogged(res, proxyRes.status, data)
|
|
323
463
|
} catch {
|
|
324
|
-
|
|
464
|
+
sendJsonLogged(res, 502, {
|
|
325
465
|
error: 'Storyboard server not running. Start it with: npx storyboard server',
|
|
326
466
|
})
|
|
327
467
|
}
|
|
328
468
|
})
|
|
329
469
|
|
|
330
470
|
// Watch toolbar.config.json for changes — trigger full reload so
|
|
331
|
-
// CoreUIBar.
|
|
471
|
+
// CoreUIBar.jsx picks up menu/mode config changes during dev
|
|
332
472
|
const toolbarConfigPath = path.resolve(
|
|
333
473
|
path.dirname(new URL(import.meta.url).pathname),
|
|
334
474
|
'../../toolbar.config.json'
|
|
@@ -377,6 +517,9 @@ export default function storyboardServer() {
|
|
|
377
517
|
const prefix = slashIndex === -1 ? pathAfterPrefix : pathAfterPrefix.slice(0, slashIndex)
|
|
378
518
|
const restPath = slashIndex === -1 ? '/' : pathAfterPrefix.slice(slashIndex)
|
|
379
519
|
|
|
520
|
+
// Attach route context for the logging sendJson wrapper
|
|
521
|
+
res.__sbLogCtx = { method: req.method, url, route: prefix, subRoute: restPath }
|
|
522
|
+
|
|
380
523
|
const handler = routeHandlers.get(prefix)
|
|
381
524
|
if (!handler) {
|
|
382
525
|
// Proxy to standalone storyboard server for unhandled prefixes
|
|
@@ -388,7 +531,7 @@ export default function storyboardServer() {
|
|
|
388
531
|
proxyRes.pipe(res)
|
|
389
532
|
})
|
|
390
533
|
proxy.on('error', () => {
|
|
391
|
-
|
|
534
|
+
sendJsonLogged(res, 502, { error: `Storyboard server not running. Start it with: npx storyboard server` })
|
|
392
535
|
})
|
|
393
536
|
if (req.method === 'POST' || req.method === 'PUT' || req.method === 'PATCH') {
|
|
394
537
|
req.pipe(proxy)
|
|
@@ -396,7 +539,7 @@ export default function storyboardServer() {
|
|
|
396
539
|
proxy.end()
|
|
397
540
|
}
|
|
398
541
|
} catch {
|
|
399
|
-
|
|
542
|
+
sendJsonLogged(res, 502, { error: 'Storyboard server not running' })
|
|
400
543
|
}
|
|
401
544
|
return
|
|
402
545
|
}
|
|
@@ -406,10 +549,9 @@ export default function storyboardServer() {
|
|
|
406
549
|
if (req.method === 'POST' || req.method === 'PUT' || req.method === 'PATCH' || req.method === 'DELETE') {
|
|
407
550
|
body = await parseJsonBody(req)
|
|
408
551
|
}
|
|
409
|
-
await handler(req, res, { body, path: restPath, method: req.method })
|
|
552
|
+
await handler(req, res, { body, path: restPath, method: req.method, __viteWs: server.ws })
|
|
410
553
|
} catch (err) {
|
|
411
|
-
|
|
412
|
-
sendJson(res, 500, { error: err.message || 'Internal server error' })
|
|
554
|
+
sendJsonLogged(res, 500, { error: err.message || 'Internal server error' })
|
|
413
555
|
}
|
|
414
556
|
})
|
|
415
557
|
},
|
|
@@ -424,6 +566,46 @@ export default function storyboardServer() {
|
|
|
424
566
|
children: 'window.__SB_LOCAL_DEV__=true',
|
|
425
567
|
injectTo: 'head',
|
|
426
568
|
})
|
|
569
|
+
|
|
570
|
+
// Browser error bridge — forwards console.error/warn and uncaught
|
|
571
|
+
// exceptions to the dev server via HMR for structured o11y logging
|
|
572
|
+
tags.push({
|
|
573
|
+
tag: 'script',
|
|
574
|
+
attrs: { type: 'module' },
|
|
575
|
+
children: `
|
|
576
|
+
(function() {
|
|
577
|
+
if (!import.meta.hot) return;
|
|
578
|
+
var MAX_LEN = 2000;
|
|
579
|
+
function trunc(s) { return typeof s === 'string' && s.length > MAX_LEN ? s.slice(0, MAX_LEN) + '…' : s; }
|
|
580
|
+
function route() { return location.pathname + location.hash; }
|
|
581
|
+
function send(level, msg, extra) {
|
|
582
|
+
try { import.meta.hot.send('storyboard:client-error', Object.assign({ level: level, message: trunc(msg), route: route() }, extra || {})); } catch {}
|
|
583
|
+
}
|
|
584
|
+
// Patch console.error and console.warn
|
|
585
|
+
['error', 'warn'].forEach(function(level) {
|
|
586
|
+
var orig = console[level];
|
|
587
|
+
console[level] = function() {
|
|
588
|
+
orig.apply(console, arguments);
|
|
589
|
+
var parts = [];
|
|
590
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
591
|
+
try { parts.push(typeof arguments[i] === 'string' ? arguments[i] : JSON.stringify(arguments[i])); } catch { parts.push(String(arguments[i])); }
|
|
592
|
+
}
|
|
593
|
+
send(level, parts.join(' '));
|
|
594
|
+
};
|
|
595
|
+
});
|
|
596
|
+
// Uncaught errors
|
|
597
|
+
window.addEventListener('error', function(e) {
|
|
598
|
+
send('error', e.message || 'Uncaught error', { url: e.filename, line: e.lineno, col: e.colno, stack: trunc(e.error && e.error.stack) });
|
|
599
|
+
});
|
|
600
|
+
// Unhandled promise rejections
|
|
601
|
+
window.addEventListener('unhandledrejection', function(e) {
|
|
602
|
+
var msg = e.reason ? (e.reason.message || String(e.reason)) : 'Unhandled rejection';
|
|
603
|
+
send('error', msg, { stack: trunc(e.reason && e.reason.stack) });
|
|
604
|
+
});
|
|
605
|
+
})();
|
|
606
|
+
`.trim(),
|
|
607
|
+
injectTo: 'head',
|
|
608
|
+
})
|
|
427
609
|
}
|
|
428
610
|
|
|
429
611
|
// Inject base path so the inspector UI can resolve static assets
|
|
@@ -549,7 +731,7 @@ export default function storyboardServer() {
|
|
|
549
731
|
|
|
550
732
|
// Emit canvas images so they're available in deployed (static) builds.
|
|
551
733
|
// Dev server serves these dynamically; production needs the static files.
|
|
552
|
-
// Private images (prefixed with
|
|
734
|
+
// Private images (prefixed with ~) are excluded from the build.
|
|
553
735
|
for (const dir of [
|
|
554
736
|
path.join(root, 'assets', 'canvas', 'images'),
|
|
555
737
|
path.join(root, 'assets', 'canvas', 'snapshots'),
|
|
@@ -558,7 +740,7 @@ export default function storyboardServer() {
|
|
|
558
740
|
const imageFiles = await fs.promises.readdir(dir)
|
|
559
741
|
const subdir = dir.endsWith('snapshots') ? 'snapshots' : 'images'
|
|
560
742
|
for (const file of imageFiles) {
|
|
561
|
-
if (file.startsWith('
|
|
743
|
+
if (file.startsWith('~') || file.startsWith('.')) continue
|
|
562
744
|
try {
|
|
563
745
|
const data = await fs.promises.readFile(path.join(dir, file))
|
|
564
746
|
this.emitFile({
|