@dfosco/storyboard-core 4.2.0-beta.3 → 4.2.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.
Files changed (419) hide show
  1. package/commandpalette.config.json +109 -24
  2. package/dist/storyboard-ui.css +1 -1
  3. package/dist/storyboard-ui.js +16711 -27239
  4. package/dist/storyboard-ui.js.map +1 -1
  5. package/dist/tailwind.css +1 -1
  6. package/package.json +5 -2
  7. package/scaffold/agents/prompt-agent.agent.md +181 -0
  8. package/scaffold/agents/terminal-agent.agent.md +351 -0
  9. package/scaffold/codex/config.toml +246 -0
  10. package/scaffold/manifest.json +5 -10
  11. package/scaffold/skills/canvas/SKILL.md +5 -4
  12. package/scaffold/skills/ship/SKILL.md +1 -1
  13. package/scaffold/storyboard.config.json +11 -1
  14. package/src/ActionMenuButton.jsx +103 -0
  15. package/src/AutosyncMenuButton.css +67 -0
  16. package/src/AutosyncMenuButton.jsx +242 -0
  17. package/src/BranchSelect.jsx +29 -0
  18. package/src/BranchSelect.module.css +30 -0
  19. package/src/CanvasAgentsMenu.jsx +89 -0
  20. package/src/CanvasCreateMenu.jsx +611 -0
  21. package/src/CanvasSnap.css +27 -0
  22. package/src/CanvasSnap.jsx +51 -0
  23. package/src/CanvasUndoRedo.css +36 -0
  24. package/src/CanvasUndoRedo.jsx +62 -0
  25. package/src/CanvasZoomControl.css +53 -0
  26. package/src/CanvasZoomControl.jsx +49 -0
  27. package/src/CanvasZoomToFit.css +18 -0
  28. package/src/CanvasZoomToFit.jsx +26 -0
  29. package/src/CommandMenu.css +8 -0
  30. package/src/CommandMenu.jsx +287 -0
  31. package/src/CommandPalette.jsx +35 -0
  32. package/src/CommandPaletteTrigger.jsx +25 -0
  33. package/src/CommentsMenuButton.jsx +40 -0
  34. package/src/CoreUIBar.css +47 -0
  35. package/src/CoreUIBar.jsx +858 -0
  36. package/src/CreateMenuButton.jsx +117 -0
  37. package/src/HideChromeTrigger.jsx +40 -0
  38. package/src/InspectorPanel.css +109 -0
  39. package/src/InspectorPanel.jsx +632 -0
  40. package/src/PwaInstallBanner.css +42 -0
  41. package/src/PwaInstallBanner.jsx +124 -0
  42. package/src/SidePanel.jsx +261 -0
  43. package/src/ThemeMenuButton.jsx +139 -0
  44. package/src/autosync/server.js +202 -5
  45. package/src/autosync/server.test.js +111 -0
  46. package/src/canvas/__tests__/agent-integration.test.js +596 -0
  47. package/src/canvas/__tests__/helpers/browser.js +95 -0
  48. package/src/canvas/__tests__/helpers/canvas-api.js +129 -0
  49. package/src/canvas/__tests__/helpers/perf.js +118 -0
  50. package/src/canvas/__tests__/helpers/setup.js +176 -0
  51. package/src/canvas/__tests__/helpers/tmux.js +130 -0
  52. package/src/canvas/__tests__/helpers/transcript.js +132 -0
  53. package/src/canvas/__tests__/terminal-integration.test.js +177 -0
  54. package/src/canvas/hot-pool.js +756 -0
  55. package/src/canvas/materializer.js +31 -0
  56. package/src/canvas/materializer.test.js +56 -0
  57. package/src/canvas/selectedWidgets.js +65 -7
  58. package/src/canvas/server.js +1802 -22
  59. package/src/canvas/server.test.js +239 -0
  60. package/src/canvas/terminal-config.js +330 -0
  61. package/src/canvas/terminal-registry.js +41 -3
  62. package/src/canvas/terminal-server.js +1098 -37
  63. package/src/canvas/writeGuard.js +51 -3
  64. package/src/canvasConfig.js +67 -1
  65. package/src/canvasConfig.test.js +79 -1
  66. package/src/cli/agent.js +85 -0
  67. package/src/cli/branch.js +232 -0
  68. package/src/cli/canvasAdd.js +61 -14
  69. package/src/cli/canvasBatch.js +98 -0
  70. package/src/cli/canvasBounds.js +1 -1
  71. package/src/cli/canvasRead.js +1 -1
  72. package/src/cli/canvasUpdate.js +179 -0
  73. package/src/cli/compact.js +0 -2
  74. package/src/cli/create.js +40 -16
  75. package/src/cli/dev.js +158 -84
  76. package/src/cli/exit.js +23 -24
  77. package/src/cli/index.js +55 -2
  78. package/src/cli/proxy.js +96 -37
  79. package/src/cli/schemas.js +22 -4
  80. package/src/cli/server.js +149 -26
  81. package/src/cli/serverUrl.js +8 -3
  82. package/src/cli/sessions.js +133 -7
  83. package/src/cli/setup.js +138 -12
  84. package/src/cli/terminal-commands.js +20 -9
  85. package/src/cli/terminal-messaging.js +231 -0
  86. package/src/cli/terminal-welcome.js +449 -34
  87. package/src/cli/updateVersion.js +1 -1
  88. package/src/commandActions.js +1 -0
  89. package/src/commandPaletteConfig.js +9 -0
  90. package/src/comments/auth.js +2 -1
  91. package/src/comments/ui/AuthModal.jsx +114 -0
  92. package/src/comments/ui/CommentWindow.jsx +329 -0
  93. package/src/comments/ui/CommentsDrawer.jsx +102 -0
  94. package/src/comments/ui/Composer.jsx +64 -0
  95. package/src/comments/ui/authModal.test.js +1 -1
  96. package/src/comments/ui/commentWindow.js +16 -17
  97. package/src/comments/ui/commentsDrawer.js +25 -26
  98. package/src/comments/ui/composer.js +23 -24
  99. package/src/comments/ui/index.js +2 -3
  100. package/src/configSchema.js +59 -1
  101. package/src/configStore.js +161 -0
  102. package/src/core-ui-colors.css +12 -0
  103. package/src/devtools.js +17 -19
  104. package/src/devtools.test.js +18 -9
  105. package/src/featureFlags.js +12 -5
  106. package/src/fuzzySearch.test.js +10 -0
  107. package/src/index.js +15 -3
  108. package/src/lib/components/ui/alert/alert-action.jsx +11 -0
  109. package/src/lib/components/ui/alert/alert-description.jsx +11 -0
  110. package/src/lib/components/ui/alert/alert-title.jsx +11 -0
  111. package/src/lib/components/ui/alert/alert.jsx +25 -0
  112. package/src/lib/components/ui/alert/index.js +15 -15
  113. package/src/lib/components/ui/avatar/avatar-badge.jsx +22 -0
  114. package/src/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
  115. package/src/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
  116. package/src/lib/components/ui/avatar/avatar-group.jsx +19 -0
  117. package/src/lib/components/ui/avatar/avatar-image.jsx +15 -0
  118. package/src/lib/components/ui/avatar/avatar.jsx +19 -0
  119. package/src/lib/components/ui/avatar/index.js +20 -20
  120. package/src/lib/components/ui/badge/badge.jsx +31 -0
  121. package/src/lib/components/ui/badge/index.js +2 -2
  122. package/src/lib/components/ui/button/button.jsx +100 -0
  123. package/src/lib/components/ui/button/index.js +9 -9
  124. package/src/lib/components/ui/card/card-action.jsx +11 -0
  125. package/src/lib/components/ui/card/card-content.jsx +11 -0
  126. package/src/lib/components/ui/card/card-description.jsx +11 -0
  127. package/src/lib/components/ui/card/card-footer.jsx +11 -0
  128. package/src/lib/components/ui/card/card-header.jsx +19 -0
  129. package/src/lib/components/ui/card/card-title.jsx +11 -0
  130. package/src/lib/components/ui/card/card.jsx +17 -0
  131. package/src/lib/components/ui/card/index.js +23 -23
  132. package/src/lib/components/ui/checkbox/checkbox.jsx +29 -0
  133. package/src/lib/components/ui/checkbox/index.js +5 -5
  134. package/src/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
  135. package/src/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
  136. package/src/lib/components/ui/collapsible/collapsible.jsx +7 -0
  137. package/src/lib/components/ui/collapsible/index.js +11 -11
  138. package/src/lib/components/ui/dialog/dialog-close.jsx +7 -0
  139. package/src/lib/components/ui/dialog/dialog-content.jsx +34 -0
  140. package/src/lib/components/ui/dialog/dialog-description.jsx +15 -0
  141. package/src/lib/components/ui/dialog/dialog-footer.jsx +23 -0
  142. package/src/lib/components/ui/dialog/dialog-header.jsx +11 -0
  143. package/src/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
  144. package/src/lib/components/ui/dialog/dialog-portal.jsx +4 -0
  145. package/src/lib/components/ui/dialog/dialog-title.jsx +15 -0
  146. package/src/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
  147. package/src/lib/components/ui/dialog/dialog.jsx +4 -0
  148. package/src/lib/components/ui/dialog/index.js +32 -32
  149. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
  150. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
  151. package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
  152. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
  153. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
  154. package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
  155. package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
  156. package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
  157. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
  158. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
  159. package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
  160. package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
  161. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
  162. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
  163. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
  164. package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
  165. package/src/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
  166. package/src/lib/components/ui/dropdown-menu/index.js +52 -52
  167. package/src/lib/components/ui/input/index.js +5 -5
  168. package/src/lib/components/ui/input/input.jsx +19 -0
  169. package/src/lib/components/ui/label/index.js +5 -5
  170. package/src/lib/components/ui/label/label.jsx +19 -0
  171. package/src/lib/components/ui/panel/index.js +21 -21
  172. package/src/lib/components/ui/panel/panel-body.jsx +11 -0
  173. package/src/lib/components/ui/panel/panel-close.jsx +16 -0
  174. package/src/lib/components/ui/panel/panel-content.jsx +29 -0
  175. package/src/lib/components/ui/panel/panel-footer.jsx +11 -0
  176. package/src/lib/components/ui/panel/panel-header.jsx +11 -0
  177. package/src/lib/components/ui/panel/panel-title.jsx +12 -0
  178. package/src/lib/components/ui/panel/panel.jsx +4 -0
  179. package/src/lib/components/ui/popover/index.js +26 -26
  180. package/src/lib/components/ui/popover/popover-close.jsx +7 -0
  181. package/src/lib/components/ui/popover/popover-content.jsx +22 -0
  182. package/src/lib/components/ui/popover/popover-description.jsx +11 -0
  183. package/src/lib/components/ui/popover/popover-header.jsx +11 -0
  184. package/src/lib/components/ui/popover/popover-portal.jsx +4 -0
  185. package/src/lib/components/ui/popover/popover-title.jsx +11 -0
  186. package/src/lib/components/ui/popover/popover-trigger.jsx +8 -0
  187. package/src/lib/components/ui/popover/popover.jsx +4 -0
  188. package/src/lib/components/ui/searchable-list.jsx +160 -0
  189. package/src/lib/components/ui/select/index.js +35 -35
  190. package/src/lib/components/ui/select/select-content.jsx +30 -0
  191. package/src/lib/components/ui/select/select-group-heading.jsx +17 -0
  192. package/src/lib/components/ui/select/select-group.jsx +15 -0
  193. package/src/lib/components/ui/select/select-item.jsx +26 -0
  194. package/src/lib/components/ui/select/select-label.jsx +11 -0
  195. package/src/lib/components/ui/select/select-portal.jsx +4 -0
  196. package/src/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
  197. package/src/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
  198. package/src/lib/components/ui/select/select-separator.jsx +15 -0
  199. package/src/lib/components/ui/select/select-trigger.jsx +25 -0
  200. package/src/lib/components/ui/select/select.jsx +4 -0
  201. package/src/lib/components/ui/separator/index.js +5 -5
  202. package/src/lib/components/ui/separator/separator.jsx +22 -0
  203. package/src/lib/components/ui/sheet/index.js +32 -32
  204. package/src/lib/components/ui/sheet/sheet-close.jsx +7 -0
  205. package/src/lib/components/ui/sheet/sheet-content.jsx +35 -0
  206. package/src/lib/components/ui/sheet/sheet-description.jsx +15 -0
  207. package/src/lib/components/ui/sheet/sheet-footer.jsx +11 -0
  208. package/src/lib/components/ui/sheet/sheet-header.jsx +11 -0
  209. package/src/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
  210. package/src/lib/components/ui/sheet/sheet-portal.jsx +4 -0
  211. package/src/lib/components/ui/sheet/sheet-title.jsx +15 -0
  212. package/src/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
  213. package/src/lib/components/ui/sheet/sheet.jsx +4 -0
  214. package/src/lib/components/ui/textarea/index.js +5 -5
  215. package/src/lib/components/ui/textarea/textarea.jsx +18 -0
  216. package/src/lib/components/ui/toggle/index.js +6 -9
  217. package/src/lib/components/ui/toggle/toggle.jsx +36 -0
  218. package/src/lib/components/ui/toggle-group/index.js +8 -8
  219. package/src/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
  220. package/src/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
  221. package/src/lib/components/ui/tooltip/index.js +3 -3
  222. package/src/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
  223. package/src/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
  224. package/src/lib/components/ui/tooltip/tooltip.jsx +11 -0
  225. package/src/lib/components/ui/trigger-button/index.js +3 -3
  226. package/src/lib/components/ui/trigger-button/trigger-button.css +38 -0
  227. package/src/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
  228. package/src/logger/devLogger.js +238 -0
  229. package/src/logger/devLogger.test.js +193 -0
  230. package/src/modes.test.js +4 -4
  231. package/src/mountStoryboardCore.js +133 -35
  232. package/src/paletteProviders.js +3 -0
  233. package/src/paletteProviders.test.js +2 -2
  234. package/src/server/index.js +104 -40
  235. package/src/sidepanel.css +214 -0
  236. package/src/smoothCorners.js +1 -1
  237. package/src/styles/tailwind.css +1 -1
  238. package/src/svelte-plugin-ui/__tests__/ModeSwitch.test.ts +8 -8
  239. package/src/svelte-plugin-ui/__tests__/ToolbarShell.test.ts +11 -10
  240. package/src/svelte-plugin-ui/components/Icon.css +11 -0
  241. package/src/svelte-plugin-ui/components/Icon.jsx +281 -0
  242. package/src/svelte-plugin-ui/components/ModeSwitch.css +90 -0
  243. package/src/svelte-plugin-ui/components/ModeSwitch.jsx +47 -0
  244. package/src/svelte-plugin-ui/components/ToolbarShell.css +80 -0
  245. package/src/svelte-plugin-ui/components/ToolbarShell.jsx +84 -0
  246. package/src/svelte-plugin-ui/components/Viewfinder.css +412 -0
  247. package/src/svelte-plugin-ui/components/Viewfinder.jsx +513 -0
  248. package/src/svelte-plugin-ui/mount.ts +12 -16
  249. package/src/toolRegistry.js +4 -4
  250. package/src/toolbarConfigStore.js +30 -0
  251. package/src/tools/handlers/autosync.js +1 -1
  252. package/src/tools/handlers/canvasAddWidget.js +1 -1
  253. package/src/tools/handlers/canvasAgents.js +20 -0
  254. package/src/tools/handlers/canvasToolbar.js +8 -8
  255. package/src/tools/handlers/commandPalette.js +9 -0
  256. package/src/tools/handlers/comments.js +2 -2
  257. package/src/tools/handlers/create.js +1 -1
  258. package/src/tools/handlers/devtools.js +19 -3
  259. package/src/tools/handlers/devtools.test.js +38 -0
  260. package/src/tools/handlers/featureFlags.js +1 -1
  261. package/src/tools/handlers/flows.js +3 -3
  262. package/src/tools/handlers/hideChrome.js +9 -0
  263. package/src/tools/handlers/paletteTheme.js +35 -0
  264. package/src/tools/handlers/theme.js +1 -1
  265. package/src/tools/registry.js +4 -1
  266. package/src/tools/surfaces/commandList.js +3 -3
  267. package/src/tools/surfaces/mainToolbar.js +3 -3
  268. package/src/tools/surfaces/registry.js +4 -4
  269. package/src/ui/design-modes.ts +2 -2
  270. package/src/ui/viewfinder.ts +1 -1
  271. package/src/vite/server-plugin.js +243 -61
  272. package/src/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
  273. package/src/workshop/features/createCanvas/index.js +1 -1
  274. package/src/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
  275. package/src/workshop/features/createFlow/index.js +1 -1
  276. package/src/workshop/features/createPage/CreatePageForm.jsx +304 -0
  277. package/src/workshop/features/createPage/index.js +1 -1
  278. package/src/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
  279. package/src/workshop/features/createPrototype/index.js +1 -1
  280. package/src/workshop/features/createPrototype/server.js +98 -0
  281. package/src/workshop/features/createStory/CreateStoryForm.jsx +208 -0
  282. package/src/workshop/features/createStory/index.js +1 -1
  283. package/src/workshop/ui/WorkshopPanel.jsx +98 -0
  284. package/src/workshop/ui/mount.ts +1 -1
  285. package/src/worktree/port.js +48 -0
  286. package/src/worktree/serverRegistry.js +120 -0
  287. package/toolbar.config.json +93 -42
  288. package/widgets.config.json +580 -12
  289. package/scaffold/commandpalette.config.json +0 -4
  290. package/scaffold/toolbar.config.json +0 -4
  291. package/src/ActionMenuButton.svelte +0 -119
  292. package/src/AutosyncMenuButton.svelte +0 -397
  293. package/src/CanvasCreateMenu.svelte +0 -295
  294. package/src/CanvasSnap.svelte +0 -87
  295. package/src/CanvasUndoRedo.svelte +0 -108
  296. package/src/CanvasZoomControl.svelte +0 -111
  297. package/src/CanvasZoomToFit.svelte +0 -52
  298. package/src/CommandMenu.svelte +0 -249
  299. package/src/CommandPalette.svelte +0 -33
  300. package/src/CommentsMenuButton.svelte +0 -53
  301. package/src/CoreUIBar.svelte +0 -847
  302. package/src/CreateMenuButton.svelte +0 -133
  303. package/src/DocPanel.svelte +0 -299
  304. package/src/InspectorPanel.svelte +0 -745
  305. package/src/PwaInstallBanner.svelte +0 -124
  306. package/src/SidePanel.svelte +0 -480
  307. package/src/ThemeMenuButton.svelte +0 -132
  308. package/src/comments/ui/AuthModal.svelte +0 -108
  309. package/src/comments/ui/CommentWindow.svelte +0 -333
  310. package/src/comments/ui/CommentsDrawer.svelte +0 -96
  311. package/src/comments/ui/Composer.svelte +0 -65
  312. package/src/lib/components/ui/alert/alert-action.svelte +0 -19
  313. package/src/lib/components/ui/alert/alert-description.svelte +0 -22
  314. package/src/lib/components/ui/alert/alert-title.svelte +0 -22
  315. package/src/lib/components/ui/alert/alert.svelte +0 -38
  316. package/src/lib/components/ui/avatar/avatar-badge.svelte +0 -25
  317. package/src/lib/components/ui/avatar/avatar-fallback.svelte +0 -20
  318. package/src/lib/components/ui/avatar/avatar-group-count.svelte +0 -22
  319. package/src/lib/components/ui/avatar/avatar-group.svelte +0 -22
  320. package/src/lib/components/ui/avatar/avatar-image.svelte +0 -17
  321. package/src/lib/components/ui/avatar/avatar.svelte +0 -24
  322. package/src/lib/components/ui/badge/badge.svelte +0 -44
  323. package/src/lib/components/ui/button/button.svelte +0 -108
  324. package/src/lib/components/ui/card/card-action.svelte +0 -21
  325. package/src/lib/components/ui/card/card-content.svelte +0 -19
  326. package/src/lib/components/ui/card/card-description.svelte +0 -19
  327. package/src/lib/components/ui/card/card-footer.svelte +0 -18
  328. package/src/lib/components/ui/card/card-header.svelte +0 -21
  329. package/src/lib/components/ui/card/card-title.svelte +0 -14
  330. package/src/lib/components/ui/card/card.svelte +0 -21
  331. package/src/lib/components/ui/checkbox/checkbox.svelte +0 -39
  332. package/src/lib/components/ui/collapsible/collapsible-content.svelte +0 -7
  333. package/src/lib/components/ui/collapsible/collapsible-trigger.svelte +0 -7
  334. package/src/lib/components/ui/collapsible/collapsible.svelte +0 -11
  335. package/src/lib/components/ui/dialog/dialog-close.svelte +0 -11
  336. package/src/lib/components/ui/dialog/dialog-content.svelte +0 -42
  337. package/src/lib/components/ui/dialog/dialog-description.svelte +0 -17
  338. package/src/lib/components/ui/dialog/dialog-footer.svelte +0 -29
  339. package/src/lib/components/ui/dialog/dialog-header.svelte +0 -19
  340. package/src/lib/components/ui/dialog/dialog-overlay.svelte +0 -17
  341. package/src/lib/components/ui/dialog/dialog-portal.svelte +0 -7
  342. package/src/lib/components/ui/dialog/dialog-title.svelte +0 -17
  343. package/src/lib/components/ui/dialog/dialog-trigger.svelte +0 -11
  344. package/src/lib/components/ui/dialog/dialog.svelte +0 -7
  345. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte +0 -16
  346. package/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +0 -40
  347. package/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte +0 -27
  348. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte +0 -18
  349. package/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte +0 -7
  350. package/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte +0 -24
  351. package/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte +0 -20
  352. package/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte +0 -7
  353. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte +0 -16
  354. package/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte +0 -34
  355. package/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte +0 -17
  356. package/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte +0 -19
  357. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte +0 -17
  358. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte +0 -27
  359. package/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte +0 -7
  360. package/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte +0 -7
  361. package/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte +0 -7
  362. package/src/lib/components/ui/input/input.svelte +0 -40
  363. package/src/lib/components/ui/label/label.svelte +0 -20
  364. package/src/lib/components/ui/panel/panel-body.svelte +0 -13
  365. package/src/lib/components/ui/panel/panel-close.svelte +0 -16
  366. package/src/lib/components/ui/panel/panel-content.svelte +0 -33
  367. package/src/lib/components/ui/panel/panel-footer.svelte +0 -13
  368. package/src/lib/components/ui/panel/panel-header.svelte +0 -16
  369. package/src/lib/components/ui/panel/panel-title.svelte +0 -14
  370. package/src/lib/components/ui/panel/panel.svelte +0 -15
  371. package/src/lib/components/ui/popover/popover-close.svelte +0 -7
  372. package/src/lib/components/ui/popover/popover-content.svelte +0 -27
  373. package/src/lib/components/ui/popover/popover-description.svelte +0 -19
  374. package/src/lib/components/ui/popover/popover-header.svelte +0 -19
  375. package/src/lib/components/ui/popover/popover-portal.svelte +0 -7
  376. package/src/lib/components/ui/popover/popover-title.svelte +0 -19
  377. package/src/lib/components/ui/popover/popover-trigger.svelte +0 -17
  378. package/src/lib/components/ui/popover/popover.svelte +0 -7
  379. package/src/lib/components/ui/select/select-content.svelte +0 -40
  380. package/src/lib/components/ui/select/select-group-heading.svelte +0 -19
  381. package/src/lib/components/ui/select/select-group.svelte +0 -17
  382. package/src/lib/components/ui/select/select-item.svelte +0 -38
  383. package/src/lib/components/ui/select/select-label.svelte +0 -18
  384. package/src/lib/components/ui/select/select-portal.svelte +0 -7
  385. package/src/lib/components/ui/select/select-scroll-down-button.svelte +0 -20
  386. package/src/lib/components/ui/select/select-scroll-up-button.svelte +0 -20
  387. package/src/lib/components/ui/select/select-separator.svelte +0 -17
  388. package/src/lib/components/ui/select/select-trigger.svelte +0 -27
  389. package/src/lib/components/ui/select/select.svelte +0 -11
  390. package/src/lib/components/ui/separator/separator.svelte +0 -23
  391. package/src/lib/components/ui/sheet/sheet-close.svelte +0 -7
  392. package/src/lib/components/ui/sheet/sheet-content.svelte +0 -43
  393. package/src/lib/components/ui/sheet/sheet-description.svelte +0 -17
  394. package/src/lib/components/ui/sheet/sheet-footer.svelte +0 -18
  395. package/src/lib/components/ui/sheet/sheet-header.svelte +0 -19
  396. package/src/lib/components/ui/sheet/sheet-overlay.svelte +0 -17
  397. package/src/lib/components/ui/sheet/sheet-portal.svelte +0 -7
  398. package/src/lib/components/ui/sheet/sheet-title.svelte +0 -17
  399. package/src/lib/components/ui/sheet/sheet-trigger.svelte +0 -7
  400. package/src/lib/components/ui/sheet/sheet.svelte +0 -7
  401. package/src/lib/components/ui/textarea/textarea.svelte +0 -21
  402. package/src/lib/components/ui/toggle/toggle.svelte +0 -45
  403. package/src/lib/components/ui/toggle-group/toggle-group-item.svelte +0 -35
  404. package/src/lib/components/ui/toggle-group/toggle-group.svelte +0 -63
  405. package/src/lib/components/ui/tooltip/tooltip-content.svelte +0 -24
  406. package/src/lib/components/ui/tooltip/tooltip-trigger.svelte +0 -27
  407. package/src/lib/components/ui/tooltip/tooltip.svelte +0 -9
  408. package/src/lib/components/ui/trigger-button/trigger-button.svelte +0 -106
  409. package/src/svelte-plugin-ui/components/Icon.svelte +0 -181
  410. package/src/svelte-plugin-ui/components/ModeSwitch.svelte +0 -121
  411. package/src/svelte-plugin-ui/components/ToolbarShell.svelte +0 -150
  412. package/src/svelte-plugin-ui/components/Viewfinder.svelte +0 -1001
  413. package/src/tools/handlers/docs.js +0 -11
  414. package/src/workshop/features/createCanvas/CreateCanvasForm.svelte +0 -139
  415. package/src/workshop/features/createFlow/CreateFlowForm.svelte +0 -314
  416. package/src/workshop/features/createPage/CreatePageForm.svelte +0 -249
  417. package/src/workshop/features/createPrototype/CreatePrototypeForm.svelte +0 -287
  418. package/src/workshop/features/createStory/CreateStoryForm.svelte +0 -161
  419. package/src/workshop/ui/WorkshopPanel.svelte +0 -97
