get-shit-done-cc 1.22.2 → 1.22.4
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 +2 -2
- package/agents/gsd-debugger.md +1 -0
- package/agents/gsd-executor.md +1 -0
- package/agents/gsd-nyquist-auditor.md +178 -0
- package/agents/gsd-phase-researcher.md +4 -3
- package/agents/gsd-plan-checker.md +15 -1
- package/agents/gsd-planner.md +8 -7
- package/agents/gsd-roadmapper.md +12 -12
- package/bin/install.js +67 -4
- package/commands/gsd/debug.md +1 -0
- package/commands/gsd/quick.md +6 -2
- package/commands/gsd/research-phase.md +1 -0
- 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/references/planning-config.md +4 -0
- package/get-shit-done/templates/config.json +2 -2
- package/get-shit-done/templates/roadmap.md +1 -1
- package/get-shit-done/workflows/add-phase.md +1 -0
- package/get-shit-done/workflows/add-tests.md +1 -0
- package/get-shit-done/workflows/add-todo.md +1 -0
- package/get-shit-done/workflows/audit-milestone.md +35 -0
- package/get-shit-done/workflows/check-todos.md +1 -0
- package/get-shit-done/workflows/complete-milestone.md +1 -0
- package/get-shit-done/workflows/discuss-phase.md +1 -0
- package/get-shit-done/workflows/execute-phase.md +1 -0
- package/get-shit-done/workflows/execute-plan.md +1 -0
- package/get-shit-done/workflows/health.md +3 -0
- package/get-shit-done/workflows/insert-phase.md +1 -0
- package/get-shit-done/workflows/map-codebase.md +1 -0
- package/get-shit-done/workflows/new-milestone.md +1 -0
- package/get-shit-done/workflows/new-project.md +19 -16
- package/get-shit-done/workflows/plan-phase.md +26 -14
- package/get-shit-done/workflows/progress.md +1 -0
- package/get-shit-done/workflows/quick.md +152 -4
- package/get-shit-done/workflows/remove-phase.md +1 -0
- package/get-shit-done/workflows/research-phase.md +1 -0
- package/get-shit-done/workflows/resume-project.md +1 -0
- package/get-shit-done/workflows/set-profile.md +1 -0
- package/get-shit-done/workflows/settings.md +3 -2
- package/get-shit-done/workflows/validate-phase.md +167 -0
- package/get-shit-done/workflows/verify-phase.md +1 -0
- package/get-shit-done/workflows/verify-work.md +14 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -516,7 +516,7 @@ You're never locked in. The system adapts.
|
|
|
516
516
|
| `/gsd:add-todo [desc]` | Capture idea for later |
|
|
517
517
|
| `/gsd:check-todos` | List pending todos |
|
|
518
518
|
| `/gsd:debug [desc]` | Systematic debugging with persistent state |
|
|
519
|
-
| `/gsd:quick [--full]` | Execute ad-hoc task with GSD guarantees (`--full` adds plan-checking and verification) |
|
|
519
|
+
| `/gsd:quick [--full] [--discuss]` | Execute ad-hoc task with GSD guarantees (`--full` adds plan-checking and verification, `--discuss` gathers context first) |
|
|
520
520
|
| `/gsd:health [--repair]` | Validate `.planning/` directory integrity, auto-repair with `--repair` |
|
|
521
521
|
|
|
522
522
|
<sup>¹ Contributed by reddit user OracleGreyBeard</sup>
|
|
@@ -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
|
|
package/agents/gsd-debugger.md
CHANGED
|
@@ -1038,6 +1038,7 @@ mv .planning/debug/{slug}.md .planning/debug/resolved/
|
|
|
1038
1038
|
|
|
1039
1039
|
```bash
|
|
1040
1040
|
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" state load)
|
|
1041
|
+
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
1041
1042
|
# commit_docs is in the JSON output
|
|
1042
1043
|
```
|
|
1043
1044
|
|
package/agents/gsd-executor.md
CHANGED
|
@@ -46,6 +46,7 @@ Load execution context:
|
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
48
|
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init execute-phase "${PHASE}")
|
|
49
|
+
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
49
50
|
```
|
|
50
51
|
|
|
51
52
|
Extract from init JSON: `executor_model`, `commit_docs`, `phase_dir`, `plans`, `incomplete_plans`.
|
|
@@ -0,0 +1,178 @@
|
|
|
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
|
+
skills:
|
|
13
|
+
- gsd-nyquist-auditor-workflow
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
<role>
|
|
17
|
+
GSD Nyquist auditor. Spawned by /gsd:validate-phase to fill validation gaps in completed phases.
|
|
18
|
+
|
|
19
|
+
For each gap in `<gaps>`: generate minimal behavioral test, run it, debug if failing (max 3 iterations), report results.
|
|
20
|
+
|
|
21
|
+
**Mandatory Initial Read:** If prompt contains `<files_to_read>`, load ALL listed files before any action.
|
|
22
|
+
|
|
23
|
+
**Implementation files are READ-ONLY.** Only create/modify: test files, fixtures, VALIDATION.md. Implementation bugs → ESCALATE. Never fix implementation.
|
|
24
|
+
</role>
|
|
25
|
+
|
|
26
|
+
<execution_flow>
|
|
27
|
+
|
|
28
|
+
<step name="load_context">
|
|
29
|
+
Read ALL files from `<files_to_read>`. Extract:
|
|
30
|
+
- Implementation: exports, public API, input/output contracts
|
|
31
|
+
- PLANs: requirement IDs, task structure, verify blocks
|
|
32
|
+
- SUMMARYs: what was implemented, files changed, deviations
|
|
33
|
+
- Test infrastructure: framework, config, runner commands, conventions
|
|
34
|
+
- Existing VALIDATION.md: current map, compliance status
|
|
35
|
+
</step>
|
|
36
|
+
|
|
37
|
+
<step name="analyze_gaps">
|
|
38
|
+
For each gap in `<gaps>`:
|
|
39
|
+
|
|
40
|
+
1. Read related implementation files
|
|
41
|
+
2. Identify observable behavior the requirement demands
|
|
42
|
+
3. Classify test type:
|
|
43
|
+
|
|
44
|
+
| Behavior | Test Type |
|
|
45
|
+
|----------|-----------|
|
|
46
|
+
| Pure function I/O | Unit |
|
|
47
|
+
| API endpoint | Integration |
|
|
48
|
+
| CLI command | Smoke |
|
|
49
|
+
| DB/filesystem operation | Integration |
|
|
50
|
+
|
|
51
|
+
4. Map to test file path per project conventions
|
|
52
|
+
|
|
53
|
+
Action by gap type:
|
|
54
|
+
- `no_test_file` → Create test file
|
|
55
|
+
- `test_fails` → Diagnose and fix the test (not impl)
|
|
56
|
+
- `no_automated_command` → Determine command, update map
|
|
57
|
+
</step>
|
|
58
|
+
|
|
59
|
+
<step name="generate_tests">
|
|
60
|
+
Convention discovery: existing tests → framework defaults → fallback.
|
|
61
|
+
|
|
62
|
+
| Framework | File Pattern | Runner | Assert Style |
|
|
63
|
+
|-----------|-------------|--------|--------------|
|
|
64
|
+
| pytest | `test_{name}.py` | `pytest {file} -v` | `assert result == expected` |
|
|
65
|
+
| jest | `{name}.test.ts` | `npx jest {file}` | `expect(result).toBe(expected)` |
|
|
66
|
+
| vitest | `{name}.test.ts` | `npx vitest run {file}` | `expect(result).toBe(expected)` |
|
|
67
|
+
| go test | `{name}_test.go` | `go test -v -run {Name}` | `if got != want { t.Errorf(...) }` |
|
|
68
|
+
|
|
69
|
+
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`).
|
|
70
|
+
</step>
|
|
71
|
+
|
|
72
|
+
<step name="run_and_verify">
|
|
73
|
+
Execute each test. If passes: record success, next gap. If fails: enter debug loop.
|
|
74
|
+
|
|
75
|
+
Run every test. Never mark untested tests as passing.
|
|
76
|
+
</step>
|
|
77
|
+
|
|
78
|
+
<step name="debug_loop">
|
|
79
|
+
Max 3 iterations per failing test.
|
|
80
|
+
|
|
81
|
+
| Failure Type | Action |
|
|
82
|
+
|--------------|--------|
|
|
83
|
+
| Import/syntax/fixture error | Fix test, re-run |
|
|
84
|
+
| Assertion: actual matches impl but violates requirement | IMPLEMENTATION BUG → ESCALATE |
|
|
85
|
+
| Assertion: test expectation wrong | Fix assertion, re-run |
|
|
86
|
+
| Environment/runtime error | ESCALATE |
|
|
87
|
+
|
|
88
|
+
Track: `{ gap_id, iteration, error_type, action, result }`
|
|
89
|
+
|
|
90
|
+
After 3 failed iterations: ESCALATE with requirement, expected vs actual behavior, impl file reference.
|
|
91
|
+
</step>
|
|
92
|
+
|
|
93
|
+
<step name="report">
|
|
94
|
+
Resolved gaps: `{ task_id, requirement, test_type, automated_command, file_path, status: "green" }`
|
|
95
|
+
Escalated gaps: `{ task_id, requirement, reason, debug_iterations, last_error }`
|
|
96
|
+
|
|
97
|
+
Return one of three formats below.
|
|
98
|
+
</step>
|
|
99
|
+
|
|
100
|
+
</execution_flow>
|
|
101
|
+
|
|
102
|
+
<structured_returns>
|
|
103
|
+
|
|
104
|
+
## GAPS FILLED
|
|
105
|
+
|
|
106
|
+
```markdown
|
|
107
|
+
## GAPS FILLED
|
|
108
|
+
|
|
109
|
+
**Phase:** {N} — {name}
|
|
110
|
+
**Resolved:** {count}/{count}
|
|
111
|
+
|
|
112
|
+
### Tests Created
|
|
113
|
+
| # | File | Type | Command |
|
|
114
|
+
|---|------|------|---------|
|
|
115
|
+
| 1 | {path} | {unit/integration/smoke} | `{cmd}` |
|
|
116
|
+
|
|
117
|
+
### Verification Map Updates
|
|
118
|
+
| Task ID | Requirement | Command | Status |
|
|
119
|
+
|---------|-------------|---------|--------|
|
|
120
|
+
| {id} | {req} | `{cmd}` | green |
|
|
121
|
+
|
|
122
|
+
### Files for Commit
|
|
123
|
+
{test file paths}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## PARTIAL
|
|
127
|
+
|
|
128
|
+
```markdown
|
|
129
|
+
## PARTIAL
|
|
130
|
+
|
|
131
|
+
**Phase:** {N} — {name}
|
|
132
|
+
**Resolved:** {M}/{total} | **Escalated:** {K}/{total}
|
|
133
|
+
|
|
134
|
+
### Resolved
|
|
135
|
+
| Task ID | Requirement | File | Command | Status |
|
|
136
|
+
|---------|-------------|------|---------|--------|
|
|
137
|
+
| {id} | {req} | {file} | `{cmd}` | green |
|
|
138
|
+
|
|
139
|
+
### Escalated
|
|
140
|
+
| Task ID | Requirement | Reason | Iterations |
|
|
141
|
+
|---------|-------------|--------|------------|
|
|
142
|
+
| {id} | {req} | {reason} | {N}/3 |
|
|
143
|
+
|
|
144
|
+
### Files for Commit
|
|
145
|
+
{test file paths for resolved gaps}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## ESCALATE
|
|
149
|
+
|
|
150
|
+
```markdown
|
|
151
|
+
## ESCALATE
|
|
152
|
+
|
|
153
|
+
**Phase:** {N} — {name}
|
|
154
|
+
**Resolved:** 0/{total}
|
|
155
|
+
|
|
156
|
+
### Details
|
|
157
|
+
| Task ID | Requirement | Reason | Iterations |
|
|
158
|
+
|---------|-------------|--------|------------|
|
|
159
|
+
| {id} | {req} | {reason} | {N}/3 |
|
|
160
|
+
|
|
161
|
+
### Recommendations
|
|
162
|
+
- **{req}:** {manual test instructions or implementation fix needed}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
</structured_returns>
|
|
166
|
+
|
|
167
|
+
<success_criteria>
|
|
168
|
+
- [ ] All `<files_to_read>` loaded before any action
|
|
169
|
+
- [ ] Each gap analyzed with correct test type
|
|
170
|
+
- [ ] Tests follow project conventions
|
|
171
|
+
- [ ] Tests verify behavior, not structure
|
|
172
|
+
- [ ] Every test executed — none marked passing without running
|
|
173
|
+
- [ ] Implementation files never modified
|
|
174
|
+
- [ ] Max 3 debug iterations per gap
|
|
175
|
+
- [ ] Implementation bugs escalated, not fixed
|
|
176
|
+
- [ ] Structured return provided (GAPS FILLED / PARTIAL / ESCALATE)
|
|
177
|
+
- [ ] Test files listed for commit
|
|
178
|
+
</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 |
|
|
@@ -368,11 +368,12 @@ Orchestrator provides: phase number/name, description/goal, requirements, constr
|
|
|
368
368
|
Load phase context using init command:
|
|
369
369
|
```bash
|
|
370
370
|
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHASE}")
|
|
371
|
+
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
371
372
|
```
|
|
372
373
|
|
|
373
374
|
Extract from init JSON: `phase_dir`, `padded_phase`, `phase_number`, `commit_docs`.
|
|
374
375
|
|
|
375
|
-
Also read `.planning/config.json` —
|
|
376
|
+
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
377
|
|
|
377
378
|
Then read CONTEXT.md if exists:
|
|
378
379
|
```bash
|
|
@@ -408,7 +409,7 @@ For each domain: Context7 first → Official docs → WebSearch → Cross-verify
|
|
|
408
409
|
|
|
409
410
|
## Step 4: Validation Architecture Research (if nyquist_validation enabled)
|
|
410
411
|
|
|
411
|
-
**Skip if** workflow.nyquist_validation is false.
|
|
412
|
+
**Skip if** workflow.nyquist_validation is explicitly set to false. If absent, treat as enabled.
|
|
412
413
|
|
|
413
414
|
### Detect Test Infrastructure
|
|
414
415
|
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
|
|
|
@@ -368,6 +381,7 @@ If FAIL: return to planner with specific fixes. Same revision loop as other dime
|
|
|
368
381
|
Load phase operation context:
|
|
369
382
|
```bash
|
|
370
383
|
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHASE_ARG}")
|
|
384
|
+
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
371
385
|
```
|
|
372
386
|
|
|
373
387
|
Extract from init JSON: `phase_dir`, `phase_number`, `has_plans`, `plan_count`.
|
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
|
|
|
@@ -973,6 +973,7 @@ Load planning context:
|
|
|
973
973
|
|
|
974
974
|
```bash
|
|
975
975
|
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init plan-phase "${PHASE}")
|
|
976
|
+
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
976
977
|
```
|
|
977
978
|
|
|
978
979
|
Extract from init JSON: `planner_model`, `researcher_model`, `checker_model`, `commit_docs`, `research_enabled`, `phase_dir`, `phase_number`, `has_research`, `has_context`.
|
|
@@ -1135,7 +1136,7 @@ Apply goal-backward methodology (see goal_backward section):
|
|
|
1135
1136
|
</step>
|
|
1136
1137
|
|
|
1137
1138
|
<step name="estimate_scope">
|
|
1138
|
-
Verify each plan fits context budget: 2-3 tasks, ~50% target. Split if necessary. Check
|
|
1139
|
+
Verify each plan fits context budget: 2-3 tasks, ~50% target. Split if necessary. Check granularity setting.
|
|
1139
1140
|
</step>
|
|
1140
1141
|
|
|
1141
1142
|
<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);
|
package/commands/gsd/debug.md
CHANGED
|
@@ -32,6 +32,7 @@ ls .planning/debug/*.md 2>/dev/null | grep -v resolved | head -5
|
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" state load)
|
|
35
|
+
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
35
36
|
```
|
|
36
37
|
|
|
37
38
|
Extract `commit_docs` from init JSON. Resolve debugger model:
|
package/commands/gsd/quick.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gsd:quick
|
|
3
3
|
description: Execute a quick task with GSD guarantees (atomic commits, state tracking) but skip optional agents
|
|
4
|
-
argument-hint: "[--full]"
|
|
4
|
+
argument-hint: "[--full] [--discuss]"
|
|
5
5
|
allowed-tools:
|
|
6
6
|
- Read
|
|
7
7
|
- Write
|
|
@@ -20,9 +20,13 @@ Quick mode is the same system with a shorter path:
|
|
|
20
20
|
- Quick tasks live in `.planning/quick/` separate from planned phases
|
|
21
21
|
- Updates STATE.md "Quick Tasks Completed" table (NOT ROADMAP.md)
|
|
22
22
|
|
|
23
|
-
**Default:** Skips research, plan-checker, verifier. Use when you know exactly what to do.
|
|
23
|
+
**Default:** Skips research, discussion, plan-checker, verifier. Use when you know exactly what to do.
|
|
24
|
+
|
|
25
|
+
**`--discuss` flag:** Lightweight discussion phase before planning. Surfaces assumptions, clarifies gray areas, captures decisions in CONTEXT.md. Use when the task has ambiguity worth resolving upfront.
|
|
24
26
|
|
|
25
27
|
**`--full` flag:** Enables plan-checking (max 2 iterations) and post-execution verification. Use when you want quality guarantees without full milestone ceremony.
|
|
28
|
+
|
|
29
|
+
Flags are composable: `--discuss --full` gives discussion + plan-checking + verification.
|
|
26
30
|
</objective>
|
|
27
31
|
|
|
28
32
|
<execution_context>
|
|
@@ -35,6 +35,7 @@ Normalize phase input in step 1 before any directory lookups.
|
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
37
|
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "$ARGUMENTS")
|
|
38
|
+
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
|
38
39
|
```
|
|
39
40
|
|
|
40
41
|
Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`, `phase_found`, `commit_docs`, `has_research`, `state_path`, `requirements_path`, `context_path`, `research_path`.
|
|
@@ -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) {
|