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.
- package/README.md +67 -42
- package/bin/commands/config.js +19 -0
- package/bin/commands/events.js +40 -0
- package/bin/commands/launch.js +126 -0
- package/bin/commands/manifest.js +283 -0
- package/bin/commands/registry.js +104 -0
- package/bin/commands/update.js +24 -0
- package/bin/lib/helpers.js +229 -0
- package/bin/orbital.js +147 -319
- package/dist/assets/Landing-CfQdHR0N.js +11 -0
- package/dist/assets/PrimitivesConfig-DThSipFy.js +32 -0
- package/dist/assets/QualityGates-B4kxM5UU.js +26 -0
- package/dist/assets/SessionTimeline-Bz1iZnmg.js +1 -0
- package/dist/assets/Settings-DLcZwbCT.js +12 -0
- package/dist/assets/SourceControl-BMNIz7Lt.js +36 -0
- package/dist/assets/WorkflowVisualizer-CxuSBOYu.js +69 -0
- package/dist/assets/arrow-down-DVPp6_qp.js +6 -0
- package/dist/assets/bot-NFaJBDn_.js +6 -0
- package/dist/assets/charts-LGLb8hyU.js +68 -0
- package/dist/assets/circle-x-IsFCkBZu.js +6 -0
- package/dist/assets/file-text-J1cebZXF.js +6 -0
- package/dist/assets/globe-WzeyHsUc.js +6 -0
- package/dist/assets/index-BdJ57EhC.css +1 -0
- package/dist/assets/index-o4ScMAuR.js +349 -0
- package/dist/assets/key-CKR8JJSj.js +6 -0
- package/dist/assets/minus-CHBsJyjp.js +6 -0
- package/dist/assets/radio-xqZaR-Uk.js +6 -0
- package/dist/assets/rocket-D_xvvNG6.js +6 -0
- package/dist/assets/shield-TdB1yv_a.js +6 -0
- package/dist/assets/ui-BmsSg9jU.js +53 -0
- package/dist/assets/useSocketListener-0L5yiN5i.js +1 -0
- package/dist/assets/useWorkflowEditor-CqeRWVQX.js +11 -0
- package/dist/assets/{vendor-Dzv9lrRc.js → vendor-Bqt8AJn2.js} +1 -1
- package/dist/assets/workflow-constants-Rw-GmgHZ.js +6 -0
- package/dist/assets/zap-C9wqYMpl.js +6 -0
- package/dist/favicon.svg +1 -0
- package/dist/index.html +6 -5
- package/dist/server/server/__tests__/data-routes.test.js +126 -0
- package/dist/server/server/__tests__/helpers/db.js +17 -0
- package/dist/server/server/__tests__/helpers/mock-emitter.js +8 -0
- package/dist/server/server/__tests__/scope-routes.test.js +138 -0
- package/dist/server/server/__tests__/sprint-routes.test.js +102 -0
- package/dist/server/server/__tests__/workflow-routes.test.js +107 -0
- package/dist/server/server/config-migrator.js +135 -0
- package/dist/server/server/config.js +51 -7
- package/dist/server/server/database.js +21 -28
- package/dist/server/server/global-config.js +143 -0
- package/dist/server/server/index.js +118 -276
- package/dist/server/server/init.js +243 -225
- package/dist/server/server/launch.js +29 -0
- package/dist/server/server/manifest-types.js +8 -0
- package/dist/server/server/manifest.js +454 -0
- package/dist/server/server/migrate-legacy.js +229 -0
- package/dist/server/server/parsers/event-parser.js +4 -1
- package/dist/server/server/parsers/event-parser.test.js +117 -0
- package/dist/server/server/parsers/scope-parser.js +74 -28
- package/dist/server/server/parsers/scope-parser.test.js +230 -0
- package/dist/server/server/project-context.js +265 -0
- package/dist/server/server/project-emitter.js +41 -0
- package/dist/server/server/project-manager.js +297 -0
- package/dist/server/server/routes/aggregate-routes.js +871 -0
- package/dist/server/server/routes/config-routes.js +41 -90
- package/dist/server/server/routes/data-routes.js +25 -123
- package/dist/server/server/routes/dispatch-routes.js +37 -15
- package/dist/server/server/routes/git-routes.js +74 -0
- package/dist/server/server/routes/manifest-routes.js +319 -0
- package/dist/server/server/routes/scope-routes.js +45 -28
- package/dist/server/server/routes/sync-routes.js +134 -0
- package/dist/server/server/routes/version-routes.js +1 -15
- package/dist/server/server/routes/workflow-routes.js +9 -3
- package/dist/server/server/schema.js +3 -0
- package/dist/server/server/services/batch-orchestrator.js +41 -17
- package/dist/server/server/services/claude-session-service.js +17 -14
- package/dist/server/server/services/config-service.js +10 -1
- package/dist/server/server/services/deploy-service.test.js +119 -0
- package/dist/server/server/services/event-service.js +64 -1
- package/dist/server/server/services/event-service.test.js +191 -0
- package/dist/server/server/services/gate-service.test.js +105 -0
- package/dist/server/server/services/git-service.js +108 -4
- package/dist/server/server/services/github-service.js +110 -2
- package/dist/server/server/services/readiness-service.test.js +190 -0
- package/dist/server/server/services/scope-cache.js +5 -1
- package/dist/server/server/services/scope-cache.test.js +142 -0
- package/dist/server/server/services/scope-service.js +222 -131
- package/dist/server/server/services/scope-service.test.js +137 -0
- package/dist/server/server/services/sprint-orchestrator.js +29 -15
- package/dist/server/server/services/sprint-service.js +23 -3
- package/dist/server/server/services/sprint-service.test.js +238 -0
- package/dist/server/server/services/sync-service.js +434 -0
- package/dist/server/server/services/sync-types.js +2 -0
- package/dist/server/server/services/workflow-service.js +26 -5
- package/dist/server/server/services/workflow-service.test.js +159 -0
- package/dist/server/server/settings-sync.js +284 -0
- package/dist/server/server/uninstall.js +195 -0
- package/dist/server/server/update-planner.js +279 -0
- package/dist/server/server/update.js +212 -0
- package/dist/server/server/utils/cc-hooks-parser.js +3 -0
- package/dist/server/server/utils/cc-hooks-parser.test.js +86 -0
- package/dist/server/server/utils/dispatch-utils.js +83 -24
- package/dist/server/server/utils/dispatch-utils.test.js +182 -0
- package/dist/server/server/utils/flag-builder.js +54 -0
- package/dist/server/server/utils/json-fields.js +14 -0
- package/dist/server/server/utils/json-fields.test.js +73 -0
- package/dist/server/server/utils/logger.js +37 -3
- package/dist/server/server/utils/package-info.js +30 -0
- package/dist/server/server/utils/route-helpers.js +47 -0
- package/dist/server/server/utils/route-helpers.test.js +115 -0
- package/dist/server/server/utils/terminal-launcher.js +79 -25
- package/dist/server/server/utils/worktree-manager.js +13 -4
- package/dist/server/server/validator.js +230 -0
- package/dist/server/server/watchers/event-watcher.js +28 -13
- package/dist/server/server/watchers/global-watcher.js +63 -0
- package/dist/server/server/watchers/scope-watcher.js +27 -12
- package/dist/server/server/wizard/config-editor.js +237 -0
- package/dist/server/server/wizard/detect.js +96 -0
- package/dist/server/server/wizard/doctor.js +115 -0
- package/dist/server/server/wizard/index.js +340 -0
- package/dist/server/server/wizard/phases/confirm.js +39 -0
- package/dist/server/server/wizard/phases/project-setup.js +90 -0
- package/dist/server/server/wizard/phases/setup-wizard.js +66 -0
- package/dist/server/server/wizard/phases/welcome.js +32 -0
- package/dist/server/server/wizard/phases/workflow-setup.js +22 -0
- package/dist/server/server/wizard/types.js +29 -0
- package/dist/server/server/wizard/ui.js +73 -0
- package/dist/server/shared/__fixtures__/workflow-configs.js +75 -0
- package/dist/server/shared/api-types.js +80 -1
- package/dist/server/shared/default-workflow.json +65 -0
- package/dist/server/shared/onboarding-tour.test.js +81 -0
- package/dist/server/shared/project-colors.js +24 -0
- package/dist/server/shared/workflow-config.test.js +84 -0
- package/dist/server/shared/workflow-engine.js +1 -1
- package/dist/server/shared/workflow-engine.test.js +302 -0
- package/dist/server/shared/workflow-normalizer.js +101 -0
- package/dist/server/shared/workflow-normalizer.test.js +100 -0
- package/dist/server/src/components/onboarding/tour-steps.js +84 -0
- package/package.json +34 -29
- package/schemas/orbital.config.schema.json +2 -5
- package/scripts/postinstall.js +18 -6
- package/scripts/release.sh +53 -0
- package/server/__tests__/data-routes.test.ts +151 -0
- package/server/__tests__/helpers/db.ts +19 -0
- package/server/__tests__/helpers/mock-emitter.ts +10 -0
- package/server/__tests__/scope-routes.test.ts +158 -0
- package/server/__tests__/sprint-routes.test.ts +118 -0
- package/server/__tests__/workflow-routes.test.ts +120 -0
- package/server/config-migrator.ts +160 -0
- package/server/config.ts +64 -12
- package/server/database.ts +22 -31
- package/server/global-config.ts +204 -0
- package/server/index.ts +139 -316
- package/server/init.ts +266 -234
- package/server/launch.ts +32 -0
- package/server/manifest-types.ts +145 -0
- package/server/manifest.ts +494 -0
- package/server/migrate-legacy.ts +290 -0
- package/server/parsers/event-parser.test.ts +135 -0
- package/server/parsers/event-parser.ts +4 -1
- package/server/parsers/scope-parser.test.ts +270 -0
- package/server/parsers/scope-parser.ts +79 -31
- package/server/project-context.ts +325 -0
- package/server/project-emitter.ts +50 -0
- package/server/project-manager.ts +368 -0
- package/server/routes/aggregate-routes.ts +968 -0
- package/server/routes/config-routes.ts +43 -85
- package/server/routes/data-routes.ts +34 -156
- package/server/routes/dispatch-routes.ts +46 -17
- package/server/routes/git-routes.ts +77 -0
- package/server/routes/manifest-routes.ts +388 -0
- package/server/routes/scope-routes.ts +39 -30
- package/server/routes/sync-routes.ts +175 -0
- package/server/routes/version-routes.ts +1 -16
- package/server/routes/workflow-routes.ts +9 -3
- package/server/schema.ts +3 -0
- package/server/services/batch-orchestrator.ts +41 -17
- package/server/services/claude-session-service.ts +16 -14
- package/server/services/config-service.ts +10 -1
- package/server/services/deploy-service.test.ts +145 -0
- package/server/services/deploy-service.ts +2 -2
- package/server/services/event-service.test.ts +242 -0
- package/server/services/event-service.ts +92 -3
- package/server/services/gate-service.test.ts +131 -0
- package/server/services/gate-service.ts +2 -2
- package/server/services/git-service.ts +137 -4
- package/server/services/github-service.ts +120 -2
- package/server/services/readiness-service.test.ts +217 -0
- package/server/services/scope-cache.test.ts +167 -0
- package/server/services/scope-cache.ts +4 -1
- package/server/services/scope-service.test.ts +169 -0
- package/server/services/scope-service.ts +224 -130
- package/server/services/sprint-orchestrator.ts +30 -15
- package/server/services/sprint-service.test.ts +271 -0
- package/server/services/sprint-service.ts +29 -5
- package/server/services/sync-service.ts +482 -0
- package/server/services/sync-types.ts +77 -0
- package/server/services/workflow-service.test.ts +190 -0
- package/server/services/workflow-service.ts +29 -9
- package/server/settings-sync.ts +359 -0
- package/server/uninstall.ts +214 -0
- package/server/update-planner.ts +346 -0
- package/server/update.ts +263 -0
- package/server/utils/cc-hooks-parser.test.ts +96 -0
- package/server/utils/cc-hooks-parser.ts +4 -0
- package/server/utils/dispatch-utils.test.ts +245 -0
- package/server/utils/dispatch-utils.ts +102 -30
- package/server/utils/flag-builder.ts +56 -0
- package/server/utils/json-fields.test.ts +83 -0
- package/server/utils/json-fields.ts +14 -0
- package/server/utils/logger.ts +40 -3
- package/server/utils/package-info.ts +32 -0
- package/server/utils/route-helpers.test.ts +144 -0
- package/server/utils/route-helpers.ts +50 -0
- package/server/utils/terminal-launcher.ts +85 -25
- package/server/utils/worktree-manager.ts +9 -4
- package/server/validator.ts +270 -0
- package/server/watchers/event-watcher.ts +24 -12
- package/server/watchers/global-watcher.ts +77 -0
- package/server/watchers/scope-watcher.ts +21 -9
- package/server/wizard/config-editor.ts +248 -0
- package/server/wizard/detect.ts +104 -0
- package/server/wizard/doctor.ts +114 -0
- package/server/wizard/index.ts +438 -0
- package/server/wizard/phases/confirm.ts +45 -0
- package/server/wizard/phases/project-setup.ts +106 -0
- package/server/wizard/phases/setup-wizard.ts +78 -0
- package/server/wizard/phases/welcome.ts +39 -0
- package/server/wizard/phases/workflow-setup.ts +28 -0
- package/server/wizard/types.ts +56 -0
- package/server/wizard/ui.ts +92 -0
- package/shared/__fixtures__/workflow-configs.ts +80 -0
- package/shared/api-types.ts +106 -0
- package/shared/onboarding-tour.test.ts +94 -0
- package/shared/project-colors.ts +24 -0
- package/shared/workflow-config.test.ts +111 -0
- package/shared/workflow-config.ts +7 -0
- package/shared/workflow-engine.test.ts +388 -0
- package/shared/workflow-engine.ts +1 -1
- package/shared/workflow-normalizer.test.ts +119 -0
- package/shared/workflow-normalizer.ts +118 -0
- package/templates/agents/QUICK-REFERENCE.md +1 -0
- package/templates/agents/README.md +1 -0
- package/templates/agents/SKILL-TRIGGERS.md +11 -0
- package/templates/agents/green-team/deep-dive.md +361 -0
- package/templates/hooks/end-session.sh +4 -1
- package/templates/hooks/init-session.sh +1 -0
- package/templates/hooks/orbital-emit.sh +2 -2
- package/templates/hooks/orbital-report-deploy.sh +4 -4
- package/templates/hooks/orbital-report-gates.sh +4 -4
- package/templates/hooks/orbital-scope-update.sh +1 -1
- package/templates/hooks/scope-commit-logger.sh +2 -2
- package/templates/hooks/scope-create-cleanup.sh +2 -2
- package/templates/hooks/scope-create-gate.sh +2 -5
- package/templates/hooks/scope-gate.sh +4 -6
- package/templates/hooks/scope-helpers.sh +28 -1
- package/templates/hooks/scope-lifecycle-gate.sh +14 -5
- package/templates/hooks/scope-prepare.sh +67 -12
- package/templates/hooks/scope-transition.sh +14 -6
- package/templates/hooks/time-tracker.sh +2 -5
- package/templates/migrations/renames.json +1 -0
- package/templates/orbital.config.json +8 -6
- package/{shared/default-workflow.json → templates/presets/default.json} +65 -0
- package/templates/presets/development.json +4 -4
- package/templates/presets/gitflow.json +7 -0
- package/templates/prompts/README.md +23 -0
- package/templates/prompts/deep-dive-audit.md +94 -0
- package/templates/quick/rules.md +56 -5
- package/templates/settings-hooks.json +1 -1
- package/templates/skills/git-commit/SKILL.md +27 -7
- package/templates/skills/git-dev/SKILL.md +13 -4
- package/templates/skills/git-main/SKILL.md +13 -3
- package/templates/skills/git-production/SKILL.md +9 -2
- package/templates/skills/git-staging/SKILL.md +11 -3
- package/templates/skills/scope-create/SKILL.md +17 -3
- package/templates/skills/scope-fix-review/SKILL.md +14 -7
- package/templates/skills/scope-implement/SKILL.md +15 -4
- package/templates/skills/scope-post-review/SKILL.md +77 -7
- package/templates/skills/scope-pre-review/SKILL.md +11 -4
- package/templates/skills/scope-verify/SKILL.md +5 -3
- package/templates/skills/test-code-review/SKILL.md +41 -33
- package/templates/skills/test-scaffold/SKILL.md +222 -0
- package/dist/assets/WorkflowVisualizer-BZ21PIIF.js +0 -84
- package/dist/assets/charts-D__PA1zp.js +0 -72
- package/dist/assets/index-D1G6i0nS.css +0 -1
- package/dist/assets/index-DpItvKpf.js +0 -419
- package/dist/assets/ui-BvF022GT.js +0 -53
- package/index.html +0 -15
- package/postcss.config.js +0 -6
- package/src/App.tsx +0 -33
- package/src/components/AgentBadge.tsx +0 -40
- package/src/components/BatchPreflightModal.tsx +0 -115
- package/src/components/CardDisplayToggle.tsx +0 -74
- package/src/components/ColumnHeaderActions.tsx +0 -55
- package/src/components/ColumnMenu.tsx +0 -99
- package/src/components/DeployHistory.tsx +0 -141
- package/src/components/DispatchModal.tsx +0 -164
- package/src/components/DispatchPopover.tsx +0 -139
- package/src/components/DragOverlay.tsx +0 -25
- package/src/components/DriftSidebar.tsx +0 -140
- package/src/components/EnvironmentStrip.tsx +0 -88
- package/src/components/ErrorBoundary.tsx +0 -62
- package/src/components/FilterChip.tsx +0 -105
- package/src/components/GateIndicator.tsx +0 -33
- package/src/components/IdeaDetailModal.tsx +0 -190
- package/src/components/IdeaFormDialog.tsx +0 -113
- package/src/components/KanbanColumn.tsx +0 -201
- package/src/components/MarkdownRenderer.tsx +0 -114
- package/src/components/NeonGrid.tsx +0 -128
- package/src/components/PromotionQueue.tsx +0 -89
- package/src/components/ScopeCard.tsx +0 -234
- package/src/components/ScopeDetailModal.tsx +0 -255
- package/src/components/ScopeFilterBar.tsx +0 -152
- package/src/components/SearchInput.tsx +0 -102
- package/src/components/SessionPanel.tsx +0 -335
- package/src/components/SprintContainer.tsx +0 -303
- package/src/components/SprintDependencyDialog.tsx +0 -78
- package/src/components/SprintPreflightModal.tsx +0 -138
- package/src/components/StatusBar.tsx +0 -168
- package/src/components/SwimCell.tsx +0 -67
- package/src/components/SwimLaneRow.tsx +0 -94
- package/src/components/SwimlaneBoardView.tsx +0 -108
- package/src/components/VersionBadge.tsx +0 -139
- package/src/components/ViewModeSelector.tsx +0 -114
- package/src/components/config/AgentChip.tsx +0 -53
- package/src/components/config/AgentCreateDialog.tsx +0 -321
- package/src/components/config/AgentEditor.tsx +0 -175
- package/src/components/config/DirectoryTree.tsx +0 -582
- package/src/components/config/FileEditor.tsx +0 -550
- package/src/components/config/HookChip.tsx +0 -50
- package/src/components/config/StageCard.tsx +0 -198
- package/src/components/config/TransitionZone.tsx +0 -173
- package/src/components/config/UnifiedWorkflowPipeline.tsx +0 -216
- package/src/components/config/WorkflowPipeline.tsx +0 -161
- package/src/components/source-control/BranchList.tsx +0 -93
- package/src/components/source-control/BranchPanel.tsx +0 -105
- package/src/components/source-control/CommitLog.tsx +0 -100
- package/src/components/source-control/CommitRow.tsx +0 -47
- package/src/components/source-control/GitHubPanel.tsx +0 -110
- package/src/components/source-control/GitHubSetupGuide.tsx +0 -52
- package/src/components/source-control/GitOverviewBar.tsx +0 -101
- package/src/components/source-control/PullRequestList.tsx +0 -69
- package/src/components/source-control/WorktreeList.tsx +0 -80
- package/src/components/ui/badge.tsx +0 -41
- package/src/components/ui/button.tsx +0 -55
- package/src/components/ui/card.tsx +0 -78
- package/src/components/ui/dialog.tsx +0 -94
- package/src/components/ui/popover.tsx +0 -33
- package/src/components/ui/scroll-area.tsx +0 -54
- package/src/components/ui/separator.tsx +0 -28
- package/src/components/ui/tabs.tsx +0 -52
- package/src/components/ui/toggle-switch.tsx +0 -35
- package/src/components/ui/tooltip.tsx +0 -27
- package/src/components/workflow/AddEdgeDialog.tsx +0 -217
- package/src/components/workflow/AddListDialog.tsx +0 -201
- package/src/components/workflow/ChecklistEditor.tsx +0 -239
- package/src/components/workflow/CommandPrefixManager.tsx +0 -118
- package/src/components/workflow/ConfigSettingsPanel.tsx +0 -189
- package/src/components/workflow/DirectionSelector.tsx +0 -133
- package/src/components/workflow/DispatchConfigPanel.tsx +0 -180
- package/src/components/workflow/EdgeDetailPanel.tsx +0 -236
- package/src/components/workflow/EdgePropertyEditor.tsx +0 -251
- package/src/components/workflow/EditToolbar.tsx +0 -138
- package/src/components/workflow/HookDetailPanel.tsx +0 -250
- package/src/components/workflow/HookExecutionLog.tsx +0 -24
- package/src/components/workflow/HookSourceModal.tsx +0 -129
- package/src/components/workflow/HooksDashboard.tsx +0 -363
- package/src/components/workflow/ListPropertyEditor.tsx +0 -251
- package/src/components/workflow/MigrationPreviewDialog.tsx +0 -237
- package/src/components/workflow/MovementRulesPanel.tsx +0 -188
- package/src/components/workflow/NodeDetailPanel.tsx +0 -245
- package/src/components/workflow/PresetSelector.tsx +0 -414
- package/src/components/workflow/SkillCommandBuilder.tsx +0 -174
- package/src/components/workflow/WorkflowEdgeComponent.tsx +0 -145
- package/src/components/workflow/WorkflowNode.tsx +0 -147
- package/src/components/workflow/graphLayout.ts +0 -186
- package/src/components/workflow/mergeHooks.ts +0 -85
- package/src/components/workflow/useEditHistory.ts +0 -88
- package/src/components/workflow/useWorkflowEditor.ts +0 -262
- package/src/components/workflow/validateConfig.ts +0 -70
- package/src/hooks/useActiveDispatches.ts +0 -198
- package/src/hooks/useBoardSettings.ts +0 -170
- package/src/hooks/useCardDisplay.ts +0 -57
- package/src/hooks/useCcHooks.ts +0 -24
- package/src/hooks/useConfigTree.ts +0 -51
- package/src/hooks/useEnforcementRules.ts +0 -46
- package/src/hooks/useEvents.ts +0 -59
- package/src/hooks/useFileEditor.ts +0 -165
- package/src/hooks/useGates.ts +0 -57
- package/src/hooks/useIdeaActions.ts +0 -53
- package/src/hooks/useKanbanDnd.ts +0 -410
- package/src/hooks/useOrbitalConfig.ts +0 -54
- package/src/hooks/usePipeline.ts +0 -47
- package/src/hooks/usePipelineData.ts +0 -338
- package/src/hooks/useReconnect.ts +0 -25
- package/src/hooks/useScopeFilters.ts +0 -125
- package/src/hooks/useScopeSessions.ts +0 -44
- package/src/hooks/useScopes.ts +0 -67
- package/src/hooks/useSearch.ts +0 -67
- package/src/hooks/useSettings.tsx +0 -187
- package/src/hooks/useSocket.ts +0 -25
- package/src/hooks/useSourceControl.ts +0 -105
- package/src/hooks/useSprintPreflight.ts +0 -55
- package/src/hooks/useSprints.ts +0 -154
- package/src/hooks/useStatusBarHighlight.ts +0 -18
- package/src/hooks/useSwimlaneBoardSettings.ts +0 -104
- package/src/hooks/useTheme.ts +0 -9
- package/src/hooks/useTransitionReadiness.ts +0 -53
- package/src/hooks/useVersion.ts +0 -155
- package/src/hooks/useViolations.ts +0 -65
- package/src/hooks/useWorkflow.tsx +0 -125
- package/src/hooks/useZoomModifier.ts +0 -19
- package/src/index.css +0 -797
- package/src/layouts/DashboardLayout.tsx +0 -113
- package/src/lib/collisionDetection.ts +0 -20
- package/src/lib/scope-fields.ts +0 -61
- package/src/lib/swimlane.ts +0 -146
- package/src/lib/utils.ts +0 -15
- package/src/main.tsx +0 -19
- package/src/socket.ts +0 -11
- package/src/types/index.ts +0 -497
- package/src/views/AgentFeed.tsx +0 -339
- package/src/views/DeployPipeline.tsx +0 -59
- package/src/views/EnforcementView.tsx +0 -378
- package/src/views/PrimitivesConfig.tsx +0 -500
- package/src/views/QualityGates.tsx +0 -1012
- package/src/views/ScopeBoard.tsx +0 -454
- package/src/views/SessionTimeline.tsx +0 -516
- package/src/views/Settings.tsx +0 -183
- package/src/views/SourceControl.tsx +0 -95
- package/src/views/WorkflowVisualizer.tsx +0 -382
- package/tailwind.config.js +0 -161
- package/tsconfig.json +0 -25
- package/vite.config.ts +0 -38
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, vi } from 'vitest';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import request from 'supertest';
|
|
4
|
+
import { createSprintRoutes } from '../routes/sprint-routes.js';
|
|
5
|
+
|
|
6
|
+
describe('sprint-routes', () => {
|
|
7
|
+
let app: express.Express;
|
|
8
|
+
|
|
9
|
+
const mockSprintService = {
|
|
10
|
+
create: vi.fn().mockReturnValue({ id: 1, name: 'Sprint 1', status: 'assembling', scope_ids: [], scopes: [], layers: null, progress: { pending: 0, in_progress: 0, completed: 0, failed: 0, skipped: 0 } }),
|
|
11
|
+
getAll: vi.fn().mockReturnValue([]),
|
|
12
|
+
getById: vi.fn((id: number) => id === 1 ? { id: 1, name: 'Sprint 1', status: 'assembling', scope_ids: [], scopes: [] } : null),
|
|
13
|
+
rename: vi.fn().mockReturnValue(true),
|
|
14
|
+
delete: vi.fn().mockReturnValue(true),
|
|
15
|
+
addScopes: vi.fn().mockReturnValue({ added: [1, 2], unmet_dependencies: [] }),
|
|
16
|
+
removeScopes: vi.fn().mockReturnValue(true),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const mockSprintOrchestrator = {
|
|
20
|
+
startSprint: vi.fn().mockReturnValue({ ok: true, layers: [[1], [2]] }),
|
|
21
|
+
cancelSprint: vi.fn().mockReturnValue({ ok: true }),
|
|
22
|
+
getExecutionGraph: vi.fn().mockReturnValue({ nodes: [], edges: [] }),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const mockBatchOrchestrator = {
|
|
26
|
+
dispatch: vi.fn().mockReturnValue({ ok: true }),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
beforeAll(() => {
|
|
30
|
+
const router = createSprintRoutes({
|
|
31
|
+
sprintService: mockSprintService as any,
|
|
32
|
+
sprintOrchestrator: mockSprintOrchestrator as any,
|
|
33
|
+
batchOrchestrator: mockBatchOrchestrator as any,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
app = express();
|
|
37
|
+
app.use(express.json());
|
|
38
|
+
app.use('/api/orbital', router);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe('POST /sprints', () => {
|
|
42
|
+
it('creates sprint with name (201)', async () => {
|
|
43
|
+
const res = await request(app)
|
|
44
|
+
.post('/api/orbital/sprints')
|
|
45
|
+
.send({ name: 'New Sprint' });
|
|
46
|
+
expect(res.status).toBe(201);
|
|
47
|
+
expect(mockSprintService.create).toHaveBeenCalledWith('New Sprint', expect.anything());
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('rejects empty name (400)', async () => {
|
|
51
|
+
const res = await request(app)
|
|
52
|
+
.post('/api/orbital/sprints')
|
|
53
|
+
.send({ name: ' ' });
|
|
54
|
+
expect(res.status).toBe(400);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('GET /sprints', () => {
|
|
59
|
+
it('returns sprint list', async () => {
|
|
60
|
+
const res = await request(app).get('/api/orbital/sprints');
|
|
61
|
+
expect(res.status).toBe(200);
|
|
62
|
+
expect(Array.isArray(res.body)).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('passes status filter', async () => {
|
|
66
|
+
await request(app).get('/api/orbital/sprints?status=assembling');
|
|
67
|
+
expect(mockSprintService.getAll).toHaveBeenCalledWith('assembling', undefined);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('PATCH /sprints/:id', () => {
|
|
72
|
+
it('renames sprint', async () => {
|
|
73
|
+
const res = await request(app)
|
|
74
|
+
.patch('/api/orbital/sprints/1')
|
|
75
|
+
.send({ name: 'Renamed' });
|
|
76
|
+
expect(res.status).toBe(200);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('rejects missing name (400)', async () => {
|
|
80
|
+
const res = await request(app)
|
|
81
|
+
.patch('/api/orbital/sprints/1')
|
|
82
|
+
.send({});
|
|
83
|
+
expect(res.status).toBe(400);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('DELETE /sprints/:id', () => {
|
|
88
|
+
it('deletes sprint', async () => {
|
|
89
|
+
const res = await request(app).delete('/api/orbital/sprints/1');
|
|
90
|
+
expect(res.status).toBe(200);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('POST /sprints/:id/scopes', () => {
|
|
95
|
+
it('adds scopes to sprint', async () => {
|
|
96
|
+
const res = await request(app)
|
|
97
|
+
.post('/api/orbital/sprints/1/scopes')
|
|
98
|
+
.send({ scope_ids: [1, 2] });
|
|
99
|
+
expect(res.status).toBe(200);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('rejects empty scope_ids (400)', async () => {
|
|
103
|
+
const res = await request(app)
|
|
104
|
+
.post('/api/orbital/sprints/1/scopes')
|
|
105
|
+
.send({ scope_ids: [] });
|
|
106
|
+
expect(res.status).toBe(400);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('POST /sprints/:id/dispatch', () => {
|
|
111
|
+
it('dispatches sprint', async () => {
|
|
112
|
+
const res = await request(app)
|
|
113
|
+
.post('/api/orbital/sprints/1/dispatch')
|
|
114
|
+
.send({});
|
|
115
|
+
expect(res.status).toBe(200);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll, vi } from 'vitest';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import request from 'supertest';
|
|
4
|
+
import { createWorkflowRoutes } from '../routes/workflow-routes.js';
|
|
5
|
+
import { WorkflowEngine } from '../../shared/workflow-engine.js';
|
|
6
|
+
import { DEFAULT_CONFIG, MINIMAL_CONFIG } from '../../shared/__fixtures__/workflow-configs.js';
|
|
7
|
+
|
|
8
|
+
describe('workflow-routes', () => {
|
|
9
|
+
let app: express.Express;
|
|
10
|
+
const engine = new WorkflowEngine(DEFAULT_CONFIG);
|
|
11
|
+
|
|
12
|
+
const mockWorkflowService = {
|
|
13
|
+
getActive: vi.fn().mockReturnValue(DEFAULT_CONFIG),
|
|
14
|
+
updateActive: vi.fn().mockReturnValue({ valid: true, errors: [], warnings: [] }),
|
|
15
|
+
listPresets: vi.fn().mockReturnValue([{ name: 'default', createdAt: '2026-01-01', listCount: 7, edgeCount: 14 }]),
|
|
16
|
+
savePreset: vi.fn(),
|
|
17
|
+
getPreset: vi.fn((name: string) => name === 'default' ? DEFAULT_CONFIG : (() => { throw new Error('Not found'); })()),
|
|
18
|
+
deletePreset: vi.fn((name: string) => { if (name === 'default') throw new Error('Cannot delete default'); }),
|
|
19
|
+
previewMigration: vi.fn().mockReturnValue({ orphanedScopes: [], addedLists: [], removedLists: [], scopeMoves: [] }),
|
|
20
|
+
applyMigration: vi.fn().mockReturnValue({ orphanedScopes: [], addedLists: [], removedLists: [], scopeMoves: [] }),
|
|
21
|
+
getEngine: vi.fn().mockReturnValue(engine),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
beforeAll(() => {
|
|
25
|
+
const router = createWorkflowRoutes({
|
|
26
|
+
workflowService: mockWorkflowService as any,
|
|
27
|
+
projectRoot: '/tmp/test-project',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
app = express();
|
|
31
|
+
app.use(express.json());
|
|
32
|
+
app.use('/api/orbital', router);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('GET /workflow', () => {
|
|
36
|
+
it('returns active workflow config', async () => {
|
|
37
|
+
const res = await request(app).get('/api/orbital/workflow');
|
|
38
|
+
expect(res.status).toBe(200);
|
|
39
|
+
expect(res.body.success).toBe(true);
|
|
40
|
+
expect(res.body.data.name).toBe('Default Workflow');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('PUT /workflow', () => {
|
|
45
|
+
it('updates workflow config', async () => {
|
|
46
|
+
const res = await request(app)
|
|
47
|
+
.put('/api/orbital/workflow')
|
|
48
|
+
.send(MINIMAL_CONFIG);
|
|
49
|
+
expect(res.status).toBe(200);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('returns 400 for invalid config', async () => {
|
|
53
|
+
mockWorkflowService.updateActive.mockReturnValueOnce({ valid: false, errors: ['Missing lists'], warnings: [] });
|
|
54
|
+
const res = await request(app)
|
|
55
|
+
.put('/api/orbital/workflow')
|
|
56
|
+
.send({ version: 1, name: 'Bad', lists: [], edges: [] });
|
|
57
|
+
expect(res.status).toBe(400);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('GET /workflow/presets', () => {
|
|
62
|
+
it('returns preset list', async () => {
|
|
63
|
+
const res = await request(app).get('/api/orbital/workflow/presets');
|
|
64
|
+
expect(res.status).toBe(200);
|
|
65
|
+
expect(res.body.success).toBe(true);
|
|
66
|
+
expect(Array.isArray(res.body.data)).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('POST /workflow/presets', () => {
|
|
71
|
+
it('saves preset with valid name', async () => {
|
|
72
|
+
const res = await request(app)
|
|
73
|
+
.post('/api/orbital/workflow/presets')
|
|
74
|
+
.send({ name: 'my-preset' });
|
|
75
|
+
expect(res.status).toBe(200);
|
|
76
|
+
expect(mockWorkflowService.savePreset).toHaveBeenCalledWith('my-preset');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('rejects missing name (400)', async () => {
|
|
80
|
+
const res = await request(app)
|
|
81
|
+
.post('/api/orbital/workflow/presets')
|
|
82
|
+
.send({});
|
|
83
|
+
expect(res.status).toBe(400);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('DELETE /workflow/presets/:name', () => {
|
|
88
|
+
it('rejects deleting default preset', async () => {
|
|
89
|
+
const res = await request(app).delete('/api/orbital/workflow/presets/default');
|
|
90
|
+
expect(res.status).toBe(400);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('GET /workflow/hooks', () => {
|
|
95
|
+
it('returns hooks with edge mapping', async () => {
|
|
96
|
+
const res = await request(app).get('/api/orbital/workflow/hooks');
|
|
97
|
+
expect(res.status).toBe(200);
|
|
98
|
+
expect(res.body.success).toBe(true);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('GET /workflow/hooks/:id/source', () => {
|
|
103
|
+
it('rejects path traversal attempts', async () => {
|
|
104
|
+
// The engine has hooks with targets like '.claude/hooks/blocker-check.sh'
|
|
105
|
+
// Trying to traverse out should fail
|
|
106
|
+
const res = await request(app).get('/api/orbital/workflow/hooks/../../etc/passwd/source');
|
|
107
|
+
expect([400, 404]).toContain(res.status);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe('POST /workflow/preview', () => {
|
|
112
|
+
it('returns migration preview', async () => {
|
|
113
|
+
const res = await request(app)
|
|
114
|
+
.post('/api/orbital/workflow/preview')
|
|
115
|
+
.send(MINIMAL_CONFIG);
|
|
116
|
+
expect(res.status).toBe(200);
|
|
117
|
+
expect(res.body.success).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config migration runner for orbital.config.json.
|
|
3
|
+
*
|
|
4
|
+
* Applies incremental, idempotent migrations when upgrading between
|
|
5
|
+
* package versions. Also fills schema defaults for new fields that
|
|
6
|
+
* don't require explicit migration logic.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import type { ConfigMigration } from './manifest-types.js';
|
|
11
|
+
|
|
12
|
+
// ─── Migration Registry ─────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* All config migrations, ordered by target version.
|
|
16
|
+
*
|
|
17
|
+
* Rules:
|
|
18
|
+
* - Each migration MUST be idempotent (safe to run twice)
|
|
19
|
+
* - Each migration MUST check before applying (don't blindly overwrite)
|
|
20
|
+
* - ID format: "fromVersion->toVersion"
|
|
21
|
+
*/
|
|
22
|
+
const MIGRATIONS: ConfigMigration[] = [
|
|
23
|
+
// Future migrations go here. Example:
|
|
24
|
+
// {
|
|
25
|
+
// id: '0.2.0->0.3.0',
|
|
26
|
+
// description: 'Add notifications config section',
|
|
27
|
+
// migrate: (config) => {
|
|
28
|
+
// if (!('notifications' in config)) {
|
|
29
|
+
// config.notifications = { enabled: false };
|
|
30
|
+
// }
|
|
31
|
+
// return config;
|
|
32
|
+
// },
|
|
33
|
+
// },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
// ─── Schema Defaults ────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
/** Default values from the schema, keyed by property path. */
|
|
39
|
+
const SCHEMA_DEFAULTS: Record<string, unknown> = {
|
|
40
|
+
projectName: 'My Project',
|
|
41
|
+
scopesDir: 'scopes',
|
|
42
|
+
eventsDir: '.claude/orbital-events',
|
|
43
|
+
dbDir: '.claude/orbital',
|
|
44
|
+
configDir: '.claude/config',
|
|
45
|
+
serverPort: 4444,
|
|
46
|
+
clientPort: 4445,
|
|
47
|
+
logLevel: 'info',
|
|
48
|
+
categories: ['feature', 'bugfix', 'refactor', 'infrastructure', 'docs'],
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const NESTED_DEFAULTS: Record<string, Record<string, unknown>> = {
|
|
52
|
+
terminal: {
|
|
53
|
+
adapter: 'auto',
|
|
54
|
+
profilePrefix: 'Orbital',
|
|
55
|
+
},
|
|
56
|
+
claude: {
|
|
57
|
+
executable: 'claude',
|
|
58
|
+
flags: ['--dangerously-skip-permissions'],
|
|
59
|
+
},
|
|
60
|
+
commands: {
|
|
61
|
+
typeCheck: null,
|
|
62
|
+
lint: null,
|
|
63
|
+
build: null,
|
|
64
|
+
test: null,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// ─── Public API ─────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
export interface MigrationResult {
|
|
71
|
+
applied: string[];
|
|
72
|
+
defaultsFilled: string[];
|
|
73
|
+
errors: string[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Run all pending config migrations and fill schema defaults.
|
|
78
|
+
*
|
|
79
|
+
* @param configPath - Path to orbital.config.json
|
|
80
|
+
* @param appliedMigrations - IDs already recorded in the manifest
|
|
81
|
+
* @returns List of migration IDs that were applied
|
|
82
|
+
*/
|
|
83
|
+
export function migrateConfig(
|
|
84
|
+
configPath: string,
|
|
85
|
+
appliedMigrations: string[],
|
|
86
|
+
): MigrationResult {
|
|
87
|
+
const result: MigrationResult = { applied: [], defaultsFilled: [], errors: [] };
|
|
88
|
+
|
|
89
|
+
if (!fs.existsSync(configPath)) return result;
|
|
90
|
+
|
|
91
|
+
let config: Record<string, unknown>;
|
|
92
|
+
try {
|
|
93
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
94
|
+
} catch {
|
|
95
|
+
result.errors.push('Failed to parse orbital.config.json');
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const appliedSet = new Set(appliedMigrations);
|
|
100
|
+
|
|
101
|
+
// Apply explicit migrations in order
|
|
102
|
+
for (const migration of MIGRATIONS) {
|
|
103
|
+
if (appliedSet.has(migration.id)) continue;
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
config = migration.migrate(config);
|
|
107
|
+
result.applied.push(migration.id);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
result.errors.push(`Migration ${migration.id} failed: ${String(err)}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Fill schema defaults for missing top-level properties
|
|
114
|
+
for (const [key, defaultValue] of Object.entries(SCHEMA_DEFAULTS)) {
|
|
115
|
+
if (!(key in config)) {
|
|
116
|
+
config[key] = defaultValue;
|
|
117
|
+
result.defaultsFilled.push(key);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Fill nested defaults
|
|
122
|
+
for (const [section, defaults] of Object.entries(NESTED_DEFAULTS)) {
|
|
123
|
+
if (!(section in config)) {
|
|
124
|
+
config[section] = { ...defaults };
|
|
125
|
+
result.defaultsFilled.push(section);
|
|
126
|
+
} else if (typeof config[section] === 'object' && config[section] !== null) {
|
|
127
|
+
const sectionObj = config[section] as Record<string, unknown>;
|
|
128
|
+
for (const [key, defaultValue] of Object.entries(defaults)) {
|
|
129
|
+
if (!(key in sectionObj)) {
|
|
130
|
+
sectionObj[key] = defaultValue;
|
|
131
|
+
result.defaultsFilled.push(`${section}.${key}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Write back if any changes were made
|
|
138
|
+
if (result.applied.length > 0 || result.defaultsFilled.length > 0) {
|
|
139
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get all migration IDs that haven't been applied yet.
|
|
147
|
+
*/
|
|
148
|
+
export function getPendingMigrations(appliedMigrations: string[]): string[] {
|
|
149
|
+
const appliedSet = new Set(appliedMigrations);
|
|
150
|
+
return MIGRATIONS
|
|
151
|
+
.filter(m => !appliedSet.has(m.id))
|
|
152
|
+
.map(m => m.id);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Get all registered migrations (for display/debug).
|
|
157
|
+
*/
|
|
158
|
+
export function getAllMigrations(): Array<{ id: string; description: string }> {
|
|
159
|
+
return MIGRATIONS.map(m => ({ id: m.id, description: m.description }));
|
|
160
|
+
}
|
package/server/config.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface TerminalConfig {
|
|
|
14
14
|
export interface ClaudeConfig {
|
|
15
15
|
executable: string;
|
|
16
16
|
flags: string[];
|
|
17
|
+
dispatchFlags: DispatchFlags;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export interface CommandsConfig {
|
|
@@ -21,13 +22,18 @@ export interface CommandsConfig {
|
|
|
21
22
|
lint: string | null;
|
|
22
23
|
build: string | null;
|
|
23
24
|
test: string | null;
|
|
24
|
-
validateTemplates: string | null;
|
|
25
|
-
validateDocs: string | null;
|
|
26
|
-
checkRules: string | null;
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
export type { AgentConfig } from '../shared/api-types.js';
|
|
30
|
-
import type { AgentConfig } from '../shared/api-types.js';
|
|
27
|
+
export type { AgentConfig, DispatchFlags, DispatchConfig } from '../shared/api-types.js';
|
|
28
|
+
import type { AgentConfig, DispatchFlags, DispatchConfig } from '../shared/api-types.js';
|
|
29
|
+
import { DEFAULT_DISPATCH_FLAGS, DEFAULT_DISPATCH_CONFIG } from '../shared/api-types.js';
|
|
30
|
+
import { loadGlobalConfig as loadGlobal } from './global-config.js';
|
|
31
|
+
|
|
32
|
+
export interface TelemetryConfig {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
url: string;
|
|
35
|
+
headers: Record<string, string>;
|
|
36
|
+
}
|
|
31
37
|
|
|
32
38
|
export interface OrbitalConfig {
|
|
33
39
|
projectName: string;
|
|
@@ -49,6 +55,9 @@ export interface OrbitalConfig {
|
|
|
49
55
|
// Claude Code CLI
|
|
50
56
|
claude: ClaudeConfig;
|
|
51
57
|
|
|
58
|
+
// Dispatch operational settings
|
|
59
|
+
dispatch: DispatchConfig;
|
|
60
|
+
|
|
52
61
|
// Build/test commands
|
|
53
62
|
commands: CommandsConfig;
|
|
54
63
|
|
|
@@ -58,6 +67,9 @@ export interface OrbitalConfig {
|
|
|
58
67
|
// Dynamic configuration
|
|
59
68
|
categories: string[];
|
|
60
69
|
agents: AgentConfig[];
|
|
70
|
+
|
|
71
|
+
// Telemetry
|
|
72
|
+
telemetry: TelemetryConfig;
|
|
61
73
|
}
|
|
62
74
|
|
|
63
75
|
// ─── Defaults ───────────────────────────────────────────────
|
|
@@ -77,22 +89,25 @@ const DEFAULT_CONFIG: Omit<OrbitalConfig, 'projectRoot'> = {
|
|
|
77
89
|
claude: {
|
|
78
90
|
executable: 'claude',
|
|
79
91
|
flags: ['--dangerously-skip-permissions'],
|
|
92
|
+
dispatchFlags: DEFAULT_DISPATCH_FLAGS,
|
|
80
93
|
},
|
|
94
|
+
dispatch: DEFAULT_DISPATCH_CONFIG,
|
|
81
95
|
commands: {
|
|
82
96
|
typeCheck: null,
|
|
83
97
|
lint: null,
|
|
84
98
|
build: null,
|
|
85
99
|
test: null,
|
|
86
|
-
validateTemplates: null,
|
|
87
|
-
validateDocs: null,
|
|
88
|
-
checkRules: null,
|
|
89
100
|
},
|
|
90
101
|
logLevel: 'info' as const,
|
|
102
|
+
telemetry: {
|
|
103
|
+
enabled: false,
|
|
104
|
+
url: '',
|
|
105
|
+
headers: {},
|
|
106
|
+
},
|
|
91
107
|
categories: ['feature', 'bugfix', 'refactor', 'infrastructure', 'docs'],
|
|
92
108
|
agents: [
|
|
93
109
|
{ id: 'attacker', label: 'Attacker', emoji: '\u{1F5E1}\u{FE0F}', color: '#ff1744' },
|
|
94
110
|
{ id: 'chaos', label: 'Chaos', emoji: '\u{1F4A5}', color: '#F97316' },
|
|
95
|
-
{ id: 'solana-expert', label: 'Solana Expert', emoji: '\u{26D3}\u{FE0F}', color: '#8B5CF6' },
|
|
96
111
|
{ id: 'frontend-designer', label: 'Frontend Designer', emoji: '\u{1F3A8}', color: '#EC4899' },
|
|
97
112
|
{ id: 'architect', label: 'Architect', emoji: '\u{1F3D7}\u{FE0F}', color: '#536dfe' },
|
|
98
113
|
{ id: 'rules-enforcer', label: 'Rules Enforcer', emoji: '\u{1F4CB}', color: '#6B7280' },
|
|
@@ -154,6 +169,15 @@ export function getClaudeSessionsDir(projectRoot: string): string {
|
|
|
154
169
|
export function loadConfig(projectRoot?: string): OrbitalConfig {
|
|
155
170
|
const root = projectRoot ?? resolveProjectRoot();
|
|
156
171
|
|
|
172
|
+
// Try loading edition overrides (e.g. edition.json at repo root)
|
|
173
|
+
const editionPath = path.join(root, 'edition.json');
|
|
174
|
+
let editionConfig: Record<string, unknown> = {};
|
|
175
|
+
if (fs.existsSync(editionPath)) {
|
|
176
|
+
try {
|
|
177
|
+
editionConfig = JSON.parse(fs.readFileSync(editionPath, 'utf-8'));
|
|
178
|
+
} catch { /* malformed edition.json — ignore */ }
|
|
179
|
+
}
|
|
180
|
+
|
|
157
181
|
// Try loading user config
|
|
158
182
|
const configPath = path.join(root, '.claude', 'orbital.config.json');
|
|
159
183
|
let userConfig: Record<string, unknown> = {};
|
|
@@ -168,8 +192,11 @@ export function loadConfig(projectRoot?: string): OrbitalConfig {
|
|
|
168
192
|
}
|
|
169
193
|
}
|
|
170
194
|
|
|
171
|
-
// Merge with defaults
|
|
172
|
-
const
|
|
195
|
+
// Merge with defaults — derive project name from directory if not configured
|
|
196
|
+
const defaultProjectName = path.basename(root)
|
|
197
|
+
.replace(/[-_]+/g, ' ')
|
|
198
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
199
|
+
const projectName = (userConfig.projectName as string) ?? defaultProjectName;
|
|
173
200
|
|
|
174
201
|
const scopesDir = path.resolve(root, (userConfig.scopesDir as string) ?? DEFAULT_CONFIG.scopesDir);
|
|
175
202
|
const eventsDir = path.resolve(root, (userConfig.eventsDir as string) ?? DEFAULT_CONFIG.eventsDir);
|
|
@@ -184,11 +211,26 @@ export function loadConfig(projectRoot?: string): OrbitalConfig {
|
|
|
184
211
|
...(userConfig.terminal as Partial<TerminalConfig> ?? {}),
|
|
185
212
|
};
|
|
186
213
|
|
|
214
|
+
// Global settings — seed from ~/.orbital/config.json
|
|
215
|
+
let globalDispatchFlags = DEFAULT_DISPATCH_FLAGS;
|
|
216
|
+
let globalDispatch = DEFAULT_DISPATCH_CONFIG;
|
|
217
|
+
let globalTelemetry: Partial<TelemetryConfig> = {};
|
|
218
|
+
try {
|
|
219
|
+
const global = loadGlobal();
|
|
220
|
+
if (global.dispatchFlags) globalDispatchFlags = { ...DEFAULT_DISPATCH_FLAGS, ...global.dispatchFlags };
|
|
221
|
+
if (global.dispatch) globalDispatch = { ...DEFAULT_DISPATCH_CONFIG, ...global.dispatch };
|
|
222
|
+
if (global.telemetry) globalTelemetry = global.telemetry;
|
|
223
|
+
} catch { /* global config may not exist yet */ }
|
|
224
|
+
|
|
225
|
+
const userClaude = (userConfig.claude as Partial<ClaudeConfig>) ?? {};
|
|
187
226
|
const claude: ClaudeConfig = {
|
|
188
227
|
...DEFAULT_CONFIG.claude,
|
|
189
|
-
...
|
|
228
|
+
...userClaude,
|
|
229
|
+
dispatchFlags: globalDispatchFlags,
|
|
190
230
|
};
|
|
191
231
|
|
|
232
|
+
const dispatch: DispatchConfig = globalDispatch;
|
|
233
|
+
|
|
192
234
|
const commands: CommandsConfig = {
|
|
193
235
|
...DEFAULT_CONFIG.commands,
|
|
194
236
|
...(userConfig.commands as Partial<CommandsConfig> ?? {}),
|
|
@@ -198,6 +240,14 @@ export function loadConfig(projectRoot?: string): OrbitalConfig {
|
|
|
198
240
|
const categories = (userConfig.categories as string[]) ?? DEFAULT_CONFIG.categories;
|
|
199
241
|
const agents = (userConfig.agents as AgentConfig[]) ?? DEFAULT_CONFIG.agents;
|
|
200
242
|
|
|
243
|
+
const telemetry: TelemetryConfig = {
|
|
244
|
+
...DEFAULT_CONFIG.telemetry,
|
|
245
|
+
...globalTelemetry,
|
|
246
|
+
...(editionConfig.telemetry as Partial<TelemetryConfig> ?? {}),
|
|
247
|
+
...(userConfig.telemetry as Partial<TelemetryConfig> ?? {}),
|
|
248
|
+
};
|
|
249
|
+
if (process.env.ORBITAL_TELEMETRY === 'false') telemetry.enabled = false;
|
|
250
|
+
|
|
201
251
|
return {
|
|
202
252
|
projectName,
|
|
203
253
|
projectRoot: root,
|
|
@@ -209,10 +259,12 @@ export function loadConfig(projectRoot?: string): OrbitalConfig {
|
|
|
209
259
|
clientPort,
|
|
210
260
|
terminal,
|
|
211
261
|
claude,
|
|
262
|
+
dispatch,
|
|
212
263
|
commands,
|
|
213
264
|
logLevel,
|
|
214
265
|
categories,
|
|
215
266
|
agents,
|
|
267
|
+
telemetry,
|
|
216
268
|
};
|
|
217
269
|
}
|
|
218
270
|
|
package/server/database.ts
CHANGED
|
@@ -2,39 +2,33 @@ import Database from 'better-sqlite3';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import { SCHEMA_DDL } from './schema.js';
|
|
5
|
-
import { getConfig } from './config.js';
|
|
6
5
|
import { createLogger } from './utils/logger.js';
|
|
7
6
|
|
|
8
7
|
const log = createLogger('database');
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
const config = getConfig();
|
|
12
|
-
return { dir: config.dbDir, file: path.join(config.dbDir, 'orbital.db') };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
let db: Database.Database | null = null;
|
|
16
|
-
|
|
17
|
-
export function getDatabase(): Database.Database {
|
|
18
|
-
if (db) return db;
|
|
9
|
+
// ─── Factory (multi-project) ────────────────────────────────
|
|
19
10
|
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Open a project-scoped SQLite database at the given directory.
|
|
13
|
+
* Creates the directory if needed, applies schema DDL and migrations.
|
|
14
|
+
*
|
|
15
|
+
* Each call returns a NEW connection — callers manage their own lifecycle.
|
|
16
|
+
*/
|
|
17
|
+
export function openProjectDatabase(dbDir: string): Database.Database {
|
|
18
|
+
fs.mkdirSync(dbDir, { recursive: true });
|
|
19
|
+
const file = path.join(dbDir, 'orbital.db');
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
const database = new Database(file);
|
|
24
22
|
log.info('Database initialized', { path: file });
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
db.pragma('foreign_keys = ON');
|
|
24
|
+
database.pragma('journal_mode = WAL');
|
|
25
|
+
database.pragma('synchronous = NORMAL');
|
|
26
|
+
database.pragma('foreign_keys = ON');
|
|
30
27
|
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
database.exec(SCHEMA_DDL);
|
|
29
|
+
runMigrations(database);
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
runMigrations(db);
|
|
36
|
-
|
|
37
|
-
return db;
|
|
31
|
+
return database;
|
|
38
32
|
}
|
|
39
33
|
|
|
40
34
|
/** Check if a table exists in the database */
|
|
@@ -59,6 +53,11 @@ function runMigrations(database: Database.Database): void {
|
|
|
59
53
|
database.exec('ALTER TABLE sessions ADD COLUMN action TEXT');
|
|
60
54
|
}
|
|
61
55
|
|
|
56
|
+
// Migration 9: Add telemetry_sent_at column to sessions
|
|
57
|
+
if (!sessionCols.some((c) => c.name === 'telemetry_sent_at')) {
|
|
58
|
+
database.exec('ALTER TABLE sessions ADD COLUMN telemetry_sent_at TEXT');
|
|
59
|
+
}
|
|
60
|
+
|
|
62
61
|
// Migration 8: Add batch group columns to sprints
|
|
63
62
|
const sprintCols = database.pragma('table_info(sprints)') as Array<{ name: string }>;
|
|
64
63
|
if (!sprintCols.some((c) => c.name === 'target_column')) {
|
|
@@ -97,11 +96,3 @@ function runMigrations(database: Database.Database): void {
|
|
|
97
96
|
`);
|
|
98
97
|
}
|
|
99
98
|
}
|
|
100
|
-
|
|
101
|
-
export function closeDatabase(): void {
|
|
102
|
-
if (db) {
|
|
103
|
-
db.close();
|
|
104
|
-
db = null;
|
|
105
|
-
log.debug('Database closed');
|
|
106
|
-
}
|
|
107
|
-
}
|