@@ -5,21 +5,101 @@
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
- import { dim, cyan, bold } from './intro.js'
23
+ import { dim, bold } from './intro.js'
24
+ import { takePendingMessages } from '../canvas/terminal-config.js'
16
25
 
17
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
+ }
18
97
 
19
98
  const flagSchema = {
20
99
  branch: { type: 'string', description: 'Current branch name' },
21
100
  canvas: { type: 'string', description: 'Current canvas name' },
22
101
  name: { type: 'string', description: 'Terminal pretty name' },
102
+ startup: { type: 'string', description: 'Auto-launch this command on first iteration' },
23
103
  }
24
104
 
25
105
  const { flags } = parseFlags(process.argv.slice(3), flagSchema)
@@ -27,27 +107,329 @@ const branch = flags.branch || 'unknown'
27
107
  const canvas = flags.canvas || 'unknown'
28
108
  const prettyName = flags.name || null
29
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
+ }
30
330
 
31
331
  async function welcomeLoop() {
332
+ let firstIteration = true
333
+ const MAX_STARTUP_RETRIES = 2
334
+
32
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()
33
382
  console.clear()
34
383
  p.intro(`${bold('storyboard terminal')}`)
35
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()
36
391
  const action = await p.select({
37
392
  message: 'How would you like to start?',
38
393
  options: [
39
- { value: 'copilot', label: '✦ Start a new Copilot session' },
394
+ agentOption,
40
395
  { value: 'shell', label: '▸ Start a new terminal session' },
41
396
  { value: 'sessions', label: '⊞ Browse existing sessions' },
42
397
  ],
43
398
  })
44
399
 
45
400
  if (p.isCancel(action)) {
46
- p.outro(dim('Opening shell...'))
47
- break
401
+ // Don't exit to shell on cancel — loop back to welcome
402
+ continue
48
403
  }
49
404
 
50
- // Show metadata after selection
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)
51
433
  const meta = [
52
434
  prettyName ? `${dim('name:')} ${blue(prettyName)}` : null,
53
435
  `${dim('branch:')} ${blue(branch)}`,
@@ -56,40 +438,73 @@ async function welcomeLoop() {
56
438
  p.log.info(meta)
57
439
 
58
440
  if (action === 'shell') {
59
- p.outro(dim('Opening shell...'))
60
- break
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
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 */ }
77
445
  continue
78
446
  }
79
447
 
80
448
  if (action === 'sessions') {
81
- p.outro(dim('Loading sessions...'))
82
- try {
83
- const child = spawn('storyboard', ['terminal'], { stdio: 'inherit' })
84
- await new Promise((resolve) => {
85
- child.on('close', resolve)
86
- child.on('error', resolve)
87
- })
88
- } catch {
89
- p.log.error('Failed to load sessions.')
90
- await new Promise(r => setTimeout(r, 2000))
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
91
481
  }
92
- // Loop back to welcome prompt
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
+
93
508
  continue
94
509
  }
95
510
  }
@@ -106,7 +106,7 @@ try {
106
106
  'scripts',
107
107
  ]
108
108
  for (const f of filesToStage) {
109
- try { execSync(`git add ${f}`, { cwd: process.cwd(), stdio: 'pipe' }) } catch {}
109
+ try { execSync(`git add ${f}`, { cwd: process.cwd(), stdio: 'pipe' }) } catch { /* empty */ }
110
110
  }
111
111
 
112
112
  // Only commit if there are staged changes
@@ -194,6 +194,7 @@ export function getActionsForMode(mode) {
194
194
  url: a.url || null,
195
195
  toolKey: a.toolKey || null,
196
196
  localOnly: a.localOnly || false,
197
+ hideFromCommandPaletteSearch: a.hideFromCommandPaletteSearch || false,
197
198
  handler,
198
199
  active,
199
200
  }
@@ -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
  }
@@ -73,7 +73,8 @@ export async function validateToken(token) {
73
73
  }
74
74
 
75
75
  const user = await res.json()
76
- const userInfo = { login: user.login, avatarUrl: user.avatar_url }
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)