orbital-command 0.1.4 → 0.3.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/bin/orbital.js +676 -53
- package/dist/assets/PrimitivesConfig-CrmQXYh4.js +32 -0
- package/dist/assets/QualityGates-BbasOsF3.js +21 -0
- package/dist/assets/SessionTimeline-CGeJsVvy.js +1 -0
- package/dist/assets/Settings-oiM496mc.js +12 -0
- package/dist/assets/SourceControl-B1fP2nJL.js +41 -0
- package/dist/assets/WorkflowVisualizer-CWLYf-f0.js +74 -0
- package/dist/assets/arrow-down-CPy85_J6.js +6 -0
- package/dist/assets/charts-DbDg0Psc.js +68 -0
- package/dist/assets/circle-x-Cwz6ZQDV.js +6 -0
- package/dist/assets/file-text-C46Xr65c.js +6 -0
- package/dist/assets/formatDistanceToNow-BMqsSP44.js +1 -0
- package/dist/assets/globe-Cn2yNZUD.js +6 -0
- package/dist/assets/index-Aj4sV8Al.css +1 -0
- package/dist/assets/index-Bc9dK3MW.js +354 -0
- package/dist/assets/key-OPaNTWJ5.js +6 -0
- package/dist/assets/minus-GMsbpKym.js +6 -0
- package/dist/assets/shield-DwAFkDYI.js +6 -0
- package/dist/assets/ui-BmsSg9jU.js +53 -0
- package/dist/assets/useWorkflowEditor-BJkTX_NR.js +16 -0
- package/dist/assets/{vendor-Dzv9lrRc.js → vendor-Bqt8AJn2.js} +1 -1
- package/dist/assets/zap-DfbUoOty.js +11 -0
- package/dist/favicon.svg +1 -0
- package/dist/index.html +6 -5
- package/dist/server/server/__tests__/data-routes.test.js +124 -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 +137 -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 +138 -0
- package/dist/server/server/config.js +17 -2
- package/dist/server/server/database.js +27 -12
- package/dist/server/server/global-config.js +143 -0
- package/dist/server/server/index.js +882 -252
- package/dist/server/server/init.js +579 -194
- 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.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 +255 -0
- package/dist/server/server/project-emitter.js +41 -0
- package/dist/server/server/project-manager.js +297 -0
- package/dist/server/server/routes/config-routes.js +1 -3
- package/dist/server/server/routes/data-routes.js +22 -110
- package/dist/server/server/routes/dispatch-routes.js +15 -9
- 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 +37 -23
- 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 +2 -0
- package/dist/server/server/services/batch-orchestrator.js +26 -16
- package/dist/server/server/services/claude-session-service.js +17 -14
- 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 +217 -126
- package/dist/server/server/services/scope-service.test.js +137 -0
- package/dist/server/server/services/sprint-orchestrator.js +7 -6
- package/dist/server/server/services/sprint-service.js +21 -1
- 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/telemetry-service.js +143 -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/update-planner.js +279 -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 +77 -20
- package/dist/server/server/utils/dispatch-utils.test.js +182 -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 +10 -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/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 +155 -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 +35 -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 +74 -0
- package/dist/server/shared/__fixtures__/workflow-configs.js +75 -0
- 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.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 +20 -15
- package/schemas/orbital.config.schema.json +16 -1
- package/scripts/postinstall.js +55 -7
- package/server/__tests__/data-routes.test.ts +149 -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 +157 -0
- package/server/__tests__/sprint-routes.test.ts +118 -0
- package/server/__tests__/workflow-routes.test.ts +120 -0
- package/server/config-migrator.ts +163 -0
- package/server/config.ts +26 -2
- package/server/database.ts +35 -18
- package/server/global-config.ts +200 -0
- package/server/index.ts +975 -287
- package/server/init.ts +625 -182
- 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/scope-parser.test.ts +270 -0
- package/server/parsers/scope-parser.ts +79 -31
- package/server/project-context.ts +309 -0
- package/server/project-emitter.ts +50 -0
- package/server/project-manager.ts +369 -0
- package/server/routes/config-routes.ts +3 -5
- package/server/routes/data-routes.ts +28 -141
- package/server/routes/dispatch-routes.ts +19 -11
- package/server/routes/git-routes.ts +77 -0
- package/server/routes/manifest-routes.ts +388 -0
- package/server/routes/scope-routes.ts +29 -25
- 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 +2 -0
- package/server/services/batch-orchestrator.ts +24 -16
- package/server/services/claude-session-service.ts +16 -14
- 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 +220 -126
- package/server/services/sprint-orchestrator.ts +7 -7
- package/server/services/sprint-service.test.ts +271 -0
- package/server/services/sprint-service.ts +27 -3
- package/server/services/sync-service.ts +482 -0
- package/server/services/sync-types.ts +77 -0
- package/server/services/telemetry-service.ts +195 -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/update-planner.ts +346 -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 +97 -27
- package/server/utils/logger.ts +40 -3
- package/server/utils/package-info.ts +32 -0
- package/server/utils/route-helpers.ts +12 -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/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 +187 -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 +43 -0
- package/server/wizard/phases/workflow-setup.ts +28 -0
- package/server/wizard/types.ts +56 -0
- package/server/wizard/ui.ts +93 -0
- package/shared/__fixtures__/workflow-configs.ts +80 -0
- package/shared/default-workflow.json +65 -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-normalizer.test.ts +119 -0
- package/shared/workflow-normalizer.ts +118 -0
- package/templates/hooks/end-session.sh +3 -1
- 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-create-cleanup.sh +2 -2
- package/templates/hooks/scope-create-gate.sh +0 -1
- package/templates/hooks/scope-helpers.sh +18 -0
- package/templates/hooks/scope-prepare.sh +66 -11
- package/templates/migrations/renames.json +1 -0
- package/templates/orbital.config.json +7 -2
- package/templates/settings-hooks.json +1 -1
- package/templates/skills/git-commit/SKILL.md +9 -4
- package/templates/skills/git-dev/SKILL.md +8 -3
- package/templates/skills/git-main/SKILL.md +8 -2
- package/templates/skills/git-production/SKILL.md +6 -2
- package/templates/skills/git-staging/SKILL.md +8 -3
- package/templates/skills/scope-create/SKILL.md +17 -3
- package/templates/skills/scope-fix-review/SKILL.md +6 -3
- package/templates/skills/scope-implement/SKILL.md +4 -1
- package/templates/skills/scope-post-review/SKILL.md +63 -5
- package/templates/skills/scope-pre-review/SKILL.md +5 -2
- 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 -49
package/bin/orbital.js
CHANGED
|
@@ -31,6 +31,11 @@ function resolveBin(name) {
|
|
|
31
31
|
// CLI Helpers
|
|
32
32
|
// ---------------------------------------------------------------------------
|
|
33
33
|
|
|
34
|
+
function getFlagValue(args, flag) {
|
|
35
|
+
const idx = args.indexOf(flag);
|
|
36
|
+
return idx !== -1 && idx + 1 < args.length ? args[idx + 1] : undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
34
39
|
function detectProjectRoot() {
|
|
35
40
|
try {
|
|
36
41
|
return execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf8' }).trim();
|
|
@@ -131,59 +136,152 @@ async function loadSharedModule() {
|
|
|
131
136
|
}
|
|
132
137
|
}
|
|
133
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Load the interactive wizard module.
|
|
141
|
+
*/
|
|
142
|
+
async function loadWizardModule() {
|
|
143
|
+
try {
|
|
144
|
+
return await import('../dist/server/server/wizard/index.js');
|
|
145
|
+
} catch {
|
|
146
|
+
try {
|
|
147
|
+
return await import('../server/wizard/index.js');
|
|
148
|
+
} catch {
|
|
149
|
+
console.error('Error: Wizard module not found.');
|
|
150
|
+
console.error('Try reinstalling: npm install -g orbital-command');
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
134
156
|
// ---------------------------------------------------------------------------
|
|
135
157
|
// Commands
|
|
136
158
|
// ---------------------------------------------------------------------------
|
|
137
159
|
|
|
160
|
+
function orbitalSetupDone() {
|
|
161
|
+
return fs.existsSync(path.join(ORBITAL_HOME, 'config.json'));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function autoRegisterProject(projectRoot) {
|
|
165
|
+
if (!fs.existsSync(ORBITAL_HOME)) fs.mkdirSync(ORBITAL_HOME, { recursive: true });
|
|
166
|
+
const registry = loadRegistry();
|
|
167
|
+
if (!(registry.projects || []).some(p => p.path === projectRoot)) {
|
|
168
|
+
cmdRegister([projectRoot]);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
138
172
|
async function cmdInit(args) {
|
|
139
|
-
const
|
|
173
|
+
const isYes = args.includes('--yes') || args.includes('-y');
|
|
174
|
+
const isInteractive = process.stdout.isTTY && !process.env.CI && !isYes;
|
|
140
175
|
const projectRoot = detectProjectRoot();
|
|
141
176
|
|
|
142
|
-
|
|
143
|
-
|
|
177
|
+
if (isInteractive) {
|
|
178
|
+
const wiz = await loadWizardModule();
|
|
179
|
+
const version = getPackageVersion();
|
|
144
180
|
|
|
181
|
+
// If Orbital hasn't been set up yet, run Phase 1 first
|
|
182
|
+
if (!orbitalSetupDone()) {
|
|
183
|
+
await wiz.runSetupWizard(version);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Phase 2: project setup for current directory
|
|
187
|
+
await wiz.runProjectSetup(projectRoot, version, args);
|
|
188
|
+
stampTemplateVersion(projectRoot);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Non-interactive / --yes fallback (existing behavior preserved)
|
|
193
|
+
const force = args.includes('--force');
|
|
194
|
+
const globalPrivate = loadRegistry().privateMode === true;
|
|
195
|
+
const isPrivate = args.includes('--private') || globalPrivate;
|
|
196
|
+
const preset = getFlagValue(args, '--preset');
|
|
197
|
+
const projectName = getFlagValue(args, '--project-name');
|
|
198
|
+
const serverPort = getFlagValue(args, '--server-port');
|
|
199
|
+
const clientPort = getFlagValue(args, '--client-port');
|
|
200
|
+
|
|
201
|
+
const { runInit } = await loadSharedModule();
|
|
202
|
+
runInit(projectRoot, {
|
|
203
|
+
force,
|
|
204
|
+
preset: preset || undefined,
|
|
205
|
+
projectName: projectName || undefined,
|
|
206
|
+
serverPort: serverPort ? Number(serverPort) : undefined,
|
|
207
|
+
clientPort: clientPort ? Number(clientPort) : undefined,
|
|
208
|
+
});
|
|
145
209
|
stampTemplateVersion(projectRoot);
|
|
146
|
-
|
|
210
|
+
|
|
211
|
+
if (isPrivate) {
|
|
212
|
+
const configPath = path.join(projectRoot, '.claude', 'orbital.config.json');
|
|
213
|
+
if (fs.existsSync(configPath)) {
|
|
214
|
+
try {
|
|
215
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
216
|
+
if (!config.telemetry) config.telemetry = {};
|
|
217
|
+
config.telemetry.enabled = false;
|
|
218
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
219
|
+
|
|
220
|
+
} catch { /* leave config as-is */ }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
autoRegisterProject(projectRoot);
|
|
225
|
+
console.log(`Run \`orbital launch\` to start the dashboard.\n`);
|
|
147
226
|
}
|
|
148
227
|
|
|
149
|
-
function
|
|
228
|
+
function cmdLaunchOrDev(forceViteFlag) {
|
|
150
229
|
const shouldOpen = process.argv.includes('--open');
|
|
230
|
+
const forceVite = forceViteFlag || process.argv.includes('--vite');
|
|
151
231
|
const projectRoot = detectProjectRoot();
|
|
152
232
|
const config = loadConfig(projectRoot);
|
|
153
233
|
const serverPort = config.serverPort || 4444;
|
|
154
234
|
const clientPort = config.clientPort || 4445;
|
|
155
235
|
|
|
156
|
-
|
|
236
|
+
autoRegisterProject(projectRoot);
|
|
237
|
+
|
|
238
|
+
// Detect packaged mode: dist/index.html exists → serve pre-built frontend
|
|
239
|
+
const hasPrebuiltFrontend = fs.existsSync(path.join(PACKAGE_ROOT, 'dist', 'index.html'));
|
|
240
|
+
const useVite = forceVite || !hasPrebuiltFrontend;
|
|
241
|
+
|
|
242
|
+
console.log(`\nOrbital Command — ${useVite ? 'dev' : 'launch'}`);
|
|
157
243
|
console.log(`Project root: ${projectRoot}`);
|
|
158
|
-
|
|
159
|
-
|
|
244
|
+
if (useVite) {
|
|
245
|
+
console.log(`Server: http://localhost:${serverPort}`);
|
|
246
|
+
console.log(`Client: http://localhost:${clientPort} (Vite dev server)\n`);
|
|
247
|
+
} else {
|
|
248
|
+
console.log(`Dashboard: http://localhost:${serverPort}\n`);
|
|
249
|
+
}
|
|
160
250
|
|
|
161
251
|
checkTemplatesStaleness(projectRoot);
|
|
162
252
|
|
|
163
253
|
const env = {
|
|
164
254
|
...process.env,
|
|
165
|
-
|
|
255
|
+
ORBITAL_LAUNCH_MODE: 'central',
|
|
256
|
+
ORBITAL_AUTO_REGISTER: projectRoot,
|
|
166
257
|
ORBITAL_SERVER_PORT: String(serverPort),
|
|
167
258
|
};
|
|
168
259
|
|
|
169
|
-
|
|
260
|
+
const serverScript = path.join(PACKAGE_ROOT, 'server', 'launch.ts');
|
|
170
261
|
const tsxBin = resolveBin('tsx');
|
|
171
262
|
const serverProcess = tsxBin
|
|
172
|
-
? spawn(tsxBin, ['watch',
|
|
263
|
+
? spawn(tsxBin, ['watch', serverScript],
|
|
173
264
|
{ stdio: 'inherit', env, cwd: PACKAGE_ROOT })
|
|
174
|
-
: spawn('npx', ['tsx', 'watch',
|
|
265
|
+
: spawn('npx', ['tsx', 'watch', serverScript],
|
|
175
266
|
{ stdio: 'inherit', env, cwd: PACKAGE_ROOT });
|
|
176
267
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
268
|
+
let viteProcess = null;
|
|
269
|
+
|
|
270
|
+
if (useVite) {
|
|
271
|
+
const viteBin = resolveBin('vite');
|
|
272
|
+
viteProcess = viteBin
|
|
273
|
+
? spawn(viteBin, ['--config', path.join(PACKAGE_ROOT, 'vite.config.ts'), '--port', String(clientPort)],
|
|
274
|
+
{ stdio: 'inherit', env, cwd: PACKAGE_ROOT })
|
|
275
|
+
: spawn('npx', ['vite', '--config', path.join(PACKAGE_ROOT, 'vite.config.ts'), '--port', String(clientPort)],
|
|
276
|
+
{ stdio: 'inherit', env, cwd: PACKAGE_ROOT });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const dashboardUrl = useVite
|
|
280
|
+
? `http://localhost:${clientPort}`
|
|
281
|
+
: `http://localhost:${serverPort}`;
|
|
184
282
|
|
|
185
283
|
if (shouldOpen) {
|
|
186
|
-
setTimeout(() => openBrowser(
|
|
284
|
+
setTimeout(() => openBrowser(dashboardUrl), 2000);
|
|
187
285
|
}
|
|
188
286
|
|
|
189
287
|
let exiting = false;
|
|
@@ -192,7 +290,7 @@ function cmdDev() {
|
|
|
192
290
|
if (exiting) return;
|
|
193
291
|
exiting = true;
|
|
194
292
|
serverProcess.kill();
|
|
195
|
-
viteProcess.kill();
|
|
293
|
+
if (viteProcess) viteProcess.kill();
|
|
196
294
|
process.exit(0);
|
|
197
295
|
}
|
|
198
296
|
process.on('SIGINT', cleanup);
|
|
@@ -202,16 +300,18 @@ function cmdDev() {
|
|
|
202
300
|
if (exiting) return;
|
|
203
301
|
exiting = true;
|
|
204
302
|
console.log(`Server exited with code ${code}`);
|
|
205
|
-
viteProcess.kill();
|
|
206
|
-
process.exit(code || 0);
|
|
207
|
-
});
|
|
208
|
-
viteProcess.on('exit', (code) => {
|
|
209
|
-
if (exiting) return;
|
|
210
|
-
exiting = true;
|
|
211
|
-
console.log(`Vite exited with code ${code}`);
|
|
212
|
-
serverProcess.kill();
|
|
303
|
+
if (viteProcess) viteProcess.kill();
|
|
213
304
|
process.exit(code || 0);
|
|
214
305
|
});
|
|
306
|
+
if (viteProcess) {
|
|
307
|
+
viteProcess.on('exit', (code) => {
|
|
308
|
+
if (exiting) return;
|
|
309
|
+
exiting = true;
|
|
310
|
+
console.log(`Vite exited with code ${code}`);
|
|
311
|
+
serverProcess.kill();
|
|
312
|
+
process.exit(code || 0);
|
|
313
|
+
});
|
|
314
|
+
}
|
|
215
315
|
}
|
|
216
316
|
|
|
217
317
|
function cmdBuild() {
|
|
@@ -265,20 +365,442 @@ function cmdEmit(args) {
|
|
|
265
365
|
console.log(` File: ${path.relative(projectRoot, filePath)}`);
|
|
266
366
|
}
|
|
267
367
|
|
|
268
|
-
async function cmdUpdate() {
|
|
368
|
+
async function cmdUpdate(args) {
|
|
269
369
|
const projectRoot = detectProjectRoot();
|
|
370
|
+
const dryRun = args.includes('--dry-run');
|
|
270
371
|
|
|
271
372
|
const { runUpdate } = await loadSharedModule();
|
|
272
|
-
runUpdate(projectRoot);
|
|
373
|
+
runUpdate(projectRoot, { dryRun });
|
|
273
374
|
|
|
274
|
-
stampTemplateVersion(projectRoot);
|
|
375
|
+
if (!dryRun) stampTemplateVersion(projectRoot);
|
|
275
376
|
}
|
|
276
377
|
|
|
277
|
-
async function cmdUninstall() {
|
|
378
|
+
async function cmdUninstall(args) {
|
|
278
379
|
const projectRoot = detectProjectRoot();
|
|
380
|
+
const dryRun = args.includes('--dry-run');
|
|
381
|
+
const keepConfig = args.includes('--keep-config');
|
|
279
382
|
|
|
280
383
|
const { runUninstall } = await loadSharedModule();
|
|
281
|
-
runUninstall(projectRoot);
|
|
384
|
+
runUninstall(projectRoot, { dryRun, keepConfig });
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// ---------------------------------------------------------------------------
|
|
388
|
+
// Manifest management commands
|
|
389
|
+
// ---------------------------------------------------------------------------
|
|
390
|
+
|
|
391
|
+
async function cmdValidate() {
|
|
392
|
+
const projectRoot = detectProjectRoot();
|
|
393
|
+
|
|
394
|
+
const mod = await loadSharedModule();
|
|
395
|
+
const report = mod.validate(projectRoot, getPackageVersion());
|
|
396
|
+
console.log(mod.formatValidationReport(report));
|
|
397
|
+
process.exit(report.errors > 0 ? 1 : 0);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async function cmdStatus() {
|
|
401
|
+
const projectRoot = detectProjectRoot();
|
|
402
|
+
|
|
403
|
+
const mod = await loadSharedModule();
|
|
404
|
+
const manifest = mod.loadManifest(projectRoot);
|
|
405
|
+
|
|
406
|
+
if (!manifest) {
|
|
407
|
+
console.log('\nNo manifest found. Run `orbital init` or `orbital update` to create one.\n');
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const claudeDir = path.join(projectRoot, '.claude');
|
|
412
|
+
mod.refreshFileStatuses(manifest, claudeDir);
|
|
413
|
+
|
|
414
|
+
const summary = mod.summarizeManifest(manifest);
|
|
415
|
+
const packageVersion = getPackageVersion();
|
|
416
|
+
const needsUpdate = manifest.packageVersion !== packageVersion;
|
|
417
|
+
|
|
418
|
+
console.log(`\nOrbital Command v${packageVersion}${needsUpdate ? ` (installed: ${manifest.packageVersion} → needs update)` : ''}\n`);
|
|
419
|
+
|
|
420
|
+
for (const [type, counts] of Object.entries(summary.byType)) {
|
|
421
|
+
const parts = [];
|
|
422
|
+
if (counts.synced) parts.push(`${counts.synced} synced`);
|
|
423
|
+
if (counts.outdated) parts.push(`${counts.outdated} outdated`);
|
|
424
|
+
if (counts.modified) parts.push(`${counts.modified} modified`);
|
|
425
|
+
if (counts.pinned) parts.push(`${counts.pinned} pinned`);
|
|
426
|
+
if (counts.userOwned) parts.push(`${counts.userOwned} user-owned`);
|
|
427
|
+
console.log(` ${type.padEnd(16)} ${parts.join(', ')}`);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Show outdated files (template moved ahead, user hasn't touched)
|
|
431
|
+
const outdated = Object.entries(manifest.files)
|
|
432
|
+
.filter(([, r]) => r.status === 'outdated');
|
|
433
|
+
if (outdated.length > 0) {
|
|
434
|
+
console.log('\n Outdated files (safe to update):');
|
|
435
|
+
for (const [file] of outdated) {
|
|
436
|
+
console.log(` ${file}`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Show modified files (user edited)
|
|
441
|
+
const modified = Object.entries(manifest.files)
|
|
442
|
+
.filter(([, r]) => r.status === 'modified');
|
|
443
|
+
if (modified.length > 0) {
|
|
444
|
+
console.log('\n Modified files (user edited):');
|
|
445
|
+
for (const [file] of modified) {
|
|
446
|
+
console.log(` ${file} (run 'orbital diff ${file}')`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Show pinned files
|
|
451
|
+
const pinned = Object.entries(manifest.files)
|
|
452
|
+
.filter(([, r]) => r.status === 'pinned');
|
|
453
|
+
if (pinned.length > 0) {
|
|
454
|
+
console.log('\n Pinned files:');
|
|
455
|
+
for (const [file, record] of pinned) {
|
|
456
|
+
const reason = record.pinnedReason ? `"${record.pinnedReason}"` : '';
|
|
457
|
+
console.log(` ${file} ${reason}`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
console.log();
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async function cmdPin(args) {
|
|
465
|
+
const projectRoot = detectProjectRoot();
|
|
466
|
+
const filePath = args.find(a => !a.startsWith('--'));
|
|
467
|
+
const reasonIdx = args.indexOf('--reason');
|
|
468
|
+
const reason = reasonIdx !== -1 ? args[reasonIdx + 1] : undefined;
|
|
469
|
+
|
|
470
|
+
if (!filePath) {
|
|
471
|
+
console.error('Usage: orbital pin <relative-path> [--reason "..."]');
|
|
472
|
+
process.exit(1);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const mod = await loadSharedModule();
|
|
476
|
+
const manifest = mod.loadManifest(projectRoot);
|
|
477
|
+
if (!manifest) {
|
|
478
|
+
console.error('No manifest found. Run `orbital init` first.');
|
|
479
|
+
process.exit(1);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
const record = manifest.files[filePath];
|
|
483
|
+
if (!record) {
|
|
484
|
+
console.error(`File not tracked: ${filePath}`);
|
|
485
|
+
process.exit(1);
|
|
486
|
+
}
|
|
487
|
+
if (record.origin === 'user') {
|
|
488
|
+
console.error(`Cannot pin user-owned file: ${filePath}`);
|
|
489
|
+
process.exit(1);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
record.status = 'pinned';
|
|
493
|
+
record.pinnedAt = new Date().toISOString();
|
|
494
|
+
if (reason) record.pinnedReason = reason;
|
|
495
|
+
|
|
496
|
+
mod.saveManifest(projectRoot, manifest);
|
|
497
|
+
console.log(`Pinned: ${filePath}${reason ? ` (${reason})` : ''}`);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
async function cmdUnpin(args) {
|
|
501
|
+
const projectRoot = detectProjectRoot();
|
|
502
|
+
const filePath = args[0];
|
|
503
|
+
|
|
504
|
+
if (!filePath) {
|
|
505
|
+
console.error('Usage: orbital unpin <relative-path>');
|
|
506
|
+
process.exit(1);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const mod = await loadSharedModule();
|
|
510
|
+
const manifest = mod.loadManifest(projectRoot);
|
|
511
|
+
if (!manifest) {
|
|
512
|
+
console.error('No manifest found. Run `orbital init` first.');
|
|
513
|
+
process.exit(1);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const record = manifest.files[filePath];
|
|
517
|
+
if (!record || record.status !== 'pinned') {
|
|
518
|
+
console.error(`File is not pinned: ${filePath}`);
|
|
519
|
+
process.exit(1);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// Clear pinned state, then recompute
|
|
523
|
+
record.status = 'synced';
|
|
524
|
+
delete record.pinnedAt;
|
|
525
|
+
delete record.pinnedReason;
|
|
526
|
+
|
|
527
|
+
const absPath = path.join(projectRoot, '.claude', filePath);
|
|
528
|
+
if (fs.existsSync(absPath)) {
|
|
529
|
+
const currentHash = mod.hashFile(absPath);
|
|
530
|
+
record.status = mod.computeFileStatus(record, currentHash);
|
|
531
|
+
} else {
|
|
532
|
+
record.status = 'synced';
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
mod.saveManifest(projectRoot, manifest);
|
|
536
|
+
console.log(`Unpinned: ${filePath} (now ${record.status})`);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async function cmdPins() {
|
|
540
|
+
const projectRoot = detectProjectRoot();
|
|
541
|
+
|
|
542
|
+
const mod = await loadSharedModule();
|
|
543
|
+
const manifest = mod.loadManifest(projectRoot);
|
|
544
|
+
if (!manifest) {
|
|
545
|
+
console.error('No manifest found. Run `orbital init` first.');
|
|
546
|
+
process.exit(1);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const pinned = Object.entries(manifest.files)
|
|
550
|
+
.filter(([, r]) => r.status === 'pinned');
|
|
551
|
+
|
|
552
|
+
if (pinned.length === 0) {
|
|
553
|
+
console.log('No pinned files.');
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
console.log(`\n Pinned files:\n`);
|
|
558
|
+
for (const [file, record] of pinned) {
|
|
559
|
+
const reason = record.pinnedReason || '(no reason)';
|
|
560
|
+
const date = record.pinnedAt ? new Date(record.pinnedAt).toLocaleDateString() : '';
|
|
561
|
+
console.log(` ${file}`);
|
|
562
|
+
console.log(` Reason: ${reason} Pinned: ${date}`);
|
|
563
|
+
if (record.templateHash !== record.installedHash) {
|
|
564
|
+
console.log(` Template has changed since pin — run 'orbital diff ${file}' to compare`);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
console.log();
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
async function cmdDiff(args) {
|
|
571
|
+
const projectRoot = detectProjectRoot();
|
|
572
|
+
const filePath = args[0];
|
|
573
|
+
|
|
574
|
+
if (!filePath) {
|
|
575
|
+
console.error('Usage: orbital diff <relative-path>');
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const mod = await loadSharedModule();
|
|
580
|
+
const manifest = mod.loadManifest(projectRoot);
|
|
581
|
+
if (!manifest) {
|
|
582
|
+
console.error('No manifest found. Run `orbital init` first.');
|
|
583
|
+
process.exit(1);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const record = manifest.files[filePath];
|
|
587
|
+
if (!record || record.origin !== 'template') {
|
|
588
|
+
console.error(`Not a template file: ${filePath}`);
|
|
589
|
+
process.exit(1);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Resolve template path
|
|
593
|
+
let templateRelPath = filePath;
|
|
594
|
+
if (filePath.startsWith('config/workflows/')) {
|
|
595
|
+
templateRelPath = filePath.replace('config/workflows/', 'presets/');
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const templatePath = path.join(PACKAGE_ROOT, 'templates', templateRelPath);
|
|
599
|
+
const localPath = path.join(projectRoot, '.claude', filePath);
|
|
600
|
+
|
|
601
|
+
if (!fs.existsSync(templatePath)) {
|
|
602
|
+
console.error(`Template file not found: ${templateRelPath}`);
|
|
603
|
+
process.exit(1);
|
|
604
|
+
}
|
|
605
|
+
if (!fs.existsSync(localPath)) {
|
|
606
|
+
console.log('Local file does not exist. Template content:');
|
|
607
|
+
console.log(fs.readFileSync(templatePath, 'utf-8'));
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Use git diff for nice formatting (safe: no user input in arguments)
|
|
612
|
+
const { execFileSync } = await import('child_process');
|
|
613
|
+
try {
|
|
614
|
+
const output = execFileSync(
|
|
615
|
+
'git', ['diff', '--no-index', '--color', '--', templatePath, localPath],
|
|
616
|
+
{ encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }
|
|
617
|
+
);
|
|
618
|
+
console.log(output);
|
|
619
|
+
} catch (e) {
|
|
620
|
+
// git diff exits 1 when files differ — that's expected
|
|
621
|
+
if (e.stdout) console.log(e.stdout);
|
|
622
|
+
else console.log('Files differ but git diff is unavailable.');
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
async function cmdReset(args) {
|
|
627
|
+
const projectRoot = detectProjectRoot();
|
|
628
|
+
const filePath = args[0];
|
|
629
|
+
|
|
630
|
+
if (!filePath) {
|
|
631
|
+
console.error('Usage: orbital reset <relative-path>');
|
|
632
|
+
process.exit(1);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const mod = await loadSharedModule();
|
|
636
|
+
const manifest = mod.loadManifest(projectRoot);
|
|
637
|
+
if (!manifest) {
|
|
638
|
+
console.error('No manifest found. Run `orbital init` first.');
|
|
639
|
+
process.exit(1);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const record = manifest.files[filePath];
|
|
643
|
+
if (!record || record.origin !== 'template') {
|
|
644
|
+
console.error(`Not a template file: ${filePath}`);
|
|
645
|
+
process.exit(1);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Resolve and copy template file
|
|
649
|
+
let templateRelPath = filePath;
|
|
650
|
+
if (filePath.startsWith('config/workflows/')) {
|
|
651
|
+
templateRelPath = filePath.replace('config/workflows/', 'presets/');
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const templatePath = path.join(PACKAGE_ROOT, 'templates', templateRelPath);
|
|
655
|
+
const localPath = path.join(projectRoot, '.claude', filePath);
|
|
656
|
+
|
|
657
|
+
if (!fs.existsSync(templatePath)) {
|
|
658
|
+
console.error(`Template file not found: ${templateRelPath}`);
|
|
659
|
+
process.exit(1);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
fs.copyFileSync(templatePath, localPath);
|
|
663
|
+
const newHash = mod.hashFile(localPath);
|
|
664
|
+
record.status = 'synced';
|
|
665
|
+
record.templateHash = newHash;
|
|
666
|
+
record.installedHash = newHash;
|
|
667
|
+
delete record.pinnedAt;
|
|
668
|
+
delete record.pinnedReason;
|
|
669
|
+
|
|
670
|
+
mod.saveManifest(projectRoot, manifest);
|
|
671
|
+
console.log(`Reset: ${filePath} → synced with template`);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// ---------------------------------------------------------------------------
|
|
675
|
+
// Multi-project commands
|
|
676
|
+
// ---------------------------------------------------------------------------
|
|
677
|
+
|
|
678
|
+
const ORBITAL_HOME = path.join(process.env.HOME || process.env.USERPROFILE || '~', '.orbital');
|
|
679
|
+
const REGISTRY_PATH = path.join(ORBITAL_HOME, 'config.json');
|
|
680
|
+
|
|
681
|
+
function loadRegistry() {
|
|
682
|
+
if (!fs.existsSync(REGISTRY_PATH)) return { version: 1, projects: [] };
|
|
683
|
+
try {
|
|
684
|
+
return JSON.parse(fs.readFileSync(REGISTRY_PATH, 'utf8'));
|
|
685
|
+
} catch {
|
|
686
|
+
return { version: 1, projects: [] };
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// cmdLaunch removed — merged into cmdLaunchOrDev() above
|
|
691
|
+
|
|
692
|
+
function cmdRegister(args) {
|
|
693
|
+
const targetPath = args[0] ? path.resolve(args[0]) : detectProjectRoot();
|
|
694
|
+
const nameFlag = args.indexOf('--alias');
|
|
695
|
+
const name = nameFlag >= 0 ? args[nameFlag + 1] : path.basename(targetPath);
|
|
696
|
+
|
|
697
|
+
// Ensure ~/.orbital/ exists
|
|
698
|
+
if (!fs.existsSync(ORBITAL_HOME)) fs.mkdirSync(ORBITAL_HOME, { recursive: true });
|
|
699
|
+
|
|
700
|
+
// Check the project has been initialized
|
|
701
|
+
if (!fs.existsSync(path.join(targetPath, '.claude'))) {
|
|
702
|
+
console.error(`Error: ${targetPath} has not been initialized with Orbital Command.`);
|
|
703
|
+
console.error(`Run \`orbital init\` in that directory first.`);
|
|
704
|
+
process.exit(1);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
const registry = loadRegistry();
|
|
708
|
+
|
|
709
|
+
// Check if already registered
|
|
710
|
+
if (registry.projects?.some(p => p.path === targetPath)) {
|
|
711
|
+
console.log(`Project already registered: ${targetPath}`);
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Color palette
|
|
716
|
+
const COLORS = [
|
|
717
|
+
'210 80% 55%', '340 75% 55%', '160 60% 45%', '30 90% 55%',
|
|
718
|
+
'270 65% 55%', '50 85% 50%', '180 55% 45%', '0 70% 55%',
|
|
719
|
+
'120 50% 42%', '300 60% 50%', '200 70% 50%', '15 80% 55%',
|
|
720
|
+
];
|
|
721
|
+
const usedColors = (registry.projects || []).map(p => p.color);
|
|
722
|
+
const color = COLORS.find(c => !usedColors.includes(c)) || COLORS[0];
|
|
723
|
+
|
|
724
|
+
// Generate slug
|
|
725
|
+
const baseSlug = path.basename(targetPath).toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '') || 'project';
|
|
726
|
+
const existingIds = (registry.projects || []).map(p => p.id);
|
|
727
|
+
const slug = existingIds.includes(baseSlug)
|
|
728
|
+
? `${baseSlug}-${crypto.createHash('sha256').update(targetPath).digest('hex').slice(0, 4)}`
|
|
729
|
+
: baseSlug;
|
|
730
|
+
|
|
731
|
+
const project = {
|
|
732
|
+
id: slug,
|
|
733
|
+
path: targetPath,
|
|
734
|
+
name,
|
|
735
|
+
color,
|
|
736
|
+
registeredAt: new Date().toISOString(),
|
|
737
|
+
enabled: true,
|
|
738
|
+
};
|
|
739
|
+
|
|
740
|
+
if (!registry.projects) registry.projects = [];
|
|
741
|
+
registry.projects.push(project);
|
|
742
|
+
fs.writeFileSync(REGISTRY_PATH, JSON.stringify(registry, null, 2), 'utf8');
|
|
743
|
+
|
|
744
|
+
console.log(`Registered project: ${name}`);
|
|
745
|
+
console.log(` ID: ${slug}`);
|
|
746
|
+
console.log(` Path: ${targetPath}`);
|
|
747
|
+
console.log(` Color: ${color}`);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function cmdUnregister(args) {
|
|
751
|
+
const idOrPath = args[0];
|
|
752
|
+
if (!idOrPath) {
|
|
753
|
+
console.error('Usage: orbital unregister <id-or-path>');
|
|
754
|
+
process.exit(1);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const absPath = path.isAbsolute(idOrPath) ? idOrPath : path.resolve(idOrPath);
|
|
758
|
+
const registry = loadRegistry();
|
|
759
|
+
const idx = (registry.projects || []).findIndex(p => p.id === idOrPath || p.path === absPath);
|
|
760
|
+
|
|
761
|
+
if (idx === -1) {
|
|
762
|
+
console.error(`Project not found: ${idOrPath}`);
|
|
763
|
+
process.exit(1);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const removed = registry.projects.splice(idx, 1)[0];
|
|
767
|
+
fs.writeFileSync(REGISTRY_PATH, JSON.stringify(registry, null, 2), 'utf8');
|
|
768
|
+
|
|
769
|
+
console.log(`Unregistered project: ${removed.name} (${removed.id})`);
|
|
770
|
+
console.log(` Project files in ${removed.path} are preserved.`);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
function cmdProjects() {
|
|
774
|
+
const registry = loadRegistry();
|
|
775
|
+
const projects = registry.projects || [];
|
|
776
|
+
|
|
777
|
+
if (projects.length === 0) {
|
|
778
|
+
console.log('\nNo projects registered.');
|
|
779
|
+
console.log('Use `orbital register` or `orbital init` to add a project.\n');
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
console.log(`\n ${'ID'.padEnd(22)} ${'NAME'.padEnd(22)} ${'STATUS'.padEnd(10)} PATH`);
|
|
784
|
+
console.log(` ${'─'.repeat(22)} ${'─'.repeat(22)} ${'─'.repeat(10)} ${'─'.repeat(30)}`);
|
|
785
|
+
for (const p of projects) {
|
|
786
|
+
const status = p.enabled ? (fs.existsSync(p.path) ? 'active' : 'offline') : 'disabled';
|
|
787
|
+
console.log(` ${p.id.padEnd(22)} ${p.name.padEnd(22)} ${status.padEnd(10)} ${p.path}`);
|
|
788
|
+
}
|
|
789
|
+
console.log();
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
async function cmdConfig(args) {
|
|
793
|
+
const { runConfigEditor } = await loadWizardModule();
|
|
794
|
+
const projectRoot = detectProjectRoot();
|
|
795
|
+
const version = getPackageVersion();
|
|
796
|
+
await runConfigEditor(projectRoot, version, args);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
async function cmdDoctor() {
|
|
800
|
+
const { runDoctor } = await loadWizardModule();
|
|
801
|
+
const projectRoot = detectProjectRoot();
|
|
802
|
+
const version = getPackageVersion();
|
|
803
|
+
await runDoctor(projectRoot, version);
|
|
282
804
|
}
|
|
283
805
|
|
|
284
806
|
function printHelp() {
|
|
@@ -289,29 +811,66 @@ Usage:
|
|
|
289
811
|
orbital <command> [options]
|
|
290
812
|
|
|
291
813
|
Commands:
|
|
292
|
-
init
|
|
293
|
-
|
|
294
|
-
|
|
814
|
+
init Set up Orbital Command (interactive wizard)
|
|
815
|
+
launch Start the dashboard
|
|
816
|
+
config Modify project settings interactively
|
|
817
|
+
doctor Health check and version diagnostics
|
|
818
|
+
update Sync templates and apply migrations
|
|
819
|
+
status Show template sync status
|
|
820
|
+
|
|
821
|
+
Aliases:
|
|
822
|
+
setup Same as init
|
|
823
|
+
dev Same as launch --vite (development with HMR)
|
|
824
|
+
|
|
825
|
+
Config Subcommands:
|
|
826
|
+
config show Print current config as JSON
|
|
827
|
+
config set <k> <v> Set a config value non-interactively
|
|
828
|
+
|
|
829
|
+
Template Management:
|
|
830
|
+
validate Check cross-references and consistency
|
|
831
|
+
pin <path> Lock a file from updates
|
|
832
|
+
unpin <path> Unlock a pinned file
|
|
833
|
+
pins List all pinned files
|
|
834
|
+
diff <path> Show diff between template and local file
|
|
835
|
+
reset <path> Restore a file from the current template
|
|
836
|
+
|
|
837
|
+
Project Management:
|
|
838
|
+
register [path] Register a project with the dashboard
|
|
839
|
+
unregister <id> Remove a project from the dashboard
|
|
840
|
+
projects List all registered projects
|
|
841
|
+
|
|
842
|
+
Other:
|
|
843
|
+
build Production build of the dashboard frontend
|
|
295
844
|
emit <TYPE> <JSON> Emit an orbital event
|
|
296
|
-
update Re-copy hooks/skills/agents from package templates
|
|
297
845
|
uninstall Remove Orbital artifacts from the project
|
|
298
846
|
|
|
299
847
|
Init Options:
|
|
300
|
-
--force
|
|
301
|
-
--
|
|
302
|
-
--
|
|
848
|
+
--force Overwrite existing hooks, skills, and agents
|
|
849
|
+
--yes, -y Skip the wizard, use auto-detected defaults
|
|
850
|
+
--private Disable telemetry for this project
|
|
851
|
+
--preset <name> Workflow preset (default/minimal/development/gitflow)
|
|
852
|
+
--project-name <n> Override auto-detected project name
|
|
853
|
+
--server-port <n> Override default server port (4444)
|
|
854
|
+
--client-port <n> Override default client port (4445)
|
|
855
|
+
|
|
856
|
+
Launch Options:
|
|
857
|
+
--open Open the dashboard in the browser
|
|
858
|
+
--vite Force Vite dev server for HMR
|
|
859
|
+
|
|
860
|
+
Update Options:
|
|
861
|
+
--dry-run Preview changes without applying them
|
|
303
862
|
|
|
304
|
-
|
|
305
|
-
--
|
|
863
|
+
Uninstall Options:
|
|
864
|
+
--dry-run Preview removal without applying
|
|
865
|
+
--keep-config Keep orbital.config.json for re-initialization
|
|
306
866
|
|
|
307
867
|
Examples:
|
|
308
868
|
orbital init
|
|
309
|
-
orbital
|
|
310
|
-
orbital
|
|
311
|
-
orbital
|
|
312
|
-
orbital
|
|
313
|
-
orbital
|
|
314
|
-
orbital uninstall
|
|
869
|
+
orbital launch --open
|
|
870
|
+
orbital config
|
|
871
|
+
orbital doctor
|
|
872
|
+
orbital update --dry-run
|
|
873
|
+
orbital status
|
|
315
874
|
`);
|
|
316
875
|
}
|
|
317
876
|
|
|
@@ -323,11 +882,30 @@ const [command, ...args] = process.argv.slice(2);
|
|
|
323
882
|
|
|
324
883
|
async function main() {
|
|
325
884
|
switch (command) {
|
|
885
|
+
case 'launch':
|
|
886
|
+
cmdLaunchOrDev(false);
|
|
887
|
+
break;
|
|
326
888
|
case 'init':
|
|
889
|
+
case 'setup':
|
|
327
890
|
await cmdInit(args);
|
|
328
891
|
break;
|
|
892
|
+
case 'config':
|
|
893
|
+
await cmdConfig(args);
|
|
894
|
+
break;
|
|
895
|
+
case 'doctor':
|
|
896
|
+
await cmdDoctor();
|
|
897
|
+
break;
|
|
329
898
|
case 'dev':
|
|
330
|
-
|
|
899
|
+
cmdLaunchOrDev(true);
|
|
900
|
+
break;
|
|
901
|
+
case 'register':
|
|
902
|
+
cmdRegister(args);
|
|
903
|
+
break;
|
|
904
|
+
case 'unregister':
|
|
905
|
+
cmdUnregister(args);
|
|
906
|
+
break;
|
|
907
|
+
case 'projects':
|
|
908
|
+
cmdProjects();
|
|
331
909
|
break;
|
|
332
910
|
case 'build':
|
|
333
911
|
cmdBuild();
|
|
@@ -336,18 +914,63 @@ async function main() {
|
|
|
336
914
|
cmdEmit(args);
|
|
337
915
|
break;
|
|
338
916
|
case 'update':
|
|
339
|
-
await cmdUpdate();
|
|
917
|
+
await cmdUpdate(args);
|
|
340
918
|
break;
|
|
341
919
|
case 'uninstall':
|
|
342
|
-
await cmdUninstall();
|
|
920
|
+
await cmdUninstall(args);
|
|
921
|
+
break;
|
|
922
|
+
case 'status':
|
|
923
|
+
await cmdStatus();
|
|
924
|
+
break;
|
|
925
|
+
case 'validate':
|
|
926
|
+
await cmdValidate();
|
|
927
|
+
break;
|
|
928
|
+
case 'pin':
|
|
929
|
+
await cmdPin(args);
|
|
930
|
+
break;
|
|
931
|
+
case 'unpin':
|
|
932
|
+
await cmdUnpin(args);
|
|
343
933
|
break;
|
|
934
|
+
case 'pins':
|
|
935
|
+
await cmdPins();
|
|
936
|
+
break;
|
|
937
|
+
case 'diff':
|
|
938
|
+
await cmdDiff(args);
|
|
939
|
+
break;
|
|
940
|
+
case 'reset':
|
|
941
|
+
await cmdReset(args);
|
|
942
|
+
break;
|
|
943
|
+
case 'private': {
|
|
944
|
+
const registry = loadRegistry();
|
|
945
|
+
const enable = args[0] !== 'off';
|
|
946
|
+
registry.privateMode = enable;
|
|
947
|
+
if (!fs.existsSync(ORBITAL_HOME)) fs.mkdirSync(ORBITAL_HOME, { recursive: true });
|
|
948
|
+
fs.writeFileSync(REGISTRY_PATH, JSON.stringify(registry, null, 2), 'utf8');
|
|
949
|
+
console.log(`Private mode ${enable ? 'enabled' : 'disabled'} globally.`);
|
|
950
|
+
|
|
951
|
+
break;
|
|
952
|
+
}
|
|
344
953
|
case 'help':
|
|
345
954
|
case '--help':
|
|
346
955
|
case '-h':
|
|
347
956
|
printHelp();
|
|
348
957
|
break;
|
|
349
958
|
case undefined:
|
|
350
|
-
|
|
959
|
+
if (process.stdout.isTTY && !process.env.CI) {
|
|
960
|
+
const wiz = await loadWizardModule();
|
|
961
|
+
const version = getPackageVersion();
|
|
962
|
+
if (!orbitalSetupDone()) {
|
|
963
|
+
// First time — run Phase 1 setup
|
|
964
|
+
await wiz.runSetupWizard(version);
|
|
965
|
+
} else {
|
|
966
|
+
// Already set up — run Phase 2 for current directory
|
|
967
|
+
const projectRoot = detectProjectRoot();
|
|
968
|
+
await wiz.runProjectSetup(projectRoot, version, []);
|
|
969
|
+
stampTemplateVersion(projectRoot);
|
|
970
|
+
}
|
|
971
|
+
} else {
|
|
972
|
+
printHelp();
|
|
973
|
+
}
|
|
351
974
|
break;
|
|
352
975
|
default:
|
|
353
976
|
console.error(`Unknown command: ${command}`);
|