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
package/server/index.ts
CHANGED
|
@@ -4,91 +4,61 @@ import { Server } from 'socket.io';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
|
-
import { getDatabase, closeDatabase } from './database.js';
|
|
8
|
-
import { getConfig, resetConfig } from './config.js';
|
|
9
|
-
import { ScopeCache } from './services/scope-cache.js';
|
|
10
|
-
import { ScopeService } from './services/scope-service.js';
|
|
11
|
-
import { EventService } from './services/event-service.js';
|
|
12
|
-
import { GateService } from './services/gate-service.js';
|
|
13
|
-
import { DeployService } from './services/deploy-service.js';
|
|
14
|
-
import { SprintService } from './services/sprint-service.js';
|
|
15
|
-
import { SprintOrchestrator } from './services/sprint-orchestrator.js';
|
|
16
|
-
import { BatchOrchestrator } from './services/batch-orchestrator.js';
|
|
17
|
-
import { ReadinessService } from './services/readiness-service.js';
|
|
18
|
-
import { startScopeWatcher } from './watchers/scope-watcher.js';
|
|
19
|
-
import { startEventWatcher } from './watchers/event-watcher.js';
|
|
20
|
-
import { ensureDynamicProfiles } from './utils/terminal-launcher.js';
|
|
21
|
-
import { syncClaudeSessionsToDB } from './services/claude-session-service.js';
|
|
22
|
-
import { resolveStaleDispatches, resolveActiveDispatchesForScope, resolveDispatchesByPid, resolveDispatchesByDispatchId, linkPidToDispatch } from './utils/dispatch-utils.js';
|
|
23
|
-
import { createScopeRoutes } from './routes/scope-routes.js';
|
|
24
|
-
import { createDataRoutes } from './routes/data-routes.js';
|
|
25
|
-
import { createDispatchRoutes } from './routes/dispatch-routes.js';
|
|
26
|
-
import { createSprintRoutes } from './routes/sprint-routes.js';
|
|
27
|
-
import { createWorkflowRoutes } from './routes/workflow-routes.js';
|
|
28
|
-
import { createConfigRoutes } from './routes/config-routes.js';
|
|
29
|
-
import { createGitRoutes } from './routes/git-routes.js';
|
|
30
7
|
import { createVersionRoutes } from './routes/version-routes.js';
|
|
31
|
-
import {
|
|
32
|
-
import { GitService } from './services/git-service.js';
|
|
33
|
-
import { GitHubService } from './services/github-service.js';
|
|
34
|
-
import { WorkflowEngine } from '../shared/workflow-engine.js';
|
|
35
|
-
import defaultWorkflow from '../shared/default-workflow.json' with { type: 'json' };
|
|
36
|
-
import type { WorkflowConfig } from '../shared/workflow-config.js';
|
|
8
|
+
import { createAggregateRoutes } from './routes/aggregate-routes.js';
|
|
37
9
|
import { createLogger, setLogLevel } from './utils/logger.js';
|
|
38
10
|
import type { LogLevel } from './utils/logger.js';
|
|
39
11
|
|
|
40
12
|
import type http from 'http';
|
|
41
|
-
import type Database from 'better-sqlite3';
|
|
42
13
|
|
|
43
|
-
// ───
|
|
44
|
-
|
|
45
|
-
|
|
14
|
+
// ─── Central Server ─────────────────────────────────────────
|
|
15
|
+
|
|
16
|
+
import { ProjectManager } from './project-manager.js';
|
|
17
|
+
import { SyncService } from './services/sync-service.js';
|
|
18
|
+
import { startGlobalWatcher } from './watchers/global-watcher.js';
|
|
19
|
+
import { createSyncRoutes } from './routes/sync-routes.js';
|
|
20
|
+
import { seedGlobalPrimitives } from './init.js';
|
|
21
|
+
import {
|
|
22
|
+
ensureOrbitalHome,
|
|
23
|
+
loadGlobalConfig,
|
|
24
|
+
registerProject as registerProjectGlobal,
|
|
25
|
+
GLOBAL_PRIMITIVES_DIR,
|
|
26
|
+
ORBITAL_HOME,
|
|
27
|
+
} from './global-config.js';
|
|
28
|
+
|
|
29
|
+
export interface CentralServerOverrides {
|
|
46
30
|
port?: number;
|
|
47
|
-
|
|
31
|
+
clientPort?: number;
|
|
32
|
+
/** If set, auto-register this project on first launch */
|
|
33
|
+
autoRegisterPath?: string;
|
|
48
34
|
}
|
|
49
35
|
|
|
50
|
-
export interface
|
|
36
|
+
export interface CentralServerInstance {
|
|
51
37
|
app: express.Application;
|
|
52
38
|
io: Server;
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
projectManager: ProjectManager;
|
|
40
|
+
syncService: SyncService;
|
|
55
41
|
httpServer: http.Server;
|
|
56
42
|
shutdown: () => Promise<void>;
|
|
57
43
|
}
|
|
58
44
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
export async function startServer(overrides?: ServerOverrides): Promise<ServerInstance> {
|
|
62
|
-
// Apply project root override before config loads
|
|
63
|
-
if (overrides?.projectRoot) {
|
|
64
|
-
process.env.ORBITAL_PROJECT_ROOT = overrides.projectRoot;
|
|
65
|
-
resetConfig();
|
|
66
|
-
}
|
|
45
|
+
export async function startCentralServer(overrides?: CentralServerOverrides): Promise<CentralServerInstance> {
|
|
46
|
+
ensureOrbitalHome();
|
|
67
47
|
|
|
68
|
-
const config = getConfig();
|
|
69
48
|
const envLevel = process.env.ORBITAL_LOG_LEVEL;
|
|
70
49
|
if (envLevel && ['debug', 'info', 'warn', 'error'].includes(envLevel)) {
|
|
71
50
|
setLogLevel(envLevel as LogLevel);
|
|
72
|
-
} else {
|
|
73
|
-
setLogLevel(config.logLevel);
|
|
74
51
|
}
|
|
75
|
-
const log = createLogger('
|
|
76
|
-
const port = overrides?.port ??
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const ICEBOX_DIR = path.join(config.scopesDir, 'icebox');
|
|
86
|
-
// Resolve path to the bundled default workflow config.
|
|
87
|
-
const __selfDir2 = path.dirname(fileURLToPath(import.meta.url));
|
|
88
|
-
const DEFAULT_CONFIG_PATH = path.resolve(__selfDir2, '../shared/default-workflow.json');
|
|
89
|
-
|
|
90
|
-
// Ensure icebox directory exists for idea files
|
|
91
|
-
if (!fs.existsSync(ICEBOX_DIR)) fs.mkdirSync(ICEBOX_DIR, { recursive: true });
|
|
52
|
+
const log = createLogger('central');
|
|
53
|
+
const port = overrides?.port ?? (Number(process.env.ORBITAL_SERVER_PORT) || 4444);
|
|
54
|
+
const clientPort = overrides?.clientPort ?? (Number(process.env.ORBITAL_CLIENT_PORT) || 4445);
|
|
55
|
+
|
|
56
|
+
// Auto-register current project if registry is empty
|
|
57
|
+
const globalConfig = loadGlobalConfig();
|
|
58
|
+
if (globalConfig.projects.length === 0 && overrides?.autoRegisterPath) {
|
|
59
|
+
registerProjectGlobal(overrides.autoRegisterPath);
|
|
60
|
+
log.info('Auto-registered current project', { path: overrides.autoRegisterPath });
|
|
61
|
+
}
|
|
92
62
|
|
|
93
63
|
const app = express();
|
|
94
64
|
const httpServer = createServer(app);
|
|
@@ -96,7 +66,6 @@ export async function startServer(overrides?: ServerOverrides): Promise<ServerIn
|
|
|
96
66
|
const io = new Server(httpServer, {
|
|
97
67
|
cors: {
|
|
98
68
|
origin: (origin, callback) => {
|
|
99
|
-
// Allow all localhost origins (dev tool, not production)
|
|
100
69
|
if (!origin || origin.startsWith('http://localhost:')) {
|
|
101
70
|
callback(null, true);
|
|
102
71
|
} else {
|
|
@@ -107,324 +76,174 @@ export async function startServer(overrides?: ServerOverrides): Promise<ServerIn
|
|
|
107
76
|
},
|
|
108
77
|
});
|
|
109
78
|
|
|
110
|
-
// Middleware
|
|
111
79
|
app.use(express.json());
|
|
112
80
|
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const scopeService = new ScopeService(scopeCache, io, config.scopesDir, workflowEngine);
|
|
119
|
-
const eventService = new EventService(db, io);
|
|
120
|
-
const gateService = new GateService(db, io);
|
|
121
|
-
const deployService = new DeployService(db, io);
|
|
122
|
-
const sprintService = new SprintService(db, io, scopeService);
|
|
123
|
-
const sprintOrchestrator = new SprintOrchestrator(db, io, sprintService, scopeService, workflowEngine);
|
|
124
|
-
const batchOrchestrator = new BatchOrchestrator(db, io, sprintService, scopeService, workflowEngine);
|
|
125
|
-
const readinessService = new ReadinessService(scopeService, gateService, workflowEngine, config.projectRoot);
|
|
126
|
-
const workflowService = new WorkflowService(config.configDir, workflowEngine, config.scopesDir, DEFAULT_CONFIG_PATH);
|
|
127
|
-
workflowService.setSocketServer(io);
|
|
128
|
-
|
|
129
|
-
// Ensure in-memory engine reflects the actual active config (may differ from bundled default
|
|
130
|
-
// if the user applied a custom preset)
|
|
131
|
-
workflowEngine.reload(workflowService.getActive());
|
|
132
|
-
const gitService = new GitService(config.projectRoot, scopeCache);
|
|
133
|
-
const githubService = new GitHubService(config.projectRoot);
|
|
134
|
-
|
|
135
|
-
// Wire active-group guard into scope service (blocks manual moves for scopes in active batches/sprints)
|
|
136
|
-
scopeService.setActiveGroupCheck((scopeId) => sprintService.getActiveGroupForScope(scopeId));
|
|
137
|
-
|
|
138
|
-
// ─── Event Wiring ──────────────────────────────────────────
|
|
139
|
-
|
|
140
|
-
function inferScopeStatus(
|
|
141
|
-
eventType: string,
|
|
142
|
-
scopeId: unknown,
|
|
143
|
-
data: Record<string, unknown>
|
|
144
|
-
): void {
|
|
145
|
-
if (scopeId == null) return;
|
|
146
|
-
const id = Number(scopeId);
|
|
147
|
-
if (isNaN(id) || id <= 0) return;
|
|
148
|
-
|
|
149
|
-
// Don't infer status for icebox idea cards
|
|
150
|
-
const current = scopeService.getById(id);
|
|
151
|
-
if (current?.status === 'icebox') return;
|
|
152
|
-
|
|
153
|
-
const currentStatus = current?.status ?? '';
|
|
154
|
-
const result = workflowEngine.inferStatus(eventType, currentStatus, data);
|
|
155
|
-
if (result === null) return;
|
|
156
|
-
|
|
157
|
-
// Handle dispatch resolution (AGENT_COMPLETED with outcome)
|
|
158
|
-
if (typeof result === 'object' && 'dispatchResolution' in result) {
|
|
159
|
-
resolveActiveDispatchesForScope(
|
|
160
|
-
db, io, id,
|
|
161
|
-
result.resolution as 'completed' | 'failed',
|
|
162
|
-
);
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
scopeService.updateStatus(id, result, 'event');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
eventService.onIngest((eventType, scopeId, data) => {
|
|
170
|
-
// Handle SESSION_START: link PID to dispatch via dispatch_id env var
|
|
171
|
-
if (eventType === 'SESSION_START' && typeof data.dispatch_id === 'string' && typeof data.pid === 'number') {
|
|
172
|
-
linkPidToDispatch(db, data.dispatch_id, data.pid);
|
|
173
|
-
log.info('SESSION_START: linked PID to dispatch', { pid: data.pid, dispatch_id: data.dispatch_id });
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
81
|
+
// ─── Bind port early ──────────────────────────────────────
|
|
82
|
+
// Listen before async init so Vite's proxy doesn't get ECONNREFUSED
|
|
83
|
+
const actualPort = await new Promise<number>((resolve, reject) => {
|
|
84
|
+
let attempt = 0;
|
|
85
|
+
const maxAttempts = 10;
|
|
176
86
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
log.info('SESSION_END: resolved dispatches', { count, dispatch_id: data.dispatch_id });
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// PID fallback for old hooks without dispatch_id
|
|
187
|
-
if (count === 0 && typeof data.pid === 'number') {
|
|
188
|
-
count = resolveDispatchesByPid(db, io, data.pid);
|
|
189
|
-
if (count > 0) {
|
|
190
|
-
log.info('SESSION_END: resolved dispatches by PID fallback', { count, pid: data.pid });
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
// Immediately resolve any batches/sprints whose session just ended,
|
|
194
|
-
// rather than waiting for the next stale-check interval
|
|
195
|
-
if (count > 0) {
|
|
196
|
-
batchOrchestrator.resolveStaleBatches();
|
|
87
|
+
httpServer.on('error', (err: NodeJS.ErrnoException) => {
|
|
88
|
+
if (err.code === 'EADDRINUSE' && attempt < maxAttempts) {
|
|
89
|
+
attempt++;
|
|
90
|
+
httpServer.listen(port + attempt);
|
|
91
|
+
} else {
|
|
92
|
+
reject(new Error(`Failed to start server: ${err.message}`));
|
|
197
93
|
}
|
|
198
|
-
|
|
199
|
-
}
|
|
94
|
+
});
|
|
200
95
|
|
|
201
|
-
|
|
202
|
-
|
|
96
|
+
httpServer.on('listening', () => {
|
|
97
|
+
const addr = httpServer.address();
|
|
98
|
+
resolve(typeof addr === 'object' && addr ? addr.port : port);
|
|
99
|
+
});
|
|
203
100
|
|
|
204
|
-
|
|
205
|
-
if (newStatus === 'dev') {
|
|
206
|
-
sprintOrchestrator.onScopeReachedDev(scopeId);
|
|
207
|
-
}
|
|
208
|
-
// Batch orchestrator tracks all status transitions (dev, staging, production)
|
|
209
|
-
batchOrchestrator.onScopeStatusChanged(scopeId, newStatus);
|
|
101
|
+
httpServer.listen(port);
|
|
210
102
|
});
|
|
211
103
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
104
|
+
// Initialize ProjectManager and boot all registered projects
|
|
105
|
+
const projectManager = new ProjectManager(io);
|
|
106
|
+
await projectManager.initializeAll();
|
|
107
|
+
|
|
108
|
+
// Seed global primitives if empty (lazy fallback for first launch)
|
|
109
|
+
const globalPrimitivesEmpty = ['agents', 'skills', 'hooks'].every(t => {
|
|
110
|
+
const dir = path.join(GLOBAL_PRIMITIVES_DIR, t);
|
|
111
|
+
return !fs.existsSync(dir) || fs.readdirSync(dir).filter(f => !f.startsWith('.')).length === 0;
|
|
216
112
|
});
|
|
113
|
+
if (globalPrimitivesEmpty) {
|
|
114
|
+
seedGlobalPrimitives();
|
|
115
|
+
log.info('Seeded global primitives from package templates');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Initialize SyncService and global watcher
|
|
119
|
+
const syncService = new SyncService();
|
|
120
|
+
const globalWatcher = startGlobalWatcher(syncService, io);
|
|
217
121
|
|
|
218
|
-
// ─── Routes
|
|
122
|
+
// ─── Routes ──────────────────────────────────────────────
|
|
219
123
|
|
|
124
|
+
// Health check
|
|
220
125
|
app.get('/api/orbital/health', (_req, res) => {
|
|
221
126
|
res.json({ status: 'ok', uptime: process.uptime(), timestamp: new Date().toISOString() });
|
|
222
127
|
});
|
|
223
128
|
|
|
224
|
-
//
|
|
225
|
-
app.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
129
|
+
// Project management + sync routes (top-level)
|
|
130
|
+
app.use('/api/orbital', createSyncRoutes({ syncService, projectManager }));
|
|
131
|
+
app.use('/api/orbital', createVersionRoutes({ io }));
|
|
132
|
+
|
|
133
|
+
// Per-project routes — dynamic middleware that resolves :projectId
|
|
134
|
+
app.use('/api/orbital/projects/:projectId', (req, res, next) => {
|
|
135
|
+
const projectId = req.params.projectId;
|
|
136
|
+
const router = projectManager.getRouter(projectId);
|
|
137
|
+
if (!router) {
|
|
138
|
+
const ctx = projectManager.getContext(projectId);
|
|
139
|
+
if (!ctx) return res.status(404).json({ error: `Project '${projectId}' not found` });
|
|
140
|
+
return res.status(503).json({ error: `Project '${projectId}' is offline` });
|
|
141
|
+
}
|
|
142
|
+
router(req, res, next);
|
|
233
143
|
});
|
|
234
144
|
|
|
235
|
-
|
|
236
|
-
app.use('/api/orbital',
|
|
237
|
-
app.use('/api/orbital', createDispatchRoutes({ db, io, scopeService, projectRoot: config.projectRoot, engine: workflowEngine }));
|
|
238
|
-
app.use('/api/orbital', createSprintRoutes({ sprintService, sprintOrchestrator, batchOrchestrator }));
|
|
239
|
-
app.use('/api/orbital', createWorkflowRoutes({ workflowService, projectRoot: config.projectRoot }));
|
|
240
|
-
app.use('/api/orbital', createConfigRoutes({ projectRoot: config.projectRoot, workflowService, io }));
|
|
241
|
-
app.use('/api/orbital', createGitRoutes({ gitService, githubService, engine: workflowEngine }));
|
|
242
|
-
app.use('/api/orbital', createVersionRoutes({ io }));
|
|
145
|
+
// Aggregate endpoints (cross-project)
|
|
146
|
+
app.use('/api/orbital', createAggregateRoutes({ projectManager, io, syncService }));
|
|
243
147
|
|
|
244
|
-
// ─── Static File Serving
|
|
148
|
+
// ─── Static File Serving ─────────────────────────────────
|
|
245
149
|
|
|
246
|
-
// Resolve the Vite-built frontend dist directory (server/ → ../dist).
|
|
247
150
|
const __selfDir = path.dirname(fileURLToPath(import.meta.url));
|
|
248
151
|
const distDir = path.resolve(__selfDir, '../dist');
|
|
249
|
-
|
|
152
|
+
const devMode = clientPort !== port;
|
|
153
|
+
const hasBuiltFrontend = !devMode && fs.existsSync(path.join(distDir, 'index.html'));
|
|
154
|
+
if (hasBuiltFrontend) {
|
|
250
155
|
app.use(express.static(distDir));
|
|
251
156
|
app.get('*', (req, res, next) => {
|
|
252
157
|
if (req.path.startsWith('/api/') || req.path.startsWith('/socket.io')) return next();
|
|
253
158
|
res.sendFile(path.join(distDir, 'index.html'));
|
|
254
159
|
});
|
|
255
160
|
} else {
|
|
256
|
-
|
|
257
|
-
app.get('/', (_req, res) => res.redirect(`http://localhost:${config.clientPort}`));
|
|
161
|
+
app.get('/', (_req, res) => res.redirect(`http://localhost:${clientPort}`));
|
|
258
162
|
}
|
|
259
163
|
|
|
260
|
-
// ─── Socket.io
|
|
164
|
+
// ─── Socket.io ───────────────────────────────────────────
|
|
261
165
|
|
|
262
166
|
io.on('connection', (socket) => {
|
|
263
167
|
log.debug('Client connected', { socketId: socket.id });
|
|
264
168
|
|
|
265
|
-
socket.on('
|
|
266
|
-
|
|
169
|
+
socket.on('subscribe', (payload: { projectId?: string; scope?: string }) => {
|
|
170
|
+
if (payload.scope === 'all') {
|
|
171
|
+
socket.join('all-projects');
|
|
172
|
+
} else if (payload.projectId) {
|
|
173
|
+
socket.join(`project:${payload.projectId}`);
|
|
174
|
+
}
|
|
267
175
|
});
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
// ─── Startup ───────────────────────────────────────────────
|
|
271
|
-
|
|
272
|
-
// References for graceful shutdown
|
|
273
|
-
let scopeWatcher: ReturnType<typeof startScopeWatcher>;
|
|
274
|
-
let eventWatcher: ReturnType<typeof startEventWatcher>;
|
|
275
|
-
let batchRecoveryInterval: ReturnType<typeof setInterval>;
|
|
276
|
-
let staleCleanupInterval: ReturnType<typeof setInterval>;
|
|
277
|
-
let sessionSyncInterval: ReturnType<typeof setInterval>;
|
|
278
|
-
let gitPollInterval: ReturnType<typeof setInterval>;
|
|
279
|
-
|
|
280
|
-
const actualPort = await new Promise<number>((resolve, reject) => {
|
|
281
|
-
let attempt = 0;
|
|
282
|
-
const maxAttempts = 10;
|
|
283
176
|
|
|
284
|
-
|
|
285
|
-
if (
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
httpServer.listen(nextPort);
|
|
290
|
-
} else {
|
|
291
|
-
reject(new Error(`Failed to start server: ${err.message}`));
|
|
177
|
+
socket.on('unsubscribe', (payload: { projectId?: string; scope?: string }) => {
|
|
178
|
+
if (payload.scope === 'all') {
|
|
179
|
+
socket.leave('all-projects');
|
|
180
|
+
} else if (payload.projectId) {
|
|
181
|
+
socket.leave(`project:${payload.projectId}`);
|
|
292
182
|
}
|
|
293
183
|
});
|
|
294
184
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const listenPort = typeof addr === 'object' && addr ? addr.port : port;
|
|
298
|
-
resolve(listenPort);
|
|
185
|
+
socket.on('disconnect', () => {
|
|
186
|
+
log.debug('Client disconnected', { socketId: socket.id });
|
|
299
187
|
});
|
|
300
|
-
|
|
301
|
-
httpServer.listen(port);
|
|
302
188
|
});
|
|
303
189
|
|
|
304
|
-
// ───
|
|
305
|
-
|
|
306
|
-
// Sync scopes from filesystem on startup (populates in-memory cache)
|
|
307
|
-
const scopeCount = scopeService.syncFromFilesystem();
|
|
190
|
+
// ─── Error Handling Middleware ─────────────────────────────
|
|
191
|
+
// Catches unhandled errors thrown from route handlers.
|
|
308
192
|
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
ensureDynamicProfiles(workflowEngine);
|
|
317
|
-
|
|
318
|
-
// Start file watchers
|
|
319
|
-
scopeWatcher = startScopeWatcher(config.scopesDir, scopeService);
|
|
320
|
-
eventWatcher = startEventWatcher(config.eventsDir, eventService);
|
|
321
|
-
|
|
322
|
-
// Recover any active sprints/batches from before server restart
|
|
323
|
-
sprintOrchestrator.recoverActiveSprints().catch(err => log.error('Sprint recovery failed', { error: err.message }));
|
|
324
|
-
batchOrchestrator.recoverActiveBatches().catch(err => log.error('Batch recovery failed', { error: err.message }));
|
|
193
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
194
|
+
app.use((err: Error, _req: express.Request, res: express.Response, _next: express.NextFunction) => {
|
|
195
|
+
log.error('Unhandled route error', { error: err.message, stack: err.stack });
|
|
196
|
+
if (!res.headersSent) {
|
|
197
|
+
res.status(500).json({ ok: false, error: 'Internal server error' });
|
|
198
|
+
}
|
|
199
|
+
});
|
|
325
200
|
|
|
326
|
-
//
|
|
327
|
-
const staleBatchesResolved = batchOrchestrator.resolveStaleBatches();
|
|
328
|
-
if (staleBatchesResolved > 0) {
|
|
329
|
-
log.info('Resolved stale batches', { count: staleBatchesResolved });
|
|
330
|
-
}
|
|
201
|
+
// ─── Startup Banner ──────────────────────────────────────
|
|
331
202
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
203
|
+
const projectList = projectManager.getProjectList();
|
|
204
|
+
const projectLines = projectList.map(p =>
|
|
205
|
+
`║ ${p.status === 'active' ? '●' : '○'} ${p.name.padEnd(20)} ${String(p.scopeCount).padStart(3)} scopes ${p.status.padEnd(8)} ║`
|
|
206
|
+
).join('\n');
|
|
336
207
|
|
|
337
|
-
|
|
338
|
-
staleCleanupInterval = setInterval(() => {
|
|
339
|
-
const count = resolveStaleDispatches(db, io, scopeService, workflowEngine);
|
|
340
|
-
if (count > 0) {
|
|
341
|
-
log.info('Periodic cleanup: resolved stale dispatches', { count });
|
|
342
|
-
}
|
|
343
|
-
const batchCount = batchOrchestrator.resolveStaleBatches();
|
|
344
|
-
if (batchCount > 0) {
|
|
345
|
-
log.info('Periodic cleanup: resolved stale batches', { count: batchCount });
|
|
346
|
-
}
|
|
347
|
-
}, 30_000);
|
|
348
|
-
|
|
349
|
-
// Sync frontmatter-derived sessions into DB (non-blocking)
|
|
350
|
-
syncClaudeSessionsToDB(db, scopeService).then((count) => {
|
|
351
|
-
log.info('Synced frontmatter sessions', { count });
|
|
352
|
-
|
|
353
|
-
// Purge legacy pattern-matched rows (no action = old regex system)
|
|
354
|
-
const purged = db.prepare(
|
|
355
|
-
"DELETE FROM sessions WHERE action IS NULL AND id LIKE 'claude-%'"
|
|
356
|
-
).run();
|
|
357
|
-
if (purged.changes > 0) {
|
|
358
|
-
log.info('Purged legacy pattern-matched session rows', { count: purged.changes });
|
|
359
|
-
}
|
|
360
|
-
}).catch(err => log.error('Session sync failed', { error: err.message }));
|
|
361
|
-
|
|
362
|
-
// Re-sync every 5 minutes so new sessions appear without restart
|
|
363
|
-
sessionSyncInterval = setInterval(() => {
|
|
364
|
-
syncClaudeSessionsToDB(db, scopeService)
|
|
365
|
-
.then((count) => {
|
|
366
|
-
if (count > 0) io.emit('session:updated', { type: 'resync', count });
|
|
367
|
-
})
|
|
368
|
-
.catch(err => log.error('Session resync failed', { error: err.message }));
|
|
369
|
-
}, 5 * 60 * 1000);
|
|
370
|
-
|
|
371
|
-
// Poll git status every 10s — emit socket event on change
|
|
372
|
-
let lastGitHash = '';
|
|
373
|
-
gitPollInterval = setInterval(async () => {
|
|
374
|
-
try {
|
|
375
|
-
const hash = await gitService.getStatusHash();
|
|
376
|
-
if (lastGitHash && hash !== lastGitHash) {
|
|
377
|
-
gitService.clearCache();
|
|
378
|
-
io.emit('git:status:changed');
|
|
379
|
-
}
|
|
380
|
-
lastGitHash = hash;
|
|
381
|
-
} catch { /* ok */ }
|
|
382
|
-
}, 10_000);
|
|
208
|
+
const dashboardPort = devMode ? clientPort : actualPort;
|
|
383
209
|
|
|
384
210
|
// eslint-disable-next-line no-console
|
|
385
211
|
console.log(`
|
|
386
212
|
╔══════════════════════════════════════════════════════╗
|
|
387
|
-
║ Orbital Command
|
|
388
|
-
║ ${config.projectName.padEnd(42)} ║
|
|
213
|
+
║ Orbital Command — Central Server ║
|
|
389
214
|
║ ║
|
|
390
|
-
║ >>> Open: http://localhost:${
|
|
215
|
+
║ >>> Open: http://localhost:${String(dashboardPort).padEnd(25)} <<<║
|
|
391
216
|
║ ║
|
|
392
217
|
╠══════════════════════════════════════════════════════╣
|
|
393
|
-
|
|
218
|
+
${projectLines}
|
|
219
|
+
╠══════════════════════════════════════════════════════╣
|
|
394
220
|
║ API: http://localhost:${actualPort}/api/orbital/* ║
|
|
395
221
|
║ Socket.io: ws://localhost:${actualPort} ║
|
|
222
|
+
║ Home: ${ORBITAL_HOME.padEnd(39)} ║
|
|
396
223
|
╚══════════════════════════════════════════════════════╝
|
|
397
224
|
`);
|
|
398
225
|
|
|
399
|
-
// ─── Graceful Shutdown
|
|
226
|
+
// ─── Graceful Shutdown ───────────────────────────────────
|
|
400
227
|
|
|
401
228
|
let shuttingDown = false;
|
|
402
|
-
function shutdown(): Promise<void> {
|
|
403
|
-
if (shuttingDown) return
|
|
229
|
+
async function shutdown(): Promise<void> {
|
|
230
|
+
if (shuttingDown) return;
|
|
404
231
|
shuttingDown = true;
|
|
405
|
-
log.info('Shutting down');
|
|
406
|
-
scopeWatcher.close();
|
|
407
|
-
eventWatcher.close();
|
|
408
|
-
clearInterval(batchRecoveryInterval);
|
|
409
|
-
clearInterval(staleCleanupInterval);
|
|
410
|
-
clearInterval(sessionSyncInterval);
|
|
411
|
-
clearInterval(gitPollInterval);
|
|
232
|
+
log.info('Shutting down central server');
|
|
412
233
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
closeDatabase();
|
|
416
|
-
resolve();
|
|
417
|
-
}, 2000);
|
|
234
|
+
if (globalWatcher) await globalWatcher.close();
|
|
235
|
+
await projectManager.shutdownAll();
|
|
418
236
|
|
|
237
|
+
return new Promise<void>((resolve) => {
|
|
238
|
+
const forceTimeout = setTimeout(resolve, 2000);
|
|
419
239
|
io.close(() => {
|
|
420
240
|
clearTimeout(forceTimeout);
|
|
421
|
-
closeDatabase();
|
|
422
241
|
resolve();
|
|
423
242
|
});
|
|
424
243
|
});
|
|
425
244
|
}
|
|
426
245
|
|
|
427
|
-
return { app, io,
|
|
246
|
+
return { app, io, projectManager, syncService, httpServer, shutdown };
|
|
428
247
|
}
|
|
429
248
|
|
|
430
249
|
// ─── Direct Execution (backward compat: tsx watch server/index.ts) ───
|
|
@@ -436,7 +255,11 @@ const isDirectRun = process.argv[1] && (
|
|
|
436
255
|
);
|
|
437
256
|
|
|
438
257
|
if (isDirectRun) {
|
|
439
|
-
|
|
258
|
+
const projectRoot = process.env.ORBITAL_PROJECT_ROOT || process.cwd();
|
|
259
|
+
startCentralServer({
|
|
260
|
+
port: Number(process.env.ORBITAL_SERVER_PORT) || 4444,
|
|
261
|
+
autoRegisterPath: projectRoot,
|
|
262
|
+
}).then(({ shutdown }) => {
|
|
440
263
|
process.on('SIGINT', async () => {
|
|
441
264
|
await shutdown();
|
|
442
265
|
process.exit(0);
|