gsd-opencode 1.22.1 → 1.33.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/agents/gsd-advisor-researcher.md +112 -0
- package/agents/gsd-assumptions-analyzer.md +110 -0
- package/agents/gsd-codebase-mapper.md +0 -2
- package/agents/gsd-debugger.md +117 -2
- package/agents/gsd-doc-verifier.md +207 -0
- package/agents/gsd-doc-writer.md +608 -0
- package/agents/gsd-executor.md +45 -4
- package/agents/gsd-integration-checker.md +0 -2
- package/agents/gsd-nyquist-auditor.md +0 -2
- package/agents/gsd-phase-researcher.md +191 -5
- package/agents/gsd-plan-checker.md +152 -5
- package/agents/gsd-planner.md +131 -157
- package/agents/gsd-project-researcher.md +28 -3
- package/agents/gsd-research-synthesizer.md +0 -2
- package/agents/gsd-roadmapper.md +29 -2
- package/agents/gsd-security-auditor.md +129 -0
- package/agents/gsd-ui-auditor.md +485 -0
- package/agents/gsd-ui-checker.md +305 -0
- package/agents/gsd-ui-researcher.md +368 -0
- package/agents/gsd-user-profiler.md +173 -0
- package/agents/gsd-verifier.md +207 -22
- package/commands/gsd/gsd-add-backlog.md +76 -0
- package/commands/gsd/gsd-analyze-dependencies.md +34 -0
- package/commands/gsd/gsd-audit-uat.md +24 -0
- package/commands/gsd/gsd-autonomous.md +45 -0
- package/commands/gsd/gsd-cleanup.md +5 -0
- package/commands/gsd/gsd-debug.md +29 -21
- package/commands/gsd/gsd-discuss-phase.md +15 -36
- package/commands/gsd/gsd-do.md +30 -0
- package/commands/gsd/gsd-docs-update.md +48 -0
- package/commands/gsd/gsd-execute-phase.md +24 -2
- package/commands/gsd/gsd-fast.md +30 -0
- package/commands/gsd/gsd-forensics.md +56 -0
- package/commands/gsd/gsd-help.md +2 -0
- package/commands/gsd/gsd-join-discord.md +2 -1
- package/commands/gsd/gsd-list-workspaces.md +19 -0
- package/commands/gsd/gsd-manager.md +40 -0
- package/commands/gsd/gsd-milestone-summary.md +51 -0
- package/commands/gsd/gsd-new-project.md +4 -0
- package/commands/gsd/gsd-new-workspace.md +44 -0
- package/commands/gsd/gsd-next.md +24 -0
- package/commands/gsd/gsd-note.md +34 -0
- package/commands/gsd/gsd-plan-phase.md +8 -1
- package/commands/gsd/gsd-plant-seed.md +28 -0
- package/commands/gsd/gsd-pr-branch.md +25 -0
- package/commands/gsd/gsd-profile-user.md +46 -0
- package/commands/gsd/gsd-quick.md +7 -3
- package/commands/gsd/gsd-reapply-patches.md +178 -45
- package/commands/gsd/gsd-remove-workspace.md +26 -0
- package/commands/gsd/gsd-research-phase.md +7 -12
- package/commands/gsd/gsd-review-backlog.md +62 -0
- package/commands/gsd/gsd-review.md +38 -0
- package/commands/gsd/gsd-secure-phase.md +35 -0
- package/commands/gsd/gsd-session-report.md +19 -0
- package/commands/gsd/gsd-set-profile.md +24 -23
- package/commands/gsd/gsd-ship.md +23 -0
- package/commands/gsd/gsd-stats.md +18 -0
- package/commands/gsd/gsd-thread.md +127 -0
- package/commands/gsd/gsd-ui-phase.md +34 -0
- package/commands/gsd/gsd-ui-review.md +32 -0
- package/commands/gsd/gsd-workstreams.md +71 -0
- package/get-shit-done/bin/gsd-tools.cjs +450 -90
- package/get-shit-done/bin/lib/commands.cjs +489 -24
- package/get-shit-done/bin/lib/config.cjs +329 -48
- package/get-shit-done/bin/lib/core.cjs +1143 -102
- package/get-shit-done/bin/lib/docs.cjs +267 -0
- package/get-shit-done/bin/lib/frontmatter.cjs +125 -43
- package/get-shit-done/bin/lib/init.cjs +918 -106
- package/get-shit-done/bin/lib/milestone.cjs +65 -33
- package/get-shit-done/bin/lib/model-profiles.cjs +70 -0
- package/get-shit-done/bin/lib/phase.cjs +434 -404
- package/get-shit-done/bin/lib/profile-output.cjs +1048 -0
- package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
- package/get-shit-done/bin/lib/roadmap.cjs +156 -101
- package/get-shit-done/bin/lib/schema-detect.cjs +238 -0
- package/get-shit-done/bin/lib/security.cjs +384 -0
- package/get-shit-done/bin/lib/state.cjs +711 -79
- package/get-shit-done/bin/lib/template.cjs +2 -2
- package/get-shit-done/bin/lib/uat.cjs +282 -0
- package/get-shit-done/bin/lib/verify.cjs +254 -42
- package/get-shit-done/bin/lib/workstream.cjs +495 -0
- package/get-shit-done/references/agent-contracts.md +79 -0
- package/get-shit-done/references/artifact-types.md +113 -0
- package/get-shit-done/references/checkpoints.md +12 -10
- package/get-shit-done/references/context-budget.md +49 -0
- package/get-shit-done/references/continuation-format.md +15 -15
- package/get-shit-done/references/decimal-phase-calculation.md +2 -3
- package/get-shit-done/references/domain-probes.md +125 -0
- package/get-shit-done/references/gate-prompts.md +100 -0
- package/get-shit-done/references/git-integration.md +47 -0
- package/get-shit-done/references/model-profile-resolution.md +2 -0
- package/get-shit-done/references/model-profiles.md +62 -16
- package/get-shit-done/references/phase-argument-parsing.md +2 -2
- package/get-shit-done/references/planner-gap-closure.md +62 -0
- package/get-shit-done/references/planner-reviews.md +39 -0
- package/get-shit-done/references/planner-revision.md +87 -0
- package/get-shit-done/references/planning-config.md +18 -1
- package/get-shit-done/references/revision-loop.md +97 -0
- package/get-shit-done/references/ui-brand.md +2 -2
- package/get-shit-done/references/universal-anti-patterns.md +58 -0
- package/get-shit-done/references/user-profiling.md +681 -0
- package/get-shit-done/references/workstream-flag.md +111 -0
- package/get-shit-done/templates/SECURITY.md +61 -0
- package/get-shit-done/templates/UAT.md +21 -3
- package/get-shit-done/templates/UI-SPEC.md +100 -0
- package/get-shit-done/templates/VALIDATION.md +3 -3
- package/get-shit-done/templates/claude-md.md +145 -0
- package/get-shit-done/templates/config.json +14 -3
- package/get-shit-done/templates/context.md +61 -6
- package/get-shit-done/templates/debug-subagent-prompt.md +2 -6
- package/get-shit-done/templates/dev-preferences.md +21 -0
- package/get-shit-done/templates/discussion-log.md +63 -0
- package/get-shit-done/templates/phase-prompt.md +46 -5
- package/get-shit-done/templates/planner-subagent-prompt.md +2 -10
- package/get-shit-done/templates/project.md +2 -0
- package/get-shit-done/templates/state.md +2 -2
- package/get-shit-done/templates/user-profile.md +146 -0
- package/get-shit-done/workflows/add-phase.md +4 -4
- package/get-shit-done/workflows/add-tests.md +4 -4
- package/get-shit-done/workflows/add-todo.md +4 -4
- package/get-shit-done/workflows/analyze-dependencies.md +96 -0
- package/get-shit-done/workflows/audit-milestone.md +20 -16
- package/get-shit-done/workflows/audit-uat.md +109 -0
- package/get-shit-done/workflows/autonomous.md +1036 -0
- package/get-shit-done/workflows/check-todos.md +4 -4
- package/get-shit-done/workflows/cleanup.md +4 -4
- package/get-shit-done/workflows/complete-milestone.md +22 -10
- package/get-shit-done/workflows/diagnose-issues.md +21 -7
- package/get-shit-done/workflows/discovery-phase.md +2 -2
- package/get-shit-done/workflows/discuss-phase-assumptions.md +671 -0
- package/get-shit-done/workflows/discuss-phase-power.md +291 -0
- package/get-shit-done/workflows/discuss-phase.md +558 -47
- package/get-shit-done/workflows/do.md +104 -0
- package/get-shit-done/workflows/docs-update.md +1093 -0
- package/get-shit-done/workflows/execute-phase.md +741 -58
- package/get-shit-done/workflows/execute-plan.md +77 -12
- package/get-shit-done/workflows/fast.md +105 -0
- package/get-shit-done/workflows/forensics.md +265 -0
- package/get-shit-done/workflows/health.md +28 -6
- package/get-shit-done/workflows/help.md +127 -7
- package/get-shit-done/workflows/insert-phase.md +4 -4
- package/get-shit-done/workflows/list-phase-assumptions.md +2 -2
- package/get-shit-done/workflows/list-workspaces.md +56 -0
- package/get-shit-done/workflows/manager.md +363 -0
- package/get-shit-done/workflows/map-codebase.md +83 -44
- package/get-shit-done/workflows/milestone-summary.md +223 -0
- package/get-shit-done/workflows/new-milestone.md +133 -25
- package/get-shit-done/workflows/new-project.md +216 -54
- package/get-shit-done/workflows/new-workspace.md +237 -0
- package/get-shit-done/workflows/next.md +97 -0
- package/get-shit-done/workflows/node-repair.md +92 -0
- package/get-shit-done/workflows/note.md +156 -0
- package/get-shit-done/workflows/pause-work.md +132 -15
- package/get-shit-done/workflows/plan-milestone-gaps.md +6 -7
- package/get-shit-done/workflows/plan-phase.md +513 -62
- package/get-shit-done/workflows/plant-seed.md +169 -0
- package/get-shit-done/workflows/pr-branch.md +129 -0
- package/get-shit-done/workflows/profile-user.md +450 -0
- package/get-shit-done/workflows/progress.md +154 -29
- package/get-shit-done/workflows/quick.md +285 -111
- package/get-shit-done/workflows/remove-phase.md +2 -2
- package/get-shit-done/workflows/remove-workspace.md +90 -0
- package/get-shit-done/workflows/research-phase.md +13 -9
- package/get-shit-done/workflows/resume-project.md +37 -18
- package/get-shit-done/workflows/review.md +281 -0
- package/get-shit-done/workflows/secure-phase.md +154 -0
- package/get-shit-done/workflows/session-report.md +146 -0
- package/get-shit-done/workflows/set-profile.md +2 -2
- package/get-shit-done/workflows/settings.md +91 -11
- package/get-shit-done/workflows/ship.md +237 -0
- package/get-shit-done/workflows/stats.md +60 -0
- package/get-shit-done/workflows/transition.md +150 -23
- package/get-shit-done/workflows/ui-phase.md +292 -0
- package/get-shit-done/workflows/ui-review.md +183 -0
- package/get-shit-done/workflows/update.md +262 -30
- package/get-shit-done/workflows/validate-phase.md +14 -17
- package/get-shit-done/workflows/verify-phase.md +143 -11
- package/get-shit-done/workflows/verify-work.md +141 -39
- package/package.json +1 -1
- package/skills/gsd-audit-milestone/SKILL.md +29 -0
- package/skills/gsd-cleanup/SKILL.md +19 -0
- package/skills/gsd-complete-milestone/SKILL.md +131 -0
- package/skills/gsd-discuss-phase/SKILL.md +54 -0
- package/skills/gsd-execute-phase/SKILL.md +49 -0
- package/skills/gsd-plan-phase/SKILL.md +37 -0
- package/skills/gsd-ui-phase/SKILL.md +24 -0
- package/skills/gsd-ui-review/SKILL.md +24 -0
- package/skills/gsd-verify-work/SKILL.md +30 -0
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const { safeReadFile, loadConfig, normalizePhaseName, escapeRegex, execGit, findPhaseInternal, getMilestoneInfo, stripShippedMilestones, extractCurrentMilestone, planningDir, planningRoot, output, error, checkAgentsInstalled, CONFIG_DEFAULTS } = require('./core.cjs');
|
|
8
9
|
const { extractFrontmatter, parseMustHavesBlock } = require('./frontmatter.cjs');
|
|
9
10
|
const { writeStateMd } = require('./state.cjs');
|
|
10
11
|
|
|
@@ -395,8 +396,8 @@ function cmdVerifyKeyLinks(cwd, planFilePath, raw) {
|
|
|
395
396
|
}
|
|
396
397
|
|
|
397
398
|
function cmdValidateConsistency(cwd, raw) {
|
|
398
|
-
const roadmapPath = path.join(cwd, '
|
|
399
|
-
const phasesDir = path.join(cwd, '
|
|
399
|
+
const roadmapPath = path.join(planningDir(cwd), 'ROADMAP.md');
|
|
400
|
+
const phasesDir = path.join(planningDir(cwd), 'phases');
|
|
400
401
|
const errors = [];
|
|
401
402
|
const warnings = [];
|
|
402
403
|
|
|
@@ -407,9 +408,10 @@ function cmdValidateConsistency(cwd, raw) {
|
|
|
407
408
|
return;
|
|
408
409
|
}
|
|
409
410
|
|
|
410
|
-
const
|
|
411
|
+
const roadmapContentRaw = fs.readFileSync(roadmapPath, 'utf-8');
|
|
412
|
+
const roadmapContent = extractCurrentMilestone(roadmapContentRaw, cwd);
|
|
411
413
|
|
|
412
|
-
// Extract phases from ROADMAP
|
|
414
|
+
// Extract phases from ROADMAP (archived milestones already stripped)
|
|
413
415
|
const roadmapPhases = new Set();
|
|
414
416
|
const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:/gi;
|
|
415
417
|
let m;
|
|
@@ -426,7 +428,7 @@ function cmdValidateConsistency(cwd, raw) {
|
|
|
426
428
|
const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
|
|
427
429
|
if (dm) diskPhases.add(dm[1]);
|
|
428
430
|
}
|
|
429
|
-
} catch {}
|
|
431
|
+
} catch { /* intentionally empty */ }
|
|
430
432
|
|
|
431
433
|
// Check: phases in ROADMAP but not on disk
|
|
432
434
|
for (const p of roadmapPhases) {
|
|
@@ -443,15 +445,18 @@ function cmdValidateConsistency(cwd, raw) {
|
|
|
443
445
|
}
|
|
444
446
|
}
|
|
445
447
|
|
|
446
|
-
// Check: sequential phase numbers (integers only)
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
448
|
+
// Check: sequential phase numbers (integers only, skip in custom naming mode)
|
|
449
|
+
const config = loadConfig(cwd);
|
|
450
|
+
if (config.phase_naming !== 'custom') {
|
|
451
|
+
const integerPhases = [...diskPhases]
|
|
452
|
+
.filter(p => !p.includes('.'))
|
|
453
|
+
.map(p => parseInt(p, 10))
|
|
454
|
+
.sort((a, b) => a - b);
|
|
455
|
+
|
|
456
|
+
for (let i = 1; i < integerPhases.length; i++) {
|
|
457
|
+
if (integerPhases[i] !== integerPhases[i - 1] + 1) {
|
|
458
|
+
warnings.push(`Gap in phase numbering: ${integerPhases[i - 1]} → ${integerPhases[i]}`);
|
|
459
|
+
}
|
|
455
460
|
}
|
|
456
461
|
}
|
|
457
462
|
|
|
@@ -488,7 +493,7 @@ function cmdValidateConsistency(cwd, raw) {
|
|
|
488
493
|
}
|
|
489
494
|
}
|
|
490
495
|
}
|
|
491
|
-
} catch {}
|
|
496
|
+
} catch { /* intentionally empty */ }
|
|
492
497
|
|
|
493
498
|
// Check: frontmatter in plans has required fields
|
|
494
499
|
try {
|
|
@@ -508,19 +513,33 @@ function cmdValidateConsistency(cwd, raw) {
|
|
|
508
513
|
}
|
|
509
514
|
}
|
|
510
515
|
}
|
|
511
|
-
} catch {}
|
|
516
|
+
} catch { /* intentionally empty */ }
|
|
512
517
|
|
|
513
518
|
const passed = errors.length === 0;
|
|
514
519
|
output({ passed, errors, warnings, warning_count: warnings.length }, raw, passed ? 'passed' : 'failed');
|
|
515
520
|
}
|
|
516
521
|
|
|
517
522
|
function cmdValidateHealth(cwd, options, raw) {
|
|
518
|
-
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
523
|
+
// Guard: detect if CWD is the home directory (likely accidental)
|
|
524
|
+
const resolved = path.resolve(cwd);
|
|
525
|
+
if (resolved === os.homedir()) {
|
|
526
|
+
output({
|
|
527
|
+
status: 'error',
|
|
528
|
+
errors: [{ code: 'E010', message: `CWD is home directory (${resolved}) — health check would read the wrong .planning/ directory. Run from your project root instead.`, fix: 'cd into your project directory and retry' }],
|
|
529
|
+
warnings: [],
|
|
530
|
+
info: [{ code: 'I010', message: `Resolved CWD: ${resolved}` }],
|
|
531
|
+
repairable_count: 0,
|
|
532
|
+
}, raw);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const planBase = planningDir(cwd);
|
|
537
|
+
const planRoot = planningRoot(cwd);
|
|
538
|
+
const projectPath = path.join(planRoot, 'PROJECT.md');
|
|
539
|
+
const roadmapPath = path.join(planBase, 'ROADMAP.md');
|
|
540
|
+
const statePath = path.join(planBase, 'STATE.md');
|
|
541
|
+
const configPath = path.join(planRoot, 'config.json');
|
|
542
|
+
const phasesDir = path.join(planBase, 'phases');
|
|
524
543
|
|
|
525
544
|
const errors = [];
|
|
526
545
|
const warnings = [];
|
|
@@ -536,7 +555,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
536
555
|
};
|
|
537
556
|
|
|
538
557
|
// ─── Check 1: .planning/ exists ───────────────────────────────────────────
|
|
539
|
-
if (!fs.existsSync(
|
|
558
|
+
if (!fs.existsSync(planBase)) {
|
|
540
559
|
addIssue('error', 'E001', '.planning/ directory not found', 'Run /gsd-new-project to initialize');
|
|
541
560
|
output({
|
|
542
561
|
status: 'broken',
|
|
@@ -584,15 +603,19 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
584
603
|
if (m) diskPhases.add(m[1]);
|
|
585
604
|
}
|
|
586
605
|
}
|
|
587
|
-
} catch {}
|
|
606
|
+
} catch { /* intentionally empty */ }
|
|
588
607
|
// Check for invalid references
|
|
589
608
|
for (const ref of phaseRefs) {
|
|
590
609
|
const normalizedRef = String(parseInt(ref, 10)).padStart(2, '0');
|
|
591
610
|
if (!diskPhases.has(ref) && !diskPhases.has(normalizedRef) && !diskPhases.has(String(parseInt(ref, 10)))) {
|
|
592
611
|
// Only warn if phases dir has any content (not just an empty project)
|
|
593
612
|
if (diskPhases.size > 0) {
|
|
594
|
-
addIssue(
|
|
595
|
-
|
|
613
|
+
addIssue(
|
|
614
|
+
'warning',
|
|
615
|
+
'W002',
|
|
616
|
+
`STATE.md references phase ${ref}, but only phases ${[...diskPhases].sort().join(', ')} exist`,
|
|
617
|
+
'Review STATE.md manually before changing it; /gsd-health --repair will not overwrite an existing STATE.md for phase mismatches'
|
|
618
|
+
);
|
|
596
619
|
}
|
|
597
620
|
}
|
|
598
621
|
}
|
|
@@ -607,7 +630,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
607
630
|
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
608
631
|
const parsed = JSON.parse(raw);
|
|
609
632
|
// Validate known fields
|
|
610
|
-
const validProfiles = ['quality', 'balanced', 'budget'];
|
|
633
|
+
const validProfiles = ['quality', 'balanced', 'budget', 'inherit'];
|
|
611
634
|
if (parsed.model_profile && !validProfiles.includes(parsed.model_profile)) {
|
|
612
635
|
addIssue('warning', 'W004', `config.json: invalid model_profile "${parsed.model_profile}"`, `Valid values: ${validProfiles.join(', ')}`);
|
|
613
636
|
}
|
|
@@ -626,7 +649,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
626
649
|
addIssue('warning', 'W008', 'config.json: workflow.nyquist_validation absent (defaults to enabled but agents may skip)', 'Run /gsd-health --repair to add key', true);
|
|
627
650
|
if (!repairs.includes('addNyquistKey')) repairs.push('addNyquistKey');
|
|
628
651
|
}
|
|
629
|
-
} catch {}
|
|
652
|
+
} catch { /* intentionally empty */ }
|
|
630
653
|
}
|
|
631
654
|
|
|
632
655
|
// ─── Check 6: Phase directory naming (NN-name format) ─────────────────────
|
|
@@ -637,7 +660,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
637
660
|
addIssue('warning', 'W005', `Phase directory "${e.name}" doesn't follow NN-name format`, 'Rename to match pattern (e.g., 01-setup)');
|
|
638
661
|
}
|
|
639
662
|
}
|
|
640
|
-
} catch {}
|
|
663
|
+
} catch { /* intentionally empty */ }
|
|
641
664
|
|
|
642
665
|
// ─── Check 7: Orphaned plans (PLAN without SUMMARY) ───────────────────────
|
|
643
666
|
try {
|
|
@@ -656,7 +679,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
656
679
|
}
|
|
657
680
|
}
|
|
658
681
|
}
|
|
659
|
-
} catch {}
|
|
682
|
+
} catch { /* intentionally empty */ }
|
|
660
683
|
|
|
661
684
|
// ─── Check 7b: Nyquist VALIDATION.md consistency ────────────────────────
|
|
662
685
|
try {
|
|
@@ -674,12 +697,31 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
674
697
|
}
|
|
675
698
|
}
|
|
676
699
|
}
|
|
677
|
-
} catch {}
|
|
700
|
+
} catch { /* intentionally empty */ }
|
|
701
|
+
|
|
702
|
+
// ─── Check 7c: Agent installation (#1371) ──────────────────────────────────
|
|
703
|
+
// Verify GSD agents are installed. Missing agents cause task(subagent_type=...)
|
|
704
|
+
// to silently fall back to general-purpose, losing specialized instructions.
|
|
705
|
+
try {
|
|
706
|
+
const agentStatus = checkAgentsInstalled();
|
|
707
|
+
if (!agentStatus.agents_installed) {
|
|
708
|
+
if (agentStatus.installed_agents.length === 0) {
|
|
709
|
+
addIssue('warning', 'W010',
|
|
710
|
+
`No GSD agents found in ${agentStatus.agents_dir} — task(subagent_type="gsd-*") will fall back to general-purpose`,
|
|
711
|
+
'Run the GSD installer: npx gsd-opencode@latest');
|
|
712
|
+
} else {
|
|
713
|
+
addIssue('warning', 'W010',
|
|
714
|
+
`Missing ${agentStatus.missing_agents.length} GSD agents: ${agentStatus.missing_agents.join(', ')} — affected workflows will fall back to general-purpose`,
|
|
715
|
+
'Run the GSD installer: npx gsd-opencode@latest');
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
} catch { /* intentionally empty — agent check is non-blocking */ }
|
|
678
719
|
|
|
679
720
|
// ─── Check 8: Run existing consistency checks ─────────────────────────────
|
|
680
721
|
// Inline subset of cmdValidateConsistency
|
|
681
722
|
if (fs.existsSync(roadmapPath)) {
|
|
682
|
-
const
|
|
723
|
+
const roadmapContentRaw = fs.readFileSync(roadmapPath, 'utf-8');
|
|
724
|
+
const roadmapContent = extractCurrentMilestone(roadmapContentRaw, cwd);
|
|
683
725
|
const roadmapPhases = new Set();
|
|
684
726
|
const phasePattern = /#{2,4}\s*Phase\s+(\d+[A-Z]?(?:\.\d+)*)\s*:/gi;
|
|
685
727
|
let m;
|
|
@@ -696,7 +738,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
696
738
|
if (dm) diskPhases.add(dm[1]);
|
|
697
739
|
}
|
|
698
740
|
}
|
|
699
|
-
} catch {}
|
|
741
|
+
} catch { /* intentionally empty */ }
|
|
700
742
|
|
|
701
743
|
// Phases in ROADMAP but not on disk
|
|
702
744
|
for (const p of roadmapPhases) {
|
|
@@ -715,6 +757,71 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
715
757
|
}
|
|
716
758
|
}
|
|
717
759
|
|
|
760
|
+
// ─── Check 9: STATE.md / ROADMAP.md cross-validation ─────────────────────
|
|
761
|
+
if (fs.existsSync(statePath) && fs.existsSync(roadmapPath)) {
|
|
762
|
+
try {
|
|
763
|
+
const stateContent = fs.readFileSync(statePath, 'utf-8');
|
|
764
|
+
const roadmapContentFull = fs.readFileSync(roadmapPath, 'utf-8');
|
|
765
|
+
|
|
766
|
+
// Extract current phase from STATE.md
|
|
767
|
+
const currentPhaseMatch = stateContent.match(/\*\*Current Phase:\*\*\s*(\S+)/i) ||
|
|
768
|
+
stateContent.match(/Current Phase:\s*(\S+)/i);
|
|
769
|
+
if (currentPhaseMatch) {
|
|
770
|
+
const statePhase = currentPhaseMatch[1].replace(/^0+/, '');
|
|
771
|
+
// Check if ROADMAP shows this phase as already complete
|
|
772
|
+
const phaseCheckboxRe = new RegExp(`-\\s*\\[x\\].*Phase\\s+0*${escapeRegex(statePhase)}[:\\s]`, 'i');
|
|
773
|
+
if (phaseCheckboxRe.test(roadmapContentFull)) {
|
|
774
|
+
// STATE says "current" but ROADMAP says "complete" — divergence
|
|
775
|
+
const stateStatus = stateContent.match(/\*\*Status:\*\*\s*(.+)/i);
|
|
776
|
+
const statusVal = stateStatus ? stateStatus[1].trim().toLowerCase() : '';
|
|
777
|
+
if (statusVal !== 'complete' && statusVal !== 'done') {
|
|
778
|
+
addIssue('warning', 'W011',
|
|
779
|
+
`STATE.md says current phase is ${statePhase} (status: ${statusVal || 'unknown'}) but ROADMAP.md shows it as [x] complete — state files may be out of sync`,
|
|
780
|
+
'Run /gsd-progress to re-derive current position, or manually update STATE.md');
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
} catch { /* intentionally empty — cross-validation is advisory */ }
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// ─── Check 10: Config field validation ────────────────────────────────────
|
|
788
|
+
if (fs.existsSync(configPath)) {
|
|
789
|
+
try {
|
|
790
|
+
const configRaw = fs.readFileSync(configPath, 'utf-8');
|
|
791
|
+
const configParsed = JSON.parse(configRaw);
|
|
792
|
+
|
|
793
|
+
// Validate branching_strategy
|
|
794
|
+
const validStrategies = ['none', 'phase', 'milestone'];
|
|
795
|
+
if (configParsed.branching_strategy && !validStrategies.includes(configParsed.branching_strategy)) {
|
|
796
|
+
addIssue('warning', 'W012',
|
|
797
|
+
`config.json: invalid branching_strategy "${configParsed.branching_strategy}"`,
|
|
798
|
+
`Valid values: ${validStrategies.join(', ')}`);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Validate context_window is a positive integer
|
|
802
|
+
if (configParsed.context_window !== undefined) {
|
|
803
|
+
const cw = configParsed.context_window;
|
|
804
|
+
if (typeof cw !== 'number' || cw <= 0 || !Number.isInteger(cw)) {
|
|
805
|
+
addIssue('warning', 'W013',
|
|
806
|
+
`config.json: context_window should be a positive integer, got "${cw}"`,
|
|
807
|
+
'Set to 200000 (default) or 1000000 (for 1M models)');
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// Validate branch templates have required placeholders
|
|
812
|
+
if (configParsed.phase_branch_template && !configParsed.phase_branch_template.includes('{phase}')) {
|
|
813
|
+
addIssue('warning', 'W014',
|
|
814
|
+
'config.json: phase_branch_template missing {phase} placeholder',
|
|
815
|
+
'Template must include {phase} for phase number substitution');
|
|
816
|
+
}
|
|
817
|
+
if (configParsed.milestone_branch_template && !configParsed.milestone_branch_template.includes('{milestone}')) {
|
|
818
|
+
addIssue('warning', 'W015',
|
|
819
|
+
'config.json: milestone_branch_template missing {milestone} placeholder',
|
|
820
|
+
'Template must include {milestone} for version substitution');
|
|
821
|
+
}
|
|
822
|
+
} catch { /* parse error already caught in Check 5 */ }
|
|
823
|
+
}
|
|
824
|
+
|
|
718
825
|
// ─── Perform repairs if requested ─────────────────────────────────────────
|
|
719
826
|
const repairActions = [];
|
|
720
827
|
if (options.repair && repairs.length > 0) {
|
|
@@ -724,14 +831,21 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
724
831
|
case 'createConfig':
|
|
725
832
|
case 'resetConfig': {
|
|
726
833
|
const defaults = {
|
|
727
|
-
model_profile:
|
|
728
|
-
commit_docs:
|
|
729
|
-
search_gitignored:
|
|
730
|
-
branching_strategy:
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
834
|
+
model_profile: CONFIG_DEFAULTS.model_profile,
|
|
835
|
+
commit_docs: CONFIG_DEFAULTS.commit_docs,
|
|
836
|
+
search_gitignored: CONFIG_DEFAULTS.search_gitignored,
|
|
837
|
+
branching_strategy: CONFIG_DEFAULTS.branching_strategy,
|
|
838
|
+
phase_branch_template: CONFIG_DEFAULTS.phase_branch_template,
|
|
839
|
+
milestone_branch_template: CONFIG_DEFAULTS.milestone_branch_template,
|
|
840
|
+
quick_branch_template: CONFIG_DEFAULTS.quick_branch_template,
|
|
841
|
+
workflow: {
|
|
842
|
+
research: CONFIG_DEFAULTS.research,
|
|
843
|
+
plan_check: CONFIG_DEFAULTS.plan_checker,
|
|
844
|
+
verifier: CONFIG_DEFAULTS.verifier,
|
|
845
|
+
nyquist_validation: CONFIG_DEFAULTS.nyquist_validation,
|
|
846
|
+
},
|
|
847
|
+
parallelization: CONFIG_DEFAULTS.parallelization,
|
|
848
|
+
brave_search: CONFIG_DEFAULTS.brave_search,
|
|
735
849
|
};
|
|
736
850
|
fs.writeFileSync(configPath, JSON.stringify(defaults, null, 2), 'utf-8');
|
|
737
851
|
repairActions.push({ action: repair, success: true, path: 'config.json' });
|
|
@@ -807,6 +921,102 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
807
921
|
}, raw);
|
|
808
922
|
}
|
|
809
923
|
|
|
924
|
+
/**
|
|
925
|
+
* Validate agent installation status (#1371).
|
|
926
|
+
* Returns detailed information about which agents are installed and which are missing.
|
|
927
|
+
*/
|
|
928
|
+
function cmdValidateAgents(cwd, raw) {
|
|
929
|
+
const { MODEL_PROFILES } = require('./model-profiles.cjs');
|
|
930
|
+
const agentStatus = checkAgentsInstalled();
|
|
931
|
+
const expected = Object.keys(MODEL_PROFILES);
|
|
932
|
+
|
|
933
|
+
output({
|
|
934
|
+
agents_dir: agentStatus.agents_dir,
|
|
935
|
+
agents_found: agentStatus.agents_installed,
|
|
936
|
+
installed: agentStatus.installed_agents,
|
|
937
|
+
missing: agentStatus.missing_agents,
|
|
938
|
+
expected,
|
|
939
|
+
}, raw);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
// ─── Schema Drift Detection ──────────────────────────────────────────────────
|
|
943
|
+
|
|
944
|
+
function cmdVerifySchemaDrift(cwd, phaseArg, skipFlag, raw) {
|
|
945
|
+
const { detectSchemaFiles, checkSchemaDrift } = require('./schema-detect.cjs');
|
|
946
|
+
|
|
947
|
+
if (!phaseArg) {
|
|
948
|
+
error('Usage: verify schema-drift <phase> [--skip]');
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
// Find phase directory
|
|
953
|
+
const pDir = planningDir(cwd);
|
|
954
|
+
const phasesDir = path.join(pDir, 'phases');
|
|
955
|
+
if (!fs.existsSync(phasesDir)) {
|
|
956
|
+
output({ drift_detected: false, blocking: false, message: 'No phases directory' }, raw);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// Find matching phase directory
|
|
961
|
+
let phaseDir = null;
|
|
962
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
963
|
+
for (const entry of entries) {
|
|
964
|
+
if (entry.isDirectory() && entry.name.includes(phaseArg)) {
|
|
965
|
+
phaseDir = path.join(phasesDir, entry.name);
|
|
966
|
+
break;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// Also try exact match
|
|
971
|
+
if (!phaseDir) {
|
|
972
|
+
const exact = path.join(phasesDir, phaseArg);
|
|
973
|
+
if (fs.existsSync(exact)) phaseDir = exact;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
if (!phaseDir) {
|
|
977
|
+
output({ drift_detected: false, blocking: false, message: `Phase directory not found: ${phaseArg}` }, raw);
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// Collect files_modified from all PLAN.md files in the phase
|
|
982
|
+
const allFiles = [];
|
|
983
|
+
const planFiles = fs.readdirSync(phaseDir).filter(f => f.endsWith('-PLAN.md'));
|
|
984
|
+
for (const pf of planFiles) {
|
|
985
|
+
const content = fs.readFileSync(path.join(phaseDir, pf), 'utf-8');
|
|
986
|
+
// Extract files_modified from frontmatter
|
|
987
|
+
const fmMatch = content.match(/files_modified:\s*\[([^\]]*)\]/);
|
|
988
|
+
if (fmMatch) {
|
|
989
|
+
const files = fmMatch[1].split(',').map(f => f.trim()).filter(Boolean);
|
|
990
|
+
allFiles.push(...files);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// Collect execution log from SUMMARY.md files
|
|
995
|
+
let executionLog = '';
|
|
996
|
+
const summaryFiles = fs.readdirSync(phaseDir).filter(f => f.endsWith('-SUMMARY.md'));
|
|
997
|
+
for (const sf of summaryFiles) {
|
|
998
|
+
executionLog += fs.readFileSync(path.join(phaseDir, sf), 'utf-8') + '\n';
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// Also check git commit messages for push evidence
|
|
1002
|
+
const gitLog = execGit(cwd, ['log', '--oneline', '--all', '-50']);
|
|
1003
|
+
if (gitLog.exitCode === 0) {
|
|
1004
|
+
executionLog += '\n' + gitLog.stdout;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
const result = checkSchemaDrift(allFiles, executionLog, { skipCheck: !!skipFlag });
|
|
1008
|
+
|
|
1009
|
+
output({
|
|
1010
|
+
drift_detected: result.driftDetected,
|
|
1011
|
+
blocking: result.blocking,
|
|
1012
|
+
schema_files: result.schemaFiles,
|
|
1013
|
+
orms: result.orms,
|
|
1014
|
+
unpushed_orms: result.unpushedOrms,
|
|
1015
|
+
message: result.message,
|
|
1016
|
+
skipped: result.skipped || false,
|
|
1017
|
+
}, raw);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
810
1020
|
module.exports = {
|
|
811
1021
|
cmdVerifySummary,
|
|
812
1022
|
cmdVerifyPlanStructure,
|
|
@@ -817,4 +1027,6 @@ module.exports = {
|
|
|
817
1027
|
cmdVerifyKeyLinks,
|
|
818
1028
|
cmdValidateConsistency,
|
|
819
1029
|
cmdValidateHealth,
|
|
1030
|
+
cmdValidateAgents,
|
|
1031
|
+
cmdVerifySchemaDrift,
|
|
820
1032
|
};
|