@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
package/src/cli/setup.js CHANGED
@@ -5,11 +5,11 @@
5
5
  */
6
6
 
7
7
  import * as p from '@clack/prompts'
8
- import { existsSync, writeFileSync, mkdirSync } from 'fs'
8
+ import { existsSync, writeFileSync, readFileSync, mkdirSync, readdirSync, symlinkSync } from 'fs'
9
9
  import path from 'path'
10
10
  import { execSync } from 'child_process'
11
11
  import { generateCaddyfile, isCaddyInstalled, isCaddyRunning, startCaddy, reloadCaddy } from './proxy.js'
12
- import { gettingStartedLines, dim, magenta, bold, green, yellow } from './intro.js'
12
+ import { gettingStartedLines, dim, magenta, bold, yellow } from './intro.js'
13
13
 
14
14
  /**
15
15
  * Run a potentially slow task with a spinner that only appears after 500ms.
@@ -188,7 +188,7 @@ if (isInstalled('code')) {
188
188
 
189
189
  // 7. Asset directories
190
190
  {
191
- const dirs = ['assets/canvas/images', '.storyboard']
191
+ const dirs = ['assets/canvas/images', 'assets/.storyboard-public/terminal-snapshots', '.storyboard', '.storyboard/terminals', '.storyboard/terminal-buffers', '.storyboard/logs']
192
192
  for (const dir of dirs) {
193
193
  if (!existsSync(dir)) {
194
194
  try { mkdirSync(dir, { recursive: true }) } catch { /* ignore */ }
@@ -211,6 +211,81 @@ if (isInstalled('code')) {
211
211
  p.log.success('Canvas asset directories ready')
212
212
  }
213
213
 
214
+ // 7a. Scaffold .gitignore entries for private canvas images
215
+ {
216
+ const gitignorePath = '.gitignore'
217
+ const privatePatterns = [
218
+ 'src/canvas/images/~*',
219
+ 'assets/canvas/images/~*',
220
+ 'assets/canvas/snapshots/~*',
221
+ 'assets/.storyboard-public/terminal-snapshots/~*',
222
+ ]
223
+ if (existsSync(gitignorePath)) {
224
+ try {
225
+ let content = readFileSync(gitignorePath, 'utf-8')
226
+ const missing = privatePatterns.filter(p => !content.includes(p))
227
+ if (missing.length > 0) {
228
+ const block = '\n# Private canvas images (tilde prefix = not committed)\n' + missing.join('\n') + '\n'
229
+ content = content.trimEnd() + '\n' + block
230
+ writeFileSync(gitignorePath, content, 'utf-8')
231
+ p.log.success('Added private image patterns to .gitignore')
232
+ }
233
+ } catch { /* ignore */ }
234
+ }
235
+ }
236
+
237
+ // 7b. Copilot agents
238
+ {
239
+ const agentsDir = '.agents'
240
+ if (!existsSync(agentsDir)) {
241
+ try { mkdirSync(agentsDir, { recursive: true }) } catch { /* ignore */ }
242
+ }
243
+
244
+ const scaffoldAgents = path.resolve(import.meta.dirname, '..', '..', 'scaffold', 'agents')
245
+ if (existsSync(scaffoldAgents)) {
246
+ try {
247
+ const agentFiles = execSync(`ls "${scaffoldAgents}"`, { encoding: 'utf8' }).trim().split('\n').filter(Boolean)
248
+ for (const file of agentFiles) {
249
+ const dest = path.join(agentsDir, file)
250
+ if (!existsSync(dest)) {
251
+ run(`cp "${path.join(scaffoldAgents, file)}" "${dest}"`)
252
+ }
253
+ }
254
+ if (agentFiles.length > 0) {
255
+ p.log.success('Copilot agents scaffolded (.agents/)')
256
+ }
257
+ } catch { /* ignore */ }
258
+ }
259
+
260
+ // Create symlinks in each CLI's expected agent directory.
261
+ // Source of truth: .agents/*.agent.md
262
+ // Copilot CLI reads .github/agents/*.md
263
+ // Claude Code reads .claude/agents/*.md
264
+ // Codex CLI uses .codex/config.toml (no agent files needed)
265
+ try {
266
+ const agentFiles = readdirSync(agentsDir).filter(f => f.endsWith('.agent.md'))
267
+ const targets = [
268
+ { dir: path.join('.github', 'agents'), label: 'Copilot CLI' },
269
+ { dir: path.join('.claude', 'agents'), label: 'Claude Code' },
270
+ ]
271
+ for (const { dir, label } of targets) {
272
+ try { mkdirSync(dir, { recursive: true }) } catch { /* ignore */ }
273
+ let linked = 0
274
+ for (const file of agentFiles) {
275
+ const linkName = file.replace('.agent.md', '.md')
276
+ const linkPath = path.join(dir, linkName)
277
+ const target = path.relative(dir, path.join(agentsDir, file))
278
+ if (!existsSync(linkPath)) {
279
+ try { symlinkSync(target, linkPath); linked++ } catch { /* ignore */ }
280
+ }
281
+ }
282
+ if (linked > 0) {
283
+ p.log.success(`${label} agent symlinks created (${dir}/)`)
284
+ }
285
+ }
286
+ } catch { /* ignore */ }
287
+ }
288
+
214
289
  // 8. Proxy
