diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md new file mode 100644 index 0000000..6f6520f --- /dev/null +++ b/.planning/codebase/ARCHITECTURE.md @@ -0,0 +1,170 @@ +# Architecture + +**Analysis Date:** 2026-03-27 + +## Pattern Overview + +**Overall:** Agent-orchestrated agentic code framework (GSD - Get Shit Done) + +**Key Characteristics:** +- Multi-agent cooperative system: 18 specialized agents working in coordinated workflows +- Document-driven state management: All decisions and progress stored as Markdown files +- Workflow-based orchestration: 56 workflows guide agent interactions and user engagement +- Agentic code execution: Plans are executable prompts for Claude model execution +- Extensible per-runtime: Same architecture replicated across 7 IDE/agent providers (.claude, .agent, .gemini, .codex, .cursor, .windsurf, .opencode) + +## Layers + +**Orchestration Layer:** +- Purpose: Coordinate user commands, route to agents, manage phase/milestone progression +- Location: `.claude/get-shit-done/workflows/` +- Contains: 56 workflow definitions (markdown files), each defining a multi-step process +- Depends on: gsd-tools.cjs CLI for state management, git operations, config parsing +- Used by: All commands (user entry points) + +**Agent Layer:** +- Purpose: Specialized reasoning for different task types (planning, execution, research, verification, mapping) +- Location: `.claude/agents/` (18 agents) +- Contains: Agent role definitions, instructions, tool access lists +- Agents: gsd-planner, gsd-executor, gsd-phase-researcher, gsd-verifier, gsd-debugger, gsd-codebase-mapper, gsd-integration-checker, gsd-ui-auditor, gsd-plan-checker, and 9 others +- Depends on: Workflow coordination, tools (Read, Write, Bash, Grep, Glob, WebFetch) +- Used by: Orchestration workflows, invoked via `@agent-name` or Task() calls + +**State Management Layer:** +- Purpose: Persistent tracking of project progress, decisions, and configuration +- Location: `.planning/` (global state), phase directories (phase-local state) +- Contains: STATE.md (global), CONTEXT.md (decisions), ROADMAP.md (scope), PLAN.md (task breakdown), SUMMARY.md (execution results), VERIFICATION.md (quality gates) +- Depends on: gsd-tools.cjs for parsing, git for history +- Used by: All agents and orchestration layer + +**Tool Layer:** +- Purpose: Provide execution capabilities for agents +- Location: Various (bash, file I/O, git, web) +- Tools: Read, Write, Edit, Bash, Grep, Glob, WebFetch, mcp__context7__* +- Depends on: Agent invocations +- Used by: Agents during execution + +**CLI Tool Layer:** +- Purpose: Centralized state/config operations shared across 50+ workflow/agent files +- Location: `.claude/get-shit-done/bin/gsd-tools.cjs` (~1000 lines) +- Contains: 100+ commands for state management, phase operations, validation, progress tracking +- Depends on: Node.js built-ins, git, file system +- Used by: Every workflow and agent (called via bash subprocess) + +## Data Flow + +**Phase Planning Flow:** + +1. User invokes `/gsd:plan-phase PHASE_NUMBER` +2. Orchestrator (plan-phase workflow) loads PHASE state via gsd-tools.cjs +3. Planner agent (gsd-planner) reads CONTEXT.md (user decisions), codebase structure, creates PLAN.md +4. Plan Checker agent validates PLAN.md structure and quality +5. PLAN.md written to phase directory +6. User reviews, optionally discusses via `/gsd:discuss-phase` → updates CONTEXT.md +7. Flow loops if plan changes needed + +**Phase Execution Flow:** + +1. User invokes `/gsd:execute-phase PHASE_NUMBER` +2. Executor orchestrator loads phase plans (multiple per phase) +3. Plans grouped by wave (dependency-aware parallelization) +4. For each wave: + - Executor agent loads PLAN.md + - Executes tasks sequentially (each task → code change → test verification) + - Commits per-task (atomic commits for rollback safety) + - Writes SUMMARY.md with results +5. Orchestrator collects all SUMMARY.md files +6. Verifier agent checks phase completion against VERIFICATION.md +7. STATE.md updated with completion status +8. Planning docs committed to git (if commit_docs: true) + +**Verification Flow:** + +1. Phase execution completes, SUMMARY.md produced +2. Verifier agent compares output against VERIFICATION.md (user-defined success criteria) +3. If gaps detected: Trigger `/gsd:plan-phase --gaps` for remedial planning +4. Remedial PLAN.md created with gap-closure tasks +5. Execute → Verify loop continues until no gaps + +**State Management Flow:** + +1. STATE.md maintains global position: current_phase, current_milestone, workstream, blockers +2. Phase directories contain CONTEXT.md (decisions), PLAN.md (tasks), SUMMARY.md (results), VERIFICATION.md (success gates) +3. ROADMAP.md holds master scope: all phases with descriptions +4. .planning/config.json: branching strategy, model profiles, search behavior +5. Each operation updates relevant state file, committed atomically + +## Key Abstractions + +**Phase:** +- Purpose: Logical unit of work scoped by user, contains multiple Plans +- Examples: `1`, `1.1`, `1.2` (decimal numbering for sub-phases) +- Pattern: Each phase has directory `.planning/phases/N/` with CONTEXT.md, PLAN.md, SUMMARY.md, VERIFICATION.md + +**Plan:** +- Purpose: Executable task breakdown derived from phase scope (typically 2-3 tasks per plan) +- Examples: `PLAN-01.md`, `PLAN-02.md` within a phase directory +- Pattern: PLAN.md contains frontmatter (metadata), objective, context references, tasks array, success criteria + +**Task:** +- Purpose: Atomic unit of work within a plan (code change, test, commit) +- Types: `type="auto"` (fully autonomous), `type="checkpoint"` (pause before), `type="review"` (requires human sign-off) +- Pattern: Task has action (what to do), verification criteria, expected artifacts + +**Workflow:** +- Purpose: Multi-step process coordinating user input and agent actions +- Examples: `plan-phase.md`, `execute-phase.md`, `discuss-phase.md` +- Pattern: Workflows define steps with conditional branching, agent spawning, state updates + +**Agent Profiles:** +- Purpose: Model selection strategy for agent execution (quality vs cost) +- Profiles: `quality` (Opus for all), `balanced` (Opus planning, Sonnet execution), `budget` (minimal Opus) +- Pattern: Resolved via gsd-tools.cjs based on `.planning/config.json` model_profile setting + +## Entry Points + +**Command Entry Point:** +- Location: `.claude/get-shit-done/workflows/` (any `.md` file) +- Triggers: User invokes `/gsd:WORKFLOW_NAME [args]` +- Responsibilities: Parse arguments, call gsd-tools.cjs init command, route to agents or inline execution + +**Agent Entry Point:** +- Location: `.claude/agents/AGENT_NAME.md` +- Triggers: Spawned by orchestrator via `@AGENT_NAME` mention or Task() call +- Responsibilities: Load context, read mandatory files, execute role-specific logic, return results + +**Tool Entry Point:** +- Location: `.claude/get-shit-done/bin/gsd-tools.cjs` +- Triggers: `node gsd-tools.cjs [args]` +- Responsibilities: Parse subcommands, perform atomic state/git operations, output JSON + +## Error Handling + +**Strategy:** Graceful degradation with checkpoint pauses + +**Patterns:** +- **Auth Errors:** Executor pauses at checkpoint, waits for user to provide credentials +- **Verification Failures:** Verifier identifies gaps, planner creates remedial PLAN.md, executor runs gap-closure phase +- **Invalid State:** gsd-tools.cjs validate commands detect inconsistencies, suggest repairs +- **Parse Failures:** Frontmatter validation catches schema violations early +- **Git Conflicts:** Executor respects branching strategy, creates feature branches per config + +## Cross-Cutting Concerns + +**Logging:** Shell output captured from gsd-tools.cjs, bash task execution. Errors logged to console, summary tracked in SUMMARY.md. + +**Validation:** gsd-tools.cjs provides `validate` commands for: +- Phase numbering consistency +- Plan structure (required fields, task arrays) +- References (@ paths resolve to existing files) +- Artifacts (must_haves tracked in PLAN.md) + +**Authentication:** Config stored in `~/.gsd/` (outside repo), environment variable overrides for CI. Secrets never committed to git. + +**Atomicity:** gsd-tools.cjs commit command handles commit_docs check and .gitignore detection. Each task commits separately for rollback safety. + +**Determinism:** Model profiles ensure same agent type always gets same model (unless inherit mode). Frontmatter schema validation prevents parsing ambiguity. + +--- + +*Architecture analysis: 2026-03-27* diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md new file mode 100644 index 0000000..8dff04e --- /dev/null +++ b/.planning/codebase/CONCERNS.md @@ -0,0 +1,250 @@ +# Codebase Concerns + +**Analysis Date:** 2026-03-27 + +## Silent Error Handling (Critical) + +**Widespread use of empty catch blocks:** +- Files: `/.claude/hooks/gsd-prompt-guard.js`, `/.claude/hooks/gsd-context-monitor.js`, `/.claude/hooks/gsd-workflow-guard.js`, `/.claude/hooks/gsd-statusline.js`, `/.claude/hooks/gsd-check-update.js` +- Issue: 14+ catch blocks across hooks swallow errors silently with `catch (e) {}` or `catch (e) { // comment }` without logging +- Impact: Failures in hook execution go undetected, making debugging difficult. When files are corrupted, config fails to parse, or file system errors occur, no indication is provided to users or developers +- Current mitigation: Comments explain intent (e.g., "Silent fail -- bridge is best-effort", "don't break statusline on parse errors"), but no logging mechanism exists +- Recommendation: Implement optional debug logging to stderr (only when hooks are invoked in debug mode) without breaking normal operation. Use environment variable like `GSD_HOOK_DEBUG=1` to enable error logging + +--- + +## Fragile Hook Timeout Architecture + +**Context-Monitor Hook (`.claude/hooks/gsd-context-monitor.js`)**: +- Issue: 10-second stdin timeout (line 35) is tight for slow systems. On Windows/Git Bash, pipe delays can exceed this +- Files: `/.claude/hooks/gsd-context-monitor.js` (line 35: `setTimeout(() => process.exit(0), 10000)`) +- Current mitigation: Comments reference issues #775, #1162 indicating this was a known problem +- Risk: On systems with slow I/O, the hook exits prematurely without reading input, potentially leaving metrics unprocessed +- Safe modification: Consider detecting platform and adjusting timeout accordingly, or make timeout configurable via environment variable + +--- + +## Hardcoded Buffer Percentage + +**Status Line Hook Context Normalization**: +- Issue: 16.5% buffer hardcoded for Claude Code autocompact (line 29) +- Files: `/.claude/hooks/gsd-statusline.js` (line 29: `const AUTO_COMPACT_BUFFER_PCT = 16.5`) +- Impact: If Claude Code changes autocompact behavior or other models have different buffers, context calculations become inaccurate +- Recommendation: Make this configurable via `.planning/config.json` with sensible defaults per model (Claude, Gemini, OpenCode) + +--- + +## Stale Hook Version Tracking + +**Hook Version Header Validation**: +- Issue: Version detection depends on comment headers in JavaScript files (line 78 in `gsd-check-update.js`) +- Files: `/.claude/hooks/gsd-check-update.js` (lines 73-92) +- Risk: If hook files are minified, reformatted, or copied incorrectly, version headers can be lost, making stale hook detection fail silently +- Current state: Detects "unknown" version if header is missing, but this doesn't prevent the hook from running with wrong version +- Recommendation: Add a checksum or content hash validation in addition to version headers to detect unintended hook modifications + +--- + +## Process Detachment on Windows + +**Check-Update Hook Background Process**: +- Issue: Uses `spawn()` with `detached: true` (line 111 in `gsd-check-update.js`) +- Files: `/.claude/hooks/gsd-check-update.js` (lines 108-114) +- Impact: Background npm process can hang on Windows if not properly detached. Blocks are prevented by `unref()` (line 114), but edge cases remain if process fails +- Current state: `windowsHide: true` flag added, `stdio: 'ignore'` set +- Recommendation: Add timeout to background spawn, return immediately after unref, and consider writing to log file instead of silently ignoring errors + +--- + +## Config File Parsing Without Validation + +**Multiple Hooks Read `.planning/config.json`**: +- Issue: Config files are parsed with `JSON.parse()` but no schema validation exists +- Files: `/.claude/hooks/gsd-context-monitor.js` (line 53), `/.claude/hooks/gsd-workflow-guard.js` (line 65) +- Risk: Malformed JSON or missing expected fields cause silent failures. If config structure changes, old configs won't error but silently ignore new fields +- Recommendation: Implement a simple schema validation utility (even lightweight: check for required keys and types) and log warnings when config doesn't match expected shape + +--- + +## Race Conditions in Metrics Bridge + +**Context Metrics Between Statusline and Monitor Hooks**: +- Issue: Two separate hooks read/write to `/tmp/claude-ctx-{sessionId}.json` without file locking +- Files: `/.claude/hooks/gsd-statusline.js` (line 40-47 writes), `/.claude/hooks/gsd-context-monitor.js` (line 63-70 reads) +- Risk: On high-frequency tool use, write and read can race, causing monitor hook to read stale metrics or corrupted JSON +- Current mitigation: Both have try-catch around JSON.parse(), stale metrics are detected by timestamp (line 74) +- Recommendation: Use atomic writes (write-to-temp-then-rename pattern) for metrics file, or switch to a simpler shared state mechanism + +--- + +## Missing Logging Infrastructure + +**No Structured Logging**: +- Issue: Hooks only log to stdout via process.stdout.write() for hook outputs. No persistent logs for troubleshooting +- Files: All hook files (`/.claude/hooks/*.js`) +- Impact: When hooks fail silently, no audit trail exists to debug issues. Users cannot see what hooks detected or why they exited +- Recommendation: Create optional debug logs in `.planning/hooks-debug.log` (only when env var `GSD_DEBUG=1`), append structured JSON records with timestamp, hook name, and outcome + +--- + +## Unbounded Memory in Warning State File + +**Context Monitor Warning Debounce**: +- Issue: Warning state tracked in `/tmp/claude-ctx-{sessionId}-warned.json` accumulates indefinitely +- Files: `/.claude/hooks/gsd-context-monitor.js` (lines 87-117) +- Risk: Temporary directory might not clean this up, causing stale state from previous sessions to affect new sessions +- Current mitigation: State is per-session (uses sessionId), so scope is limited +- Recommendation: Add timestamp to warning state and treat state older than 1 hour as stale (auto-reset) + +--- + +## Regex Pattern Complexity in Prompt Guard + +**Prompt Injection Detection Patterns**: +- Issue: 12 regex patterns for injection detection (lines 18-32 in `gsd-prompt-guard.js`) are not anchored and may be fragile +- Files: `/.claude/hooks/gsd-prompt-guard.js` (lines 18-32) +- Risk: Some patterns (e.g., `/you\s+are\s+now\s+/i`) could match benign documentation text about "You are now ready to..." and trigger false warnings +- Impact: While warnings are advisory-only, frequent false positives degrade user experience +- Recommendation: Review patterns for false positive risk, consider context (e.g., only in code blocks, not in comments), or add allowlist for common false positives + +--- + +## Inconsistent Hook Version Across Environments + +**Multi-Environment Hook Duplication**: +- Issue: Identical hooks duplicated across `.claude/`, `.agent/`, `.gemini/`, `.opencode/` directories +- Files: 4x each of `gsd-prompt-guard.js`, `gsd-context-monitor.js`, `gsd-workflow-guard.js`, `gsd-statusline.js`, `gsd-check-update.js` +- Risk: If one environment's hooks are updated, others can drift out of sync. Version check in `gsd-check-update.js` detects this (line 81-82) but doesn't auto-fix +- Impact: Users with multiple agent environments may see inconsistent behavior +- Recommendation: Consolidate hooks to a shared location or implement auto-sync mechanism in installer + +--- + +## Resource Leaks in Timeouts + +**Stdin Timeout Cleanup**: +- Issue: `setTimeout()` created for stdin timeout in all hooks, relies on `clearTimeout()` to clean up +- Files: `/.claude/hooks/gsd-prompt-guard.js`, `/.claude/hooks/gsd-context-monitor.js`, `/.claude/hooks/gsd-workflow-guard.js`, `/.claude/hooks/gsd-statusline.js` +- Risk: If process exits before reaching `process.stdin.on('end')`, timeout continues running until expiry (3-10 seconds) +- Current state: Process exits on timeout with code 0, but spawned processes inherit this timeout +- Recommendation: Add `unref()` call on timeout timers so they don't keep process alive + +--- + +## Platform-Specific Path Separator + +**Windows Path Handling in Guards**: +- Issue: Guards check for both `/` and `\\` in file paths (e.g., line 52 in `gsd-prompt-guard.js`) +- Files: `/.claude/hooks/gsd-prompt-guard.js` (line 52), `/.claude/hooks/gsd-workflow-guard.js` (line 43) +- Risk: Mixing separators when checking `.planning/` paths may not catch all variations on Windows (e.g., mixed slashes) +- Recommendation: Normalize paths using `path.normalize()` before comparison, or use `path.sep` for platform detection + +--- + +## Missing Config Directory Override Documentation + +**CLAUDE_CONFIG_DIR Environment Variable**: +- Issue: Support for `CLAUDE_CONFIG_DIR` environment variable is implemented (line 18 in `gsd-check-update.js`, line 73 in `gsd-statusline.js`) but not documented +- Files: `/.claude/hooks/gsd-check-update.js` (line 18), `/.claude/hooks/gsd-statusline.js` (line 73) +- Impact: Users with custom config directories won't know this variable exists, potentially breaking hook functionality +- Recommendation: Document in copilot-instructions.md or add reference in hook comments + +--- + +## Temporary File Cleanup Strategy + +**Metric Files Never Cleaned**: +- Issue: `/tmp/claude-ctx-{sessionId}.json` and `/tmp/claude-ctx-{sessionId}-warned.json` are never deleted +- Files: `/.claude/hooks/gsd-statusline.js` (writes), `/.claude/hooks/gsd-context-monitor.js` (reads) +- Risk: On long-running systems, /tmp fills up with stale session files +- Recommendation: Implement cleanup logic to delete temp files older than 7 days, or hook into session cleanup to delete files on logout + +--- + +## Package.json Missing Dependencies + +**Minimal Configuration**: +- Issue: `.claude/package.json` only contains `{"type":"commonjs"}`, no dependencies listed +- Files: `/.claude/package.json` +- Risk: Hooks use built-in Node modules (fs, path, os, child_process), so this is correct, but appears incomplete +- Current state: This is intentional (all hooks use only Node builtins), but unclear to maintainers +- Recommendation: Add comment in package.json explaining that hooks intentionally use no external dependencies for portability + +--- + +## Potential Memory Bloat in Large Outputs + +**No Stream Processing in Hooks**: +- Issue: All hooks read entire stdin into memory before processing (`let input = ''; process.stdin.on('data', chunk => input += chunk)`) +- Files: All hook files +- Risk: If a tool call writes gigabytes of content (e.g., massive file read), the hook process could run out of memory +- Current mitigation: Only tool writes/edits are inspected, and these are typically small +- Recommendation: For hooks processing large content (especially prompt injection guard), implement streaming regex matching or line-by-line processing + +--- + +## Test Coverage Gaps + +**No Unit Tests for Hooks**: +- What's not tested: None of the 5 hook files have automated tests +- Files: `/.claude/hooks/*.js` (all of them) +- Risk: Changes to hook logic have no regression protection. Timeout tweaks, path logic, or regex patterns could break without detection +- Impact: Hook failures are silent (by design), so broken hooks go unnoticed until users report issues +- Priority: High — hooks are critical path for agent context management + +--- + +## Missing Error Recovery in Executor + +**Deviation Rule Priority Conflicts**: +- Issue: Executor auto-applies Rules 1-3 without clear priority when multiple rules could apply +- Files: `/.github/agents/gsd-executor.agent.md` (line 150 mentions "RULE PRIORITY:") +- Risk: When a task has multiple issues (e.g., bug AND missing critical functionality), executor might fix bug first, missing that missing-function blocking task completion +- Recommendation: Clarify priority order: blocking issues (Rule 3) > missing critical functionality (Rule 2) > bugs (Rule 1) + +--- + +## Subprocess Error Propagation in Background Checks + +**npm view Command Failure Silent**: +- Issue: `execSync('npm view get-shit-done-cc version')` wrapped in try-catch, timeout 10s (line 96 in `gsd-check-update.js`) +- Files: `/.claude/hooks/gsd-check-update.js` (lines 95-97) +- Risk: If npm is not installed, offline, or slow, fails silently. Users won't know update check failed +- Impact: Latest version is set to "unknown", update check becomes unreliable +- Recommendation: Log to file when update check fails (optional debug log), or retry with exponential backoff + +--- + +## Missing Instrumentation for Decision Points + +**No Audit Trail for Hook Decisions**: +- Issue: When context monitor injects critical warning or workflow guard injects advisory, no record of decision +- Files: `/.claude/hooks/gsd-context-monitor.js` (lines 125-142), `/.claude/hooks/gsd-workflow-guard.js` (lines 78-87) +- Risk: If user behavior doesn't match warning, no way to audit what warning was shown or when +- Recommendation: Write decision logs to `.planning/hooks-audit.log` with timestamp, hook name, decision, and reason (only in GSD active mode) + +--- + +## Scalability of Hook Frequency + +**Hooks Run on Every Tool Use**: +- Issue: Context monitor (PostToolUse) runs after EVERY tool call, reads file, parses JSON, checks thresholds +- Files: `/.claude/hooks/gsd-context-monitor.js` +- Risk: On high-frequency tool sessions (100+ tools), accumulated overhead could impact performance +- Current mitigation: Debounce warnings (line 108), stale metric detection (line 74) +- Recommendation: Profile hook execution time under load, consider batching metrics or reducing check frequency + +--- + +## Unclear Behavior on Missing Files + +**Graceful Degradation Assumptions**: +- Issue: When `.planning/STATE.md`, `.planning/config.json`, or todo files don't exist, hooks silently skip functionality +- Files: All hooks that check for optional files +- Risk: Unclear to users whether missing files are "normal" or indicate misconfiguration +- Example: Statusline shows "no task" if todos not found, but user might think todos are lost +- Recommendation: Distinguish between "feature not enabled" (e.g., no .planning/ = not a GSD project) vs. "feature broken" (e.g., config.json exists but unparseable) + +--- + +*Concerns audit: 2026-03-27* diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md new file mode 100644 index 0000000..72dbe0b --- /dev/null +++ b/.planning/codebase/CONVENTIONS.md @@ -0,0 +1,179 @@ +# Coding Conventions + +**Analysis Date:** 2026-03-27 + +## Language & Runtime + +**Primary Language:** JavaScript (CommonJS) +- Node.js environment (no TypeScript transpilation) +- All hooks use `.js` extension with shebang: `#!/usr/bin/env node` + +**Module System:** +- CommonJS (`require()` only, no ES6 imports) +- Node.js built-in modules: `fs`, `path`, `os`, `child_process` +- No external npm dependencies in hook files + +## Naming Patterns + +**Files:** +- Kebab-case: `gsd-hook-name.js` +- Pattern: `gsd-` prefix + feature name + `.js` extension +- Examples: `gsd-prompt-guard.js`, `gsd-context-monitor.js`, `gsd-statusline.js` + +**Functions:** +- camelCase: `detectConfigDir()`, `clearTimeout()`, `writeFileSync()` +- Single-letter shorthand acceptable for simple operations: `f` for file in loops + +**Constants:** +- UPPER_SNAKE_CASE for immutable values: `WARNING_THRESHOLD`, `CRITICAL_THRESHOLD`, `STALE_SECONDS`, `DEBOUNCE_CALLS` +- Inline comments after constants for clarity: `const WARNING_THRESHOLD = 35; // remaining_percentage <= 35%` + +**Variables:** +- camelCase: `input`, `stdinTimeout`, `data`, `filePath`, `findings`, `configPath` +- Descriptive names: `remaining_percentage`, `callsSinceWarn`, `hookEventName` +- Single-letter loop variables: `f`, `e` (for errors), `p` (for patterns) + +**Types/Objects:** +- Object keys use snake_case: `tool_name`, `tool_input`, `file_path`, `hook_version`, `installed_version` +- Array items plural: `staleHooks`, `findings`, `allowedPatterns`, `files`, `hookFiles` + +## Code Style + +**Formatting:** +- No linter configured (no eslintrc, prettier, or biome config files found) +- Line length: typically 80-120 characters, no strict enforced limit observed +- Indentation: 2 spaces consistently across all files + +**Comments:** +- Single-line comments: `// comment` +- Multi-line blocks: Multiple `//` lines stacked (no `/* */` blocks found) +- Header comments with metadata: Version, purpose, triggers, behavior + - Pattern: `// gsd-hook-version: X.Y.Z` as first comment after shebang + - Purpose explanation follows immediately + +**String Formatting:** +- Single quotes for regular strings: `'utf8'`, `'end'` +- Template literals for interpolation: `` `${variable}` `` +- Backticks for paths and code examples in comments: `` `${filePath}` `` + +## Error Handling + +**Try-Catch Pattern:** +- All file I/O and JSON parsing wrapped in try-catch +- Silent failures preferred: catch blocks often empty or call `process.exit(0)` +- Examples from codebase: + - `try { const data = JSON.parse(input); } catch { process.exit(0); }` + - `try { ... } catch (e) { // Silent fail on parse errors }` + +**Graceful Degradation:** +- Never block operations with errors +- Timeout guards prevent hanging: `const stdinTimeout = setTimeout(() => process.exit(0), 3000);` +- File existence checks before operations: `if (fs.existsSync(configPath)) { ... }` +- Return early on missing critical data: `if (!sessionId) { process.exit(0); }` + +**Error Recovery:** +- Corrupted files reset to defaults: `catch (e) { warnData = { callsSinceWarn: 0, lastLevel: null }; }` +- Optional chain operators for safe access: `data.tool_input?.file_path || ''` + +## Type Coercion & Checks + +**Null/Undefined Handling:** +- Null coalescing default values: `data.session_id || ''`, `data.cwd || process.cwd()` +- Explicit null checks: `if (remaining != null)` (distinguishes null from undefined) +- Undefined/null fallbacks: `|| 'unknown'`, `|| []`, `|| {}` + +**Truthiness Checks:** +- Explicit boolean comparisons: `if (config.hooks?.workflow_guard) { ... }` +- Array length checks: `if (files.length > 0) { ... }`, `if (findings.length === 0) { ... }` + +**Number Conversions:** +- Explicit parsing: `Math.floor(Date.now() / 1000)`, `Math.round(100 - usableRemaining)` +- Clamping with Math: `Math.max(0, value)`, `Math.min(100, value)` + +## Imports & Requires + +**Order (when present):** +1. Node.js built-in modules: `fs`, `path`, `os`, `child_process` +2. Destructured imports grouped: `const { spawn } = require('child_process');` +3. No external package requires in hooks + +**Require Pattern:** +```javascript +const fs = require('fs'); +const path = require('path'); +const os = require('os'); +const { spawn } = require('child_process'); +``` + +## Object & Array Patterns + +**Object Creation:** +- Literal syntax: `{ hookEventName: 'PreToolUse', additionalContext: message }` +- Computed properties from template literals: `` { [key]: value } `` (not observed, uses direct literals) +- Spread operators: Not used in codebase + +**Array Operations:** +- `.filter()`: `files.filter(f => f.startsWith(session))` +- `.map()`: `files.map(f => ({ name: f, mtime: fs.statSync(...) }))` +- `.find()`: `todos.find(t => t.status === 'in_progress')` +- `.some()`: `allowedPatterns.some(p => p.test(filePath))` +- Arrow functions for callbacks: `chunk => input += chunk` + +**Sorting & Ordering:** +- Reverse chronological: `files.sort((a, b) => b.mtime - a.mtime)` +- File system operations ordered first, then filtering + +## Output Patterns + +**JSON Output:** +- All hook output is JSON: `process.stdout.write(JSON.stringify(output));` +- Output structure includes `hookSpecificOutput` wrapper: + ```javascript + const output = { + hookSpecificOutput: { + hookEventName: 'PreToolUse', + additionalContext: message + } + }; + ``` + +**Process Exit:** +- Success: `process.exit(0)` or implicit exit after writing output +- Error: `process.exit(0)` (never `process.exit(1)` to avoid breaking workflows) +- Cleanup: `clearTimeout()` called before operations + +## File I/O Patterns + +**Synchronous Operations:** +- `fs.readFileSync(path, 'utf8')` for reads +- `fs.writeFileSync(path, JSON.stringify(data))` for writes +- `fs.existsSync(path)` for checks +- `fs.readdirSync(path)` for directory listing +- `fs.statSync(path).mtime` for file metadata + +**Path Operations:** +- `path.join()` for path concatenation: `path.join(cwd, '.planning', 'config.json')` +- `path.basename(dir)` for extracting final component +- `path.dirname()` for parent directory + +## Regular Expressions + +**Pattern Definition:** +- Captured in constants array at file top: `const INJECTION_PATTERNS = [ /pattern1/i, /pattern2/i ]` +- Case-insensitive flag commonly used: `/pattern/i` +- Multiline patterns use raw strings: `/[\u200B-\u200F]/` for Unicode detection + +**Pattern Testing:** +- `.test()` method for boolean check: `if (pattern.test(content))` +- `.match()` for capture groups: `const versionMatch = content.match(/\\/\\/ gsd-hook-version:\\s*(.+)/)` +- `.source` property for pattern string: `findings.push(pattern.source)` + +## No Additional Frameworks + +**Testing:** Not detected - no test files exist +**Build Tools:** Not detected - runs directly as Node.js scripts +**Linting/Formatting:** Not detected - no .eslintrc, .prettierrc, or similar configs + +--- + +*Convention analysis: 2026-03-27* diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md new file mode 100644 index 0000000..b73ecf4 --- /dev/null +++ b/.planning/codebase/INTEGRATIONS.md @@ -0,0 +1,114 @@ +# External Integrations + +**Analysis Date:** 2026-03-27 + +## APIs & External Services + +**Web Search:** +- Brave Search - Web search integration for research and discovery phases + - SDK/Client: Native `fetch` API (Node.js built-in) + - Auth: `BRAVE_API_KEY` environment variable or `~/.gsd/brave_api_key` file + - Endpoint: `https://api.search.brave.com/res/v1/web/search` + - Implementation: `cmdWebSearch()` in `/home/ys/family-repo/AgenticCode/.claude/get-shit-done/bin/lib/commands.cjs` + +**Web Scraping (Optional):** +- Firecrawl - Web content extraction + - Auth: `FIRECRAWL_API_KEY` environment variable or `~/.gsd/firecrawl_api_key` file + - Status: Configuration detected, not actively used in codebase + +**Search Alternative (Optional):** +- Exa Search - Alternative search API + - Auth: `~/.gsd/exa_api_key` file + - Status: Configuration detected, not actively used in codebase + +## Data Storage + +**Repositories:** +- Git - Primary version control system for all planning documents + - Client: Git CLI via `child_process.execSync()` and `execFileSync()` + - Operations: Commit, status, log, diff, tag management + - Integration points: `execGit()` in `core.cjs`, phase operations in `phase.cjs` + +**File Storage:** +- Local filesystem only + - `.planning/` directory tree - All state, roadmaps, phases, requirements + - `~/.gsd/` directory - User-level API key storage + - Multi-workspace support via `.planning/config.json` sub_repos configuration + +**Caching:** +- None detected + +## Authentication & Identity + +**Auth Provider:** +- Custom/API Key based +- No centralized identity provider +- Individual API keys per external service stored in files or environment variables +- Git authentication via system SSH/credentials configured externally + +## Monitoring & Observability + +**Error Tracking:** +- None detected - errors handled via console output + +**Logs:** +- Console output via `output()` and `error()` functions in `/home/ys/family-repo/AgenticCode/.claude/get-shit-done/bin/lib/core.cjs` +- Support for structured JSON output via `--raw` flag +- Context monitoring hooks in `.claude/hooks/gsd-context-monitor.js` + +## CI/CD & Deployment + +**Hosting:** +- Self-hosted Node.js CLI +- IDE integration via Claude, Gemini, Agent, Cursor, OpenCode, Windsurf editors +- Editor-specific hooks and commands in `./.[editor]/.claude/hooks/` + +**CI Pipeline:** +- Git hooks integration via Claude settings +- Post-tool-use monitoring: `gsd-context-monitor.js` +- Pre-write guards: `gsd-prompt-guard.js` +- Update checking: `gsd-check-update.js` + +## Environment Configuration + +**Required env vars:** +- `HOME` - User home directory (for API key storage and config) +- `BRAVE_API_KEY` - (optional) Brave Search API key for web search functionality + +**Optional env vars:** +- `FIRECRAWL_API_KEY` - Web scraping capability +- `EXA_API_KEY` - Alternative search provider + +**Secrets location:** +- Environment variables: `.env` or shell environment +- File-based: `~/.gsd/brave_api_key`, `~/.gsd/firecrawl_api_key`, `~/.gsd/exa_api_key` +- Git-ignored configuration: Not applicable (no local .env files in codebase) + +## Webhooks & Callbacks + +**Incoming:** +- None detected + +**Outgoing:** +- Git commits via `execGit()` - Triggers CI/CD if configured +- Status updates via stdio - Display progress to Claude/editor interface + +## Git Integration + +**Operations Supported:** +- `git status` - Check working tree state +- `git add` - Stage files +- `git commit` - Create planning commits with auto-generated messages +- `git log` - Query commit history +- `git diff` - Compare changes +- `git tag` - Version marking for phases and milestones +- Commit routing for multi-repo workspaces + +**Key Implementation:** +- Location: `execGit()` in `/home/ys/family-repo/AgenticCode/.claude/get-shit-done/bin/lib/core.cjs` +- Supports sub-repo commit routing via `commit-to-subrepo` command +- Automatic message generation with structured frontmatter + +--- + +*Integration audit: 2026-03-27* diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md new file mode 100644 index 0000000..7cc538b --- /dev/null +++ b/.planning/codebase/STACK.md @@ -0,0 +1,76 @@ +# Technology Stack + +**Analysis Date:** 2026-03-27 + +## Languages + +**Primary:** +- JavaScript (Node.js) - Core framework and tooling +- CommonJS (`.cjs`) - Module format for all library files +- Markdown - Configuration, documentation, and state files + +## Runtime + +**Environment:** +- Node.js (version not explicitly specified, uses `#!/usr/bin/env node` shebang) + +**Package Manager:** +- npm (inferred from package.json presence) +- Lockfile: Not detected in codebase + +## Frameworks + +**Core:** +- Get Shit Done (GSD) Framework v1.29.0 - Agentic code orchestration and planning +- Native Node.js APIs - `child_process`, `fs`, `path` + +**Search & Web:** +- Brave Search API - Web search integration via HTTP fetch + +**Build/Dev:** +- Node.js built-in utilities - No external build tool detected + +## Key Dependencies + +**Critical:** +- `child_process` - Subprocess execution for git commands and CLI operations +- `fs` - File system operations for planning document management +- `path` - Cross-platform path handling +- `os` - Environment detection (home directory, temp directories) + +**Infrastructure:** +- `fetch` API (native Node.js) - HTTP requests for Brave Search API + +## Configuration + +**Environment:** +- Stored in `~/.gsd/` directory with separate API key files +- Environment variable overrides: `BRAVE_API_KEY`, `FIRECRAWL_API_KEY`, `EXA_API_KEY` + +**Key Configuration Files:** +- `.planning/config.json` - Project-wide configuration and feature flags +- `settings.json` - Agent-specific settings (per `./.agent/`, `./.claude/`, `./.gemini/`, etc.) +- `.gsd-file-manifest.json` - File integrity tracking with SHA256 hashes + +**Configuration Features:** +- Multi-repository workspace support +- Model profile resolution +- Milestone and workstream management +- Phase numbering strategies (decimal or custom) + +## Platform Requirements + +**Development:** +- Node.js with built-in ES2020+ support +- Git (for repository operations and commits) +- Bash/Shell environment for command execution +- File system with support for symlinks and deep directory structures + +**Production:** +- Self-contained Node.js CLI tool +- No external runtime required beyond Node.js +- Execution via `node gsd-tools.cjs` or direct command invocation + +--- + +*Stack analysis: 2026-03-27* diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md new file mode 100644 index 0000000..14073d2 --- /dev/null +++ b/.planning/codebase/STRUCTURE.md @@ -0,0 +1,217 @@ +# Codebase Structure + +**Analysis Date:** 2026-03-27 + +## Directory Layout + +``` +/home/ys/family-repo/AgenticCode/ +├── .agent/ # Anthropic Agent-specific GSD setup +│ ├── agents/ # Agent definitions (symlinks or copies) +│ ├── get-shit-done/ # Workflows, templates, references +│ ├── hooks/ # Post-tool integration hooks +│ ├── skills/ # Project skills (agent instructions) +│ └── package.json # CommonJS marker +├── .claude/ # Claude Code / Claude Web setup +│ ├── agents/ # 18 agent definition files (master) +│ ├── get-shit-done/ # Master workflows, references, commands +│ │ ├── bin/ # gsd-tools.cjs CLI (~1000 lines) +│ │ ├── commands/gsd/ # Command metadata (workstreams.md) +│ │ ├── references/ # Documentation and config specs +│ │ ├── templates/ # Scaffold templates for PLAN.md, SUMMARY.md +│ │ └── workflows/ # 56 orchestration workflows +│ ├── commands/gsd/ # Claude Code command overrides +│ ├── hooks/ # Post-tool hooks for linting/formatting +│ ├── package.json # CommonJS marker +│ └── settings.json # Per-runtime settings +├── .codex/ # Codeium Codex setup (mirrors .claude/) +├── .cursor/ # Cursor IDE setup (mirrors .claude/) +├── .gemini/ # Google Gemini setup (mirrors .claude/) +├── .opencode/ # OpenCode setup (mirrors .claude/) +├── .windsurf/ # Codeium Windsurf setup (mirrors .claude/) +├── .github/ # GitHub integration +│ ├── gsd-file-manifest.json # File integrity checksums +│ └── get-shit-done/ # GitHub action templates +├── .planning/ # Project state and planning documents +│ ├── codebase/ # Analysis documents (STACK.md, ARCHITECTURE.md, etc.) +│ ├── config.json # Project configuration (branching, model profiles) +│ ├── STATE.md # Global project state (current phase, milestone, blockers) +│ ├── ROADMAP.md # Full scope and phase definitions +│ ├── REQUIREMENTS.md # Traceability for feature requirements +│ └── phases/ # Phase execution directories +│ ├── 1/ # Phase 1 +│ │ ├── CONTEXT.md # User decisions for this phase +│ │ ├── PLAN-01.md # Task breakdown (plan 1 of N) +│ │ ├── PLAN-02.md # Task breakdown (plan 2 of N) +│ │ ├── SUMMARY-01.md # Execution results (for PLAN-01) +│ │ ├── VERIFICATION.md # Success criteria and quality gates +│ │ └── WAITING.json # Optional: pause signal for checkpoints +│ ├── 1.1/ # Sub-phase 1.1 +│ └── 2/ # Phase 2 +├── .git/ # Git repository +├── .gitignore # Standard: excludes node_modules, .env, .planning (optional) +├── README.md # Project descriptor +└── .gsd-file-manifest.json # Root-level file integrity tracking +``` + +## Directory Purposes + +**`.claude/` (Master Directory):** +- Purpose: Contains the canonical GSD system — agents, workflows, CLI tool, references +- Contains: Agent role definitions (18 files), 56 workflows, gsd-tools.cjs, documentation +- Key files: `agents/gsd-planner.md`, `agents/gsd-executor.md`, `agents/gsd-codebase-mapper.md`, `get-shit-done/bin/gsd-tools.cjs` + +**`.claude/agents/`:** +- Purpose: Agent role definitions — instructions, tool access, execution patterns +- Contains: 18 agent files (one per agent type) +- File pattern: `gsd-{role-name}.md` (e.g., `gsd-planner.md`) +- Size: Large files (10KB-45KB), front-loaded with role definition, process steps + +**`.claude/get-shit-done/workflows/`:** +- Purpose: Orchestration logic — multi-step processes coordinating agents and user input +- Contains: 56 markdown workflow files +- Naming: workflow names map to commands (e.g., `execute-phase.md` → `/gsd:execute-phase`) +- Pattern: Each workflow defines steps with conditional branching, gsd-tools.cjs calls, agent spawning + +**`.claude/get-shit-done/bin/`:** +- Purpose: CLI tool providing centralized state/git operations +- Contains: `gsd-tools.cjs` (main tool, ~1000 lines), `lib/` (supporting utilities) +- Commands: 100+ subcommands for state, phases, roadmaps, validation, commits +- Called from: Every workflow and agent via `node gsd-tools.cjs ` + +**`.claude/get-shit-done/references/`:** +- Purpose: Documentation and configuration specifications +- Contains: 15 reference files (model-profiles.md, planning-config.md, checkpoints.md, etc.) +- Usage: Read by agents to understand patterns, by implementers to understand system + +**`.claude/get-shit-done/templates/`:** +- Purpose: Scaffold templates for plan and summary generation +- Contains: PLAN.md template, SUMMARY.md template, CONTEXT.md template +- Usage: Developers fill templates when creating new phases + +**`.agent/`, `.gemini/`, `.codex/`, `.cursor/`, `.windsurf/`, `.opencode/`:** +- Purpose: Per-IDE setup directories (mirrors of `.claude/`) +- Contains: Symlinks or copies of agents/, workflows/, hooks/, settings.json +- Why separate: Each IDE has own credential storage, hook integration points, settings + +**`.planning/`:** +- Purpose: Global project state and phase-local planning documents +- Contains: STATE.md (global), ROADMAP.md (full scope), config.json, phases/ directory tree +- Key files: `STATE.md` (current position), `ROADMAP.md` (phase definitions), `config.json` (branching strategy, model profiles) + +**`.planning/phases/N/`:** +- Purpose: Per-phase execution directory — holds decisions, plans, summaries +- Contains: CONTEXT.md (user decisions), PLAN-*.md (task breakdowns), SUMMARY-*.md (results), VERIFICATION.md (success gates) +- Naming: Phase directories use number (1, 1.1, 1.2, 2) corresponding to ROADMAP.md phases + +## Key File Locations + +**Entry Points:** +- `.claude/get-shit-done/workflows/*.md` - User command entry points +- `.claude/agents/*.md` - Agent entry points (invoked by workflows) +- `.claude/get-shit-done/bin/gsd-tools.cjs` - CLI tool entry point + +**Configuration:** +- `.planning/config.json` - Project-wide configuration (branching, model profiles, search behavior) +- `.claude/settings.json` - Per-runtime agent settings (model overrides, parallelization) +- `~/.gsd/defaults.json` - User-global GSD defaults (read-only in repo) + +**Core Logic:** +- `.claude/agents/gsd-planner.md` - Phase planning logic (45KB, ~700 lines) +- `.claude/agents/gsd-executor.md` - Plan execution logic (21KB, ~450 lines) +- `.claude/agents/gsd-codebase-mapper.md` - Project analysis for architecture/tech docs +- `.claude/get-shit-done/bin/gsd-tools.cjs` - Centralized state/git operations + +**State & Decisions:** +- `.planning/STATE.md` - Global state (current phase, milestone, workstream, blockers) +- `.planning/ROADMAP.md` - Master scope (phase numbers, descriptions, order) +- `.planning/phases/N/CONTEXT.md` - User decisions for phase N +- `.planning/phases/N/PLAN-*.md` - Task breakdowns (executable prompts) + +**Execution & Verification:** +- `.planning/phases/N/SUMMARY-*.md` - Execution results, commit hashes, artifacts +- `.planning/phases/N/VERIFICATION.md` - Success criteria, quality gates, test requirements +- `.planning/REQUIREMENTS.md` - Requirement IDs (REQ-01, etc.) for traceability + +**Documentation & References:** +- `.claude/get-shit-done/references/model-profiles.md` - Agent model selection strategies +- `.claude/get-shit-done/references/planning-config.md` - Configuration options spec +- `.claude/get-shit-done/references/checkpoints.md` - Pause point definition and usage + +## Naming Conventions + +**Files:** +- Workflows: kebab-case (e.g., `execute-phase.md`, `plan-phase.md`) +- Agents: kebab-case with gsd- prefix (e.g., `gsd-planner.md`, `gsd-executor.md`) +- Phase documents: UPPERCASE with phase number (e.g., `PLAN-01.md`, `SUMMARY-02.md`) +- Config files: lowercase (e.g., `config.json`, `settings.json`) +- State files: UPPERCASE (e.g., `STATE.md`, `ROADMAP.md`) + +**Directories:** +- Hidden IDE-specific: dot-prefixed (`.claude`, `.agent`, `.gemini`) +- Planning: `.planning` with phase structure (phases/1/, phases/1.1/, etc.) +- Tools/resources: lowercase (agents, workflows, bin, lib, references, templates) + +**Phase Numbering:** +- Integer phases: 1, 2, 3 (major phases) +- Decimal sub-phases: 1.1, 1.2, 1.3 (sub-divisions of phase 1) +- Directory structure mirrors numbering: `.planning/phases/1/`, `.planning/phases/1.1/` + +## Where to Add New Code + +**New Agent:** +1. Create ``.claude/agents/gsd-{agent-name}.md`` with role definition, process steps, tools +2. Size: Keep under 50KB (agents are consumed whole as context) +3. Register: List in agent registry within workflow files and orchestrator +4. Mirror: Copy to `.agent/agents/`, `.gemini/agents/`, etc. after validation + +**New Workflow:** +1. Create `.claude/get-shit-done/workflows/{workflow-name}.md` +2. Define: ``, `` with numbered steps, subprocess calls to gsd-tools.cjs +3. Commands: If user-facing, add metadata entry in `.claude/commands/gsd/` +4. Routing: Document how workflow invokes agents (inline vs spawned via Task()) + +**New Reference Documentation:** +1. Create `.claude/get-shit-done/references/{topic}.md` +2. Purpose: Explain system patterns, configuration options, validation rules +3. Read by: Agents when implementing features, developers understanding system +4. Update: Link from agent files or workflow documentation + +**New Phase (during project execution):** +1. Create phase directory: `.planning/phases/{N}/` (where N is next phase number) +2. Create CONTEXT.md (template in references/) +3. Planner creates PLAN-*.md files +4. Add phase to ROADMAP.md with description +5. Update STATE.md current_phase field + +**Phase Documents (during planning):** +- PLAN.md: Created by gsd-planner agent (follows template in templates/) +- VERIFICATION.md: User creates to define success criteria (template available) +- CONTEXT.md: Created by gsd-discuss-phase agent from user decisions + +## Special Directories + +**`.planning/codebase/`:** +- Purpose: Analysis documents for executor reference (STACK.md, ARCHITECTURE.md, CONVENTIONS.md, TESTING.md, CONCERNS.md) +- Generated: By gsd-codebase-mapper agent via `/gsd:map-codebase` +- Committed: Yes, documents tracked in git for future reference + +**`.planning/phases/N/`:** +- Purpose: Execution workspace for phase N (isolated state) +- Generated: Directories created by gsd-tools.cjs during phase setup +- Committed: Yes, all planning docs committed (unless .planning/ in .gitignore) + +**`.claude/get-shit-done/bin/lib/`:** +- Purpose: Supporting utilities for gsd-tools.cjs +- Contents: Shared functions for JSON parsing, git operations, file I/O +- Generated: No, part of GSD system +- Committed: Yes, part of codebase + +**`node_modules/`:** +- Purpose: NPM dependencies (if any) +- Generated: Yes, by `npm install` +- Committed: No, excluded via .gitignore + +--- + +*Structure analysis: 2026-03-27* diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md new file mode 100644 index 0000000..03a1ba0 --- /dev/null +++ b/.planning/codebase/TESTING.md @@ -0,0 +1,209 @@ +# Testing Patterns + +**Analysis Date:** 2026-03-27 + +## Test Framework + +**Status:** Not detected +- No test files (*.test.js, *.spec.js) found in codebase +- No test runner configured (no jest.config.js, vitest.config.js, or mocha configuration) +- No test dependencies listed in package.json files + +**Code Context:** +- The codebase consists of 5 Node.js hook scripts (579 total lines across `.claude/hooks/`) +- Each hook is a standalone CLI tool that reads JSON from stdin and outputs JSON to stdout +- Hooks are event-driven (SessionStart, PreToolUse, PostToolUse, AfterTool lifecycle events) +- No application code beyond these hooks exists in the repository + +## Script Type & Testing Approach + +**Current Architecture:** +Each hook file (`gsd-*.js` in `/home/ys/family-repo/AgenticCode/.claude/hooks/`) follows the same structural pattern: +- Shebang: `#!/usr/bin/env node` +- Node.js built-in modules only (fs, path, os, child_process) +- JSON stdin → processing → JSON stdout +- Silent failure on errors (timeout guards, try-catch with exit(0)) + +**Hook Files:** +- `gsd-prompt-guard.js` (96 lines) - Detects prompt injection patterns in written files +- `gsd-statusline.js` (119 lines) - Renders context usage and task status +- `gsd-context-monitor.js` (156 lines) - Warns when context window is low +- `gsd-workflow-guard.js` (94 lines) - Advises on workflow compliance +- `gsd-check-update.js` (114 lines) - Checks for GSD updates in background + +## Manual Testing Indicators + +**Integration Points (evidence of real-world testing):** +- Comments referencing specific issues: `See #775`, `See #1162`, `See #870`, `See #884` +- Platform-specific workarounds: `windowsHide: true` for child_process to prevent console flash on Windows +- Timeout guards: `const stdinTimeout = setTimeout(() => process.exit(0), 3000);` prevents hanging on pipe issues +- Git Bash compatibility: explicit handling of stdin timeout on Windows Git Bash + +**Behavioral Validation Patterns:** +- Config file validation: reads `.planning/config.json`, catches parse errors gracefully +- File existence checks before operations: `if (fs.existsSync(filePath))` +- Stale data detection: `if ((now - metrics.timestamp) > STALE_SECONDS)` +- Severity escalation tracking: debounce counter resets on warning level change + +## Input Validation + +**JSON Parsing with Error Handling:** +All hooks follow this pattern (example from `gsd-prompt-guard.js`): +```javascript +let input = ''; +const stdinTimeout = setTimeout(() => process.exit(0), 3000); +process.stdin.setEncoding('utf8'); +process.stdin.on('data', chunk => input += chunk); +process.stdin.on('end', () => { + clearTimeout(stdinTimeout); + try { + const data = JSON.parse(input); + // Process data + } catch { + // Silent fail — never block tool execution + process.exit(0); + } +}); +``` + +**Defensive Checks:** +- Field existence: `const toolName = data.tool_name;` then `if (toolName !== 'Write' && toolName !== 'Edit')` +- Optional chaining: `data.tool_input?.file_path || ''` +- Null checks: `if (!sessionId) { process.exit(0); }` +- Default values: `data.cwd || process.cwd()`, `data.model?.display_name || 'Claude'` + +## File I/O Testing + +**Patterns for Reliability:** +- Synchronous I/O ensures order: `fs.readFileSync()` → process → `fs.writeFileSync()` +- Directory existence checked before writing: `if (!fs.existsSync(cacheDir)) { fs.mkdirSync(cacheDir, { recursive: true }); }` +- Try-catch wraps all file operations that could fail: + ```javascript + try { + const bridgeData = JSON.stringify({ ... }); + fs.writeFileSync(bridgePath, bridgeData); + } catch (e) { + // Silent fail -- bridge is best-effort, don't break statusline + } + ``` + +## State Machine / Behavior Testing + +**Context Monitor Debounce Logic** (`gsd-context-monitor.js`): +- Tracks warning state in file: `/tmp/claude-ctx-{session_id}-warned.json` +- Debounce counter incremented: `warnData.callsSinceWarn = (warnData.callsSinceWarn || 0) + 1` +- Severity escalation bypasses debounce: `if (severityEscalated) { // emit immediately }` +- State reset on warn: `warnData.callsSinceWarn = 0` + +This pattern validates behavior without formal tests: +```javascript +let warnData = { callsSinceWarn: 0, lastLevel: null }; +const isCritical = remaining <= CRITICAL_THRESHOLD; +const currentLevel = isCritical ? 'critical' : 'warning'; +const severityEscalated = currentLevel === 'critical' && warnData.lastLevel === 'warning'; +if (!firstWarn && warnData.callsSinceWarn < DEBOUNCE_CALLS && !severityEscalated) { + process.exit(0); // Suppress warning +} +``` + +## Regex Pattern Testing + +**Prompt Injection Detection** (`gsd-prompt-guard.js`): +Patterns tested against content without formal unit tests: +```javascript +const INJECTION_PATTERNS = [ + /ignore\s+(all\s+)?previous\s+instructions/i, + /override\s+(system|previous)\s+(prompt|instructions)/i, + /you\s+are\s+now\s+(?:a|an|the)\s+/i, + /(?:print|output|reveal|show|display|repeat)\s+(?:your\s+)?(?:system\s+)?(?:prompt|instructions)/i, + /\[SYSTEM\]/i, + /<<\s*SYS\s*>>/i, +]; +for (const pattern of INJECTION_PATTERNS) { + if (pattern.test(content)) { + findings.push(pattern.source); + } +} +``` + +Unicode detection without regex: `if (/[\u200B-\u200F\u2028-\u202F\uFEFF\u00AD]/.test(content))` + +## Environment & Configuration Testing + +**Configuration Loading Safety** (all hooks): +- Try-catch with silent fail: + ```javascript + const configPath = path.join(cwd, '.planning', 'config.json'); + if (fs.existsSync(configPath)) { + try { + const config = JSON.parse(fs.readFileSync(configPath, 'utf8')); + if (config.hooks?.context_warnings === false) { + process.exit(0); // Feature disabled + } + } catch (e) { + // Ignore config parse errors + } + } + ``` +- Optional chaining for nested config: `config.hooks?.workflow_guard`, `config.hooks?.context_warnings` + +**Environment Variable Access:** +```javascript +const envDir = process.env.CLAUDE_CONFIG_DIR; +if (envDir && fs.existsSync(path.join(envDir, 'get-shit-done', 'VERSION'))) { + return envDir; // Custom config dir detected +} +``` + +## Performance & Resource Management + +**Timeout Guards (prevent resource leaks):** +- All hooks implement stdin timeout: `const stdinTimeout = setTimeout(() => process.exit(0), 3000);` +- Longer timeout for high-volume operations: `const stdinTimeout = setTimeout(() => process.exit(0), 10000);` in context-monitor +- Always cleared before processing: `clearTimeout(stdinTimeout);` + +**Background Process Management** (`gsd-check-update.js`): +- Child process spawned with `stdio: 'ignore'`: doesn't inherit parent's stdio +- Process detached on Windows: `detached: true` (required for proper cleanup) +- Parent calls `child.unref()`: parent doesn't wait for child to exit + +```javascript +const child = spawn(process.execPath, ['-e', `...inline script...`], { + stdio: 'ignore', + windowsHide: true, + detached: true +}); +child.unref(); +``` + +## Test Coverage Gaps + +**Areas Without Formal Testing:** +1. **Regex Pattern Accuracy** - Injection patterns untested against false positives/negatives +2. **Debounce Counter Edge Cases** - Corruption recovery, counter reset logic +3. **Platform-Specific Behavior** - Windows vs Linux path handling, process detachment +4. **Concurrent Access** - Multiple hooks writing to same state files simultaneously +5. **Large Input Handling** - No tests for multi-megabyte JSON on stdin +6. **Stale File Cleanup** - No validation that temp files are properly removed +7. **Spawn Child Behavior** - Background update check success/failure not validated + +## Recommendation for Testing + +**Given the architecture (CLI hooks, not library code):** +- Integration testing more valuable than unit tests +- Manual testing via real Claude Code sessions is current primary validation +- Would recommend: + 1. Snapshot tests for JSON output structure + 2. Mock file system for configuration loading paths + 3. Integration tests simulating tool use hook flow + 4. Platform-specific testing (Windows, macOS, Linux) for path handling + +**Lack of tests is acceptable for:** +- Simple stdin/stdout data transformation scripts +- Hooks deployed once per installation (not on every tool call) +- Silent-fail-safe design (errors don't break workflows) +- Real-world testing via 50+ GitHub issues and fixes + +--- + +*Testing analysis: 2026-03-27*