@dfosco/storyboard 0.5.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commandpalette.config.json +152 -0
- package/dist/storyboard-ui.css +1 -0
- package/dist/storyboard-ui.js +21328 -0
- package/dist/storyboard-ui.js.map +1 -0
- package/dist/tailwind.css +2 -0
- package/dist/tiny-canvas.css +1 -0
- package/dist/tiny-canvas.js +389 -0
- package/package.json +121 -0
- package/paste.config.json +67 -0
- package/scaffold/AGENTS.md +432 -0
- 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/deploy.yml +103 -0
- package/scaffold/githooks/pre-push +114 -0
- package/scaffold/gitignore +64 -0
- package/scaffold/manifest.json +56 -0
- package/scaffold/preview.yml +181 -0
- package/scaffold/scripts/link.sh +26 -0
- package/scaffold/scripts/unlink.sh +10 -0
- package/scaffold/skills/agent-browser/SKILL.md +260 -0
- package/scaffold/skills/canvas/SKILL.md +364 -0
- package/scaffold/skills/create/SKILL.md +501 -0
- package/scaffold/skills/ship/SKILL.md +237 -0
- package/scaffold/skills/storyboard/SKILL.md +360 -0
- package/scaffold/skills/update-storyboard/SKILL.md +16 -0
- package/scaffold/skills/update-storyboard/update-storyboard-packages.sh +26 -0
- package/scaffold/skills/vitest/GENERATION.md +5 -0
- package/scaffold/skills/vitest/SKILL.md +52 -0
- package/scaffold/skills/vitest/references/advanced-environments.md +264 -0
- package/scaffold/skills/vitest/references/advanced-projects.md +300 -0
- package/scaffold/skills/vitest/references/advanced-type-testing.md +237 -0
- package/scaffold/skills/vitest/references/advanced-vi.md +249 -0
- package/scaffold/skills/vitest/references/core-cli.md +166 -0
- package/scaffold/skills/vitest/references/core-config.md +174 -0
- package/scaffold/skills/vitest/references/core-describe.md +193 -0
- package/scaffold/skills/vitest/references/core-expect.md +219 -0
- package/scaffold/skills/vitest/references/core-hooks.md +244 -0
- package/scaffold/skills/vitest/references/core-test-api.md +233 -0
- package/scaffold/skills/vitest/references/features-concurrency.md +250 -0
- package/scaffold/skills/vitest/references/features-context.md +238 -0
- package/scaffold/skills/vitest/references/features-coverage.md +207 -0
- package/scaffold/skills/vitest/references/features-filtering.md +211 -0
- package/scaffold/skills/vitest/references/features-mocking.md +265 -0
- package/scaffold/skills/vitest/references/features-snapshots.md +207 -0
- package/scaffold/skills/worktree/SKILL.md +93 -0
- package/scaffold/storyboard.config.json +44 -0
- package/src/canvas/Canvas.jsx +78 -0
- package/src/canvas/Draggable.jsx +235 -0
- package/src/canvas/index.d.ts +41 -0
- package/src/canvas/index.js +6 -0
- package/src/canvas/style.css +118 -0
- package/src/canvas/useResetCanvas.js +17 -0
- package/src/canvas/utils.js +136 -0
- package/src/core/assets/fonts/IoskeleyMono-Bold.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Italic.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Medium.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-Regular.woff2 +0 -0
- package/src/core/assets/fonts/IoskeleyMono-SemiBold.woff2 +0 -0
- package/src/core/autosync/server.js +714 -0
- package/src/core/autosync/server.test.js +158 -0
- package/src/core/canvas/__tests__/agent-integration.test.js +596 -0
- package/src/core/canvas/__tests__/helpers/browser.js +95 -0
- package/src/core/canvas/__tests__/helpers/canvas-api.js +129 -0
- package/src/core/canvas/__tests__/helpers/perf.js +118 -0
- package/src/core/canvas/__tests__/helpers/setup.js +176 -0
- package/src/core/canvas/__tests__/helpers/tmux.js +130 -0
- package/src/core/canvas/__tests__/helpers/transcript.js +132 -0
- package/src/core/canvas/__tests__/terminal-integration.test.js +177 -0
- package/src/core/canvas/collision.js +292 -0
- package/src/core/canvas/collision.test.js +371 -0
- package/src/core/canvas/compact.js +83 -0
- package/src/core/canvas/deriveCanvasId.test.js +40 -0
- package/src/core/canvas/githubEmbeds.js +527 -0
- package/src/core/canvas/githubEmbeds.test.js +302 -0
- package/src/core/canvas/hot-pool.js +766 -0
- package/src/core/canvas/identity.js +107 -0
- package/src/core/canvas/identity.test.js +100 -0
- package/src/core/canvas/materializer.js +259 -0
- package/src/core/canvas/materializer.test.js +356 -0
- package/src/core/canvas/selectedWidgets.js +270 -0
- package/src/core/canvas/selectedWidgets.test.js +321 -0
- package/src/core/canvas/server.js +3134 -0
- package/src/core/canvas/server.test.js +379 -0
- package/src/core/canvas/terminal-config.js +330 -0
- package/src/core/canvas/terminal-registry.js +465 -0
- package/src/core/canvas/terminal-server.js +1436 -0
- package/src/core/canvas/writeGuard.js +53 -0
- package/src/core/cli/agent.js +85 -0
- package/src/core/cli/branch.js +386 -0
- package/src/core/cli/canvasAdd.js +241 -0
- package/src/core/cli/canvasBatch.js +98 -0
- package/src/core/cli/canvasBounds.js +160 -0
- package/src/core/cli/canvasRead.js +236 -0
- package/src/core/cli/canvasUpdate.js +179 -0
- package/src/core/cli/code.js +67 -0
- package/src/core/cli/compact.js +62 -0
- package/src/core/cli/create.js +674 -0
- package/src/core/cli/dev-helpers.js +53 -0
- package/src/core/cli/dev-helpers.test.js +53 -0
- package/src/core/cli/dev.js +430 -0
- package/src/core/cli/exit.js +38 -0
- package/src/core/cli/flags.js +174 -0
- package/src/core/cli/flags.test.js +155 -0
- package/src/core/cli/index.js +233 -0
- package/src/core/cli/intro.js +37 -0
- package/src/core/cli/proxy.js +319 -0
- package/src/core/cli/proxy.test.js +63 -0
- package/src/core/cli/schemas.js +223 -0
- package/src/core/cli/server.js +192 -0
- package/src/core/cli/serverUrl.js +61 -0
- package/src/core/cli/sessions.js +459 -0
- package/src/core/cli/setup.js +404 -0
- package/src/core/cli/terminal-commands.js +287 -0
- package/src/core/cli/terminal-messaging.js +231 -0
- package/src/core/cli/terminal-welcome.js +515 -0
- package/src/core/cli/updateVersion.js +124 -0
- package/src/core/comments/api.js +284 -0
- package/src/core/comments/api.test.js +282 -0
- package/src/core/comments/auth.js +151 -0
- package/src/core/comments/auth.test.js +167 -0
- package/src/core/comments/commentCache.js +109 -0
- package/src/core/comments/commentCache.test.js +48 -0
- package/src/core/comments/commentDrafts.js +68 -0
- package/src/core/comments/commentMode.js +63 -0
- package/src/core/comments/commentMode.test.js +90 -0
- package/src/core/comments/config.js +47 -0
- package/src/core/comments/config.test.js +77 -0
- package/src/core/comments/graphql.js +65 -0
- package/src/core/comments/graphql.test.js +95 -0
- package/src/core/comments/index.js +42 -0
- package/src/core/comments/metadata.js +52 -0
- package/src/core/comments/metadata.test.js +110 -0
- package/src/core/comments/queries.js +245 -0
- package/src/core/comments/ui/AuthModal.jsx +114 -0
- package/src/core/comments/ui/CommentOverlay.js +52 -0
- package/src/core/comments/ui/CommentWindow.jsx +329 -0
- package/src/core/comments/ui/CommentsDrawer.jsx +102 -0
- package/src/core/comments/ui/Composer.jsx +64 -0
- package/src/core/comments/ui/authModal.js +66 -0
- package/src/core/comments/ui/authModal.test.js +76 -0
- package/src/core/comments/ui/comment-cursor-dark.svg +1 -0
- package/src/core/comments/ui/comment-cursor.svg +1 -0
- package/src/core/comments/ui/comment-layout.css +142 -0
- package/src/core/comments/ui/commentWindow.js +121 -0
- package/src/core/comments/ui/comments.css +242 -0
- package/src/core/comments/ui/commentsDrawer.js +84 -0
- package/src/core/comments/ui/composer.js +136 -0
- package/src/core/comments/ui/index.js +14 -0
- package/src/core/comments/ui/mount.js +687 -0
- package/src/core/comments/ui/mount.test.js +336 -0
- package/src/core/data/dotPath.js +53 -0
- package/src/core/data/dotPath.test.js +114 -0
- package/src/core/data/loader.js +409 -0
- package/src/core/data/loader.test.js +599 -0
- package/src/core/data/viewfinder.js +363 -0
- package/src/core/data/viewfinder.test.js +456 -0
- package/src/core/devtools/devtools-consumer.js +28 -0
- package/src/core/devtools/devtools.js +144 -0
- package/src/core/devtools/devtools.test.js +75 -0
- package/src/core/devtools/sceneDebug.js +112 -0
- package/src/core/devtools/sceneDebug.test.js +141 -0
- package/src/core/index.js +124 -0
- package/src/core/inspector/fiberWalker.js +239 -0
- package/src/core/inspector/highlighter.js +275 -0
- package/src/core/inspector/mouseMode.js +259 -0
- package/src/core/lib/components/ui/alert/alert-action.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert-description.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert-title.jsx +11 -0
- package/src/core/lib/components/ui/alert/alert.jsx +25 -0
- package/src/core/lib/components/ui/alert/index.js +17 -0
- package/src/core/lib/components/ui/avatar/avatar-badge.jsx +22 -0
- package/src/core/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
- package/src/core/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
- package/src/core/lib/components/ui/avatar/avatar-group.jsx +19 -0
- package/src/core/lib/components/ui/avatar/avatar-image.jsx +15 -0
- package/src/core/lib/components/ui/avatar/avatar.jsx +19 -0
- package/src/core/lib/components/ui/avatar/index.js +22 -0
- package/src/core/lib/components/ui/badge/badge.jsx +31 -0
- package/src/core/lib/components/ui/badge/index.js +2 -0
- package/src/core/lib/components/ui/button/button.jsx +100 -0
- package/src/core/lib/components/ui/button/index.js +12 -0
- package/src/core/lib/components/ui/card/card-action.jsx +11 -0
- package/src/core/lib/components/ui/card/card-content.jsx +11 -0
- package/src/core/lib/components/ui/card/card-description.jsx +11 -0
- package/src/core/lib/components/ui/card/card-footer.jsx +11 -0
- package/src/core/lib/components/ui/card/card-header.jsx +19 -0
- package/src/core/lib/components/ui/card/card-title.jsx +11 -0
- package/src/core/lib/components/ui/card/card.jsx +17 -0
- package/src/core/lib/components/ui/card/index.js +25 -0
- package/src/core/lib/components/ui/checkbox/checkbox.jsx +29 -0
- package/src/core/lib/components/ui/checkbox/index.js +6 -0
- package/src/core/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/collapsible.jsx +7 -0
- package/src/core/lib/components/ui/collapsible/index.js +13 -0
- package/src/core/lib/components/ui/dialog/dialog-close.jsx +7 -0
- package/src/core/lib/components/ui/dialog/dialog-content.jsx +34 -0
- package/src/core/lib/components/ui/dialog/dialog-description.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-footer.jsx +23 -0
- package/src/core/lib/components/ui/dialog/dialog-header.jsx +11 -0
- package/src/core/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-portal.jsx +4 -0
- package/src/core/lib/components/ui/dialog/dialog-title.jsx +15 -0
- package/src/core/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
- package/src/core/lib/components/ui/dialog/dialog.jsx +4 -0
- package/src/core/lib/components/ui/dialog/index.js +34 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
- package/src/core/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
- package/src/core/lib/components/ui/dropdown-menu/index.js +54 -0
- package/src/core/lib/components/ui/input/index.js +7 -0
- package/src/core/lib/components/ui/input/input.jsx +19 -0
- package/src/core/lib/components/ui/label/index.js +7 -0
- package/src/core/lib/components/ui/label/label.jsx +19 -0
- package/src/core/lib/components/ui/panel/index.js +24 -0
- package/src/core/lib/components/ui/panel/panel-body.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-close.jsx +16 -0
- package/src/core/lib/components/ui/panel/panel-content.jsx +29 -0
- package/src/core/lib/components/ui/panel/panel-footer.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-header.jsx +11 -0
- package/src/core/lib/components/ui/panel/panel-title.jsx +12 -0
- package/src/core/lib/components/ui/panel/panel.jsx +4 -0
- package/src/core/lib/components/ui/popover/index.js +28 -0
- package/src/core/lib/components/ui/popover/popover-close.jsx +7 -0
- package/src/core/lib/components/ui/popover/popover-content.jsx +22 -0
- package/src/core/lib/components/ui/popover/popover-description.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-header.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-portal.jsx +4 -0
- package/src/core/lib/components/ui/popover/popover-title.jsx +11 -0
- package/src/core/lib/components/ui/popover/popover-trigger.jsx +8 -0
- package/src/core/lib/components/ui/popover/popover.jsx +4 -0
- package/src/core/lib/components/ui/searchable-list.jsx +160 -0
- package/src/core/lib/components/ui/select/index.js +37 -0
- package/src/core/lib/components/ui/select/select-content.jsx +30 -0
- package/src/core/lib/components/ui/select/select-group-heading.jsx +17 -0
- package/src/core/lib/components/ui/select/select-group.jsx +15 -0
- package/src/core/lib/components/ui/select/select-item.jsx +26 -0
- package/src/core/lib/components/ui/select/select-label.jsx +11 -0
- package/src/core/lib/components/ui/select/select-portal.jsx +4 -0
- package/src/core/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
- package/src/core/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
- package/src/core/lib/components/ui/select/select-separator.jsx +15 -0
- package/src/core/lib/components/ui/select/select-trigger.jsx +25 -0
- package/src/core/lib/components/ui/select/select.jsx +4 -0
- package/src/core/lib/components/ui/separator/index.js +7 -0
- package/src/core/lib/components/ui/separator/separator.jsx +22 -0
- package/src/core/lib/components/ui/sheet/index.js +34 -0
- package/src/core/lib/components/ui/sheet/sheet-close.jsx +7 -0
- package/src/core/lib/components/ui/sheet/sheet-content.jsx +35 -0
- package/src/core/lib/components/ui/sheet/sheet-description.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-footer.jsx +11 -0
- package/src/core/lib/components/ui/sheet/sheet-header.jsx +11 -0
- package/src/core/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-portal.jsx +4 -0
- package/src/core/lib/components/ui/sheet/sheet-title.jsx +15 -0
- package/src/core/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
- package/src/core/lib/components/ui/sheet/sheet.jsx +4 -0
- package/src/core/lib/components/ui/textarea/index.js +7 -0
- package/src/core/lib/components/ui/textarea/textarea.jsx +18 -0
- package/src/core/lib/components/ui/toggle/index.js +8 -0
- package/src/core/lib/components/ui/toggle/toggle.jsx +36 -0
- package/src/core/lib/components/ui/toggle-group/index.js +10 -0
- package/src/core/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
- package/src/core/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
- package/src/core/lib/components/ui/tooltip/index.js +3 -0
- package/src/core/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
- package/src/core/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
- package/src/core/lib/components/ui/tooltip/tooltip.jsx +11 -0
- package/src/core/lib/components/ui/trigger-button/index.js +6 -0
- package/src/core/lib/components/ui/trigger-button/trigger-button.css +38 -0
- package/src/core/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
- package/src/core/lib/utils/index.js +6 -0
- package/src/core/logger/devLogger.js +238 -0
- package/src/core/logger/devLogger.test.js +193 -0
- package/src/core/modes/modes.css +98 -0
- package/src/core/modes/modes.js +492 -0
- package/src/core/modes/modes.test.js +562 -0
- package/src/core/mountStoryboardCore.js +478 -0
- package/src/core/rename-watcher/config.json +23 -0
- package/src/core/rename-watcher/watcher.js +531 -0
- package/src/core/scaffold.js +100 -0
- package/src/core/server/index.js +391 -0
- package/src/core/session/bodyClasses.js +128 -0
- package/src/core/session/bodyClasses.test.js +192 -0
- package/src/core/session/hashSubscribe.js +19 -0
- package/src/core/session/hashSubscribe.test.js +62 -0
- package/src/core/session/hideMode.js +424 -0
- package/src/core/session/hideMode.test.js +268 -0
- package/src/core/session/interceptHideParams.js +35 -0
- package/src/core/session/interceptHideParams.test.js +90 -0
- package/src/core/session/localStorage.js +134 -0
- package/src/core/session/localStorage.test.js +148 -0
- package/src/core/session/session.js +76 -0
- package/src/core/session/session.test.js +91 -0
- package/src/core/stores/canvasConfig.js +134 -0
- package/src/core/stores/canvasConfig.test.js +120 -0
- package/src/core/stores/commandActions.js +284 -0
- package/src/core/stores/commandPaletteConfig.js +31 -0
- package/src/core/stores/configSchema.js +232 -0
- package/src/core/stores/configSchema.test.js +72 -0
- package/src/core/stores/configStore.js +161 -0
- package/src/core/stores/customerModeConfig.js +30 -0
- package/src/core/stores/featureFlags.js +127 -0
- package/src/core/stores/paletteProviders.js +360 -0
- package/src/core/stores/paletteProviders.test.js +186 -0
- package/src/core/stores/plugins.js +40 -0
- package/src/core/stores/plugins.test.js +68 -0
- package/src/core/stores/recentArtifacts.js +68 -0
- package/src/core/stores/recentArtifacts.test.js +71 -0
- package/src/core/stores/sidePanelStore.ts +143 -0
- package/src/core/stores/themeStore.ts +291 -0
- package/src/core/stores/toolRegistry.js +227 -0
- package/src/core/stores/toolStateStore.js +183 -0
- package/src/core/stores/toolStateStore.test.js +220 -0
- package/src/core/stores/toolbarConfigStore.js +165 -0
- package/src/core/stores/uiConfig.js +64 -0
- package/src/core/stores/uiConfig.test.js +63 -0
- package/src/core/styles/tailwind.css +204 -0
- package/src/core/tools/handlers/autosync.js +12 -0
- package/src/core/tools/handlers/canvasAddWidget.js +11 -0
- package/src/core/tools/handlers/canvasAgents.js +20 -0
- package/src/core/tools/handlers/canvasToolbar.js +56 -0
- package/src/core/tools/handlers/commandPalette.js +9 -0
- package/src/core/tools/handlers/comments.js +16 -0
- package/src/core/tools/handlers/create.js +39 -0
- package/src/core/tools/handlers/devtools.js +122 -0
- package/src/core/tools/handlers/devtools.test.js +87 -0
- package/src/core/tools/handlers/featureFlags.js +21 -0
- package/src/core/tools/handlers/flows.js +68 -0
- package/src/core/tools/handlers/hideChrome.js +9 -0
- package/src/core/tools/handlers/hideToolbars.js +25 -0
- package/src/core/tools/handlers/inspector.js +19 -0
- package/src/core/tools/handlers/paletteTheme.js +35 -0
- package/src/core/tools/handlers/theme.js +9 -0
- package/src/core/tools/registry.js +26 -0
- package/src/core/tools/surfaces/canvasToolbar.js +10 -0
- package/src/core/tools/surfaces/commandList.js +10 -0
- package/src/core/tools/surfaces/mainToolbar.js +11 -0
- package/src/core/tools/surfaces/registry.js +19 -0
- package/src/core/ui/ActionMenuButton.jsx +114 -0
- package/src/core/ui/AutosyncMenuButton.css +67 -0
- package/src/core/ui/AutosyncMenuButton.jsx +242 -0
- package/src/core/ui/BranchSelect.jsx +29 -0
- package/src/core/ui/BranchSelect.module.css +30 -0
- package/src/core/ui/CanvasAgentsMenu.jsx +89 -0
- package/src/core/ui/CanvasCreateMenu.jsx +611 -0
- package/src/core/ui/CanvasSnap.css +27 -0
- package/src/core/ui/CanvasSnap.jsx +51 -0
- package/src/core/ui/CanvasUndoRedo.css +36 -0
- package/src/core/ui/CanvasUndoRedo.jsx +62 -0
- package/src/core/ui/CanvasZoomControl.css +53 -0
- package/src/core/ui/CanvasZoomControl.jsx +49 -0
- package/src/core/ui/CanvasZoomToFit.css +18 -0
- package/src/core/ui/CanvasZoomToFit.jsx +26 -0
- package/src/core/ui/CommandMenu.css +8 -0
- package/src/core/ui/CommandMenu.jsx +287 -0
- package/src/core/ui/CommandPalette.jsx +35 -0
- package/src/core/ui/CommandPaletteTrigger.jsx +25 -0
- package/src/core/ui/CommentsMenuButton.jsx +40 -0
- package/src/core/ui/CoreUIBar.css +47 -0
- package/src/core/ui/CoreUIBar.jsx +905 -0
- package/src/core/ui/CreateMenuButton.jsx +117 -0
- package/src/core/ui/HideChromeTrigger.jsx +48 -0
- package/src/core/ui/Icon.jsx +279 -0
- package/src/core/ui/InspectorPanel.css +109 -0
- package/src/core/ui/InspectorPanel.jsx +632 -0
- package/src/core/ui/PwaInstallBanner.css +42 -0
- package/src/core/ui/PwaInstallBanner.jsx +124 -0
- package/src/core/ui/SidePanel.jsx +261 -0
- package/src/core/ui/ThemeMenuButton.jsx +139 -0
- package/src/core/ui/core-ui-colors.css +129 -0
- package/src/core/ui/design-modes.ts +7 -0
- package/src/core/ui/sidepanel.css +301 -0
- package/src/core/ui/viewfinder.ts +7 -0
- package/src/core/ui-entry.js +30 -0
- package/src/core/utils/fuzzySearch.js +117 -0
- package/src/core/utils/fuzzySearch.test.js +119 -0
- package/src/core/utils/mobileViewport.js +57 -0
- package/src/core/utils/mobileViewport.test.js +68 -0
- package/src/core/utils/prodMode.js +38 -0
- package/src/core/utils/smoothCorners.js +20 -0
- package/src/core/vite/docs-handler.js +155 -0
- package/src/core/vite/server-plugin.js +797 -0
- package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
- package/src/core/workshop/features/createCanvas/index.js +14 -0
- package/src/core/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
- package/src/core/workshop/features/createFlow/index.js +19 -0
- package/src/core/workshop/features/createFlow/server.js +663 -0
- package/src/core/workshop/features/createPage/CreatePageForm.jsx +304 -0
- package/src/core/workshop/features/createPage/index.js +11 -0
- package/src/core/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
- package/src/core/workshop/features/createPrototype/index.js +19 -0
- package/src/core/workshop/features/createPrototype/server.js +433 -0
- package/src/core/workshop/features/createStory/CreateStoryForm.jsx +208 -0
- package/src/core/workshop/features/createStory/index.js +14 -0
- package/src/core/workshop/features/registry-server.js +22 -0
- package/src/core/workshop/features/registry.js +28 -0
- package/src/core/workshop/features/templateIndex.js +155 -0
- package/src/core/workshop/ui/WorkshopPanel.jsx +98 -0
- package/src/core/workshop/ui/mount.ts +6 -0
- package/src/core/worktree/port.js +268 -0
- package/src/core/worktree/port.test.js +222 -0
- package/src/core/worktree/serverRegistry.js +120 -0
- package/src/internals/AuthModal/AuthModal.jsx +132 -0
- package/src/internals/AuthModal/AuthModal.module.css +221 -0
- package/src/internals/BranchBar/BranchBar.jsx +87 -0
- package/src/internals/BranchBar/BranchBar.module.css +247 -0
- package/src/internals/BranchBar/useBranches.js +93 -0
- package/src/internals/BranchBar/useBranches.test.js +68 -0
- package/src/internals/CommandPalette/CommandPalette.jsx +1361 -0
- package/src/internals/CommandPalette/CreateDialog.jsx +219 -0
- package/src/internals/CommandPalette/command-palette.css +180 -0
- package/src/internals/FlowError.module.css +30 -0
- package/src/internals/Icon.jsx +279 -0
- package/src/internals/StoryboardContext.js +3 -0
- package/src/internals/Viewfinder.jsx +1479 -0
- package/src/internals/Viewfinder.module.css +1540 -0
- package/src/internals/Workspace.jsx +7 -0
- package/src/internals/__mocks__/virtual-storyboard-data-index.js +4 -0
- package/src/internals/canvas/CanvasControls.jsx +112 -0
- package/src/internals/canvas/CanvasControls.module.css +135 -0
- package/src/internals/canvas/CanvasPage.bridge.test.jsx +387 -0
- package/src/internals/canvas/CanvasPage.dragdrop.test.jsx +350 -0
- package/src/internals/canvas/CanvasPage.jsx +3092 -0
- package/src/internals/canvas/CanvasPage.module.css +187 -0
- package/src/internals/canvas/CanvasPage.multiselect.test.jsx +358 -0
- package/src/internals/canvas/CanvasToolbar.jsx +73 -0
- package/src/internals/canvas/CanvasToolbar.module.css +92 -0
- package/src/internals/canvas/ComponentErrorBoundary.jsx +50 -0
- package/src/internals/canvas/ConnectorLayer.jsx +208 -0
- package/src/internals/canvas/ConnectorLayer.module.css +129 -0
- package/src/internals/canvas/MarqueeOverlay.jsx +20 -0
- package/src/internals/canvas/PageSelector.jsx +587 -0
- package/src/internals/canvas/PageSelector.module.css +261 -0
- package/src/internals/canvas/PageSelector.test.jsx +113 -0
- package/src/internals/canvas/WebGLContextPool.jsx +292 -0
- package/src/internals/canvas/WebGLContextPool.test.jsx +165 -0
- package/src/internals/canvas/canvasApi.js +164 -0
- package/src/internals/canvas/canvasReloadGuard.js +37 -0
- package/src/internals/canvas/canvasReloadGuard.test.js +27 -0
- package/src/internals/canvas/canvasTheme.js +118 -0
- package/src/internals/canvas/componentIsolate.jsx +165 -0
- package/src/internals/canvas/componentSetIsolate.jsx +257 -0
- package/src/internals/canvas/computeCanvasBounds.test.js +121 -0
- package/src/internals/canvas/connectorGeometry.js +132 -0
- package/src/internals/canvas/hotPoolDevLogs.js +25 -0
- package/src/internals/canvas/textSelection.js +10 -0
- package/src/internals/canvas/textSelection.test.js +26 -0
- package/src/internals/canvas/useCanvas.js +126 -0
- package/src/internals/canvas/useCanvas.test.js +26 -0
- package/src/internals/canvas/useMarqueeSelect.js +213 -0
- package/src/internals/canvas/useMarqueeSelect.test.js +78 -0
- package/src/internals/canvas/useUndoRedo.js +86 -0
- package/src/internals/canvas/useUndoRedo.test.js +231 -0
- package/src/internals/canvas/widgets/CodePenEmbed.jsx +293 -0
- package/src/internals/canvas/widgets/CodePenEmbed.module.css +161 -0
- package/src/internals/canvas/widgets/ComponentSetWidget.jsx +2 -0
- package/src/internals/canvas/widgets/ComponentSetWidget.module.css +89 -0
- package/src/internals/canvas/widgets/ComponentWidget.jsx +14 -0
- package/src/internals/canvas/widgets/ComponentWidget.module.css +0 -0
- package/src/internals/canvas/widgets/CropOverlay.jsx +179 -0
- package/src/internals/canvas/widgets/CropOverlay.module.css +154 -0
- package/src/internals/canvas/widgets/ExpandedPane.jsx +474 -0
- package/src/internals/canvas/widgets/ExpandedPane.module.css +179 -0
- package/src/internals/canvas/widgets/ExpandedPane.test.jsx +240 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +111 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.module.css +59 -0
- package/src/internals/canvas/widgets/ExpandedPaneTopBar.test.jsx +45 -0
- package/src/internals/canvas/widgets/FigmaEmbed.jsx +296 -0
- package/src/internals/canvas/widgets/FigmaEmbed.module.css +222 -0
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.jsx +151 -0
- package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +83 -0
- package/src/internals/canvas/widgets/ImageWidget.jsx +287 -0
- package/src/internals/canvas/widgets/ImageWidget.module.css +81 -0
- package/src/internals/canvas/widgets/LinkPreview.jsx +439 -0
- package/src/internals/canvas/widgets/LinkPreview.module.css +585 -0
- package/src/internals/canvas/widgets/LinkPreview.test.jsx +193 -0
- package/src/internals/canvas/widgets/MarkdownBlock.jsx +354 -0
- package/src/internals/canvas/widgets/MarkdownBlock.module.css +377 -0
- package/src/internals/canvas/widgets/MarkdownBlock.test.jsx +92 -0
- package/src/internals/canvas/widgets/PromptWidget.jsx +428 -0
- package/src/internals/canvas/widgets/PromptWidget.module.css +273 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.jsx +463 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.module.css +579 -0
- package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +10 -0
- package/src/internals/canvas/widgets/ResizeHandle.jsx +67 -0
- package/src/internals/canvas/widgets/ResizeHandle.module.css +29 -0
- package/src/internals/canvas/widgets/StickyNote.jsx +92 -0
- package/src/internals/canvas/widgets/StickyNote.module.css +70 -0
- package/src/internals/canvas/widgets/StickyNote.test.jsx +116 -0
- package/src/internals/canvas/widgets/StorySetWidget.jsx +208 -0
- package/src/internals/canvas/widgets/StorySetWidget.module.css +89 -0
- package/src/internals/canvas/widgets/StoryWidget.jsx +334 -0
- package/src/internals/canvas/widgets/StoryWidget.module.css +211 -0
- package/src/internals/canvas/widgets/TerminalReadWidget.jsx +146 -0
- package/src/internals/canvas/widgets/TerminalReadWidget.module.css +94 -0
- package/src/internals/canvas/widgets/TerminalWidget.jsx +704 -0
- package/src/internals/canvas/widgets/TerminalWidget.module.css +444 -0
- package/src/internals/canvas/widgets/TilesWidget.jsx +300 -0
- package/src/internals/canvas/widgets/TilesWidget.module.css +133 -0
- package/src/internals/canvas/widgets/WidgetChrome.jsx +580 -0
- package/src/internals/canvas/widgets/WidgetChrome.module.css +421 -0
- package/src/internals/canvas/widgets/WidgetWrapper.jsx +15 -0
- package/src/internals/canvas/widgets/WidgetWrapper.module.css +25 -0
- package/src/internals/canvas/widgets/codepenUrl.js +75 -0
- package/src/internals/canvas/widgets/codepenUrl.test.js +76 -0
- package/src/internals/canvas/widgets/embedInteraction.test.jsx +173 -0
- package/src/internals/canvas/widgets/embedOverlay.module.css +35 -0
- package/src/internals/canvas/widgets/embedTheme.js +148 -0
- package/src/internals/canvas/widgets/expandUtils.js +559 -0
- package/src/internals/canvas/widgets/expandUtils.test.js +155 -0
- package/src/internals/canvas/widgets/figmaUrl.js +118 -0
- package/src/internals/canvas/widgets/figmaUrl.test.js +139 -0
- package/src/internals/canvas/widgets/githubUrl.js +82 -0
- package/src/internals/canvas/widgets/githubUrl.test.js +74 -0
- package/src/internals/canvas/widgets/iframeDevLogs.js +49 -0
- package/src/internals/canvas/widgets/iframeDevLogs.test.jsx +81 -0
- package/src/internals/canvas/widgets/index.js +42 -0
- package/src/internals/canvas/widgets/pasteRules.js +295 -0
- package/src/internals/canvas/widgets/pasteRules.test.js +474 -0
- package/src/internals/canvas/widgets/snapshotDisplay.test.jsx +211 -0
- package/src/internals/canvas/widgets/tilePool.js +23 -0
- package/src/internals/canvas/widgets/tiles/diagonal-bl.png +0 -0
- package/src/internals/canvas/widgets/tiles/diagonal-br.png +0 -0
- package/src/internals/canvas/widgets/tiles/diagonal-tl.png +0 -0
- package/src/internals/canvas/widgets/tiles/leaf.png +0 -0
- package/src/internals/canvas/widgets/tiles/quarter-tl.png +0 -0
- package/src/internals/canvas/widgets/tiles/quarter-tr.png +0 -0
- package/src/internals/canvas/widgets/tiles/solid-a.png +0 -0
- package/src/internals/canvas/widgets/tiles/solid-b.png +0 -0
- package/src/internals/canvas/widgets/widgetConfig.js +291 -0
- package/src/internals/canvas/widgets/widgetConfig.test.js +68 -0
- package/src/internals/canvas/widgets/widgetIcons.jsx +190 -0
- package/src/internals/canvas/widgets/widgetProps.js +133 -0
- package/src/internals/context/FormContext.js +13 -0
- package/src/internals/context/FormContext.test.js +48 -0
- package/src/internals/context.jsx +481 -0
- package/src/internals/context.test.jsx +296 -0
- package/src/internals/hashPreserver.js +73 -0
- package/src/internals/hashPreserver.test.js +107 -0
- package/src/internals/hooks/useConfig.js +14 -0
- package/src/internals/hooks/useFeatureFlag.js +14 -0
- package/src/internals/hooks/useFlows.js +50 -0
- package/src/internals/hooks/useFlows.test.js +134 -0
- package/src/internals/hooks/useHideMode.js +31 -0
- package/src/internals/hooks/useHideMode.test.js +43 -0
- package/src/internals/hooks/useLocalStorage.js +57 -0
- package/src/internals/hooks/useLocalStorage.test.js +75 -0
- package/src/internals/hooks/useMode.js +43 -0
- package/src/internals/hooks/useObject.js +101 -0
- package/src/internals/hooks/useObject.test.js +74 -0
- package/src/internals/hooks/useOverride.js +84 -0
- package/src/internals/hooks/useOverride.test.js +71 -0
- package/src/internals/hooks/usePrototypeReloadGuard.js +64 -0
- package/src/internals/hooks/useRecord.js +158 -0
- package/src/internals/hooks/useRecord.test.js +221 -0
- package/src/internals/hooks/useScene.js +38 -0
- package/src/internals/hooks/useScene.test.js +66 -0
- package/src/internals/hooks/useSceneData.js +108 -0
- package/src/internals/hooks/useSceneData.test.js +136 -0
- package/src/internals/hooks/useSession.js +4 -0
- package/src/internals/hooks/useSession.test.js +8 -0
- package/src/internals/hooks/useThemeState.js +61 -0
- package/src/internals/hooks/useThemeState.test.js +66 -0
- package/src/internals/hooks/useUndoRedo.js +28 -0
- package/src/internals/hooks/useUndoRedo.test.js +64 -0
- package/src/internals/index.js +58 -0
- package/src/internals/story/ComponentSetPage.jsx +198 -0
- package/src/internals/story/ComponentSetPage.module.css +129 -0
- package/src/internals/story/StoryPage.jsx +147 -0
- package/src/internals/story/StoryPage.module.css +18 -0
- package/src/internals/test-utils.js +45 -0
- package/src/internals/vite/data-plugin.js +1508 -0
- package/src/internals/vite/data-plugin.test.js +1223 -0
- package/src/test-utils.js +44 -0
- package/toolbar.config.json +271 -0
- package/widgets.config.json +1537 -0
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* storyboard terminal-welcome — interactive welcome prompt for new terminal sessions.
|
|
4
|
+
*
|
|
5
|
+
* Runs inside tmux, presents a Clack select prompt, loops back after
|
|
6
|
+
* the chosen program exits.
|
|
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
|
+
*
|
|
13
|
+
* Usage (called automatically by terminal-server for new sessions):
|
|
14
|
+
* storyboard terminal-welcome [--branch <name>] [--canvas <name>]
|
|
15
|
+
* storyboard terminal-welcome --startup "copilot --agent terminal-agent" [--branch <name>] [--canvas <name>]
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import * as p from '@clack/prompts'
|
|
19
|
+
import { execSync, spawn } from 'node:child_process'
|
|
20
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
21
|
+
import { resolve, join } from 'node:path'
|
|
22
|
+
import { parseFlags } from './flags.js'
|
|
23
|
+
import { dim, bold } from './intro.js'
|
|
24
|
+
import { takePendingMessages } from '../canvas/terminal-config.js'
|
|
25
|
+
|
|
26
|
+
const blue = (s) => `\x1b[34m${s}\x1b[0m`
|
|
27
|
+
const yellow = (s) => `\x1b[33m${s}\x1b[0m`
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Drain any pending bytes from stdin to prevent stale mouse escape sequences
|
|
31
|
+
* (or other buffered input) from being consumed by Clack prompts.
|
|
32
|
+
* This is critical after tmux mouse mode was on — mouse events from the
|
|
33
|
+
* browser widget are sent as escape sequences to stdin.
|
|
34
|
+
*/
|
|
35
|
+
function drainStdin() {
|
|
36
|
+
if (!process.stdin.readable) return
|
|
37
|
+
const wasPaused = process.stdin.isPaused?.()
|
|
38
|
+
try {
|
|
39
|
+
process.stdin.setRawMode?.(true)
|
|
40
|
+
process.stdin.resume()
|
|
41
|
+
// Read and discard all buffered data
|
|
42
|
+
while (process.stdin.read() !== null) { /* discard */ }
|
|
43
|
+
} catch { /* best effort */ }
|
|
44
|
+
if (wasPaused) {
|
|
45
|
+
try { process.stdin.pause() } catch { /* empty */ }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Prepend .storyboard/terminals/bin/ to PATH so `start`, `copilot`, etc.
|
|
50
|
+
// are available in child shells. Done once at startup; child shells inherit it.
|
|
51
|
+
const binDir = join(process.cwd(), '.storyboard', 'terminals', 'bin')
|
|
52
|
+
if (existsSync(binDir) && !process.env.PATH?.includes(binDir)) {
|
|
53
|
+
process.env.PATH = `${binDir}:${process.env.PATH || ''}`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Return a copy of process.env with the .storyboard/terminals/bin/ dir
|
|
58
|
+
* stripped from PATH. Used when spawning agent commands so the real binary
|
|
59
|
+
* is found instead of the wrapper scripts that route back through
|
|
60
|
+
* terminal-welcome (which would cause infinite recursion).
|
|
61
|
+
*/
|
|
62
|
+
function agentEnv() {
|
|
63
|
+
const cleanPath = (process.env.PATH || '').split(':')
|
|
64
|
+
.filter(p => !p.endsWith('.storyboard/terminals/bin'))
|
|
65
|
+
.join(':')
|
|
66
|
+
return { ...process.env, PATH: cleanPath }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Read agents config from storyboard.config.json.
|
|
71
|
+
* Returns an array of { id, label, startupCommand, resumeCommand } entries.
|
|
72
|
+
*/
|
|
73
|
+
function loadAgents() {
|
|
74
|
+
try {
|
|
75
|
+
const raw = readFileSync(resolve(process.cwd(), 'storyboard.config.json'), 'utf8')
|
|
76
|
+
const config = JSON.parse(raw)
|
|
77
|
+
const agents = config?.canvas?.agents
|
|
78
|
+
if (!agents || typeof agents !== 'object') return []
|
|
79
|
+
return Object.entries(agents).map(([id, cfg]) => ({
|
|
80
|
+
id,
|
|
81
|
+
label: cfg.label || id,
|
|
82
|
+
startupCommand: cfg.startupCommand || null,
|
|
83
|
+
resumeCommand: cfg.resumeCommand || null,
|
|
84
|
+
readinessSignal: cfg.readinessSignal || null,
|
|
85
|
+
postStartup: cfg.postStartup || null,
|
|
86
|
+
})).filter(a => a.startupCommand)
|
|
87
|
+
} catch { return [] }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const agents = loadAgents()
|
|
91
|
+
|
|
92
|
+
// Enable/disable tmux mouse — must be off during Clack prompts (mouse
|
|
93
|
+
// events crash Clack), on during shell/copilot sessions (for scrolling).
|
|
94
|
+
function setMouse(on) {
|
|
95
|
+
try { execSync(`tmux set-option mouse ${on ? 'on' : 'off'} 2>/dev/null`, { stdio: 'ignore' }) } catch { /* empty */ }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const flagSchema = {
|
|
99
|
+
branch: { type: 'string', description: 'Current branch name' },
|
|
100
|
+
canvas: { type: 'string', description: 'Current canvas name' },
|
|
101
|
+
name: { type: 'string', description: 'Terminal pretty name' },
|
|
102
|
+
startup: { type: 'string', description: 'Auto-launch this command on first iteration' },
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const { flags } = parseFlags(process.argv.slice(3), flagSchema)
|
|
106
|
+
const branch = flags.branch || 'unknown'
|
|
107
|
+
const canvas = flags.canvas || 'unknown'
|
|
108
|
+
const prettyName = flags.name || null
|
|
109
|
+
const canvasShort = canvas === 'unknown' ? canvas : canvas.split('/').pop()
|
|
110
|
+
const startupCmd = flags.startup || null
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Reset terminal state after a child process exits.
|
|
114
|
+
* Children (especially TUI apps) may leave the terminal in raw mode,
|
|
115
|
+
* alternate screen, or with the cursor hidden.
|
|
116
|
+
*/
|
|
117
|
+
function resetTerminal() {
|
|
118
|
+
// Leave alternate screen, show cursor, reset attributes
|
|
119
|
+
process.stdout.write('\x1b[?1049l\x1b[?25h\x1b[0m')
|
|
120
|
+
try { execSync('stty sane 2>/dev/null', { stdio: 'ignore' }) } catch { /* empty */ }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Spawn an interactive shell with the storyboard bin dir on PATH.
|
|
125
|
+
* zsh re-initializes PATH from .zshrc/.zprofile, so we inject an
|
|
126
|
+
* `export PATH=...` via tmux send-keys after the shell initializes.
|
|
127
|
+
*/
|
|
128
|
+
function spawnShell() {
|
|
129
|
+
const shell = process.env.SHELL || '/bin/zsh'
|
|
130
|
+
const child = spawn(shell, [], { stdio: 'inherit' })
|
|
131
|
+
|
|
132
|
+
// Inject PATH after shell init so `start`, `copilot`, etc. are available
|
|
133
|
+
if (existsSync(binDir)) {
|
|
134
|
+
setTimeout(() => {
|
|
135
|
+
try {
|
|
136
|
+
execSync(`tmux send-keys -l ${JSON.stringify(`export PATH="${binDir}:$PATH"`)}`, { stdio: 'ignore' })
|
|
137
|
+
execSync(`tmux send-keys Enter`, { stdio: 'ignore' })
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
try {
|
|
140
|
+
execSync(`tmux send-keys -l "clear"`, { stdio: 'ignore' })
|
|
141
|
+
execSync(`tmux send-keys Enter`, { stdio: 'ignore' })
|
|
142
|
+
} catch { /* empty */ }
|
|
143
|
+
}, 200)
|
|
144
|
+
} catch { /* empty */ }
|
|
145
|
+
}, 500)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return new Promise((resolve) => {
|
|
149
|
+
child.on('close', resolve)
|
|
150
|
+
child.on('error', resolve)
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get the current tmux session name (safe — returns null outside tmux).
|
|
156
|
+
*/
|
|
157
|
+
function getTmuxName() {
|
|
158
|
+
try {
|
|
159
|
+
return execSync('tmux display-message -p "#{session_name}"', { encoding: 'utf8', timeout: 1000 }).trim() || null
|
|
160
|
+
} catch { return null }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Inject [System] identity message into the running agent via tmux send-keys.
|
|
165
|
+
* Mirrors the identity injection in terminal-server.js so agents launched from
|
|
166
|
+
* the welcome menu receive the same initial context.
|
|
167
|
+
*/
|
|
168
|
+
function injectIdentityMessage(tmuxName) {
|
|
169
|
+
const widgetId = process.env.STORYBOARD_WIDGET_ID
|
|
170
|
+
if (!tmuxName || !widgetId) return
|
|
171
|
+
|
|
172
|
+
const canvasId = process.env.STORYBOARD_CANVAS_ID || canvas
|
|
173
|
+
const serverUrl = process.env.STORYBOARD_SERVER_URL || ''
|
|
174
|
+
const displayName = prettyName || widgetId
|
|
175
|
+
const configFile = `.storyboard/terminals/${widgetId}.json`
|
|
176
|
+
|
|
177
|
+
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.`
|
|
178
|
+
try {
|
|
179
|
+
execSync(`tmux send-keys -t "${tmuxName}" -l ${JSON.stringify(msg)}`, { stdio: 'ignore' })
|
|
180
|
+
execSync(`tmux send-keys -t "${tmuxName}" Enter`, { stdio: 'ignore' })
|
|
181
|
+
} catch { /* empty */ }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Deliver pending messages to the running agent via tmux send-keys.
|
|
186
|
+
* Uses takePendingMessages for atomic read+clear.
|
|
187
|
+
*/
|
|
188
|
+
function deliverPendingMessages(tmuxName) {
|
|
189
|
+
const widgetId = process.env.STORYBOARD_WIDGET_ID
|
|
190
|
+
if (!tmuxName || !widgetId) return
|
|
191
|
+
|
|
192
|
+
const messages = takePendingMessages(widgetId)
|
|
193
|
+
messages.forEach((msg, i) => {
|
|
194
|
+
setTimeout(() => {
|
|
195
|
+
try {
|
|
196
|
+
const excerpt = msg.message.length > 200 ? msg.message.slice(0, 200) + '…' : msg.message
|
|
197
|
+
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'` : ''}`
|
|
198
|
+
execSync(`tmux send-keys -t "${tmuxName}" -l ${JSON.stringify(formatted)}`, { stdio: 'ignore' })
|
|
199
|
+
execSync(`tmux send-keys -t "${tmuxName}" Enter`, { stdio: 'ignore' })
|
|
200
|
+
} catch { /* empty */ }
|
|
201
|
+
}, i * 1500)
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Launch an agent by spawning its startupCommand via the user's shell.
|
|
207
|
+
* After the agent reaches readiness, injects identity context and pending
|
|
208
|
+
* messages — same treatment as the terminal-server cold path.
|
|
209
|
+
*
|
|
210
|
+
* @param {Object} agent - Agent config with label, startupCommand, readinessSignal, postStartup
|
|
211
|
+
* @param {Object} [opts]
|
|
212
|
+
* @param {boolean} [opts.isInitialStartup=false] - Skip context injection on the first
|
|
213
|
+
* --startup iteration (terminal-server.js handles it independently).
|
|
214
|
+
*/
|
|
215
|
+
async function launchAgent(agent, { isInitialStartup = false } = {}) {
|
|
216
|
+
// Show metadata after selection
|
|
217
|
+
const meta = [
|
|
218
|
+
prettyName ? `${dim('name:')} ${blue(prettyName)}` : null,
|
|
219
|
+
`${dim('branch:')} ${blue(branch)}`,
|
|
220
|
+
`${dim('canvas:')} ${blue(canvasShort)}`,
|
|
221
|
+
].filter(Boolean).join(' ')
|
|
222
|
+
p.log.info(meta)
|
|
223
|
+
p.outro(dim(`Starting ${agent.label}...`))
|
|
224
|
+
setMouse(true)
|
|
225
|
+
|
|
226
|
+
let exitCode = null
|
|
227
|
+
const startTime = Date.now()
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const shell = process.env.SHELL || '/bin/zsh'
|
|
231
|
+
const child = spawn(shell, ['-lc', agent.startupCommand], {
|
|
232
|
+
stdio: 'inherit',
|
|
233
|
+
env: agentEnv(),
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// Context injection — inject identity, postStartup, and pending messages
|
|
237
|
+
// after the agent reaches readiness. Skip on initial --startup since
|
|
238
|
+
// terminal-server.js handles that path independently.
|
|
239
|
+
let pollInterval = null
|
|
240
|
+
let readinessTimeout = null
|
|
241
|
+
const tmuxName = !isInitialStartup ? getTmuxName() : null
|
|
242
|
+
const widgetId = process.env.STORYBOARD_WIDGET_ID
|
|
243
|
+
|
|
244
|
+
if (tmuxName && widgetId) {
|
|
245
|
+
const readinessSignal = agent.readinessSignal
|
|
246
|
+
const firstWord = agent.startupCommand.trim().split(/\s+/)[0]
|
|
247
|
+
|
|
248
|
+
if (readinessSignal) {
|
|
249
|
+
let contextSent = false
|
|
250
|
+
pollInterval = setInterval(() => {
|
|
251
|
+
if (contextSent) { clearInterval(pollInterval); pollInterval = null; return }
|
|
252
|
+
try {
|
|
253
|
+
const paneContent = execSync(
|
|
254
|
+
`tmux capture-pane -t "${tmuxName}" -p`,
|
|
255
|
+
{ encoding: 'utf8', timeout: 1000 }
|
|
256
|
+
)
|
|
257
|
+
// Check configured readiness signal + copilot prompt fallback
|
|
258
|
+
const isReady = paneContent.includes(readinessSignal) ||
|
|
259
|
+
(firstWord === 'copilot' && paneContent.match(/^[>❯]\s*$/m))
|
|
260
|
+
if (isReady) {
|
|
261
|
+
contextSent = true
|
|
262
|
+
clearInterval(pollInterval)
|
|
263
|
+
pollInterval = null
|
|
264
|
+
setTimeout(() => {
|
|
265
|
+
if (agent.postStartup) {
|
|
266
|
+
try {
|
|
267
|
+
execSync(`tmux send-keys -t "${tmuxName}" -l ${JSON.stringify(agent.postStartup)}`, { stdio: 'ignore' })
|
|
268
|
+
execSync(`tmux send-keys -t "${tmuxName}" Enter`, { stdio: 'ignore' })
|
|
269
|
+
} catch { /* empty */ }
|
|
270
|
+
}
|
|
271
|
+
injectIdentityMessage(tmuxName)
|
|
272
|
+
setTimeout(() => deliverPendingMessages(tmuxName), 2000)
|
|
273
|
+
}, 500)
|
|
274
|
+
}
|
|
275
|
+
} catch { /* empty */ }
|
|
276
|
+
}, 2000)
|
|
277
|
+
// Timeout after 30s — don't wait forever
|
|
278
|
+
readinessTimeout = setTimeout(() => {
|
|
279
|
+
if (!contextSent) {
|
|
280
|
+
contextSent = true
|
|
281
|
+
if (pollInterval) { clearInterval(pollInterval); pollInterval = null }
|
|
282
|
+
}
|
|
283
|
+
}, 30000)
|
|
284
|
+
} else {
|
|
285
|
+
// No readiness signal configured — inject after a delay
|
|
286
|
+
const delayTimer = setTimeout(() => {
|
|
287
|
+
injectIdentityMessage(tmuxName)
|
|
288
|
+
setTimeout(() => deliverPendingMessages(tmuxName), 2000)
|
|
289
|
+
}, 5000)
|
|
290
|
+
// Store reference for cleanup
|
|
291
|
+
pollInterval = { clear: () => clearTimeout(delayTimer) }
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
exitCode = await new Promise((resolve) => {
|
|
296
|
+
child.on('close', (code) => {
|
|
297
|
+
if (pollInterval) {
|
|
298
|
+
if (typeof pollInterval.clear === 'function') pollInterval.clear()
|
|
299
|
+
else clearInterval(pollInterval)
|
|
300
|
+
}
|
|
301
|
+
if (readinessTimeout) clearTimeout(readinessTimeout)
|
|
302
|
+
resolve(code)
|
|
303
|
+
})
|
|
304
|
+
child.on('error', () => {
|
|
305
|
+
if (pollInterval) {
|
|
306
|
+
if (typeof pollInterval.clear === 'function') pollInterval.clear()
|
|
307
|
+
else clearInterval(pollInterval)
|
|
308
|
+
}
|
|
309
|
+
if (readinessTimeout) clearTimeout(readinessTimeout)
|
|
310
|
+
resolve(1)
|
|
311
|
+
})
|
|
312
|
+
})
|
|
313
|
+
} catch {
|
|
314
|
+
p.log.error(`Failed to start ${agent.label}. Is it installed?`)
|
|
315
|
+
await new Promise(r => setTimeout(r, 2000))
|
|
316
|
+
exitCode = 1
|
|
317
|
+
} finally {
|
|
318
|
+
// Always disable mouse and drain stdin before returning to the welcome
|
|
319
|
+
// loop. Without this, tmux mouse escape sequences from the browser widget
|
|
320
|
+
// accumulate in stdin while the agent runs, and Clack's p.select() reads
|
|
321
|
+
// them as keystrokes — auto-selecting menu options in a tight loop.
|
|
322
|
+
setMouse(false)
|
|
323
|
+
await new Promise(r => setTimeout(r, 50))
|
|
324
|
+
drainStdin()
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const durationMs = Date.now() - startTime
|
|
328
|
+
return { exitCode, durationMs }
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async function welcomeLoop() {
|
|
332
|
+
let firstIteration = true
|
|
333
|
+
const MAX_STARTUP_RETRIES = 2
|
|
334
|
+
|
|
335
|
+
while (true) {
|
|
336
|
+
// On first iteration with --startup, auto-launch the command
|
|
337
|
+
if (firstIteration && startupCmd) {
|
|
338
|
+
firstIteration = false
|
|
339
|
+
|
|
340
|
+
if (startupCmd === 'shell') {
|
|
341
|
+
// Plain shell — spawn interactive shell, return to welcome on exit
|
|
342
|
+
setMouse(true)
|
|
343
|
+
try { await spawnShell() } catch { /* empty */ }
|
|
344
|
+
resetTerminal()
|
|
345
|
+
continue
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Try to match against a configured agent for label resolution
|
|
349
|
+
const matchedAgent = agents.find(a =>
|
|
350
|
+
startupCmd.startsWith(a.startupCommand?.split(' ')[0])
|
|
351
|
+
)
|
|
352
|
+
const agent = matchedAgent || { label: startupCmd.split(/\s+/)[0], startupCommand: startupCmd }
|
|
353
|
+
|
|
354
|
+
let succeeded = false
|
|
355
|
+
for (let attempt = 0; attempt < MAX_STARTUP_RETRIES; attempt++) {
|
|
356
|
+
const result = await launchAgent(agent, { isInitialStartup: true })
|
|
357
|
+
resetTerminal()
|
|
358
|
+
|
|
359
|
+
// Normal exit (user quit the agent) — proceed to welcome menu
|
|
360
|
+
if (result.exitCode === 0 || result.exitCode === null) { succeeded = true; break }
|
|
361
|
+
|
|
362
|
+
// Non-zero exit — agent crashed or failed to start
|
|
363
|
+
const isLastAttempt = attempt === MAX_STARTUP_RETRIES - 1
|
|
364
|
+
if (isLastAttempt) {
|
|
365
|
+
p.log.warn(yellow(`${agent.label} failed to start (exit code ${result.exitCode}).`))
|
|
366
|
+
p.log.info(dim('Falling back to the welcome menu. You can retry from there.'))
|
|
367
|
+
await new Promise(r => setTimeout(r, 2000))
|
|
368
|
+
} else {
|
|
369
|
+
p.log.warn(yellow(`${agent.label} exited unexpectedly (exit code ${result.exitCode}). Retrying...`))
|
|
370
|
+
await new Promise(r => setTimeout(r, 3000))
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (succeeded) continue
|
|
375
|
+
// Fall through to the interactive welcome menu
|
|
376
|
+
}
|
|
377
|
+
firstIteration = false
|
|
378
|
+
|
|
379
|
+
resetTerminal()
|
|
380
|
+
setMouse(false)
|
|
381
|
+
drainStdin()
|
|
382
|
+
console.clear()
|
|
383
|
+
p.intro(`${bold('storyboard terminal')}`)
|
|
384
|
+
|
|
385
|
+
// Build the first option based on number of configured agents
|
|
386
|
+
const agentOption = agents.length > 1
|
|
387
|
+
? { value: 'agents', label: '✦ Start a new agent session' }
|
|
388
|
+
: { value: 'copilot', label: `✦ Start a new ${agents[0]?.label || 'Copilot'} session` }
|
|
389
|
+
|
|
390
|
+
drainStdin()
|
|
391
|
+
const action = await p.select({
|
|
392
|
+
message: 'How would you like to start?',
|
|
393
|
+
options: [
|
|
394
|
+
agentOption,
|
|
395
|
+
{ value: 'shell', label: '▸ Start a new terminal session' },
|
|
396
|
+
{ value: 'sessions', label: '⊞ Browse existing sessions' },
|
|
397
|
+
],
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
if (p.isCancel(action)) {
|
|
401
|
+
// Don't exit to shell on cancel — loop back to welcome
|
|
402
|
+
continue
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (action === 'agents') {
|
|
406
|
+
// Multi-agent sub-select
|
|
407
|
+
drainStdin()
|
|
408
|
+
const agentChoice = await p.select({
|
|
409
|
+
message: 'Which agent?',
|
|
410
|
+
options: agents.map(a => ({
|
|
411
|
+
value: a.id,
|
|
412
|
+
label: `✦ Start a new ${a.label} session`,
|
|
413
|
+
})),
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
if (p.isCancel(agentChoice)) continue
|
|
417
|
+
|
|
418
|
+
const agent = agents.find(a => a.id === agentChoice)
|
|
419
|
+
if (agent) {
|
|
420
|
+
await launchAgent(agent)
|
|
421
|
+
}
|
|
422
|
+
continue
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (action === 'copilot') {
|
|
426
|
+
// Single agent — launch directly
|
|
427
|
+
const agent = agents[0] || { label: 'Copilot', startupCommand: 'copilot --agent terminal-agent' }
|
|
428
|
+
await launchAgent(agent)
|
|
429
|
+
continue
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// Show metadata for non-agent actions (shell, sessions)
|
|
433
|
+
const meta = [
|
|
434
|
+
prettyName ? `${dim('name:')} ${blue(prettyName)}` : null,
|
|
435
|
+
`${dim('branch:')} ${blue(branch)}`,
|
|
436
|
+
`${dim('canvas:')} ${blue(canvasShort)}`,
|
|
437
|
+
].filter(Boolean).join(' ')
|
|
438
|
+
p.log.info(meta)
|
|
439
|
+
|
|
440
|
+
if (action === 'shell') {
|
|
441
|
+
p.outro(dim('Opening shell... Enter any command below.'))
|
|
442
|
+
setMouse(true)
|
|
443
|
+
// Spawn an interactive shell; when it exits, loop back to welcome
|
|
444
|
+
try { await spawnShell() } catch { /* empty */ }
|
|
445
|
+
continue
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (action === 'sessions') {
|
|
449
|
+
// Sub-menu: pick which agent's sessions to browse, or terminal sessions
|
|
450
|
+
const resumableAgents = agents.filter(a => a.resumeCommand)
|
|
451
|
+
|
|
452
|
+
const sessionOptions = [
|
|
453
|
+
...resumableAgents.map(a => ({
|
|
454
|
+
value: `agent:${a.id}`,
|
|
455
|
+
label: `✦ ${a.label} sessions`,
|
|
456
|
+
})),
|
|
457
|
+
{ value: 'terminal', label: '⊞ Terminal sessions' },
|
|
458
|
+
]
|
|
459
|
+
|
|
460
|
+
drainStdin()
|
|
461
|
+
const sessionChoice = await p.select({
|
|
462
|
+
message: 'Browse sessions',
|
|
463
|
+
options: sessionOptions,
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
if (p.isCancel(sessionChoice)) continue
|
|
467
|
+
|
|
468
|
+
if (sessionChoice === 'terminal') {
|
|
469
|
+
p.outro(dim('Loading terminal sessions...'))
|
|
470
|
+
try {
|
|
471
|
+
const child = spawn('storyboard', ['terminal'], { stdio: 'inherit' })
|
|
472
|
+
await new Promise((resolve) => {
|
|
473
|
+
child.on('close', resolve)
|
|
474
|
+
child.on('error', resolve)
|
|
475
|
+
})
|
|
476
|
+
} catch {
|
|
477
|
+
p.log.error('Failed to load sessions.')
|
|
478
|
+
await new Promise(r => setTimeout(r, 2000))
|
|
479
|
+
}
|
|
480
|
+
continue
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Agent resume — spawn the resume command interactively
|
|
484
|
+
if (sessionChoice.startsWith('agent:')) {
|
|
485
|
+
const agentId = sessionChoice.replace('agent:', '')
|
|
486
|
+
const agent = resumableAgents.find(a => a.id === agentId)
|
|
487
|
+
if (agent) {
|
|
488
|
+
p.outro(dim(`Loading ${agent.label} sessions...`))
|
|
489
|
+
setMouse(true)
|
|
490
|
+
try {
|
|
491
|
+
const shell = process.env.SHELL || '/bin/zsh'
|
|
492
|
+
const child = spawn(shell, ['-lc', agent.resumeCommand], {
|
|
493
|
+
stdio: 'inherit',
|
|
494
|
+
env: agentEnv(),
|
|
495
|
+
})
|
|
496
|
+
await new Promise((resolve) => {
|
|
497
|
+
child.on('close', resolve)
|
|
498
|
+
child.on('error', resolve)
|
|
499
|
+
})
|
|
500
|
+
} catch {
|
|
501
|
+
p.log.error(`Failed to load ${agent.label} sessions.`)
|
|
502
|
+
await new Promise(r => setTimeout(r, 2000))
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
continue
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
continue
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
welcomeLoop().catch(() => {
|
|
514
|
+
// On any error, just let the shell take over
|
|
515
|
+
})
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* storyboard update[:channel|:version] — Update all @dfosco/storyboard-* packages.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* storyboard update # update to latest stable
|
|
6
|
+
* storyboard update:version 4.0.0 # update to specific version
|
|
7
|
+
* storyboard update:4.0.0-beta.1 # update to specific version (shorthand)
|
|
8
|
+
* storyboard update:beta # update to latest beta
|
|
9
|
+
* storyboard update:alpha # update to latest alpha
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as p from '@clack/prompts'
|
|
13
|
+
import { execSync } from 'child_process'
|
|
14
|
+
import { readFileSync } from 'fs'
|
|
15
|
+
import { resolve } from 'path'
|
|
16
|
+
|
|
17
|
+
const command = process.argv[2]
|
|
18
|
+
const channels = { 'update:beta': 'beta', 'update:alpha': 'alpha' }
|
|
19
|
+
|
|
20
|
+
let channel, targetVersion
|
|
21
|
+
if (channels[command]) {
|
|
22
|
+
channel = channels[command]
|
|
23
|
+
} else if (command === 'update:version') {
|
|
24
|
+
targetVersion = process.argv[3]
|
|
25
|
+
} else if (command && command.startsWith('update:')) {
|
|
26
|
+
// update:<version> shorthand, e.g. update:4.0.0-beta.1
|
|
27
|
+
targetVersion = command.slice('update:'.length)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const pkgPath = resolve(process.cwd(), 'package.json')
|
|
31
|
+
let pkg
|
|
32
|
+
try {
|
|
33
|
+
pkg = JSON.parse(readFileSync(pkgPath, 'utf8'))
|
|
34
|
+
} catch (err) {
|
|
35
|
+
p.log.error(`Failed to read package.json: ${err.message}`)
|
|
36
|
+
process.exit(1)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Collect all @dfosco/storyboard-* packages from deps and devDeps
|
|
40
|
+
const storyboardPkgs = new Set()
|
|
41
|
+
for (const depField of ['dependencies', 'devDependencies']) {
|
|
42
|
+
if (!pkg[depField]) continue
|
|
43
|
+
for (const name of Object.keys(pkg[depField])) {
|
|
44
|
+
if (name.startsWith('@dfosco/storyboard-') || name === '@dfosco/tiny-canvas') {
|
|
45
|
+
storyboardPkgs.add(name)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (storyboardPkgs.size === 0) {
|
|
51
|
+
p.log.warn('No @dfosco/storyboard-* packages found in package.json')
|
|
52
|
+
process.exit(0)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const tag = channel || (targetVersion ? undefined : 'latest')
|
|
56
|
+
const suffix = targetVersion ? `@${targetVersion}` : `@${tag}`
|
|
57
|
+
const packages = [...storyboardPkgs].map(name => `${name}${suffix}`).join(' ')
|
|
58
|
+
|
|
59
|
+
// Resolve actual version from the registry when using a tag (channel or latest)
|
|
60
|
+
let resolvedVersion
|
|
61
|
+
if (tag) {
|
|
62
|
+
try {
|
|
63
|
+
const probe = [...storyboardPkgs][0]
|
|
64
|
+
resolvedVersion = execSync(`npm view ${probe}@${tag} version`, { encoding: 'utf8' }).trim()
|
|
65
|
+
} catch { /* fall back to showing the tag */ }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const displayVersion = resolvedVersion || targetVersion || tag
|
|
69
|
+
const label = resolvedVersion && channel ? `to ${resolvedVersion} (${channel})` : resolvedVersion ? `to ${resolvedVersion}` : channel ? `to ${channel}` : targetVersion ? `to ${targetVersion}` : ''
|
|
70
|
+
p.intro(`storyboard ${command}`)
|
|
71
|
+
p.log.info(`Updating ${storyboardPkgs.size} package(s)${label ? ` ${label}` : ''}…`)
|
|
72
|
+
for (const name of storyboardPkgs) {
|
|
73
|
+
p.log.message(` ${name}@${displayVersion}`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
execSync(`npm install ${packages}`, { stdio: 'inherit', cwd: process.cwd() })
|
|
78
|
+
p.log.success('All storyboard packages updated')
|
|
79
|
+
} catch {
|
|
80
|
+
p.log.error('Failed to update packages — see npm output above')
|
|
81
|
+
process.exit(1)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Sync scaffold files (skills, scripts) from the updated package
|
|
85
|
+
p.log.info('Syncing scaffold files…')
|
|
86
|
+
try {
|
|
87
|
+
execSync('npx storyboard-scaffold', { stdio: 'inherit', cwd: process.cwd() })
|
|
88
|
+
} catch {
|
|
89
|
+
p.log.warn('Scaffold sync failed — run `npx storyboard-scaffold` manually')
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Auto-commit the version update (only if package.json or lock file changed)
|
|
93
|
+
try {
|
|
94
|
+
// Read the installed version from the core package
|
|
95
|
+
const corePkg = JSON.parse(readFileSync(resolve(process.cwd(), 'node_modules', '@dfosco', 'storyboard-core', 'package.json'), 'utf8'))
|
|
96
|
+
const installedVersion = corePkg.version || suffix.slice(1)
|
|
97
|
+
const commitMsg = `[storyboard-update] Update storyboard to ${installedVersion}`
|
|
98
|
+
|
|
99
|
+
// Only stage update-related files (package.json, lock files, scaffold outputs)
|
|
100
|
+
const filesToStage = [
|
|
101
|
+
'package.json',
|
|
102
|
+
'package-lock.json',
|
|
103
|
+
'yarn.lock',
|
|
104
|
+
'pnpm-lock.yaml',
|
|
105
|
+
'.github/skills',
|
|
106
|
+
'scripts',
|
|
107
|
+
]
|
|
108
|
+
for (const f of filesToStage) {
|
|
109
|
+
try { execSync(`git add ${f}`, { cwd: process.cwd(), stdio: 'pipe' }) } catch { /* empty */ }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Only commit if there are staged changes
|
|
113
|
+
try {
|
|
114
|
+
execSync('git diff --cached --quiet', { cwd: process.cwd(), stdio: 'pipe' })
|
|
115
|
+
p.log.message('No changes to commit — already up to date')
|
|
116
|
+
} catch {
|
|
117
|
+
execSync(`git commit -m "${commitMsg}"`, { cwd: process.cwd(), stdio: 'pipe' })
|
|
118
|
+
p.log.success(`Committed: ${commitMsg}`)
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
p.log.warn(`Auto-commit failed: ${err.message}`)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
p.outro('Done')
|