@dfosco/storyboard 0.5.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (592) hide show
  1. package/commandpalette.config.json +152 -0
  2. package/dist/storyboard-ui.css +1 -0
  3. package/dist/storyboard-ui.js +21328 -0
  4. package/dist/storyboard-ui.js.map +1 -0
  5. package/dist/tailwind.css +2 -0
  6. package/dist/tiny-canvas.css +1 -0
  7. package/dist/tiny-canvas.js +389 -0
  8. package/package.json +121 -0
  9. package/paste.config.json +67 -0
  10. package/scaffold/AGENTS.md +432 -0
  11. package/scaffold/agents/prompt-agent.agent.md +181 -0
  12. package/scaffold/agents/terminal-agent.agent.md +351 -0
  13. package/scaffold/codex/config.toml +246 -0
  14. package/scaffold/deploy.yml +103 -0
  15. package/scaffold/githooks/pre-push +114 -0
  16. package/scaffold/gitignore +64 -0
  17. package/scaffold/manifest.json +56 -0
  18. package/scaffold/preview.yml +181 -0
  19. package/scaffold/scripts/link.sh +26 -0
  20. package/scaffold/scripts/unlink.sh +10 -0
  21. package/scaffold/skills/agent-browser/SKILL.md +260 -0
  22. package/scaffold/skills/canvas/SKILL.md +364 -0
  23. package/scaffold/skills/create/SKILL.md +501 -0
  24. package/scaffold/skills/ship/SKILL.md +237 -0
  25. package/scaffold/skills/storyboard/SKILL.md +360 -0
  26. package/scaffold/skills/update-storyboard/SKILL.md +16 -0
  27. package/scaffold/skills/update-storyboard/update-storyboard-packages.sh +26 -0
  28. package/scaffold/skills/vitest/GENERATION.md +5 -0
  29. package/scaffold/skills/vitest/SKILL.md +52 -0
  30. package/scaffold/skills/vitest/references/advanced-environments.md +264 -0
  31. package/scaffold/skills/vitest/references/advanced-projects.md +300 -0
  32. package/scaffold/skills/vitest/references/advanced-type-testing.md +237 -0
  33. package/scaffold/skills/vitest/references/advanced-vi.md +249 -0
  34. package/scaffold/skills/vitest/references/core-cli.md +166 -0
  35. package/scaffold/skills/vitest/references/core-config.md +174 -0
  36. package/scaffold/skills/vitest/references/core-describe.md +193 -0
  37. package/scaffold/skills/vitest/references/core-expect.md +219 -0
  38. package/scaffold/skills/vitest/references/core-hooks.md +244 -0
  39. package/scaffold/skills/vitest/references/core-test-api.md +233 -0
  40. package/scaffold/skills/vitest/references/features-concurrency.md +250 -0
  41. package/scaffold/skills/vitest/references/features-context.md +238 -0
  42. package/scaffold/skills/vitest/references/features-coverage.md +207 -0
  43. package/scaffold/skills/vitest/references/features-filtering.md +211 -0
  44. package/scaffold/skills/vitest/references/features-mocking.md +265 -0
  45. package/scaffold/skills/vitest/references/features-snapshots.md +207 -0
  46. package/scaffold/skills/worktree/SKILL.md +93 -0
  47. package/scaffold/storyboard.config.json +44 -0
  48. package/src/canvas/Canvas.jsx +78 -0
  49. package/src/canvas/Draggable.jsx +235 -0
  50. package/src/canvas/index.d.ts +41 -0
  51. package/src/canvas/index.js +6 -0
  52. package/src/canvas/style.css +118 -0
  53. package/src/canvas/useResetCanvas.js +17 -0
  54. package/src/canvas/utils.js +136 -0
  55. package/src/core/assets/fonts/IoskeleyMono-Bold.woff2 +0 -0
  56. package/src/core/assets/fonts/IoskeleyMono-Italic.woff2 +0 -0
  57. package/src/core/assets/fonts/IoskeleyMono-Medium.woff2 +0 -0
  58. package/src/core/assets/fonts/IoskeleyMono-Regular.woff2 +0 -0
  59. package/src/core/assets/fonts/IoskeleyMono-SemiBold.woff2 +0 -0
  60. package/src/core/autosync/server.js +714 -0
  61. package/src/core/autosync/server.test.js +158 -0
  62. package/src/core/canvas/__tests__/agent-integration.test.js +596 -0
  63. package/src/core/canvas/__tests__/helpers/browser.js +95 -0
  64. package/src/core/canvas/__tests__/helpers/canvas-api.js +129 -0
  65. package/src/core/canvas/__tests__/helpers/perf.js +118 -0
  66. package/src/core/canvas/__tests__/helpers/setup.js +176 -0
  67. package/src/core/canvas/__tests__/helpers/tmux.js +130 -0
  68. package/src/core/canvas/__tests__/helpers/transcript.js +132 -0
  69. package/src/core/canvas/__tests__/terminal-integration.test.js +177 -0
  70. package/src/core/canvas/collision.js +292 -0
  71. package/src/core/canvas/collision.test.js +371 -0
  72. package/src/core/canvas/compact.js +83 -0
  73. package/src/core/canvas/deriveCanvasId.test.js +40 -0
  74. package/src/core/canvas/githubEmbeds.js +527 -0
  75. package/src/core/canvas/githubEmbeds.test.js +302 -0
  76. package/src/core/canvas/hot-pool.js +766 -0
  77. package/src/core/canvas/identity.js +107 -0
  78. package/src/core/canvas/identity.test.js +100 -0
  79. package/src/core/canvas/materializer.js +259 -0
  80. package/src/core/canvas/materializer.test.js +356 -0
  81. package/src/core/canvas/selectedWidgets.js +270 -0
  82. package/src/core/canvas/selectedWidgets.test.js +321 -0
  83. package/src/core/canvas/server.js +3134 -0
  84. package/src/core/canvas/server.test.js +379 -0
  85. package/src/core/canvas/terminal-config.js +330 -0
  86. package/src/core/canvas/terminal-registry.js +465 -0
  87. package/src/core/canvas/terminal-server.js +1436 -0
  88. package/src/core/canvas/writeGuard.js +53 -0
  89. package/src/core/cli/agent.js +85 -0
  90. package/src/core/cli/branch.js +386 -0
  91. package/src/core/cli/canvasAdd.js +241 -0
  92. package/src/core/cli/canvasBatch.js +98 -0
  93. package/src/core/cli/canvasBounds.js +160 -0
  94. package/src/core/cli/canvasRead.js +236 -0
  95. package/src/core/cli/canvasUpdate.js +179 -0
  96. package/src/core/cli/code.js +67 -0
  97. package/src/core/cli/compact.js +62 -0
  98. package/src/core/cli/create.js +674 -0
  99. package/src/core/cli/dev-helpers.js +53 -0
  100. package/src/core/cli/dev-helpers.test.js +53 -0
  101. package/src/core/cli/dev.js +430 -0
  102. package/src/core/cli/exit.js +38 -0
  103. package/src/core/cli/flags.js +174 -0
  104. package/src/core/cli/flags.test.js +155 -0
  105. package/src/core/cli/index.js +233 -0
  106. package/src/core/cli/intro.js +37 -0
  107. package/src/core/cli/proxy.js +319 -0
  108. package/src/core/cli/proxy.test.js +63 -0
  109. package/src/core/cli/schemas.js +223 -0
  110. package/src/core/cli/server.js +192 -0
  111. package/src/core/cli/serverUrl.js +61 -0
  112. package/src/core/cli/sessions.js +459 -0
  113. package/src/core/cli/setup.js +404 -0
  114. package/src/core/cli/terminal-commands.js +287 -0
  115. package/src/core/cli/terminal-messaging.js +231 -0
  116. package/src/core/cli/terminal-welcome.js +515 -0
  117. package/src/core/cli/updateVersion.js +124 -0
  118. package/src/core/comments/api.js +284 -0
  119. package/src/core/comments/api.test.js +282 -0
  120. package/src/core/comments/auth.js +151 -0
  121. package/src/core/comments/auth.test.js +167 -0
  122. package/src/core/comments/commentCache.js +109 -0
  123. package/src/core/comments/commentCache.test.js +48 -0
  124. package/src/core/comments/commentDrafts.js +68 -0
  125. package/src/core/comments/commentMode.js +63 -0
  126. package/src/core/comments/commentMode.test.js +90 -0
  127. package/src/core/comments/config.js +47 -0
  128. package/src/core/comments/config.test.js +77 -0
  129. package/src/core/comments/graphql.js +65 -0
  130. package/src/core/comments/graphql.test.js +95 -0
  131. package/src/core/comments/index.js +42 -0
  132. package/src/core/comments/metadata.js +52 -0
  133. package/src/core/comments/metadata.test.js +110 -0
  134. package/src/core/comments/queries.js +245 -0
  135. package/src/core/comments/ui/AuthModal.jsx +114 -0
  136. package/src/core/comments/ui/CommentOverlay.js +52 -0
  137. package/src/core/comments/ui/CommentWindow.jsx +329 -0
  138. package/src/core/comments/ui/CommentsDrawer.jsx +102 -0
  139. package/src/core/comments/ui/Composer.jsx +64 -0
  140. package/src/core/comments/ui/authModal.js +66 -0
  141. package/src/core/comments/ui/authModal.test.js +76 -0
  142. package/src/core/comments/ui/comment-cursor-dark.svg +1 -0
  143. package/src/core/comments/ui/comment-cursor.svg +1 -0
  144. package/src/core/comments/ui/comment-layout.css +142 -0
  145. package/src/core/comments/ui/commentWindow.js +121 -0
  146. package/src/core/comments/ui/comments.css +242 -0
  147. package/src/core/comments/ui/commentsDrawer.js +84 -0
  148. package/src/core/comments/ui/composer.js +136 -0
  149. package/src/core/comments/ui/index.js +14 -0
  150. package/src/core/comments/ui/mount.js +687 -0
  151. package/src/core/comments/ui/mount.test.js +336 -0
  152. package/src/core/data/dotPath.js +53 -0
  153. package/src/core/data/dotPath.test.js +114 -0
  154. package/src/core/data/loader.js +409 -0
  155. package/src/core/data/loader.test.js +599 -0
  156. package/src/core/data/viewfinder.js +363 -0
  157. package/src/core/data/viewfinder.test.js +456 -0
  158. package/src/core/devtools/devtools-consumer.js +28 -0
  159. package/src/core/devtools/devtools.js +144 -0
  160. package/src/core/devtools/devtools.test.js +75 -0
  161. package/src/core/devtools/sceneDebug.js +112 -0
  162. package/src/core/devtools/sceneDebug.test.js +141 -0
  163. package/src/core/index.js +124 -0
  164. package/src/core/inspector/fiberWalker.js +239 -0
  165. package/src/core/inspector/highlighter.js +275 -0
  166. package/src/core/inspector/mouseMode.js +259 -0
  167. package/src/core/lib/components/ui/alert/alert-action.jsx +11 -0
  168. package/src/core/lib/components/ui/alert/alert-description.jsx +11 -0
  169. package/src/core/lib/components/ui/alert/alert-title.jsx +11 -0
  170. package/src/core/lib/components/ui/alert/alert.jsx +25 -0
  171. package/src/core/lib/components/ui/alert/index.js +17 -0
  172. package/src/core/lib/components/ui/avatar/avatar-badge.jsx +22 -0
  173. package/src/core/lib/components/ui/avatar/avatar-fallback.jsx +18 -0
  174. package/src/core/lib/components/ui/avatar/avatar-group-count.jsx +19 -0
  175. package/src/core/lib/components/ui/avatar/avatar-group.jsx +19 -0
  176. package/src/core/lib/components/ui/avatar/avatar-image.jsx +15 -0
  177. package/src/core/lib/components/ui/avatar/avatar.jsx +19 -0
  178. package/src/core/lib/components/ui/avatar/index.js +22 -0
  179. package/src/core/lib/components/ui/badge/badge.jsx +31 -0
  180. package/src/core/lib/components/ui/badge/index.js +2 -0
  181. package/src/core/lib/components/ui/button/button.jsx +100 -0
  182. package/src/core/lib/components/ui/button/index.js +12 -0
  183. package/src/core/lib/components/ui/card/card-action.jsx +11 -0
  184. package/src/core/lib/components/ui/card/card-content.jsx +11 -0
  185. package/src/core/lib/components/ui/card/card-description.jsx +11 -0
  186. package/src/core/lib/components/ui/card/card-footer.jsx +11 -0
  187. package/src/core/lib/components/ui/card/card-header.jsx +19 -0
  188. package/src/core/lib/components/ui/card/card-title.jsx +11 -0
  189. package/src/core/lib/components/ui/card/card.jsx +17 -0
  190. package/src/core/lib/components/ui/card/index.js +25 -0
  191. package/src/core/lib/components/ui/checkbox/checkbox.jsx +29 -0
  192. package/src/core/lib/components/ui/checkbox/index.js +6 -0
  193. package/src/core/lib/components/ui/collapsible/collapsible-content.jsx +7 -0
  194. package/src/core/lib/components/ui/collapsible/collapsible-trigger.jsx +7 -0
  195. package/src/core/lib/components/ui/collapsible/collapsible.jsx +7 -0
  196. package/src/core/lib/components/ui/collapsible/index.js +13 -0
  197. package/src/core/lib/components/ui/dialog/dialog-close.jsx +7 -0
  198. package/src/core/lib/components/ui/dialog/dialog-content.jsx +34 -0
  199. package/src/core/lib/components/ui/dialog/dialog-description.jsx +15 -0
  200. package/src/core/lib/components/ui/dialog/dialog-footer.jsx +23 -0
  201. package/src/core/lib/components/ui/dialog/dialog-header.jsx +11 -0
  202. package/src/core/lib/components/ui/dialog/dialog-overlay.jsx +15 -0
  203. package/src/core/lib/components/ui/dialog/dialog-portal.jsx +4 -0
  204. package/src/core/lib/components/ui/dialog/dialog-title.jsx +15 -0
  205. package/src/core/lib/components/ui/dialog/dialog-trigger.jsx +7 -0
  206. package/src/core/lib/components/ui/dialog/dialog.jsx +4 -0
  207. package/src/core/lib/components/ui/dialog/index.js +34 -0
  208. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.jsx +8 -0
  209. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.jsx +30 -0
  210. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-content.jsx +22 -0
  211. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.jsx +16 -0
  212. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-group.jsx +7 -0
  213. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-item.jsx +20 -0
  214. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-label.jsx +17 -0
  215. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-portal.jsx +4 -0
  216. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.jsx +7 -0
  217. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.jsx +29 -0
  218. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-separator.jsx +15 -0
  219. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.jsx +16 -0
  220. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.jsx +15 -0
  221. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.jsx +23 -0
  222. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-sub.jsx +4 -0
  223. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu-trigger.jsx +7 -0
  224. package/src/core/lib/components/ui/dropdown-menu/dropdown-menu.jsx +4 -0
  225. package/src/core/lib/components/ui/dropdown-menu/index.js +54 -0
  226. package/src/core/lib/components/ui/input/index.js +7 -0
  227. package/src/core/lib/components/ui/input/input.jsx +19 -0
  228. package/src/core/lib/components/ui/label/index.js +7 -0
  229. package/src/core/lib/components/ui/label/label.jsx +19 -0
  230. package/src/core/lib/components/ui/panel/index.js +24 -0
  231. package/src/core/lib/components/ui/panel/panel-body.jsx +11 -0
  232. package/src/core/lib/components/ui/panel/panel-close.jsx +16 -0
  233. package/src/core/lib/components/ui/panel/panel-content.jsx +29 -0
  234. package/src/core/lib/components/ui/panel/panel-footer.jsx +11 -0
  235. package/src/core/lib/components/ui/panel/panel-header.jsx +11 -0
  236. package/src/core/lib/components/ui/panel/panel-title.jsx +12 -0
  237. package/src/core/lib/components/ui/panel/panel.jsx +4 -0
  238. package/src/core/lib/components/ui/popover/index.js +28 -0
  239. package/src/core/lib/components/ui/popover/popover-close.jsx +7 -0
  240. package/src/core/lib/components/ui/popover/popover-content.jsx +22 -0
  241. package/src/core/lib/components/ui/popover/popover-description.jsx +11 -0
  242. package/src/core/lib/components/ui/popover/popover-header.jsx +11 -0
  243. package/src/core/lib/components/ui/popover/popover-portal.jsx +4 -0
  244. package/src/core/lib/components/ui/popover/popover-title.jsx +11 -0
  245. package/src/core/lib/components/ui/popover/popover-trigger.jsx +8 -0
  246. package/src/core/lib/components/ui/popover/popover.jsx +4 -0
  247. package/src/core/lib/components/ui/searchable-list.jsx +160 -0
  248. package/src/core/lib/components/ui/select/index.js +37 -0
  249. package/src/core/lib/components/ui/select/select-content.jsx +30 -0
  250. package/src/core/lib/components/ui/select/select-group-heading.jsx +17 -0
  251. package/src/core/lib/components/ui/select/select-group.jsx +15 -0
  252. package/src/core/lib/components/ui/select/select-item.jsx +26 -0
  253. package/src/core/lib/components/ui/select/select-label.jsx +11 -0
  254. package/src/core/lib/components/ui/select/select-portal.jsx +4 -0
  255. package/src/core/lib/components/ui/select/select-scroll-down-button.jsx +18 -0
  256. package/src/core/lib/components/ui/select/select-scroll-up-button.jsx +18 -0
  257. package/src/core/lib/components/ui/select/select-separator.jsx +15 -0
  258. package/src/core/lib/components/ui/select/select-trigger.jsx +25 -0
  259. package/src/core/lib/components/ui/select/select.jsx +4 -0
  260. package/src/core/lib/components/ui/separator/index.js +7 -0
  261. package/src/core/lib/components/ui/separator/separator.jsx +22 -0
  262. package/src/core/lib/components/ui/sheet/index.js +34 -0
  263. package/src/core/lib/components/ui/sheet/sheet-close.jsx +7 -0
  264. package/src/core/lib/components/ui/sheet/sheet-content.jsx +35 -0
  265. package/src/core/lib/components/ui/sheet/sheet-description.jsx +15 -0
  266. package/src/core/lib/components/ui/sheet/sheet-footer.jsx +11 -0
  267. package/src/core/lib/components/ui/sheet/sheet-header.jsx +11 -0
  268. package/src/core/lib/components/ui/sheet/sheet-overlay.jsx +15 -0
  269. package/src/core/lib/components/ui/sheet/sheet-portal.jsx +4 -0
  270. package/src/core/lib/components/ui/sheet/sheet-title.jsx +15 -0
  271. package/src/core/lib/components/ui/sheet/sheet-trigger.jsx +7 -0
  272. package/src/core/lib/components/ui/sheet/sheet.jsx +4 -0
  273. package/src/core/lib/components/ui/textarea/index.js +7 -0
  274. package/src/core/lib/components/ui/textarea/textarea.jsx +18 -0
  275. package/src/core/lib/components/ui/toggle/index.js +8 -0
  276. package/src/core/lib/components/ui/toggle/toggle.jsx +36 -0
  277. package/src/core/lib/components/ui/toggle-group/index.js +10 -0
  278. package/src/core/lib/components/ui/toggle-group/toggle-group-item.jsx +29 -0
  279. package/src/core/lib/components/ui/toggle-group/toggle-group.jsx +43 -0
  280. package/src/core/lib/components/ui/tooltip/index.js +3 -0
  281. package/src/core/lib/components/ui/tooltip/tooltip-content.jsx +21 -0
  282. package/src/core/lib/components/ui/tooltip/tooltip-trigger.jsx +23 -0
  283. package/src/core/lib/components/ui/tooltip/tooltip.jsx +11 -0
  284. package/src/core/lib/components/ui/trigger-button/index.js +6 -0
  285. package/src/core/lib/components/ui/trigger-button/trigger-button.css +38 -0
  286. package/src/core/lib/components/ui/trigger-button/trigger-button.jsx +63 -0
  287. package/src/core/lib/utils/index.js +6 -0
  288. package/src/core/logger/devLogger.js +238 -0
  289. package/src/core/logger/devLogger.test.js +193 -0
  290. package/src/core/modes/modes.css +98 -0
  291. package/src/core/modes/modes.js +492 -0
  292. package/src/core/modes/modes.test.js +562 -0
  293. package/src/core/mountStoryboardCore.js +478 -0
  294. package/src/core/rename-watcher/config.json +23 -0
  295. package/src/core/rename-watcher/watcher.js +531 -0
  296. package/src/core/scaffold.js +100 -0
  297. package/src/core/server/index.js +391 -0
  298. package/src/core/session/bodyClasses.js +128 -0
  299. package/src/core/session/bodyClasses.test.js +192 -0
  300. package/src/core/session/hashSubscribe.js +19 -0
  301. package/src/core/session/hashSubscribe.test.js +62 -0
  302. package/src/core/session/hideMode.js +424 -0
  303. package/src/core/session/hideMode.test.js +268 -0
  304. package/src/core/session/interceptHideParams.js +35 -0
  305. package/src/core/session/interceptHideParams.test.js +90 -0
  306. package/src/core/session/localStorage.js +134 -0
  307. package/src/core/session/localStorage.test.js +148 -0
  308. package/src/core/session/session.js +76 -0
  309. package/src/core/session/session.test.js +91 -0
  310. package/src/core/stores/canvasConfig.js +134 -0
  311. package/src/core/stores/canvasConfig.test.js +120 -0
  312. package/src/core/stores/commandActions.js +284 -0
  313. package/src/core/stores/commandPaletteConfig.js +31 -0
  314. package/src/core/stores/configSchema.js +232 -0
  315. package/src/core/stores/configSchema.test.js +72 -0
  316. package/src/core/stores/configStore.js +161 -0
  317. package/src/core/stores/customerModeConfig.js +30 -0
  318. package/src/core/stores/featureFlags.js +127 -0
  319. package/src/core/stores/paletteProviders.js +360 -0
  320. package/src/core/stores/paletteProviders.test.js +186 -0
  321. package/src/core/stores/plugins.js +40 -0
  322. package/src/core/stores/plugins.test.js +68 -0
  323. package/src/core/stores/recentArtifacts.js +68 -0
  324. package/src/core/stores/recentArtifacts.test.js +71 -0
  325. package/src/core/stores/sidePanelStore.ts +143 -0
  326. package/src/core/stores/themeStore.ts +291 -0
  327. package/src/core/stores/toolRegistry.js +227 -0
  328. package/src/core/stores/toolStateStore.js +183 -0
  329. package/src/core/stores/toolStateStore.test.js +220 -0
  330. package/src/core/stores/toolbarConfigStore.js +165 -0
  331. package/src/core/stores/uiConfig.js +64 -0
  332. package/src/core/stores/uiConfig.test.js +63 -0
  333. package/src/core/styles/tailwind.css +204 -0
  334. package/src/core/tools/handlers/autosync.js +12 -0
  335. package/src/core/tools/handlers/canvasAddWidget.js +11 -0
  336. package/src/core/tools/handlers/canvasAgents.js +20 -0
  337. package/src/core/tools/handlers/canvasToolbar.js +56 -0
  338. package/src/core/tools/handlers/commandPalette.js +9 -0
  339. package/src/core/tools/handlers/comments.js +16 -0
  340. package/src/core/tools/handlers/create.js +39 -0
  341. package/src/core/tools/handlers/devtools.js +122 -0
  342. package/src/core/tools/handlers/devtools.test.js +87 -0
  343. package/src/core/tools/handlers/featureFlags.js +21 -0
  344. package/src/core/tools/handlers/flows.js +68 -0
  345. package/src/core/tools/handlers/hideChrome.js +9 -0
  346. package/src/core/tools/handlers/hideToolbars.js +25 -0
  347. package/src/core/tools/handlers/inspector.js +19 -0
  348. package/src/core/tools/handlers/paletteTheme.js +35 -0
  349. package/src/core/tools/handlers/theme.js +9 -0
  350. package/src/core/tools/registry.js +26 -0
  351. package/src/core/tools/surfaces/canvasToolbar.js +10 -0
  352. package/src/core/tools/surfaces/commandList.js +10 -0
  353. package/src/core/tools/surfaces/mainToolbar.js +11 -0
  354. package/src/core/tools/surfaces/registry.js +19 -0
  355. package/src/core/ui/ActionMenuButton.jsx +114 -0
  356. package/src/core/ui/AutosyncMenuButton.css +67 -0
  357. package/src/core/ui/AutosyncMenuButton.jsx +242 -0
  358. package/src/core/ui/BranchSelect.jsx +29 -0
  359. package/src/core/ui/BranchSelect.module.css +30 -0
  360. package/src/core/ui/CanvasAgentsMenu.jsx +89 -0
  361. package/src/core/ui/CanvasCreateMenu.jsx +611 -0
  362. package/src/core/ui/CanvasSnap.css +27 -0
  363. package/src/core/ui/CanvasSnap.jsx +51 -0
  364. package/src/core/ui/CanvasUndoRedo.css +36 -0
  365. package/src/core/ui/CanvasUndoRedo.jsx +62 -0
  366. package/src/core/ui/CanvasZoomControl.css +53 -0
  367. package/src/core/ui/CanvasZoomControl.jsx +49 -0
  368. package/src/core/ui/CanvasZoomToFit.css +18 -0
  369. package/src/core/ui/CanvasZoomToFit.jsx +26 -0
  370. package/src/core/ui/CommandMenu.css +8 -0
  371. package/src/core/ui/CommandMenu.jsx +287 -0
  372. package/src/core/ui/CommandPalette.jsx +35 -0
  373. package/src/core/ui/CommandPaletteTrigger.jsx +25 -0
  374. package/src/core/ui/CommentsMenuButton.jsx +40 -0
  375. package/src/core/ui/CoreUIBar.css +47 -0
  376. package/src/core/ui/CoreUIBar.jsx +905 -0
  377. package/src/core/ui/CreateMenuButton.jsx +117 -0
  378. package/src/core/ui/HideChromeTrigger.jsx +48 -0
  379. package/src/core/ui/Icon.jsx +279 -0
  380. package/src/core/ui/InspectorPanel.css +109 -0
  381. package/src/core/ui/InspectorPanel.jsx +632 -0
  382. package/src/core/ui/PwaInstallBanner.css +42 -0
  383. package/src/core/ui/PwaInstallBanner.jsx +124 -0
  384. package/src/core/ui/SidePanel.jsx +261 -0
  385. package/src/core/ui/ThemeMenuButton.jsx +139 -0
  386. package/src/core/ui/core-ui-colors.css +129 -0
  387. package/src/core/ui/design-modes.ts +7 -0
  388. package/src/core/ui/sidepanel.css +301 -0
  389. package/src/core/ui/viewfinder.ts +7 -0
  390. package/src/core/ui-entry.js +30 -0
  391. package/src/core/utils/fuzzySearch.js +117 -0
  392. package/src/core/utils/fuzzySearch.test.js +119 -0
  393. package/src/core/utils/mobileViewport.js +57 -0
  394. package/src/core/utils/mobileViewport.test.js +68 -0
  395. package/src/core/utils/prodMode.js +38 -0
  396. package/src/core/utils/smoothCorners.js +20 -0
  397. package/src/core/vite/docs-handler.js +155 -0
  398. package/src/core/vite/server-plugin.js +797 -0
  399. package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +260 -0
  400. package/src/core/workshop/features/createCanvas/index.js +14 -0
  401. package/src/core/workshop/features/createFlow/CreateFlowForm.jsx +334 -0
  402. package/src/core/workshop/features/createFlow/index.js +19 -0
  403. package/src/core/workshop/features/createFlow/server.js +663 -0
  404. package/src/core/workshop/features/createPage/CreatePageForm.jsx +304 -0
  405. package/src/core/workshop/features/createPage/index.js +11 -0
  406. package/src/core/workshop/features/createPrototype/CreatePrototypeForm.jsx +289 -0
  407. package/src/core/workshop/features/createPrototype/index.js +19 -0
  408. package/src/core/workshop/features/createPrototype/server.js +433 -0
  409. package/src/core/workshop/features/createStory/CreateStoryForm.jsx +208 -0
  410. package/src/core/workshop/features/createStory/index.js +14 -0
  411. package/src/core/workshop/features/registry-server.js +22 -0
  412. package/src/core/workshop/features/registry.js +28 -0
  413. package/src/core/workshop/features/templateIndex.js +155 -0
  414. package/src/core/workshop/ui/WorkshopPanel.jsx +98 -0
  415. package/src/core/workshop/ui/mount.ts +6 -0
  416. package/src/core/worktree/port.js +268 -0
  417. package/src/core/worktree/port.test.js +222 -0
  418. package/src/core/worktree/serverRegistry.js +120 -0
  419. package/src/internals/AuthModal/AuthModal.jsx +132 -0
  420. package/src/internals/AuthModal/AuthModal.module.css +221 -0
  421. package/src/internals/BranchBar/BranchBar.jsx +87 -0
  422. package/src/internals/BranchBar/BranchBar.module.css +247 -0
  423. package/src/internals/BranchBar/useBranches.js +93 -0
  424. package/src/internals/BranchBar/useBranches.test.js +68 -0
  425. package/src/internals/CommandPalette/CommandPalette.jsx +1361 -0
  426. package/src/internals/CommandPalette/CreateDialog.jsx +219 -0
  427. package/src/internals/CommandPalette/command-palette.css +180 -0
  428. package/src/internals/FlowError.module.css +30 -0
  429. package/src/internals/Icon.jsx +279 -0
  430. package/src/internals/StoryboardContext.js +3 -0
  431. package/src/internals/Viewfinder.jsx +1479 -0
  432. package/src/internals/Viewfinder.module.css +1540 -0
  433. package/src/internals/Workspace.jsx +7 -0
  434. package/src/internals/__mocks__/virtual-storyboard-data-index.js +4 -0
  435. package/src/internals/canvas/CanvasControls.jsx +112 -0
  436. package/src/internals/canvas/CanvasControls.module.css +135 -0
  437. package/src/internals/canvas/CanvasPage.bridge.test.jsx +387 -0
  438. package/src/internals/canvas/CanvasPage.dragdrop.test.jsx +350 -0
  439. package/src/internals/canvas/CanvasPage.jsx +3092 -0
  440. package/src/internals/canvas/CanvasPage.module.css +187 -0
  441. package/src/internals/canvas/CanvasPage.multiselect.test.jsx +358 -0
  442. package/src/internals/canvas/CanvasToolbar.jsx +73 -0
  443. package/src/internals/canvas/CanvasToolbar.module.css +92 -0
  444. package/src/internals/canvas/ComponentErrorBoundary.jsx +50 -0
  445. package/src/internals/canvas/ConnectorLayer.jsx +208 -0
  446. package/src/internals/canvas/ConnectorLayer.module.css +129 -0
  447. package/src/internals/canvas/MarqueeOverlay.jsx +20 -0
  448. package/src/internals/canvas/PageSelector.jsx +587 -0
  449. package/src/internals/canvas/PageSelector.module.css +261 -0
  450. package/src/internals/canvas/PageSelector.test.jsx +113 -0
  451. package/src/internals/canvas/WebGLContextPool.jsx +292 -0
  452. package/src/internals/canvas/WebGLContextPool.test.jsx +165 -0
  453. package/src/internals/canvas/canvasApi.js +164 -0
  454. package/src/internals/canvas/canvasReloadGuard.js +37 -0
  455. package/src/internals/canvas/canvasReloadGuard.test.js +27 -0
  456. package/src/internals/canvas/canvasTheme.js +118 -0
  457. package/src/internals/canvas/componentIsolate.jsx +165 -0
  458. package/src/internals/canvas/componentSetIsolate.jsx +257 -0
  459. package/src/internals/canvas/computeCanvasBounds.test.js +121 -0
  460. package/src/internals/canvas/connectorGeometry.js +132 -0
  461. package/src/internals/canvas/hotPoolDevLogs.js +25 -0
  462. package/src/internals/canvas/textSelection.js +10 -0
  463. package/src/internals/canvas/textSelection.test.js +26 -0
  464. package/src/internals/canvas/useCanvas.js +126 -0
  465. package/src/internals/canvas/useCanvas.test.js +26 -0
  466. package/src/internals/canvas/useMarqueeSelect.js +213 -0
  467. package/src/internals/canvas/useMarqueeSelect.test.js +78 -0
  468. package/src/internals/canvas/useUndoRedo.js +86 -0
  469. package/src/internals/canvas/useUndoRedo.test.js +231 -0
  470. package/src/internals/canvas/widgets/CodePenEmbed.jsx +293 -0
  471. package/src/internals/canvas/widgets/CodePenEmbed.module.css +161 -0
  472. package/src/internals/canvas/widgets/ComponentSetWidget.jsx +2 -0
  473. package/src/internals/canvas/widgets/ComponentSetWidget.module.css +89 -0
  474. package/src/internals/canvas/widgets/ComponentWidget.jsx +14 -0
  475. package/src/internals/canvas/widgets/ComponentWidget.module.css +0 -0
  476. package/src/internals/canvas/widgets/CropOverlay.jsx +179 -0
  477. package/src/internals/canvas/widgets/CropOverlay.module.css +154 -0
  478. package/src/internals/canvas/widgets/ExpandedPane.jsx +474 -0
  479. package/src/internals/canvas/widgets/ExpandedPane.module.css +179 -0
  480. package/src/internals/canvas/widgets/ExpandedPane.test.jsx +240 -0
  481. package/src/internals/canvas/widgets/ExpandedPaneTopBar.jsx +111 -0
  482. package/src/internals/canvas/widgets/ExpandedPaneTopBar.module.css +59 -0
  483. package/src/internals/canvas/widgets/ExpandedPaneTopBar.test.jsx +45 -0
  484. package/src/internals/canvas/widgets/FigmaEmbed.jsx +296 -0
  485. package/src/internals/canvas/widgets/FigmaEmbed.module.css +222 -0
  486. package/src/internals/canvas/widgets/FrozenTerminalOverlay.jsx +151 -0
  487. package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +83 -0
  488. package/src/internals/canvas/widgets/ImageWidget.jsx +287 -0
  489. package/src/internals/canvas/widgets/ImageWidget.module.css +81 -0
  490. package/src/internals/canvas/widgets/LinkPreview.jsx +439 -0
  491. package/src/internals/canvas/widgets/LinkPreview.module.css +585 -0
  492. package/src/internals/canvas/widgets/LinkPreview.test.jsx +193 -0
  493. package/src/internals/canvas/widgets/MarkdownBlock.jsx +354 -0
  494. package/src/internals/canvas/widgets/MarkdownBlock.module.css +377 -0
  495. package/src/internals/canvas/widgets/MarkdownBlock.test.jsx +92 -0
  496. package/src/internals/canvas/widgets/PromptWidget.jsx +428 -0
  497. package/src/internals/canvas/widgets/PromptWidget.module.css +273 -0
  498. package/src/internals/canvas/widgets/PrototypeEmbed.jsx +463 -0
  499. package/src/internals/canvas/widgets/PrototypeEmbed.module.css +579 -0
  500. package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +10 -0
  501. package/src/internals/canvas/widgets/ResizeHandle.jsx +67 -0
  502. package/src/internals/canvas/widgets/ResizeHandle.module.css +29 -0
  503. package/src/internals/canvas/widgets/StickyNote.jsx +92 -0
  504. package/src/internals/canvas/widgets/StickyNote.module.css +70 -0
  505. package/src/internals/canvas/widgets/StickyNote.test.jsx +116 -0
  506. package/src/internals/canvas/widgets/StorySetWidget.jsx +208 -0
  507. package/src/internals/canvas/widgets/StorySetWidget.module.css +89 -0
  508. package/src/internals/canvas/widgets/StoryWidget.jsx +334 -0
  509. package/src/internals/canvas/widgets/StoryWidget.module.css +211 -0
  510. package/src/internals/canvas/widgets/TerminalReadWidget.jsx +146 -0
  511. package/src/internals/canvas/widgets/TerminalReadWidget.module.css +94 -0
  512. package/src/internals/canvas/widgets/TerminalWidget.jsx +704 -0
  513. package/src/internals/canvas/widgets/TerminalWidget.module.css +444 -0
  514. package/src/internals/canvas/widgets/TilesWidget.jsx +300 -0
  515. package/src/internals/canvas/widgets/TilesWidget.module.css +133 -0
  516. package/src/internals/canvas/widgets/WidgetChrome.jsx +580 -0
  517. package/src/internals/canvas/widgets/WidgetChrome.module.css +421 -0
  518. package/src/internals/canvas/widgets/WidgetWrapper.jsx +15 -0
  519. package/src/internals/canvas/widgets/WidgetWrapper.module.css +25 -0
  520. package/src/internals/canvas/widgets/codepenUrl.js +75 -0
  521. package/src/internals/canvas/widgets/codepenUrl.test.js +76 -0
  522. package/src/internals/canvas/widgets/embedInteraction.test.jsx +173 -0
  523. package/src/internals/canvas/widgets/embedOverlay.module.css +35 -0
  524. package/src/internals/canvas/widgets/embedTheme.js +148 -0
  525. package/src/internals/canvas/widgets/expandUtils.js +559 -0
  526. package/src/internals/canvas/widgets/expandUtils.test.js +155 -0
  527. package/src/internals/canvas/widgets/figmaUrl.js +118 -0
  528. package/src/internals/canvas/widgets/figmaUrl.test.js +139 -0
  529. package/src/internals/canvas/widgets/githubUrl.js +82 -0
  530. package/src/internals/canvas/widgets/githubUrl.test.js +74 -0
  531. package/src/internals/canvas/widgets/iframeDevLogs.js +49 -0
  532. package/src/internals/canvas/widgets/iframeDevLogs.test.jsx +81 -0
  533. package/src/internals/canvas/widgets/index.js +42 -0
  534. package/src/internals/canvas/widgets/pasteRules.js +295 -0
  535. package/src/internals/canvas/widgets/pasteRules.test.js +474 -0
  536. package/src/internals/canvas/widgets/snapshotDisplay.test.jsx +211 -0
  537. package/src/internals/canvas/widgets/tilePool.js +23 -0
  538. package/src/internals/canvas/widgets/tiles/diagonal-bl.png +0 -0
  539. package/src/internals/canvas/widgets/tiles/diagonal-br.png +0 -0
  540. package/src/internals/canvas/widgets/tiles/diagonal-tl.png +0 -0
  541. package/src/internals/canvas/widgets/tiles/leaf.png +0 -0
  542. package/src/internals/canvas/widgets/tiles/quarter-tl.png +0 -0
  543. package/src/internals/canvas/widgets/tiles/quarter-tr.png +0 -0
  544. package/src/internals/canvas/widgets/tiles/solid-a.png +0 -0
  545. package/src/internals/canvas/widgets/tiles/solid-b.png +0 -0
  546. package/src/internals/canvas/widgets/widgetConfig.js +291 -0
  547. package/src/internals/canvas/widgets/widgetConfig.test.js +68 -0
  548. package/src/internals/canvas/widgets/widgetIcons.jsx +190 -0
  549. package/src/internals/canvas/widgets/widgetProps.js +133 -0
  550. package/src/internals/context/FormContext.js +13 -0
  551. package/src/internals/context/FormContext.test.js +48 -0
  552. package/src/internals/context.jsx +481 -0
  553. package/src/internals/context.test.jsx +296 -0
  554. package/src/internals/hashPreserver.js +73 -0
  555. package/src/internals/hashPreserver.test.js +107 -0
  556. package/src/internals/hooks/useConfig.js +14 -0
  557. package/src/internals/hooks/useFeatureFlag.js +14 -0
  558. package/src/internals/hooks/useFlows.js +50 -0
  559. package/src/internals/hooks/useFlows.test.js +134 -0
  560. package/src/internals/hooks/useHideMode.js +31 -0
  561. package/src/internals/hooks/useHideMode.test.js +43 -0
  562. package/src/internals/hooks/useLocalStorage.js +57 -0
  563. package/src/internals/hooks/useLocalStorage.test.js +75 -0
  564. package/src/internals/hooks/useMode.js +43 -0
  565. package/src/internals/hooks/useObject.js +101 -0
  566. package/src/internals/hooks/useObject.test.js +74 -0
  567. package/src/internals/hooks/useOverride.js +84 -0
  568. package/src/internals/hooks/useOverride.test.js +71 -0
  569. package/src/internals/hooks/usePrototypeReloadGuard.js +64 -0
  570. package/src/internals/hooks/useRecord.js +158 -0
  571. package/src/internals/hooks/useRecord.test.js +221 -0
  572. package/src/internals/hooks/useScene.js +38 -0
  573. package/src/internals/hooks/useScene.test.js +66 -0
  574. package/src/internals/hooks/useSceneData.js +108 -0
  575. package/src/internals/hooks/useSceneData.test.js +136 -0
  576. package/src/internals/hooks/useSession.js +4 -0
  577. package/src/internals/hooks/useSession.test.js +8 -0
  578. package/src/internals/hooks/useThemeState.js +61 -0
  579. package/src/internals/hooks/useThemeState.test.js +66 -0
  580. package/src/internals/hooks/useUndoRedo.js +28 -0
  581. package/src/internals/hooks/useUndoRedo.test.js +64 -0
  582. package/src/internals/index.js +58 -0
  583. package/src/internals/story/ComponentSetPage.jsx +198 -0
  584. package/src/internals/story/ComponentSetPage.module.css +129 -0
  585. package/src/internals/story/StoryPage.jsx +147 -0
  586. package/src/internals/story/StoryPage.module.css +18 -0
  587. package/src/internals/test-utils.js +45 -0
  588. package/src/internals/vite/data-plugin.js +1508 -0
  589. package/src/internals/vite/data-plugin.test.js +1223 -0
  590. package/src/test-utils.js +44 -0
  591. package/toolbar.config.json +271 -0
  592. package/widgets.config.json +1537 -0
