@bhargavvc/sdd-cc 1.30.1 → 1.35.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.ja-JP.md +144 -110
- package/README.ko-KR.md +143 -107
- package/README.md +183 -112
- package/README.pt-BR.md +90 -52
- package/README.zh-CN.md +141 -101
- package/agents/sdd-advisor-researcher.md +23 -0
- package/agents/sdd-ai-researcher.md +133 -0
- package/agents/sdd-code-fixer.md +516 -0
- package/agents/sdd-code-reviewer.md +355 -0
- package/agents/sdd-codebase-mapper.md +3 -3
- package/agents/sdd-debugger.md +17 -5
- package/agents/sdd-doc-verifier.md +201 -0
- package/agents/sdd-doc-writer.md +602 -0
- package/agents/sdd-domain-researcher.md +153 -0
- package/agents/sdd-eval-auditor.md +164 -0
- package/agents/sdd-eval-planner.md +154 -0
- package/agents/sdd-executor.md +87 -4
- package/agents/sdd-framework-selector.md +160 -0
- package/agents/sdd-intel-updater.md +314 -0
- package/agents/sdd-nyquist-auditor.md +1 -1
- package/agents/sdd-phase-researcher.md +71 -4
- package/agents/sdd-plan-checker.md +100 -6
- package/agents/sdd-planner.md +145 -206
- package/agents/sdd-project-researcher.md +25 -2
- package/agents/sdd-research-synthesizer.md +3 -3
- package/agents/sdd-roadmapper.md +6 -6
- package/agents/sdd-security-auditor.md +128 -0
- package/agents/sdd-ui-auditor.md +43 -3
- package/agents/sdd-ui-checker.md +5 -5
- package/agents/sdd-ui-researcher.md +27 -4
- package/agents/sdd-user-profiler.md +2 -2
- package/agents/sdd-verifier.md +142 -22
- package/bin/install.js +2145 -545
- package/commands/sdd/add-backlog.md +5 -5
- package/commands/sdd/add-tests.md +2 -2
- package/commands/sdd/ai-integration-phase.md +36 -0
- package/commands/sdd/analyze-dependencies.md +34 -0
- package/commands/sdd/audit-fix.md +33 -0
- package/commands/sdd/autonomous.md +7 -2
- package/commands/sdd/cleanup.md +5 -0
- package/commands/sdd/code-review-fix.md +52 -0
- package/commands/sdd/code-review.md +55 -0
- package/commands/sdd/complete-milestone.md +6 -6
- package/commands/sdd/debug.md +22 -9
- package/commands/sdd/discuss-phase.md +7 -2
- package/commands/sdd/do.md +1 -1
- package/commands/sdd/docs-update.md +48 -0
- package/commands/sdd/eval-review.md +32 -0
- package/commands/sdd/execute-phase.md +4 -0
- package/commands/sdd/explore.md +27 -0
- package/commands/sdd/fast.md +2 -2
- package/commands/sdd/from-sdd2.md +45 -0
- package/commands/sdd/help.md +2 -0
- package/commands/sdd/import.md +36 -0
- package/commands/sdd/intel.md +179 -0
- package/commands/sdd/join-discord.md +2 -1
- package/commands/sdd/manager.md +1 -0
- package/commands/sdd/map-codebase.md +3 -3
- package/commands/sdd/new-milestone.md +1 -1
- package/commands/sdd/new-project.md +5 -1
- package/commands/sdd/new-workspace.md +1 -1
- package/commands/sdd/next.md +2 -0
- package/commands/sdd/plan-milestone-gaps.md +2 -2
- package/commands/sdd/plan-phase.md +6 -1
- package/commands/sdd/plant-seed.md +1 -1
- package/commands/sdd/profile-user.md +1 -1
- package/commands/sdd/quick.md +5 -3
- package/commands/sdd/reapply-patches.md +230 -42
- package/commands/sdd/research-phase.md +3 -3
- package/commands/sdd/review-backlog.md +1 -0
- package/commands/sdd/review.md +6 -3
- package/commands/sdd/scan.md +26 -0
- package/commands/sdd/secure-phase.md +35 -0
- package/commands/sdd/ship.md +1 -1
- package/commands/sdd/thread.md +5 -5
- package/commands/sdd/undo.md +34 -0
- package/commands/sdd/verify-work.md +1 -1
- package/commands/sdd/workstreams.md +17 -11
- package/hooks/dist/sdd-check-update.js +33 -8
- package/hooks/dist/sdd-context-monitor.js +17 -8
- package/hooks/dist/sdd-phase-boundary.sh +27 -0
- package/hooks/dist/sdd-prompt-guard.js +1 -0
- package/hooks/dist/sdd-read-guard.js +82 -0
- package/hooks/dist/sdd-session-state.sh +33 -0
- package/hooks/dist/sdd-statusline.js +137 -15
- package/hooks/dist/sdd-validate-commit.sh +47 -0
- package/hooks/dist/sdd-workflow-guard.js +4 -4
- package/hooks/sdd-check-update.js +139 -0
- package/hooks/sdd-context-monitor.js +165 -0
- package/hooks/sdd-phase-boundary.sh +27 -0
- package/hooks/sdd-prompt-guard.js +97 -0
- package/hooks/sdd-read-guard.js +82 -0
- package/hooks/sdd-session-state.sh +33 -0
- package/hooks/sdd-statusline.js +241 -0
- package/hooks/sdd-validate-commit.sh +47 -0
- package/hooks/sdd-workflow-guard.js +94 -0
- package/package.json +3 -3
- package/scripts/build-hooks.js +18 -7
- package/scripts/prompt-injection-scan.sh +1 -0
- package/scripts/rebrand-gsd-to-sdd.sh +221 -220
- package/scripts/run-tests.cjs +5 -1
- package/scripts/sync-upstream.sh +1 -1
- package/sdd/bin/lib/commands.cjs +79 -17
- package/sdd/bin/lib/config.cjs +90 -48
- package/sdd/bin/lib/core.cjs +452 -87
- package/sdd/bin/lib/docs.cjs +267 -0
- package/sdd/bin/lib/frontmatter.cjs +381 -336
- package/sdd/bin/lib/init.cjs +110 -16
- package/sdd/bin/lib/intel.cjs +660 -0
- package/sdd/bin/lib/learnings.cjs +378 -0
- package/sdd/bin/lib/milestone.cjs +42 -11
- package/sdd/bin/lib/model-profiles.cjs +17 -15
- package/sdd/bin/lib/phase.cjs +367 -288
- package/sdd/bin/lib/profile-output.cjs +106 -10
- package/sdd/bin/lib/roadmap.cjs +146 -115
- package/sdd/bin/lib/schema-detect.cjs +238 -0
- package/sdd/bin/lib/sdd2-import.cjs +511 -0
- package/sdd/bin/lib/security.cjs +124 -3
- package/sdd/bin/lib/state.cjs +648 -264
- package/sdd/bin/lib/template.cjs +8 -4
- package/sdd/bin/lib/verify.cjs +209 -28
- package/sdd/bin/lib/workstream.cjs +7 -3
- package/sdd/bin/sdd-tools.cjs +184 -12
- package/sdd/contexts/dev.md +21 -0
- package/sdd/contexts/research.md +22 -0
- package/sdd/contexts/review.md +22 -0
- package/sdd/references/agent-contracts.md +79 -0
- package/sdd/references/ai-evals.md +156 -0
- package/sdd/references/ai-frameworks.md +186 -0
- package/sdd/references/artifact-types.md +113 -0
- package/sdd/references/common-bug-patterns.md +114 -0
- package/sdd/references/context-budget.md +49 -0
- package/sdd/references/continuation-format.md +25 -25
- package/sdd/references/domain-probes.md +125 -0
- package/sdd/references/few-shot-examples/plan-checker.md +73 -0
- package/sdd/references/few-shot-examples/verifier.md +109 -0
- package/sdd/references/gate-prompts.md +100 -0
- package/sdd/references/gates.md +70 -0
- package/sdd/references/git-integration.md +1 -1
- package/sdd/references/ios-scaffold.md +123 -0
- package/sdd/references/model-profile-resolution.md +2 -0
- package/sdd/references/model-profiles.md +24 -18
- package/sdd/references/planner-gap-closure.md +62 -0
- package/sdd/references/planner-reviews.md +39 -0
- package/sdd/references/planner-revision.md +87 -0
- package/sdd/references/planning-config.md +252 -0
- package/sdd/references/revision-loop.md +97 -0
- package/sdd/references/thinking-models-debug.md +44 -0
- package/sdd/references/thinking-models-execution.md +50 -0
- package/sdd/references/thinking-models-planning.md +62 -0
- package/sdd/references/thinking-models-research.md +50 -0
- package/sdd/references/thinking-models-verification.md +55 -0
- package/sdd/references/thinking-partner.md +96 -0
- package/sdd/references/ui-brand.md +4 -4
- package/sdd/references/universal-anti-patterns.md +63 -0
- package/sdd/references/verification-overrides.md +227 -0
- package/sdd/references/workstream-flag.md +56 -3
- package/sdd/templates/AI-SPEC.md +246 -0
- package/sdd/templates/DEBUG.md +1 -1
- package/sdd/templates/SECURITY.md +61 -0
- package/sdd/templates/UAT.md +4 -4
- package/sdd/templates/VALIDATION.md +4 -4
- package/sdd/templates/claude-md.md +32 -9
- package/sdd/templates/config.json +4 -0
- package/sdd/templates/debug-subagent-prompt.md +1 -1
- package/sdd/templates/dev-preferences.md +1 -1
- package/sdd/templates/discovery.md +2 -2
- package/sdd/templates/phase-prompt.md +1 -1
- package/sdd/templates/planner-subagent-prompt.md +3 -3
- package/sdd/templates/project.md +1 -1
- package/sdd/templates/research.md +1 -1
- package/sdd/templates/state.md +2 -2
- package/sdd/workflows/add-phase.md +8 -8
- package/sdd/workflows/add-tests.md +12 -9
- package/sdd/workflows/add-todo.md +5 -3
- package/sdd/workflows/ai-integration-phase.md +284 -0
- package/sdd/workflows/analyze-dependencies.md +96 -0
- package/sdd/workflows/audit-fix.md +157 -0
- package/sdd/workflows/audit-milestone.md +11 -11
- package/sdd/workflows/audit-uat.md +2 -2
- package/sdd/workflows/autonomous.md +195 -27
- package/sdd/workflows/check-todos.md +12 -10
- package/sdd/workflows/cleanup.md +2 -0
- package/sdd/workflows/code-review-fix.md +497 -0
- package/sdd/workflows/code-review.md +515 -0
- package/sdd/workflows/complete-milestone.md +56 -22
- package/sdd/workflows/diagnose-issues.md +10 -3
- package/sdd/workflows/discovery-phase.md +5 -3
- package/sdd/workflows/discuss-phase-assumptions.md +24 -6
- package/sdd/workflows/discuss-phase-power.md +291 -0
- package/sdd/workflows/discuss-phase.md +173 -21
- package/sdd/workflows/do.md +23 -21
- package/sdd/workflows/docs-update.md +1155 -0
- package/sdd/workflows/eval-review.md +155 -0
- package/sdd/workflows/execute-phase.md +594 -38
- package/sdd/workflows/execute-plan.md +67 -96
- package/sdd/workflows/explore.md +139 -0
- package/sdd/workflows/fast.md +5 -5
- package/sdd/workflows/forensics.md +2 -2
- package/sdd/workflows/health.md +4 -4
- package/sdd/workflows/help.md +122 -119
- package/sdd/workflows/import.md +276 -0
- package/sdd/workflows/inbox.md +387 -0
- package/sdd/workflows/insert-phase.md +7 -7
- package/sdd/workflows/list-phase-assumptions.md +4 -4
- package/sdd/workflows/list-workspaces.md +2 -2
- package/sdd/workflows/manager.md +35 -32
- package/sdd/workflows/map-codebase.md +7 -5
- package/sdd/workflows/milestone-summary.md +2 -2
- package/sdd/workflows/new-milestone.md +17 -9
- package/sdd/workflows/new-project.md +50 -25
- package/sdd/workflows/new-workspace.md +7 -5
- package/sdd/workflows/next.md +67 -11
- package/sdd/workflows/note.md +9 -7
- package/sdd/workflows/pause-work.md +75 -12
- package/sdd/workflows/plan-milestone-gaps.md +8 -8
- package/sdd/workflows/plan-phase.md +294 -42
- package/sdd/workflows/plant-seed.md +6 -3
- package/sdd/workflows/pr-branch.md +42 -14
- package/sdd/workflows/profile-user.md +9 -7
- package/sdd/workflows/progress.md +45 -45
- package/sdd/workflows/quick.md +195 -47
- package/sdd/workflows/remove-phase.md +6 -6
- package/sdd/workflows/remove-workspace.md +3 -1
- package/sdd/workflows/research-phase.md +2 -2
- package/sdd/workflows/resume-project.md +12 -12
- package/sdd/workflows/review.md +109 -9
- package/sdd/workflows/scan.md +102 -0
- package/sdd/workflows/secure-phase.md +166 -0
- package/sdd/workflows/session-report.md +2 -2
- package/sdd/workflows/settings.md +38 -12
- package/sdd/workflows/ship.md +21 -9
- package/sdd/workflows/stats.md +1 -1
- package/sdd/workflows/transition.md +23 -23
- package/sdd/workflows/ui-phase.md +15 -7
- package/sdd/workflows/ui-review.md +29 -4
- package/sdd/workflows/undo.md +314 -0
- package/sdd/workflows/update.md +171 -20
- package/sdd/workflows/validate-phase.md +6 -4
- package/sdd/workflows/verify-phase.md +210 -6
- package/sdd/workflows/verify-work.md +83 -9
- package/sdd/commands/sdd/workstreams.md +0 -63
package/sdd/bin/lib/template.cjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const { normalizePhaseName, findPhaseInternal, generateSlugInternal, normalizeMd, toPosixPath, output, error } = require('./core.cjs');
|
|
7
|
+
const { normalizePhaseName, findPhaseInternal, generateSlugInternal, normalizeMd, toPosixPath, planningDir, output, error } = require('./core.cjs');
|
|
8
8
|
const { reconstructFrontmatter } = require('./frontmatter.cjs');
|
|
9
9
|
|
|
10
10
|
function cmdTemplateSelect(cwd, planPath, raw) {
|
|
@@ -131,6 +131,10 @@ function cmdTemplateFill(cwd, templateType, options, raw) {
|
|
|
131
131
|
must_haves: { truths: [], artifacts: [], key_links: [] },
|
|
132
132
|
...fields,
|
|
133
133
|
};
|
|
134
|
+
const planBase = planningDir(cwd);
|
|
135
|
+
const projectRef = toPosixPath(path.relative(cwd, path.join(planBase, 'PROJECT.md')));
|
|
136
|
+
const roadmapRef = toPosixPath(path.relative(cwd, path.join(planBase, 'ROADMAP.md')));
|
|
137
|
+
const stateRef = toPosixPath(path.relative(cwd, path.join(planBase, 'STATE.md')));
|
|
134
138
|
body = [
|
|
135
139
|
`# Phase ${options.phase} Plan ${planNum}: [Title]`,
|
|
136
140
|
'',
|
|
@@ -140,9 +144,9 @@ function cmdTemplateFill(cwd, templateType, options, raw) {
|
|
|
140
144
|
'- **Output:** [Concrete deliverable]',
|
|
141
145
|
'',
|
|
142
146
|
'## Context',
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
147
|
+
`@${projectRef}`,
|
|
148
|
+
`@${roadmapRef}`,
|
|
149
|
+
`@${stateRef}`,
|
|
146
150
|
'',
|
|
147
151
|
'## Tasks',
|
|
148
152
|
'',
|
package/sdd/bin/lib/verify.cjs
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const os = require('os');
|
|
8
|
-
const { safeReadFile, loadConfig, normalizePhaseName, execGit, findPhaseInternal, getMilestoneInfo, stripShippedMilestones, extractCurrentMilestone, planningDir,
|
|
8
|
+
const { safeReadFile, loadConfig, normalizePhaseName, escapeRegex, execGit, findPhaseInternal, getMilestoneInfo, stripShippedMilestones, extractCurrentMilestone, planningDir, output, error, checkAgentsInstalled, CONFIG_DEFAULTS } = require('./core.cjs');
|
|
9
9
|
const { extractFrontmatter, parseMustHavesBlock } = require('./frontmatter.cjs');
|
|
10
10
|
const { writeStateMd } = require('./state.cjs');
|
|
11
11
|
|
|
@@ -534,11 +534,10 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
534
534
|
}
|
|
535
535
|
|
|
536
536
|
const planBase = planningDir(cwd);
|
|
537
|
-
const
|
|
538
|
-
const projectPath = path.join(planRoot, 'PROJECT.md');
|
|
537
|
+
const projectPath = path.join(planBase, 'PROJECT.md');
|
|
539
538
|
const roadmapPath = path.join(planBase, 'ROADMAP.md');
|
|
540
539
|
const statePath = path.join(planBase, 'STATE.md');
|
|
541
|
-
const configPath = path.join(
|
|
540
|
+
const configPath = path.join(planBase, 'config.json');
|
|
542
541
|
const phasesDir = path.join(planBase, 'phases');
|
|
543
542
|
|
|
544
543
|
const errors = [];
|
|
@@ -556,7 +555,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
556
555
|
|
|
557
556
|
// ─── Check 1: .planning/ exists ───────────────────────────────────────────
|
|
558
557
|
if (!fs.existsSync(planBase)) {
|
|
559
|
-
addIssue('error', 'E001', '.planning/ directory not found', 'Run /sdd
|
|
558
|
+
addIssue('error', 'E001', '.planning/ directory not found', 'Run /sdd-new-project to initialize');
|
|
560
559
|
output({
|
|
561
560
|
status: 'broken',
|
|
562
561
|
errors,
|
|
@@ -569,7 +568,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
569
568
|
|
|
570
569
|
// ─── Check 2: PROJECT.md exists and has required sections ─────────────────
|
|
571
570
|
if (!fs.existsSync(projectPath)) {
|
|
572
|
-
addIssue('error', 'E002', 'PROJECT.md not found', 'Run /sdd
|
|
571
|
+
addIssue('error', 'E002', 'PROJECT.md not found', 'Run /sdd-new-project to create');
|
|
573
572
|
} else {
|
|
574
573
|
const content = fs.readFileSync(projectPath, 'utf-8');
|
|
575
574
|
const requiredSections = ['## What This Is', '## Core Value', '## Requirements'];
|
|
@@ -582,12 +581,12 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
582
581
|
|
|
583
582
|
// ─── Check 3: ROADMAP.md exists ───────────────────────────────────────────
|
|
584
583
|
if (!fs.existsSync(roadmapPath)) {
|
|
585
|
-
addIssue('error', 'E003', 'ROADMAP.md not found', 'Run /sdd
|
|
584
|
+
addIssue('error', 'E003', 'ROADMAP.md not found', 'Run /sdd-new-milestone to create roadmap');
|
|
586
585
|
}
|
|
587
586
|
|
|
588
587
|
// ─── Check 4: STATE.md exists and references valid phases ─────────────────
|
|
589
588
|
if (!fs.existsSync(statePath)) {
|
|
590
|
-
addIssue('error', 'E004', 'STATE.md not found', 'Run /sdd
|
|
589
|
+
addIssue('error', 'E004', 'STATE.md not found', 'Run /sdd-health --repair to regenerate', true);
|
|
591
590
|
repairs.push('regenerateState');
|
|
592
591
|
} else {
|
|
593
592
|
const stateContent = fs.readFileSync(statePath, 'utf-8');
|
|
@@ -614,7 +613,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
614
613
|
'warning',
|
|
615
614
|
'W002',
|
|
616
615
|
`STATE.md references phase ${ref}, but only phases ${[...diskPhases].sort().join(', ')} exist`,
|
|
617
|
-
'Review STATE.md manually before changing it; /sdd
|
|
616
|
+
'Review STATE.md manually before changing it; /sdd-health --repair will not overwrite an existing STATE.md for phase mismatches'
|
|
618
617
|
);
|
|
619
618
|
}
|
|
620
619
|
}
|
|
@@ -623,7 +622,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
623
622
|
|
|
624
623
|
// ─── Check 5: config.json valid JSON + valid schema ───────────────────────
|
|
625
624
|
if (!fs.existsSync(configPath)) {
|
|
626
|
-
addIssue('warning', 'W003', 'config.json not found', 'Run /sdd
|
|
625
|
+
addIssue('warning', 'W003', 'config.json not found', 'Run /sdd-health --repair to create with defaults', true);
|
|
627
626
|
repairs.push('createConfig');
|
|
628
627
|
} else {
|
|
629
628
|
try {
|
|
@@ -635,7 +634,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
635
634
|
addIssue('warning', 'W004', `config.json: invalid model_profile "${parsed.model_profile}"`, `Valid values: ${validProfiles.join(', ')}`);
|
|
636
635
|
}
|
|
637
636
|
} catch (err) {
|
|
638
|
-
addIssue('error', 'E005', `config.json: JSON parse error - ${err.message}`, 'Run /sdd
|
|
637
|
+
addIssue('error', 'E005', `config.json: JSON parse error - ${err.message}`, 'Run /sdd-health --repair to reset to defaults', true);
|
|
639
638
|
repairs.push('resetConfig');
|
|
640
639
|
}
|
|
641
640
|
}
|
|
@@ -646,9 +645,13 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
646
645
|
const configRaw = fs.readFileSync(configPath, 'utf-8');
|
|
647
646
|
const configParsed = JSON.parse(configRaw);
|
|
648
647
|
if (configParsed.workflow && configParsed.workflow.nyquist_validation === undefined) {
|
|
649
|
-
addIssue('warning', 'W008', 'config.json: workflow.nyquist_validation absent (defaults to enabled but agents may skip)', 'Run /sdd
|
|
648
|
+
addIssue('warning', 'W008', 'config.json: workflow.nyquist_validation absent (defaults to enabled but agents may skip)', 'Run /sdd-health --repair to add key', true);
|
|
650
649
|
if (!repairs.includes('addNyquistKey')) repairs.push('addNyquistKey');
|
|
651
650
|
}
|
|
651
|
+
if (configParsed.workflow && configParsed.workflow.ai_integration_phase === undefined) {
|
|
652
|
+
addIssue('warning', 'W016', 'config.json: workflow.ai_integration_phase absent (defaults to enabled — run /sdd-ai-integration-phase before planning AI system phases)', 'Run /sdd-health --repair to add key', true);
|
|
653
|
+
if (!repairs.includes('addAiIntegrationPhaseKey')) repairs.push('addAiIntegrationPhaseKey');
|
|
654
|
+
}
|
|
652
655
|
} catch { /* intentionally empty */ }
|
|
653
656
|
}
|
|
654
657
|
|
|
@@ -693,7 +696,7 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
693
696
|
const researchFile = phaseFiles.find(f => f.endsWith('-RESEARCH.md'));
|
|
694
697
|
const researchContent = fs.readFileSync(path.join(phasesDir, e.name, researchFile), 'utf-8');
|
|
695
698
|
if (researchContent.includes('## Validation Architecture')) {
|
|
696
|
-
addIssue('warning', 'W009', `Phase ${e.name}: has Validation Architecture in RESEARCH.md but no VALIDATION.md`, 'Re-run /sdd
|
|
699
|
+
addIssue('warning', 'W009', `Phase ${e.name}: has Validation Architecture in RESEARCH.md but no VALIDATION.md`, 'Re-run /sdd-plan-phase with --research to regenerate');
|
|
697
700
|
}
|
|
698
701
|
}
|
|
699
702
|
}
|
|
@@ -740,10 +743,24 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
740
743
|
}
|
|
741
744
|
} catch { /* intentionally empty */ }
|
|
742
745
|
|
|
746
|
+
// Build a set of phases explicitly marked not-yet-started in the ROADMAP
|
|
747
|
+
// summary list (- [ ] **Phase N:**). These phases are intentionally absent
|
|
748
|
+
// from disk -- W006 must not fire for them (#2009).
|
|
749
|
+
const notStartedPhases = new Set();
|
|
750
|
+
const uncheckedPattern = /-\s*\[\s\]\s*\*{0,2}Phase\s+(\d+[A-Z]?(?:\.\d+)*)[:\s*]/gi;
|
|
751
|
+
let um;
|
|
752
|
+
while ((um = uncheckedPattern.exec(roadmapContent)) !== null) {
|
|
753
|
+
notStartedPhases.add(um[1]);
|
|
754
|
+
// Also add zero-padded variant so 1 and 01 both match
|
|
755
|
+
notStartedPhases.add(String(parseInt(um[1], 10)).padStart(2, '0'));
|
|
756
|
+
}
|
|
757
|
+
|
|
743
758
|
// Phases in ROADMAP but not on disk
|
|
744
759
|
for (const p of roadmapPhases) {
|
|
745
760
|
const padded = String(parseInt(p, 10)).padStart(2, '0');
|
|
746
761
|
if (!diskPhases.has(p) && !diskPhases.has(padded)) {
|
|
762
|
+
// Skip phases explicitly flagged as not-yet-started in the summary list
|
|
763
|
+
if (notStartedPhases.has(p) || notStartedPhases.has(padded)) continue;
|
|
747
764
|
addIssue('warning', 'W006', `Phase ${p} in ROADMAP.md but no directory on disk`, 'Create phase directory or remove from roadmap');
|
|
748
765
|
}
|
|
749
766
|
}
|
|
@@ -757,6 +774,71 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
757
774
|
}
|
|
758
775
|
}
|
|
759
776
|
|
|
777
|
+
// ─── Check 9: STATE.md / ROADMAP.md cross-validation ─────────────────────
|
|
778
|
+
if (fs.existsSync(statePath) && fs.existsSync(roadmapPath)) {
|
|
779
|
+
try {
|
|
780
|
+
const stateContent = fs.readFileSync(statePath, 'utf-8');
|
|
781
|
+
const roadmapContentFull = fs.readFileSync(roadmapPath, 'utf-8');
|
|
782
|
+
|
|
783
|
+
// Extract current phase from STATE.md
|
|
784
|
+
const currentPhaseMatch = stateContent.match(/\*\*Current Phase:\*\*\s*(\S+)/i) ||
|
|
785
|
+
stateContent.match(/Current Phase:\s*(\S+)/i);
|
|
786
|
+
if (currentPhaseMatch) {
|
|
787
|
+
const statePhase = currentPhaseMatch[1].replace(/^0+/, '');
|
|
788
|
+
// Check if ROADMAP shows this phase as already complete
|
|
789
|
+
const phaseCheckboxRe = new RegExp(`-\\s*\\[x\\].*Phase\\s+0*${escapeRegex(statePhase)}[:\\s]`, 'i');
|
|
790
|
+
if (phaseCheckboxRe.test(roadmapContentFull)) {
|
|
791
|
+
// STATE says "current" but ROADMAP says "complete" — divergence
|
|
792
|
+
const stateStatus = stateContent.match(/\*\*Status:\*\*\s*(.+)/i);
|
|
793
|
+
const statusVal = stateStatus ? stateStatus[1].trim().toLowerCase() : '';
|
|
794
|
+
if (statusVal !== 'complete' && statusVal !== 'done') {
|
|
795
|
+
addIssue('warning', 'W011',
|
|
796
|
+
`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`,
|
|
797
|
+
'Run /sdd-progress to re-derive current position, or manually update STATE.md');
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
} catch { /* intentionally empty — cross-validation is advisory */ }
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// ─── Check 10: Config field validation ────────────────────────────────────
|
|
805
|
+
if (fs.existsSync(configPath)) {
|
|
806
|
+
try {
|
|
807
|
+
const configRaw = fs.readFileSync(configPath, 'utf-8');
|
|
808
|
+
const configParsed = JSON.parse(configRaw);
|
|
809
|
+
|
|
810
|
+
// Validate branching_strategy
|
|
811
|
+
const validStrategies = ['none', 'phase', 'milestone'];
|
|
812
|
+
if (configParsed.branching_strategy && !validStrategies.includes(configParsed.branching_strategy)) {
|
|
813
|
+
addIssue('warning', 'W012',
|
|
814
|
+
`config.json: invalid branching_strategy "${configParsed.branching_strategy}"`,
|
|
815
|
+
`Valid values: ${validStrategies.join(', ')}`);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// Validate context_window is a positive integer
|
|
819
|
+
if (configParsed.context_window !== undefined) {
|
|
820
|
+
const cw = configParsed.context_window;
|
|
821
|
+
if (typeof cw !== 'number' || cw <= 0 || !Number.isInteger(cw)) {
|
|
822
|
+
addIssue('warning', 'W013',
|
|
823
|
+
`config.json: context_window should be a positive integer, got "${cw}"`,
|
|
824
|
+
'Set to 200000 (default) or 1000000 (for 1M models)');
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// Validate branch templates have required placeholders
|
|
829
|
+
if (configParsed.phase_branch_template && !configParsed.phase_branch_template.includes('{phase}')) {
|
|
830
|
+
addIssue('warning', 'W014',
|
|
831
|
+
'config.json: phase_branch_template missing {phase} placeholder',
|
|
832
|
+
'Template must include {phase} for phase number substitution');
|
|
833
|
+
}
|
|
834
|
+
if (configParsed.milestone_branch_template && !configParsed.milestone_branch_template.includes('{milestone}')) {
|
|
835
|
+
addIssue('warning', 'W015',
|
|
836
|
+
'config.json: milestone_branch_template missing {milestone} placeholder',
|
|
837
|
+
'Template must include {milestone} for version substitution');
|
|
838
|
+
}
|
|
839
|
+
} catch { /* parse error already caught in Check 5 */ }
|
|
840
|
+
}
|
|
841
|
+
|
|
760
842
|
// ─── Perform repairs if requested ─────────────────────────────────────────
|
|
761
843
|
const repairActions = [];
|
|
762
844
|
if (options.repair && repairs.length > 0) {
|
|
@@ -766,21 +848,21 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
766
848
|
case 'createConfig':
|
|
767
849
|
case 'resetConfig': {
|
|
768
850
|
const defaults = {
|
|
769
|
-
model_profile:
|
|
770
|
-
commit_docs:
|
|
771
|
-
search_gitignored:
|
|
772
|
-
branching_strategy:
|
|
773
|
-
phase_branch_template:
|
|
774
|
-
milestone_branch_template:
|
|
775
|
-
quick_branch_template:
|
|
851
|
+
model_profile: CONFIG_DEFAULTS.model_profile,
|
|
852
|
+
commit_docs: CONFIG_DEFAULTS.commit_docs,
|
|
853
|
+
search_gitignored: CONFIG_DEFAULTS.search_gitignored,
|
|
854
|
+
branching_strategy: CONFIG_DEFAULTS.branching_strategy,
|
|
855
|
+
phase_branch_template: CONFIG_DEFAULTS.phase_branch_template,
|
|
856
|
+
milestone_branch_template: CONFIG_DEFAULTS.milestone_branch_template,
|
|
857
|
+
quick_branch_template: CONFIG_DEFAULTS.quick_branch_template,
|
|
776
858
|
workflow: {
|
|
777
|
-
research:
|
|
778
|
-
plan_check:
|
|
779
|
-
verifier:
|
|
780
|
-
nyquist_validation:
|
|
859
|
+
research: CONFIG_DEFAULTS.research,
|
|
860
|
+
plan_check: CONFIG_DEFAULTS.plan_checker,
|
|
861
|
+
verifier: CONFIG_DEFAULTS.verifier,
|
|
862
|
+
nyquist_validation: CONFIG_DEFAULTS.nyquist_validation,
|
|
781
863
|
},
|
|
782
|
-
parallelization:
|
|
783
|
-
brave_search:
|
|
864
|
+
parallelization: CONFIG_DEFAULTS.parallelization,
|
|
865
|
+
brave_search: CONFIG_DEFAULTS.brave_search,
|
|
784
866
|
};
|
|
785
867
|
fs.writeFileSync(configPath, JSON.stringify(defaults, null, 2), 'utf-8');
|
|
786
868
|
repairActions.push({ action: repair, success: true, path: 'config.json' });
|
|
@@ -796,15 +878,18 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
796
878
|
}
|
|
797
879
|
// Generate minimal STATE.md from ROADMAP.md structure
|
|
798
880
|
const milestone = getMilestoneInfo(cwd);
|
|
881
|
+
const projectRef = path
|
|
882
|
+
.relative(cwd, path.join(planningDir(cwd), 'PROJECT.md'))
|
|
883
|
+
.split(path.sep).join('/');
|
|
799
884
|
let stateContent = `# Session State\n\n`;
|
|
800
885
|
stateContent += `## Project Reference\n\n`;
|
|
801
|
-
stateContent += `See:
|
|
886
|
+
stateContent += `See: ${projectRef}\n\n`;
|
|
802
887
|
stateContent += `## Position\n\n`;
|
|
803
888
|
stateContent += `**Milestone:** ${milestone.version} ${milestone.name}\n`;
|
|
804
889
|
stateContent += `**Current phase:** (determining...)\n`;
|
|
805
890
|
stateContent += `**Status:** Resuming\n\n`;
|
|
806
891
|
stateContent += `## Session Log\n\n`;
|
|
807
|
-
stateContent += `- ${new Date().toISOString().split('T')[0]}: STATE.md regenerated by /sdd
|
|
892
|
+
stateContent += `- ${new Date().toISOString().split('T')[0]}: STATE.md regenerated by /sdd-health --repair\n`;
|
|
808
893
|
writeStateMd(statePath, stateContent, cwd);
|
|
809
894
|
repairActions.push({ action: repair, success: true, path: 'STATE.md' });
|
|
810
895
|
break;
|
|
@@ -826,6 +911,23 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
826
911
|
}
|
|
827
912
|
break;
|
|
828
913
|
}
|
|
914
|
+
case 'addAiIntegrationPhaseKey': {
|
|
915
|
+
if (fs.existsSync(configPath)) {
|
|
916
|
+
try {
|
|
917
|
+
const configRaw = fs.readFileSync(configPath, 'utf-8');
|
|
918
|
+
const configParsed = JSON.parse(configRaw);
|
|
919
|
+
if (!configParsed.workflow) configParsed.workflow = {};
|
|
920
|
+
if (configParsed.workflow.ai_integration_phase === undefined) {
|
|
921
|
+
configParsed.workflow.ai_integration_phase = true;
|
|
922
|
+
fs.writeFileSync(configPath, JSON.stringify(configParsed, null, 2), 'utf-8');
|
|
923
|
+
}
|
|
924
|
+
repairActions.push({ action: repair, success: true, path: 'config.json' });
|
|
925
|
+
} catch (err) {
|
|
926
|
+
repairActions.push({ action: repair, success: false, error: err.message });
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
break;
|
|
930
|
+
}
|
|
829
931
|
}
|
|
830
932
|
} catch (err) {
|
|
831
933
|
repairActions.push({ action: repair, success: false, error: err.message });
|
|
@@ -874,6 +976,84 @@ function cmdValidateAgents(cwd, raw) {
|
|
|
874
976
|
}, raw);
|
|
875
977
|
}
|
|
876
978
|
|
|
979
|
+
// ─── Schema Drift Detection ──────────────────────────────────────────────────
|
|
980
|
+
|
|
981
|
+
function cmdVerifySchemaDrift(cwd, phaseArg, skipFlag, raw) {
|
|
982
|
+
const { detectSchemaFiles, checkSchemaDrift } = require('./schema-detect.cjs');
|
|
983
|
+
|
|
984
|
+
if (!phaseArg) {
|
|
985
|
+
error('Usage: verify schema-drift <phase> [--skip]');
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
// Find phase directory
|
|
990
|
+
const pDir = planningDir(cwd);
|
|
991
|
+
const phasesDir = path.join(pDir, 'phases');
|
|
992
|
+
if (!fs.existsSync(phasesDir)) {
|
|
993
|
+
output({ drift_detected: false, blocking: false, message: 'No phases directory' }, raw);
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// Find matching phase directory
|
|
998
|
+
let phaseDir = null;
|
|
999
|
+
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
1000
|
+
for (const entry of entries) {
|
|
1001
|
+
if (entry.isDirectory() && entry.name.includes(phaseArg)) {
|
|
1002
|
+
phaseDir = path.join(phasesDir, entry.name);
|
|
1003
|
+
break;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// Also try exact match
|
|
1008
|
+
if (!phaseDir) {
|
|
1009
|
+
const exact = path.join(phasesDir, phaseArg);
|
|
1010
|
+
if (fs.existsSync(exact)) phaseDir = exact;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
if (!phaseDir) {
|
|
1014
|
+
output({ drift_detected: false, blocking: false, message: `Phase directory not found: ${phaseArg}` }, raw);
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// Collect files_modified from all PLAN.md files in the phase
|
|
1019
|
+
const allFiles = [];
|
|
1020
|
+
const planFiles = fs.readdirSync(phaseDir).filter(f => f.endsWith('-PLAN.md'));
|
|
1021
|
+
for (const pf of planFiles) {
|
|
1022
|
+
const content = fs.readFileSync(path.join(phaseDir, pf), 'utf-8');
|
|
1023
|
+
// Extract files_modified from frontmatter
|
|
1024
|
+
const fmMatch = content.match(/files_modified:\s*\[([^\]]*)\]/);
|
|
1025
|
+
if (fmMatch) {
|
|
1026
|
+
const files = fmMatch[1].split(',').map(f => f.trim()).filter(Boolean);
|
|
1027
|
+
allFiles.push(...files);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
// Collect execution log from SUMMARY.md files
|
|
1032
|
+
let executionLog = '';
|
|
1033
|
+
const summaryFiles = fs.readdirSync(phaseDir).filter(f => f.endsWith('-SUMMARY.md'));
|
|
1034
|
+
for (const sf of summaryFiles) {
|
|
1035
|
+
executionLog += fs.readFileSync(path.join(phaseDir, sf), 'utf-8') + '\n';
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// Also check git commit messages for push evidence
|
|
1039
|
+
const gitLog = execGit(cwd, ['log', '--oneline', '--all', '-50']);
|
|
1040
|
+
if (gitLog.exitCode === 0) {
|
|
1041
|
+
executionLog += '\n' + gitLog.stdout;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
const result = checkSchemaDrift(allFiles, executionLog, { skipCheck: !!skipFlag });
|
|
1045
|
+
|
|
1046
|
+
output({
|
|
1047
|
+
drift_detected: result.driftDetected,
|
|
1048
|
+
blocking: result.blocking,
|
|
1049
|
+
schema_files: result.schemaFiles,
|
|
1050
|
+
orms: result.orms,
|
|
1051
|
+
unpushed_orms: result.unpushedOrms,
|
|
1052
|
+
message: result.message,
|
|
1053
|
+
skipped: result.skipped || false,
|
|
1054
|
+
}, raw);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
877
1057
|
module.exports = {
|
|
878
1058
|
cmdVerifySummary,
|
|
879
1059
|
cmdVerifyPlanStructure,
|
|
@@ -885,4 +1065,5 @@ module.exports = {
|
|
|
885
1065
|
cmdValidateConsistency,
|
|
886
1066
|
cmdValidateHealth,
|
|
887
1067
|
cmdValidateAgents,
|
|
1068
|
+
cmdVerifySchemaDrift,
|
|
888
1069
|
};
|
|
@@ -78,7 +78,7 @@ function cmdWorkstreamCreate(cwd, name, options, raw) {
|
|
|
78
78
|
|
|
79
79
|
const baseDir = planningRoot(cwd);
|
|
80
80
|
if (!fs.existsSync(baseDir)) {
|
|
81
|
-
error('.planning/ directory not found — run /sdd
|
|
81
|
+
error('.planning/ directory not found — run /sdd-new-project first');
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
const wsRoot = path.join(baseDir, 'workstreams');
|
|
@@ -339,9 +339,13 @@ function cmdWorkstreamComplete(cwd, name, options, raw) {
|
|
|
339
339
|
// ─── Active Workstream Commands ──────────────────────────────────────────────
|
|
340
340
|
|
|
341
341
|
function cmdWorkstreamSet(cwd, name, raw) {
|
|
342
|
-
if (!name) {
|
|
342
|
+
if (!name || name === '--clear') {
|
|
343
|
+
if (name !== '--clear') {
|
|
344
|
+
error('Workstream name required. Usage: workstream set <name> (or workstream set --clear to unset)');
|
|
345
|
+
}
|
|
346
|
+
const previous = getActiveWorkstream(cwd);
|
|
343
347
|
setActiveWorkstream(cwd, null);
|
|
344
|
-
output({ active: null, cleared: true }, raw);
|
|
348
|
+
output({ active: null, cleared: true, previous: previous || null }, raw);
|
|
345
349
|
return;
|
|
346
350
|
}
|
|
347
351
|
|