get-shit-done-cc 1.22.2 → 1.22.3
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 +1 -1
- package/agents/gsd-nyquist-auditor.md +176 -0
- package/agents/gsd-phase-researcher.md +3 -3
- package/agents/gsd-plan-checker.md +14 -1
- package/agents/gsd-planner.md +7 -7
- package/agents/gsd-roadmapper.md +12 -12
- package/bin/install.js +67 -4
- package/commands/gsd/validate-phase.md +35 -0
- package/get-shit-done/bin/lib/config.cjs +8 -1
- package/get-shit-done/bin/lib/core.cjs +10 -1
- package/get-shit-done/bin/lib/verify.cjs +47 -0
- package/get-shit-done/references/model-profiles.md +1 -0
- package/get-shit-done/templates/config.json +2 -2
- package/get-shit-done/templates/roadmap.md +1 -1
- package/get-shit-done/workflows/audit-milestone.md +34 -0
- package/get-shit-done/workflows/health.md +3 -0
- package/get-shit-done/workflows/new-project.md +18 -16
- package/get-shit-done/workflows/plan-phase.md +25 -14
- package/get-shit-done/workflows/settings.md +2 -2
- package/get-shit-done/workflows/validate-phase.md +166 -0
- package/get-shit-done/workflows/verify-work.md +13 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -532,7 +532,7 @@ GSD stores project settings in `.planning/config.json`. Configure during `/gsd:n
|
|
|
532
532
|
| Setting | Options | Default | What it controls |
|
|
533
533
|
|---------|---------|---------|------------------|
|
|
534
534
|
| `mode` | `yolo`, `interactive` | `interactive` | Auto-approve vs confirm at each step |
|
|
535
|
-
| `
|
|
535
|
+
| `granularity` | `coarse`, `standard`, `fine` | `standard` | Phase granularity — how finely scope is sliced (phases × plans) |
|
|
536
536
|
|
|
537
537
|
### Model Profiles
|
|
538
538
|
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsd-nyquist-auditor
|
|
3
|
+
description: Fills Nyquist validation gaps by generating tests and verifying coverage for phase requirements
|
|
4
|
+
tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Write
|
|
7
|
+
- Edit
|
|
8
|
+
- Bash
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
color: "#8B5CF6"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<role>
|
|
15
|
+
GSD Nyquist auditor. Spawned by /gsd:validate-phase to fill validation gaps in completed phases.
|
|
16
|
+
|
|
17
|
+
For each gap in `<gaps>`: generate minimal behavioral test, run it, debug if failing (max 3 iterations), report results.
|
|
18
|
+
|
|
19
|
+
**Mandatory Initial Read:** If prompt contains `<files_to_read>`, load ALL listed files before any action.
|
|
20
|
+
|
|
21
|
+
**Implementation files are READ-ONLY.** Only create/modify: test files, fixtures, VALIDATION.md. Implementation bugs → ESCALATE. Never fix implementation.
|
|
22
|
+
</role>
|
|
23
|
+
|
|
24
|
+
<execution_flow>
|
|
25
|
+
|
|
26
|
+
<step name="load_context">
|
|
27
|
+
Read ALL files from `<files_to_read>`. Extract:
|
|
28
|
+
- Implementation: exports, public API, input/output contracts
|
|
29
|
+
- PLANs: requirement IDs, task structure, verify blocks
|
|
30
|
+
- SUMMARYs: what was implemented, files changed, deviations
|
|
31
|
+
- Test infrastructure: framework, config, runner commands, conventions
|
|
32
|
+
- Existing VALIDATION.md: current map, compliance status
|
|
33
|
+
</step>
|
|
34
|
+
|
|
35
|
+
<step name="analyze_gaps">
|
|
36
|
+
For each gap in `<gaps>`:
|
|
37
|
+
|
|
38
|
+
1. Read related implementation files
|
|
39
|
+
2. Identify observable behavior the requirement demands
|
|
40
|
+
3. Classify test type:
|
|
41
|
+
|
|
42
|
+
| Behavior | Test Type |
|
|
43
|
+
|----------|-----------|
|
|
44
|
+
| Pure function I/O | Unit |
|
|
45
|
+
| API endpoint | Integration |
|
|
46
|
+
| CLI command | Smoke |
|
|
47
|
+
| DB/filesystem operation | Integration |
|
|
48
|
+
|
|
49
|
+
4. Map to test file path per project conventions
|
|
50
|
+
|
|
51
|
+
Action by gap type:
|
|
52
|
+
- `no_test_file` → Create test file
|
|
53
|
+
- `test_fails` → Diagnose and fix the test (not impl)
|
|
54
|
+
- `no_automated_command` → Determine command, update map
|
|
55
|
+
</step>
|
|
56
|
+
|
|
57
|
+
<step name="generate_tests">
|
|
58
|
+
Convention discovery: existing tests → framework defaults → fallback.
|
|
59
|
+
|
|
60
|
+
| Framework | File Pattern | Runner | Assert Style |
|
|
61
|
+
|-----------|-------------|--------|--------------|
|
|
62
|
+
| pytest | `test_{name}.py` | `pytest {file} -v` | `assert result == expected` |
|
|
63
|
+
| jest | `{name}.test.ts` | `npx jest {file}` | `expect(result).toBe(expected)` |
|
|
64
|
+
| vitest | `{name}.test.ts` | `npx vitest run {file}` | `expect(result).toBe(expected)` |
|
|
65
|
+
| go test | `{name}_test.go` | `go test -v -run {Name}` | `if got != want { t.Errorf(...) }` |
|
|
66
|
+
|
|
67
|
+
Per gap: Write test file. One focused test per requirement behavior. Arrange/Act/Assert. Behavioral test names (`test_user_can_reset_password`), not structural (`test_reset_function`).
|
|
68
|
+
</step>
|
|
69
|
+
|
|
70
|
+
<step name="run_and_verify">
|
|
71
|
+
Execute each test. If passes: record success, next gap. If fails: enter debug loop.
|
|
72
|
+
|
|
73
|
+
Run every test. Never mark untested tests as passing.
|
|
74
|
+
</step>
|
|
75
|
+
|
|
76
|
+
<step name="debug_loop">
|
|
77
|
+
Max 3 iterations per failing test.
|
|
78
|
+
|
|
79
|
+
| Failure Type | Action |
|
|
80
|
+
|--------------|--------|
|
|
81
|
+
| Import/syntax/fixture error | Fix test, re-run |
|
|
82
|
+
| Assertion: actual matches impl but violates requirement | IMPLEMENTATION BUG → ESCALATE |
|
|
83
|
+
| Assertion: test expectation wrong | Fix assertion, re-run |
|
|
84
|
+
| Environment/runtime error | ESCALATE |
|
|
85
|
+
|
|
86
|
+
Track: `{ gap_id, iteration, error_type, action, result }`
|
|
87
|
+
|
|
88
|
+
After 3 failed iterations: ESCALATE with requirement, expected vs actual behavior, impl file reference.
|
|
89
|
+
</step>
|
|
90
|
+
|
|
91
|
+
<step name="report">
|
|
92
|
+
Resolved gaps: `{ task_id, requirement, test_type, automated_command, file_path, status: "green" }`
|
|
93
|
+
Escalated gaps: `{ task_id, requirement, reason, debug_iterations, last_error }`
|
|
94
|
+
|
|
95
|
+
Return one of three formats below.
|
|
96
|
+
</step>
|
|
97
|
+
|
|
98
|
+
</execution_flow>
|
|
99
|
+
|
|
100
|
+
<structured_returns>
|
|
101
|
+
|
|
102
|
+
## GAPS FILLED
|
|
103
|
+
|
|
104
|
+
```markdown
|
|
105
|
+
## GAPS FILLED
|
|
106
|
+
|
|
107
|
+
**Phase:** {N} — {name}
|
|
108
|
+
**Resolved:** {count}/{count}
|
|
109
|
+
|
|
110
|
+
### Tests Created
|
|
111
|
+
| # | File | Type | Command |
|
|
112
|
+
|---|------|------|---------|
|
|
113
|
+
| 1 | {path} | {unit/integration/smoke} | `{cmd}` |
|
|
114
|
+
|
|
115
|
+
### Verification Map Updates
|
|
116
|
+
| Task ID | Requirement | Command | Status |
|
|
117
|
+
|---------|-------------|---------|--------|
|
|
118
|
+
| {id} | {req} | `{cmd}` | green |
|
|
119
|
+
|
|
120
|
+
### Files for Commit
|
|
121
|
+
{test file paths}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## PARTIAL
|
|
125
|
+
|
|
126
|
+
```markdown
|
|
127
|
+
## PARTIAL
|
|
128
|
+
|
|
129
|
+
**Phase:** {N} — {name}
|
|
130
|
+
**Resolved:** {M}/{total} | **Escalated:** {K}/{total}
|
|
131
|
+
|
|
132
|
+
### Resolved
|
|
133
|
+
| Task ID | Requirement | File | Command | Status |
|
|
134
|
+
|---------|-------------|------|---------|--------|
|
|
135
|
+
| {id} | {req} | {file} | `{cmd}` | green |
|
|
136
|
+
|
|
137
|
+
### Escalated
|
|
138
|
+
| Task ID | Requirement | Reason | Iterations |
|
|
139
|
+
|---------|-------------|--------|------------|
|
|
140
|
+
| {id} | {req} | {reason} | {N}/3 |
|
|
141
|
+
|
|
142
|
+
### Files for Commit
|
|
143
|
+
{test file paths for resolved gaps}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## ESCALATE
|
|
147
|
+
|
|
148
|
+
```markdown
|
|
149
|
+
## ESCALATE
|
|
150
|
+
|
|
151
|
+
**Phase:** {N} — {name}
|
|
152
|
+
**Resolved:** 0/{total}
|
|
153
|
+
|
|
154
|
+
### Details
|
|
155
|
+
| Task ID | Requirement | Reason | Iterations |
|
|
156
|
+
|---------|-------------|--------|------------|
|
|
157
|
+
| {id} | {req} | {reason} | {N}/3 |
|
|
158
|
+
|
|
159
|
+
### Recommendations
|
|
160
|
+
- **{req}:** {manual test instructions or implementation fix needed}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
</structured_returns>
|
|
164
|
+
|
|
165
|
+
<success_criteria>
|
|
166
|
+
- [ ] All `<files_to_read>` loaded before any action
|
|
167
|
+
- [ ] Each gap analyzed with correct test type
|
|
168
|
+
- [ ] Tests follow project conventions
|
|
169
|
+
- [ ] Tests verify behavior, not structure
|
|
170
|
+
- [ ] Every test executed — none marked passing without running
|
|
171
|
+
- [ ] Implementation files never modified
|
|
172
|
+
- [ ] Max 3 debug iterations per gap
|
|
173
|
+
- [ ] Implementation bugs escalated, not fixed
|
|
174
|
+
- [ ] Structured return provided (GAPS FILLED / PARTIAL / ESCALATE)
|
|
175
|
+
- [ ] Test files listed for commit
|
|
176
|
+
</success_criteria>
|
|
@@ -306,7 +306,7 @@ Verified patterns from official sources:
|
|
|
306
306
|
|
|
307
307
|
## Validation Architecture
|
|
308
308
|
|
|
309
|
-
> Skip this section entirely if workflow.nyquist_validation is false in .planning/config.json
|
|
309
|
+
> Skip this section entirely if workflow.nyquist_validation is explicitly set to false in .planning/config.json. If the key is absent, treat as enabled.
|
|
310
310
|
|
|
311
311
|
### Test Framework
|
|
312
312
|
| Property | Value |
|
|
@@ -372,7 +372,7 @@ INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHA
|
|
|
372
372
|
|
|
373
373
|
Extract from init JSON: `phase_dir`, `padded_phase`, `phase_number`, `commit_docs`.
|
|
374
374
|
|
|
375
|
-
Also read `.planning/config.json` —
|
|
375
|
+
Also read `.planning/config.json` — include Validation Architecture section in RESEARCH.md unless `workflow.nyquist_validation` is explicitly `false`. If the key is absent or `true`, include the section.
|
|
376
376
|
|
|
377
377
|
Then read CONTEXT.md if exists:
|
|
378
378
|
```bash
|
|
@@ -408,7 +408,7 @@ For each domain: Context7 first → Official docs → WebSearch → Cross-verify
|
|
|
408
408
|
|
|
409
409
|
## Step 4: Validation Architecture Research (if nyquist_validation enabled)
|
|
410
410
|
|
|
411
|
-
**Skip if** workflow.nyquist_validation is false.
|
|
411
|
+
**Skip if** workflow.nyquist_validation is explicitly set to false. If absent, treat as enabled.
|
|
412
412
|
|
|
413
413
|
### Detect Test Infrastructure
|
|
414
414
|
Scan for: test config files (pytest.ini, jest.config.*, vitest.config.*), test directories (test/, tests/, __tests__/), test files (*.test.*, *.spec.*), package.json test scripts.
|
|
@@ -316,7 +316,20 @@ issue:
|
|
|
316
316
|
|
|
317
317
|
## Dimension 8: Nyquist Compliance
|
|
318
318
|
|
|
319
|
-
Skip if: `workflow.nyquist_validation` is false, phase has no RESEARCH.md, or RESEARCH.md has no "Validation Architecture" section. Output: "Dimension 8: SKIPPED (nyquist_validation disabled or not applicable)"
|
|
319
|
+
Skip if: `workflow.nyquist_validation` is explicitly set to `false` in config.json (absent key = enabled), phase has no RESEARCH.md, or RESEARCH.md has no "Validation Architecture" section. Output: "Dimension 8: SKIPPED (nyquist_validation disabled or not applicable)"
|
|
320
|
+
|
|
321
|
+
### Check 8e — VALIDATION.md Existence (Gate)
|
|
322
|
+
|
|
323
|
+
Before running checks 8a-8d, verify VALIDATION.md exists:
|
|
324
|
+
|
|
325
|
+
```bash
|
|
326
|
+
ls "${PHASE_DIR}"/*-VALIDATION.md 2>/dev/null
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
**If missing:** **BLOCKING FAIL** — "VALIDATION.md not found for phase {N}. Re-run `/gsd:plan-phase {N} --research` to regenerate."
|
|
330
|
+
Skip checks 8a-8d entirely. Report Dimension 8 as FAIL with this single issue.
|
|
331
|
+
|
|
332
|
+
**If exists:** Proceed to checks 8a-8d.
|
|
320
333
|
|
|
321
334
|
### Check 8a — Automated Verify Presence
|
|
322
335
|
|
package/agents/gsd-planner.md
CHANGED
|
@@ -371,15 +371,15 @@ Plans should complete within ~50% context (not 80%). No context anxiety, quality
|
|
|
371
371
|
|
|
372
372
|
**CONSIDER splitting:** >5 files total, complex domains, uncertainty about approach, natural semantic boundaries.
|
|
373
373
|
|
|
374
|
-
##
|
|
374
|
+
## Granularity Calibration
|
|
375
375
|
|
|
376
|
-
|
|
|
377
|
-
|
|
378
|
-
|
|
|
376
|
+
| Granularity | Typical Plans/Phase | Tasks/Plan |
|
|
377
|
+
|-------------|---------------------|------------|
|
|
378
|
+
| Coarse | 1-3 | 2-3 |
|
|
379
379
|
| Standard | 3-5 | 2-3 |
|
|
380
|
-
|
|
|
380
|
+
| Fine | 5-10 | 2-3 |
|
|
381
381
|
|
|
382
|
-
Derive plans from actual work.
|
|
382
|
+
Derive plans from actual work. Granularity determines compression tolerance, not a target. Don't pad small work to hit a number. Don't compress complex work to look efficient.
|
|
383
383
|
|
|
384
384
|
## Context Per Task Estimates
|
|
385
385
|
|
|
@@ -1135,7 +1135,7 @@ Apply goal-backward methodology (see goal_backward section):
|
|
|
1135
1135
|
</step>
|
|
1136
1136
|
|
|
1137
1137
|
<step name="estimate_scope">
|
|
1138
|
-
Verify each plan fits context budget: 2-3 tasks, ~50% target. Split if necessary. Check
|
|
1138
|
+
Verify each plan fits context budget: 2-3 tasks, ~50% target. Split if necessary. Check granularity setting.
|
|
1139
1139
|
</step>
|
|
1140
1140
|
|
|
1141
1141
|
<step name="confirm_breakdown">
|
package/agents/gsd-roadmapper.md
CHANGED
|
@@ -200,17 +200,17 @@ Track coverage as you go.
|
|
|
200
200
|
- New milestone: Start at 1
|
|
201
201
|
- Continuing milestone: Check existing phases, start at last + 1
|
|
202
202
|
|
|
203
|
-
##
|
|
203
|
+
## Granularity Calibration
|
|
204
204
|
|
|
205
|
-
Read
|
|
205
|
+
Read granularity from config.json. Granularity controls compression tolerance.
|
|
206
206
|
|
|
207
|
-
|
|
|
208
|
-
|
|
209
|
-
|
|
|
207
|
+
| Granularity | Typical Phases | What It Means |
|
|
208
|
+
|-------------|----------------|---------------|
|
|
209
|
+
| Coarse | 3-5 | Combine aggressively, critical path only |
|
|
210
210
|
| Standard | 5-8 | Balanced grouping |
|
|
211
|
-
|
|
|
211
|
+
| Fine | 8-12 | Let natural boundaries stand |
|
|
212
212
|
|
|
213
|
-
**Key:** Derive phases from work, then apply
|
|
213
|
+
**Key:** Derive phases from work, then apply granularity as compression guidance. Don't pad small projects or compress complex ones.
|
|
214
214
|
|
|
215
215
|
## Good Phase Patterns
|
|
216
216
|
|
|
@@ -357,7 +357,7 @@ When presenting to user for approval:
|
|
|
357
357
|
## ROADMAP DRAFT
|
|
358
358
|
|
|
359
359
|
**Phases:** [N]
|
|
360
|
-
**
|
|
360
|
+
**Granularity:** [from config]
|
|
361
361
|
**Coverage:** [X]/[Y] requirements mapped
|
|
362
362
|
|
|
363
363
|
### Phase Structure
|
|
@@ -401,7 +401,7 @@ Orchestrator provides:
|
|
|
401
401
|
- PROJECT.md content (core value, constraints)
|
|
402
402
|
- REQUIREMENTS.md content (v1 requirements with REQ-IDs)
|
|
403
403
|
- research/SUMMARY.md content (if exists - phase suggestions)
|
|
404
|
-
- config.json (
|
|
404
|
+
- config.json (granularity setting)
|
|
405
405
|
|
|
406
406
|
Parse and confirm understanding before proceeding.
|
|
407
407
|
|
|
@@ -437,7 +437,7 @@ Apply phase identification methodology:
|
|
|
437
437
|
1. Group requirements by natural delivery boundaries
|
|
438
438
|
2. Identify dependencies between groups
|
|
439
439
|
3. Create phases that complete coherent capabilities
|
|
440
|
-
4. Check
|
|
440
|
+
4. Check granularity setting for compression guidance
|
|
441
441
|
|
|
442
442
|
## Step 5: Derive Success Criteria
|
|
443
443
|
|
|
@@ -502,7 +502,7 @@ When files are written and returning to orchestrator:
|
|
|
502
502
|
### Summary
|
|
503
503
|
|
|
504
504
|
**Phases:** {N}
|
|
505
|
-
**
|
|
505
|
+
**Granularity:** {from config}
|
|
506
506
|
**Coverage:** {X}/{X} requirements mapped ✓
|
|
507
507
|
|
|
508
508
|
| Phase | Goal | Requirements |
|
|
@@ -628,7 +628,7 @@ Roadmap is complete when:
|
|
|
628
628
|
- [ ] All v1 requirements extracted with IDs
|
|
629
629
|
- [ ] Research context loaded (if exists)
|
|
630
630
|
- [ ] Phases derived from requirements (not imposed)
|
|
631
|
-
- [ ]
|
|
631
|
+
- [ ] Granularity calibration applied
|
|
632
632
|
- [ ] Dependencies between phases identified
|
|
633
633
|
- [ ] Success criteria derived for each phase (2-5 observable behaviors)
|
|
634
634
|
- [ ] Success criteria cross-checked against requirements (gaps resolved)
|
package/bin/install.js
CHANGED
|
@@ -58,6 +58,21 @@ if (hasAll) {
|
|
|
58
58
|
if (hasCodex) selectedRuntimes.push('codex');
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Convert a pathPrefix (which uses absolute paths for global installs) to a
|
|
63
|
+
* $HOME-relative form for replacing $HOME/.claude/ references in bash code blocks.
|
|
64
|
+
* Preserves $HOME as a shell variable so paths remain portable across machines.
|
|
65
|
+
*/
|
|
66
|
+
function toHomePrefix(pathPrefix) {
|
|
67
|
+
const home = os.homedir().replace(/\\/g, '/');
|
|
68
|
+
const normalized = pathPrefix.replace(/\\/g, '/');
|
|
69
|
+
if (normalized.startsWith(home)) {
|
|
70
|
+
return '$HOME' + normalized.slice(home.length);
|
|
71
|
+
}
|
|
72
|
+
// For relative paths or paths not under $HOME, return as-is
|
|
73
|
+
return normalized;
|
|
74
|
+
}
|
|
75
|
+
|
|
61
76
|
// Helper to get directory name for a runtime (used for local/project installs)
|
|
62
77
|
function getDirName(runtime) {
|
|
63
78
|
if (runtime === 'opencode') return '.opencode';
|
|
@@ -700,8 +715,14 @@ function installCodexConfig(targetDir, agentsSrc) {
|
|
|
700
715
|
const agentEntries = fs.readdirSync(agentsSrc).filter(f => f.startsWith('gsd-') && f.endsWith('.md'));
|
|
701
716
|
const agents = [];
|
|
702
717
|
|
|
718
|
+
// Compute the Codex pathPrefix for replacing .claude paths
|
|
719
|
+
const codexPathPrefix = `${targetDir.replace(/\\/g, '/')}/`;
|
|
720
|
+
|
|
703
721
|
for (const file of agentEntries) {
|
|
704
|
-
|
|
722
|
+
let content = fs.readFileSync(path.join(agentsSrc, file), 'utf8');
|
|
723
|
+
// Replace .claude paths before generating TOML (source files use ~/.claude and $HOME/.claude)
|
|
724
|
+
content = content.replace(/~\/\.claude\//g, codexPathPrefix);
|
|
725
|
+
content = content.replace(/\$HOME\/\.claude\//g, toHomePrefix(codexPathPrefix));
|
|
705
726
|
const { frontmatter } = extractFrontmatterAndBody(content);
|
|
706
727
|
const name = extractFrontmatterField(frontmatter, 'name') || file.replace('.md', '');
|
|
707
728
|
const description = extractFrontmatterField(frontmatter, 'description') || '';
|
|
@@ -823,8 +844,9 @@ function convertClaudeToOpencodeFrontmatter(content) {
|
|
|
823
844
|
convertedContent = convertedContent.replace(/\bTodoWrite\b/g, 'todowrite');
|
|
824
845
|
// Replace /gsd:command with /gsd-command for opencode (flat command structure)
|
|
825
846
|
convertedContent = convertedContent.replace(/\/gsd:/g, '/gsd-');
|
|
826
|
-
// Replace ~/.claude with
|
|
847
|
+
// Replace ~/.claude and $HOME/.claude with OpenCode's config location
|
|
827
848
|
convertedContent = convertedContent.replace(/~\/\.claude\b/g, '~/.config/opencode');
|
|
849
|
+
convertedContent = convertedContent.replace(/\$HOME\/\.claude\b/g, '$HOME/.config/opencode');
|
|
828
850
|
// Replace general-purpose subagent type with OpenCode's equivalent "general"
|
|
829
851
|
convertedContent = convertedContent.replace(/subagent_type="general-purpose"/g, 'subagent_type="general"');
|
|
830
852
|
|
|
@@ -1006,9 +1028,11 @@ function copyFlattenedCommands(srcDir, destDir, prefix, pathPrefix, runtime) {
|
|
|
1006
1028
|
|
|
1007
1029
|
let content = fs.readFileSync(srcPath, 'utf8');
|
|
1008
1030
|
const globalClaudeRegex = /~\/\.claude\//g;
|
|
1031
|
+
const globalClaudeHomeRegex = /\$HOME\/\.claude\//g;
|
|
1009
1032
|
const localClaudeRegex = /\.\/\.claude\//g;
|
|
1010
1033
|
const opencodeDirRegex = /~\/\.opencode\//g;
|
|
1011
1034
|
content = content.replace(globalClaudeRegex, pathPrefix);
|
|
1035
|
+
content = content.replace(globalClaudeHomeRegex, toHomePrefix(pathPrefix));
|
|
1012
1036
|
content = content.replace(localClaudeRegex, `./${getDirName(runtime)}/`);
|
|
1013
1037
|
content = content.replace(opencodeDirRegex, pathPrefix);
|
|
1014
1038
|
content = processAttribution(content, getCommitAttribution(runtime));
|
|
@@ -1065,9 +1089,11 @@ function copyCommandsAsCodexSkills(srcDir, skillsDir, prefix, pathPrefix, runtim
|
|
|
1065
1089
|
|
|
1066
1090
|
let content = fs.readFileSync(srcPath, 'utf8');
|
|
1067
1091
|
const globalClaudeRegex = /~\/\.claude\//g;
|
|
1092
|
+
const globalClaudeHomeRegex = /\$HOME\/\.claude\//g;
|
|
1068
1093
|
const localClaudeRegex = /\.\/\.claude\//g;
|
|
1069
1094
|
const codexDirRegex = /~\/\.codex\//g;
|
|
1070
1095
|
content = content.replace(globalClaudeRegex, pathPrefix);
|
|
1096
|
+
content = content.replace(globalClaudeHomeRegex, toHomePrefix(pathPrefix));
|
|
1071
1097
|
content = content.replace(localClaudeRegex, `./${getDirName(runtime)}/`);
|
|
1072
1098
|
content = content.replace(codexDirRegex, pathPrefix);
|
|
1073
1099
|
content = processAttribution(content, getCommitAttribution(runtime));
|
|
@@ -1108,11 +1134,13 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand
|
|
|
1108
1134
|
if (entry.isDirectory()) {
|
|
1109
1135
|
copyWithPathReplacement(srcPath, destPath, pathPrefix, runtime, isCommand);
|
|
1110
1136
|
} else if (entry.name.endsWith('.md')) {
|
|
1111
|
-
// Replace ~/.claude/ and ./.claude/ with runtime-appropriate paths
|
|
1137
|
+
// Replace ~/.claude/ and $HOME/.claude/ and ./.claude/ with runtime-appropriate paths
|
|
1112
1138
|
let content = fs.readFileSync(srcPath, 'utf8');
|
|
1113
1139
|
const globalClaudeRegex = /~\/\.claude\//g;
|
|
1140
|
+
const globalClaudeHomeRegex = /\$HOME\/\.claude\//g;
|
|
1114
1141
|
const localClaudeRegex = /\.\/\.claude\//g;
|
|
1115
1142
|
content = content.replace(globalClaudeRegex, pathPrefix);
|
|
1143
|
+
content = content.replace(globalClaudeHomeRegex, toHomePrefix(pathPrefix));
|
|
1116
1144
|
content = content.replace(localClaudeRegex, `./${dirName}/`);
|
|
1117
1145
|
content = processAttribution(content, getCommitAttribution(runtime));
|
|
1118
1146
|
|
|
@@ -1953,9 +1981,11 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
1953
1981
|
for (const entry of agentEntries) {
|
|
1954
1982
|
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
1955
1983
|
let content = fs.readFileSync(path.join(agentsSrc, entry.name), 'utf8');
|
|
1956
|
-
//
|
|
1984
|
+
// Replace ~/.claude/ and $HOME/.claude/ as they are the source of truth in the repo
|
|
1957
1985
|
const dirRegex = /~\/\.claude\//g;
|
|
1986
|
+
const homeDirRegex = /\$HOME\/\.claude\//g;
|
|
1958
1987
|
content = content.replace(dirRegex, pathPrefix);
|
|
1988
|
+
content = content.replace(homeDirRegex, toHomePrefix(pathPrefix));
|
|
1959
1989
|
content = processAttribution(content, getCommitAttribution(runtime));
|
|
1960
1990
|
// Convert frontmatter for runtime compatibility
|
|
1961
1991
|
if (isOpencode) {
|
|
@@ -2046,6 +2076,39 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
2046
2076
|
// Report any backed-up local patches
|
|
2047
2077
|
reportLocalPatches(targetDir, runtime);
|
|
2048
2078
|
|
|
2079
|
+
// Verify no leaked .claude paths in non-Claude runtimes
|
|
2080
|
+
if (runtime !== 'claude') {
|
|
2081
|
+
const leakedPaths = [];
|
|
2082
|
+
function scanForLeakedPaths(dir) {
|
|
2083
|
+
if (!fs.existsSync(dir)) return;
|
|
2084
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
2085
|
+
for (const entry of entries) {
|
|
2086
|
+
const fullPath = path.join(dir, entry.name);
|
|
2087
|
+
if (entry.isDirectory()) {
|
|
2088
|
+
scanForLeakedPaths(fullPath);
|
|
2089
|
+
} else if ((entry.name.endsWith('.md') || entry.name.endsWith('.toml')) && entry.name !== 'CHANGELOG.md') {
|
|
2090
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
2091
|
+
const matches = content.match(/(?:~|\$HOME)\/\.claude\b/g);
|
|
2092
|
+
if (matches) {
|
|
2093
|
+
leakedPaths.push({ file: fullPath.replace(targetDir + '/', ''), count: matches.length });
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
scanForLeakedPaths(targetDir);
|
|
2099
|
+
if (leakedPaths.length > 0) {
|
|
2100
|
+
const totalLeaks = leakedPaths.reduce((sum, l) => sum + l.count, 0);
|
|
2101
|
+
console.warn(`\n ${yellow}⚠${reset} Found ${totalLeaks} unreplaced .claude path reference(s) in ${leakedPaths.length} file(s):`);
|
|
2102
|
+
for (const leak of leakedPaths.slice(0, 5)) {
|
|
2103
|
+
console.warn(` ${dim}${leak.file}${reset} (${leak.count})`);
|
|
2104
|
+
}
|
|
2105
|
+
if (leakedPaths.length > 5) {
|
|
2106
|
+
console.warn(` ${dim}... and ${leakedPaths.length - 5} more file(s)${reset}`);
|
|
2107
|
+
}
|
|
2108
|
+
console.warn(` ${dim}These paths may not resolve correctly for ${runtimeLabel}.${reset}`);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
|
|
2049
2112
|
if (isCodex) {
|
|
2050
2113
|
// Generate Codex config.toml and per-agent .toml files
|
|
2051
2114
|
const agentCount = installCodexConfig(targetDir, agentsSrc);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsd:validate-phase
|
|
3
|
+
description: Retroactively audit and fill Nyquist validation gaps for a completed phase
|
|
4
|
+
argument-hint: "[phase number]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Edit
|
|
9
|
+
- Bash
|
|
10
|
+
- Glob
|
|
11
|
+
- Grep
|
|
12
|
+
- Task
|
|
13
|
+
- AskUserQuestion
|
|
14
|
+
---
|
|
15
|
+
<objective>
|
|
16
|
+
Audit Nyquist validation coverage for a completed phase. Three states:
|
|
17
|
+
- (A) VALIDATION.md exists — audit and fill gaps
|
|
18
|
+
- (B) No VALIDATION.md, SUMMARY.md exists — reconstruct from artifacts
|
|
19
|
+
- (C) Phase not executed — exit with guidance
|
|
20
|
+
|
|
21
|
+
Output: updated VALIDATION.md + generated test files.
|
|
22
|
+
</objective>
|
|
23
|
+
|
|
24
|
+
<execution_context>
|
|
25
|
+
@~/.claude/get-shit-done/workflows/validate-phase.md
|
|
26
|
+
</execution_context>
|
|
27
|
+
|
|
28
|
+
<context>
|
|
29
|
+
Phase: $ARGUMENTS — optional, defaults to last completed phase.
|
|
30
|
+
</context>
|
|
31
|
+
|
|
32
|
+
<process>
|
|
33
|
+
Execute @~/.claude/get-shit-done/workflows/validate-phase.md.
|
|
34
|
+
Preserve all workflow gates.
|
|
35
|
+
</process>
|
|
@@ -37,6 +37,13 @@ function cmdConfigEnsureSection(cwd, raw) {
|
|
|
37
37
|
try {
|
|
38
38
|
if (fs.existsSync(globalDefaultsPath)) {
|
|
39
39
|
userDefaults = JSON.parse(fs.readFileSync(globalDefaultsPath, 'utf-8'));
|
|
40
|
+
// Migrate deprecated "depth" key to "granularity"
|
|
41
|
+
if ('depth' in userDefaults && !('granularity' in userDefaults)) {
|
|
42
|
+
const depthToGranularity = { quick: 'coarse', standard: 'standard', comprehensive: 'fine' };
|
|
43
|
+
userDefaults.granularity = depthToGranularity[userDefaults.depth] || userDefaults.depth;
|
|
44
|
+
delete userDefaults.depth;
|
|
45
|
+
try { fs.writeFileSync(globalDefaultsPath, JSON.stringify(userDefaults, null, 2), 'utf-8'); } catch {}
|
|
46
|
+
}
|
|
40
47
|
}
|
|
41
48
|
} catch (err) {
|
|
42
49
|
// Ignore malformed global defaults, fall back to hardcoded
|
|
@@ -54,7 +61,7 @@ function cmdConfigEnsureSection(cwd, raw) {
|
|
|
54
61
|
research: true,
|
|
55
62
|
plan_check: true,
|
|
56
63
|
verifier: true,
|
|
57
|
-
nyquist_validation:
|
|
64
|
+
nyquist_validation: true,
|
|
58
65
|
},
|
|
59
66
|
parallelization: true,
|
|
60
67
|
brave_search: hasBraveSearch,
|
|
@@ -27,6 +27,7 @@ const MODEL_PROFILES = {
|
|
|
27
27
|
'gsd-verifier': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
|
28
28
|
'gsd-plan-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
|
29
29
|
'gsd-integration-checker': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
|
30
|
+
'gsd-nyquist-auditor': { quality: 'sonnet', balanced: 'sonnet', budget: 'haiku' },
|
|
30
31
|
};
|
|
31
32
|
|
|
32
33
|
// ─── Output helpers ───────────────────────────────────────────────────────────
|
|
@@ -76,7 +77,7 @@ function loadConfig(cwd) {
|
|
|
76
77
|
research: true,
|
|
77
78
|
plan_checker: true,
|
|
78
79
|
verifier: true,
|
|
79
|
-
nyquist_validation:
|
|
80
|
+
nyquist_validation: true,
|
|
80
81
|
parallelization: true,
|
|
81
82
|
brave_search: false,
|
|
82
83
|
};
|
|
@@ -85,6 +86,14 @@ function loadConfig(cwd) {
|
|
|
85
86
|
const raw = fs.readFileSync(configPath, 'utf-8');
|
|
86
87
|
const parsed = JSON.parse(raw);
|
|
87
88
|
|
|
89
|
+
// Migrate deprecated "depth" key to "granularity" with value mapping
|
|
90
|
+
if ('depth' in parsed && !('granularity' in parsed)) {
|
|
91
|
+
const depthToGranularity = { quick: 'coarse', standard: 'standard', comprehensive: 'fine' };
|
|
92
|
+
parsed.granularity = depthToGranularity[parsed.depth] || parsed.depth;
|
|
93
|
+
delete parsed.depth;
|
|
94
|
+
try { fs.writeFileSync(configPath, JSON.stringify(parsed, null, 2), 'utf-8'); } catch {}
|
|
95
|
+
}
|
|
96
|
+
|
|
88
97
|
const get = (key, nested) => {
|
|
89
98
|
if (parsed[key] !== undefined) return parsed[key];
|
|
90
99
|
if (nested && parsed[nested.section] && parsed[nested.section][nested.field] !== undefined) {
|
|
@@ -617,6 +617,18 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
617
617
|
}
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
+
// ─── Check 5b: Nyquist validation key presence ──────────────────────────
|
|
621
|
+
if (fs.existsSync(configPath)) {
|
|
622
|
+
try {
|
|
623
|
+
const configRaw = fs.readFileSync(configPath, 'utf-8');
|
|
624
|
+
const configParsed = JSON.parse(configRaw);
|
|
625
|
+
if (configParsed.workflow && configParsed.workflow.nyquist_validation === undefined) {
|
|
626
|
+
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
|
+
if (!repairs.includes('addNyquistKey')) repairs.push('addNyquistKey');
|
|
628
|
+
}
|
|
629
|
+
} catch {}
|
|
630
|
+
}
|
|
631
|
+
|
|
620
632
|
// ─── Check 6: Phase directory naming (NN-name format) ─────────────────────
|
|
621
633
|
try {
|
|
622
634
|
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
@@ -646,6 +658,24 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
646
658
|
}
|
|
647
659
|
} catch {}
|
|
648
660
|
|
|
661
|
+
// ─── Check 7b: Nyquist VALIDATION.md consistency ────────────────────────
|
|
662
|
+
try {
|
|
663
|
+
const phaseEntries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
|
664
|
+
for (const e of phaseEntries) {
|
|
665
|
+
if (!e.isDirectory()) continue;
|
|
666
|
+
const phaseFiles = fs.readdirSync(path.join(phasesDir, e.name));
|
|
667
|
+
const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md'));
|
|
668
|
+
const hasValidation = phaseFiles.some(f => f.endsWith('-VALIDATION.md'));
|
|
669
|
+
if (hasResearch && !hasValidation) {
|
|
670
|
+
const researchFile = phaseFiles.find(f => f.endsWith('-RESEARCH.md'));
|
|
671
|
+
const researchContent = fs.readFileSync(path.join(phasesDir, e.name, researchFile), 'utf-8');
|
|
672
|
+
if (researchContent.includes('## Validation Architecture')) {
|
|
673
|
+
addIssue('warning', 'W009', `Phase ${e.name}: has Validation Architecture in RESEARCH.md but no VALIDATION.md`, 'Re-run /gsd:plan-phase with --research to regenerate');
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
} catch {}
|
|
678
|
+
|
|
649
679
|
// ─── Check 8: Run existing consistency checks ─────────────────────────────
|
|
650
680
|
// Inline subset of cmdValidateConsistency
|
|
651
681
|
if (fs.existsSync(roadmapPath)) {
|
|
@@ -730,6 +760,23 @@ function cmdValidateHealth(cwd, options, raw) {
|
|
|
730
760
|
repairActions.push({ action: repair, success: true, path: 'STATE.md' });
|
|
731
761
|
break;
|
|
732
762
|
}
|
|
763
|
+
case 'addNyquistKey': {
|
|
764
|
+
if (fs.existsSync(configPath)) {
|
|
765
|
+
try {
|
|
766
|
+
const configRaw = fs.readFileSync(configPath, 'utf-8');
|
|
767
|
+
const configParsed = JSON.parse(configRaw);
|
|
768
|
+
if (!configParsed.workflow) configParsed.workflow = {};
|
|
769
|
+
if (configParsed.workflow.nyquist_validation === undefined) {
|
|
770
|
+
configParsed.workflow.nyquist_validation = true;
|
|
771
|
+
fs.writeFileSync(configPath, JSON.stringify(configParsed, null, 2), 'utf-8');
|
|
772
|
+
}
|
|
773
|
+
repairActions.push({ action: repair, success: true, path: 'config.json' });
|
|
774
|
+
} catch (err) {
|
|
775
|
+
repairActions.push({ action: repair, success: false, error: err.message });
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
break;
|
|
779
|
+
}
|
|
733
780
|
}
|
|
734
781
|
} catch (err) {
|
|
735
782
|
repairActions.push({ action: repair, success: false, error: err.message });
|
|
@@ -17,6 +17,7 @@ Model profiles control which Claude model each GSD agent uses. This allows balan
|
|
|
17
17
|
| gsd-verifier | sonnet | sonnet | haiku |
|
|
18
18
|
| gsd-plan-checker | sonnet | sonnet | haiku |
|
|
19
19
|
| gsd-integration-checker | sonnet | sonnet | haiku |
|
|
20
|
+
| gsd-nyquist-auditor | sonnet | sonnet | haiku |
|
|
20
21
|
|
|
21
22
|
## Profile Philosophy
|
|
22
23
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"mode": "interactive",
|
|
3
|
-
"
|
|
3
|
+
"granularity": "standard",
|
|
4
4
|
"workflow": {
|
|
5
5
|
"research": true,
|
|
6
6
|
"plan_check": true,
|
|
7
7
|
"verifier": true,
|
|
8
8
|
"auto_advance": false,
|
|
9
|
-
"nyquist_validation":
|
|
9
|
+
"nyquist_validation": true
|
|
10
10
|
},
|
|
11
11
|
"planning": {
|
|
12
12
|
"commit_docs": true,
|
|
@@ -105,7 +105,7 @@ Phases execute in numeric order: 2 → 2.1 → 2.2 → 3 → 3.1 → 4
|
|
|
105
105
|
|
|
106
106
|
<guidelines>
|
|
107
107
|
**Initial planning (v1.0):**
|
|
108
|
-
- Phase count depends on
|
|
108
|
+
- Phase count depends on granularity setting (coarse: 3-5, standard: 5-8, fine: 8-12)
|
|
109
109
|
- Each phase delivers something coherent
|
|
110
110
|
- Phases can have 1+ plans (split if >3 tasks or multiple subsystems)
|
|
111
111
|
- Plans use naming: {phase}-{plan}-PLAN.md (e.g., 01-02-PLAN.md)
|
|
@@ -127,6 +127,30 @@ For each REQ-ID, determine status using all three sources:
|
|
|
127
127
|
|
|
128
128
|
**Orphan detection:** Requirements present in REQUIREMENTS.md traceability table but absent from ALL phase VERIFICATION.md files MUST be flagged as orphaned. Orphaned requirements are treated as `unsatisfied` — they were assigned but never verified by any phase.
|
|
129
129
|
|
|
130
|
+
## 5.5. Nyquist Compliance Discovery
|
|
131
|
+
|
|
132
|
+
Skip if `workflow.nyquist_validation` is explicitly `false` (absent = enabled).
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
NYQUIST_CONFIG=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config get workflow.nyquist_validation --raw 2>/dev/null)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
If `false`: skip entirely.
|
|
139
|
+
|
|
140
|
+
For each phase directory, check `*-VALIDATION.md`. If exists, parse frontmatter (`nyquist_compliant`, `wave_0_complete`).
|
|
141
|
+
|
|
142
|
+
Classify per phase:
|
|
143
|
+
|
|
144
|
+
| Status | Condition |
|
|
145
|
+
|--------|-----------|
|
|
146
|
+
| COMPLIANT | `nyquist_compliant: true` and all tasks green |
|
|
147
|
+
| PARTIAL | VALIDATION.md exists, `nyquist_compliant: false` or red/pending |
|
|
148
|
+
| MISSING | No VALIDATION.md |
|
|
149
|
+
|
|
150
|
+
Add to audit YAML: `nyquist: { compliant_phases, partial_phases, missing_phases, overall }`
|
|
151
|
+
|
|
152
|
+
Discovery only — never auto-calls `/gsd:validate-phase`.
|
|
153
|
+
|
|
130
154
|
## 6. Aggregate into v{version}-MILESTONE-AUDIT.md
|
|
131
155
|
|
|
132
156
|
Create `.planning/v{version}-v{version}-MILESTONE-AUDIT.md` with:
|
|
@@ -227,6 +251,14 @@ All requirements covered. Cross-phase integration verified. E2E flows complete.
|
|
|
227
251
|
{For each flow gap:}
|
|
228
252
|
- **{flow name}:** breaks at {step}
|
|
229
253
|
|
|
254
|
+
### Nyquist Coverage
|
|
255
|
+
|
|
256
|
+
| Phase | VALIDATION.md | Compliant | Action |
|
|
257
|
+
|-------|---------------|-----------|--------|
|
|
258
|
+
| {phase} | exists/missing | true/false/partial | `/gsd:validate-phase {N}` |
|
|
259
|
+
|
|
260
|
+
Phases needing validation: run `/gsd:validate-phase {N}` for each flagged phase.
|
|
261
|
+
|
|
230
262
|
───────────────────────────────────────────────────────────────
|
|
231
263
|
|
|
232
264
|
## ▶ Next Up
|
|
@@ -293,5 +325,7 @@ All requirements met. No critical blockers. Accumulated tech debt needs review.
|
|
|
293
325
|
- [ ] Integration checker spawned with milestone requirement IDs
|
|
294
326
|
- [ ] v{version}-MILESTONE-AUDIT.md created with structured requirement gap objects
|
|
295
327
|
- [ ] FAIL gate enforced — any unsatisfied requirement forces gaps_found status
|
|
328
|
+
- [ ] Nyquist compliance scanned for all milestone phases (if enabled)
|
|
329
|
+
- [ ] Missing VALIDATION.md phases flagged with validate-phase suggestion
|
|
296
330
|
- [ ] Results presented with actionable next steps
|
|
297
331
|
</success_criteria>
|
|
@@ -136,6 +136,8 @@ Report final status.
|
|
|
136
136
|
| W005 | warning | Phase directory naming mismatch | No |
|
|
137
137
|
| W006 | warning | Phase in ROADMAP but no directory | No |
|
|
138
138
|
| W007 | warning | Phase on disk but not in ROADMAP | No |
|
|
139
|
+
| W008 | warning | config.json: workflow.nyquist_validation absent (defaults to enabled but agents may skip) | Yes |
|
|
140
|
+
| W009 | warning | Phase has Validation Architecture in RESEARCH.md but no VALIDATION.md | No |
|
|
139
141
|
| I001 | info | Plan without SUMMARY (may be in progress) | No |
|
|
140
142
|
|
|
141
143
|
</error_codes>
|
|
@@ -147,6 +149,7 @@ Report final status.
|
|
|
147
149
|
| createConfig | Create config.json with defaults | None |
|
|
148
150
|
| resetConfig | Delete + recreate config.json | Loses custom settings |
|
|
149
151
|
| regenerateState | Create STATE.md from ROADMAP structure | Loses session history |
|
|
152
|
+
| addNyquistKey | Add workflow.nyquist_validation: true to config.json | None — matches existing default |
|
|
150
153
|
|
|
151
154
|
**Not repairable (too risky):**
|
|
152
155
|
- PROJECT.md, ROADMAP.md content
|
|
@@ -14,7 +14,7 @@ Check if `--auto` flag is present in $ARGUMENTS.
|
|
|
14
14
|
**If auto mode:**
|
|
15
15
|
- Skip brownfield mapping offer (assume greenfield)
|
|
16
16
|
- Skip deep questioning (extract context from provided document)
|
|
17
|
-
- Config: YOLO mode is implicit (skip that question), but ask
|
|
17
|
+
- Config: YOLO mode is implicit (skip that question), but ask granularity/git/agents FIRST (Step 2a)
|
|
18
18
|
- After config: run Steps 6-9 automatically with smart defaults:
|
|
19
19
|
- Research: Always yes
|
|
20
20
|
- Requirements: Include all table stakes + features from provided document
|
|
@@ -90,13 +90,13 @@ YOLO mode is implicit (auto = YOLO). Ask remaining config questions:
|
|
|
90
90
|
```
|
|
91
91
|
AskUserQuestion([
|
|
92
92
|
{
|
|
93
|
-
header: "
|
|
94
|
-
question: "How
|
|
93
|
+
header: "Granularity",
|
|
94
|
+
question: "How finely should scope be sliced into phases?",
|
|
95
95
|
multiSelect: false,
|
|
96
96
|
options: [
|
|
97
|
-
{ label: "
|
|
98
|
-
{ label: "Standard", description: "Balanced
|
|
99
|
-
{ label: "
|
|
97
|
+
{ label: "Coarse (Recommended)", description: "Fewer, broader phases (3-5 phases, 1-3 plans each)" },
|
|
98
|
+
{ label: "Standard", description: "Balanced phase size (5-8 phases, 3-5 plans each)" },
|
|
99
|
+
{ label: "Fine", description: "Many focused phases (8-12 phases, 5-10 plans each)" }
|
|
100
100
|
]
|
|
101
101
|
},
|
|
102
102
|
{
|
|
@@ -169,7 +169,7 @@ Create `.planning/config.json` with mode set to "yolo":
|
|
|
169
169
|
```json
|
|
170
170
|
{
|
|
171
171
|
"mode": "yolo",
|
|
172
|
-
"
|
|
172
|
+
"granularity": "[selected]",
|
|
173
173
|
"parallelization": true|false,
|
|
174
174
|
"commit_docs": true|false,
|
|
175
175
|
"model_profile": "quality|balanced|budget",
|
|
@@ -177,6 +177,7 @@ Create `.planning/config.json` with mode set to "yolo":
|
|
|
177
177
|
"research": true|false,
|
|
178
178
|
"plan_check": true|false,
|
|
179
179
|
"verifier": true|false,
|
|
180
|
+
"nyquist_validation": depth !== "quick",
|
|
180
181
|
"auto_advance": true
|
|
181
182
|
}
|
|
182
183
|
}
|
|
@@ -379,13 +380,13 @@ questions: [
|
|
|
379
380
|
]
|
|
380
381
|
},
|
|
381
382
|
{
|
|
382
|
-
header: "
|
|
383
|
-
question: "How
|
|
383
|
+
header: "Granularity",
|
|
384
|
+
question: "How finely should scope be sliced into phases?",
|
|
384
385
|
multiSelect: false,
|
|
385
386
|
options: [
|
|
386
|
-
{ label: "
|
|
387
|
-
{ label: "Standard", description: "Balanced
|
|
388
|
-
{ label: "
|
|
387
|
+
{ label: "Coarse", description: "Fewer, broader phases (3-5 phases, 1-3 plans each)" },
|
|
388
|
+
{ label: "Standard", description: "Balanced phase size (5-8 phases, 3-5 plans each)" },
|
|
389
|
+
{ label: "Fine", description: "Many focused phases (8-12 phases, 5-10 plans each)" }
|
|
389
390
|
]
|
|
390
391
|
},
|
|
391
392
|
{
|
|
@@ -468,14 +469,15 @@ Create `.planning/config.json` with all settings:
|
|
|
468
469
|
```json
|
|
469
470
|
{
|
|
470
471
|
"mode": "yolo|interactive",
|
|
471
|
-
"
|
|
472
|
+
"granularity": "coarse|standard|fine",
|
|
472
473
|
"parallelization": true|false,
|
|
473
474
|
"commit_docs": true|false,
|
|
474
475
|
"model_profile": "quality|balanced|budget",
|
|
475
476
|
"workflow": {
|
|
476
477
|
"research": true|false,
|
|
477
478
|
"plan_check": true|false,
|
|
478
|
-
"verifier": true|false
|
|
479
|
+
"verifier": true|false,
|
|
480
|
+
"nyquist_validation": depth !== "quick"
|
|
479
481
|
}
|
|
480
482
|
}
|
|
481
483
|
```
|
|
@@ -903,7 +905,7 @@ Task(prompt="
|
|
|
903
905
|
- .planning/PROJECT.md (Project context)
|
|
904
906
|
- .planning/REQUIREMENTS.md (v1 Requirements)
|
|
905
907
|
- .planning/research/SUMMARY.md (Research findings - if exists)
|
|
906
|
-
- .planning/config.json (
|
|
908
|
+
- .planning/config.json (Granularity and mode settings)
|
|
907
909
|
</files_to_read>
|
|
908
910
|
|
|
909
911
|
</planning_context>
|
|
@@ -1090,7 +1092,7 @@ Exit skill and invoke SlashCommand("/gsd:discuss-phase 1 --auto")
|
|
|
1090
1092
|
- [ ] Brownfield detection completed
|
|
1091
1093
|
- [ ] Deep questioning completed (threads followed, not rushed)
|
|
1092
1094
|
- [ ] PROJECT.md captures full context → **committed**
|
|
1093
|
-
- [ ] config.json has workflow mode,
|
|
1095
|
+
- [ ] config.json has workflow mode, granularity, parallelization → **committed**
|
|
1094
1096
|
- [ ] Research completed (if selected) — 4 parallel agents spawned → **committed**
|
|
1095
1097
|
- [ ] Requirements gathered (from research or conversation)
|
|
1096
1098
|
- [ ] User scoped each category (v1/v2/out of scope)
|
|
@@ -219,30 +219,26 @@ Task(
|
|
|
219
219
|
- **`## RESEARCH COMPLETE`:** Display confirmation, continue to step 6
|
|
220
220
|
- **`## RESEARCH BLOCKED`:** Display blocker, offer: 1) Provide context, 2) Skip research, 3) Abort
|
|
221
221
|
|
|
222
|
-
## 5.5. Create Validation Strategy
|
|
222
|
+
## 5.5. Create Validation Strategy
|
|
223
223
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
After researcher completes, check if RESEARCH.md contains a Validation Architecture section:
|
|
224
|
+
MANDATORY unless `nyquist_validation_enabled` is false.
|
|
227
225
|
|
|
228
226
|
```bash
|
|
229
227
|
grep -l "## Validation Architecture" "${PHASE_DIR}"/*-RESEARCH.md 2>/dev/null
|
|
230
228
|
```
|
|
231
229
|
|
|
232
230
|
**If found:**
|
|
233
|
-
1. Read
|
|
234
|
-
2. Write to `${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md`
|
|
235
|
-
3. Fill frontmatter:
|
|
236
|
-
4.
|
|
231
|
+
1. Read template: `~/.claude/get-shit-done/templates/VALIDATION.md`
|
|
232
|
+
2. Write to `${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md` (use Write tool)
|
|
233
|
+
3. Fill frontmatter: `{N}` → phase number, `{phase-slug}` → slug, `{date}` → current date
|
|
234
|
+
4. Verify:
|
|
237
235
|
```bash
|
|
238
|
-
|
|
236
|
+
test -f "${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md" && echo "VALIDATION_CREATED=true" || echo "VALIDATION_CREATED=false"
|
|
239
237
|
```
|
|
238
|
+
5. If `VALIDATION_CREATED=false`: STOP — do not proceed to Step 6
|
|
239
|
+
6. If `commit_docs`: `commit-docs "docs(phase-${PHASE}): add validation strategy"`
|
|
240
240
|
|
|
241
|
-
**If not found
|
|
242
|
-
```
|
|
243
|
-
⚠ Nyquist validation enabled but researcher did not produce a Validation Architecture section.
|
|
244
|
-
Continuing without validation strategy. Plans may fail Dimension 8 check.
|
|
245
|
-
```
|
|
241
|
+
**If not found:** Warn and continue — plans may fail Dimension 8.
|
|
246
242
|
|
|
247
243
|
## 6. Check Existing Plans
|
|
248
244
|
|
|
@@ -266,6 +262,21 @@ UAT_PATH=$(printf '%s\n' "$INIT" | jq -r '.uat_path // empty')
|
|
|
266
262
|
CONTEXT_PATH=$(printf '%s\n' "$INIT" | jq -r '.context_path // empty')
|
|
267
263
|
```
|
|
268
264
|
|
|
265
|
+
## 7.5. Verify Nyquist Artifacts
|
|
266
|
+
|
|
267
|
+
Skip if `nyquist_validation_enabled` is false.
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
VALIDATION_EXISTS=$(ls "${PHASE_DIR}"/*-VALIDATION.md 2>/dev/null | head -1)
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
If missing and Nyquist enabled — ask user:
|
|
274
|
+
1. Re-run: `/gsd:plan-phase {PHASE} --research`
|
|
275
|
+
2. Disable Nyquist in config
|
|
276
|
+
3. Continue anyway (plans fail Dimension 8)
|
|
277
|
+
|
|
278
|
+
Proceed to Step 8 only if user selects 2 or 3.
|
|
279
|
+
|
|
269
280
|
## 8. Spawn gsd-planner Agent
|
|
270
281
|
|
|
271
282
|
Display banner:
|
|
@@ -28,7 +28,7 @@ Parse current values (default to `true` if not present):
|
|
|
28
28
|
- `workflow.research` — spawn researcher during plan-phase
|
|
29
29
|
- `workflow.plan_check` — spawn plan checker during plan-phase
|
|
30
30
|
- `workflow.verifier` — spawn verifier during execute-phase
|
|
31
|
-
- `workflow.nyquist_validation` — validation architecture research during plan-phase
|
|
31
|
+
- `workflow.nyquist_validation` — validation architecture research during plan-phase (default: true if absent)
|
|
32
32
|
- `model_profile` — which model each agent uses (default: `balanced`)
|
|
33
33
|
- `git.branching_strategy` — branching approach (default: `"none"`)
|
|
34
34
|
</step>
|
|
@@ -157,7 +157,7 @@ Write `~/.gsd/defaults.json` with:
|
|
|
157
157
|
```json
|
|
158
158
|
{
|
|
159
159
|
"mode": <current>,
|
|
160
|
-
"
|
|
160
|
+
"granularity": <current>,
|
|
161
161
|
"model_profile": <current>,
|
|
162
162
|
"commit_docs": <current>,
|
|
163
163
|
"parallelization": <current>,
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
<purpose>
|
|
2
|
+
Audit Nyquist validation gaps for a completed phase. Generate missing tests. Update VALIDATION.md.
|
|
3
|
+
</purpose>
|
|
4
|
+
|
|
5
|
+
<required_reading>
|
|
6
|
+
@~/.claude/get-shit-done/references/ui-brand.md
|
|
7
|
+
</required_reading>
|
|
8
|
+
|
|
9
|
+
<process>
|
|
10
|
+
|
|
11
|
+
## 0. Initialize
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHASE_ARG}")
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
AUDITOR_MODEL=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" resolve-model gsd-nyquist-auditor --raw)
|
|
21
|
+
NYQUIST_CFG=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config get workflow.nyquist_validation --raw)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If `NYQUIST_CFG` is `false`: exit with "Nyquist validation is disabled. Enable via /gsd:settings."
|
|
25
|
+
|
|
26
|
+
Display banner: `GSD > VALIDATE PHASE {N}: {name}`
|
|
27
|
+
|
|
28
|
+
## 1. Detect Input State
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
VALIDATION_FILE=$(ls "${PHASE_DIR}"/*-VALIDATION.md 2>/dev/null | head -1)
|
|
32
|
+
SUMMARY_FILES=$(ls "${PHASE_DIR}"/*-SUMMARY.md 2>/dev/null)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **State A** (`VALIDATION_FILE` non-empty): Audit existing
|
|
36
|
+
- **State B** (`VALIDATION_FILE` empty, `SUMMARY_FILES` non-empty): Reconstruct from artifacts
|
|
37
|
+
- **State C** (`SUMMARY_FILES` empty): Exit — "Phase {N} not executed. Run /gsd:execute-phase {N} first."
|
|
38
|
+
|
|
39
|
+
## 2. Discovery
|
|
40
|
+
|
|
41
|
+
### 2a. Read Phase Artifacts
|
|
42
|
+
|
|
43
|
+
Read all PLAN and SUMMARY files. Extract: task lists, requirement IDs, key-files changed, verify blocks.
|
|
44
|
+
|
|
45
|
+
### 2b. Build Requirement-to-Task Map
|
|
46
|
+
|
|
47
|
+
Per task: `{ task_id, plan_id, wave, requirement_ids, has_automated_command }`
|
|
48
|
+
|
|
49
|
+
### 2c. Detect Test Infrastructure
|
|
50
|
+
|
|
51
|
+
State A: Parse from existing VALIDATION.md Test Infrastructure table.
|
|
52
|
+
State B: Filesystem scan:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
find . -name "pytest.ini" -o -name "jest.config.*" -o -name "vitest.config.*" -o -name "pyproject.toml" 2>/dev/null | head -10
|
|
56
|
+
find . \( -name "*.test.*" -o -name "*.spec.*" -o -name "test_*" \) -not -path "*/node_modules/*" 2>/dev/null | head -40
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2d. Cross-Reference
|
|
60
|
+
|
|
61
|
+
Match each requirement to existing tests by filename, imports, test descriptions. Record: requirement → test_file → status.
|
|
62
|
+
|
|
63
|
+
## 3. Gap Analysis
|
|
64
|
+
|
|
65
|
+
Classify each requirement:
|
|
66
|
+
|
|
67
|
+
| Status | Criteria |
|
|
68
|
+
|--------|----------|
|
|
69
|
+
| COVERED | Test exists, targets behavior, runs green |
|
|
70
|
+
| PARTIAL | Test exists, failing or incomplete |
|
|
71
|
+
| MISSING | No test found |
|
|
72
|
+
|
|
73
|
+
Build: `{ task_id, requirement, gap_type, suggested_test_path, suggested_command }`
|
|
74
|
+
|
|
75
|
+
No gaps → skip to Step 6, set `nyquist_compliant: true`.
|
|
76
|
+
|
|
77
|
+
## 4. Present Gap Plan
|
|
78
|
+
|
|
79
|
+
Call AskUserQuestion with gap table and options:
|
|
80
|
+
1. "Fix all gaps" → Step 5
|
|
81
|
+
2. "Skip — mark manual-only" → add to Manual-Only, Step 6
|
|
82
|
+
3. "Cancel" → exit
|
|
83
|
+
|
|
84
|
+
## 5. Spawn gsd-nyquist-auditor
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
Task(
|
|
88
|
+
prompt="Read ~/.claude/agents/gsd-nyquist-auditor.md for instructions.\n\n" +
|
|
89
|
+
"<files_to_read>{PLAN, SUMMARY, impl files, VALIDATION.md}</files_to_read>" +
|
|
90
|
+
"<gaps>{gap list}</gaps>" +
|
|
91
|
+
"<test_infrastructure>{framework, config, commands}</test_infrastructure>" +
|
|
92
|
+
"<constraints>Never modify impl files. Max 3 debug iterations. Escalate impl bugs.</constraints>",
|
|
93
|
+
subagent_type="gsd-nyquist-auditor",
|
|
94
|
+
model="{AUDITOR_MODEL}",
|
|
95
|
+
description="Fill validation gaps for Phase {N}"
|
|
96
|
+
)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Handle return:
|
|
100
|
+
- `## GAPS FILLED` → record tests + map updates, Step 6
|
|
101
|
+
- `## PARTIAL` → record resolved, move escalated to manual-only, Step 6
|
|
102
|
+
- `## ESCALATE` → move all to manual-only, Step 6
|
|
103
|
+
|
|
104
|
+
## 6. Generate/Update VALIDATION.md
|
|
105
|
+
|
|
106
|
+
**State B (create):**
|
|
107
|
+
1. Read template from `~/.claude/get-shit-done/templates/VALIDATION.md`
|
|
108
|
+
2. Fill: frontmatter, Test Infrastructure, Per-Task Map, Manual-Only, Sign-Off
|
|
109
|
+
3. Write to `${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md`
|
|
110
|
+
|
|
111
|
+
**State A (update):**
|
|
112
|
+
1. Update Per-Task Map statuses, add escalated to Manual-Only, update frontmatter
|
|
113
|
+
2. Append audit trail:
|
|
114
|
+
|
|
115
|
+
```markdown
|
|
116
|
+
## Validation Audit {date}
|
|
117
|
+
| Metric | Count |
|
|
118
|
+
|--------|-------|
|
|
119
|
+
| Gaps found | {N} |
|
|
120
|
+
| Resolved | {M} |
|
|
121
|
+
| Escalated | {K} |
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## 7. Commit
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
git add {test_files}
|
|
128
|
+
git commit -m "test(phase-${PHASE}): add Nyquist validation tests"
|
|
129
|
+
|
|
130
|
+
node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit-docs "docs(phase-${PHASE}): add/update validation strategy"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 8. Results + Routing
|
|
134
|
+
|
|
135
|
+
**Compliant:**
|
|
136
|
+
```
|
|
137
|
+
GSD > PHASE {N} IS NYQUIST-COMPLIANT
|
|
138
|
+
All requirements have automated verification.
|
|
139
|
+
▶ Next: /gsd:audit-milestone
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Partial:**
|
|
143
|
+
```
|
|
144
|
+
GSD > PHASE {N} VALIDATED (PARTIAL)
|
|
145
|
+
{M} automated, {K} manual-only.
|
|
146
|
+
▶ Retry: /gsd:validate-phase {N}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Display `/clear` reminder.
|
|
150
|
+
|
|
151
|
+
</process>
|
|
152
|
+
|
|
153
|
+
<success_criteria>
|
|
154
|
+
- [ ] Nyquist config checked (exit if disabled)
|
|
155
|
+
- [ ] Input state detected (A/B/C)
|
|
156
|
+
- [ ] State C exits cleanly
|
|
157
|
+
- [ ] PLAN/SUMMARY files read, requirement map built
|
|
158
|
+
- [ ] Test infrastructure detected
|
|
159
|
+
- [ ] Gaps classified (COVERED/PARTIAL/MISSING)
|
|
160
|
+
- [ ] User gate with gap table
|
|
161
|
+
- [ ] Auditor spawned with complete context
|
|
162
|
+
- [ ] All three return formats handled
|
|
163
|
+
- [ ] VALIDATION.md created or updated
|
|
164
|
+
- [ ] Test files committed separately
|
|
165
|
+
- [ ] Results with routing presented
|
|
166
|
+
</success_criteria>
|
|
@@ -108,6 +108,19 @@ Examples:
|
|
|
108
108
|
→ Expected: "Clicking Reply opens inline composer below comment. Submitting shows reply nested under parent with visual indentation."
|
|
109
109
|
|
|
110
110
|
Skip internal/non-observable items (refactors, type changes, etc.).
|
|
111
|
+
|
|
112
|
+
**Cold-start smoke test injection:**
|
|
113
|
+
|
|
114
|
+
After extracting tests from SUMMARYs, scan the SUMMARY files for modified/created file paths. If ANY path matches these patterns:
|
|
115
|
+
|
|
116
|
+
`server.ts`, `server.js`, `app.ts`, `app.js`, `index.ts`, `index.js`, `main.ts`, `main.js`, `database/*`, `db/*`, `seed/*`, `seeds/*`, `migrations/*`, `startup*`, `docker-compose*`, `Dockerfile*`
|
|
117
|
+
|
|
118
|
+
Then **prepend** this test to the test list:
|
|
119
|
+
|
|
120
|
+
- name: "Cold Start Smoke Test"
|
|
121
|
+
- expected: "Kill any running server/service. Clear ephemeral state (temp DBs, caches, lock files). Start the application from scratch. Server boots without errors, any seed/migration completes, and a primary query (health check, homepage load, or basic API call) returns live data."
|
|
122
|
+
|
|
123
|
+
This catches bugs that only manifest on fresh start — race conditions in startup sequences, silent seed failures, missing environment setup — which pass against warm state but break in production.
|
|
111
124
|
</step>
|
|
112
125
|
|
|
113
126
|
<step name="create_uat_file">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "get-shit-done-cc",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.3",
|
|
4
4
|
"description": "A meta-prompting, context engineering and spec-driven development system for Claude Code, OpenCode, Gemini and Codex by TÂCHES.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"get-shit-done-cc": "bin/install.js"
|