@@ -0,0 +1,674 @@
1
+ /**
2
+ * storyboard create — Create prototypes, canvases, flows, and pages.
3
+ *
4
+ * Supports both interactive prompts and non-interactive flags.
5
+ * When all required flags are provided, skips prompts entirely.
6
+ * When some flags are provided, prompts only for missing fields.
7
+ *
8
+ * Usage:
9
+ * storyboard create Interactive picker
10
+ * storyboard create prototype Interactive prototype creation
11
+ * storyboard create prototype --name my-proto Non-interactive (or partial)
12
+ * storyboard create canvas --name my-canvas Non-interactive (or partial)
13
+ * storyboard create flow --name default --prototype my-proto
14
+ * storyboard create page --prototype my-proto --path settings
15
+ */
16
+
17
+ import * as p from '@clack/prompts'
18
+ import { parseFlags, hasFlags, formatFlagHelp } from './flags.js'
19
+ import { prototypeSchema, canvasSchema, flowSchema, pageSchema, componentSchema } from './schemas.js'
20
+ import { getServerUrl } from './serverUrl.js'
21
+ import { detectWorktreeName, getPort, resolveRunningPort } from '../worktree/port.js'
22
+
23
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`
24
+ const green = (s) => `\x1b[32m${s}\x1b[0m`
25
+ const cyan = (s) => `\x1b[36m${s}\x1b[0m`
26
+
27
+ function promptOrCancel(promise) {
28
+ return promise.then((v) => {
29
+ if (p.isCancel(v)) process.exit(0)
30
+ return v
31
+ })
32
+ }
33
+
34
+ function showHelp(type, schema) {
35
+ console.log(`\n ${type} flags:\n`)
36
+ console.log(formatFlagHelp(schema))
37
+ console.log('')
38
+ process.exit(0)
39
+ }
40
+
41
+ async function serverGet(path) {
42
+ const base = getServerUrl()
43
+ const res = await fetch(`${base}${path}`)
44
+ if (!res.ok) throw new Error(`${res.status} ${res.statusText}`)
45
+ return res.json()
46
+ }
47
+
48
+ async function serverPost(path, body) {
49
+ const base = getServerUrl()
50
+ const res = await fetch(`${base}${path}`, {
51
+ method: 'POST',
52
+ headers: { 'Content-Type': 'application/json' },
53
+ body: JSON.stringify(body),
54
+ })
55
+ if (!res.ok) {
56
+ const text = await res.text().catch(() => '')
57
+ throw new Error(`${res.status} ${res.statusText}${text ? ': ' + text : ''}`)
58
+ }
59
+ return res.json()
60
+ }
61
+
62
+ async function checkServer(url, { quiet = false } = {}) {
63
+ const target = url || getServerUrl()
64
+ try {
65
+ await fetch(`${target}/_storyboard/canvas/list`, { signal: AbortSignal.timeout(5000) })
66
+ return true
67
+ } catch (err) {
68
+ if (!quiet) p.log.warning(`Could not reach dev server at ${target}: ${err.message}`)
69
+ return false
70
+ }
71
+ }
72
+
73
+ async function ensureDevServer({ quiet = false } = {}) {
74
+ // 1. If STORYBOARD_SERVER_URL is explicitly set, try it first (with retry)
75
+ if (process.env.STORYBOARD_SERVER_URL) {
76
+ const envUrl = process.env.STORYBOARD_SERVER_URL.replace(/\/$/, '')
77
+ if (await checkServer(envUrl, { quiet })) return
78
+
79
+ // Retry once after a short delay (server may be mid-restart)
80
+ await new Promise((r) => setTimeout(r, 1000))
81
+ if (await checkServer(envUrl, { quiet })) return
82
+
83
+ if (!quiet) {
84
+ p.log.warning(
85
+ `STORYBOARD_SERVER_URL (${envUrl}) is not reachable — falling back to auto-discovery.`
86
+ )
87
+ }
88
+ }
89
+
90
+ // 2. Try auto-discovered URL (Caddy → ports.json)
91
+ if (await checkServer(undefined, { quiet })) return
92
+
93
+ // 3. No server found — start one
94
+ let s
95
+ if (!quiet) {
96
+ s = p.spinner()
97
+ s.start('No running dev server found — starting one...')
98
+ }
99
+
100
+ const { spawn } = await import('child_process')
101
+ const { generateCaddyfile, isCaddyRunning, reloadCaddy } = await import('./proxy.js')
102
+
103
+ const worktreeName = detectWorktreeName()
104
+ const port = getPort(worktreeName)
105
+ const isMain = worktreeName === 'main'
106
+ const basePath = isMain ? '/' : `/branch--${worktreeName}/`
107
+
108
+ const child = spawn('npx', ['vite', '--port', String(port)], {
109
+ env: { ...process.env, VITE_BASE_PATH: basePath },
110
+ stdio: ['ignore', 'pipe', 'pipe'],
111
+ detached: true,
112
+ })
113
+ child.unref()
114
+
115
+ // Wait for Vite to be ready (up to 30s)
116
+ const start = Date.now()
117
+ while (Date.now() - start < 30000) {
118
+ await new Promise((r) => setTimeout(r, 500))
119
+ try {
120
+ await fetch(`http://localhost:${port}`, { signal: AbortSignal.timeout(2000) })
121
+ // Update Caddy with actual port
122
+ try {
123
+ const caddyfilePath = generateCaddyfile({ [worktreeName]: port })
124
+ if (isCaddyRunning()) reloadCaddy(caddyfilePath)
125
+ } catch { /* empty */ }
126
+ if (s) s.stop('Dev server started')
127
+ return
128
+ } catch {
129
+ // Not ready yet — keep waiting
130
+ }
131
+ }
132
+ if (s) s.stop('Dev server may still be starting...')
133
+ }
134
+
135
+ function getProxyUrl() {
136
+ const name = detectWorktreeName()
137
+ const isMain = name === 'main'
138
+ return isMain ? 'http://storyboard.localhost/' : `http://storyboard.localhost/branch--${name}/`
139
+ }
140
+
141
+ function getDirectUrl() {
142
+ const name = detectWorktreeName()
143
+ const port = resolveRunningPort(name)
144
+ const isMain = name === 'main'
145
+ return isMain ? `http://localhost:${port}/` : `http://localhost:${port}/branch--${name}/`
146
+ }
147
+
148
+ /**
149
+ * After creation: show URL and open in browser.
150
+ * @param {string} resultPath — e.g. "src/canvas/test.canvas.jsonl" or "src/prototypes/MyProto"
151
+ * @param {'canvas'|'prototype'} type
152
+ */
153
+ async function postCreateFlow(resultPath, type) {
154
+ const { isCaddyRunning } = await import('./proxy.js')
155
+ const proxyRunning = isCaddyRunning()
156
+ const baseUrl = proxyRunning ? getProxyUrl() : getDirectUrl()
157
+
158
+ // Build the view URL
159
+ let viewUrl = baseUrl
160
+ if (type === 'canvas' && resultPath) {
161
+ const canvasName = resultPath.replace(/^src\/canvas\//, '').replace(/\.canvas\.jsonl$/, '')
162
+ viewUrl = `${baseUrl}canvas/${canvasName}`
163
+ } else if (type === 'prototype' && resultPath) {
164
+ const protoName = resultPath.replace(/^src\/prototypes\//, '')
165
+ viewUrl = `${baseUrl}${protoName}`
166
+ }
167
+
168
+ p.log.info(`${cyan(viewUrl)}`)
169
+
170
+ // Open in browser
171
+ try {
172
+ const { execSync } = await import('child_process')
173
+ execSync(`open "${viewUrl}"`, { stdio: 'ignore' })
174
+ } catch { /* empty */ }
175
+
176
+ p.outro('')
177
+ }
178
+
179
+ // ── Prototype creation ────────────────────────────────────────
180
+
181
+ async function createPrototype() {
182
+ const argv = process.argv.slice(4)
183
+ if (argv.includes('--help') || argv.includes('-h')) return showHelp('create prototype', prototypeSchema)
184
+ const flagMode = hasFlags(argv)
185
+ const { flags, errors } = flagMode ? parseFlags(argv, prototypeSchema) : { flags: {}, errors: [] }
186
+
187
+ if (errors.length) {
188
+ for (const e of errors) p.log.error(e)
189
+ process.exit(1)
190
+ }
191
+
192
+ p.intro('storyboard create prototype')
193
+ await ensureDevServer()
194
+
195
+ // Fetch available folders and templates from server
196
+ let folders = []
197
+ let partials = []
198
+ try {
199
+ const data = await serverGet('/_storyboard/workshop/prototypes')
200
+ folders = data.folders || []
201
+ partials = data.partials || []
202
+ } catch {
203
+ // Server may not support this endpoint — continue without options
204
+ }
205
+
206
+ // Resolve each field: use flag if provided, otherwise prompt
207
+ const isExternal = flags.url !== undefined
208
+ ? true
209
+ : flagMode
210
+ ? false
211
+ : await promptOrCancel(p.confirm({ message: 'Is this an external prototype?', initialValue: false }))
212
+
213
+ let url = flags.url || ''
214
+ if (isExternal && !url) {
215
+ url = await promptOrCancel(p.text({
216
+ message: 'External URL',
217
+ placeholder: 'https://example.com/prototype',
218
+ validate: (v) => {
219
+ if (!v) return 'URL is required for external prototypes'
220
+ if (!/^https?:\/\//.test(v)) return 'URL must start with http:// or https://'
221
+ },
222
+ }))
223
+ }
224
+
225
+ const name = flags.name || await promptOrCancel(p.text({
226
+ message: 'Prototype name',
227
+ placeholder: 'my-prototype',
228
+ validate: (v) => {
229
+ if (!v) return 'Name is required'
230
+ if (/[A-Z\s]/.test(v)) return 'Use kebab-case (lowercase, hyphens)'
231
+ },
232
+ }))
233
+
234
+ const defaultTitle = name.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
235
+ const title = flags.title || (flagMode ? defaultTitle : await promptOrCancel(p.text({
236
+ message: 'Display title',
237
+ placeholder: defaultTitle,
238
+ defaultValue: defaultTitle,
239
+ })))
240
+
241
+ // Folder selection
242
+ let folder = flags.folder || ''
243
+ if (!folder && !flagMode && folders.length > 0) {
244
+ folder = await promptOrCancel(p.select({
245
+ message: 'Folder',
246
+ options: [
247
+ { value: '', label: 'None (root)' },
248
+ ...folders.map((f) => ({ value: f, label: f })),
249
+ ],
250
+ }))
251
+ }
252
+
253
+ // Template selection
254
+ let partial = flags.partial || ''
255
+ if (!partial && !isExternal && !flagMode && partials.length > 0) {
256
+ const templateOptions = [
257
+ { value: '', label: 'Blank (no template)' },
258
+ ...partials.map((t) => ({
259
+ value: t.id || t.name || t,
260
+ label: t.name || t.label || t,
261
+ hint: t.directory || undefined,
262
+ })),
263
+ ]
264
+ partial = await promptOrCancel(p.select({ message: 'Template', options: templateOptions }))
265
+ }
266
+
267
+ const author = flags.author || (flagMode ? '' : await promptOrCancel(p.text({
268
+ message: 'Author',
269
+ placeholder: 'your-name',
270
+ defaultValue: '',
271
+ })))
272
+
273
+ const description = flags.description || (flagMode ? '' : await promptOrCancel(p.text({
274
+ message: 'Description',
275
+ placeholder: 'What is this prototype about?',
276
+ defaultValue: '',
277
+ })))
278
+
279
+ let createFlow = flags.flow ?? false
280
+ if (!flagMode && !isExternal) {
281
+ createFlow = await promptOrCancel(p.confirm({ message: 'Create a default flow file?', initialValue: false }))
282
+ }
283
+
284
+ // Submit
285
+ const s = p.spinner()
286
+ s.start('Creating prototype...')
287
+
288
+ try {
289
+ const body = {
290
+ name,
291
+ title: title || name,
292
+ folder: folder || undefined,
293
+ partial: partial || undefined,
294
+ author: author || undefined,
295
+ description: description || undefined,
296
+ createFlow,
297
+ }
298
+ if (isExternal) body.url = url
299
+
300
+ const result = await serverPost('/_storyboard/workshop/prototypes', body)
301
+ s.stop('Prototype created!')
302
+ if (result.path) {
303
+ p.log.success(` ${result.path}`)
304
+ }
305
+ await postCreateFlow(result.path || `src/prototypes/${name}`, 'prototype')
306
+ return
307
+ } catch (err) {
308
+ s.stop('Failed to create prototype')
309
+ p.log.error(err.message)
310
+ }
311
+
312
+ p.outro('')
313
+ }
314
+
315
+ // ── Canvas creation ───────────────────────────────────────────
316
+
317
+ async function createCanvas() {
318
+ const argv = process.argv.slice(4)
319
+ if (argv.includes('--help') || argv.includes('-h')) return showHelp('create canvas', canvasSchema)
320
+ const flagMode = hasFlags(argv)
321
+ const { flags, errors } = flagMode ? parseFlags(argv, canvasSchema) : { flags: {}, errors: [] }
322
+
323
+ if (errors.length) {
324
+ for (const e of errors) p.log.error(e)
325
+ process.exit(1)
326
+ }
327
+
328
+ p.intro('storyboard create canvas')
329
+ await ensureDevServer()
330
+
331
+ // Fetch available folders
332
+ let folders = []
333
+ try {
334
+ const data = await serverGet('/_storyboard/canvas/folders')
335
+ folders = data.folders || data || []
336
+ } catch {
337
+ // Continue without folders
338
+ }
339
+
340
+ const name = flags.name || await promptOrCancel(p.text({
341
+ message: 'Canvas name',
342
+ placeholder: 'my-canvas',
343
+ validate: (v) => {
344
+ if (!v) return 'Name is required'
345
+ if (/[A-Z\s]/.test(v)) return 'Use kebab-case (lowercase, hyphens)'
346
+ },
347
+ }))
348
+
349
+ const defaultTitle = name.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
350
+ const title = flags.title || (flagMode ? defaultTitle : await promptOrCancel(p.text({
351
+ message: 'Display title',
352
+ placeholder: defaultTitle,
353
+ defaultValue: defaultTitle,
354
+ })))
355
+
356
+ let folder = flags.folder || ''
357
+ if (!folder && !flagMode && Array.isArray(folders) && folders.length > 0) {
358
+ folder = await promptOrCancel(p.select({
359
+ message: 'Folder',
360
+ options: [
361
+ { value: '', label: 'None (root)' },
362
+ ...folders.map((f) => ({ value: f, label: f })),
363
+ ],
364
+ }))
365
+ }
366
+
367
+ const grid = flags.grid ?? (flagMode ? true : await promptOrCancel(p.confirm({
368
+ message: 'Show dot grid?',
369
+ initialValue: true,
370
+ })))
371
+
372
+ const includeJsx = flags.jsx ?? (flagMode ? false : await promptOrCancel(p.confirm({
373
+ message: 'Include JSX companion file?',
374
+ initialValue: false,
375
+ })))
376
+
377
+ const description = flags.description || (flagMode ? '' : (await promptOrCancel(p.text({
378
+ message: 'Description (optional)',
379
+ placeholder: 'A brief description of this canvas',
380
+ }))) || '')
381
+
382
+ // Submit
383
+ const s = p.spinner()
384
+ s.start('Creating canvas...')
385
+
386
+ try {
387
+ const result = await serverPost('/_storyboard/canvas/create', {
388
+ name,
389
+ title: title || name,
390
+ folder: folder || undefined,
391
+ grid,
392
+ includeJsx,
393
+ description: description || undefined,
394
+ })
395
+ s.stop('Canvas created!')
396
+ if (result.path || result.name) {
397
+ p.log.success(` ${result.path || result.name}`)
398
+ }
399
+ await postCreateFlow(result.path || `src/canvas/${name}.canvas.jsonl`, 'canvas')
400
+ return
401
+ } catch (err) {
402
+ s.stop('Failed to create canvas')
403
+ p.log.error(err.message)
404
+ }
405
+
406
+ p.outro('')
407
+ }
408
+
409
+ // ── Flow creation ─────────────────────────────────────────────
410
+
411
+ async function createFlow() {
412
+ const argv = process.argv.slice(4)
413
+ if (argv.includes('--help') || argv.includes('-h')) return showHelp('create flow', flowSchema)
414
+ const flagMode = hasFlags(argv)
415
+ const { flags, errors } = flagMode ? parseFlags(argv, flowSchema) : { flags: {}, errors: [] }
416
+
417
+ if (errors.length) {
418
+ for (const e of errors) p.log.error(e)
419
+ process.exit(1)
420
+ }
421
+
422
+ p.intro('storyboard create flow')
423
+ await ensureDevServer()
424
+
425
+ const prototype = flags.prototype || await promptOrCancel(p.text({
426
+ message: 'Prototype name',
427
+ placeholder: 'my-prototype',
428
+ validate: (v) => { if (!v) return 'Prototype is required' },
429
+ }))
430
+
431
+ const name = flags.name || await promptOrCancel(p.text({
432
+ message: 'Flow name',
433
+ placeholder: 'default',
434
+ validate: (v) => { if (!v) return 'Name is required' },
435
+ }))
436
+
437
+ const title = flags.title || (flagMode ? '' : await promptOrCancel(p.text({
438
+ message: 'Display title',
439
+ placeholder: name.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()),
440
+ defaultValue: '',
441
+ })))
442
+
443
+ const folder = flags.folder || ''
444
+ const author = flags.author || ''
445
+ const description = flags.description || ''
446
+ const copyFrom = flags['copy-from'] || undefined
447
+ const startingPage = flags['starting-page'] || undefined
448
+ const globals = flags.globals || undefined
449
+
450
+ // Submit
451
+ const s = p.spinner()
452
+ s.start('Creating flow...')
453
+
454
+ try {
455
+ const body = {
456
+ name,
457
+ prototype,
458
+ title: title || undefined,
459
+ folder: folder || undefined,
460
+ author: author || undefined,
461
+ description: description || undefined,
462
+ copyFrom,
463
+ startingPage,
464
+ globals,
465
+ }
466
+
467
+ const result = await serverPost('/_storyboard/workshop/flows', body)
468
+ s.stop('Flow created!')
469
+ if (result.path) {
470
+ p.log.success(` ${result.path}`)
471
+ }
472
+ p.outro('')
473
+ } catch (err) {
474
+ s.stop('Failed to create flow')
475
+ p.log.error(err.message)
476
+ p.outro('')
477
+ }
478
+ }
479
+
480
+ // ── Page creation ─────────────────────────────────────────────
481
+
482
+ async function createPage() {
483
+ const argv = process.argv.slice(4)
484
+ if (argv.includes('--help') || argv.includes('-h')) return showHelp('create page', pageSchema)
485
+ const flagMode = hasFlags(argv)
486
+ const { flags, errors } = flagMode ? parseFlags(argv, pageSchema) : { flags: {}, errors: [] }
487
+
488
+ if (errors.length) {
489
+ for (const e of errors) p.log.error(e)
490
+ process.exit(1)
491
+ }
492
+
493
+ p.intro('storyboard create page')
494
+ await ensureDevServer()
495
+
496
+ const prototype = flags.prototype || await promptOrCancel(p.text({
497
+ message: 'Prototype name',
498
+ placeholder: 'my-prototype',
499
+ validate: (v) => { if (!v) return 'Prototype is required' },
500
+ }))
501
+
502
+ const pagePath = flags.path || await promptOrCancel(p.text({
503
+ message: 'Page path (e.g. settings/general)',
504
+ placeholder: 'settings',
505
+ validate: (v) => { if (!v) return 'Path is required' },
506
+ }))
507
+
508
+ const folder = flags.folder || ''
509
+ const template = flags.template || ''
510
+
511
+ // Submit
512
+ const s = p.spinner()
513
+ s.start('Creating page...')
514
+
515
+ try {
516
+ const body = {
517
+ prototype,
518
+ path: pagePath,
519
+ folder: folder || undefined,
520
+ template: template || undefined,
521
+ }
522
+
523
+ const result = await serverPost('/_storyboard/workshop/pages', body)
524
+ s.stop('Page created!')
525
+ if (result.path) {
526
+ p.log.success(` ${result.path}`)
527
+ }
528
+ p.outro('')
529
+ } catch (err) {
530
+ s.stop('Failed to create page')
531
+ p.log.error(err.message)
532
+ p.outro('')
533
+ }
534
+ }
535
+
536
+ // ── Create Component ───────────────────────────────────────────
537
+
538
+ async function createComponent() {
539
+ const rest = process.argv.slice(4)
540
+ if (rest.includes('--help') || rest.includes('-h')) showHelp('component', componentSchema)
541
+
542
+ const flagMode = hasFlags(rest)
543
+ const { flags, errors } = flagMode ? parseFlags(rest, componentSchema) : { flags: {}, errors: [] }
544
+ if (errors.length) {
545
+ for (const e of errors) p.log.error(e)
546
+ process.exit(1)
547
+ }
548
+
549
+ p.intro('storyboard create component')
550
+
551
+ const componentName = flags.name || await promptOrCancel(
552
+ p.text({
553
+ message: 'Component name',
554
+ placeholder: 'my-component',
555
+ validate: (v) => {
556
+ if (!v) return 'Name is required'
557
+ if (!/^[a-z][a-z0-9-]*$/.test(v)) return 'Use kebab-case (e.g. my-component)'
558
+ },
559
+ }),
560
+ )
561
+
562
+ // Directory picker — list existing subdirectories inside src/components/
563
+ const fs = await import('node:fs')
564
+ const path = await import('node:path')
565
+ const componentsRoot = path.resolve('src/components')
566
+
567
+ let directory = flags.directory || ''
568
+ if (!directory) {
569
+ const existingDirs = []
570
+ if (fs.existsSync(componentsRoot)) {
571
+ for (const entry of fs.readdirSync(componentsRoot, { withFileTypes: true })) {
572
+ if (entry.isDirectory() && !entry.name.startsWith('_') && !entry.name.startsWith('.')) {
573
+ existingDirs.push(entry.name)
574
+ }
575
+ }
576
+ }
577
+
578
+ if (existingDirs.length > 0) {
579
+ const dirChoice = await promptOrCancel(
580
+ p.select({
581
+ message: 'Directory',
582
+ options: [
583
+ { value: '', label: 'src/components/ (root)', hint: 'Top-level component' },
584
+ ...existingDirs.map((d) => ({ value: d, label: `src/components/${d}/` })),
585
+ ],
586
+ }),
587
+ )
588
+ directory = dirChoice
589
+ }
590
+ }
591
+
592
+ // Build file path
593
+ const targetDir = directory
594
+ ? path.join(componentsRoot, directory)
595
+ : componentsRoot
596
+ const storyFile = path.join(targetDir, `${componentName}.story.jsx`)
597
+
598
+ if (fs.existsSync(storyFile)) {
599
+ p.log.error(`File already exists: ${path.relative('.', storyFile)}`)
600
+ p.outro('')
601
+ return
602
+ }
603
+
604
+ // Scaffold the story file
605
+ const pascalName = componentName
606
+ .split('-')
607
+ .map((s) => s.charAt(0).toUpperCase() + s.slice(1))
608
+ .join('')
609
+
610
+ const content = `/**
611
+ * ${pascalName} component stories.
612
+ * Each named export renders as an embeddable component at /components/${directory ? directory + '/' : ''}${componentName}
613
+ */
614
+
615
+ export function Default() {
616
+ return (
617
+ <div style={{ padding: '1.5rem', minWidth: 280 }}>
618
+ <p>${pascalName} component</p>
619
+ </div>
620
+ )
621
+ }
622
+ `
623
+
624
+ const s = p.spinner()
625
+ s.start('Creating component...')
626
+
627
+ fs.mkdirSync(targetDir, { recursive: true })
628
+ fs.writeFileSync(storyFile, content)
629
+
630
+ s.stop('Component created!')
631
+ p.log.success(` ${green(path.relative('.', storyFile))}`)
632
+ p.log.info(` ${dim('Route:')} /components/${directory ? directory + '/' : ''}${componentName}`)
633
+ p.outro('')
634
+ }
635
+
636
+ // ── Dispatcher ────────────────────────────────────────────────
637
+
638
+ export { createFlow, createPage, createComponent, ensureDevServer, serverPost, postCreateFlow, getServerUrl }
639
+
640
+ async function main() {
641
+ const subcommand = process.argv[3]
642
+
643
+ if (subcommand === 'prototype') return createPrototype()
644
+ if (subcommand === 'canvas') return createCanvas()
645
+ if (subcommand === 'flow') return createFlow()
646
+ if (subcommand === 'page') return createPage()
647
+ if (subcommand === 'component') return createComponent()
648
+
649
+ // Interactive picker
650
+ p.intro('storyboard create')
651
+
652
+ const type = await p.select({
653
+ message: 'What would you like to create?',
654
+ options: [
655
+ { value: 'prototype', label: 'Prototype', hint: 'React-based interactive prototype' },
656
+ { value: 'canvas', label: 'Canvas', hint: 'Freeform canvas with widgets' },
657
+ { value: 'flow', label: 'Flow', hint: 'Data context for a prototype page' },
658
+ { value: 'page', label: 'Page', hint: 'New page in a prototype' },
659
+ { value: 'component', label: 'Component', hint: 'Story-format component (.story.jsx)' },
660
+ ],
661
+ })
662
+
663
+ if (p.isCancel(type)) return process.exit(0)
664
+
665
+ if (type === 'prototype') return createPrototype()
666
+ if (type === 'canvas') return createCanvas()
667
+ if (type === 'flow') return createFlow()
668
+ if (type === 'page') return createPage()
669
+ if (type === 'component') return createComponent()
670
+ }
671
+
672
+ // Only run main() when this file is the entry point, not when imported
673
+ const isDirectEntry = process.argv[2] === 'create'
674
+ if (isDirectEntry) main()