orbital-command 0.2.0 → 1.0.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 (431) hide show
  1. package/README.md +67 -42
  2. package/bin/commands/config.js +19 -0
  3. package/bin/commands/events.js +40 -0
  4. package/bin/commands/launch.js +126 -0
  5. package/bin/commands/manifest.js +283 -0
  6. package/bin/commands/registry.js +104 -0
  7. package/bin/commands/update.js +24 -0
  8. package/bin/lib/helpers.js +229 -0
  9. package/bin/orbital.js +147 -319
  10. package/dist/assets/Landing-CfQdHR0N.js +11 -0
  11. package/dist/assets/PrimitivesConfig-DThSipFy.js +32 -0
  12. package/dist/assets/QualityGates-B4kxM5UU.js +26 -0
  13. package/dist/assets/SessionTimeline-Bz1iZnmg.js +1 -0
  14. package/dist/assets/Settings-DLcZwbCT.js +12 -0
  15. package/dist/assets/SourceControl-BMNIz7Lt.js +36 -0
  16. package/dist/assets/WorkflowVisualizer-CxuSBOYu.js +69 -0
  17. package/dist/assets/arrow-down-DVPp6_qp.js +6 -0
  18. package/dist/assets/bot-NFaJBDn_.js +6 -0
  19. package/dist/assets/charts-LGLb8hyU.js +68 -0
  20. package/dist/assets/circle-x-IsFCkBZu.js +6 -0
  21. package/dist/assets/file-text-J1cebZXF.js +6 -0
  22. package/dist/assets/globe-WzeyHsUc.js +6 -0
  23. package/dist/assets/index-BdJ57EhC.css +1 -0
  24. package/dist/assets/index-o4ScMAuR.js +349 -0
  25. package/dist/assets/key-CKR8JJSj.js +6 -0
  26. package/dist/assets/minus-CHBsJyjp.js +6 -0
  27. package/dist/assets/radio-xqZaR-Uk.js +6 -0
  28. package/dist/assets/rocket-D_xvvNG6.js +6 -0
  29. package/dist/assets/shield-TdB1yv_a.js +6 -0
  30. package/dist/assets/ui-BmsSg9jU.js +53 -0
  31. package/dist/assets/useSocketListener-0L5yiN5i.js +1 -0
  32. package/dist/assets/useWorkflowEditor-CqeRWVQX.js +11 -0
  33. package/dist/assets/{vendor-Dzv9lrRc.js → vendor-Bqt8AJn2.js} +1 -1
  34. package/dist/assets/workflow-constants-Rw-GmgHZ.js +6 -0
  35. package/dist/assets/zap-C9wqYMpl.js +6 -0
  36. package/dist/favicon.svg +1 -0
  37. package/dist/index.html +6 -5
  38. package/dist/server/server/__tests__/data-routes.test.js +126 -0
  39. package/dist/server/server/__tests__/helpers/db.js +17 -0
  40. package/dist/server/server/__tests__/helpers/mock-emitter.js +8 -0
  41. package/dist/server/server/__tests__/scope-routes.test.js +138 -0
  42. package/dist/server/server/__tests__/sprint-routes.test.js +102 -0
  43. package/dist/server/server/__tests__/workflow-routes.test.js +107 -0
  44. package/dist/server/server/config-migrator.js +135 -0
  45. package/dist/server/server/config.js +51 -7
  46. package/dist/server/server/database.js +21 -28
  47. package/dist/server/server/global-config.js +143 -0
  48. package/dist/server/server/index.js +118 -276
  49. package/dist/server/server/init.js +243 -225
  50. package/dist/server/server/launch.js +29 -0
  51. package/dist/server/server/manifest-types.js +8 -0
  52. package/dist/server/server/manifest.js +454 -0
  53. package/dist/server/server/migrate-legacy.js +229 -0
  54. package/dist/server/server/parsers/event-parser.js +4 -1
  55. package/dist/server/server/parsers/event-parser.test.js +117 -0
  56. package/dist/server/server/parsers/scope-parser.js +74 -28
  57. package/dist/server/server/parsers/scope-parser.test.js +230 -0
  58. package/dist/server/server/project-context.js +265 -0
  59. package/dist/server/server/project-emitter.js +41 -0
  60. package/dist/server/server/project-manager.js +297 -0
  61. package/dist/server/server/routes/aggregate-routes.js +871 -0
  62. package/dist/server/server/routes/config-routes.js +41 -90
  63. package/dist/server/server/routes/data-routes.js +25 -123
  64. package/dist/server/server/routes/dispatch-routes.js +37 -15
  65. package/dist/server/server/routes/git-routes.js +74 -0
  66. package/dist/server/server/routes/manifest-routes.js +319 -0
  67. package/dist/server/server/routes/scope-routes.js +45 -28
  68. package/dist/server/server/routes/sync-routes.js +134 -0
  69. package/dist/server/server/routes/version-routes.js +1 -15
  70. package/dist/server/server/routes/workflow-routes.js +9 -3
  71. package/dist/server/server/schema.js +3 -0
  72. package/dist/server/server/services/batch-orchestrator.js +41 -17
  73. package/dist/server/server/services/claude-session-service.js +17 -14
  74. package/dist/server/server/services/config-service.js +10 -1
  75. package/dist/server/server/services/deploy-service.test.js +119 -0
  76. package/dist/server/server/services/event-service.js +64 -1
  77. package/dist/server/server/services/event-service.test.js +191 -0
  78. package/dist/server/server/services/gate-service.test.js +105 -0
  79. package/dist/server/server/services/git-service.js +108 -4
  80. package/dist/server/server/services/github-service.js +110 -2
  81. package/dist/server/server/services/readiness-service.test.js +190 -0
  82. package/dist/server/server/services/scope-cache.js +5 -1
  83. package/dist/server/server/services/scope-cache.test.js +142 -0
  84. package/dist/server/server/services/scope-service.js +222 -131
  85. package/dist/server/server/services/scope-service.test.js +137 -0
  86. package/dist/server/server/services/sprint-orchestrator.js +29 -15
  87. package/dist/server/server/services/sprint-service.js +23 -3
  88. package/dist/server/server/services/sprint-service.test.js +238 -0
  89. package/dist/server/server/services/sync-service.js +434 -0
  90. package/dist/server/server/services/sync-types.js +2 -0
  91. package/dist/server/server/services/workflow-service.js +26 -5
  92. package/dist/server/server/services/workflow-service.test.js +159 -0
  93. package/dist/server/server/settings-sync.js +284 -0
  94. package/dist/server/server/uninstall.js +195 -0
  95. package/dist/server/server/update-planner.js +279 -0
  96. package/dist/server/server/update.js +212 -0
  97. package/dist/server/server/utils/cc-hooks-parser.js +3 -0
  98. package/dist/server/server/utils/cc-hooks-parser.test.js +86 -0
  99. package/dist/server/server/utils/dispatch-utils.js +83 -24
  100. package/dist/server/server/utils/dispatch-utils.test.js +182 -0
  101. package/dist/server/server/utils/flag-builder.js +54 -0
  102. package/dist/server/server/utils/json-fields.js +14 -0
  103. package/dist/server/server/utils/json-fields.test.js +73 -0
  104. package/dist/server/server/utils/logger.js +37 -3
  105. package/dist/server/server/utils/package-info.js +30 -0
  106. package/dist/server/server/utils/route-helpers.js +47 -0
  107. package/dist/server/server/utils/route-helpers.test.js +115 -0
  108. package/dist/server/server/utils/terminal-launcher.js +79 -25
  109. package/dist/server/server/utils/worktree-manager.js +13 -4
  110. package/dist/server/server/validator.js +230 -0
  111. package/dist/server/server/watchers/event-watcher.js +28 -13
  112. package/dist/server/server/watchers/global-watcher.js +63 -0
  113. package/dist/server/server/watchers/scope-watcher.js +27 -12
  114. package/dist/server/server/wizard/config-editor.js +237 -0
  115. package/dist/server/server/wizard/detect.js +96 -0
  116. package/dist/server/server/wizard/doctor.js +115 -0
  117. package/dist/server/server/wizard/index.js +340 -0
  118. package/dist/server/server/wizard/phases/confirm.js +39 -0
  119. package/dist/server/server/wizard/phases/project-setup.js +90 -0
  120. package/dist/server/server/wizard/phases/setup-wizard.js +66 -0
  121. package/dist/server/server/wizard/phases/welcome.js +32 -0
  122. package/dist/server/server/wizard/phases/workflow-setup.js +22 -0
  123. package/dist/server/server/wizard/types.js +29 -0
  124. package/dist/server/server/wizard/ui.js +73 -0
  125. package/dist/server/shared/__fixtures__/workflow-configs.js +75 -0
  126. package/dist/server/shared/api-types.js +80 -1
  127. package/dist/server/shared/default-workflow.json +65 -0
  128. package/dist/server/shared/onboarding-tour.test.js +81 -0
  129. package/dist/server/shared/project-colors.js +24 -0
  130. package/dist/server/shared/workflow-config.test.js +84 -0
  131. package/dist/server/shared/workflow-engine.js +1 -1
  132. package/dist/server/shared/workflow-engine.test.js +302 -0
  133. package/dist/server/shared/workflow-normalizer.js +101 -0
  134. package/dist/server/shared/workflow-normalizer.test.js +100 -0
  135. package/dist/server/src/components/onboarding/tour-steps.js +84 -0
  136. package/package.json +34 -29
  137. package/schemas/orbital.config.schema.json +2 -5
  138. package/scripts/postinstall.js +18 -6
  139. package/scripts/release.sh +53 -0
  140. package/server/__tests__/data-routes.test.ts +151 -0
  141. package/server/__tests__/helpers/db.ts +19 -0
  142. package/server/__tests__/helpers/mock-emitter.ts +10 -0
  143. package/server/__tests__/scope-routes.test.ts +158 -0
  144. package/server/__tests__/sprint-routes.test.ts +118 -0
  145. package/server/__tests__/workflow-routes.test.ts +120 -0
  146. package/server/config-migrator.ts +160 -0
  147. package/server/config.ts +64 -12
  148. package/server/database.ts +22 -31
  149. package/server/global-config.ts +204 -0
  150. package/server/index.ts +139 -316
  151. package/server/init.ts +266 -234
  152. package/server/launch.ts +32 -0
  153. package/server/manifest-types.ts +145 -0
  154. package/server/manifest.ts +494 -0
  155. package/server/migrate-legacy.ts +290 -0
  156. package/server/parsers/event-parser.test.ts +135 -0
  157. package/server/parsers/event-parser.ts +4 -1
  158. package/server/parsers/scope-parser.test.ts +270 -0
  159. package/server/parsers/scope-parser.ts +79 -31
  160. package/server/project-context.ts +325 -0
  161. package/server/project-emitter.ts +50 -0
  162. package/server/project-manager.ts +368 -0
  163. package/server/routes/aggregate-routes.ts +968 -0
  164. package/server/routes/config-routes.ts +43 -85
  165. package/server/routes/data-routes.ts +34 -156
  166. package/server/routes/dispatch-routes.ts +46 -17
  167. package/server/routes/git-routes.ts +77 -0
  168. package/server/routes/manifest-routes.ts +388 -0
  169. package/server/routes/scope-routes.ts +39 -30
  170. package/server/routes/sync-routes.ts +175 -0
  171. package/server/routes/version-routes.ts +1 -16
  172. package/server/routes/workflow-routes.ts +9 -3
  173. package/server/schema.ts +3 -0
  174. package/server/services/batch-orchestrator.ts +41 -17
  175. package/server/services/claude-session-service.ts +16 -14
  176. package/server/services/config-service.ts +10 -1
  177. package/server/services/deploy-service.test.ts +145 -0
  178. package/server/services/deploy-service.ts +2 -2
  179. package/server/services/event-service.test.ts +242 -0
  180. package/server/services/event-service.ts +92 -3
  181. package/server/services/gate-service.test.ts +131 -0
  182. package/server/services/gate-service.ts +2 -2
  183. package/server/services/git-service.ts +137 -4
  184. package/server/services/github-service.ts +120 -2
  185. package/server/services/readiness-service.test.ts +217 -0
  186. package/server/services/scope-cache.test.ts +167 -0
  187. package/server/services/scope-cache.ts +4 -1
  188. package/server/services/scope-service.test.ts +169 -0
  189. package/server/services/scope-service.ts +224 -130
  190. package/server/services/sprint-orchestrator.ts +30 -15
  191. package/server/services/sprint-service.test.ts +271 -0
  192. package/server/services/sprint-service.ts +29 -5
  193. package/server/services/sync-service.ts +482 -0
  194. package/server/services/sync-types.ts +77 -0
  195. package/server/services/workflow-service.test.ts +190 -0
  196. package/server/services/workflow-service.ts +29 -9
  197. package/server/settings-sync.ts +359 -0
  198. package/server/uninstall.ts +214 -0
  199. package/server/update-planner.ts +346 -0
  200. package/server/update.ts +263 -0
  201. package/server/utils/cc-hooks-parser.test.ts +96 -0
  202. package/server/utils/cc-hooks-parser.ts +4 -0
  203. package/server/utils/dispatch-utils.test.ts +245 -0
  204. package/server/utils/dispatch-utils.ts +102 -30
  205. package/server/utils/flag-builder.ts +56 -0
  206. package/server/utils/json-fields.test.ts +83 -0
  207. package/server/utils/json-fields.ts +14 -0
  208. package/server/utils/logger.ts +40 -3
  209. package/server/utils/package-info.ts +32 -0
  210. package/server/utils/route-helpers.test.ts +144 -0
  211. package/server/utils/route-helpers.ts +50 -0
  212. package/server/utils/terminal-launcher.ts +85 -25
  213. package/server/utils/worktree-manager.ts +9 -4
  214. package/server/validator.ts +270 -0
  215. package/server/watchers/event-watcher.ts +24 -12
  216. package/server/watchers/global-watcher.ts +77 -0
  217. package/server/watchers/scope-watcher.ts +21 -9
  218. package/server/wizard/config-editor.ts +248 -0
  219. package/server/wizard/detect.ts +104 -0
  220. package/server/wizard/doctor.ts +114 -0
  221. package/server/wizard/index.ts +438 -0
  222. package/server/wizard/phases/confirm.ts +45 -0
  223. package/server/wizard/phases/project-setup.ts +106 -0
  224. package/server/wizard/phases/setup-wizard.ts +78 -0
  225. package/server/wizard/phases/welcome.ts +39 -0
  226. package/server/wizard/phases/workflow-setup.ts +28 -0
  227. package/server/wizard/types.ts +56 -0
  228. package/server/wizard/ui.ts +92 -0
  229. package/shared/__fixtures__/workflow-configs.ts +80 -0
  230. package/shared/api-types.ts +106 -0
  231. package/shared/onboarding-tour.test.ts +94 -0
  232. package/shared/project-colors.ts +24 -0
  233. package/shared/workflow-config.test.ts +111 -0
  234. package/shared/workflow-config.ts +7 -0
  235. package/shared/workflow-engine.test.ts +388 -0
  236. package/shared/workflow-engine.ts +1 -1
  237. package/shared/workflow-normalizer.test.ts +119 -0
  238. package/shared/workflow-normalizer.ts +118 -0
  239. package/templates/agents/QUICK-REFERENCE.md +1 -0
  240. package/templates/agents/README.md +1 -0
  241. package/templates/agents/SKILL-TRIGGERS.md +11 -0
  242. package/templates/agents/green-team/deep-dive.md +361 -0
  243. package/templates/hooks/end-session.sh +4 -1
  244. package/templates/hooks/init-session.sh +1 -0
  245. package/templates/hooks/orbital-emit.sh +2 -2
  246. package/templates/hooks/orbital-report-deploy.sh +4 -4
  247. package/templates/hooks/orbital-report-gates.sh +4 -4
  248. package/templates/hooks/orbital-scope-update.sh +1 -1
  249. package/templates/hooks/scope-commit-logger.sh +2 -2
  250. package/templates/hooks/scope-create-cleanup.sh +2 -2
  251. package/templates/hooks/scope-create-gate.sh +2 -5
  252. package/templates/hooks/scope-gate.sh +4 -6
  253. package/templates/hooks/scope-helpers.sh +28 -1
  254. package/templates/hooks/scope-lifecycle-gate.sh +14 -5
  255. package/templates/hooks/scope-prepare.sh +67 -12
  256. package/templates/hooks/scope-transition.sh +14 -6
  257. package/templates/hooks/time-tracker.sh +2 -5
  258. package/templates/migrations/renames.json +1 -0
  259. package/templates/orbital.config.json +8 -6
  260. package/{shared/default-workflow.json → templates/presets/default.json} +65 -0
  261. package/templates/presets/development.json +4 -4
  262. package/templates/presets/gitflow.json +7 -0
  263. package/templates/prompts/README.md +23 -0
  264. package/templates/prompts/deep-dive-audit.md +94 -0
  265. package/templates/quick/rules.md +56 -5
  266. package/templates/settings-hooks.json +1 -1
  267. package/templates/skills/git-commit/SKILL.md +27 -7
  268. package/templates/skills/git-dev/SKILL.md +13 -4
  269. package/templates/skills/git-main/SKILL.md +13 -3
  270. package/templates/skills/git-production/SKILL.md +9 -2
  271. package/templates/skills/git-staging/SKILL.md +11 -3
  272. package/templates/skills/scope-create/SKILL.md +17 -3
  273. package/templates/skills/scope-fix-review/SKILL.md +14 -7
  274. package/templates/skills/scope-implement/SKILL.md +15 -4
  275. package/templates/skills/scope-post-review/SKILL.md +77 -7
  276. package/templates/skills/scope-pre-review/SKILL.md +11 -4
  277. package/templates/skills/scope-verify/SKILL.md +5 -3
  278. package/templates/skills/test-code-review/SKILL.md +41 -33
  279. package/templates/skills/test-scaffold/SKILL.md +222 -0
  280. package/dist/assets/WorkflowVisualizer-BZ21PIIF.js +0 -84
  281. package/dist/assets/charts-D__PA1zp.js +0 -72
  282. package/dist/assets/index-D1G6i0nS.css +0 -1
  283. package/dist/assets/index-DpItvKpf.js +0 -419
  284. package/dist/assets/ui-BvF022GT.js +0 -53
  285. package/index.html +0 -15
  286. package/postcss.config.js +0 -6
  287. package/src/App.tsx +0 -33
  288. package/src/components/AgentBadge.tsx +0 -40
  289. package/src/components/BatchPreflightModal.tsx +0 -115
  290. package/src/components/CardDisplayToggle.tsx +0 -74
  291. package/src/components/ColumnHeaderActions.tsx +0 -55
  292. package/src/components/ColumnMenu.tsx +0 -99
  293. package/src/components/DeployHistory.tsx +0 -141
  294. package/src/components/DispatchModal.tsx +0 -164
  295. package/src/components/DispatchPopover.tsx +0 -139
  296. package/src/components/DragOverlay.tsx +0 -25
  297. package/src/components/DriftSidebar.tsx +0 -140
  298. package/src/components/EnvironmentStrip.tsx +0 -88
  299. package/src/components/ErrorBoundary.tsx +0 -62
  300. package/src/components/FilterChip.tsx +0 -105
  301. package/src/components/GateIndicator.tsx +0 -33
  302. package/src/components/IdeaDetailModal.tsx +0 -190
  303. package/src/components/IdeaFormDialog.tsx +0 -113
  304. package/src/components/KanbanColumn.tsx +0 -201
  305. package/src/components/MarkdownRenderer.tsx +0 -114
  306. package/src/components/NeonGrid.tsx +0 -128
  307. package/src/components/PromotionQueue.tsx +0 -89
  308. package/src/components/ScopeCard.tsx +0 -234
  309. package/src/components/ScopeDetailModal.tsx +0 -255
  310. package/src/components/ScopeFilterBar.tsx +0 -152
  311. package/src/components/SearchInput.tsx +0 -102
  312. package/src/components/SessionPanel.tsx +0 -335
  313. package/src/components/SprintContainer.tsx +0 -303
  314. package/src/components/SprintDependencyDialog.tsx +0 -78
  315. package/src/components/SprintPreflightModal.tsx +0 -138
  316. package/src/components/StatusBar.tsx +0 -168
  317. package/src/components/SwimCell.tsx +0 -67
  318. package/src/components/SwimLaneRow.tsx +0 -94
  319. package/src/components/SwimlaneBoardView.tsx +0 -108
  320. package/src/components/VersionBadge.tsx +0 -139
  321. package/src/components/ViewModeSelector.tsx +0 -114
  322. package/src/components/config/AgentChip.tsx +0 -53
  323. package/src/components/config/AgentCreateDialog.tsx +0 -321
  324. package/src/components/config/AgentEditor.tsx +0 -175
  325. package/src/components/config/DirectoryTree.tsx +0 -582
  326. package/src/components/config/FileEditor.tsx +0 -550
  327. package/src/components/config/HookChip.tsx +0 -50
  328. package/src/components/config/StageCard.tsx +0 -198
  329. package/src/components/config/TransitionZone.tsx +0 -173
  330. package/src/components/config/UnifiedWorkflowPipeline.tsx +0 -216
  331. package/src/components/config/WorkflowPipeline.tsx +0 -161
  332. package/src/components/source-control/BranchList.tsx +0 -93
  333. package/src/components/source-control/BranchPanel.tsx +0 -105
  334. package/src/components/source-control/CommitLog.tsx +0 -100
  335. package/src/components/source-control/CommitRow.tsx +0 -47
  336. package/src/components/source-control/GitHubPanel.tsx +0 -110
  337. package/src/components/source-control/GitHubSetupGuide.tsx +0 -52
  338. package/src/components/source-control/GitOverviewBar.tsx +0 -101
  339. package/src/components/source-control/PullRequestList.tsx +0 -69
  340. package/src/components/source-control/WorktreeList.tsx +0 -80
  341. package/src/components/ui/badge.tsx +0 -41
  342. package/src/components/ui/button.tsx +0 -55
  343. package/src/components/ui/card.tsx +0 -78
  344. package/src/components/ui/dialog.tsx +0 -94
  345. package/src/components/ui/popover.tsx +0 -33
  346. package/src/components/ui/scroll-area.tsx +0 -54
  347. package/src/components/ui/separator.tsx +0 -28
  348. package/src/components/ui/tabs.tsx +0 -52
  349. package/src/components/ui/toggle-switch.tsx +0 -35
  350. package/src/components/ui/tooltip.tsx +0 -27
  351. package/src/components/workflow/AddEdgeDialog.tsx +0 -217
  352. package/src/components/workflow/AddListDialog.tsx +0 -201
  353. package/src/components/workflow/ChecklistEditor.tsx +0 -239
  354. package/src/components/workflow/CommandPrefixManager.tsx +0 -118
  355. package/src/components/workflow/ConfigSettingsPanel.tsx +0 -189
  356. package/src/components/workflow/DirectionSelector.tsx +0 -133
  357. package/src/components/workflow/DispatchConfigPanel.tsx +0 -180
  358. package/src/components/workflow/EdgeDetailPanel.tsx +0 -236
  359. package/src/components/workflow/EdgePropertyEditor.tsx +0 -251
  360. package/src/components/workflow/EditToolbar.tsx +0 -138
  361. package/src/components/workflow/HookDetailPanel.tsx +0 -250
  362. package/src/components/workflow/HookExecutionLog.tsx +0 -24
  363. package/src/components/workflow/HookSourceModal.tsx +0 -129
  364. package/src/components/workflow/HooksDashboard.tsx +0 -363
  365. package/src/components/workflow/ListPropertyEditor.tsx +0 -251
  366. package/src/components/workflow/MigrationPreviewDialog.tsx +0 -237
  367. package/src/components/workflow/MovementRulesPanel.tsx +0 -188
  368. package/src/components/workflow/NodeDetailPanel.tsx +0 -245
  369. package/src/components/workflow/PresetSelector.tsx +0 -414
  370. package/src/components/workflow/SkillCommandBuilder.tsx +0 -174
  371. package/src/components/workflow/WorkflowEdgeComponent.tsx +0 -145
  372. package/src/components/workflow/WorkflowNode.tsx +0 -147
  373. package/src/components/workflow/graphLayout.ts +0 -186
  374. package/src/components/workflow/mergeHooks.ts +0 -85
  375. package/src/components/workflow/useEditHistory.ts +0 -88
  376. package/src/components/workflow/useWorkflowEditor.ts +0 -262
  377. package/src/components/workflow/validateConfig.ts +0 -70
  378. package/src/hooks/useActiveDispatches.ts +0 -198
  379. package/src/hooks/useBoardSettings.ts +0 -170
  380. package/src/hooks/useCardDisplay.ts +0 -57
  381. package/src/hooks/useCcHooks.ts +0 -24
  382. package/src/hooks/useConfigTree.ts +0 -51
  383. package/src/hooks/useEnforcementRules.ts +0 -46
  384. package/src/hooks/useEvents.ts +0 -59
  385. package/src/hooks/useFileEditor.ts +0 -165
  386. package/src/hooks/useGates.ts +0 -57
  387. package/src/hooks/useIdeaActions.ts +0 -53
  388. package/src/hooks/useKanbanDnd.ts +0 -410
  389. package/src/hooks/useOrbitalConfig.ts +0 -54
  390. package/src/hooks/usePipeline.ts +0 -47
  391. package/src/hooks/usePipelineData.ts +0 -338
  392. package/src/hooks/useReconnect.ts +0 -25
  393. package/src/hooks/useScopeFilters.ts +0 -125
  394. package/src/hooks/useScopeSessions.ts +0 -44
  395. package/src/hooks/useScopes.ts +0 -67
  396. package/src/hooks/useSearch.ts +0 -67
  397. package/src/hooks/useSettings.tsx +0 -187
  398. package/src/hooks/useSocket.ts +0 -25
  399. package/src/hooks/useSourceControl.ts +0 -105
  400. package/src/hooks/useSprintPreflight.ts +0 -55
  401. package/src/hooks/useSprints.ts +0 -154
  402. package/src/hooks/useStatusBarHighlight.ts +0 -18
  403. package/src/hooks/useSwimlaneBoardSettings.ts +0 -104
  404. package/src/hooks/useTheme.ts +0 -9
  405. package/src/hooks/useTransitionReadiness.ts +0 -53
  406. package/src/hooks/useVersion.ts +0 -155
  407. package/src/hooks/useViolations.ts +0 -65
  408. package/src/hooks/useWorkflow.tsx +0 -125
  409. package/src/hooks/useZoomModifier.ts +0 -19
  410. package/src/index.css +0 -797
  411. package/src/layouts/DashboardLayout.tsx +0 -113
  412. package/src/lib/collisionDetection.ts +0 -20
  413. package/src/lib/scope-fields.ts +0 -61
  414. package/src/lib/swimlane.ts +0 -146
  415. package/src/lib/utils.ts +0 -15
  416. package/src/main.tsx +0 -19
  417. package/src/socket.ts +0 -11
  418. package/src/types/index.ts +0 -497
  419. package/src/views/AgentFeed.tsx +0 -339
  420. package/src/views/DeployPipeline.tsx +0 -59
  421. package/src/views/EnforcementView.tsx +0 -378
  422. package/src/views/PrimitivesConfig.tsx +0 -500
  423. package/src/views/QualityGates.tsx +0 -1012
  424. package/src/views/ScopeBoard.tsx +0 -454
  425. package/src/views/SessionTimeline.tsx +0 -516
  426. package/src/views/Settings.tsx +0 -183
  427. package/src/views/SourceControl.tsx +0 -95
  428. package/src/views/WorkflowVisualizer.tsx +0 -382
  429. package/tailwind.config.js +0 -161
  430. package/tsconfig.json +0 -25
  431. package/vite.config.ts +0 -38
