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,39 @@
1
+ /**
2
+ * Phase 2 welcome gate — project-scoped only.
3
+ *
4
+ * If the project is already initialized, offers re-init or config editor.
5
+ * If not, returns false to continue the project setup flow.
6
+ */
7
+
8
+ import * as p from '@clack/prompts';
9
+ import pc from 'picocolors';
10
+ import type { ProjectSetupState } from '../types.js';
11
+ import { NOTES } from '../ui.js';
12
+ import { runConfigEditor } from '../config-editor.js';
13
+
14
+ export async function phaseWelcome(state: ProjectSetupState): Promise<boolean> {
15
+ if (state.isProjectInitialized) {
16
+ p.note(NOTES.reconfigure, pc.yellow('Already Initialized'));
17
+
18
+ const action = await p.select({
19
+ message: 'What would you like to do?',
20
+ options: [
21
+ { value: 'configure', label: 'Open config editor', hint: 'modify settings' },
22
+ { value: 'cancel', label: 'Cancel' },
23
+ ],
24
+ });
25
+
26
+ if (p.isCancel(action) || action === 'cancel') {
27
+ p.cancel('Cancelled.');
28
+ process.exit(0);
29
+ }
30
+
31
+ if (action === 'configure') {
32
+ await runConfigEditor(state.projectRoot, state.packageVersion, []);
33
+ process.exit(0);
34
+ }
35
+ }
36
+
37
+ // Not initialized — continue normally
38
+ return false;
39
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Phase 2: Workflow preset selection.
3
+ */
4
+
5
+ import * as p from '@clack/prompts';
6
+ import type { ProjectSetupState } from '../types.js';
7
+ import { WORKFLOW_PRESETS } from '../types.js';
8
+ import { NOTES } from '../ui.js';
9
+
10
+ export async function phaseWorkflowSetup(state: ProjectSetupState): Promise<void> {
11
+ p.note(NOTES.workflow, 'Workflow Selection');
12
+
13
+ const preset = await p.select({
14
+ message: 'Choose a workflow preset',
15
+ options: WORKFLOW_PRESETS.map(p => ({
16
+ value: p.value,
17
+ label: p.label,
18
+ hint: p.hint,
19
+ })),
20
+ });
21
+
22
+ if (p.isCancel(preset)) {
23
+ p.cancel('Setup cancelled.');
24
+ process.exit(0);
25
+ }
26
+
27
+ state.workflowPreset = preset as string;
28
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Types for the interactive CLI wizard.
3
+ *
4
+ * Two wizard flows:
5
+ * Phase 1 (SetupState) — first-time Orbital setup, ~/.orbital/ creation
6
+ * Phase 2 (ProjectSetupState) — per-project scaffolding into .claude/
7
+ */
8
+
9
+ export interface SetupState {
10
+ packageVersion: string;
11
+ isFirstTime: boolean; // ~/.orbital/ doesn't exist yet
12
+ linkedProjects: string[]; // project paths added during setup
13
+ }
14
+
15
+ export interface ProjectSetupState {
16
+ projectRoot: string;
17
+ isProjectInitialized: boolean; // .claude/orbital.config.json exists
18
+ packageVersion: string;
19
+
20
+ // Collected from phases
21
+ projectName?: string;
22
+ serverPort?: number;
23
+ clientPort?: number;
24
+ detectedCommands?: Record<string, string | null>;
25
+ selectedCommands?: Record<string, string | null>;
26
+ workflowPreset?: string; // 'default' | 'minimal' | 'development' | 'gitflow'
27
+ }
28
+
29
+ export interface PresetInfo {
30
+ value: string;
31
+ label: string;
32
+ hint: string;
33
+ }
34
+
35
+ export const WORKFLOW_PRESETS: PresetInfo[] = [
36
+ {
37
+ value: 'default',
38
+ label: 'Default',
39
+ hint: '7 lists, trunk-based — Icebox → Planning → Backlog → Implementing → Review → Completed → Main',
40
+ },
41
+ {
42
+ value: 'minimal',
43
+ label: 'Minimal',
44
+ hint: '3 lists — To Do → In Progress → Done',
45
+ },
46
+ {
47
+ value: 'development',
48
+ label: 'Development',
49
+ hint: '5 lists, dev branch — Backlog → Implementing → Review → Completed → Dev',
50
+ },
51
+ {
52
+ value: 'gitflow',
53
+ label: 'Gitflow',
54
+ hint: '9 lists, multi-branch — Full pipeline with Dev, Staging, and Production',
55
+ },
56
+ ];
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Shared UI helpers, concept notes, and formatting for the wizard.
3
+ */
4
+
5
+ import pc from 'picocolors';
6
+
7
+ // ─── Concept Notes ──────────────────────────────────────────────
8
+
9
+ export const NOTES = {
10
+ // Phase 1: Setup wizard (runs on install / first use)
11
+ setupWelcome: `Orbital Command is a mission control layer for Claude Code.
12
+
13
+ It gives your projects a real-time dashboard with a Kanban board,
14
+ ${pc.cyan('scopes')} (work items), ${pc.cyan('workflow stages')}, ${pc.cyan('quality gates')},
15
+ ${pc.cyan('dispatches')} (automated Claude sessions), and a ${pc.cyan('sprint orchestrator')}.
16
+
17
+ Everything is driven by config files and hooks inside your project's
18
+ ${pc.cyan('.claude/')} directory — no database or external service required.`,
19
+
20
+ setupComplete: `${pc.bold('Setup complete.')}
21
+
22
+ ${pc.cyan('orbital')} Add a project or launch the dashboard
23
+ ${pc.cyan('orbital doctor')} Health check & version info`,
24
+
25
+ addProject: `You can add projects now or later by running ${pc.cyan('orbital')} in a project directory.
26
+ Each project gets its own workflow, scopes, and quality gates.`,
27
+
28
+ // Phase 2: Project setup (runs per-project)
29
+ reconfigure: `This project is already initialized with Orbital Command.
30
+ You can reconfigure settings or select ${pc.cyan('Reset to defaults')} from the hub menu.`,
31
+
32
+ projectConfig: `${pc.bold('Project Config')} ${pc.dim('(.claude/orbital.config.json)')}
33
+
34
+ Each project gets its own config inside ${pc.cyan('.claude/')}. The project
35
+ config controls the name shown in the dashboard, ports, build commands
36
+ used by quality gates, and agent definitions.`,
37
+
38
+ workflow: `${pc.bold('Workflows')} ${pc.dim('(Scopes, Lists, Dispatches)')}
39
+
40
+ Orbital organizes work into ${pc.cyan('scopes')} (cards) that move through
41
+ ${pc.cyan('lists')} (Kanban columns). Transitions between lists can trigger
42
+ commands, quality gates, and Claude Code sessions (${pc.cyan('dispatches')}).
43
+
44
+ Choose a preset to start — you can customize it later from the
45
+ dashboard's workflow editor or by editing ${pc.cyan('.claude/config/workflow.json')}.`,
46
+
47
+ postInstall: (counts: { hooks: number; skills: number; agents: number }) =>
48
+ `${pc.bold('What was just created')}
49
+
50
+ ${pc.cyan('Hooks')} (${counts.hooks}) Lifecycle scripts that enforce rules on transitions
51
+ ${pc.cyan('Skills')} (${counts.skills}) Slash commands for Claude (/scope-create, /git-commit, etc.)
52
+ ${pc.cyan('Agents')} (${counts.agents}) Team specifications for code review, architecture, security
53
+ ${pc.cyan('Workflow')} Your selected preset defining lists and transitions
54
+ ${pc.cyan('Quality Gates')} Automated checks (lint, typecheck, tests) before transitions`,
55
+
56
+ nextSteps: `${pc.bold('Next Steps')}
57
+
58
+ 1. Run ${pc.cyan('orbital')} and select ${pc.bold('Launch dashboard')}
59
+ 2. Create a scope from the board or use ${pc.cyan('/scope-create')}
60
+ 3. Use ${pc.cyan('/scope-implement')} to start working on a scope
61
+
62
+ ${pc.bold('Useful Commands')}
63
+
64
+ ${pc.cyan('orbital')} Hub menu — launch, config, doctor, etc.
65
+ ${pc.cyan('orbital status')} See template sync status
66
+ ${pc.cyan('orbital config')} Modify project settings
67
+ ${pc.cyan('orbital update')} Sync to latest templates`,
68
+ };
69
+
70
+ // ─── Formatting Helpers ─────────────────────────────────────────
71
+
72
+ export function formatDetectedCommands(commands: Record<string, string | null>): string {
73
+ const entries = Object.entries(commands).filter(([, v]) => v !== null);
74
+ if (entries.length === 0) return pc.dim(' No commands detected');
75
+
76
+ return entries
77
+ .map(([key, val]) => ` ${pc.cyan(key.padEnd(12))} ${val}`)
78
+ .join('\n');
79
+ }
80
+
81
+ export function formatSummary(state: {
82
+ projectName?: string;
83
+ workflowPreset?: string;
84
+ serverPort?: number;
85
+ clientPort?: number;
86
+ }): string {
87
+ return [
88
+ ` Project: ${pc.cyan(state.projectName || 'Unknown')}`,
89
+ ` Workflow: ${pc.cyan(state.workflowPreset || 'default')}`,
90
+ ` Ports: ${pc.cyan(String(state.serverPort || 4444))} (server) / ${pc.cyan(String(state.clientPort || 4445))} (client)`,
91
+ ].join('\n');
92
+ }
@@ -0,0 +1,80 @@
1
+ import type { WorkflowConfig } from '../workflow-config.js';
2
+ import defaultWorkflowJson from '../default-workflow.json' with { type: 'json' };
3
+
4
+ /** The full 7-list trunk-based workflow from default-workflow.json */
5
+ export const DEFAULT_CONFIG = defaultWorkflowJson as unknown as WorkflowConfig;
6
+
7
+ /** Smallest valid config: 2 lists, 1 edge, 1 entry point */
8
+ export const MINIMAL_CONFIG: WorkflowConfig = {
9
+ version: 1,
10
+ name: 'Minimal',
11
+ lists: [
12
+ { id: 'todo', label: 'To Do', order: 0, color: '0 0% 50%', hex: '#808080', isEntryPoint: true, hasDirectory: true },
13
+ { id: 'done', label: 'Done', order: 1, color: '120 50% 50%', hex: '#40bf40', hasDirectory: true },
14
+ ],
15
+ edges: [
16
+ { from: 'todo', to: 'done', direction: 'forward', command: null, confirmLevel: 'quick', label: 'Complete', description: 'Mark as done' },
17
+ ],
18
+ terminalStatuses: ['done'],
19
+ allowedCommandPrefixes: ['/test-'],
20
+ };
21
+
22
+ /** Config with hooks for hook-related tests */
23
+ export const CONFIG_WITH_HOOKS: WorkflowConfig = {
24
+ version: 1,
25
+ name: 'With Hooks',
26
+ lists: [
27
+ { id: 'backlog', label: 'Backlog', order: 0, color: '0 0% 50%', hex: '#808080', isEntryPoint: true, hasDirectory: true, supportsSprint: true },
28
+ { id: 'active', label: 'Active', order: 1, color: '200 80% 50%', hex: '#1a8ccc', hasDirectory: true, sessionKey: 'implementScope' },
29
+ { id: 'review', label: 'Review', order: 2, color: '45 90% 50%', hex: '#f0c010', hasDirectory: true, supportsBatch: true, sessionKey: 'reviewGate' },
30
+ { id: 'shipped', label: 'Shipped', order: 3, color: '120 70% 40%', hex: '#30a030', hasDirectory: true, gitBranch: 'main' },
31
+ ],
32
+ edges: [
33
+ { from: 'backlog', to: 'active', direction: 'forward', command: '/scope-implement {id}', confirmLevel: 'quick', label: 'Start', description: 'Begin work', dispatchOnly: true, autoRevert: true, hooks: ['blocker-check'], agents: ['architect'] },
34
+ { from: 'active', to: 'review', direction: 'forward', command: '/scope-post-review {id}', confirmLevel: 'quick', label: 'Review', description: 'Submit for review', dispatchOnly: true, hooks: ['blocker-check', 'session-enforcer'] },
35
+ { from: 'review', to: 'shipped', direction: 'forward', command: '/git-main', confirmLevel: 'quick', label: 'Ship', description: 'Push to main', dispatchOnly: true },
36
+ { from: 'active', to: 'backlog', direction: 'backward', command: null, confirmLevel: 'quick', label: 'Revert', description: 'Back to backlog', humanOnly: true },
37
+ { from: 'review', to: 'active', direction: 'backward', command: null, confirmLevel: 'quick', label: 'Rework', description: 'Back to active' },
38
+ ],
39
+ hooks: [
40
+ { id: 'blocker-check', label: 'Blocker Check', timing: 'before', type: 'shell', target: '.claude/hooks/blocker-check.sh', blocking: false, category: 'gate', description: 'Checks for blockers' },
41
+ { id: 'session-enforcer', label: 'Session Auth', timing: 'before', type: 'shell', target: '.claude/hooks/session-enforcer.sh', blocking: true, category: 'guard', description: 'Enforces session auth' },
42
+ { id: 'scope-transition', label: 'File Mover', timing: 'before', type: 'shell', target: '.claude/hooks/scope-transition.sh', blocking: false, category: 'lifecycle' },
43
+ { id: 'dashboard-sync', label: 'Dashboard Sync', timing: 'after', type: 'shell', target: '.claude/hooks/dashboard-sync.sh', blocking: false, category: 'observer' },
44
+ ],
45
+ groups: [
46
+ { id: 'planning', label: 'Planning', order: 0 },
47
+ { id: 'development', label: 'Development', order: 1 },
48
+ ],
49
+ eventInference: [
50
+ { eventType: 'SCOPE_STATUS_CHANGED', targetStatus: '', dataField: 'to', forwardOnly: true },
51
+ { eventType: 'AGENT_STARTED', targetStatus: 'active', forwardOnly: true },
52
+ { eventType: 'AGENT_COMPLETED', targetStatus: '', conditions: { outcome: ['success', 'failure'], dispatchResolution: true }, forwardOnly: false },
53
+ ],
54
+ terminalStatuses: ['shipped'],
55
+ allowedCommandPrefixes: ['/scope-', '/git-'],
56
+ };
57
+
58
+ /** Named invalid configs for constructor error tests */
59
+ export const INVALID_CONFIGS = {
60
+ noLists: { version: 1 as const, name: 'No Lists', lists: [], edges: [{ from: 'a', to: 'b', direction: 'forward' as const, command: null, confirmLevel: 'quick' as const, label: 'X', description: 'X' }] } as WorkflowConfig,
61
+ noEdges: { version: 1 as const, name: 'No Edges', lists: [{ id: 'a', label: 'A', order: 0, color: '0 0% 0%', hex: '#000', isEntryPoint: true, hasDirectory: true }], edges: [] } as WorkflowConfig,
62
+ twoEntryPoints: {
63
+ version: 1 as const,
64
+ name: 'Two Entry Points',
65
+ lists: [
66
+ { id: 'a', label: 'A', order: 0, color: '0 0% 0%', hex: '#000', isEntryPoint: true, hasDirectory: true },
67
+ { id: 'b', label: 'B', order: 1, color: '0 0% 0%', hex: '#000', isEntryPoint: true, hasDirectory: true },
68
+ ],
69
+ edges: [{ from: 'a', to: 'b', direction: 'forward' as const, command: null, confirmLevel: 'quick' as const, label: 'X', description: 'X' }],
70
+ } as WorkflowConfig,
71
+ zeroEntryPoints: {
72
+ version: 1 as const,
73
+ name: 'Zero Entry Points',
74
+ lists: [
75
+ { id: 'a', label: 'A', order: 0, color: '0 0% 0%', hex: '#000', hasDirectory: true },
76
+ { id: 'b', label: 'B', order: 1, color: '0 0% 0%', hex: '#000', hasDirectory: true },
77
+ ],
78
+ edges: [{ from: 'a', to: 'b', direction: 'forward' as const, command: null, confirmLevel: 'quick' as const, label: 'X', description: 'X' }],
79
+ } as WorkflowConfig,
80
+ };
@@ -18,3 +18,109 @@ export interface AgentConfig {
18
18
  emoji: string;
19
19
  color: string;
20
20
  }
21
+
22
+ // ─── Dispatch Flags (CLI flags passed to `claude`) ──────────
23
+
24
+ export interface DispatchFlags {
25
+ permissionMode: 'bypass' | 'default' | 'plan' | 'acceptEdits';
26
+ verbose: boolean;
27
+ allowedTools: string[];
28
+ disallowedTools: string[];
29
+ appendSystemPrompt: string;
30
+ outputFormat: '' | 'text' | 'json' | 'stream-json';
31
+ noMarkdown: boolean;
32
+ printMode: boolean;
33
+ }
34
+
35
+ export const DEFAULT_DISPATCH_FLAGS: DispatchFlags = {
36
+ permissionMode: 'bypass',
37
+ verbose: true,
38
+ allowedTools: [],
39
+ disallowedTools: [],
40
+ appendSystemPrompt: '',
41
+ outputFormat: '',
42
+ noMarkdown: false,
43
+ printMode: false,
44
+ };
45
+
46
+ // ─── Dispatch Config (Orbital operational settings) ─────────
47
+
48
+ export interface DispatchConfig {
49
+ staleTimeoutMinutes: number;
50
+ maxBatchSize: number;
51
+ maxConcurrent: number;
52
+ envVars: Record<string, string>;
53
+ }
54
+
55
+ export const DEFAULT_DISPATCH_CONFIG: DispatchConfig = {
56
+ staleTimeoutMinutes: 10,
57
+ maxBatchSize: 20,
58
+ maxConcurrent: 0,
59
+ envVars: {},
60
+ };
61
+
62
+ // ─── Validation ─────────────────────────────────────────────
63
+
64
+ export const VALID_PERMISSION_MODES = ['bypass', 'default', 'plan', 'acceptEdits'] as const;
65
+ export const VALID_OUTPUT_FORMATS = ['', 'text', 'json', 'stream-json'];
66
+ export const VALID_TERMINAL_ADAPTERS = ['auto', 'iterm2', 'subprocess', 'none'];
67
+
68
+ const SAFE_TOOL_NAME = /^[a-zA-Z0-9_:.-]+$/;
69
+ const SAFE_ENV_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
70
+
71
+ export function validateToolName(name: string): boolean {
72
+ return SAFE_TOOL_NAME.test(name);
73
+ }
74
+
75
+ export function validateEnvKey(key: string): boolean {
76
+ return SAFE_ENV_KEY.test(key);
77
+ }
78
+
79
+ export function validateDispatchFlags(flags: Partial<DispatchFlags>): string | null {
80
+ if (flags.permissionMode !== undefined && !VALID_PERMISSION_MODES.includes(flags.permissionMode as typeof VALID_PERMISSION_MODES[number])) {
81
+ return `Invalid permissionMode: ${flags.permissionMode}`;
82
+ }
83
+ if (flags.outputFormat !== undefined && !VALID_OUTPUT_FORMATS.includes(flags.outputFormat as string)) {
84
+ return `Invalid outputFormat: ${flags.outputFormat}`;
85
+ }
86
+ if (flags.allowedTools !== undefined) {
87
+ if (!Array.isArray(flags.allowedTools)) return 'allowedTools must be an array';
88
+ for (const t of flags.allowedTools) {
89
+ if (typeof t !== 'string' || !validateToolName(t)) return `Invalid tool name: ${t}`;
90
+ }
91
+ }
92
+ if (flags.disallowedTools !== undefined) {
93
+ if (!Array.isArray(flags.disallowedTools)) return 'disallowedTools must be an array';
94
+ for (const t of flags.disallowedTools) {
95
+ if (typeof t !== 'string' || !validateToolName(t)) return `Invalid tool name: ${t}`;
96
+ }
97
+ }
98
+ if (flags.appendSystemPrompt !== undefined && typeof flags.appendSystemPrompt !== 'string') {
99
+ return 'appendSystemPrompt must be a string';
100
+ }
101
+ return null;
102
+ }
103
+
104
+ export function validateDispatchConfig(config: Partial<DispatchConfig> & { terminalAdapter?: string }): string | null {
105
+ if (config.terminalAdapter !== undefined && !VALID_TERMINAL_ADAPTERS.includes(config.terminalAdapter)) {
106
+ return `Invalid terminalAdapter: ${config.terminalAdapter}`;
107
+ }
108
+ if (config.staleTimeoutMinutes !== undefined && (typeof config.staleTimeoutMinutes !== 'number' || config.staleTimeoutMinutes < 1)) {
109
+ return 'staleTimeoutMinutes must be a positive number';
110
+ }
111
+ if (config.maxBatchSize !== undefined && (typeof config.maxBatchSize !== 'number' || config.maxBatchSize < 1)) {
112
+ return 'maxBatchSize must be a positive number';
113
+ }
114
+ if (config.maxConcurrent !== undefined && (typeof config.maxConcurrent !== 'number' || config.maxConcurrent < 0)) {
115
+ return 'maxConcurrent must be a non-negative number';
116
+ }
117
+ if (config.envVars !== undefined) {
118
+ if (typeof config.envVars !== 'object' || config.envVars === null || Array.isArray(config.envVars)) {
119
+ return 'envVars must be an object';
120
+ }
121
+ for (const key of Object.keys(config.envVars)) {
122
+ if (!validateEnvKey(key)) return `Invalid env var key: ${key}`;
123
+ }
124
+ }
125
+ return null;
126
+ }
@@ -0,0 +1,94 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { TOUR_STEPS } from '../src/components/onboarding/tour-steps';
3
+
4
+ describe('onboarding tour steps', () => {
5
+ it('should have at least one step', () => {
6
+ expect(TOUR_STEPS.length).toBeGreaterThan(0);
7
+ });
8
+
9
+ it('should have unique step IDs', () => {
10
+ const ids = TOUR_STEPS.map(s => s.id);
11
+ expect(new Set(ids).size).toBe(ids.length);
12
+ });
13
+
14
+ it('should have unique targets', () => {
15
+ const targets = TOUR_STEPS.map(s => s.target);
16
+ expect(new Set(targets).size).toBe(targets.length);
17
+ });
18
+
19
+ it('should have title and description for every step', () => {
20
+ for (const step of TOUR_STEPS) {
21
+ expect(step.title).toBeTruthy();
22
+ expect(step.description).toBeTruthy();
23
+ }
24
+ });
25
+
26
+ it('should have valid placement values', () => {
27
+ const validPlacements = new Set(['top', 'bottom', 'left', 'right']);
28
+ for (const step of TOUR_STEPS) {
29
+ if (step.placement) {
30
+ expect(validPlacements.has(step.placement)).toBe(true);
31
+ }
32
+ }
33
+ });
34
+
35
+ it('should mark dynamic content steps as optional', () => {
36
+ const dynamicTargets = ['kanban-column', 'scope-card'];
37
+ for (const step of TOUR_STEPS) {
38
+ if (dynamicTargets.includes(step.target)) {
39
+ expect(step.optional).toBe(true);
40
+ }
41
+ }
42
+ });
43
+
44
+ it('should cover all expected pages', () => {
45
+ const pages = new Set(TOUR_STEPS.filter(s => s.page).map(s => s.page));
46
+ expect(pages.has('/')).toBe(true);
47
+ expect(pages.has('/primitives')).toBe(true);
48
+ expect(pages.has('/guards')).toBe(true);
49
+ expect(pages.has('/repo')).toBe(true);
50
+ expect(pages.has('/sessions')).toBe(true);
51
+ expect(pages.has('/workflow')).toBe(true);
52
+ });
53
+
54
+ describe('step sequencing', () => {
55
+ it('first step should target the Kanban nav', () => {
56
+ expect(TOUR_STEPS[0].target).toBe('nav-kanban');
57
+ expect(TOUR_STEPS[0].page).toBe('/');
58
+ });
59
+
60
+ it('last step should target Settings', () => {
61
+ const last = TOUR_STEPS[TOUR_STEPS.length - 1];
62
+ expect(last.target).toBe('nav-settings');
63
+ });
64
+
65
+ it('should complete a full traversal of all steps', () => {
66
+ let index = 0;
67
+ const visited: string[] = [];
68
+ while (index < TOUR_STEPS.length) {
69
+ visited.push(TOUR_STEPS[index].id);
70
+ index++;
71
+ }
72
+ expect(visited.length).toBe(TOUR_STEPS.length);
73
+ expect(visited[0]).toBe('welcome');
74
+ expect(visited[visited.length - 1]).toBe('nav-settings');
75
+ });
76
+ });
77
+
78
+ describe('completion tracking', () => {
79
+ it('default state should be pending', () => {
80
+ const DEFAULT_STATE = 'pending';
81
+ expect(DEFAULT_STATE).toBe('pending');
82
+ });
83
+
84
+ it('completed state should be the string completed', () => {
85
+ const state: string = 'completed';
86
+ expect(state).toBe('completed');
87
+ });
88
+
89
+ it('dismissed state should be the string dismissed', () => {
90
+ const state: string = 'dismissed';
91
+ expect(state).toBe('dismissed');
92
+ });
93
+ });
94
+ });
@@ -0,0 +1,24 @@
1
+ /** Predefined project color palette (HSL strings). Used for auto-assigning
2
+ * project badge colors when projects are registered with Orbital Command. */
3
+ export const PROJECT_COLORS = [
4
+ '0 90% 62%', // red
5
+ '20 95% 60%', // vermilion
6
+ '40 95% 56%', // orange
7
+ '58 90% 52%', // amber
8
+ '76 85% 50%', // chartreuse
9
+ '100 80% 48%', // lime
10
+ '130 80% 48%', // green
11
+ '158 85% 46%', // emerald
12
+ '178 90% 46%', // teal
13
+ '194 95% 52%', // cyan
14
+ '212 90% 60%', // sky
15
+ '232 88% 64%', // blue
16
+ '254 85% 66%', // indigo
17
+ '272 85% 64%', // purple
18
+ '292 82% 62%', // violet
19
+ '312 85% 58%', // magenta
20
+ '330 88% 58%', // hot pink
21
+ '348 92% 60%', // rose
22
+ '150 82% 52%', // mint
23
+ '56 95% 62%', // gold
24
+ ] as const;
@@ -0,0 +1,111 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import {
3
+ isWorkflowConfig, isWorkflowList, isWorkflowEdge, getHookEnforcement,
4
+ type WorkflowHook,
5
+ } from './workflow-config.js';
6
+ import { MINIMAL_CONFIG, DEFAULT_CONFIG } from './__fixtures__/workflow-configs.js';
7
+
8
+ describe('isWorkflowConfig()', () => {
9
+ it('returns true for valid minimal config', () => {
10
+ expect(isWorkflowConfig(MINIMAL_CONFIG)).toBe(true);
11
+ });
12
+
13
+ it('returns true for full default config', () => {
14
+ expect(isWorkflowConfig(DEFAULT_CONFIG)).toBe(true);
15
+ });
16
+
17
+ it('returns false for null', () => {
18
+ expect(isWorkflowConfig(null)).toBe(false);
19
+ });
20
+
21
+ it('returns false for undefined', () => {
22
+ expect(isWorkflowConfig(undefined)).toBe(false);
23
+ });
24
+
25
+ it('returns false for non-object', () => {
26
+ expect(isWorkflowConfig('string')).toBe(false);
27
+ expect(isWorkflowConfig(42)).toBe(false);
28
+ });
29
+
30
+ it('returns false when version != 1', () => {
31
+ expect(isWorkflowConfig({ ...MINIMAL_CONFIG, version: 2 })).toBe(false);
32
+ });
33
+
34
+ it('returns false when lists is not an array', () => {
35
+ expect(isWorkflowConfig({ ...MINIMAL_CONFIG, lists: 'not-array' })).toBe(false);
36
+ });
37
+
38
+ it('returns false when name is not a string', () => {
39
+ expect(isWorkflowConfig({ ...MINIMAL_CONFIG, name: 123 })).toBe(false);
40
+ });
41
+
42
+ it('returns false when branchingMode is invalid', () => {
43
+ expect(isWorkflowConfig({ ...MINIMAL_CONFIG, branchingMode: 'invalid' })).toBe(false);
44
+ });
45
+
46
+ it('returns true when branchingMode is trunk or worktree', () => {
47
+ expect(isWorkflowConfig({ ...MINIMAL_CONFIG, branchingMode: 'trunk' })).toBe(true);
48
+ expect(isWorkflowConfig({ ...MINIMAL_CONFIG, branchingMode: 'worktree' })).toBe(true);
49
+ });
50
+ });
51
+
52
+ describe('isWorkflowList()', () => {
53
+ const validList = MINIMAL_CONFIG.lists[0];
54
+
55
+ it('returns true for valid list', () => {
56
+ expect(isWorkflowList(validList)).toBe(true);
57
+ });
58
+
59
+ it('returns false for non-object', () => {
60
+ expect(isWorkflowList(null)).toBe(false);
61
+ expect(isWorkflowList('string')).toBe(false);
62
+ });
63
+
64
+ it('returns false when missing required fields', () => {
65
+ expect(isWorkflowList({ id: 'a', label: 'A' })).toBe(false); // missing order, color, hex, hasDirectory
66
+ });
67
+
68
+ it('returns true with optional fields present', () => {
69
+ expect(isWorkflowList({ ...validList, gitBranch: 'main', sessionKey: 'test' })).toBe(true);
70
+ });
71
+ });
72
+
73
+ describe('isWorkflowEdge()', () => {
74
+ const validEdge = MINIMAL_CONFIG.edges[0];
75
+
76
+ it('returns true for valid edge', () => {
77
+ expect(isWorkflowEdge(validEdge)).toBe(true);
78
+ });
79
+
80
+ it('returns false for non-object', () => {
81
+ expect(isWorkflowEdge(null)).toBe(false);
82
+ expect(isWorkflowEdge(42)).toBe(false);
83
+ });
84
+
85
+ it('returns false when missing required string fields', () => {
86
+ expect(isWorkflowEdge({ from: 'a', to: 'b' })).toBe(false); // missing direction, label, description
87
+ });
88
+ });
89
+
90
+ describe('getHookEnforcement()', () => {
91
+ const makeHook = (category: string): WorkflowHook => ({
92
+ id: 'test', label: 'Test', timing: 'before', type: 'shell',
93
+ target: 'test.sh', category: category as WorkflowHook['category'],
94
+ });
95
+
96
+ it('guard -> blocker', () => {
97
+ expect(getHookEnforcement(makeHook('guard'))).toBe('blocker');
98
+ });
99
+
100
+ it('gate -> advisor', () => {
101
+ expect(getHookEnforcement(makeHook('gate'))).toBe('advisor');
102
+ });
103
+
104
+ it('lifecycle -> operator', () => {
105
+ expect(getHookEnforcement(makeHook('lifecycle'))).toBe('operator');
106
+ });
107
+
108
+ it('observer -> silent', () => {
109
+ expect(getHookEnforcement(makeHook('observer'))).toBe('silent');
110
+ });
111
+ });
@@ -59,6 +59,9 @@ export interface WorkflowConfig {
59
59
  commitBranchPatterns?: string;
60
60
  }
61
61
 
62
+ /** Semantic phase for All Projects normalization */
63
+ export type Phase = 'queued' | 'active' | 'review' | 'shipped';
64
+
62
65
  export interface WorkflowList {
63
66
  id: string;
64
67
  label: string;
@@ -73,6 +76,8 @@ export interface WorkflowList {
73
76
  gitBranch?: string;
74
77
  sessionKey?: string;
75
78
  activeHooks?: string[];
79
+ /** Semantic phase for All Projects normalization. Inferred from group/sessionKey if omitted. */
80
+ phase?: Phase;
76
81
  }
77
82
 
78
83
  export interface WorkflowEdge {
@@ -87,6 +92,8 @@ export interface WorkflowEdge {
87
92
  skipServerTransition?: boolean;
88
93
  dispatchOnly?: boolean;
89
94
  humanOnly?: boolean;
95
+ /** When true, revert scope status to `from` if the dispatch session is abandoned */
96
+ autoRevert?: boolean;
90
97
  hooks?: string[];
91
98
  agents?: string[];
92
99
  }