diff --git a/agents/gsd-debugger.md b/agents/gsd-debugger.md index b68313171..66c485c89 100644 --- a/agents/gsd-debugger.md +++ b/agents/gsd-debugger.md @@ -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:** diff --git a/agents/gsd-executor.md b/agents/gsd-executor.md index 20191c8a4..0473d4416 100644 --- a/agents/gsd-executor.md +++ b/agents/gsd-executor.md @@ -16,22 +16,21 @@ Your job: Execute the plan completely, commit each task, create SUMMARY.md, upda -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) -``` diff --git a/agents/gsd-phase-researcher.md b/agents/gsd-phase-researcher.md index 05a8d5988..91f33d438 100644 --- a/agents/gsd-phase-researcher.md +++ b/agents/gsd-phase-researcher.md @@ -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: diff --git a/agents/gsd-plan-checker.md b/agents/gsd-plan-checker.md index 5ab950662..ece6215ef 100644 --- a/agents/gsd-plan-checker.md +++ b/agents/gsd-plan-checker.md @@ -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. diff --git a/agents/gsd-planner.md b/agents/gsd-planner.md index 5175601fa..bafcbe27d 100644 --- a/agents/gsd-planner.md +++ b/agents/gsd-planner.md @@ -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 -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. @@ -905,17 +910,17 @@ done -```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. diff --git a/commands/gsd/debug.md b/commands/gsd/debug.md index 0e13eb59c..23dfa11e9 100644 --- a/commands/gsd/debug.md +++ b/commands/gsd/debug.md @@ -28,8 +28,13 @@ ls .planning/debug/*.md 2>/dev/null | grep -v resolved | head -5 -## 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) ``` diff --git a/commands/gsd/research-phase.md b/commands/gsd/research-phase.md index d6693309d..bb2428272 100644 --- a/commands/gsd/research-phase.md +++ b/commands/gsd/research-phase.md @@ -31,23 +31,26 @@ Normalize phase input in step 1 before any directory lookups. -## 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 diff --git a/get-shit-done/bin/gsd-tools.js b/get-shit-done/bin/gsd-tools.js index 74e977f47..c7cb1d2ba 100755 --- a/get-shit-done/bin/gsd-tools.js +++ b/get-shit-done/bin/gsd-tools.js @@ -8,13 +8,27 @@ * * Usage: node gsd-tools.js [args] [--raw] * - * Commands: + * Atomic Commands: * state load Load project config + state * state update Update a STATE.md field * resolve-model Get model for agent based on profile * find-phase Find phase directory by number * commit [--files f1 f2] Commit planning docs * verify-summary Verify a SUMMARY.md file + * + * Compound Commands (workflow-specific initialization): + * init execute-phase All context for execute-phase workflow + * init plan-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 All context for quick workflow + * init resume All context for resume-project workflow + * init verify-work All context for verify-work workflow + * init phase-op 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 [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 [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}`); } diff --git a/get-shit-done/references/planning-config.md b/get-shit-done/references/planning-config.md index 3ce271982..a91495278 100644 --- a/get-shit-done/references/planning-config.md +++ b/get-shit-done/references/planning-config.md @@ -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:** diff --git a/get-shit-done/workflows/add-phase.md b/get-shit-done/workflows/add-phase.md index e5f404111..39596ccc4 100644 --- a/get-shit-done/workflows/add-phase.md +++ b/get-shit-done/workflows/add-phase.md @@ -25,14 +25,14 @@ Example: /gsd:add-phase Add authentication system Exit. - -Load the roadmap file: + +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` -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) ``` diff --git a/get-shit-done/workflows/add-todo.md b/get-shit-done/workflows/add-todo.md index d0c4b8c20..39c3737fd 100644 --- a/get-shit-done/workflows/add-todo.md +++ b/get-shit-done/workflows/add-todo.md @@ -8,18 +8,21 @@ Read all files referenced by the invoking prompt's execution_context before star - + +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 ``` - - -```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. @@ -76,13 +79,14 @@ If overlapping, use AskUserQuestion: +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: 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" diff --git a/get-shit-done/workflows/audit-milestone.md b/get-shit-done/workflows/audit-milestone.md index 353df1216..3701868d5 100644 --- a/get-shit-done/workflows/audit-milestone.md +++ b/get-shit-done/workflows/audit-milestone.md @@ -8,8 +8,15 @@ Read all files referenced by the invoking prompt's execution_context before star -## 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) ``` diff --git a/get-shit-done/workflows/check-todos.md b/get-shit-done/workflows/check-todos.md index 13c280e78..e16d1bed5 100644 --- a/get-shit-done/workflows/check-todos.md +++ b/get-shit-done/workflows/check-todos.md @@ -8,13 +8,16 @@ Read all files referenced by the invoking prompt's execution_context before star - + +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: -```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. -```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. 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. diff --git a/get-shit-done/workflows/complete-milestone.md b/get-shit-done/workflows/complete-milestone.md index d03c8dfa3..564667510 100644 --- a/get-shit-done/workflows/complete-milestone.md +++ b/get-shit-done/workflows/complete-milestone.md @@ -450,11 +450,11 @@ Archive requirements for next milestone. -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:** diff --git a/get-shit-done/workflows/discuss-phase.md b/get-shit-done/workflows/discuss-phase.md index 9481882f5..4f7fb0342 100644 --- a/get-shit-done/workflows/discuss-phase.md +++ b/get-shit-done/workflows/discuss-phase.md @@ -107,15 +107,16 @@ Phase: "API documentation" - + 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. -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 -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" diff --git a/get-shit-done/workflows/execute-phase.md b/get-shit-done/workflows/execute-phase.md index a97b35807..183d79eab 100644 --- a/get-shit-done/workflows/execute-phase.md +++ b/get-shit-done/workflows/execute-phase.md @@ -7,63 +7,34 @@ Orchestrator coordinates, not executes. Each subagent loads the full execute-pla -Read STATE.md and config.json before any operation. +Read STATE.md before any operation to load project context. - + +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}") ``` - +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`. - +**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. -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. +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)" diff --git a/get-shit-done/workflows/execute-plan.md b/get-shit-done/workflows/execute-plan.md index 992013fa0..9f8e051ae 100644 --- a/get-shit-done/workflows/execute-plan.md +++ b/get-shit-done/workflows/execute-plan.md @@ -11,22 +11,21 @@ Read config.json for planning behavior settings. - -```bash -EXECUTOR_MODEL=$(node ~/.claude/get-shit-done/bin/gsd-tools.js resolve-model gsd-executor --raw) -``` - + +Load execution context (uses `init execute-phase` for full 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`, `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. diff --git a/get-shit-done/workflows/insert-phase.md b/get-shit-done/workflows/insert-phase.md index 134250e7c..1e15ecf68 100644 --- a/get-shit-done/workflows/insert-phase.md +++ b/get-shit-done/workflows/insert-phase.md @@ -44,19 +44,19 @@ fi - -Load the roadmap file: + +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. @@ -94,8 +94,9 @@ Store as: `decimal_phase="$(printf "%02d" $after_phase).${next_decimal}"` -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) ``` diff --git a/get-shit-done/workflows/map-codebase.md b/get-shit-done/workflows/map-codebase.md index c6af63448..3de427249 100644 --- a/get-shit-done/workflows/map-codebase.md +++ b/get-shit-done/workflows/map-codebase.md @@ -22,18 +22,22 @@ Documents are reference material for Claude when planning/executing. Always incl - + +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`. -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:** diff --git a/get-shit-done/workflows/new-milestone.md b/get-shit-done/workflows/new-milestone.md index 9bc3887cf..432fe412b 100644 --- a/get-shit-done/workflows/new-milestone.md +++ b/get-shit-done/workflows/new-milestone.md @@ -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?" diff --git a/get-shit-done/workflows/new-project.md b/get-shit-done/workflows/new-project.md index 282c3c26a..2f11dd7b8 100644 --- a/get-shit-done/workflows/new-project.md +++ b/get-shit-done/workflows/new-project.md @@ -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 diff --git a/get-shit-done/workflows/pause-work.md b/get-shit-done/workflows/pause-work.md index 3431d34cc..e78280815 100644 --- a/get-shit-done/workflows/pause-work.md +++ b/get-shit-done/workflows/pause-work.md @@ -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) ``` diff --git a/get-shit-done/workflows/plan-phase.md b/get-shit-done/workflows/plan-phase.md index 62715f3b8..4fd8fa03f 100644 --- a/get-shit-done/workflows/plan-phase.md +++ b/get-shit-done/workflows/plan-phase.md @@ -10,22 +10,17 @@ Read all files referenced by the invoking prompt's execution_context before star -## 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 diff --git a/get-shit-done/workflows/progress.md b/get-shit-done/workflows/progress.md index 6ba759ed0..36ae01159 100644 --- a/get-shit-done/workflows/progress.md +++ b/get-shit-done/workflows/progress.md @@ -8,16 +8,16 @@ Read all files referenced by the invoking prompt's execution_context before star - -**Verify planning structure exists:** - -Use Bash (not Glob) to check—Glob respects .gitignore but .planning/ is often gitignored: + +**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`. -**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` diff --git a/get-shit-done/workflows/quick.md b/get-shit-done/workflows/quick.md index 808fe33b9..a93995058 100644 --- a/get-shit-done/workflows/quick.md +++ b/get-shit-done/workflows/quick.md @@ -7,35 +7,7 @@ Read all files referenced by the invoking prompt's execution_context before star -**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 diff --git a/get-shit-done/workflows/remove-phase.md b/get-shit-done/workflows/remove-phase.md index a4a1cea72..0cae3f0cd 100644 --- a/get-shit-done/workflows/remove-phase.md +++ b/get-shit-done/workflows/remove-phase.md @@ -25,15 +25,16 @@ Example: /gsd:remove-phase 17 Exit. - -Load project state: + +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. @@ -132,17 +133,19 @@ Wait for confirmation. +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)" diff --git a/get-shit-done/workflows/resume-project.md b/get-shit-done/workflows/resume-project.md index 18c584bcf..7d19e72fe 100644 --- a/get-shit-done/workflows/resume-project.md +++ b/get-shit-done/workflows/resume-project.md @@ -16,21 +16,18 @@ Instantly restore full project context so "Where were we?" has an immediate, com - -Check if this is an existing project: + +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 @@ -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 ``` diff --git a/get-shit-done/workflows/set-profile.md b/get-shit-done/workflows/set-profile.md index 83706fe4b..463044d23 100644 --- a/get-shit-done/workflows/set-profile.md +++ b/get-shit-done/workflows/set-profile.md @@ -19,19 +19,19 @@ if $ARGUMENTS.profile not in ["quality", "balanced", "budget"]: ``` - + +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. -Read current config: -```bash -cat .planning/config.json -``` +Read current config from state load or directly: Update `model_profile` field: ```json diff --git a/get-shit-done/workflows/settings.md b/get-shit-done/workflows/settings.md index fd40f55a4..8966fecf0 100644 --- a/get-shit-done/workflows/settings.md +++ b/get-shit-done/workflows/settings.md @@ -8,12 +8,15 @@ Read all files referenced by the invoking prompt's execution_context before star - + +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. diff --git a/get-shit-done/workflows/verify-phase.md b/get-shit-done/workflows/verify-phase.md index 70f8aa76f..4bb83a5c9 100644 --- a/get-shit-done/workflows/verify-phase.md +++ b/get-shit-done/workflows/verify-phase.md @@ -25,12 +25,19 @@ Then verify each level against the actual codebase. -```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. diff --git a/get-shit-done/workflows/verify-work.md b/get-shit-done/workflows/verify-work.md index d9e1aa0bf..c3e11886b 100644 --- a/get-shit-done/workflows/verify-work.md +++ b/get-shit-done/workflows/verify-work.md @@ -20,11 +20,14 @@ No Pass/Fail buttons. No severity questions. Just: "Here's what should happen. D - + +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`. @@ -77,13 +80,10 @@ Continue to `create_uat_file`. **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.