feat(gsd-tools): add compound init commands and update workflows (#468)
* feat(gsd-tools): add compound init commands for workflow setup Adds 8 compound commands that return all context a workflow needs in one JSON blob, replacing 5-10 atomic calls per workflow: - init execute-phase: models, config, phase info, plan inventory - init plan-phase: models, workflow flags, existing artifacts - init new-project: models, brownfield detection, state checks - init new-milestone: models, milestone info - init quick: models, next task number, timestamps - init resume: file existence, interrupted agent - init verify-work: models, phase info - init phase-op: generic phase context Updated 8 workflows to use compound commands: - execute-phase, plan-phase, new-project, quick - resume-project, verify-work, discuss-phase Token savings: ~200 lines of bash setup replaced with single init calls. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(gsd-tools): add 4 new init commands and update files to use compound commands Add new compound init commands: - init todos - context for todo workflows - init milestone-op - context for milestone operations - init map-codebase - context for codebase mapping - init progress - context for progress workflow Update 24 files to use compound init commands instead of atomic calls: - 4 phase operation workflows (add-phase, insert-phase, remove-phase, verify-phase) - 5 todo/milestone workflows (add-todo, check-todos, audit-milestone, complete-milestone, new-milestone) - 6 misc workflows (execute-plan, map-codebase, pause-work, progress, set-profile, settings) - 6 agent files (gsd-executor, gsd-planner, gsd-phase-researcher, gsd-plan-checker, gsd-debugger, gsd-research-synthesizer) - 2 command files (debug, research-phase) - 1 reference file (planning-config) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(gsd-tools): add init to help output Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(verify-phase): correct expected init fields The workflow was referencing plans/summaries from init phase-op, but those fields come from ls command. Updated to reference has_plans and plan_count which are actually in phase-op output. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -979,10 +979,11 @@ mkdir -p .planning/debug/resolved
|
||||
mv .planning/debug/{slug}.md .planning/debug/resolved/
|
||||
```
|
||||
|
||||
**Check planning config:**
|
||||
**Check planning config using state load (commit_docs is available from the output):**
|
||||
|
||||
```bash
|
||||
COMMIT_PLANNING_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
|
||||
# commit_docs is in the JSON output
|
||||
```
|
||||
|
||||
**Commit the fix:**
|
||||
|
||||
@@ -16,22 +16,21 @@ Your job: Execute the plan completely, commit each task, create SUMMARY.md, upda
|
||||
<execution_flow>
|
||||
|
||||
<step name="load_project_state" priority="first">
|
||||
Read project state:
|
||||
Load execution context:
|
||||
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "${PHASE}")
|
||||
```
|
||||
|
||||
Extract from init JSON: `executor_model`, `commit_docs`, `phase_dir`, `plans`, `incomplete_plans`.
|
||||
|
||||
Also read STATE.md for position, decisions, blockers:
|
||||
```bash
|
||||
cat .planning/STATE.md 2>/dev/null
|
||||
```
|
||||
|
||||
Parse: current position, accumulated decisions, blockers/concerns.
|
||||
|
||||
If STATE.md missing but .planning/ exists: offer to reconstruct or continue without.
|
||||
If .planning/ missing: Error — project not initialized.
|
||||
|
||||
**Load planning config:**
|
||||
|
||||
```bash
|
||||
COMMIT_PLANNING_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
|
||||
```
|
||||
</step>
|
||||
|
||||
<step name="load_plan">
|
||||
|
||||
@@ -293,11 +293,16 @@ Verified patterns from official sources:
|
||||
|
||||
Orchestrator provides: phase number/name, description/goal, requirements, constraints, output path.
|
||||
|
||||
Load phase context using init command:
|
||||
```bash
|
||||
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE" --raw)
|
||||
PADDED_PHASE=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE" | grep -o '"phase_number":"[^"]*"' | cut -d'"' -f4)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${PHASE}")
|
||||
```
|
||||
|
||||
cat "$PHASE_DIR"/*-CONTEXT.md 2>/dev/null
|
||||
Extract from init JSON: `phase_dir`, `padded_phase`, `phase_number`, `commit_docs`.
|
||||
|
||||
Then read CONTEXT.md if exists:
|
||||
```bash
|
||||
cat "$phase_dir"/*-CONTEXT.md 2>/dev/null
|
||||
```
|
||||
|
||||
**If CONTEXT.md exists**, it constrains research:
|
||||
|
||||
@@ -297,13 +297,19 @@ issue:
|
||||
|
||||
## Step 1: Load Context
|
||||
|
||||
Load phase operation context:
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${PHASE_ARG}")
|
||||
```
|
||||
|
||||
Extract from init JSON: `phase_dir`, `phase_number`, `has_plans`, `plan_count`.
|
||||
|
||||
Orchestrator provides CONTEXT.md content in the verification prompt. If provided, parse for locked decisions, discretion areas, deferred ideas.
|
||||
|
||||
```bash
|
||||
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE_ARG" --raw)
|
||||
ls "$PHASE_DIR"/*-PLAN.md 2>/dev/null
|
||||
grep -A 10 "Phase $PHASE_NUM" .planning/ROADMAP.md | head -15
|
||||
ls "$PHASE_DIR"/*-BRIEF.md 2>/dev/null
|
||||
ls "$phase_dir"/*-PLAN.md 2>/dev/null
|
||||
grep -A 10 "Phase $phase_number" .planning/ROADMAP.md | head -15
|
||||
ls "$phase_dir"/*-BRIEF.md 2>/dev/null
|
||||
```
|
||||
|
||||
**Extract:** Phase goal, requirements (decompose goal), locked decisions, deferred ideas.
|
||||
|
||||
@@ -683,14 +683,14 @@ Triggered by `--gaps` flag. Creates plans to address verification or UAT failure
|
||||
|
||||
**1. Find gap sources:**
|
||||
|
||||
```bash
|
||||
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE_ARG" --raw)
|
||||
Use init context (from load_project_state) which provides `phase_dir`:
|
||||
|
||||
```bash
|
||||
# Check for VERIFICATION.md (code verification gaps)
|
||||
ls "$PHASE_DIR"/*-VERIFICATION.md 2>/dev/null
|
||||
ls "$phase_dir"/*-VERIFICATION.md 2>/dev/null
|
||||
|
||||
# Check for UAT.md with diagnosed status (user testing gaps)
|
||||
grep -l "status: diagnosed" "$PHASE_DIR"/*-UAT.md 2>/dev/null
|
||||
grep -l "status: diagnosed" "$phase_dir"/*-UAT.md 2>/dev/null
|
||||
```
|
||||
|
||||
**2. Parse gaps:** Each gap has: truth (failed behavior), reason, artifacts (files with issues), missing (things to add/fix).
|
||||
@@ -830,15 +830,20 @@ node ~/.claude/get-shit-done/bin/gsd-tools.js commit "fix($PHASE): revise plans
|
||||
<execution_flow>
|
||||
|
||||
<step name="load_project_state" priority="first">
|
||||
Read `.planning/STATE.md` — parse current position, accumulated decisions, pending todos, blockers/concerns.
|
||||
|
||||
If STATE.md missing but .planning/ exists, offer to reconstruct or continue without.
|
||||
|
||||
**Load planning config:**
|
||||
Load planning context:
|
||||
|
||||
```bash
|
||||
COMMIT_PLANNING_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init plan-phase "${PHASE}")
|
||||
```
|
||||
|
||||
Extract from init JSON: `planner_model`, `researcher_model`, `checker_model`, `commit_docs`, `research_enabled`, `phase_dir`, `phase_number`, `has_research`, `has_context`.
|
||||
|
||||
Also read STATE.md for position, decisions, blockers:
|
||||
```bash
|
||||
cat .planning/STATE.md 2>/dev/null
|
||||
```
|
||||
|
||||
If STATE.md missing but .planning/ exists, offer to reconstruct or continue without.
|
||||
</step>
|
||||
|
||||
<step name="load_codebase_context">
|
||||
@@ -905,17 +910,17 @@ done
|
||||
</step>
|
||||
|
||||
<step name="gather_phase_context">
|
||||
```bash
|
||||
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE" --raw)
|
||||
Use `phase_dir` from init context (already loaded in load_project_state).
|
||||
|
||||
cat "$PHASE_DIR"/*-CONTEXT.md 2>/dev/null # From /gsd:discuss-phase
|
||||
cat "$PHASE_DIR"/*-RESEARCH.md 2>/dev/null # From /gsd:research-phase
|
||||
cat "$PHASE_DIR"/*-DISCOVERY.md 2>/dev/null # From mandatory discovery
|
||||
```bash
|
||||
cat "$phase_dir"/*-CONTEXT.md 2>/dev/null # From /gsd:discuss-phase
|
||||
cat "$phase_dir"/*-RESEARCH.md 2>/dev/null # From /gsd:research-phase
|
||||
cat "$phase_dir"/*-DISCOVERY.md 2>/dev/null # From mandatory discovery
|
||||
```
|
||||
|
||||
**If CONTEXT.md exists:** Honor user's vision, prioritize essential features, respect boundaries. Locked decisions — do not revisit.
|
||||
**If CONTEXT.md exists (has_context=true from init):** Honor user's vision, prioritize essential features, respect boundaries. Locked decisions — do not revisit.
|
||||
|
||||
**If RESEARCH.md exists:** Use standard_stack, architecture_patterns, dont_hand_roll, common_pitfalls.
|
||||
**If RESEARCH.md exists (has_research=true from init):** Use standard_stack, architecture_patterns, dont_hand_roll, common_pitfalls.
|
||||
</step>
|
||||
|
||||
<step name="break_into_tasks">
|
||||
|
||||
@@ -28,8 +28,13 @@ ls .planning/debug/*.md 2>/dev/null | grep -v resolved | head -5
|
||||
|
||||
<process>
|
||||
|
||||
## 0. Resolve Model Profile
|
||||
## 0. Initialize Context
|
||||
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
|
||||
```
|
||||
|
||||
Extract `commit_docs` from init JSON. Resolve debugger model:
|
||||
```bash
|
||||
DEBUGGER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-debugger --raw)
|
||||
```
|
||||
|
||||
@@ -31,23 +31,26 @@ Normalize phase input in step 1 before any directory lookups.
|
||||
|
||||
<process>
|
||||
|
||||
## 0. Resolve Model Profile
|
||||
## 0. Initialize Context
|
||||
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "$ARGUMENTS")
|
||||
```
|
||||
|
||||
Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`, `phase_found`, `commit_docs`, `has_research`.
|
||||
|
||||
Resolve researcher model:
|
||||
```bash
|
||||
RESEARCHER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-phase-researcher --raw)
|
||||
```
|
||||
|
||||
## 1. Normalize and Validate Phase
|
||||
## 1. Validate Phase
|
||||
|
||||
```bash
|
||||
PHASE_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$ARGUMENTS")
|
||||
PHASE_DIR=$(echo "$PHASE_INFO" | grep -o '"directory":"[^"]*"' | cut -d'"' -f4)
|
||||
PHASE=$(echo "$PHASE_INFO" | grep -o '"phase_number":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
grep -A5 "Phase ${PHASE}:" .planning/ROADMAP.md 2>/dev/null
|
||||
grep -A5 "Phase ${phase_number}:" .planning/ROADMAP.md 2>/dev/null
|
||||
```
|
||||
|
||||
**If not found:** Error and exit. **If found:** Extract phase number, name, description.
|
||||
**If not found (phase_found=false):** Error and exit. **If found:** Extract phase number, name, description.
|
||||
|
||||
## 2. Check Existing Research
|
||||
|
||||
|
||||
@@ -8,13 +8,27 @@
|
||||
*
|
||||
* Usage: node gsd-tools.js <command> [args] [--raw]
|
||||
*
|
||||
* Commands:
|
||||
* Atomic Commands:
|
||||
* state load Load project config + state
|
||||
* state update <field> <value> Update a STATE.md field
|
||||
* resolve-model <agent-type> Get model for agent based on profile
|
||||
* find-phase <phase> Find phase directory by number
|
||||
* commit <message> [--files f1 f2] Commit planning docs
|
||||
* verify-summary <path> Verify a SUMMARY.md file
|
||||
*
|
||||
* Compound Commands (workflow-specific initialization):
|
||||
* init execute-phase <phase> All context for execute-phase workflow
|
||||
* init plan-phase <phase> All context for plan-phase workflow
|
||||
* init new-project All context for new-project workflow
|
||||
* init new-milestone All context for new-milestone workflow
|
||||
* init quick <description> All context for quick workflow
|
||||
* init resume All context for resume-project workflow
|
||||
* init verify-work <phase> All context for verify-work workflow
|
||||
* init phase-op <phase> Generic phase operation context
|
||||
* init todos [area] All context for todo workflows
|
||||
* init milestone-op All context for milestone operations
|
||||
* init map-codebase All context for map-codebase workflow
|
||||
* init progress All context for progress workflow
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
@@ -556,6 +570,654 @@ function cmdVerifySummary(cwd, summaryPath, checkFileCount, raw) {
|
||||
output(result, raw, passed ? 'passed' : 'failed');
|
||||
}
|
||||
|
||||
// ─── Compound Commands ────────────────────────────────────────────────────────
|
||||
|
||||
function resolveModelInternal(cwd, agentType) {
|
||||
const config = loadConfig(cwd);
|
||||
const profile = config.model_profile || 'balanced';
|
||||
const agentModels = MODEL_PROFILES[agentType];
|
||||
if (!agentModels) return 'sonnet';
|
||||
return agentModels[profile] || agentModels['balanced'] || 'sonnet';
|
||||
}
|
||||
|
||||
function findPhaseInternal(cwd, phase) {
|
||||
if (!phase) return null;
|
||||
|
||||
const phasesDir = path.join(cwd, '.planning', 'phases');
|
||||
const normalized = normalizePhaseName(phase);
|
||||
|
||||
try {
|
||||
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
||||
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
|
||||
const match = dirs.find(d => d.startsWith(normalized));
|
||||
if (!match) return null;
|
||||
|
||||
const dirMatch = match.match(/^(\d+(?:\.\d+)?)-?(.*)/);
|
||||
const phaseNumber = dirMatch ? dirMatch[1] : normalized;
|
||||
const phaseName = dirMatch && dirMatch[2] ? dirMatch[2] : null;
|
||||
const phaseDir = path.join(phasesDir, match);
|
||||
const phaseFiles = fs.readdirSync(phaseDir);
|
||||
|
||||
const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md').sort();
|
||||
const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md').sort();
|
||||
const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
|
||||
const hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
|
||||
const hasVerification = phaseFiles.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
|
||||
|
||||
// Determine incomplete plans (plans without matching summaries)
|
||||
const completedPlanIds = new Set(
|
||||
summaries.map(s => s.replace('-SUMMARY.md', '').replace('SUMMARY.md', ''))
|
||||
);
|
||||
const incompletePlans = plans.filter(p => {
|
||||
const planId = p.replace('-PLAN.md', '').replace('PLAN.md', '');
|
||||
return !completedPlanIds.has(planId);
|
||||
});
|
||||
|
||||
return {
|
||||
found: true,
|
||||
directory: path.join('.planning', 'phases', match),
|
||||
phase_number: phaseNumber,
|
||||
phase_name: phaseName,
|
||||
phase_slug: phaseName ? phaseName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') : null,
|
||||
plans,
|
||||
summaries,
|
||||
incomplete_plans: incompletePlans,
|
||||
has_research: hasResearch,
|
||||
has_context: hasContext,
|
||||
has_verification: hasVerification,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function pathExistsInternal(cwd, targetPath) {
|
||||
const fullPath = path.isAbsolute(targetPath) ? targetPath : path.join(cwd, targetPath);
|
||||
try {
|
||||
fs.statSync(fullPath);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function generateSlugInternal(text) {
|
||||
if (!text) return null;
|
||||
return text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
||||
}
|
||||
|
||||
function getMilestoneInfo(cwd) {
|
||||
try {
|
||||
const roadmap = fs.readFileSync(path.join(cwd, '.planning', 'ROADMAP.md'), 'utf-8');
|
||||
const versionMatch = roadmap.match(/v(\d+\.\d+)/);
|
||||
const nameMatch = roadmap.match(/## .*v\d+\.\d+[:\s]+([^\n(]+)/);
|
||||
return {
|
||||
version: versionMatch ? versionMatch[0] : 'v1.0',
|
||||
name: nameMatch ? nameMatch[1].trim() : 'milestone',
|
||||
};
|
||||
} catch {
|
||||
return { version: 'v1.0', name: 'milestone' };
|
||||
}
|
||||
}
|
||||
|
||||
function cmdInitExecutePhase(cwd, phase, raw) {
|
||||
if (!phase) {
|
||||
error('phase required for init execute-phase');
|
||||
}
|
||||
|
||||
const config = loadConfig(cwd);
|
||||
const phaseInfo = findPhaseInternal(cwd, phase);
|
||||
const milestone = getMilestoneInfo(cwd);
|
||||
|
||||
const result = {
|
||||
// Models
|
||||
executor_model: resolveModelInternal(cwd, 'gsd-executor'),
|
||||
verifier_model: resolveModelInternal(cwd, 'gsd-verifier'),
|
||||
|
||||
// Config flags
|
||||
commit_docs: config.commit_docs,
|
||||
parallelization: config.parallelization,
|
||||
branching_strategy: config.branching_strategy,
|
||||
phase_branch_template: config.phase_branch_template,
|
||||
milestone_branch_template: config.milestone_branch_template,
|
||||
verifier_enabled: config.verifier,
|
||||
|
||||
// Phase info
|
||||
phase_found: !!phaseInfo,
|
||||
phase_dir: phaseInfo?.directory || null,
|
||||
phase_number: phaseInfo?.phase_number || null,
|
||||
phase_name: phaseInfo?.phase_name || null,
|
||||
phase_slug: phaseInfo?.phase_slug || null,
|
||||
|
||||
// Plan inventory
|
||||
plans: phaseInfo?.plans || [],
|
||||
summaries: phaseInfo?.summaries || [],
|
||||
incomplete_plans: phaseInfo?.incomplete_plans || [],
|
||||
plan_count: phaseInfo?.plans?.length || 0,
|
||||
incomplete_count: phaseInfo?.incomplete_plans?.length || 0,
|
||||
|
||||
// Branch name (pre-computed)
|
||||
branch_name: config.branching_strategy === 'phase' && phaseInfo
|
||||
? config.phase_branch_template
|
||||
.replace('{phase}', phaseInfo.phase_number)
|
||||
.replace('{slug}', phaseInfo.phase_slug || 'phase')
|
||||
: config.branching_strategy === 'milestone'
|
||||
? config.milestone_branch_template
|
||||
.replace('{milestone}', milestone.version)
|
||||
.replace('{slug}', generateSlugInternal(milestone.name) || 'milestone')
|
||||
: null,
|
||||
|
||||
// Milestone info
|
||||
milestone_version: milestone.version,
|
||||
milestone_name: milestone.name,
|
||||
milestone_slug: generateSlugInternal(milestone.name),
|
||||
|
||||
// File existence
|
||||
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
|
||||
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
|
||||
config_exists: pathExistsInternal(cwd, '.planning/config.json'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitPlanPhase(cwd, phase, raw) {
|
||||
if (!phase) {
|
||||
error('phase required for init plan-phase');
|
||||
}
|
||||
|
||||
const config = loadConfig(cwd);
|
||||
const phaseInfo = findPhaseInternal(cwd, phase);
|
||||
|
||||
const result = {
|
||||
// Models
|
||||
researcher_model: resolveModelInternal(cwd, 'gsd-phase-researcher'),
|
||||
planner_model: resolveModelInternal(cwd, 'gsd-planner'),
|
||||
checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
|
||||
|
||||
// Workflow flags
|
||||
research_enabled: config.research,
|
||||
plan_checker_enabled: config.plan_checker,
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
// Phase info
|
||||
phase_found: !!phaseInfo,
|
||||
phase_dir: phaseInfo?.directory || null,
|
||||
phase_number: phaseInfo?.phase_number || null,
|
||||
phase_name: phaseInfo?.phase_name || null,
|
||||
phase_slug: phaseInfo?.phase_slug || null,
|
||||
padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
|
||||
|
||||
// Existing artifacts
|
||||
has_research: phaseInfo?.has_research || false,
|
||||
has_context: phaseInfo?.has_context || false,
|
||||
has_plans: (phaseInfo?.plans?.length || 0) > 0,
|
||||
plan_count: phaseInfo?.plans?.length || 0,
|
||||
|
||||
// Environment
|
||||
planning_exists: pathExistsInternal(cwd, '.planning'),
|
||||
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitNewProject(cwd, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
|
||||
// Detect existing code
|
||||
let hasCode = false;
|
||||
let hasPackageFile = false;
|
||||
try {
|
||||
const files = execSync('find . -maxdepth 3 \\( -name "*.ts" -o -name "*.js" -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.swift" -o -name "*.java" \\) 2>/dev/null | grep -v node_modules | grep -v .git | head -5', {
|
||||
cwd,
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
});
|
||||
hasCode = files.trim().length > 0;
|
||||
} catch {}
|
||||
|
||||
hasPackageFile = pathExistsInternal(cwd, 'package.json') ||
|
||||
pathExistsInternal(cwd, 'requirements.txt') ||
|
||||
pathExistsInternal(cwd, 'Cargo.toml') ||
|
||||
pathExistsInternal(cwd, 'go.mod') ||
|
||||
pathExistsInternal(cwd, 'Package.swift');
|
||||
|
||||
const result = {
|
||||
// Models
|
||||
researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
|
||||
synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
|
||||
roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
|
||||
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
// Existing state
|
||||
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
||||
has_codebase_map: pathExistsInternal(cwd, '.planning/codebase'),
|
||||
planning_exists: pathExistsInternal(cwd, '.planning'),
|
||||
|
||||
// Brownfield detection
|
||||
has_existing_code: hasCode,
|
||||
has_package_file: hasPackageFile,
|
||||
is_brownfield: hasCode || hasPackageFile,
|
||||
needs_codebase_map: (hasCode || hasPackageFile) && !pathExistsInternal(cwd, '.planning/codebase'),
|
||||
|
||||
// Git state
|
||||
has_git: pathExistsInternal(cwd, '.git'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitNewMilestone(cwd, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
const milestone = getMilestoneInfo(cwd);
|
||||
|
||||
const result = {
|
||||
// Models
|
||||
researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
|
||||
synthesizer_model: resolveModelInternal(cwd, 'gsd-research-synthesizer'),
|
||||
roadmapper_model: resolveModelInternal(cwd, 'gsd-roadmapper'),
|
||||
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
research_enabled: config.research,
|
||||
|
||||
// Current milestone
|
||||
current_milestone: milestone.version,
|
||||
current_milestone_name: milestone.name,
|
||||
|
||||
// File existence
|
||||
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
||||
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
|
||||
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitQuick(cwd, description, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
const now = new Date();
|
||||
const slug = description ? generateSlugInternal(description)?.substring(0, 40) : null;
|
||||
|
||||
// Find next quick task number
|
||||
const quickDir = path.join(cwd, '.planning', 'quick');
|
||||
let nextNum = 1;
|
||||
try {
|
||||
const existing = fs.readdirSync(quickDir)
|
||||
.filter(f => /^\d+-/.test(f))
|
||||
.map(f => parseInt(f.split('-')[0], 10))
|
||||
.filter(n => !isNaN(n));
|
||||
if (existing.length > 0) {
|
||||
nextNum = Math.max(...existing) + 1;
|
||||
}
|
||||
} catch {}
|
||||
|
||||
const result = {
|
||||
// Models
|
||||
planner_model: resolveModelInternal(cwd, 'gsd-planner'),
|
||||
executor_model: resolveModelInternal(cwd, 'gsd-executor'),
|
||||
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
// Quick task info
|
||||
next_num: nextNum,
|
||||
slug: slug,
|
||||
description: description || null,
|
||||
|
||||
// Timestamps
|
||||
date: now.toISOString().split('T')[0],
|
||||
timestamp: now.toISOString(),
|
||||
|
||||
// Paths
|
||||
quick_dir: '.planning/quick',
|
||||
task_dir: slug ? `.planning/quick/${nextNum}-${slug}` : null,
|
||||
|
||||
// File existence
|
||||
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
|
||||
planning_exists: pathExistsInternal(cwd, '.planning'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitResume(cwd, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
|
||||
// Check for interrupted agent
|
||||
let interruptedAgentId = null;
|
||||
try {
|
||||
interruptedAgentId = fs.readFileSync(path.join(cwd, '.planning', 'current-agent-id.txt'), 'utf-8').trim();
|
||||
} catch {}
|
||||
|
||||
const result = {
|
||||
// File existence
|
||||
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
|
||||
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
|
||||
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
||||
planning_exists: pathExistsInternal(cwd, '.planning'),
|
||||
|
||||
// Agent state
|
||||
has_interrupted_agent: !!interruptedAgentId,
|
||||
interrupted_agent_id: interruptedAgentId,
|
||||
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitVerifyWork(cwd, phase, raw) {
|
||||
if (!phase) {
|
||||
error('phase required for init verify-work');
|
||||
}
|
||||
|
||||
const config = loadConfig(cwd);
|
||||
const phaseInfo = findPhaseInternal(cwd, phase);
|
||||
|
||||
const result = {
|
||||
// Models
|
||||
planner_model: resolveModelInternal(cwd, 'gsd-planner'),
|
||||
checker_model: resolveModelInternal(cwd, 'gsd-plan-checker'),
|
||||
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
// Phase info
|
||||
phase_found: !!phaseInfo,
|
||||
phase_dir: phaseInfo?.directory || null,
|
||||
phase_number: phaseInfo?.phase_number || null,
|
||||
phase_name: phaseInfo?.phase_name || null,
|
||||
|
||||
// Existing artifacts
|
||||
has_verification: phaseInfo?.has_verification || false,
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitPhaseOp(cwd, phase, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
const phaseInfo = findPhaseInternal(cwd, phase);
|
||||
|
||||
const result = {
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
// Phase info
|
||||
phase_found: !!phaseInfo,
|
||||
phase_dir: phaseInfo?.directory || null,
|
||||
phase_number: phaseInfo?.phase_number || null,
|
||||
phase_name: phaseInfo?.phase_name || null,
|
||||
phase_slug: phaseInfo?.phase_slug || null,
|
||||
padded_phase: phaseInfo?.phase_number?.padStart(2, '0') || null,
|
||||
|
||||
// Existing artifacts
|
||||
has_research: phaseInfo?.has_research || false,
|
||||
has_context: phaseInfo?.has_context || false,
|
||||
has_plans: (phaseInfo?.plans?.length || 0) > 0,
|
||||
has_verification: phaseInfo?.has_verification || false,
|
||||
plan_count: phaseInfo?.plans?.length || 0,
|
||||
|
||||
// File existence
|
||||
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
|
||||
planning_exists: pathExistsInternal(cwd, '.planning'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitTodos(cwd, area, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
const now = new Date();
|
||||
|
||||
// List todos (reuse existing logic)
|
||||
const pendingDir = path.join(cwd, '.planning', 'todos', 'pending');
|
||||
let count = 0;
|
||||
const todos = [];
|
||||
|
||||
try {
|
||||
const files = fs.readdirSync(pendingDir).filter(f => f.endsWith('.md'));
|
||||
for (const file of files) {
|
||||
try {
|
||||
const content = fs.readFileSync(path.join(pendingDir, file), 'utf-8');
|
||||
const createdMatch = content.match(/^created:\s*(.+)$/m);
|
||||
const titleMatch = content.match(/^title:\s*(.+)$/m);
|
||||
const areaMatch = content.match(/^area:\s*(.+)$/m);
|
||||
const todoArea = areaMatch ? areaMatch[1].trim() : 'general';
|
||||
|
||||
if (area && todoArea !== area) continue;
|
||||
|
||||
count++;
|
||||
todos.push({
|
||||
file,
|
||||
created: createdMatch ? createdMatch[1].trim() : 'unknown',
|
||||
title: titleMatch ? titleMatch[1].trim() : 'Untitled',
|
||||
area: todoArea,
|
||||
path: path.join('.planning', 'todos', 'pending', file),
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
const result = {
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
// Timestamps
|
||||
date: now.toISOString().split('T')[0],
|
||||
timestamp: now.toISOString(),
|
||||
|
||||
// Todo inventory
|
||||
todo_count: count,
|
||||
todos,
|
||||
area_filter: area || null,
|
||||
|
||||
// Paths
|
||||
pending_dir: '.planning/todos/pending',
|
||||
completed_dir: '.planning/todos/completed',
|
||||
|
||||
// File existence
|
||||
planning_exists: pathExistsInternal(cwd, '.planning'),
|
||||
todos_dir_exists: pathExistsInternal(cwd, '.planning/todos'),
|
||||
pending_dir_exists: pathExistsInternal(cwd, '.planning/todos/pending'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitMilestoneOp(cwd, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
const milestone = getMilestoneInfo(cwd);
|
||||
|
||||
// Count phases
|
||||
let phaseCount = 0;
|
||||
let completedPhases = 0;
|
||||
const phasesDir = path.join(cwd, '.planning', 'phases');
|
||||
try {
|
||||
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
||||
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
|
||||
phaseCount = dirs.length;
|
||||
|
||||
// Count phases with summaries (completed)
|
||||
for (const dir of dirs) {
|
||||
try {
|
||||
const phaseFiles = fs.readdirSync(path.join(phasesDir, dir));
|
||||
const hasSummary = phaseFiles.some(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
|
||||
if (hasSummary) completedPhases++;
|
||||
} catch {}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
// Check archive
|
||||
const archiveDir = path.join(cwd, '.planning', 'archive');
|
||||
let archivedMilestones = [];
|
||||
try {
|
||||
archivedMilestones = fs.readdirSync(archiveDir, { withFileTypes: true })
|
||||
.filter(e => e.isDirectory())
|
||||
.map(e => e.name);
|
||||
} catch {}
|
||||
|
||||
const result = {
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
// Current milestone
|
||||
milestone_version: milestone.version,
|
||||
milestone_name: milestone.name,
|
||||
milestone_slug: generateSlugInternal(milestone.name),
|
||||
|
||||
// Phase counts
|
||||
phase_count: phaseCount,
|
||||
completed_phases: completedPhases,
|
||||
all_phases_complete: phaseCount > 0 && phaseCount === completedPhases,
|
||||
|
||||
// Archive
|
||||
archived_milestones: archivedMilestones,
|
||||
archive_count: archivedMilestones.length,
|
||||
|
||||
// File existence
|
||||
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
||||
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
|
||||
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
|
||||
archive_exists: pathExistsInternal(cwd, '.planning/archive'),
|
||||
phases_dir_exists: pathExistsInternal(cwd, '.planning/phases'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitMapCodebase(cwd, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
|
||||
// Check for existing codebase maps
|
||||
const codebaseDir = path.join(cwd, '.planning', 'codebase');
|
||||
let existingMaps = [];
|
||||
try {
|
||||
existingMaps = fs.readdirSync(codebaseDir).filter(f => f.endsWith('.md'));
|
||||
} catch {}
|
||||
|
||||
const result = {
|
||||
// Models
|
||||
mapper_model: resolveModelInternal(cwd, 'gsd-codebase-mapper'),
|
||||
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
search_gitignored: config.search_gitignored,
|
||||
parallelization: config.parallelization,
|
||||
|
||||
// Paths
|
||||
codebase_dir: '.planning/codebase',
|
||||
|
||||
// Existing maps
|
||||
existing_maps: existingMaps,
|
||||
has_maps: existingMaps.length > 0,
|
||||
|
||||
// File existence
|
||||
planning_exists: pathExistsInternal(cwd, '.planning'),
|
||||
codebase_dir_exists: pathExistsInternal(cwd, '.planning/codebase'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
function cmdInitProgress(cwd, raw) {
|
||||
const config = loadConfig(cwd);
|
||||
const milestone = getMilestoneInfo(cwd);
|
||||
|
||||
// Analyze phases
|
||||
const phasesDir = path.join(cwd, '.planning', 'phases');
|
||||
const phases = [];
|
||||
let currentPhase = null;
|
||||
let nextPhase = null;
|
||||
|
||||
try {
|
||||
const entries = fs.readdirSync(phasesDir, { withFileTypes: true });
|
||||
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name).sort();
|
||||
|
||||
for (const dir of dirs) {
|
||||
const match = dir.match(/^(\d+(?:\.\d+)?)-?(.*)/);
|
||||
const phaseNumber = match ? match[1] : dir;
|
||||
const phaseName = match && match[2] ? match[2] : null;
|
||||
|
||||
const phasePath = path.join(phasesDir, dir);
|
||||
const phaseFiles = fs.readdirSync(phasePath);
|
||||
|
||||
const plans = phaseFiles.filter(f => f.endsWith('-PLAN.md') || f === 'PLAN.md');
|
||||
const summaries = phaseFiles.filter(f => f.endsWith('-SUMMARY.md') || f === 'SUMMARY.md');
|
||||
const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
|
||||
|
||||
const status = summaries.length >= plans.length && plans.length > 0 ? 'complete' :
|
||||
plans.length > 0 ? 'in_progress' :
|
||||
hasResearch ? 'researched' : 'pending';
|
||||
|
||||
const phaseInfo = {
|
||||
number: phaseNumber,
|
||||
name: phaseName,
|
||||
directory: path.join('.planning', 'phases', dir),
|
||||
status,
|
||||
plan_count: plans.length,
|
||||
summary_count: summaries.length,
|
||||
has_research: hasResearch,
|
||||
};
|
||||
|
||||
phases.push(phaseInfo);
|
||||
|
||||
// Find current (first incomplete with plans) and next (first pending)
|
||||
if (!currentPhase && (status === 'in_progress' || status === 'researched')) {
|
||||
currentPhase = phaseInfo;
|
||||
}
|
||||
if (!nextPhase && status === 'pending') {
|
||||
nextPhase = phaseInfo;
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
// Check for paused work
|
||||
let pausedAt = null;
|
||||
try {
|
||||
const state = fs.readFileSync(path.join(cwd, '.planning', 'STATE.md'), 'utf-8');
|
||||
const pauseMatch = state.match(/\*\*Paused At:\*\*\s*(.+)/);
|
||||
if (pauseMatch) pausedAt = pauseMatch[1].trim();
|
||||
} catch {}
|
||||
|
||||
const result = {
|
||||
// Models
|
||||
executor_model: resolveModelInternal(cwd, 'gsd-executor'),
|
||||
planner_model: resolveModelInternal(cwd, 'gsd-planner'),
|
||||
|
||||
// Config
|
||||
commit_docs: config.commit_docs,
|
||||
|
||||
// Milestone
|
||||
milestone_version: milestone.version,
|
||||
milestone_name: milestone.name,
|
||||
|
||||
// Phase overview
|
||||
phases,
|
||||
phase_count: phases.length,
|
||||
completed_count: phases.filter(p => p.status === 'complete').length,
|
||||
in_progress_count: phases.filter(p => p.status === 'in_progress').length,
|
||||
|
||||
// Current state
|
||||
current_phase: currentPhase,
|
||||
next_phase: nextPhase,
|
||||
paused_at: pausedAt,
|
||||
has_work_in_progress: !!currentPhase,
|
||||
|
||||
// File existence
|
||||
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
|
||||
roadmap_exists: pathExistsInternal(cwd, '.planning/ROADMAP.md'),
|
||||
state_exists: pathExistsInternal(cwd, '.planning/STATE.md'),
|
||||
};
|
||||
|
||||
output(result, raw);
|
||||
}
|
||||
|
||||
// ─── CLI Router ───────────────────────────────────────────────────────────────
|
||||
|
||||
function main() {
|
||||
@@ -568,7 +1230,7 @@ function main() {
|
||||
const cwd = process.cwd();
|
||||
|
||||
if (!command) {
|
||||
error('Usage: gsd-tools <command> [args] [--raw]\nCommands: state, resolve-model, find-phase, commit, verify-summary, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section');
|
||||
error('Usage: gsd-tools <command> [args] [--raw]\nCommands: state, resolve-model, find-phase, commit, verify-summary, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, init');
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
@@ -634,6 +1296,51 @@ function main() {
|
||||
break;
|
||||
}
|
||||
|
||||
case 'init': {
|
||||
const workflow = args[1];
|
||||
switch (workflow) {
|
||||
case 'execute-phase':
|
||||
cmdInitExecutePhase(cwd, args[2], raw);
|
||||
break;
|
||||
case 'plan-phase':
|
||||
cmdInitPlanPhase(cwd, args[2], raw);
|
||||
break;
|
||||
case 'new-project':
|
||||
cmdInitNewProject(cwd, raw);
|
||||
break;
|
||||
case 'new-milestone':
|
||||
cmdInitNewMilestone(cwd, raw);
|
||||
break;
|
||||
case 'quick':
|
||||
cmdInitQuick(cwd, args.slice(2).join(' '), raw);
|
||||
break;
|
||||
case 'resume':
|
||||
cmdInitResume(cwd, raw);
|
||||
break;
|
||||
case 'verify-work':
|
||||
cmdInitVerifyWork(cwd, args[2], raw);
|
||||
break;
|
||||
case 'phase-op':
|
||||
cmdInitPhaseOp(cwd, args[2], raw);
|
||||
break;
|
||||
case 'todos':
|
||||
cmdInitTodos(cwd, args[2], raw);
|
||||
break;
|
||||
case 'milestone-op':
|
||||
cmdInitMilestoneOp(cwd, raw);
|
||||
break;
|
||||
case 'map-codebase':
|
||||
cmdInitMapCodebase(cwd, raw);
|
||||
break;
|
||||
case 'progress':
|
||||
cmdInitProgress(cwd, raw);
|
||||
break;
|
||||
default:
|
||||
error(`Unknown init workflow: ${workflow}\nAvailable: execute-phase, plan-phase, new-project, new-milestone, quick, resume, verify-work, phase-op, todos, milestone-op, map-codebase, progress`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
error(`Unknown command: ${command}`);
|
||||
}
|
||||
|
||||
@@ -42,8 +42,13 @@ Configuration options for `.planning/` directory behavior.
|
||||
# Commit with automatic commit_docs + gitignore checks:
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js commit "docs: update state" --files .planning/STATE.md
|
||||
|
||||
# Or read config manually:
|
||||
COMMIT_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
|
||||
# Load config via state load (returns JSON):
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
|
||||
# commit_docs is available in the JSON output
|
||||
|
||||
# Or use init commands which include commit_docs:
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "1")
|
||||
# commit_docs is included in all init command outputs
|
||||
```
|
||||
|
||||
**Auto-detection:** If `.planning/` is gitignored, `commit_docs` is automatically `false` regardless of config.json. This prevents git errors when users have `.planning/` in `.gitignore`.
|
||||
@@ -136,11 +141,16 @@ To use uncommitted mode:
|
||||
|
||||
**Checking the config:**
|
||||
|
||||
Use `init execute-phase` which returns all config as JSON:
|
||||
```bash
|
||||
GSD_CONFIG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw)
|
||||
BRANCHING_STRATEGY=$(echo "$GSD_CONFIG" | grep '^branching_strategy=' | cut -d= -f2)
|
||||
PHASE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^phase_branch_template=' | cut -d= -f2)
|
||||
MILESTONE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^milestone_branch_template=' | cut -d= -f2)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "1")
|
||||
# JSON output includes: branching_strategy, phase_branch_template, milestone_branch_template
|
||||
```
|
||||
|
||||
Or use `state load` for the config values:
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
|
||||
# Parse branching_strategy, phase_branch_template, milestone_branch_template from JSON
|
||||
```
|
||||
|
||||
**Branch creation:**
|
||||
|
||||
@@ -25,14 +25,14 @@ Example: /gsd:add-phase Add authentication system
|
||||
Exit.
|
||||
</step>
|
||||
|
||||
<step name="load_roadmap">
|
||||
Load the roadmap file:
|
||||
<step name="init_context">
|
||||
Load phase operation context:
|
||||
|
||||
```bash
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "0")
|
||||
```
|
||||
|
||||
If false:
|
||||
Check `roadmap_exists` from init JSON. If false:
|
||||
```
|
||||
ERROR: No roadmap found (.planning/ROADMAP.md)
|
||||
Run /gsd:new-project to initialize.
|
||||
@@ -75,8 +75,9 @@ Format as two-digit: `printf "%02d" $next_phase`
|
||||
</step>
|
||||
|
||||
<step name="generate_slug">
|
||||
Convert the phase description to a kebab-case slug:
|
||||
Convert the phase description to a kebab-case slug.
|
||||
|
||||
Use `init phase-op` which provides `phase_slug` computed from phase name, or call:
|
||||
```bash
|
||||
slug=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$description" --raw)
|
||||
```
|
||||
|
||||
@@ -8,18 +8,21 @@ Read all files referenced by the invoking prompt's execution_context before star
|
||||
|
||||
<process>
|
||||
|
||||
<step name="ensure_directory">
|
||||
<step name="init_context">
|
||||
Load todo context:
|
||||
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init todos)
|
||||
```
|
||||
|
||||
Extract from init JSON: `commit_docs`, `date`, `timestamp`, `todo_count`, `todos`, `pending_dir`, `todos_dir_exists`.
|
||||
|
||||
Ensure directories exist:
|
||||
```bash
|
||||
mkdir -p .planning/todos/pending .planning/todos/done
|
||||
```
|
||||
</step>
|
||||
|
||||
<step name="check_existing_areas">
|
||||
```bash
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos | grep -oP '"area":\s*"\K[^"]+' | sort -u
|
||||
```
|
||||
|
||||
Note existing areas for consistency in infer_area step.
|
||||
Note existing areas from the todos array for consistency in infer_area step.
|
||||
</step>
|
||||
|
||||
<step name="extract_content">
|
||||
@@ -76,13 +79,14 @@ If overlapping, use AskUserQuestion:
|
||||
</step>
|
||||
|
||||
<step name="create_file">
|
||||
Use values from init context: `timestamp` and `date` are already available.
|
||||
|
||||
Generate slug for the title:
|
||||
```bash
|
||||
timestamp=$(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp full --raw)
|
||||
date_prefix=$(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp date --raw)
|
||||
slug=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$title" --raw)
|
||||
```
|
||||
|
||||
Write to `.planning/todos/pending/${date_prefix}-${slug}.md`:
|
||||
Write to `.planning/todos/pending/${date}-${slug}.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
@@ -106,7 +110,7 @@ files:
|
||||
<step name="update_state">
|
||||
If `.planning/STATE.md` exists:
|
||||
|
||||
1. Count todos: `node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos --raw`
|
||||
1. Use `todo_count` from init context (or re-run `init todos` if count changed)
|
||||
2. Update "### Pending Todos" under "## Accumulated Context"
|
||||
</step>
|
||||
|
||||
|
||||
@@ -8,8 +8,15 @@ Read all files referenced by the invoking prompt's execution_context before star
|
||||
|
||||
<process>
|
||||
|
||||
## 0. Resolve Model Profile
|
||||
## 0. Initialize Milestone Context
|
||||
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init milestone-op)
|
||||
```
|
||||
|
||||
Extract from init JSON: `milestone_version`, `milestone_name`, `phase_count`, `completed_phases`, `commit_docs`.
|
||||
|
||||
Resolve integration checker model:
|
||||
```bash
|
||||
CHECKER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-integration-checker --raw)
|
||||
```
|
||||
|
||||
@@ -8,13 +8,16 @@ Read all files referenced by the invoking prompt's execution_context before star
|
||||
|
||||
<process>
|
||||
|
||||
<step name="check_exist">
|
||||
<step name="init_context">
|
||||
Load todo context:
|
||||
|
||||
```bash
|
||||
TODO_COUNT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos --raw)
|
||||
echo "Pending todos: $TODO_COUNT"
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init todos)
|
||||
```
|
||||
|
||||
If count is 0:
|
||||
Extract from init JSON: `todo_count`, `todos`, `pending_dir`.
|
||||
|
||||
If `todo_count` is 0:
|
||||
```
|
||||
No pending todos.
|
||||
|
||||
@@ -38,12 +41,9 @@ Check for area filter in arguments:
|
||||
</step>
|
||||
|
||||
<step name="list_todos">
|
||||
```bash
|
||||
# Get todos JSON
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos [area]
|
||||
```
|
||||
Use the `todos` array from init context (already filtered by area if specified).
|
||||
|
||||
Parse JSON output and display as numbered list:
|
||||
Parse and display as numbered list:
|
||||
|
||||
```
|
||||
Pending Todos:
|
||||
@@ -90,11 +90,9 @@ If `files` field has entries, read and briefly summarize each.
|
||||
</step>
|
||||
|
||||
<step name="check_roadmap">
|
||||
```bash
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw
|
||||
```
|
||||
Check for roadmap (can use init progress or directly check file existence):
|
||||
|
||||
If roadmap exists:
|
||||
If `.planning/ROADMAP.md` exists:
|
||||
1. Check if todo's area matches an upcoming phase
|
||||
2. Check if todo's files overlap with a phase's scope
|
||||
3. Note any match for action options
|
||||
@@ -148,11 +146,7 @@ Return to list_todos step.
|
||||
<step name="update_state">
|
||||
After any action that changes todo count:
|
||||
|
||||
```bash
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos --raw
|
||||
```
|
||||
|
||||
Update STATE.md "### Pending Todos" section if exists.
|
||||
Re-run `init todos` to get updated count, then update STATE.md "### Pending Todos" section if exists.
|
||||
</step>
|
||||
|
||||
<step name="git_commit">
|
||||
|
||||
@@ -450,11 +450,11 @@ Archive requirements for next milestone.
|
||||
|
||||
<step name="archive_audit">
|
||||
|
||||
Move audit file to archive (if exists):
|
||||
Move audit file to archive (if exists). Use init context or check directly:
|
||||
|
||||
```bash
|
||||
AUDIT_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/v[X.Y]-MILESTONE-AUDIT.md --raw)
|
||||
[ "$AUDIT_EXISTS" = "true" ] && mv .planning/v[X.Y]-MILESTONE-AUDIT.md .planning/milestones/
|
||||
# Check if audit file exists
|
||||
[ -f ".planning/v[X.Y]-MILESTONE-AUDIT.md" ] && mv .planning/v[X.Y]-MILESTONE-AUDIT.md .planning/milestones/
|
||||
```
|
||||
|
||||
Confirm: `✅ Audit archived to milestones/v[X.Y]-MILESTONE-AUDIT.md`
|
||||
@@ -500,13 +500,14 @@ Progress: [updated progress bar]
|
||||
|
||||
Check branching strategy and offer merge options.
|
||||
|
||||
Use `init milestone-op` for context, or load config directly:
|
||||
|
||||
```bash
|
||||
GSD_CONFIG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw)
|
||||
BRANCHING_STRATEGY=$(echo "$GSD_CONFIG" | grep '^branching_strategy=' | cut -d= -f2)
|
||||
PHASE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^phase_branch_template=' | cut -d= -f2)
|
||||
MILESTONE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^milestone_branch_template=' | cut -d= -f2)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "1")
|
||||
```
|
||||
|
||||
Extract `branching_strategy`, `phase_branch_template`, `milestone_branch_template` from init JSON.
|
||||
|
||||
**If "none":** Skip to git_tag.
|
||||
|
||||
**For "phase" strategy:**
|
||||
|
||||
@@ -107,15 +107,16 @@ Phase: "API documentation"
|
||||
|
||||
<process>
|
||||
|
||||
<step name="validate_phase" priority="first">
|
||||
<step name="initialize" priority="first">
|
||||
Phase number from argument (required).
|
||||
|
||||
Load and validate:
|
||||
- Read `.planning/ROADMAP.md`
|
||||
- Find phase entry
|
||||
- Extract: number, name, description, status
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${PHASE}")
|
||||
```
|
||||
|
||||
**If phase not found:**
|
||||
Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`, `plan_count`, `roadmap_exists`, `planning_exists`.
|
||||
|
||||
**If `phase_found` is false:**
|
||||
```
|
||||
Phase [X] not found in roadmap.
|
||||
|
||||
@@ -123,15 +124,14 @@ Use /gsd:progress to see available phases.
|
||||
```
|
||||
Exit workflow.
|
||||
|
||||
**If phase found:** Continue to analyze_phase.
|
||||
**If `phase_found` is true:** Continue to check_existing.
|
||||
</step>
|
||||
|
||||
<step name="check_existing">
|
||||
Check if CONTEXT.md already exists:
|
||||
Check if CONTEXT.md already exists using `has_context` from init.
|
||||
|
||||
```bash
|
||||
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE}" --raw)
|
||||
ls ${PHASE_DIR}/*-CONTEXT.md 2>/dev/null
|
||||
ls ${phase_dir}/*-CONTEXT.md 2>/dev/null
|
||||
```
|
||||
|
||||
**If exists:**
|
||||
@@ -280,20 +280,14 @@ Create CONTEXT.md capturing decisions made.
|
||||
|
||||
**Find or create phase directory:**
|
||||
|
||||
Use values from init: `phase_dir`, `phase_slug`, `padded_phase`.
|
||||
|
||||
If `phase_dir` is null (phase exists in roadmap but no directory):
|
||||
```bash
|
||||
PHASE_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE}")
|
||||
PHASE_DIR=$(echo "$PHASE_INFO" | grep -o '"directory":"[^"]*"' | cut -d'"' -f4)
|
||||
PADDED_PHASE=$(echo "$PHASE_INFO" | grep -o '"phase_number":"[^"]*"' | cut -d'"' -f4)
|
||||
if [ -z "$PHASE_DIR" ]; then
|
||||
PHASE_NAME=$(grep "Phase ${PHASE}:" .planning/ROADMAP.md | sed 's/.*Phase [0-9]*: //')
|
||||
PHASE_SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$PHASE_NAME" --raw)
|
||||
PADDED_PHASE=$(printf "%02d" ${PHASE})
|
||||
mkdir -p ".planning/phases/${PADDED_PHASE}-${PHASE_SLUG}"
|
||||
PHASE_DIR=".planning/phases/${PADDED_PHASE}-${PHASE_SLUG}"
|
||||
fi
|
||||
mkdir -p ".planning/phases/${padded_phase}-${phase_slug}"
|
||||
```
|
||||
|
||||
**File location:** `${PHASE_DIR}/${PADDED_PHASE}-CONTEXT.md`
|
||||
**File location:** `${phase_dir}/${padded_phase}-CONTEXT.md`
|
||||
|
||||
**Structure the content by what was discussed:**
|
||||
|
||||
@@ -391,13 +385,13 @@ Created: .planning/phases/${PADDED_PHASE}-${SLUG}/${PADDED_PHASE}-CONTEXT.md
|
||||
</step>
|
||||
|
||||
<step name="git_commit">
|
||||
Commit phase context:
|
||||
Commit phase context (uses `commit_docs` from init internally):
|
||||
|
||||
```bash
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js commit "docs(${PADDED_PHASE}): capture phase context" --files "${PHASE_DIR}/${PADDED_PHASE}-CONTEXT.md"
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js commit "docs(${padded_phase}): capture phase context" --files "${phase_dir}/${padded_phase}-CONTEXT.md"
|
||||
```
|
||||
|
||||
Confirm: "Committed: docs(${PADDED_PHASE}): capture phase context"
|
||||
Confirm: "Committed: docs(${padded_phase}): capture phase context"
|
||||
</step>
|
||||
|
||||
</process>
|
||||
|
||||
@@ -7,63 +7,34 @@ Orchestrator coordinates, not executes. Each subagent loads the full execute-pla
|
||||
</core_principle>
|
||||
|
||||
<required_reading>
|
||||
Read STATE.md and config.json before any operation.
|
||||
Read STATE.md before any operation to load project context.
|
||||
</required_reading>
|
||||
|
||||
<process>
|
||||
|
||||
<step name="resolve_model_profile" priority="first">
|
||||
<step name="initialize" priority="first">
|
||||
Load all context in one call:
|
||||
|
||||
```bash
|
||||
EXECUTOR_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-executor --raw)
|
||||
VERIFIER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-verifier --raw)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "${PHASE_ARG}")
|
||||
```
|
||||
|
||||
</step>
|
||||
Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelization`, `branching_strategy`, `branch_name`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `plans`, `incomplete_plans`, `plan_count`, `incomplete_count`, `state_exists`, `roadmap_exists`.
|
||||
|
||||
<step name="load_project_state">
|
||||
**If `phase_found` is false:** Error — phase directory not found.
|
||||
**If `plan_count` is 0:** Error — no plans found in phase.
|
||||
**If `state_exists` is false but `.planning/` exists:** Offer reconstruct or continue.
|
||||
|
||||
```bash
|
||||
cat .planning/STATE.md 2>/dev/null
|
||||
```
|
||||
|
||||
**If exists:** Parse current position, accumulated decisions, blockers.
|
||||
**If missing but .planning/ exists:** Offer reconstruct from artifacts or continue without state.
|
||||
**If .planning/ missing:** Error — project not initialized.
|
||||
|
||||
**Load configs:**
|
||||
|
||||
```bash
|
||||
GSD_CONFIG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw)
|
||||
COMMIT_PLANNING_DOCS=$(echo "$GSD_CONFIG" | grep '^commit_docs=' | cut -d= -f2)
|
||||
PARALLELIZATION=$(echo "$GSD_CONFIG" | grep '^parallelization=' | cut -d= -f2)
|
||||
BRANCHING_STRATEGY=$(echo "$GSD_CONFIG" | grep '^branching_strategy=' | cut -d= -f2)
|
||||
PHASE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^phase_branch_template=' | cut -d= -f2)
|
||||
MILESTONE_BRANCH_TEMPLATE=$(echo "$GSD_CONFIG" | grep '^milestone_branch_template=' | cut -d= -f2)
|
||||
```
|
||||
|
||||
When `PARALLELIZATION=false`, plans within a wave execute sequentially.
|
||||
When `parallelization` is false, plans within a wave execute sequentially.
|
||||
</step>
|
||||
|
||||
<step name="handle_branching">
|
||||
Create or switch to branch based on `BRANCHING_STRATEGY`.
|
||||
Check `branching_strategy` from init:
|
||||
|
||||
**"none":** Skip, continue on current branch.
|
||||
|
||||
**"phase":**
|
||||
**"phase" or "milestone":** Use pre-computed `branch_name` from init:
|
||||
```bash
|
||||
PHASE_NAME=$(basename "$PHASE_DIR" | sed 's/^[0-9]*-//')
|
||||
PHASE_SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$PHASE_NAME" --raw)
|
||||
BRANCH_NAME=$(echo "$PHASE_BRANCH_TEMPLATE" | sed "s/{phase}/$PADDED_PHASE/g" | sed "s/{slug}/$PHASE_SLUG/g")
|
||||
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
|
||||
```
|
||||
|
||||
**"milestone":**
|
||||
```bash
|
||||
MILESTONE_VERSION=$(grep -oE 'v[0-9]+\.[0-9]+' .planning/ROADMAP.md | head -1 || echo "v1.0")
|
||||
MILESTONE_NAME=$(grep -A1 "## .*$MILESTONE_VERSION" .planning/ROADMAP.md | tail -1 | sed 's/.*- //' | cut -d'(' -f1 | tr -d ' ' || echo "milestone")
|
||||
MILESTONE_SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$MILESTONE_NAME" --raw)
|
||||
BRANCH_NAME=$(echo "$MILESTONE_BRANCH_TEMPLATE" | sed "s/{milestone}/$MILESTONE_VERSION/g" | sed "s/{slug}/$MILESTONE_SLUG/g")
|
||||
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
|
||||
```
|
||||
|
||||
@@ -71,23 +42,9 @@ All subsequent commits go to this branch. User handles merging.
|
||||
</step>
|
||||
|
||||
<step name="validate_phase">
|
||||
From init JSON: `phase_dir`, `plan_count`, `incomplete_count`.
|
||||
|
||||
```bash
|
||||
PHASE_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE_ARG}")
|
||||
PHASE_DIR=$(echo "$PHASE_INFO" | grep -o '"directory":"[^"]*"' | cut -d'"' -f4)
|
||||
if [ -z "$PHASE_DIR" ]; then
|
||||
echo "ERROR: No phase directory matching '${PHASE_ARG}'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PLAN_COUNT=$(ls -1 "$PHASE_DIR"/*-PLAN.md 2>/dev/null | wc -l | tr -d ' ')
|
||||
if [ "$PLAN_COUNT" -eq 0 ]; then
|
||||
echo "ERROR: No plans found in $PHASE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
Report: "Found {N} plans in {phase_dir}"
|
||||
Report: "Found {plan_count} plans in {phase_dir} ({incomplete_count} incomplete)"
|
||||
</step>
|
||||
|
||||
<step name="discover_plans">
|
||||
|
||||
@@ -11,22 +11,21 @@ Read config.json for planning behavior settings.
|
||||
|
||||
<process>
|
||||
|
||||
<step name="resolve_model_profile" priority="first">
|
||||
```bash
|
||||
EXECUTOR_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-executor --raw)
|
||||
```
|
||||
</step>
|
||||
<step name="init_context" priority="first">
|
||||
Load execution context (uses `init execute-phase` for full context):
|
||||
|
||||
<step name="load_project_state">
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init execute-phase "${PHASE}")
|
||||
```
|
||||
|
||||
Extract from init JSON: `executor_model`, `commit_docs`, `phase_dir`, `phase_number`, `plans`, `summaries`, `incomplete_plans`.
|
||||
|
||||
Also read STATE.md for current position, decisions, blockers:
|
||||
```bash
|
||||
cat .planning/STATE.md 2>/dev/null
|
||||
```
|
||||
|
||||
Parse current position, decisions, blockers, alignment. If missing but .planning/ exists: offer reconstruct or continue. If .planning/ missing: error.
|
||||
|
||||
```bash
|
||||
COMMIT_PLANNING_DOCS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^commit_docs=' | cut -d= -f2)
|
||||
```
|
||||
If `.planning/` missing: error.
|
||||
</step>
|
||||
|
||||
<step name="identify_plan">
|
||||
|
||||
@@ -44,19 +44,19 @@ fi
|
||||
|
||||
</step>
|
||||
|
||||
<step name="load_roadmap">
|
||||
Load the roadmap file:
|
||||
<step name="init_context">
|
||||
Load phase operation context:
|
||||
|
||||
```bash
|
||||
ROADMAP_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw)
|
||||
if [ "$ROADMAP_EXISTS" = "true" ]; then
|
||||
ROADMAP=".planning/ROADMAP.md"
|
||||
else
|
||||
echo "ERROR: No roadmap found (.planning/ROADMAP.md)"
|
||||
exit 1
|
||||
fi
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${after_phase}")
|
||||
```
|
||||
|
||||
Check `roadmap_exists` from init JSON. If false:
|
||||
```
|
||||
ERROR: No roadmap found (.planning/ROADMAP.md)
|
||||
```
|
||||
Exit.
|
||||
|
||||
Read roadmap content for parsing.
|
||||
</step>
|
||||
|
||||
@@ -94,8 +94,9 @@ Store as: `decimal_phase="$(printf "%02d" $after_phase).${next_decimal}"`
|
||||
</step>
|
||||
|
||||
<step name="generate_slug">
|
||||
Convert the phase description to a kebab-case slug:
|
||||
Convert the phase description to a kebab-case slug.
|
||||
|
||||
Use `generate-slug` command (init phase-op provides `phase_slug` for existing phase, but this is a new phase):
|
||||
```bash
|
||||
slug=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$description" --raw)
|
||||
```
|
||||
|
||||
@@ -22,18 +22,22 @@ Documents are reference material for Claude when planning/executing. Always incl
|
||||
|
||||
<process>
|
||||
|
||||
<step name="resolve_model_profile" priority="first">
|
||||
<step name="init_context" priority="first">
|
||||
Load codebase mapping context:
|
||||
|
||||
```bash
|
||||
MAPPER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-codebase-mapper --raw)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init map-codebase)
|
||||
```
|
||||
|
||||
Extract from init JSON: `mapper_model`, `commit_docs`, `codebase_dir`, `existing_maps`, `has_maps`, `codebase_dir_exists`.
|
||||
</step>
|
||||
|
||||
<step name="check_existing">
|
||||
Check if .planning/codebase/ already exists:
|
||||
Check if .planning/codebase/ already exists using `has_maps` from init context.
|
||||
|
||||
If `codebase_dir_exists` is true:
|
||||
```bash
|
||||
CODEBASE_MAP_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/codebase --raw)
|
||||
[ "$CODEBASE_MAP_EXISTS" = "true" ] && ls -la .planning/codebase/
|
||||
ls -la .planning/codebase/
|
||||
```
|
||||
|
||||
**If exists:**
|
||||
|
||||
@@ -74,14 +74,14 @@ Delete MILESTONE-CONTEXT.md if exists (consumed).
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js commit "docs: start milestone v[X.Y] [Name]" --files .planning/PROJECT.md .planning/STATE.md
|
||||
```
|
||||
|
||||
## 7. Resolve Model Profile
|
||||
## 7. Load Context and Resolve Models
|
||||
|
||||
```bash
|
||||
RESEARCHER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-project-researcher --raw)
|
||||
SYNTHESIZER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-research-synthesizer --raw)
|
||||
ROADMAPPER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-roadmapper --raw)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init new-milestone)
|
||||
```
|
||||
|
||||
Extract from init JSON: `researcher_model`, `synthesizer_model`, `roadmapper_model`, `commit_docs`, `research_enabled`, `current_milestone`, `project_exists`, `roadmap_exists`.
|
||||
|
||||
## 8. Research Decision
|
||||
|
||||
AskUserQuestion: "Research the domain ecosystem for new features before defining requirements?"
|
||||
|
||||
@@ -12,39 +12,22 @@ Read all files referenced by the invoking prompt's execution_context before star
|
||||
|
||||
**MANDATORY FIRST STEP — Execute these checks before ANY user interaction:**
|
||||
|
||||
1. **Abort if project exists:**
|
||||
```bash
|
||||
PROJECT_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/PROJECT.md --raw)
|
||||
[ "$PROJECT_EXISTS" = "true" ] && echo "ERROR: Project already initialized. Use /gsd:progress" && exit 1
|
||||
```
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init new-project)
|
||||
```
|
||||
|
||||
2. **Initialize git repo in THIS directory** (required even if inside a parent repo):
|
||||
```bash
|
||||
if [ -d .git ] || [ -f .git ]; then
|
||||
echo "Git repo exists in current directory"
|
||||
else
|
||||
git init
|
||||
echo "Initialized new git repo"
|
||||
fi
|
||||
```
|
||||
Parse JSON for: `researcher_model`, `synthesizer_model`, `roadmapper_model`, `commit_docs`, `project_exists`, `has_codebase_map`, `planning_exists`, `has_existing_code`, `has_package_file`, `is_brownfield`, `needs_codebase_map`, `has_git`.
|
||||
|
||||
3. **Detect existing code (brownfield detection):**
|
||||
```bash
|
||||
CODE_FILES=$(find . -name "*.ts" -o -name "*.js" -o -name "*.py" -o -name "*.go" -o -name "*.rs" -o -name "*.swift" -o -name "*.java" 2>/dev/null | grep -v node_modules | grep -v .git | head -20)
|
||||
HAS_PACKAGE=$([ -f package.json ] || [ -f requirements.txt ] || [ -f Cargo.toml ] || [ -f go.mod ] || [ -f Package.swift ] && echo "yes")
|
||||
HAS_CODEBASE_MAP=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/codebase --raw)
|
||||
[ "$HAS_CODEBASE_MAP" = "true" ] && HAS_CODEBASE_MAP="yes"
|
||||
```
|
||||
**If `project_exists` is true:** Error — project already initialized. Use `/gsd:progress`.
|
||||
|
||||
**You MUST run all bash commands above using the Bash tool before proceeding.**
|
||||
**If `has_git` is false:** Initialize git:
|
||||
```bash
|
||||
git init
|
||||
```
|
||||
|
||||
## 2. Brownfield Offer
|
||||
|
||||
**If existing code detected and .planning/codebase/ doesn't exist:**
|
||||
|
||||
Check the results from setup step:
|
||||
- If `CODE_FILES` is non-empty OR `HAS_PACKAGE` is "yes"
|
||||
- AND `HAS_CODEBASE_MAP` is NOT "yes"
|
||||
**If `needs_codebase_map` is true** (from init — existing code detected but no codebase map):
|
||||
|
||||
Use AskUserQuestion:
|
||||
- header: "Existing Code"
|
||||
@@ -59,9 +42,7 @@ Run `/gsd:map-codebase` first, then return to `/gsd:new-project`
|
||||
```
|
||||
Exit command.
|
||||
|
||||
**If "Skip mapping":** Continue to Step 3.
|
||||
|
||||
**If no existing code detected OR codebase already mapped:** Continue to Step 3.
|
||||
**If "Skip mapping" OR `needs_codebase_map` is false:** Continue to Step 3.
|
||||
|
||||
## 3. Deep Questioning
|
||||
|
||||
@@ -335,13 +316,7 @@ node ~/.claude/get-shit-done/bin/gsd-tools.js commit "chore: add project config"
|
||||
|
||||
## 5.5. Resolve Model Profile
|
||||
|
||||
Read model profile for agent spawning:
|
||||
|
||||
```bash
|
||||
RESEARCHER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-project-researcher --raw)
|
||||
SYNTHESIZER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-research-synthesizer --raw)
|
||||
ROADMAPPER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-roadmapper --raw)
|
||||
```
|
||||
Use models from init: `researcher_model`, `synthesizer_model`, `roadmapper_model`.
|
||||
|
||||
## 6. Research Decision
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ Start with: [specific first action when resuming]
|
||||
|
||||
Be specific enough for a fresh Claude to understand immediately.
|
||||
|
||||
Use `current-timestamp` for last_updated field:
|
||||
Use `current-timestamp` for last_updated field. You can use init todos (which provides timestamps) or call directly:
|
||||
```bash
|
||||
timestamp=$(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp full --raw)
|
||||
```
|
||||
|
||||
@@ -10,22 +10,17 @@ Read all files referenced by the invoking prompt's execution_context before star
|
||||
|
||||
<process>
|
||||
|
||||
## 1. Validate Environment and Resolve Model Profile
|
||||
## 1. Initialize
|
||||
|
||||
Load all context in one call:
|
||||
|
||||
```bash
|
||||
PLANNING_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning --raw)
|
||||
echo "$PLANNING_EXISTS"
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init plan-phase "$PHASE")
|
||||
```
|
||||
|
||||
**If not found:** Error — run `/gsd:new-project` first.
|
||||
Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_enabled`, `plan_checker_enabled`, `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `plan_count`, `planning_exists`, `roadmap_exists`.
|
||||
|
||||
**Resolve models:**
|
||||
|
||||
```bash
|
||||
RESEARCHER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-phase-researcher --raw)
|
||||
PLANNER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-planner --raw)
|
||||
CHECKER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-plan-checker --raw)
|
||||
```
|
||||
**If `planning_exists` is false:** Error — run `/gsd:new-project` first.
|
||||
|
||||
## 2. Parse and Normalize Arguments
|
||||
|
||||
@@ -33,28 +28,12 @@ Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`-
|
||||
|
||||
**If no phase number:** Detect next unplanned phase from roadmap.
|
||||
|
||||
**Find phase directory:**
|
||||
|
||||
**If `phase_found` is false:** Validate phase exists in ROADMAP.md. If valid, create the directory using `phase_slug` and `padded_phase` from init:
|
||||
```bash
|
||||
PHASE_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE")
|
||||
PHASE_DIR=$(echo "$PHASE_INFO" | grep -o '"directory":"[^"]*"' | cut -d'"' -f4)
|
||||
mkdir -p ".planning/phases/${padded_phase}-${phase_slug}"
|
||||
```
|
||||
|
||||
If `found` is false, validate phase exists in ROADMAP.md. If valid, create the directory:
|
||||
```bash
|
||||
PHASE_NAME=$(grep "Phase ${PHASE}:" .planning/ROADMAP.md | sed 's/.*Phase [0-9]*: //')
|
||||
PHASE_SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$PHASE_NAME" --raw)
|
||||
PADDED=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "$PHASE" --raw | grep -o '^[0-9]*' || printf "%02d" "$PHASE")
|
||||
mkdir -p ".planning/phases/${PADDED}-${PHASE_SLUG}"
|
||||
PHASE_DIR=".planning/phases/${PADDED}-${PHASE_SLUG}"
|
||||
```
|
||||
|
||||
**Check for existing research and plans:**
|
||||
|
||||
```bash
|
||||
ls ${PHASE_DIR}/*-RESEARCH.md 2>/dev/null
|
||||
ls ${PHASE_DIR}/*-PLAN.md 2>/dev/null
|
||||
```
|
||||
**Existing artifacts from init:** `has_research`, `has_plans`, `plan_count`.
|
||||
|
||||
## 3. Validate Phase
|
||||
|
||||
@@ -76,13 +55,9 @@ If CONTEXT.md exists, display: `Using phase context from: ${PHASE_DIR}/*-CONTEXT
|
||||
|
||||
## 5. Handle Research
|
||||
|
||||
**Skip if:** `--gaps` flag, `--skip-research` flag, or config `workflow.research=false` (without `--research` override).
|
||||
**Skip if:** `--gaps` flag, `--skip-research` flag, or `research_enabled` is false (from init) without `--research` override.
|
||||
|
||||
```bash
|
||||
WORKFLOW_RESEARCH=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^research=' | cut -d= -f2)
|
||||
```
|
||||
|
||||
**If RESEARCH.md exists AND no `--research` flag:** Use existing, skip to step 6.
|
||||
**If `has_research` is true (from init) AND no `--research` flag:** Use existing, skip to step 6.
|
||||
|
||||
**If RESEARCH.md missing OR `--research` flag:**
|
||||
|
||||
@@ -229,10 +204,7 @@ Task(
|
||||
|
||||
## 9. Handle Planner Return
|
||||
|
||||
- **`## PLANNING COMPLETE`:** Display plan count. If `--skip-verify` or config `workflow.plan_check=false`: skip to step 13. Otherwise: step 10.
|
||||
```bash
|
||||
WORKFLOW_PLAN_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load --raw | grep '^plan_checker=' | cut -d= -f2)
|
||||
```
|
||||
- **`## PLANNING COMPLETE`:** Display plan count. If `--skip-verify` or `plan_checker_enabled` is false (from init): skip to step 13. Otherwise: step 10.
|
||||
- **`## CHECKPOINT REACHED`:** Present to user, get response, spawn continuation (step 12)
|
||||
- **`## PLANNING INCONCLUSIVE`:** Show attempts, offer: Add context / Retry / Manual
|
||||
|
||||
|
||||
@@ -8,16 +8,16 @@ Read all files referenced by the invoking prompt's execution_context before star
|
||||
|
||||
<process>
|
||||
|
||||
<step name="verify">
|
||||
**Verify planning structure exists:**
|
||||
|
||||
Use Bash (not Glob) to check—Glob respects .gitignore but .planning/ is often gitignored:
|
||||
<step name="init_context">
|
||||
**Load progress context:**
|
||||
|
||||
```bash
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning --raw
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init progress)
|
||||
```
|
||||
|
||||
If no `.planning/` directory:
|
||||
Extract from init JSON: `project_exists`, `roadmap_exists`, `state_exists`, `phases`, `current_phase`, `next_phase`, `milestone_version`, `completed_count`, `phase_count`, `paused_at`.
|
||||
|
||||
If `project_exists` is false (no `.planning/` directory):
|
||||
|
||||
```
|
||||
No planning structure found.
|
||||
@@ -54,13 +54,13 @@ If missing both ROADMAP.md and PROJECT.md: suggest `/gsd:new-project`.
|
||||
</step>
|
||||
|
||||
<step name="position">
|
||||
**Parse current position:**
|
||||
**Parse current position from init context:**
|
||||
|
||||
- From STATE.md: current phase, plan number, status
|
||||
- Calculate: total plans, completed plans, remaining plans
|
||||
- Note any blockers or concerns
|
||||
- Use `current_phase` and `next_phase` from init for position
|
||||
- Use `phases` array for plan counts per phase
|
||||
- Note `paused_at` if work was paused
|
||||
- Check for CONTEXT.md: For phases without PLAN.md files, check if `{phase}-CONTEXT.md` exists in phase directory
|
||||
- Count pending todos: `node ~/.claude/get-shit-done/bin/gsd-tools.js list-todos --raw`
|
||||
- Count pending todos: use `init todos` or `list-todos`
|
||||
- Check for active debug sessions: `ls .planning/debug/*.md 2>/dev/null | grep -v resolved | wc -l`
|
||||
</step>
|
||||
|
||||
|
||||
@@ -7,35 +7,7 @@ Read all files referenced by the invoking prompt's execution_context before star
|
||||
</required_reading>
|
||||
|
||||
<process>
|
||||
**Step 0: Resolve Model Profile**
|
||||
|
||||
```bash
|
||||
PLANNER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-planner --raw)
|
||||
EXECUTOR_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-executor --raw)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Step 1: Pre-flight validation**
|
||||
|
||||
Check that an active GSD project exists:
|
||||
|
||||
```bash
|
||||
ROADMAP_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw)
|
||||
if [ "$ROADMAP_EXISTS" != "true" ]; then
|
||||
echo "Quick mode requires an active project with ROADMAP.md."
|
||||
echo "Run /gsd:new-project first."
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
If validation fails, stop immediately with the error message.
|
||||
|
||||
Quick tasks can run mid-phase - validation only checks ROADMAP.md exists, not phase status.
|
||||
|
||||
---
|
||||
|
||||
**Step 2: Get task description**
|
||||
**Step 1: Get task description**
|
||||
|
||||
Prompt user interactively for the task description:
|
||||
|
||||
@@ -51,29 +23,26 @@ Store response as `$DESCRIPTION`.
|
||||
|
||||
If empty, re-prompt: "Please provide a task description."
|
||||
|
||||
Generate slug from description:
|
||||
---
|
||||
|
||||
**Step 2: Initialize**
|
||||
|
||||
```bash
|
||||
slug=$(node ~/.claude/get-shit-done/bin/gsd-tools.js generate-slug "$DESCRIPTION" --raw | cut -c1-40)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init quick "$DESCRIPTION")
|
||||
```
|
||||
|
||||
Parse JSON for: `planner_model`, `executor_model`, `commit_docs`, `next_num`, `slug`, `date`, `timestamp`, `quick_dir`, `task_dir`, `roadmap_exists`, `planning_exists`.
|
||||
|
||||
**If `roadmap_exists` is false:** Error — Quick mode requires an active project with ROADMAP.md. Run `/gsd:new-project` first.
|
||||
|
||||
Quick tasks can run mid-phase - validation only checks ROADMAP.md exists, not phase status.
|
||||
|
||||
---
|
||||
|
||||
**Step 3: Calculate next quick task number**
|
||||
|
||||
Ensure `.planning/quick/` directory exists and find the next sequential number:
|
||||
**Step 3: Create task directory**
|
||||
|
||||
```bash
|
||||
# Ensure .planning/quick/ exists
|
||||
mkdir -p .planning/quick
|
||||
|
||||
# Find highest existing number and increment
|
||||
last=$(ls -1d .planning/quick/[0-9][0-9][0-9]-* 2>/dev/null | sort -r | head -1 | xargs -I{} basename {} | grep -oE '^[0-9]+')
|
||||
|
||||
if [ -z "$last" ]; then
|
||||
next_num="001"
|
||||
else
|
||||
next_num=$(printf "%03d" $((10#$last + 1)))
|
||||
fi
|
||||
mkdir -p "${task_dir}"
|
||||
```
|
||||
|
||||
---
|
||||
@@ -199,15 +168,16 @@ Insert after `### Blockers/Concerns` section:
|
||||
|
||||
**7c. Append new row to table:**
|
||||
|
||||
Use `date` from init:
|
||||
```markdown
|
||||
| ${next_num} | ${DESCRIPTION} | $(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp date --raw) | ${commit_hash} | [${next_num}-${slug}](./quick/${next_num}-${slug}/) |
|
||||
| ${next_num} | ${DESCRIPTION} | ${date} | ${commit_hash} | [${next_num}-${slug}](./quick/${next_num}-${slug}/) |
|
||||
```
|
||||
|
||||
**7d. Update "Last activity" line:**
|
||||
|
||||
Find and update the line:
|
||||
Use `date` from init:
|
||||
```
|
||||
Last activity: $(node ~/.claude/get-shit-done/bin/gsd-tools.js current-timestamp date --raw) - Completed quick task ${next_num}: ${DESCRIPTION}
|
||||
Last activity: ${date} - Completed quick task ${next_num}: ${DESCRIPTION}
|
||||
```
|
||||
|
||||
Use Edit tool to make these changes atomically
|
||||
|
||||
@@ -25,15 +25,16 @@ Example: /gsd:remove-phase 17
|
||||
Exit.
|
||||
</step>
|
||||
|
||||
<step name="load_state">
|
||||
Load project state:
|
||||
<step name="init_context">
|
||||
Load phase operation context:
|
||||
|
||||
```bash
|
||||
cat .planning/STATE.md 2>/dev/null
|
||||
cat .planning/ROADMAP.md 2>/dev/null
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${target}")
|
||||
```
|
||||
|
||||
Parse current phase number from STATE.md "Current Position" section.
|
||||
Extract: `phase_found`, `phase_dir`, `phase_number`, `commit_docs`, `roadmap_exists`.
|
||||
|
||||
Also read STATE.md and ROADMAP.md content for parsing current position.
|
||||
</step>
|
||||
|
||||
<step name="validate_phase_exists">
|
||||
@@ -132,17 +133,19 @@ Wait for confirmation.
|
||||
</step>
|
||||
|
||||
<step name="delete_phase_directory">
|
||||
Use the init context from earlier. The `phase_dir` from `init phase-op` provides the path.
|
||||
|
||||
Delete the target phase directory if it exists:
|
||||
|
||||
```bash
|
||||
TARGET_PHASE_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists ".planning/phases/{target}-{slug}" --raw)
|
||||
if [ "$TARGET_PHASE_EXISTS" = "true" ]; then
|
||||
rm -rf ".planning/phases/{target}-{slug}"
|
||||
echo "Deleted: .planning/phases/{target}-{slug}/"
|
||||
# phase_dir from init phase-op contains the path if found
|
||||
if [ -n "$phase_dir" ]; then
|
||||
rm -rf "$phase_dir"
|
||||
echo "Deleted: $phase_dir/"
|
||||
fi
|
||||
```
|
||||
|
||||
If directory doesn't exist, note: "No directory to delete (phase not yet created)"
|
||||
If directory doesn't exist (`phase_found=false` from init), note: "No directory to delete (phase not yet created)"
|
||||
</step>
|
||||
|
||||
<step name="renumber_directories">
|
||||
|
||||
@@ -16,21 +16,18 @@ Instantly restore full project context so "Where were we?" has an immediate, com
|
||||
|
||||
<process>
|
||||
|
||||
<step name="detect_existing_project">
|
||||
Check if this is an existing project:
|
||||
<step name="initialize">
|
||||
Load all context in one call:
|
||||
|
||||
```bash
|
||||
STATE_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/STATE.md --raw)
|
||||
ROADMAP_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/ROADMAP.md --raw)
|
||||
PROJECT_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/PROJECT.md --raw)
|
||||
[ "$STATE_EXISTS" = "true" ] && echo "Project exists"
|
||||
[ "$ROADMAP_EXISTS" = "true" ] && echo "Roadmap exists"
|
||||
[ "$PROJECT_EXISTS" = "true" ] && echo "Project file exists"
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init resume)
|
||||
```
|
||||
|
||||
**If STATE.md exists:** Proceed to load_state
|
||||
**If only ROADMAP.md/PROJECT.md exist:** Offer to reconstruct STATE.md
|
||||
**If .planning/ doesn't exist:** This is a new project - route to /gsd:new-project
|
||||
Parse JSON for: `state_exists`, `roadmap_exists`, `project_exists`, `planning_exists`, `has_interrupted_agent`, `interrupted_agent_id`, `commit_docs`.
|
||||
|
||||
**If `state_exists` is true:** Proceed to load_state
|
||||
**If `state_exists` is false but `roadmap_exists` or `project_exists` is true:** Offer to reconstruct STATE.md
|
||||
**If `planning_exists` is false:** This is a new project - route to /gsd:new-project
|
||||
</step>
|
||||
|
||||
<step name="load_state">
|
||||
@@ -74,11 +71,9 @@ for plan in .planning/phases/*/*-PLAN.md; do
|
||||
[ ! -f "$summary" ] && echo "Incomplete: $plan"
|
||||
done 2>/dev/null
|
||||
|
||||
# Check for interrupted agents
|
||||
AGENT_FILE_EXISTS=$(node ~/.claude/get-shit-done/bin/gsd-tools.js verify-path-exists .planning/current-agent-id.txt --raw)
|
||||
if [ "$AGENT_FILE_EXISTS" = "true" ] && [ -s .planning/current-agent-id.txt ]; then
|
||||
AGENT_ID=$(cat .planning/current-agent-id.txt | tr -d '\n')
|
||||
echo "Interrupted agent: $AGENT_ID"
|
||||
# Check for interrupted agents (use has_interrupted_agent and interrupted_agent_id from init)
|
||||
if [ "$has_interrupted_agent" = "true" ]; then
|
||||
echo "Interrupted agent: $interrupted_agent_id"
|
||||
fi
|
||||
```
|
||||
|
||||
|
||||
@@ -19,19 +19,19 @@ if $ARGUMENTS.profile not in ["quality", "balanced", "budget"]:
|
||||
```
|
||||
</step>
|
||||
|
||||
<step name="ensure_config">
|
||||
<step name="ensure_and_load_config">
|
||||
Ensure config exists and load current state:
|
||||
|
||||
```bash
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js config-ensure-section
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
|
||||
```
|
||||
|
||||
Creates `.planning/config.json` with defaults if missing.
|
||||
This creates `.planning/config.json` with defaults if missing and loads current config.
|
||||
</step>
|
||||
|
||||
<step name="update_config">
|
||||
Read current config:
|
||||
```bash
|
||||
cat .planning/config.json
|
||||
```
|
||||
Read current config from state load or directly:
|
||||
|
||||
Update `model_profile` field:
|
||||
```json
|
||||
|
||||
@@ -8,12 +8,15 @@ Read all files referenced by the invoking prompt's execution_context before star
|
||||
|
||||
<process>
|
||||
|
||||
<step name="ensure_config">
|
||||
<step name="ensure_and_load_config">
|
||||
Ensure config exists and load current state:
|
||||
|
||||
```bash
|
||||
node ~/.claude/get-shit-done/bin/gsd-tools.js config-ensure-section
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js state load)
|
||||
```
|
||||
|
||||
Creates `.planning/config.json` with defaults if missing.
|
||||
Creates `.planning/config.json` with defaults if missing and loads current config values.
|
||||
</step>
|
||||
|
||||
<step name="read_current">
|
||||
|
||||
@@ -25,12 +25,19 @@ Then verify each level against the actual codebase.
|
||||
<process>
|
||||
|
||||
<step name="load_context" priority="first">
|
||||
```bash
|
||||
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE_ARG}" --raw)
|
||||
Load phase operation context:
|
||||
|
||||
grep -A 5 "Phase ${PHASE_NUM}" .planning/ROADMAP.md
|
||||
grep -E "^| ${PHASE_NUM}" .planning/REQUIREMENTS.md 2>/dev/null
|
||||
ls "$PHASE_DIR"/*-SUMMARY.md "$PHASE_DIR"/*-PLAN.md 2>/dev/null
|
||||
```bash
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init phase-op "${PHASE_ARG}")
|
||||
```
|
||||
|
||||
Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`, `has_plans`, `plan_count`.
|
||||
|
||||
Then load phase details and list plans/summaries:
|
||||
```bash
|
||||
grep -A 5 "Phase ${phase_number}" .planning/ROADMAP.md
|
||||
grep -E "^| ${phase_number}" .planning/REQUIREMENTS.md 2>/dev/null
|
||||
ls "$phase_dir"/*-SUMMARY.md "$phase_dir"/*-PLAN.md 2>/dev/null
|
||||
```
|
||||
|
||||
Extract **phase goal** from ROADMAP.md (the outcome to verify, not tasks) and **requirements** from REQUIREMENTS.md if it exists.
|
||||
|
||||
@@ -20,11 +20,14 @@ No Pass/Fail buttons. No severity questions. Just: "Here's what should happen. D
|
||||
|
||||
<process>
|
||||
|
||||
<step name="resolve_model_profile" priority="first">
|
||||
<step name="initialize" priority="first">
|
||||
If $ARGUMENTS contains a phase number, load context:
|
||||
|
||||
```bash
|
||||
PLANNER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-planner --raw)
|
||||
CHECKER_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-plan-checker --raw)
|
||||
INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.js init verify-work "${PHASE_ARG}")
|
||||
```
|
||||
|
||||
Parse JSON for: `planner_model`, `checker_model`, `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `has_verification`.
|
||||
</step>
|
||||
|
||||
<step name="check_active_session">
|
||||
@@ -77,13 +80,10 @@ Continue to `create_uat_file`.
|
||||
<step name="find_summaries">
|
||||
**Find what to test:**
|
||||
|
||||
Parse $ARGUMENTS as phase number (e.g., "4") or plan number (e.g., "04-02").
|
||||
Use `phase_dir` from init (or run init if not already done).
|
||||
|
||||
```bash
|
||||
PHASE_DIR=$(node ~/.claude/get-shit-done/bin/gsd-tools.js find-phase "${PHASE_ARG}" --raw)
|
||||
|
||||
# Find SUMMARY files
|
||||
ls "$PHASE_DIR"/*-SUMMARY.md 2>/dev/null
|
||||
ls "$phase_dir"/*-SUMMARY.md 2>/dev/null
|
||||
```
|
||||
|
||||
Read each SUMMARY.md to extract testable deliverables.
|
||||
|
||||
Reference in New Issue
Block a user