215
290
  if (isCaddyInstalled()) {
216
291
  const proxySpin = p.spinner()
@@ -220,18 +295,48 @@ if (isCaddyInstalled()) {
220
295
  reloadCaddy(caddyfilePath)
221
296
  proxySpin.stop('Proxy reloaded')
222
297
  } else {
223
- proxySpin.start('Starting proxy (requires sudo for port 80)...')
298
+ proxySpin.start('Starting proxy...')
224
299
  startCaddy(caddyfilePath)
225
300
  proxySpin.stop('Proxy started')
226
301
  }
227
302
  }
228
303
 
229
304
  // 9. Install / sync dependencies
230
- await withSpin(
231
- 'Installing dependencies...',
232
- 'Dependencies installed',
233
- () => { run('npm install', { stdio: 'ignore' }) }
234
- )
305
+ // Skip npm install if a dev server is running — it would trigger Vite's
306
+ // file watcher and restart the server on a different port.
307
+ {
308
+ const { SERVER_PORT } = await import('../server/index.js')
309
+ const { readDevDomain: readDomain } = await import('./proxy.js')
310
+ const http = await import('node:http')
311
+
312
+ const devRunning = await new Promise((resolve) => {
313
+ const req = http.get(`http://localhost:${SERVER_PORT}/health`, (res) => {
314
+ if (res.statusCode !== 200) { resolve(false); return }
315
+ let data = ''
316
+ res.on('data', (chunk) => { data += chunk })
317
+ res.on('end', () => {
318
+ try {
319
+ const json = JSON.parse(data)
320
+ const ourDomain = readDomain()
321
+ resolve(json.ok === true && json.devDomain === ourDomain)
322
+ } catch { resolve(false) }
323
+ })
324
+ })
325
+ req.on('error', () => resolve(false))
326
+ req.setTimeout(1000, () => { req.destroy(); resolve(false) })
327
+ })
328
+
329
+ if (devRunning) {
330
+ p.log.info(dim('Skipping npm install — dev server is running (would cause restart)'))
331
+ p.log.info(dim('Run `npm install` manually after stopping the dev server if needed'))
332
+ } else {
333
+ await withSpin(
334
+ 'Installing dependencies...',
335
+ 'Dependencies installed',
336
+ () => { run('npm install', { stdio: 'ignore' }) }
337
+ )
338
+ }
339
+ }
235
340
 