@@ -0,0 +1,438 @@
1
+ /**
2
+ * Interactive CLI wizard — main orchestrator.
3
+ *
4
+ * Entry points:
5
+ * runSetupWizard() — Phase 1: first-time Orbital setup (~/.orbital/)
6
+ * runProjectSetup() — Phase 2: per-project scaffolding (.claude/)
7
+ * runConfigEditor() — interactive config editor (orbital config)
8
+ * runDoctor() — health diagnostics (orbital doctor)
9
+ */
10
+
11
+ import fs from 'fs';
12
+ import path from 'path';
13
+ import { spawn, execFileSync } from 'child_process';
14
+ import * as p from '@clack/prompts';
15
+ import pc from 'picocolors';
16
+ import { buildSetupState, buildProjectState } from './detect.js';
17
+ import { phaseSetupWizard } from './phases/setup-wizard.js';
18
+ import { phaseWelcome } from './phases/welcome.js';
19
+ import { phaseProjectSetup } from './phases/project-setup.js';
20
+ import { phaseWorkflowSetup } from './phases/workflow-setup.js';
21
+ import { phaseConfirm, showPostInstall } from './phases/confirm.js';
22
+ import { NOTES } from './ui.js';
23
+ import { runConfigEditor } from './config-editor.js';
24
+ import { runDoctor } from './doctor.js';
25
+ import { isITerm2Available } from '../adapters/iterm2-adapter.js';
26
+ import { registerProject } from '../global-config.js';
27
+
28
+ export { runConfigEditor, runDoctor };
29
+
30
+ // ─── Phase 1: Setup Wizard ─────────────────────────────────────
31
+
32
+ /**
33
+ * First-time setup. Creates ~/.orbital/, seeds primitives,
34
+ * optionally links projects (running Phase 2 for each).
35
+ */
36
+ export async function runSetupWizard(packageVersion: string): Promise<void> {
37
+ const state = buildSetupState(packageVersion);
38
+
39
+ p.intro(`${pc.bgCyan(pc.black(' Orbital Command '))} ${pc.dim(`v${packageVersion}`)}`);
40
+
41
+ await phaseSetupWizard(state);
42
+
43
+ // If user linked projects, run Phase 2 for each
44
+ for (const projectRoot of state.linkedProjects) {
45
+ p.log.step(`Setting up ${pc.cyan(path.basename(projectRoot))}...`);
46
+ await runProjectSetupInline(projectRoot, packageVersion);
47
+ }
48
+
49
+ if (state.linkedProjects.length === 0) {
50
+ p.note(NOTES.setupComplete, 'Done');
51
+ }
52
+
53
+ p.outro(
54
+ state.linkedProjects.length > 0
55
+ ? `Run ${pc.cyan('orbital')} to launch the dashboard.`
56
+ : `Run ${pc.cyan('orbital')} in a project directory to get started.`
57
+ );
58
+ }
59
+
60
+ // ─── Phase 2: Project Setup ────────────────────────────────────
61
+
62
+ /**
63
+ * Per-project setup. Walks through name, commands, workflow, then
64
+ * calls runInit() to scaffold files into .claude/.
65
+ */
66
+ export async function runProjectSetup(projectRoot: string, packageVersion: string, args: string[]): Promise<void> {
67
+ const state = buildProjectState(projectRoot, packageVersion);
68
+ const force = args.includes('--force');
69
+
70
+ p.intro(`${pc.bgCyan(pc.black(' Orbital Command '))} ${pc.dim(`v${packageVersion}`)}`);
71
+
72
+ // Welcome gate: detect re-init / reconfigure
73
+ const forceFromWelcome = await phaseWelcome(state);
74
+ const useForce = force || forceFromWelcome;
75
+
76
+ await runProjectPhases(state, useForce);
77
+
78
+ p.outro(`Run ${pc.cyan('orbital')} to launch the dashboard.`);
79
+ }
80
+
81
+ // ─── Shared project phases (used by both flows) ────────────────
82
+
83
+ /**
84
+ * Run the project setup phases and install. Used by both
85
+ * standalone runProjectSetup() and inline from runSetupWizard().
86
+ */
87
+ async function runProjectPhases(state: ReturnType<typeof buildProjectState>, useForce: boolean): Promise<void> {
88
+ await phaseProjectSetup(state);
89
+ await phaseWorkflowSetup(state);
90
+ await phaseConfirm(state);
91
+
92
+ // Install
93
+ const s = p.spinner();
94
+ s.start('Installing into project...');
95
+
96
+ try {
97
+ const { runInit } = await import('../init.js');
98
+
99
+ runInit(state.projectRoot, {
100
+ force: useForce,
101
+ quiet: true,
102
+ preset: state.workflowPreset,
103
+ projectName: state.projectName,
104
+ serverPort: state.serverPort,
105
+ clientPort: state.clientPort,
106
+ commands: state.selectedCommands,
107
+ });
108
+
109
+ registerProject(state.projectRoot, { name: state.projectName });
110
+ stampTemplateVersion(state.projectRoot, state.packageVersion);
111
+
112
+ s.stop('Project ready.');
113
+ } catch (err) {
114
+ s.stop('Installation failed.');
115
+ p.log.error(err instanceof Error ? err.message : String(err));
116
+ process.exit(1);
117
+ }
118
+
119
+ showPostInstall(state);
120
+ }
121
+
122
+ /**
123
+ * Inline project setup — called from Phase 1 when user links a project.
124
+ * Skips intro/outro since the setup wizard already has those.
125
+ */
126
+ async function runProjectSetupInline(projectRoot: string, packageVersion: string): Promise<void> {
127
+ const state = buildProjectState(projectRoot, packageVersion);
128
+
129
+ // Skip welcome gate for inline — this is a fresh project being linked
130
+ await runProjectPhases(state, false);
131
+ }
132
+
133
+ // ─── Update Check ─────────────────────────────────────────────
134
+
135
+ interface UpdateInfo {
136
+ current: string;
137
+ latest: string;
138
+ isOutdated: boolean;
139
+ }
140
+
141
+ async function checkForUpdate(
142
+ currentVersion: string,
143
+ cache: { lastUpdateCheck?: string; latestVersion?: string },
144
+ ): Promise<{ info: UpdateInfo | null; cacheChanged: boolean }> {
145
+ // Use cache if checked within 24 hours
146
+ if (cache.lastUpdateCheck && cache.latestVersion) {
147
+ const age = Date.now() - new Date(cache.lastUpdateCheck).getTime();
148
+ if (age < 24 * 60 * 60 * 1000) {
149
+ const isOutdated = cache.latestVersion !== currentVersion;
150
+ return {
151
+ info: { current: currentVersion, latest: cache.latestVersion, isOutdated },
152
+ cacheChanged: false,
153
+ };
154
+ }
155
+ }
156
+
157
+ // Fetch from npm registry
158
+ try {
159
+ const res = await fetch('https://registry.npmjs.org/orbital-command/latest', {
160
+ signal: AbortSignal.timeout(3000),
161
+ });
162
+ const data = await res.json() as { version: string };
163
+ const latest = data.version;
164
+ return {
165
+ info: { current: currentVersion, latest, isOutdated: latest !== currentVersion },
166
+ cacheChanged: true,
167
+ };
168
+ } catch {
169
+ return { info: null, cacheChanged: false };
170
+ }
171
+ }
172
+
173
+ // ─── Hub Menu ─────────────────────────────────────────────────
174
+
175
+ export type HubAction = 'launch' | 'init' | 'config' | 'doctor' | 'update' | 'status' | 'reset';
176
+
177
+ export interface HubResult {
178
+ action: HubAction;
179
+ setItermPromptShown?: boolean;
180
+ updateCache?: { lastUpdateCheck: string; latestVersion?: string };
181
+ }
182
+
183
+ /**
184
+ * Context-aware hub menu — the main entry point for `orbital` (no args).
185
+ * Checks for updates, offers template sync, shows iTerm2 recommendation, then menu.
186
+ */
187
+ export async function runHub(opts: {
188
+ packageVersion: string;
189
+ isProjectInitialized: boolean;
190
+ projectNames: string[];
191
+ itermPromptShown: boolean;
192
+ isMac: boolean;
193
+ lastUpdateCheck?: string;
194
+ latestVersion?: string;
195
+ projectPaths: Array<{ name: string; path: string }>;
196
+ }): Promise<HubResult> {
197
+ const result: HubResult = { action: 'launch' };
198
+
199
+ p.intro(`${pc.bgCyan(pc.black(' Orbital Command '))} ${pc.dim(`v${opts.packageVersion}`)}`);
200
+
201
+ // ── Update check ──
202
+ const updateCheck = await checkForUpdate(opts.packageVersion, {
203
+ lastUpdateCheck: opts.lastUpdateCheck,
204
+ latestVersion: opts.latestVersion,
205
+ });
206
+
207
+ if (updateCheck.cacheChanged) {
208
+ result.updateCache = {
209
+ lastUpdateCheck: new Date().toISOString(),
210
+ latestVersion: updateCheck.info?.latest,
211
+ };
212
+ }
213
+
214
+ if (updateCheck.info?.isOutdated) {
215
+ p.log.info(
216
+ `Update available: ${pc.dim(`v${updateCheck.info.current}`)} → ${pc.cyan(`v${updateCheck.info.latest}`)}`
217
+ );
218
+
219
+ const updateChoice = await p.select({
220
+ message: 'Update Orbital Command now?',
221
+ options: [
222
+ { value: 'update', label: 'Yes, update' },
223
+ { value: 'skip', label: 'Skip for now' },
224
+ ],
225
+ });
226
+
227
+ if (!p.isCancel(updateChoice) && updateChoice === 'update') {
228
+ const s = p.spinner();
229
+ s.start('Updating Orbital Command...');
230
+ try {
231
+ execFileSync('npm', ['update', '-g', 'orbital-command'], { stdio: 'pipe', timeout: 60000 });
232
+ s.stop(`Updated to v${updateCheck.info.latest}!`);
233
+ p.outro(`Run ${pc.cyan('orbital')} again to use the new version.`);
234
+ process.exit(0);
235
+ } catch (err) {
236
+ s.stop('Update failed.');
237
+ const msg = err instanceof Error ? err.message : String(err);
238
+ if (msg.includes('EACCES') || msg.includes('permission denied')) {
239
+ p.log.error('Permission denied. Try running with sudo or ensure npm is installed via nvm.');
240
+ } else if (msg.includes('ETIMEDOUT') || msg.includes('timeout')) {
241
+ p.log.error('Update timed out. Check your network connection and try again.');
242
+ } else {
243
+ p.log.error(msg);
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ // ── Template staleness check ──
250
+ if (opts.projectPaths.length > 0) {
251
+ const mod = await import('../manifest.js');
252
+ const initMod = await import('../init.js');
253
+ const outdatedProjects: Array<{
254
+ name: string;
255
+ path: string;
256
+ details: string[];
257
+ }> = [];
258
+
259
+ for (const proj of opts.projectPaths) {
260
+ if (!fs.existsSync(proj.path)) {
261
+ p.log.warn(`${proj.name}: project path not found (${proj.path})`);
262
+ continue;
263
+ }
264
+ const manifest = mod.loadManifest(proj.path);
265
+ if (!manifest) continue;
266
+ const claudeDir = path.join(proj.path, '.claude');
267
+ mod.refreshFileStatuses(manifest, claudeDir);
268
+ const summary = mod.summarizeManifest(manifest);
269
+ const parts = Object.entries(summary.byType)
270
+ .filter(([, counts]) => counts.outdated > 0)
271
+ .map(([type, counts]) => `${counts.outdated} ${type}`);
272
+ if (parts.length > 0) {
273
+ outdatedProjects.push({ name: proj.name, path: proj.path, details: parts });
274
+ }
275
+ }
276
+
277
+ if (outdatedProjects.length > 0) {
278
+ const lines = outdatedProjects.map(proj =>
279
+ ` ${pc.cyan(proj.name.padEnd(16))} ${proj.details.join(', ')} outdated`
280
+ );
281
+ const count = outdatedProjects.length;
282
+ p.note(lines.join('\n'), `${count} project${count > 1 ? 's have' : ' has'} outdated templates`);
283
+
284
+ const syncChoice = await p.select({
285
+ message: 'Update project templates now?',
286
+ options: [
287
+ { value: 'update', label: 'Yes, update all safe files', hint: 'skips modified and pinned' },
288
+ { value: 'skip', label: 'Skip for now' },
289
+ ],
290
+ });
291
+
292
+ if (!p.isCancel(syncChoice) && syncChoice === 'update') {
293
+ for (const proj of outdatedProjects) {
294
+ const s = p.spinner();
295
+ s.start(`Updating ${proj.name}...`);
296
+ try {
297
+ initMod.runUpdate(proj.path, { dryRun: false });
298
+ s.stop(`${proj.name} updated.`);
299
+ } catch (err) {
300
+ s.stop(`${proj.name} failed.`);
301
+ p.log.warn(err instanceof Error ? err.message : String(err));
302
+ }
303
+ }
304
+ }
305
+ }
306
+ }
307
+
308
+ // ── iTerm2 recommendation (macOS only, one-time) ──
309
+ if (opts.isMac && !opts.itermPromptShown && !isITerm2Available()) {
310
+ p.note(
311
+ `Sprint dispatch, batch orchestration, and session management\n` +
312
+ `use iTerm2 tabs to run parallel Claude Code sessions.\n` +
313
+ `Without it, sessions fall back to basic subprocess mode.`,
314
+ 'iTerm2 Recommended',
315
+ );
316
+
317
+ const itermChoice = await p.select({
318
+ message: 'Install iTerm2?',
319
+ options: [
320
+ { value: 'install', label: 'Open download page', hint: 'https://iterm2.com' },
321
+ { value: 'skip', label: 'Skip for now' },
322
+ ],
323
+ });
324
+
325
+ result.setItermPromptShown = true;
326
+
327
+ if (!p.isCancel(itermChoice) && itermChoice === 'install') {
328
+ spawn('open', ['https://iterm2.com'], { detached: true, stdio: 'ignore' }).unref();
329
+ p.log.info('Waiting for iTerm2 to install... (press any key to skip)');
330
+
331
+ await new Promise<void>((resolve) => {
332
+ let done = false;
333
+ const cleanup = (): void => {
334
+ if (done) return;
335
+ done = true;
336
+ process.stdin.setRawMode?.(false);
337
+ process.stdin.removeListener('data', onKey);
338
+ process.stdin.pause();
339
+ clearInterval(timer);
340
+ resolve();
341
+ };
342
+ const onKey = (): void => { cleanup(); };
343
+ const startTime = Date.now();
344
+ const MAX_WAIT = 10 * 60 * 1000; // 10 minutes
345
+ const timer = setInterval(() => {
346
+ if (isITerm2Available()) {
347
+ p.log.success('iTerm2 detected!');
348
+ cleanup();
349
+ } else if (Date.now() - startTime > MAX_WAIT) {
350
+ cleanup();
351
+ }
352
+ }, 3000);
353
+ process.stdin.setRawMode?.(true);
354
+ process.stdin.resume();
355
+ process.stdin.on('data', onKey);
356
+ });
357
+ }
358
+ }
359
+
360
+ // ── Build menu options based on project state ──
361
+ const projectHint = opts.projectNames.length > 0
362
+ ? pc.dim(` (${opts.projectNames.join(', ')})`)
363
+ : '';
364
+
365
+ const options: Array<{ value: HubAction; label: string; hint?: string }> = [];
366
+
367
+ if (opts.isProjectInitialized) {
368
+ options.push(
369
+ { value: 'launch', label: `Launch dashboard${projectHint}` },
370
+ { value: 'config', label: 'Config', hint: 'modify project settings' },
371
+ { value: 'doctor', label: 'Doctor', hint: 'health check & diagnostics' },
372
+ { value: 'update', label: 'Update templates', hint: 'sync to latest' },
373
+ { value: 'status', label: 'Status', hint: 'template sync status' },
374
+ { value: 'reset', label: 'Reset to defaults', hint: 'force-reset all templates' },
375
+ );
376
+ } else {
377
+ options.push(
378
+ { value: 'init', label: 'Initialize this project' },
379
+ { value: 'launch', label: `Launch dashboard${projectHint}` },
380
+ );
381
+ }
382
+
383
+ const action = await p.select({
384
+ message: 'What would you like to do?',
385
+ options,
386
+ });
387
+
388
+ if (p.isCancel(action)) {
389
+ p.cancel('Cancelled.');
390
+ process.exit(0);
391
+ }
392
+
393
+ // ── Double-confirm for destructive reset ──
394
+ if (action === 'reset') {
395
+ p.note(
396
+ 'This will overwrite ALL hooks, skills, agents, and workflow config\n' +
397
+ 'with the default templates. Modified and pinned files will be replaced.\n' +
398
+ 'Your scopes, database, and orbital.config.json are preserved.',
399
+ 'Warning',
400
+ );
401
+ const confirmReset = await p.confirm({
402
+ message: 'Are you sure you want to reset all templates?',
403
+ initialValue: false,
404
+ });
405
+ if (p.isCancel(confirmReset) || !confirmReset) {
406
+ p.cancel('Reset cancelled.');
407
+ process.exit(0);
408
+ }
409
+ const doubleConfirm = await p.confirm({
410
+ message: 'This cannot be undone. Continue?',
411
+ initialValue: false,
412
+ });
413
+ if (p.isCancel(doubleConfirm) || !doubleConfirm) {
414
+ p.cancel('Reset cancelled.');
415
+ process.exit(0);
416
+ }
417
+ }
418
+
419
+ result.action = action;
420
+ return result;
421
+ }
422
+
423
+ // ─── Template Version Stamping ─────────────────────────────────
424
+
425
+ function stampTemplateVersion(projectRoot: string, packageVersion: string): void {
426
+ const configPath = path.join(projectRoot, '.claude', 'orbital.config.json');
427
+ if (!fs.existsSync(configPath)) return;
428
+
429
+ try {
430
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
431
+ if (config.templateVersion !== packageVersion) {
432
+ config.templateVersion = packageVersion;
433
+ const tmp = configPath + `.tmp.${process.pid}`;
434
+ fs.writeFileSync(tmp, JSON.stringify(config, null, 2) + '\n', 'utf8');
435
+ fs.renameSync(tmp, configPath);
436
+ }
437
+ } catch { /* ignore malformed config */ }
438
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Phase 3: Confirm choices, run installation, show next steps.
3
+ */
4
+
5
+ import fs from 'fs';
6
+ import path from 'path';
7
+ import * as p from '@clack/prompts';
8
+ import type { ProjectSetupState } from '../types.js';
9
+ import { NOTES, formatSummary } from '../ui.js';
10
+
11
+ export async function phaseConfirm(state: ProjectSetupState): Promise<void> {
12
+ p.note(formatSummary(state), 'Ready to Initialize');
13
+
14
+ const proceed = await p.confirm({
15
+ message: 'Proceed with installation?',
16
+ initialValue: true,
17
+ });
18
+
19
+ if (p.isCancel(proceed) || !proceed) {
20
+ p.cancel('Setup cancelled.');
21
+ process.exit(0);
22
+ }
23
+ }
24
+
25
+ export function showPostInstall(state: ProjectSetupState): void {
26
+ // Count installed artifacts
27
+ const claudeDir = path.join(state.projectRoot, '.claude');
28
+ const counts = {
29
+ hooks: countDir(path.join(claudeDir, 'hooks')),
30
+ skills: countDir(path.join(claudeDir, 'skills')),
31
+ agents: countDir(path.join(claudeDir, 'agents')),
32
+ };
33
+
34
+ p.note(NOTES.postInstall(counts), 'Installation Complete');
35
+ p.note(NOTES.nextSteps, 'Getting Started');
36
+ }
37
+
38
+ function countDir(dir: string): number {
39
+ if (!fs.existsSync(dir)) return 0;
40
+ try {
41
+ return fs.readdirSync(dir).filter(f => !f.startsWith('.')).length;
42
+ } catch {
43
+ return 0;
44
+ }
45
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Phase 1: Project configuration — name, commands, ports.
3
+ */
4
+
5
+ import * as p from '@clack/prompts';
6
+ import type { ProjectSetupState } from '../types.js';
7
+ import { NOTES, formatDetectedCommands } from '../ui.js';
8
+ import { detectProjectName, detectCommands, detectPortConflict } from '../detect.js';
9
+
10
+ export async function phaseProjectSetup(state: ProjectSetupState): Promise<void> {
11
+ p.note(NOTES.projectConfig, 'Project Configuration');
12
+
13
+ // 1. Project name
14
+ const defaultName = detectProjectName(state.projectRoot);
15
+ const name = await p.text({
16
+ message: 'Project name',
17
+ placeholder: defaultName,
18
+ defaultValue: defaultName,
19
+ });
20
+
21
+ if (p.isCancel(name)) {
22
+ p.cancel('Setup cancelled.');
23
+ process.exit(0);
24
+ }
25
+ state.projectName = name;
26
+
27
+ // 2. Command detection
28
+ const detected = detectCommands(state.projectRoot);
29
+ state.detectedCommands = detected;
30
+ const detectedCount = Object.values(detected).filter(v => v !== null).length;
31
+
32
+ if (detectedCount > 0) {
33
+ p.note(formatDetectedCommands(detected), `Detected ${detectedCount} command(s) from package.json`);
34
+
35
+ const useDetected = await p.confirm({
36
+ message: 'Use these detected commands for quality gates?',
37
+ initialValue: true,
38
+ });
39
+
40
+ if (p.isCancel(useDetected)) {
41
+ p.cancel('Setup cancelled.');
42
+ process.exit(0);
43
+ }
44
+
45
+ if (useDetected) {
46
+ state.selectedCommands = { ...detected };
47
+ } else {
48
+ state.selectedCommands = await promptCommands(detected);
49
+ }
50
+ } else {
51
+ p.log.info('No build commands detected from package.json. You can configure them later with `orbital config`.');
52
+ state.selectedCommands = detected;
53
+ }
54
+
55
+ // 3. Port conflict detection
56
+ const conflict = detectPortConflict(4444);
57
+ if (conflict) {
58
+ p.log.warn(`Port 4444 is already used by "${conflict}".`);
59
+
60
+ const serverPort = await p.text({
61
+ message: 'Server port',
62
+ placeholder: '4446',
63
+ defaultValue: '4446',
64
+ validate: (val) => {
65
+ const n = Number(val);
66
+ if (isNaN(n) || n < 1 || n > 65535) return 'Must be a valid port (1-65535)';
67
+ return undefined;
68
+ },
69
+ });
70
+
71
+ if (p.isCancel(serverPort)) {
72
+ p.cancel('Setup cancelled.');
73
+ process.exit(0);
74
+ }
75
+
76
+ state.serverPort = Number(serverPort);
77
+ state.clientPort = state.serverPort + 1;
78
+ }
79
+ }
80
+
81
+ async function promptCommands(defaults: Record<string, string | null>): Promise<Record<string, string | null>> {
82
+ const commands: Record<string, string | null> = {};
83
+ const labels: Record<string, string> = {
84
+ typeCheck: 'Type check command',
85
+ lint: 'Lint command',
86
+ build: 'Build command',
87
+ test: 'Test command',
88
+ };
89
+
90
+ for (const [key, defaultVal] of Object.entries(defaults)) {
91
+ const val = await p.text({
92
+ message: labels[key] || key,
93
+ placeholder: defaultVal || 'none',
94
+ defaultValue: defaultVal || '',
95
+ });
96
+
97
+ if (p.isCancel(val)) {
98
+ p.cancel('Setup cancelled.');
99
+ process.exit(0);
100
+ }
101
+
102
+ commands[key] = val || null;
103
+ }
104
+
105
+ return commands;
106
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Phase 1: Setup Wizard — runs on first install or when ~/.orbital/ is missing.
3
+ *
4
+ * Creates the Orbital home directory, seeds primitives, and optionally
5
+ * lets the user link projects immediately.
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import * as p from '@clack/prompts';
10
+ import pc from 'picocolors';
11
+ import type { SetupState } from '../types.js';
12
+ import { NOTES } from '../ui.js';
13
+ import { isValidProjectPath, resolveProjectPath, ORBITAL_HOME } from '../detect.js';
14
+
15
+ export async function phaseSetupWizard(state: SetupState): Promise<void> {
16
+ // Welcome and core concepts
17
+ p.note(NOTES.setupWelcome, 'Welcome');
18
+
19
+ // Create ~/.orbital/ and seed primitives
20
+ const s = p.spinner();
21
+ s.start('Setting up Orbital Command...');
22
+
23
+ try {
24
+ const { ensureOrbitalHome } = await import('../../global-config.js');
25
+ const { seedGlobalPrimitives } = await import('../../init.js');
26
+
27
+ ensureOrbitalHome();
28
+ seedGlobalPrimitives();
29
+
30
+ // Create empty registry if it doesn't exist
31
+ const registryPath = `${ORBITAL_HOME}/config.json`;
32
+ if (!fs.existsSync(registryPath)) {
33
+ fs.writeFileSync(registryPath, JSON.stringify({ version: 1, projects: [] }, null, 2), 'utf8');
34
+ }
35
+
36
+ s.stop('Orbital Command is ready.');
37
+ } catch (err) {
38
+ s.stop('Setup failed.');
39
+ p.log.error(err instanceof Error ? err.message : String(err));
40
+ process.exit(1);
41
+ }
42
+
43
+ // Offer to link projects
44
+ p.note(NOTES.addProject, 'Projects');
45
+
46
+ let addMore = true;
47
+ while (addMore) {
48
+ const wantsProject = await p.confirm({
49
+ message: state.linkedProjects.length === 0
50
+ ? 'Add a project now?'
51
+ : 'Add another project?',
52
+ initialValue: state.linkedProjects.length === 0,
53
+ });
54
+
55
+ if (p.isCancel(wantsProject) || !wantsProject) {
56
+ addMore = false;
57
+ break;
58
+ }
59
+
60
+ const projectPath = await p.text({
61
+ message: 'Project path',
62
+ placeholder: '~/Code/my-project',
63
+ validate: (val) => {
64
+ if (!val || !val.trim()) return 'Path is required';
65
+ return isValidProjectPath(val.trim());
66
+ },
67
+ });
68
+
69
+ if (p.isCancel(projectPath)) {
70
+ addMore = false;
71
+ break;
72
+ }
73
+
74
+ const resolved = resolveProjectPath(projectPath.trim());
75
+ state.linkedProjects.push(resolved);
76
+ p.log.success(`Added: ${pc.cyan(resolved)}`);
77
+ }
78
+ }