@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
|
@@ -5,21 +5,67 @@
|
|
|
5
5
|
* Runs inside tmux, presents a Clack select prompt, loops back after
|
|
6
6
|
* the chosen program exits.
|
|
7
7
|
*
|
|
8
|
+
* When called with --startup <cmd>, auto-launches that command on the first
|
|
9
|
+
* iteration, then falls back to the interactive menu on subsequent iterations
|
|
10
|
+
* (i.e. when the command exits). This makes the welcome screen the universal
|
|
11
|
+
* supervisor for all terminal widget sessions.
|
|
12
|
+
*
|
|
8
13
|
* Usage (called automatically by terminal-server for new sessions):
|
|
9
14
|
* storyboard terminal-welcome [--branch <name>] [--canvas <name>]
|
|
15
|
+
* storyboard terminal-welcome --startup "copilot --agent terminal-agent" [--branch <name>] [--canvas <name>]
|
|
10
16
|
*/
|
|
11
17
|
|
|
12
18
|
import * as p from '@clack/prompts'
|
|
13
19
|
import { execSync, spawn } from 'node:child_process'
|
|
20
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
21
|
+
import { resolve, join } from 'node:path'
|
|
14
22
|
import { parseFlags } from './flags.js'
|
|
15
23
|
import { dim, cyan, bold } from './intro.js'
|
|
24
|
+
import { takePendingMessages } from '../canvas/terminal-config.js'
|
|
16
25
|
|
|
17
26
|
const blue = (s) => `\x1b[34m${s}\x1b[0m`
|
|
18
27
|
|
|
28
|
+
// Prepend .storyboard/terminals/bin/ to PATH so `start`, `copilot`, etc.
|
|
29
|
+
// are available in child shells. Done once at startup; child shells inherit it.
|
|
30
|
+
const binDir = join(process.cwd(), '.storyboard', 'terminals', 'bin')
|
|
31
|
+
if (existsSync(binDir) && !process.env.PATH?.includes(binDir)) {
|
|
32
|
+
process.env.PATH = `${binDir}:${process.env.PATH || ''}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Read agents config from storyboard.config.json.
|
|
37
|
+
* Returns an array of { id, label, startupCommand, resumeCommand } entries.
|
|
38
|
+
*/
|
|
39
|
+
function loadAgents() {
|
|
40
|
+
try {
|
|
41
|
+
const raw = readFileSync(resolve(process.cwd(), 'storyboard.config.json'), 'utf8')
|
|
42
|
+
const config = JSON.parse(raw)
|
|
43
|
+
const agents = config?.canvas?.agents
|
|
44
|
+
if (!agents || typeof agents !== 'object') return []
|
|
45
|
+
return Object.entries(agents).map(([id, cfg]) => ({
|
|
46
|
+
id,
|
|
47
|
+
label: cfg.label || id,
|
|
48
|
+
startupCommand: cfg.startupCommand || null,
|
|
49
|
+
resumeCommand: cfg.resumeCommand || null,
|
|
50
|
+
readinessSignal: cfg.readinessSignal || null,
|
|
51
|
+
postStartup: cfg.postStartup || null,
|
|
52
|
+
})).filter(a => a.startupCommand)
|
|
53
|
+
} catch { return [] }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const agents = loadAgents()
|
|
57
|
+
|
|
58
|
+
// Enable/disable tmux mouse — must be off during Clack prompts (mouse
|
|
59
|
+
// events crash Clack), on during shell/copilot sessions (for scrolling).
|
|
60
|
+
function setMouse(on) {
|
|
61
|
+
try { execSync(`tmux set-option mouse ${on ? 'on' : 'off'} 2>/dev/null`, { stdio: 'ignore' }) } catch {}
|
|
62
|
+
}
|
|
63
|
+
|
|
19
64
|
const flagSchema = {
|
|
20
65
|
branch: { type: 'string', description: 'Current branch name' },
|
|
21
66
|
canvas: { type: 'string', description: 'Current canvas name' },
|
|
22
67
|
name: { type: 'string', description: 'Terminal pretty name' },
|
|
68
|
+
startup: { type: 'string', description: 'Auto-launch this command on first iteration' },
|
|
23
69
|
}
|
|
24
70
|
|
|
25
71
|
const { flags } = parseFlags(process.argv.slice(3), flagSchema)
|
|
@@ -27,27 +73,284 @@ const branch = flags.branch || 'unknown'
|
|
|
27
73
|
const canvas = flags.canvas || 'unknown'
|
|
28
74
|
const prettyName = flags.name || null
|
|
29
75
|
const canvasShort = canvas === 'unknown' ? canvas : canvas.split('/').pop()
|
|
76
|
+
const startupCmd = flags.startup || null
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Reset terminal state after a child process exits.
|
|
80
|
+
* Children (especially TUI apps) may leave the terminal in raw mode,
|
|
81
|
+
* alternate screen, or with the cursor hidden.
|
|
82
|
+
*/
|
|
83
|
+
function resetTerminal() {
|
|
84
|
+
// Leave alternate screen, show cursor, reset attributes
|
|
85
|
+
process.stdout.write('\x1b[?1049l\x1b[?25h\x1b[0m')
|
|
86
|
+
try { execSync('stty sane 2>/dev/null', { stdio: 'ignore' }) } catch {}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Spawn an interactive shell with the storyboard bin dir on PATH.
|
|
91
|
+
* zsh re-initializes PATH from .zshrc/.zprofile, so we inject an
|
|
92
|
+
* `export PATH=...` via tmux send-keys after the shell initializes.
|
|
93
|
+
*/
|
|
94
|
+
function spawnShell() {
|
|
95
|
+
const shell = process.env.SHELL || '/bin/zsh'
|
|
96
|
+
const child = spawn(shell, [], { stdio: 'inherit' })
|
|
97
|
+
|
|
98
|
+
// Inject PATH after shell init so `start`, `copilot`, etc. are available
|
|
99
|
+
if (existsSync(binDir)) {
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
try {
|
|
102
|
+
execSync(`tmux send-keys -l ${JSON.stringify(`export PATH="${binDir}:$PATH"`)}`, { stdio: 'ignore' })
|
|
103
|
+
execSync(`tmux send-keys Enter`, { stdio: 'ignore' })
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
try {
|
|
106
|
+
execSync(`tmux send-keys -l "clear"`, { stdio: 'ignore' })
|
|
107
|
+
execSync(`tmux send-keys Enter`, { stdio: 'ignore' })
|
|
108
|
+
} catch {}
|
|
109
|
+
}, 200)
|
|
110
|
+
} catch {}
|
|
111
|
+
}, 500)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return new Promise((resolve) => {
|
|
115
|
+
child.on('close', resolve)
|
|
116
|
+
child.on('error', resolve)
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get the current tmux session name (safe — returns null outside tmux).
|
|
122
|
+
*/
|
|
123
|
+
function getTmuxName() {
|
|
124
|
+
try {
|
|
125
|
+
return execSync('tmux display-message -p "#{session_name}"', { encoding: 'utf8', timeout: 1000 }).trim() || null
|
|
126
|
+
} catch { return null }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Inject [System] identity message into the running agent via tmux send-keys.
|
|
131
|
+
* Mirrors the identity injection in terminal-server.js so agents launched from
|
|
132
|
+
* the welcome menu receive the same initial context.
|
|
133
|
+
*/
|
|
134
|
+
function injectIdentityMessage(tmuxName) {
|
|
135
|
+
const widgetId = process.env.STORYBOARD_WIDGET_ID
|
|
136
|
+
if (!tmuxName || !widgetId) return
|
|
137
|
+
|
|
138
|
+
const canvasId = process.env.STORYBOARD_CANVAS_ID || canvas
|
|
139
|
+
const serverUrl = process.env.STORYBOARD_SERVER_URL || ''
|
|
140
|
+
const displayName = prettyName || widgetId
|
|
141
|
+
const configFile = `.storyboard/terminals/${widgetId}.json`
|
|
142
|
+
|
|
143
|
+
const msg = `[System] Your terminal identity has been set. widgetId=${widgetId} displayName=${displayName} canvasId=${canvasId} configFile=${configFile} serverUrl=${serverUrl} — this is a configuration step, no response needed.`
|
|
144
|
+
try {
|
|
145
|
+
execSync(`tmux send-keys -t "${tmuxName}" -l ${JSON.stringify(msg)}`, { stdio: 'ignore' })
|
|
146
|
+
execSync(`tmux send-keys -t "${tmuxName}" Enter`, { stdio: 'ignore' })
|
|
147
|
+
} catch {}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Deliver pending messages to the running agent via tmux send-keys.
|
|
152
|
+
* Uses takePendingMessages for atomic read+clear.
|
|
153
|
+
*/
|
|
154
|
+
function deliverPendingMessages(tmuxName) {
|
|
155
|
+
const widgetId = process.env.STORYBOARD_WIDGET_ID
|
|
156
|
+
if (!tmuxName || !widgetId) return
|
|
157
|
+
|
|
158
|
+
const messages = takePendingMessages(widgetId)
|
|
159
|
+
messages.forEach((msg, i) => {
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
try {
|
|
162
|
+
const excerpt = msg.message.length > 200 ? msg.message.slice(0, 200) + '…' : msg.message
|
|
163
|
+
const formatted = `📩 [${msg.fromName || msg.from || 'unknown'} → you]\n\`\`\`\n${excerpt}\n\`\`\`${msg.from ? `\nFull context: cat .storyboard/terminals/${msg.from}.json | jq '.latestOutput.content'` : ''}`
|
|
164
|
+
execSync(`tmux send-keys -t "${tmuxName}" -l ${JSON.stringify(formatted)}`, { stdio: 'ignore' })
|
|
165
|
+
execSync(`tmux send-keys -t "${tmuxName}" Enter`, { stdio: 'ignore' })
|
|
166
|
+
} catch {}
|
|
167
|
+
}, i * 1500)
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Launch an agent by spawning its startupCommand via the user's shell.
|
|
173
|
+
* After the agent reaches readiness, injects identity context and pending
|
|
174
|
+
* messages — same treatment as the terminal-server cold path.
|
|
175
|
+
*
|
|
176
|
+
* @param {Object} agent - Agent config with label, startupCommand, readinessSignal, postStartup
|
|
177
|
+
* @param {Object} [opts]
|
|
178
|
+
* @param {boolean} [opts.isInitialStartup=false] - Skip context injection on the first
|
|
179
|
+
* --startup iteration (terminal-server.js handles it independently).
|
|
180
|
+
*/
|
|
181
|
+
async function launchAgent(agent, { isInitialStartup = false } = {}) {
|
|
182
|
+
// Show metadata after selection
|
|
183
|
+
const meta = [
|
|
184
|
+
prettyName ? `${dim('name:')} ${blue(prettyName)}` : null,
|
|
185
|
+
`${dim('branch:')} ${blue(branch)}`,
|
|
186
|
+
`${dim('canvas:')} ${blue(canvasShort)}`,
|
|
187
|
+
].filter(Boolean).join(' ')
|
|
188
|
+
p.log.info(meta)
|
|
189
|
+
p.outro(dim(`Starting ${agent.label}...`))
|
|
190
|
+
setMouse(true)
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const shell = process.env.SHELL || '/bin/zsh'
|
|
194
|
+
const child = spawn(shell, ['-lc', agent.startupCommand], { stdio: 'inherit' })
|
|
195
|
+
|
|
196
|
+
// Context injection — inject identity, postStartup, and pending messages
|
|
197
|
+
// after the agent reaches readiness. Skip on initial --startup since
|
|
198
|
+
// terminal-server.js handles that path independently.
|
|
199
|
+
let pollInterval = null
|
|
200
|
+
const tmuxName = !isInitialStartup ? getTmuxName() : null
|
|
201
|
+
const widgetId = process.env.STORYBOARD_WIDGET_ID
|
|
202
|
+
|
|
203
|
+
if (tmuxName && widgetId) {
|
|
204
|
+
const readinessSignal = agent.readinessSignal
|
|
205
|
+
const firstWord = agent.startupCommand.trim().split(/\s+/)[0]
|
|
206
|
+
|
|
207
|
+
if (readinessSignal) {
|
|
208
|
+
let contextSent = false
|
|
209
|
+
pollInterval = setInterval(() => {
|
|
210
|
+
if (contextSent) { clearInterval(pollInterval); pollInterval = null; return }
|
|
211
|
+
try {
|
|
212
|
+
const paneContent = execSync(
|
|
213
|
+
`tmux capture-pane -t "${tmuxName}" -p`,
|
|
214
|
+
{ encoding: 'utf8', timeout: 1000 }
|
|
215
|
+
)
|
|
216
|
+
// Check configured readiness signal + copilot prompt fallback
|
|
217
|
+
const isReady = paneContent.includes(readinessSignal) ||
|
|
218
|
+
(firstWord === 'copilot' && paneContent.match(/^[>❯]\s*$/m))
|
|
219
|
+
if (isReady) {
|
|
220
|
+
contextSent = true
|
|
221
|
+
clearInterval(pollInterval)
|
|
222
|
+
pollInterval = null
|
|
223
|
+
setTimeout(() => {
|
|
224
|
+
if (agent.postStartup) {
|
|
225
|
+
try {
|
|
226
|
+
execSync(`tmux send-keys -t "${tmuxName}" -l ${JSON.stringify(agent.postStartup)}`, { stdio: 'ignore' })
|
|
227
|
+
execSync(`tmux send-keys -t "${tmuxName}" Enter`, { stdio: 'ignore' })
|
|
228
|
+
} catch {}
|
|
229
|
+
}
|
|
230
|
+
injectIdentityMessage(tmuxName)
|
|
231
|
+
setTimeout(() => deliverPendingMessages(tmuxName), 2000)
|
|
232
|
+
}, 500)
|
|
233
|
+
}
|
|
234
|
+
} catch {}
|
|
235
|
+
}, 2000)
|
|
236
|
+
// Timeout after 30s — don't wait forever
|
|
237
|
+
setTimeout(() => {
|
|
238
|
+
if (!contextSent) {
|
|
239
|
+
contextSent = true
|
|
240
|
+
if (pollInterval) { clearInterval(pollInterval); pollInterval = null }
|
|
241
|
+
}
|
|
242
|
+
}, 30000)
|
|
243
|
+
} else {
|
|
244
|
+
// No readiness signal configured — inject after a delay
|
|
245
|
+
const delayTimer = setTimeout(() => {
|
|
246
|
+
injectIdentityMessage(tmuxName)
|
|
247
|
+
setTimeout(() => deliverPendingMessages(tmuxName), 2000)
|
|
248
|
+
}, 5000)
|
|
249
|
+
// Store reference for cleanup
|
|
250
|
+
pollInterval = { clear: () => clearTimeout(delayTimer) }
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
await new Promise((resolve) => {
|
|
255
|
+
child.on('close', () => {
|
|
256
|
+
if (pollInterval) {
|
|
257
|
+
if (typeof pollInterval.clear === 'function') pollInterval.clear()
|
|
258
|
+
else clearInterval(pollInterval)
|
|
259
|
+
}
|
|
260
|
+
resolve()
|
|
261
|
+
})
|
|
262
|
+
child.on('error', () => {
|
|
263
|
+
if (pollInterval) {
|
|
264
|
+
if (typeof pollInterval.clear === 'function') pollInterval.clear()
|
|
265
|
+
else clearInterval(pollInterval)
|
|
266
|
+
}
|
|
267
|
+
resolve()
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
} catch {
|
|
271
|
+
p.log.error(`Failed to start ${agent.label}. Is it installed?`)
|
|
272
|
+
await new Promise(r => setTimeout(r, 2000))
|
|
273
|
+
}
|
|
274
|
+
}
|
|
30
275
|
|
|
31
276
|
async function welcomeLoop() {
|
|
277
|
+
let firstIteration = true
|
|
278
|
+
|
|
32
279
|
while (true) {
|
|
280
|
+
// On first iteration with --startup, auto-launch the command
|
|
281
|
+
if (firstIteration && startupCmd) {
|
|
282
|
+
firstIteration = false
|
|
283
|
+
|
|
284
|
+
if (startupCmd === 'shell') {
|
|
285
|
+
// Plain shell — spawn interactive shell, return to welcome on exit
|
|
286
|
+
setMouse(true)
|
|
287
|
+
try { await spawnShell() } catch {}
|
|
288
|
+
resetTerminal()
|
|
289
|
+
continue
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Try to match against a configured agent for label resolution
|
|
293
|
+
const matchedAgent = agents.find(a =>
|
|
294
|
+
startupCmd.startsWith(a.startupCommand?.split(' ')[0])
|
|
295
|
+
)
|
|
296
|
+
const agent = matchedAgent || { label: startupCmd.split(/\s+/)[0], startupCommand: startupCmd }
|
|
297
|
+
await launchAgent(agent, { isInitialStartup: true })
|
|
298
|
+
resetTerminal()
|
|
299
|
+
continue
|
|
300
|
+
}
|
|
301
|
+
firstIteration = false
|
|
302
|
+
|
|
303
|
+
resetTerminal()
|
|
304
|
+
setMouse(false)
|
|
33
305
|
console.clear()
|
|
34
306
|
p.intro(`${bold('storyboard terminal')}`)
|
|
35
307
|
|
|
308
|
+
// Build the first option based on number of configured agents
|
|
309
|
+
const agentOption = agents.length > 1
|
|
310
|
+
? { value: 'agents', label: '✦ Start a new agent session' }
|
|
311
|
+
: { value: 'copilot', label: `✦ Start a new ${agents[0]?.label || 'Copilot'} session` }
|
|
312
|
+
|
|
36
313
|
const action = await p.select({
|
|
37
314
|
message: 'How would you like to start?',
|
|
38
315
|
options: [
|
|
39
|
-
|
|
316
|
+
agentOption,
|
|
40
317
|
{ value: 'shell', label: '▸ Start a new terminal session' },
|
|
41
318
|
{ value: 'sessions', label: '⊞ Browse existing sessions' },
|
|
42
319
|
],
|
|
43
320
|
})
|
|
44
321
|
|
|
45
322
|
if (p.isCancel(action)) {
|
|
46
|
-
|
|
47
|
-
|
|
323
|
+
// Don't exit to shell on cancel — loop back to welcome
|
|
324
|
+
continue
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (action === 'agents') {
|
|
328
|
+
// Multi-agent sub-select
|
|
329
|
+
const agentChoice = await p.select({
|
|
330
|
+
message: 'Which agent?',
|
|
331
|
+
options: agents.map(a => ({
|
|
332
|
+
value: a.id,
|
|
333
|
+
label: `✦ Start a new ${a.label} session`,
|
|
334
|
+
})),
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
if (p.isCancel(agentChoice)) continue
|
|
338
|
+
|
|
339
|
+
const agent = agents.find(a => a.id === agentChoice)
|
|
340
|
+
if (agent) {
|
|
341
|
+
await launchAgent(agent)
|
|
342
|
+
}
|
|
343
|
+
continue
|
|
48
344
|
}
|
|
49
345
|
|
|
50
|
-
|
|
346
|
+
if (action === 'copilot') {
|
|
347
|
+
// Single agent — launch directly
|
|
348
|
+
const agent = agents[0] || { label: 'Copilot', startupCommand: 'copilot --agent terminal-agent' }
|
|
349
|
+
await launchAgent(agent)
|
|
350
|
+
continue
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Show metadata for non-agent actions (shell, sessions)
|
|
51
354
|
const meta = [
|
|
52
355
|
prettyName ? `${dim('name:')} ${blue(prettyName)}` : null,
|
|
53
356
|
`${dim('branch:')} ${blue(branch)}`,
|
|
@@ -56,40 +359,69 @@ async function welcomeLoop() {
|
|
|
56
359
|
p.log.info(meta)
|
|
57
360
|
|
|
58
361
|
if (action === 'shell') {
|
|
59
|
-
p.outro(dim('Opening shell...'))
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (action === 'copilot') {
|
|
64
|
-
p.outro(dim('Starting Copilot...'))
|
|
65
|
-
// Run copilot as a child process, wait for it to exit, then loop back
|
|
66
|
-
try {
|
|
67
|
-
const child = spawn('copilot', [], { stdio: 'inherit' })
|
|
68
|
-
await new Promise((resolve) => {
|
|
69
|
-
child.on('close', resolve)
|
|
70
|
-
child.on('error', resolve)
|
|
71
|
-
})
|
|
72
|
-
} catch {
|
|
73
|
-
p.log.error('Failed to start Copilot. Is it installed?')
|
|
74
|
-
await new Promise(r => setTimeout(r, 2000))
|
|
75
|
-
}
|
|
76
|
-
// Loop back to welcome prompt
|
|
362
|
+
p.outro(dim('Opening shell... Enter any command below.'))
|
|
363
|
+
setMouse(true)
|
|
364
|
+
// Spawn an interactive shell; when it exits, loop back to welcome
|
|
365
|
+
try { await spawnShell() } catch {}
|
|
77
366
|
continue
|
|
78
367
|
}
|
|
79
368
|
|
|
80
369
|
if (action === 'sessions') {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
370
|
+
// Sub-menu: pick which agent's sessions to browse, or terminal sessions
|
|
371
|
+
const resumableAgents = agents.filter(a => a.resumeCommand)
|
|
372
|
+
|
|
373
|
+
const sessionOptions = [
|
|
374
|
+
...resumableAgents.map(a => ({
|
|
375
|
+
value: `agent:${a.id}`,
|
|
376
|
+
label: `✦ ${a.label} sessions`,
|
|
377
|
+
})),
|
|
378
|
+
{ value: 'terminal', label: '⊞ Terminal sessions' },
|
|
379
|
+
]
|
|
380
|
+
|
|
381
|
+
const sessionChoice = await p.select({
|
|
382
|
+
message: 'Browse sessions',
|
|
383
|
+
options: sessionOptions,
|
|
384
|
+
})
|
|
385
|
+
|
|
386
|
+
if (p.isCancel(sessionChoice)) continue
|
|
387
|
+
|
|
388
|
+
if (sessionChoice === 'terminal') {
|
|
389
|
+
p.outro(dim('Loading terminal sessions...'))
|
|
390
|
+
try {
|
|
391
|
+
const child = spawn('storyboard', ['terminal'], { stdio: 'inherit' })
|
|
392
|
+
await new Promise((resolve) => {
|
|
393
|
+
child.on('close', resolve)
|
|
394
|
+
child.on('error', resolve)
|
|
395
|
+
})
|
|
396
|
+
} catch {
|
|
397
|
+
p.log.error('Failed to load sessions.')
|
|
398
|
+
await new Promise(r => setTimeout(r, 2000))
|
|
399
|
+
}
|
|
400
|
+
continue
|
|
91
401
|
}
|
|
92
|
-
|
|
402
|
+
|
|
403
|
+
// Agent resume — spawn the resume command interactively
|
|
404
|
+
if (sessionChoice.startsWith('agent:')) {
|
|
405
|
+
const agentId = sessionChoice.replace('agent:', '')
|
|
406
|
+
const agent = resumableAgents.find(a => a.id === agentId)
|
|
407
|
+
if (agent) {
|
|
408
|
+
p.outro(dim(`Loading ${agent.label} sessions...`))
|
|
409
|
+
setMouse(true)
|
|
410
|
+
try {
|
|
411
|
+
const shell = process.env.SHELL || '/bin/zsh'
|
|
412
|
+
const child = spawn(shell, ['-lc', agent.resumeCommand], { stdio: 'inherit' })
|
|
413
|
+
await new Promise((resolve) => {
|
|
414
|
+
child.on('close', resolve)
|
|
415
|
+
child.on('error', resolve)
|
|
416
|
+
})
|
|
417
|
+
} catch {
|
|
418
|
+
p.log.error(`Failed to load ${agent.label} sessions.`)
|
|
419
|
+
await new Promise(r => setTimeout(r, 2000))
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
continue
|
|
423
|
+
}
|
|
424
|
+
|
|
93
425
|
continue
|
|
94
426
|
}
|
|
95
427
|
}
|
package/src/commandActions.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Framework-agnostic (zero npm dependencies).
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { getConfig } from './configStore.js'
|
|
7
|
+
|
|
6
8
|
let _config = { sections: [] }
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -15,8 +17,15 @@ export function initCommandPaletteConfig(config) {
|
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* Get the current command palette config.
|
|
20
|
+
* Falls back to the unified config store if the legacy store wasn't initialized.
|
|
18
21
|
* @returns {{ sections: Array }}
|
|
19
22
|
*/
|
|
20
23
|
export function getCommandPaletteConfig() {
|
|
24
|
+
if (_config.sections.length === 0) {
|
|
25
|
+
const uc = getConfig('commandPalette')
|
|
26
|
+
if (uc?.sections?.length > 0) {
|
|
27
|
+
_config = { sections: [], ...uc }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
21
30
|
return _config
|
|
22
31
|
}
|
package/src/comments/auth.js
CHANGED
|
@@ -73,7 +73,8 @@ export async function validateToken(token) {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
const user = await res.json()
|
|
76
|
-
const
|
|
76
|
+
const scopes = (res.headers.get('x-oauth-scopes') || '').split(',').map(s => s.trim()).filter(Boolean)
|
|
77
|
+
const userInfo = { login: user.login, avatarUrl: user.avatar_url, scopes }
|
|
77
78
|
|
|
78
79
|
// 2. Verify the token can access repository discussions
|
|
79
80
|
await validateTokenPermissions(token)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthModal — PAT entry modal for comments authentication.
|
|
3
|
+
* Uses shadcn Button, Input, Label, Alert, Avatar.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useEffect, useRef } from 'react'
|
|
7
|
+
import { setToken, validateToken } from '../auth.js'
|
|
8
|
+
import { getCommentsConfig } from '../config.js'
|
|
9
|
+
import { Button } from '../../lib/components/ui/button/index.js'
|
|
10
|
+
import { Input } from '../../lib/components/ui/input/index.js'
|
|
11
|
+
import { Label } from '../../lib/components/ui/label/index.js'
|
|
12
|
+
import * as Alert from '../../lib/components/ui/alert/index.js'
|
|
13
|
+
import * as Avatar from '../../lib/components/ui/avatar/index.js'
|
|
14
|
+
|
|
15
|
+
export default function AuthModal({ onDone, onClose, initialError = null }) {
|
|
16
|
+
const [token, setTokenValue] = useState('')
|
|
17
|
+
const [submitting, setSubmitting] = useState(false)
|
|
18
|
+
const [error, setError] = useState(null)
|
|
19
|
+
const [user, setUser] = useState(null)
|
|
20
|
+
const inputRef = useRef(null)
|
|
21
|
+
|
|
22
|
+
const commentsConfig = getCommentsConfig()
|
|
23
|
+
const repoOwner = commentsConfig?.repo?.owner || 'github'
|
|
24
|
+
const repoName = commentsConfig?.repo?.name || 'storyboard'
|
|
25
|
+
const repoSlug = `${repoOwner}/${repoName}`
|
|
26
|
+
const tokenTemplateName = 'Storyboard Comments'
|
|
27
|
+
const tokenTemplateDescription =
|
|
28
|
+
`Token for enabling comments on ${repoSlug} prototype. Configure as:\n\n` +
|
|
29
|
+
`Owner: ${repoOwner}\n` +
|
|
30
|
+
'Expiration: 366 days (recommended)\n' +
|
|
31
|
+
`Repository access: Only select repositories > ${repoSlug}\n` +
|
|
32
|
+
'Permissions: Repositories > Discussions > Access: Read and Write'
|
|
33
|
+
const tokenCreateUrl =
|
|
34
|
+
`https://github.com/settings/personal-access-tokens/new?` +
|
|
35
|
+
new URLSearchParams({
|
|
36
|
+
name: tokenTemplateName,
|
|
37
|
+
description: tokenTemplateDescription,
|
|
38
|
+
}).toString()
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
setError(initialError)
|
|
42
|
+
inputRef.current?.focus()
|
|
43
|
+
}, [])
|
|
44
|
+
|
|
45
|
+
async function submit() {
|
|
46
|
+
const val = token.trim()
|
|
47
|
+
if (!val) return
|
|
48
|
+
setSubmitting(true); setError(null)
|
|
49
|
+
try { const result = await validateToken(val); setToken(val); setUser(result) }
|
|
50
|
+
catch (err) { setError(err.message) }
|
|
51
|
+
finally { setSubmitting(false) }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function done() { if (user) onDone?.(user) }
|
|
55
|
+
|
|
56
|
+
function handleKeydown(e) {
|
|
57
|
+
if (e.key === 'Enter' && !user) submit()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div className="bg-popover text-popover-foreground border border-border rounded-lg shadow-lg overflow-hidden max-w-[600px] w-full font-sans">
|
|
62
|
+
<div className="flex items-center justify-between px-4 py-3 border-b border-border">
|
|
63
|
+
<h2 className="text-medium font-semibold">Sign in for comments</h2>
|
|
64
|
+
<Button variant="ghost" size="icon" onClick={onClose} aria-label="Close" className="h-7 w-7 text-muted-foreground">×</Button>
|
|
65
|
+
</div>
|
|
66
|
+
<div className="p-4 space-y-3">
|
|
67
|
+
{error && <Alert.Root variant="destructive"><Alert.Description>{error}</Alert.Description></Alert.Root>}
|
|
68
|
+
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
69
|
+
Leave comments for other users to see and respond, and react to! Storyboard comments use Discussions as a back-end and require a GitHub PAT to be enabled.
|
|
70
|
+
</p>
|
|
71
|
+
<p className="text-sm text-muted-foreground leading-relaxed">
|
|
72
|
+
Create a <a className="text-primary underline" href={tokenCreateUrl} target="_blank" rel="noopener">GitHub Fine-Grained Personal Access Token</a> with the settings below to get started:
|
|
73
|
+
</p>
|
|
74
|
+
<div className="px-3 py-2 bg-muted border border-border rounded text-xs text-muted-foreground leading-relaxed">
|
|
75
|
+
<div className="mb-1"><strong className="text-foreground">Fine-grained Personal Access Token</strong></div>
|
|
76
|
+
<div>Owner: <code className="px-1 bg-background rounded font-mono text-foreground">{repoOwner}</code></div>
|
|
77
|
+
<div>Expiration: <code className="px-1 bg-background rounded font-mono text-foreground">366 days</code> (recommended)</div>
|
|
78
|
+
<div>Repository access: <code className="px-1 bg-background rounded font-mono text-foreground">Only select repositories > {repoSlug}</code></div>
|
|
79
|
+
<div>Permissions: <code className="px-1 bg-background rounded font-mono text-foreground">Repositories > Discussions > Access: Read and Write</code></div>
|
|
80
|
+
</div>
|
|
81
|
+
<div className="space-y-1">
|
|
82
|
+
<Label htmlFor="sb-auth-token-input">Personal Access Token</Label>
|
|
83
|
+
<Input
|
|
84
|
+
id="sb-auth-token-input"
|
|
85
|
+
type="password"
|
|
86
|
+
placeholder="github_pat_… or ghp_…"
|
|
87
|
+
autoComplete="off"
|
|
88
|
+
spellCheck={false}
|
|
89
|
+
className="font-mono"
|
|
90
|
+
value={token}
|
|
91
|
+
onChange={(e) => setTokenValue(e.target.value)}
|
|
92
|
+
ref={inputRef}
|
|
93
|
+
onKeyDown={handleKeydown}
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
{user && (
|
|
97
|
+
<div className="flex items-center py-1 gap-3">
|
|
98
|
+
<Avatar.Root className="h-10 w-10"><Avatar.Image src={user.avatarUrl} alt={user.login} /><Avatar.Fallback>{user.login[0]?.toUpperCase()}</Avatar.Fallback></Avatar.Root>
|
|
99
|
+
<div className="text-sm"><span className="text-foreground">{user.login}</span><span className="block text-xs text-success mt-0.5">✓ Signed in</span></div>
|
|
100
|
+
</div>
|
|
101
|
+
)}
|
|
102
|
+
<Alert.Root variant="warning" className="bg-amber-100 border-amber-300">
|
|
103
|
+
<Alert.Description className="text-amber-700">
|
|
104
|
+
⚠️ Comments are an experimental feature and may be unstable.
|
|
105
|
+
</Alert.Description>
|
|
106
|
+
</Alert.Root>
|
|
107
|
+
</div>
|
|
108
|
+
<div className="flex items-center justify-end px-4 py-3 border-t border-border gap-2">
|
|
109
|
+
<Button variant="outline" size="sm" onClick={onClose}>Cancel</Button>
|
|
110
|
+
<Button size="sm" disabled={submitting} onClick={user ? done : submit}>{user ? 'Done' : (submitting ? 'Validating\u2026' : 'Sign in')}</Button>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
)
|
|
114
|
+
}
|