236
341
  p.note(
237
342
  [
@@ -242,7 +347,28 @@ p.note(
242
347
  'Getting started'
243
348
  )
244
349
 
245
- console.log()
246
- console.log(mascot())
350
+ // Offer branch guide
351
+ {
352
+ let currentBranchName = 'main'
353
+ try {
354
+ currentBranchName = execSync('git branch --show-current', { encoding: 'utf8' }).trim() || 'main'
355
+ } catch { /* empty */ }
356
+
357
+ const wantBranch = await p.select({
358
+ message: 'Want to work from a different branch?',
359
+ options: [
360
+ { value: true, label: 'Yes (help me create it)' },
361
+ { value: false, label: `No (stay on current branch ${bold(currentBranchName)})` },
362
+ ],
363
+ initialValue: false,
364
+ })
247
365
 
248
- p.outro('')
366
+ if (!p.isCancel(wantBranch) && wantBranch) {
367
+ const { runBranchGuide } = await import('./branch.js')
368
+ await runBranchGuide()
369
+ } else {
370
+ console.log()
371
+ console.log(mascot())
372
+ p.outro('')
373
+ }
374
+ }
@@ -7,7 +7,7 @@
7
7
 
8
8
  import * as p from '@clack/prompts'
9
9
  import { execSync } from 'node:child_process'
10
- import { detectWorktreeName, getPort } from '../worktree/port.js'
10
+ import { detectWorktreeName, resolveRunningPort } from '../worktree/port.js'
11
11
  import { readDevDomain } from './proxy.js'
12
12
  import { parseFlags } from './flags.js'
13
13
  import { dim, cyan, bold, yellow } from './intro.js'
@@ -78,17 +78,25 @@ function resolveSession(sessions, id) {
78
78
  return null
79
79
  }
80
80
 
81
- /** Detect the current tmux session name */
81
+ /** Detect the current tmux session name (only if it's a storyboard session) */
82
82
  function getCurrentTmuxSession() {
83
83
  try {
84
- return execSync('tmux display-message -p "#{session_name}" 2>/dev/null', {
84
+ const name = execSync('tmux display-message -p "#{session_name}" 2>/dev/null', {
85
85
  encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'],
86
86
  }).trim()
87
+ // Only return if this is a storyboard terminal session
88
+ return name.startsWith('sb-') ? name : null
87
89
  } catch {
88
90
  return null
89
91
  }
90
92
  }
91
93
 
94
+ /** Check if we're inside ANY tmux (storyboard or user's own) */
95
+ function _isInsideTmux() {
96
+ return Boolean(process.env.TMUX)
97
+ }
98
+ void _isInsideTmux
99
+
92
100
  // ── Close (archive) ──
93
101
 
94
102
  async function closeSession(session, worktreeName, port) {
@@ -125,13 +133,15 @@ async function closeSession(session, worktreeName, port) {
125
133
 
126
134
  // ── Open (attach) ──
127
135
 
128
- async function openSession(session, worktreeName, port) {
136
+ async function openSession(session, _worktreeName, _port) {
137
+ void _worktreeName
138
+ void _port
129
139
  p.intro(bold('Open session'))
130
140
 
131
141
  const label = session.name || session.tmuxName
132
- const currentTmux = getCurrentTmuxSession()
142
+ const currentSb = getCurrentTmuxSession()
133
143
 
134
- if (session.status === 'live' && session.tmuxName !== currentTmux) {
144
+ if (session.status === 'live' && session.tmuxName !== currentSb) {
135
145
  p.log.warn(
136
146
  `Session ${cyan(label)} is currently live on widget ${dim(session.widgetId)} ` +
137
147
  `in canvas ${cyan(session.canvasId)}.`
@@ -145,8 +155,9 @@ async function openSession(session, worktreeName, port) {
145
155
  }
146
156
  }
147
157
 
148
- // If we're inside tmux, switch; otherwise attach
149
- if (currentTmux) {
158
+ // If we're inside a storyboard tmux session, use switch-client.
159
+ // Otherwise always use attach-session (even if user has their own tmux).
160
+ if (currentSb) {
150
161
  p.outro(`Switching to ${bold(label)}...`)
151
162
  try {
152
163
  execSync(`tmux switch-client -t "${session.tmuxName}"`, { stdio: 'inherit' })
@@ -234,7 +245,7 @@ async function main() {
234
245
  }
235
246
 
236
247
  const worktreeName = detectWorktreeName()
237
- const port = getPort(worktreeName)
248
+ const port = resolveRunningPort(worktreeName)
238
249
  const result = await fetchSessions(worktreeName, port)
239
250
 
240
251
  if (!result) {
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Terminal Messaging CLI — send messages between terminals and save output.
3
+ *
4
+ * Commands:
5
+ * storyboard terminal send <widgetId> "message" Send a message to a terminal
6
+ * storyboard terminal send --connected "message" Send to connected peer
7
+ * storyboard terminal output --summary "..." --content "..." Save latest output
8
+ * storyboard terminal status <widgetId> Check terminal status
9
+ * storyboard terminal read <widgetId> Read terminal buffer
10
+ */
11
+
12
+ import { getServerUrl } from './serverUrl.js'
13
+
14
+ function parseArgs(args) {
15
+ const result = { positional: [], flags: {} }
16
+ for (let i = 0; i < args.length; i++) {
17
+ if (args[i].startsWith('--')) {
18
+ const key = args[i].slice(2)
19
+ const next = args[i + 1]
20
+ if (next && !next.startsWith('--')) {
21
+ result.flags[key] = next
22
+ i++
23
+ } else {
24
+ result.flags[key] = true
25
+ }
26
+ } else {
27
+ result.positional.push(args[i])
28
+ }
29
+ }
30
+ return result
31
+ }
32
+
33
+ export async function handleSend() {
34
+ const args = process.argv.slice(4) // skip: node, sb, terminal, send
35
+ const { positional, flags } = parseArgs(args)
36
+
37
+ // Resolve sender identity from env
38
+ const senderWidgetId = process.env.STORYBOARD_WIDGET_ID || null
39
+
40
+ let targetWidgetId = null
41
+ let message = null
42
+
43
+ if (flags.connected) {
44
+ // Auto-resolve connected peer
45
+ if (!senderWidgetId) {
46
+ console.error('Error: --connected requires $STORYBOARD_WIDGET_ID to be set')
47
+ process.exit(1)
48
+ }
49
+ // Read own config to find connected agent/terminal peers
50
+ try {
51
+ const { readTerminalConfigById, initTerminalConfig } = await import('../canvas/terminal-config.js')
52
+ initTerminalConfig(process.cwd())
53
+ const config = readTerminalConfigById(senderWidgetId)
54
+ const peers = (config?.connectedWidgets || []).filter(
55
+ (w) => w.type === 'terminal' || w.type === 'agent'
56
+ )
57
+ if (peers.length === 0) {
58
+ console.error('No connected terminal/agent peers found')
59
+ process.exit(1)
60
+ }
61
+ if (peers.length > 1) {
62
+ console.error(`Multiple peers found. Specify one: ${peers.map((p) => p.id).join(', ')}`)
63
+ process.exit(1)
64
+ }
65
+ targetWidgetId = peers[0].id
66
+ } catch (err) {
67
+ console.error(`Error resolving connected peer: ${err.message}`)
68
+ process.exit(1)
69
+ }
70
+ message = typeof flags.connected === 'string' ? flags.connected : positional[0]
71
+ } else {
72
+ targetWidgetId = positional[0]
73
+ message = positional.slice(1).join(' ') || flags.message
74
+ }
75
+
76
+ if (!targetWidgetId || !message) {
77
+ console.error('Usage: storyboard terminal send <widgetId> "message"')
78
+ console.error(' storyboard terminal send --connected "message"')
79
+ process.exit(1)
80
+ }
81
+
82
+ const serverUrl = getServerUrl()
83
+ try {
84
+ const res = await fetch(`${serverUrl}/_storyboard/canvas/terminal/send`, {
85
+ method: 'POST',
86
+ headers: { 'Content-Type': 'application/json' },
87
+ body: JSON.stringify({ widgetId: targetWidgetId, message, from: senderWidgetId }),
88
+ signal: AbortSignal.timeout(10000),
89
+ })
90
+ const data = await res.json()
91
+ if (data.success) {
92
+ if (data.queued) {
93
+ console.log(`Message queued for ${targetWidgetId} (agent not running, will deliver on start)`)
94
+ } else {
95
+ console.log(`Message delivered to ${targetWidgetId}`)
96
+ }
97
+ } else {
98
+ console.error(`Failed: ${data.error}`)
99
+ process.exit(1)
100
+ }
101
+ } catch (err) {
102
+ if (err.name === 'TimeoutError') {
103
+ console.error(`Error: request timed out — is the dev server running? (tried ${serverUrl})`)
104
+ } else {
105
+ console.error(`Error: ${err.message}`)
106
+ }
107
+ process.exit(1)
108
+ }
109
+ }
110
+
111
+ export async function handleOutput() {
112
+ const args = process.argv.slice(4) // skip: node, sb, terminal, output
113
+ const { flags } = parseArgs(args)
114
+
115
+ const widgetId = flags.widget || process.env.STORYBOARD_WIDGET_ID
116
+ const summary = flags.summary || ''
117
+ const content = flags.content || ''
118
+
119
+ if (!widgetId) {
120
+ console.error('Error: --widget <id> or $STORYBOARD_WIDGET_ID required')
121
+ process.exit(1)
122
+ }
123
+
124
+ const serverUrl = getServerUrl()
125
+ try {
126
+ const res = await fetch(`${serverUrl}/_storyboard/canvas/terminal/output`, {
127
+ method: 'POST',
128
+ headers: { 'Content-Type': 'application/json' },
129
+ body: JSON.stringify({ widgetId, content, summary }),
130
+ signal: AbortSignal.timeout(10000),
131
+ })
132
+ const data = await res.json()
133
+ if (data.success) {
134
+ console.log('Output saved')
135
+ } else {
136
+ console.error(`Failed: ${data.error}`)
137
+ process.exit(1)
138
+ }
139
+ } catch (err) {
140
+ if (err.name === 'TimeoutError') {
141
+ console.error(`Error: request timed out — is the dev server running? (tried ${serverUrl})`)
142
+ } else {
143
+ console.error(`Error: ${err.message}`)
144
+ }
145
+ process.exit(1)
146
+ }
147
+ }
148
+
149
+ export async function handleStatus() {
150
+ const args = process.argv.slice(4) // skip: node, sb, terminal, status
151
+ const { positional } = parseArgs(args)
152
+
153
+ const widgetId = positional[0]
154
+ if (!widgetId) {
155
+ console.error('Usage: storyboard terminal status <widgetId>')
156
+ process.exit(1)
157
+ }
158
+
159
+ try {
160
+ const { readTerminalConfigById, initTerminalConfig } = await import('../canvas/terminal-config.js')
161
+ initTerminalConfig(process.cwd())
162
+ const config = readTerminalConfigById(widgetId)
163
+ if (!config) {
164
+ console.error(`No config found for ${widgetId}`)
165
+ process.exit(1)
166
+ }
167
+ console.log(JSON.stringify({
168
+ widgetId: config.widgetId,
169
+ displayName: config.displayName || null,
170
+ agentStatus: config.agentStatus || null,
171
+ latestOutput: config.latestOutput ? { summary: config.latestOutput.summary, updatedAt: config.latestOutput.updatedAt } : null,
172
+ pendingMessages: (config.pendingMessages || []).length,
173
+ }, null, 2))
174
+ } catch (err) {
175
+ console.error(`Error: ${err.message}`)
176
+ process.exit(1)
177
+ }
178
+ }
179
+
180
+ export async function handleRead() {
181
+ const args = process.argv.slice(4) // skip: node, sb, terminal, read
182
+ const { positional, flags } = parseArgs(args)
183
+
184
+ const widgetId = positional[0] || process.env.STORYBOARD_WIDGET_ID
185
+ if (!widgetId) {
186
+ console.error('Usage: storyboard terminal read <widgetId> [--length N]')
187
+ process.exit(1)
188
+ }
189
+
190
+ const length = flags.length ? parseInt(flags.length, 10) : undefined
191
+
192
+ // Try HTTP API first (dev server may have fresher data)
193
+ try {
194
+ const serverUrl = getServerUrl()
195
+ const qs = length ? `?length=${length}` : ''
196
+ const res = await fetch(`${serverUrl}/_storyboard/canvas/terminal-buffer/${encodeURIComponent(widgetId)}${qs}`, {
197
+ signal: AbortSignal.timeout(3000),
198
+ })
199
+ if (res.ok) {
200
+ const data = await res.json()
201
+ console.log(JSON.stringify(data, null, 2))
202
+ return
203
+ }
204
+ } catch {
205
+ // Server not reachable — read directly from file
206
+ }
207
+
208
+ // Fallback: read buffer file directly
209
+ try {
210
+ const { readFileSync, existsSync } = await import('node:fs')
211
+ const { join } = await import('node:path')
212
+ const bufferPath = join(process.cwd(), '.storyboard', 'terminal-buffers', `${widgetId}.buffer.json`)
213
+ if (!existsSync(bufferPath)) {
214
+ console.error(`No buffer found for ${widgetId}`)
215
+ process.exit(1)
216
+ }
217
+ const data = JSON.parse(readFileSync(bufferPath, 'utf8'))
218
+ if (length) {
219
+ if (data.scrollback && data.scrollback.length > length) {
220
+ data.scrollback = data.scrollback.slice(-length)
221
+ }
222
+ if (data.paneContent && data.paneContent.length > length) {
223
+ data.paneContent = data.paneContent.slice(-length)
224
+ }
225
+ }
226
+ console.log(JSON.stringify(data, null, 2))
227
+ } catch (err) {
228
+ console.error(`Error: ${err.message}`)
229
+ process.exit(1)
230
+ }
231
+ }