orbital-command 0.3.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 +95 -870
- 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-CPy85_J6.js → arrow-down-DVPp6_qp.js} +1 -1
- package/dist/assets/bot-NFaJBDn_.js +6 -0
- package/dist/assets/{charts-DbDg0Psc.js → charts-LGLb8hyU.js} +1 -1
- package/dist/assets/{circle-x-Cwz6ZQDV.js → circle-x-IsFCkBZu.js} +1 -1
- package/dist/assets/{file-text-C46Xr65c.js → file-text-J1cebZXF.js} +1 -1
- package/dist/assets/{globe-Cn2yNZUD.js → globe-WzeyHsUc.js} +1 -1
- package/dist/assets/index-BdJ57EhC.css +1 -0
- package/dist/assets/index-o4ScMAuR.js +349 -0
- package/dist/assets/{key-OPaNTWJ5.js → key-CKR8JJSj.js} +1 -1
- package/dist/assets/{minus-GMsbpKym.js → minus-CHBsJyjp.js} +1 -1
- package/dist/assets/radio-xqZaR-Uk.js +6 -0
- package/dist/assets/rocket-D_xvvNG6.js +6 -0
- package/dist/assets/{shield-DwAFkDYI.js → shield-TdB1yv_a.js} +1 -1
- package/dist/assets/useSocketListener-0L5yiN5i.js +1 -0
- package/dist/assets/useWorkflowEditor-CqeRWVQX.js +11 -0
- package/dist/assets/workflow-constants-Rw-GmgHZ.js +6 -0
- package/dist/assets/zap-C9wqYMpl.js +6 -0
- package/dist/index.html +3 -3
- package/dist/server/server/__tests__/data-routes.test.js +2 -0
- package/dist/server/server/__tests__/scope-routes.test.js +1 -0
- package/dist/server/server/config-migrator.js +0 -3
- package/dist/server/server/config.js +35 -6
- package/dist/server/server/database.js +0 -22
- package/dist/server/server/index.js +26 -814
- package/dist/server/server/init.js +32 -399
- package/dist/server/server/launch.js +1 -1
- package/dist/server/server/parsers/event-parser.js +4 -1
- package/dist/server/server/project-context.js +19 -9
- package/dist/server/server/project-manager.js +6 -6
- package/dist/server/server/routes/aggregate-routes.js +871 -0
- package/dist/server/server/routes/config-routes.js +41 -88
- package/dist/server/server/routes/data-routes.js +5 -15
- package/dist/server/server/routes/dispatch-routes.js +24 -8
- package/dist/server/server/routes/manifest-routes.js +1 -1
- package/dist/server/server/routes/scope-routes.js +10 -7
- package/dist/server/server/schema.js +1 -0
- package/dist/server/server/services/batch-orchestrator.js +17 -3
- package/dist/server/server/services/config-service.js +10 -1
- package/dist/server/server/services/scope-service.js +7 -7
- package/dist/server/server/services/sprint-orchestrator.js +24 -11
- package/dist/server/server/services/sprint-service.js +2 -2
- package/dist/server/server/uninstall.js +195 -0
- package/dist/server/server/update.js +212 -0
- package/dist/server/server/utils/dispatch-utils.js +8 -6
- 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/route-helpers.js +37 -0
- package/dist/server/server/utils/route-helpers.test.js +115 -0
- package/dist/server/server/watchers/event-watcher.js +28 -13
- package/dist/server/server/wizard/config-editor.js +4 -4
- package/dist/server/server/wizard/doctor.js +2 -2
- package/dist/server/server/wizard/index.js +224 -39
- package/dist/server/server/wizard/phases/welcome.js +1 -4
- package/dist/server/server/wizard/ui.js +6 -7
- package/dist/server/shared/api-types.js +80 -1
- package/dist/server/shared/workflow-engine.js +1 -1
- package/package.json +20 -20
- package/schemas/orbital.config.schema.json +1 -19
- package/scripts/postinstall.js +6 -42
- package/scripts/release.sh +53 -0
- package/server/__tests__/data-routes.test.ts +2 -0
- package/server/__tests__/scope-routes.test.ts +1 -0
- package/server/config-migrator.ts +0 -3
- package/server/config.ts +39 -11
- package/server/database.ts +0 -26
- package/server/global-config.ts +4 -0
- package/server/index.ts +29 -894
- package/server/init.ts +32 -443
- package/server/launch.ts +1 -1
- package/server/parsers/event-parser.ts +4 -1
- package/server/project-context.ts +26 -10
- package/server/project-manager.ts +5 -6
- package/server/routes/aggregate-routes.ts +968 -0
- package/server/routes/config-routes.ts +41 -81
- package/server/routes/data-routes.ts +7 -16
- package/server/routes/dispatch-routes.ts +29 -8
- package/server/routes/manifest-routes.ts +1 -1
- package/server/routes/scope-routes.ts +12 -7
- package/server/schema.ts +1 -0
- package/server/services/batch-orchestrator.ts +18 -2
- package/server/services/config-service.ts +10 -1
- package/server/services/scope-service.ts +6 -6
- package/server/services/sprint-orchestrator.ts +24 -9
- package/server/services/sprint-service.ts +2 -2
- package/server/uninstall.ts +214 -0
- package/server/update.ts +263 -0
- package/server/utils/dispatch-utils.ts +8 -6
- 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/route-helpers.test.ts +144 -0
- package/server/utils/route-helpers.ts +38 -0
- package/server/watchers/event-watcher.ts +24 -12
- package/server/wizard/config-editor.ts +4 -4
- package/server/wizard/doctor.ts +2 -2
- package/server/wizard/index.ts +291 -40
- package/server/wizard/phases/welcome.ts +1 -5
- package/server/wizard/ui.ts +6 -7
- package/shared/api-types.ts +106 -0
- package/shared/workflow-engine.ts +1 -1
- 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 +1 -0
- package/templates/hooks/init-session.sh +1 -0
- package/templates/hooks/scope-commit-logger.sh +2 -2
- package/templates/hooks/scope-create-gate.sh +2 -4
- package/templates/hooks/scope-gate.sh +4 -6
- package/templates/hooks/scope-helpers.sh +10 -1
- package/templates/hooks/scope-lifecycle-gate.sh +14 -5
- package/templates/hooks/scope-prepare.sh +1 -1
- package/templates/hooks/scope-transition.sh +14 -6
- package/templates/hooks/time-tracker.sh +2 -5
- package/templates/orbital.config.json +1 -4
- 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/skills/git-commit/SKILL.md +21 -6
- package/templates/skills/git-dev/SKILL.md +8 -4
- package/templates/skills/git-main/SKILL.md +8 -4
- package/templates/skills/git-production/SKILL.md +6 -3
- package/templates/skills/git-staging/SKILL.md +6 -3
- package/templates/skills/scope-fix-review/SKILL.md +8 -4
- package/templates/skills/scope-implement/SKILL.md +13 -5
- package/templates/skills/scope-post-review/SKILL.md +16 -4
- package/templates/skills/scope-pre-review/SKILL.md +6 -2
- package/dist/assets/PrimitivesConfig-CrmQXYh4.js +0 -32
- package/dist/assets/QualityGates-BbasOsF3.js +0 -21
- package/dist/assets/SessionTimeline-CGeJsVvy.js +0 -1
- package/dist/assets/Settings-oiM496mc.js +0 -12
- package/dist/assets/SourceControl-B1fP2nJL.js +0 -41
- package/dist/assets/WorkflowVisualizer-CWLYf-f0.js +0 -74
- package/dist/assets/formatDistanceToNow-BMqsSP44.js +0 -1
- package/dist/assets/index-Aj4sV8Al.css +0 -1
- package/dist/assets/index-Bc9dK3MW.js +0 -354
- package/dist/assets/useWorkflowEditor-BJkTX_NR.js +0 -16
- package/dist/assets/zap-DfbUoOty.js +0 -11
- package/dist/server/server/services/telemetry-service.js +0 -143
- package/server/services/telemetry-service.ts +0 -195
- /package/{shared/default-workflow.json → templates/presets/default.json} +0 -0
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared init logic — used by
|
|
3
|
-
* programmatic callers (e.g. tests).
|
|
2
|
+
* Shared init logic — used by the wizard and
|
|
3
|
+
* programmatic callers (e.g. tests, API routes).
|
|
4
4
|
*/
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
|
-
import { GLOBAL_PRIMITIVES_DIR, ensureOrbitalHome
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { computeUpdatePlan, loadRenameMap, formatPlan, getFilesToBackup } from './update-planner.js';
|
|
12
|
-
import { syncSettingsHooks, removeAllOrbitalHooks, getTemplateChecksum } from './settings-sync.js';
|
|
13
|
-
import { migrateConfig } from './config-migrator.js';
|
|
14
|
-
import { validate, formatValidationReport } from './validator.js';
|
|
8
|
+
import { GLOBAL_PRIMITIVES_DIR, ensureOrbitalHome } from './global-config.js';
|
|
9
|
+
import { saveManifest, createManifest, hashFile, buildTemplateInventory, templateFileRecord, userFileRecord, isSelfHosting, getSymlinkTarget, } from './manifest.js';
|
|
10
|
+
import { getTemplateChecksum } from './settings-sync.js';
|
|
15
11
|
import { getPackageVersion as _getPackageVersionUtil } from './utils/package-info.js';
|
|
16
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
17
13
|
const __dirname = path.dirname(__filename);
|
|
@@ -190,7 +186,8 @@ function generateManifest(config) {
|
|
|
190
186
|
lines.push(`WORKFLOW_TERMINAL_STATUSES="${terminalStatuses.join(' ')}"`);
|
|
191
187
|
lines.push('');
|
|
192
188
|
lines.push('# ─── Entry point status ───');
|
|
193
|
-
|
|
189
|
+
const entryPointId = lists.find((l) => l.isEntryPoint)?.id || lists[0]?.id || 'todo';
|
|
190
|
+
lines.push(`WORKFLOW_ENTRY_STATUS="${entryPointId}"`);
|
|
194
191
|
lines.push('');
|
|
195
192
|
const listMap = new Map(lists.map((l) => [l.id, l]));
|
|
196
193
|
lines.push('# ─── Transition edges (from:to:sessionKey) ───');
|
|
@@ -213,6 +210,25 @@ function generateManifest(config) {
|
|
|
213
210
|
}
|
|
214
211
|
lines.push(')');
|
|
215
212
|
lines.push('');
|
|
213
|
+
lines.push('# ─── Commit session branch patterns (regex) ───');
|
|
214
|
+
lines.push(`WORKFLOW_COMMIT_BRANCHES="${config.commitBranchPatterns ?? ''}"`);
|
|
215
|
+
lines.push('');
|
|
216
|
+
lines.push('# ─── Backward-compat direction aliases (alias:from:to:sessionKey) ───');
|
|
217
|
+
lines.push('WORKFLOW_DIRECTION_ALIASES=(');
|
|
218
|
+
for (const edge of config.edges || []) {
|
|
219
|
+
if (edge.direction !== 'forward' || !edge.dispatchOnly)
|
|
220
|
+
continue;
|
|
221
|
+
const targetList = listMap.get(edge.to);
|
|
222
|
+
if (!targetList)
|
|
223
|
+
continue;
|
|
224
|
+
const group = targetList.group;
|
|
225
|
+
if (group?.startsWith('deploy')) {
|
|
226
|
+
const sessionKey = targetList.sessionKey ?? '';
|
|
227
|
+
lines.push(` "to-${edge.to}:${edge.from}:${edge.to}:${sessionKey}"`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
lines.push(')');
|
|
231
|
+
lines.push('');
|
|
216
232
|
lines.push('# ─── Helper functions ──────────────────────────────');
|
|
217
233
|
lines.push('');
|
|
218
234
|
lines.push('status_to_dir() {');
|
|
@@ -534,10 +550,13 @@ export function seedGlobalPrimitives() {
|
|
|
534
550
|
}
|
|
535
551
|
}
|
|
536
552
|
}
|
|
537
|
-
export { TEMPLATES_DIR, ensureDir };
|
|
553
|
+
export { TEMPLATES_DIR, ensureDir, cleanEmptyDirs, chmodScripts, listTemplateFiles, writeManifest, generateIndexMd, getPackageVersion };
|
|
538
554
|
// Re-export manifest utilities for CLI access via loadSharedModule()
|
|
539
555
|
export { loadManifest, saveManifest, hashFile, buildTemplateInventory, refreshFileStatuses, summarizeManifest } from './manifest.js';
|
|
540
556
|
export { validate, formatValidationReport } from './validator.js';
|
|
557
|
+
// Re-export update and uninstall from their new homes (backward compat for loadSharedModule)
|
|
558
|
+
export { runUpdate } from './update.js';
|
|
559
|
+
export { runUninstall } from './uninstall.js';
|
|
541
560
|
export function runInit(projectRoot, options = {}) {
|
|
542
561
|
const force = options.force ?? false;
|
|
543
562
|
const quiet = options.quiet ?? false;
|
|
@@ -806,391 +825,5 @@ export function runInit(projectRoot, options = {}) {
|
|
|
806
825
|
const totalSkipped = hooksResult.skipped.length + skillsResult.skipped.length + agentsResult.skipped.length;
|
|
807
826
|
log(`\nDone. ${totalCreated} files installed, ${totalSkipped} skipped (use --force to overwrite).`);
|
|
808
827
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
const claudeDir = path.join(projectRoot, '.claude');
|
|
812
|
-
const newVersion = getPackageVersion();
|
|
813
|
-
console.log(`\nOrbital Command — update${dryRun ? ' (dry run)' : ''}`);
|
|
814
|
-
console.log(`Project root: ${projectRoot}\n`);
|
|
815
|
-
// 1. Load or create manifest (auto-migrate legacy installs)
|
|
816
|
-
let manifest = loadManifest(projectRoot);
|
|
817
|
-
if (!manifest) {
|
|
818
|
-
if (needsLegacyMigration(projectRoot)) {
|
|
819
|
-
console.log(' Migrating from legacy install...');
|
|
820
|
-
const result = migrateFromLegacy(projectRoot, TEMPLATES_DIR, newVersion);
|
|
821
|
-
console.log(` Migrated ${result.synced} synced, ${result.modified} modified, ${result.userOwned} user-owned files`);
|
|
822
|
-
if (result.importedPins > 0)
|
|
823
|
-
console.log(` Imported ${result.importedPins} pinned files from orbital-sync.json`);
|
|
824
|
-
manifest = loadManifest(projectRoot);
|
|
825
|
-
}
|
|
826
|
-
if (!manifest) {
|
|
827
|
-
console.log(' No manifest found. Run `orbital init` first.');
|
|
828
|
-
return;
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
const oldVersion = manifest.packageVersion;
|
|
832
|
-
// 1b. Refresh file statuses so outdated vs modified is accurate
|
|
833
|
-
refreshFileStatuses(manifest, claudeDir);
|
|
834
|
-
// 2. Compute update plan
|
|
835
|
-
const renameMap = loadRenameMap(TEMPLATES_DIR, oldVersion, newVersion);
|
|
836
|
-
const plan = computeUpdatePlan({
|
|
837
|
-
templatesDir: TEMPLATES_DIR,
|
|
838
|
-
claudeDir,
|
|
839
|
-
manifest,
|
|
840
|
-
newVersion,
|
|
841
|
-
renameMap,
|
|
842
|
-
});
|
|
843
|
-
// 3. Dry-run mode — print plan and exit
|
|
844
|
-
if (dryRun) {
|
|
845
|
-
console.log(formatPlan(plan, oldVersion, newVersion));
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
if (plan.isEmpty && oldVersion === newVersion) {
|
|
849
|
-
console.log(' Everything up to date. No changes needed.');
|
|
850
|
-
}
|
|
851
|
-
// 4. Create backup of files that will be modified
|
|
852
|
-
const filesToBackup = getFilesToBackup(plan);
|
|
853
|
-
if (filesToBackup.length > 0) {
|
|
854
|
-
const backupDir = createBackup(claudeDir, filesToBackup);
|
|
855
|
-
if (backupDir) {
|
|
856
|
-
console.log(` Backup ${filesToBackup.length} files → ${path.relative(claudeDir, backupDir)}/`);
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
// 5. Execute plan
|
|
860
|
-
const templateInventory = buildTemplateInventory(TEMPLATES_DIR);
|
|
861
|
-
// 5a. Handle renames
|
|
862
|
-
for (const { from, to } of plan.toRename) {
|
|
863
|
-
const fromPath = path.join(claudeDir, from);
|
|
864
|
-
const toPath = path.join(claudeDir, to);
|
|
865
|
-
const toDir = path.dirname(toPath);
|
|
866
|
-
if (!fs.existsSync(toDir))
|
|
867
|
-
fs.mkdirSync(toDir, { recursive: true });
|
|
868
|
-
if (fs.existsSync(fromPath)) {
|
|
869
|
-
safeBackupFile(fromPath);
|
|
870
|
-
const stat = fs.lstatSync(fromPath);
|
|
871
|
-
if (stat.isSymbolicLink()) {
|
|
872
|
-
// Recreate symlink at new path pointing to remapped template
|
|
873
|
-
const target = fs.readlinkSync(fromPath);
|
|
874
|
-
fs.unlinkSync(fromPath);
|
|
875
|
-
fs.symlinkSync(target, toPath);
|
|
876
|
-
}
|
|
877
|
-
else {
|
|
878
|
-
fs.renameSync(fromPath, toPath);
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
// Transfer manifest record
|
|
882
|
-
const record = manifest.files[from];
|
|
883
|
-
if (record) {
|
|
884
|
-
delete manifest.files[from];
|
|
885
|
-
const newHash = templateInventory.get(to);
|
|
886
|
-
manifest.files[to] = { ...record, templateHash: newHash, installedHash: newHash || record.installedHash };
|
|
887
|
-
}
|
|
888
|
-
console.log(` RENAME ${from} → ${to}`);
|
|
889
|
-
}
|
|
890
|
-
// 5b. Add new files
|
|
891
|
-
for (const filePath of plan.toAdd) {
|
|
892
|
-
const templateHash = templateInventory.get(filePath);
|
|
893
|
-
if (!templateHash)
|
|
894
|
-
continue;
|
|
895
|
-
const destPath = path.join(claudeDir, filePath);
|
|
896
|
-
const destDir = path.dirname(destPath);
|
|
897
|
-
if (!fs.existsSync(destDir))
|
|
898
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
899
|
-
copyTemplateFile(TEMPLATES_DIR, filePath, destPath);
|
|
900
|
-
manifest.files[filePath] = templateFileRecord(templateHash);
|
|
901
|
-
console.log(` ADD ${filePath}`);
|
|
902
|
-
}
|
|
903
|
-
// 5c. Update changed synced/outdated files
|
|
904
|
-
for (const filePath of plan.toUpdate) {
|
|
905
|
-
const templateHash = templateInventory.get(filePath);
|
|
906
|
-
if (!templateHash)
|
|
907
|
-
continue;
|
|
908
|
-
const destPath = path.join(claudeDir, filePath);
|
|
909
|
-
safeBackupFile(destPath);
|
|
910
|
-
copyTemplateFile(TEMPLATES_DIR, filePath, destPath);
|
|
911
|
-
manifest.files[filePath] = templateFileRecord(templateHash);
|
|
912
|
-
console.log(` UPDATE ${filePath}`);
|
|
913
|
-
}
|
|
914
|
-
// 5d. Remove deleted files
|
|
915
|
-
for (const filePath of plan.toRemove) {
|
|
916
|
-
const absPath = path.join(claudeDir, filePath);
|
|
917
|
-
if (fs.existsSync(absPath)) {
|
|
918
|
-
safeBackupFile(absPath);
|
|
919
|
-
fs.unlinkSync(absPath);
|
|
920
|
-
}
|
|
921
|
-
delete manifest.files[filePath];
|
|
922
|
-
console.log(` REMOVE ${filePath}`);
|
|
923
|
-
}
|
|
924
|
-
// 5e. Update pinned/modified file records (record new template hash without touching file)
|
|
925
|
-
for (const { file, reason, newTemplateHash } of plan.toSkip) {
|
|
926
|
-
if (manifest.files[file]) {
|
|
927
|
-
manifest.files[file].templateHash = newTemplateHash;
|
|
928
|
-
}
|
|
929
|
-
if (reason === 'modified') {
|
|
930
|
-
console.log(` SKIP ${file} (user modified)`);
|
|
931
|
-
}
|
|
932
|
-
else {
|
|
933
|
-
console.log(` SKIP ${file} (pinned)`);
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
// 5f. Clean up empty directories
|
|
937
|
-
for (const dir of ['hooks', 'skills', 'agents', 'config/workflows']) {
|
|
938
|
-
const dirPath = path.join(claudeDir, dir);
|
|
939
|
-
if (fs.existsSync(dirPath))
|
|
940
|
-
cleanEmptyDirs(dirPath);
|
|
941
|
-
}
|
|
942
|
-
// 6. Bidirectional settings hook sync
|
|
943
|
-
const settingsTarget = path.join(claudeDir, 'settings.local.json');
|
|
944
|
-
const settingsSrc = path.join(TEMPLATES_DIR, 'settings-hooks.json');
|
|
945
|
-
const syncResult = syncSettingsHooks(settingsTarget, settingsSrc, manifest.settingsHooksChecksum, renameMap);
|
|
946
|
-
if (!syncResult.skipped) {
|
|
947
|
-
console.log(` Settings +${syncResult.added} -${syncResult.removed} hooks (${syncResult.updated} renamed)`);
|
|
948
|
-
manifest.settingsHooksChecksum = getTemplateChecksum(settingsSrc);
|
|
949
|
-
}
|
|
950
|
-
// 7. Config migrations
|
|
951
|
-
const configPath = path.join(claudeDir, 'orbital.config.json');
|
|
952
|
-
const migrationResult = migrateConfig(configPath, manifest.appliedMigrations);
|
|
953
|
-
if (migrationResult.applied.length > 0) {
|
|
954
|
-
manifest.appliedMigrations.push(...migrationResult.applied);
|
|
955
|
-
console.log(` Config ${migrationResult.applied.length} migration(s) applied`);
|
|
956
|
-
}
|
|
957
|
-
if (migrationResult.defaultsFilled.length > 0) {
|
|
958
|
-
console.log(` Config ${migrationResult.defaultsFilled.length} default(s) filled`);
|
|
959
|
-
}
|
|
960
|
-
// 8. Regenerate derived artifacts (always)
|
|
961
|
-
const workflowManifestOk = writeManifest(claudeDir);
|
|
962
|
-
console.log(` ${workflowManifestOk ? 'Updated' : 'Skipped'} .claude/config/workflow-manifest.sh`);
|
|
963
|
-
const indexContent = generateIndexMd(projectRoot, claudeDir);
|
|
964
|
-
fs.writeFileSync(path.join(claudeDir, 'INDEX.md'), indexContent, 'utf8');
|
|
965
|
-
console.log(` Updated .claude/INDEX.md`);
|
|
966
|
-
// 9. Update agent-triggers.json (template-managed)
|
|
967
|
-
const triggersSrc = path.join(TEMPLATES_DIR, 'config', 'agent-triggers.json');
|
|
968
|
-
const triggersDest = path.join(claudeDir, 'config', 'agent-triggers.json');
|
|
969
|
-
if (fs.existsSync(triggersSrc)) {
|
|
970
|
-
fs.copyFileSync(triggersSrc, triggersDest);
|
|
971
|
-
console.log(` Updated .claude/config/agent-triggers.json`);
|
|
972
|
-
}
|
|
973
|
-
// 10. Update scope template
|
|
974
|
-
const scopeTemplateSrc = path.join(TEMPLATES_DIR, 'scopes', '_template.md');
|
|
975
|
-
const scopeTemplateDest = path.join(projectRoot, 'scopes', '_template.md');
|
|
976
|
-
if (fs.existsSync(scopeTemplateSrc)) {
|
|
977
|
-
ensureDir(path.join(projectRoot, 'scopes'));
|
|
978
|
-
fs.copyFileSync(scopeTemplateSrc, scopeTemplateDest);
|
|
979
|
-
}
|
|
980
|
-
// 11. Make hook scripts executable
|
|
981
|
-
chmodScripts(path.join(claudeDir, 'hooks'));
|
|
982
|
-
// 12. Refresh global primitives
|
|
983
|
-
seedGlobalPrimitives();
|
|
984
|
-
// 13. Update manifest metadata
|
|
985
|
-
manifest.previousPackageVersion = oldVersion;
|
|
986
|
-
manifest.packageVersion = newVersion;
|
|
987
|
-
manifest.updatedAt = new Date().toISOString();
|
|
988
|
-
saveManifest(projectRoot, manifest);
|
|
989
|
-
// 14. Validate
|
|
990
|
-
const report = validate(projectRoot, newVersion);
|
|
991
|
-
if (report.errors > 0) {
|
|
992
|
-
console.log(`\n Validation: ${report.errors} errors found`);
|
|
993
|
-
console.log(formatValidationReport(report));
|
|
994
|
-
}
|
|
995
|
-
const totalChanges = plan.toAdd.length + plan.toUpdate.length + plan.toRemove.length + plan.toRename.length;
|
|
996
|
-
console.log(`\nUpdate complete. ${totalChanges} file changes, ${plan.toSkip.length} skipped.\n`);
|
|
997
|
-
}
|
|
998
|
-
export function runUninstall(projectRoot, options = {}) {
|
|
999
|
-
const { dryRun = false, keepConfig = false } = options;
|
|
1000
|
-
const claudeDir = path.join(projectRoot, '.claude');
|
|
1001
|
-
console.log(`\nOrbital Command — uninstall${dryRun ? ' (dry run)' : ''}`);
|
|
1002
|
-
console.log(`Project root: ${projectRoot}\n`);
|
|
1003
|
-
const manifest = loadManifest(projectRoot);
|
|
1004
|
-
// Fall back to legacy uninstall if no manifest
|
|
1005
|
-
if (!manifest) {
|
|
1006
|
-
console.log(' No manifest found — falling back to legacy uninstall.');
|
|
1007
|
-
runLegacyUninstall(projectRoot);
|
|
1008
|
-
return;
|
|
1009
|
-
}
|
|
1010
|
-
// Compute what to remove vs preserve
|
|
1011
|
-
const toRemove = [];
|
|
1012
|
-
const toPreserve = [];
|
|
1013
|
-
for (const [filePath, record] of Object.entries(manifest.files)) {
|
|
1014
|
-
if (record.origin === 'user') {
|
|
1015
|
-
toPreserve.push(filePath);
|
|
1016
|
-
}
|
|
1017
|
-
else if (record.status === 'modified' || record.status === 'outdated') {
|
|
1018
|
-
toPreserve.push(filePath);
|
|
1019
|
-
}
|
|
1020
|
-
else {
|
|
1021
|
-
toRemove.push(filePath);
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
if (dryRun) {
|
|
1025
|
-
console.log(' Files to REMOVE:');
|
|
1026
|
-
for (const f of toRemove)
|
|
1027
|
-
console.log(` ${f}`);
|
|
1028
|
-
if (toPreserve.length > 0) {
|
|
1029
|
-
console.log(' Files to PRESERVE:');
|
|
1030
|
-
for (const f of toPreserve)
|
|
1031
|
-
console.log(` ${f} (${manifest.files[f].origin}/${manifest.files[f].status})`);
|
|
1032
|
-
}
|
|
1033
|
-
console.log(`\n Would also remove: settings hooks, generated artifacts, config files, gitignore entries`);
|
|
1034
|
-
console.log(` No changes made. Run without --dry-run to apply.`);
|
|
1035
|
-
return;
|
|
1036
|
-
}
|
|
1037
|
-
// 1. Remove _orbital hooks from settings.local.json
|
|
1038
|
-
const settingsPath = path.join(claudeDir, 'settings.local.json');
|
|
1039
|
-
const removedHooks = removeAllOrbitalHooks(settingsPath);
|
|
1040
|
-
console.log(` Removed ${removedHooks} orbital hook registrations`);
|
|
1041
|
-
// 2. Delete template files (synced + pinned, not modified or user-owned)
|
|
1042
|
-
let filesRemoved = 0;
|
|
1043
|
-
for (const filePath of toRemove) {
|
|
1044
|
-
const absPath = path.join(claudeDir, filePath);
|
|
1045
|
-
if (fs.existsSync(absPath)) {
|
|
1046
|
-
fs.unlinkSync(absPath);
|
|
1047
|
-
filesRemoved++;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
console.log(` Removed ${filesRemoved} template files`);
|
|
1051
|
-
if (toPreserve.length > 0) {
|
|
1052
|
-
console.log(` Preserved ${toPreserve.length} user/modified files`);
|
|
1053
|
-
}
|
|
1054
|
-
// 3. Clean up empty directories
|
|
1055
|
-
for (const dir of ['hooks', 'skills', 'agents', 'config/workflows', 'quick', 'anti-patterns']) {
|
|
1056
|
-
const dirPath = path.join(claudeDir, dir);
|
|
1057
|
-
if (fs.existsSync(dirPath))
|
|
1058
|
-
cleanEmptyDirs(dirPath);
|
|
1059
|
-
}
|
|
1060
|
-
// 4. Remove generated artifacts
|
|
1061
|
-
for (const artifact of manifest.generatedArtifacts) {
|
|
1062
|
-
const artifactPath = path.join(claudeDir, artifact);
|
|
1063
|
-
if (fs.existsSync(artifactPath)) {
|
|
1064
|
-
fs.unlinkSync(artifactPath);
|
|
1065
|
-
console.log(` Removed .claude/${artifact}`);
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
// 5. Remove template-sourced config files
|
|
1069
|
-
const configFiles = [
|
|
1070
|
-
'config/agent-triggers.json',
|
|
1071
|
-
'config/workflow.json',
|
|
1072
|
-
'lessons-learned.md',
|
|
1073
|
-
];
|
|
1074
|
-
for (const file of configFiles) {
|
|
1075
|
-
const filePath = path.join(claudeDir, file);
|
|
1076
|
-
if (fs.existsSync(filePath)) {
|
|
1077
|
-
fs.unlinkSync(filePath);
|
|
1078
|
-
console.log(` Removed .claude/${file}`);
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
// Remove config/workflows/ directory entirely
|
|
1082
|
-
const workflowsDir = path.join(claudeDir, 'config', 'workflows');
|
|
1083
|
-
if (fs.existsSync(workflowsDir)) {
|
|
1084
|
-
fs.rmSync(workflowsDir, { recursive: true, force: true });
|
|
1085
|
-
console.log(` Removed .claude/config/workflows/`);
|
|
1086
|
-
}
|
|
1087
|
-
// 6. Remove gitignore entries
|
|
1088
|
-
removeGitignoreEntries(projectRoot, manifest.gitignoreEntries);
|
|
1089
|
-
console.log(` Cleaned .gitignore`);
|
|
1090
|
-
// 7. Deregister from global registry
|
|
1091
|
-
if (unregisterProject(projectRoot)) {
|
|
1092
|
-
console.log(` Removed project from ~/.orbital/config.json`);
|
|
1093
|
-
}
|
|
1094
|
-
// 8. Remove orbital config and manifest (unless --keep-config)
|
|
1095
|
-
if (!keepConfig) {
|
|
1096
|
-
const toClean = ['orbital.config.json', 'orbital-manifest.json', 'orbital-sync.json'];
|
|
1097
|
-
for (const file of toClean) {
|
|
1098
|
-
const filePath = path.join(claudeDir, file);
|
|
1099
|
-
if (fs.existsSync(filePath))
|
|
1100
|
-
fs.unlinkSync(filePath);
|
|
1101
|
-
}
|
|
1102
|
-
// Remove backups directory
|
|
1103
|
-
const backupsDir = path.join(claudeDir, '.orbital-backups');
|
|
1104
|
-
if (fs.existsSync(backupsDir))
|
|
1105
|
-
fs.rmSync(backupsDir, { recursive: true, force: true });
|
|
1106
|
-
console.log(` Removed orbital config and manifest`);
|
|
1107
|
-
}
|
|
1108
|
-
else {
|
|
1109
|
-
// Still remove the manifest — it's invalid after uninstall
|
|
1110
|
-
const manifestPath = path.join(claudeDir, 'orbital-manifest.json');
|
|
1111
|
-
if (fs.existsSync(manifestPath))
|
|
1112
|
-
fs.unlinkSync(manifestPath);
|
|
1113
|
-
console.log(` Kept orbital.config.json (--keep-config)`);
|
|
1114
|
-
}
|
|
1115
|
-
// Clean up remaining empty directories
|
|
1116
|
-
for (const dir of ['config', 'quick', 'anti-patterns', 'review-verdicts']) {
|
|
1117
|
-
const dirPath = path.join(claudeDir, dir);
|
|
1118
|
-
if (fs.existsSync(dirPath))
|
|
1119
|
-
cleanEmptyDirs(dirPath);
|
|
1120
|
-
}
|
|
1121
|
-
const total = removedHooks + filesRemoved;
|
|
1122
|
-
console.log(`\nUninstall complete. ${total} items removed.`);
|
|
1123
|
-
if (toPreserve.length > 0) {
|
|
1124
|
-
console.log(`Note: ${toPreserve.length} user/modified files were preserved.`);
|
|
1125
|
-
}
|
|
1126
|
-
console.log(`Note: scopes/ and .claude/orbital-events/ were preserved.\n`);
|
|
1127
|
-
}
|
|
1128
|
-
/** Legacy uninstall for projects without a manifest (backward compat). */
|
|
1129
|
-
function runLegacyUninstall(projectRoot) {
|
|
1130
|
-
const claudeDir = path.join(projectRoot, '.claude');
|
|
1131
|
-
// Remove orbital hooks from settings.local.json
|
|
1132
|
-
const settingsPath = path.join(claudeDir, 'settings.local.json');
|
|
1133
|
-
const removedHooks = removeAllOrbitalHooks(settingsPath);
|
|
1134
|
-
console.log(` Removed ${removedHooks} orbital hook registrations`);
|
|
1135
|
-
// Delete hooks/skills/agents that match template files
|
|
1136
|
-
for (const dir of ['hooks', 'skills', 'agents']) {
|
|
1137
|
-
const templateFiles = listTemplateFiles(path.join(TEMPLATES_DIR, dir), path.join(claudeDir, dir));
|
|
1138
|
-
let removed = 0;
|
|
1139
|
-
for (const f of templateFiles) {
|
|
1140
|
-
if (fs.existsSync(f)) {
|
|
1141
|
-
fs.unlinkSync(f);
|
|
1142
|
-
removed++;
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
const dirPath = path.join(claudeDir, dir);
|
|
1146
|
-
if (fs.existsSync(dirPath))
|
|
1147
|
-
cleanEmptyDirs(dirPath);
|
|
1148
|
-
console.log(` Removed ${removed} ${dir} files`);
|
|
1149
|
-
}
|
|
1150
|
-
console.log(`\nLegacy uninstall complete.`);
|
|
1151
|
-
console.log(`Note: scopes/ and .claude/orbital-events/ were preserved.\n`);
|
|
1152
|
-
}
|
|
1153
|
-
/** Remove Orbital-added entries from .gitignore. */
|
|
1154
|
-
function removeGitignoreEntries(projectRoot, entries) {
|
|
1155
|
-
const gitignorePath = path.join(projectRoot, '.gitignore');
|
|
1156
|
-
if (!fs.existsSync(gitignorePath))
|
|
1157
|
-
return;
|
|
1158
|
-
let content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
1159
|
-
const marker = '# Orbital Command';
|
|
1160
|
-
// Try to remove the entire block
|
|
1161
|
-
const markerIdx = content.indexOf(marker);
|
|
1162
|
-
if (markerIdx !== -1) {
|
|
1163
|
-
// Find the block boundaries: from the marker to the next non-empty/non-orbital line
|
|
1164
|
-
const before = content.slice(0, markerIdx).replace(/\n+$/, '');
|
|
1165
|
-
const after = content.slice(markerIdx);
|
|
1166
|
-
const lines = after.split('\n');
|
|
1167
|
-
let endIdx = 0;
|
|
1168
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1169
|
-
const line = lines[i].trim();
|
|
1170
|
-
if (i === 0) {
|
|
1171
|
-
endIdx = i + 1;
|
|
1172
|
-
continue;
|
|
1173
|
-
} // skip the marker line
|
|
1174
|
-
if (line === '' || entries.includes(line)) {
|
|
1175
|
-
endIdx = i + 1;
|
|
1176
|
-
continue;
|
|
1177
|
-
}
|
|
1178
|
-
break;
|
|
1179
|
-
}
|
|
1180
|
-
const remaining = lines.slice(endIdx).join('\n');
|
|
1181
|
-
content = before + (remaining ? '\n' + remaining : '') + '\n';
|
|
1182
|
-
fs.writeFileSync(gitignorePath, content, 'utf-8');
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
/** Copy a single template file to a destination, resolving the template path. */
|
|
1186
|
-
function copyTemplateFile(templatesDir, claudeRelPath, destPath) {
|
|
1187
|
-
const templateRelPath = reverseRemapPath(claudeRelPath);
|
|
1188
|
-
const srcPath = path.join(templatesDir, templateRelPath);
|
|
1189
|
-
if (!fs.existsSync(srcPath)) {
|
|
1190
|
-
throw new Error(`Template file not found: ${templateRelPath}`);
|
|
1191
|
-
}
|
|
1192
|
-
const destDir = path.dirname(destPath);
|
|
1193
|
-
if (!fs.existsSync(destDir))
|
|
1194
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
1195
|
-
safeCopyTemplate(srcPath, destPath);
|
|
1196
|
-
}
|
|
828
|
+
// runUpdate and runUninstall have been extracted to update.ts and uninstall.ts
|
|
829
|
+
// and are re-exported above for backward compatibility.
|
|
@@ -32,7 +32,10 @@ export function parseEventFile(filePath) {
|
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
catch (err) {
|
|
35
|
-
|
|
35
|
+
const code = err.code;
|
|
36
|
+
if (code !== 'ENOENT') {
|
|
37
|
+
log.warn('Failed to parse event file', { file: filePath, error: err.message });
|
|
38
|
+
}
|
|
36
39
|
return null;
|
|
37
40
|
}
|
|
38
41
|
}
|
|
@@ -21,7 +21,6 @@ import { startScopeWatcher } from './watchers/scope-watcher.js';
|
|
|
21
21
|
import { startEventWatcher } from './watchers/event-watcher.js';
|
|
22
22
|
import { resolveStaleDispatches, resolveActiveDispatchesForScope, resolveDispatchesByPid, resolveDispatchesByDispatchId, linkPidToDispatch, tryAutoRevertAndClear } from './utils/dispatch-utils.js';
|
|
23
23
|
import { syncClaudeSessionsToDB } from './services/claude-session-service.js';
|
|
24
|
-
import { TelemetryService } from './services/telemetry-service.js';
|
|
25
24
|
import { ensureDynamicProfiles } from './utils/terminal-launcher.js';
|
|
26
25
|
import { createLogger } from './utils/logger.js';
|
|
27
26
|
const log = createLogger('project-context');
|
|
@@ -60,8 +59,8 @@ export async function createProjectContext(projectId, projectRoot, emitter) {
|
|
|
60
59
|
const gateService = new GateService(db, emitter);
|
|
61
60
|
const deployService = new DeployService(db, emitter);
|
|
62
61
|
const sprintService = new SprintService(db, emitter, scopeService);
|
|
63
|
-
const sprintOrchestrator = new SprintOrchestrator(db, emitter, sprintService, scopeService, workflowEngine, config.projectRoot);
|
|
64
|
-
const batchOrchestrator = new BatchOrchestrator(db, emitter, sprintService, scopeService, workflowEngine, config.projectRoot);
|
|
62
|
+
const sprintOrchestrator = new SprintOrchestrator(db, emitter, sprintService, scopeService, workflowEngine, config.projectRoot, config);
|
|
63
|
+
const batchOrchestrator = new BatchOrchestrator(db, emitter, sprintService, scopeService, workflowEngine, config.projectRoot, config);
|
|
65
64
|
const readinessService = new ReadinessService(scopeService, gateService, workflowEngine, config.projectRoot);
|
|
66
65
|
const workflowService = new WorkflowService(config.configDir, workflowEngine, config.scopesDir, getDefaultConfigPath());
|
|
67
66
|
workflowService.setSocketServer(emitter);
|
|
@@ -69,7 +68,17 @@ export async function createProjectContext(projectId, projectRoot, emitter) {
|
|
|
69
68
|
workflowEngine.reload(workflowService.getActive());
|
|
70
69
|
const gitService = new GitService(config.projectRoot, scopeCache);
|
|
71
70
|
const githubService = new GitHubService(config.projectRoot);
|
|
72
|
-
|
|
71
|
+
let telemetryService = null;
|
|
72
|
+
let telemetryRouter = null;
|
|
73
|
+
const telemetryMod = './services/telemetry-service.js';
|
|
74
|
+
try {
|
|
75
|
+
const mod = await import(telemetryMod);
|
|
76
|
+
telemetryService = new mod.TelemetryService(db, config.telemetry, config.projectName, config.projectRoot);
|
|
77
|
+
if (telemetryService?.enabled) {
|
|
78
|
+
telemetryRouter = mod.createTelemetryRoutes({ telemetryService });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch { /* telemetry service not installed */ }
|
|
73
82
|
// Wire active-group guard
|
|
74
83
|
scopeService.setActiveGroupCheck((scopeId) => sprintService.getActiveGroupForScope(scopeId));
|
|
75
84
|
// Wire event inference (Fix 8: diagnostic log lines match index.ts)
|
|
@@ -130,7 +139,7 @@ export async function createProjectContext(projectId, projectRoot, emitter) {
|
|
|
130
139
|
});
|
|
131
140
|
// Wire status change callbacks
|
|
132
141
|
scopeService.onStatusChange((scopeId, newStatus) => {
|
|
133
|
-
if (newStatus
|
|
142
|
+
if (workflowEngine.isTerminalStatus(newStatus))
|
|
134
143
|
sprintOrchestrator.onScopeReachedDev(scopeId);
|
|
135
144
|
batchOrchestrator.onScopeStatusChanged(scopeId, newStatus);
|
|
136
145
|
});
|
|
@@ -157,7 +166,7 @@ export async function createProjectContext(projectId, projectRoot, emitter) {
|
|
|
157
166
|
if (staleBatchesResolved > 0)
|
|
158
167
|
log.info('Resolved stale batches', { count: staleBatchesResolved });
|
|
159
168
|
// Resolve stale dispatches
|
|
160
|
-
resolveStaleDispatches(db, emitter, scopeService, workflowEngine);
|
|
169
|
+
resolveStaleDispatches(db, emitter, scopeService, workflowEngine, config.dispatch.staleTimeoutMinutes);
|
|
161
170
|
// Initial session sync + legacy purge (Fix 7)
|
|
162
171
|
syncClaudeSessionsToDB(db, scopeService, config.projectRoot).then((count) => {
|
|
163
172
|
if (count > 0)
|
|
@@ -165,7 +174,7 @@ export async function createProjectContext(projectId, projectRoot, emitter) {
|
|
|
165
174
|
const purged = db.prepare("DELETE FROM sessions WHERE action IS NULL AND id LIKE 'claude-%'").run();
|
|
166
175
|
if (purged.changes > 0)
|
|
167
176
|
log.info('Purged legacy session rows', { count: purged.changes });
|
|
168
|
-
if (telemetryService
|
|
177
|
+
if (telemetryService?.enabled) {
|
|
169
178
|
telemetryService.uploadChangedSessions().catch(() => { });
|
|
170
179
|
}
|
|
171
180
|
}).catch(err => log.error('Session sync failed', { error: err.message }));
|
|
@@ -179,13 +188,13 @@ export async function createProjectContext(projectId, projectRoot, emitter) {
|
|
|
179
188
|
batchOrchestrator.resolveStaleBatches();
|
|
180
189
|
}, 30_000));
|
|
181
190
|
intervals.push(setInterval(() => {
|
|
182
|
-
resolveStaleDispatches(db, emitter, scopeService, workflowEngine);
|
|
191
|
+
resolveStaleDispatches(db, emitter, scopeService, workflowEngine, config.dispatch.staleTimeoutMinutes);
|
|
183
192
|
}, 30_000));
|
|
184
193
|
intervals.push(setInterval(async () => {
|
|
185
194
|
const count = await syncClaudeSessionsToDB(db, scopeService, config.projectRoot);
|
|
186
195
|
if (count > 0)
|
|
187
196
|
emitter.emit('session:updated', { type: 'resync', count });
|
|
188
|
-
if (telemetryService
|
|
197
|
+
if (telemetryService?.enabled) {
|
|
189
198
|
telemetryService.uploadChangedSessions().catch(() => { });
|
|
190
199
|
}
|
|
191
200
|
}, 5 * 60_000));
|
|
@@ -221,6 +230,7 @@ export async function createProjectContext(projectId, projectRoot, emitter) {
|
|
|
221
230
|
gitService,
|
|
222
231
|
githubService,
|
|
223
232
|
telemetryService,
|
|
233
|
+
telemetryRouter,
|
|
224
234
|
scopeWatcher,
|
|
225
235
|
eventWatcher,
|
|
226
236
|
intervals,
|
|
@@ -11,7 +11,6 @@ import { createWorkflowRoutes } from './routes/workflow-routes.js';
|
|
|
11
11
|
import { createConfigRoutes } from './routes/config-routes.js';
|
|
12
12
|
import { createGitRoutes } from './routes/git-routes.js';
|
|
13
13
|
import { createManifestRoutes } from './routes/manifest-routes.js';
|
|
14
|
-
import { createTelemetryRoutes } from './services/telemetry-service.js';
|
|
15
14
|
import { TEMPLATES_DIR } from './init.js';
|
|
16
15
|
import { getPackageVersion } from './utils/package-info.js';
|
|
17
16
|
import { resolveActiveDispatchesForScope } from './utils/dispatch-utils.js';
|
|
@@ -227,7 +226,7 @@ export class ProjectManager {
|
|
|
227
226
|
* are global (they update the Orbital Command package), not per-project. */
|
|
228
227
|
buildProjectRouter(ctx) {
|
|
229
228
|
const router = Router();
|
|
230
|
-
const { db, emitter, config, scopeService, eventService, gateService, deployService, sprintService, sprintOrchestrator, batchOrchestrator, readinessService, workflowService, workflowEngine, gitService, githubService
|
|
229
|
+
const { db, emitter, config, scopeService, eventService, gateService, deployService, sprintService, sprintOrchestrator, batchOrchestrator, readinessService, workflowService, workflowEngine, gitService, githubService } = ctx;
|
|
231
230
|
// Scope status inference function (same logic as index.ts)
|
|
232
231
|
function inferScopeStatus(eventType, scopeId, data) {
|
|
233
232
|
if (scopeId == null)
|
|
@@ -262,16 +261,16 @@ export class ProjectManager {
|
|
|
262
261
|
router.use(createScopeRoutes({
|
|
263
262
|
db, io: emitter, scopeService, readinessService,
|
|
264
263
|
projectRoot: config.projectRoot, projectName: config.projectName,
|
|
265
|
-
engine: workflowEngine,
|
|
264
|
+
engine: workflowEngine, config,
|
|
266
265
|
}));
|
|
267
266
|
router.use(createDataRoutes({
|
|
268
267
|
db, io: emitter, eventService, gateService, deployService, gitService,
|
|
269
268
|
engine: workflowEngine, projectRoot: config.projectRoot,
|
|
270
|
-
inferScopeStatus,
|
|
269
|
+
inferScopeStatus, config,
|
|
271
270
|
}));
|
|
272
271
|
router.use(createDispatchRoutes({
|
|
273
272
|
db, io: emitter, scopeService,
|
|
274
|
-
projectRoot: config.projectRoot, engine: workflowEngine,
|
|
273
|
+
projectRoot: config.projectRoot, engine: workflowEngine, config,
|
|
275
274
|
}));
|
|
276
275
|
router.use(createSprintRoutes({
|
|
277
276
|
sprintService, sprintOrchestrator, batchOrchestrator,
|
|
@@ -291,7 +290,8 @@ export class ProjectManager {
|
|
|
291
290
|
packageVersion: getPackageVersion(),
|
|
292
291
|
io: emitter,
|
|
293
292
|
}));
|
|
294
|
-
|
|
293
|
+
if (ctx.telemetryRouter)
|
|
294
|
+
router.use(ctx.telemetryRouter);
|
|
295
295
|
return router;
|
|
296
296
|
}
|
|
297
297
|
}
|