فهرست منبع

Add test suite for subagent-driven-development skill

Two test projects for validating the skill with full end-to-end runs:
- go-fractals: 10 tasks, CLI tool with Sierpinski and Mandelbrot
- svelte-todo: 12 tasks, CRUD app with localStorage and Playwright

Each test has design.md, plan.md, and scaffold.sh. Run with:
  ./tests/subagent-driven-dev/run-test.sh go-fractals
Jesse Vincent 9 ماه پیش
والد
کامیت
baef5241aa

+ 81 - 0
tests/subagent-driven-dev/go-fractals/design.md

@@ -0,0 +1,81 @@
+# Go Fractals CLI - Design
+
+## Overview
+
+A command-line tool that generates ASCII art fractals. Supports two fractal types with configurable output.
+
+## Usage
+
+```bash
+# Sierpinski triangle
+fractals sierpinski --size 32 --depth 5
+
+# Mandelbrot set
+fractals mandelbrot --width 80 --height 24 --iterations 100
+
+# Custom character
+fractals sierpinski --size 16 --char '#'
+
+# Help
+fractals --help
+fractals sierpinski --help
+```
+
+## Commands
+
+### `sierpinski`
+
+Generates a Sierpinski triangle using recursive subdivision.
+
+Flags:
+- `--size` (default: 32) - Width of the triangle base in characters
+- `--depth` (default: 5) - Recursion depth
+- `--char` (default: '*') - Character to use for filled points
+
+Output: Triangle printed to stdout, one line per row.
+
+### `mandelbrot`
+
+Renders the Mandelbrot set as ASCII art. Maps iteration count to characters.
+
+Flags:
+- `--width` (default: 80) - Output width in characters
+- `--height` (default: 24) - Output height in characters
+- `--iterations` (default: 100) - Maximum iterations for escape calculation
+- `--char` (default: gradient) - Single character, or omit for gradient " .:-=+*#%@"
+
+Output: Rectangle printed to stdout.
+
+## Architecture
+
+```
+cmd/
+  fractals/
+    main.go           # Entry point, CLI setup
+internal/
+  sierpinski/
+    sierpinski.go     # Algorithm
+    sierpinski_test.go
+  mandelbrot/
+    mandelbrot.go     # Algorithm
+    mandelbrot_test.go
+  cli/
+    root.go           # Root command, help
+    sierpinski.go     # Sierpinski subcommand
+    mandelbrot.go     # Mandelbrot subcommand
+```
+
+## Dependencies
+
+- Go 1.21+
+- `github.com/spf13/cobra` for CLI
+
+## Acceptance Criteria
+
+1. `fractals --help` shows usage
+2. `fractals sierpinski` outputs a recognizable triangle
+3. `fractals mandelbrot` outputs a recognizable Mandelbrot set
+4. `--size`, `--width`, `--height`, `--depth`, `--iterations` flags work
+5. `--char` customizes output character
+6. Invalid inputs produce clear error messages
+7. All tests pass

+ 172 - 0
tests/subagent-driven-dev/go-fractals/plan.md

@@ -0,0 +1,172 @@
+# Go Fractals CLI - Implementation Plan
+
+Execute this plan using the `superpowers:subagent-driven-development` skill.
+
+## Context
+
+Building a CLI tool that generates ASCII fractals. See `design.md` for full specification.
+
+## Tasks
+
+### Task 1: Project Setup
+
+Create the Go module and directory structure.
+
+**Do:**
+- Initialize `go.mod` with module name `github.com/superpowers-test/fractals`
+- Create directory structure: `cmd/fractals/`, `internal/sierpinski/`, `internal/mandelbrot/`, `internal/cli/`
+- Create minimal `cmd/fractals/main.go` that prints "fractals cli"
+- Add `github.com/spf13/cobra` dependency
+
+**Verify:**
+- `go build ./cmd/fractals` succeeds
+- `./fractals` prints "fractals cli"
+
+---
+
+### Task 2: CLI Framework with Help
+
+Set up Cobra root command with help output.
+
+**Do:**
+- Create `internal/cli/root.go` with root command
+- Configure help text showing available subcommands
+- Wire root command into `main.go`
+
+**Verify:**
+- `./fractals --help` shows usage with "sierpinski" and "mandelbrot" listed as available commands
+- `./fractals` (no args) shows help
+
+---
+
+### Task 3: Sierpinski Algorithm
+
+Implement the Sierpinski triangle generation algorithm.
+
+**Do:**
+- Create `internal/sierpinski/sierpinski.go`
+- Implement `Generate(size, depth int, char rune) []string` that returns lines of the triangle
+- Use recursive midpoint subdivision algorithm
+- Create `internal/sierpinski/sierpinski_test.go` with tests:
+  - Small triangle (size=4, depth=2) matches expected output
+  - Size=1 returns single character
+  - Depth=0 returns filled triangle
+
+**Verify:**
+- `go test ./internal/sierpinski/...` passes
+
+---
+
+### Task 4: Sierpinski CLI Integration
+
+Wire the Sierpinski algorithm to a CLI subcommand.
+
+**Do:**
+- Create `internal/cli/sierpinski.go` with `sierpinski` subcommand
+- Add flags: `--size` (default 32), `--depth` (default 5), `--char` (default '*')
+- Call `sierpinski.Generate()` and print result to stdout
+
+**Verify:**
+- `./fractals sierpinski` outputs a triangle
+- `./fractals sierpinski --size 16 --depth 3` outputs smaller triangle
+- `./fractals sierpinski --help` shows flag documentation
+
+---
+
+### Task 5: Mandelbrot Algorithm
+
+Implement the Mandelbrot set ASCII renderer.
+
+**Do:**
+- Create `internal/mandelbrot/mandelbrot.go`
+- Implement `Render(width, height, maxIter int, char string) []string`
+- Map complex plane region (-2.5 to 1.0 real, -1.0 to 1.0 imaginary) to output dimensions
+- Map iteration count to character gradient " .:-=+*#%@" (or single char if provided)
+- Create `internal/mandelbrot/mandelbrot_test.go` with tests:
+  - Output dimensions match requested width/height
+  - Known point inside set (0,0) maps to max-iteration character
+  - Known point outside set (2,0) maps to low-iteration character
+
+**Verify:**
+- `go test ./internal/mandelbrot/...` passes
+
+---
+
+### Task 6: Mandelbrot CLI Integration
+
+Wire the Mandelbrot algorithm to a CLI subcommand.
+
+**Do:**
+- Create `internal/cli/mandelbrot.go` with `mandelbrot` subcommand
+- Add flags: `--width` (default 80), `--height` (default 24), `--iterations` (default 100), `--char` (default "")
+- Call `mandelbrot.Render()` and print result to stdout
+
+**Verify:**
+- `./fractals mandelbrot` outputs recognizable Mandelbrot set
+- `./fractals mandelbrot --width 40 --height 12` outputs smaller version
+- `./fractals mandelbrot --help` shows flag documentation
+
+---
+
+### Task 7: Character Set Configuration
+
+Ensure `--char` flag works consistently across both commands.
+
+**Do:**
+- Verify Sierpinski `--char` flag passes character to algorithm
+- For Mandelbrot, `--char` should use single character instead of gradient
+- Add tests for custom character output
+
+**Verify:**
+- `./fractals sierpinski --char '#'` uses '#' character
+- `./fractals mandelbrot --char '.'` uses '.' for all filled points
+- Tests pass
+
+---
+
+### Task 8: Input Validation and Error Handling
+
+Add validation for invalid inputs.
+
+**Do:**
+- Sierpinski: size must be > 0, depth must be >= 0
+- Mandelbrot: width/height must be > 0, iterations must be > 0
+- Return clear error messages for invalid inputs
+- Add tests for error cases
+
+**Verify:**
+- `./fractals sierpinski --size 0` prints error, exits non-zero
+- `./fractals mandelbrot --width -1` prints error, exits non-zero
+- Error messages are clear and helpful
+
+---
+
+### Task 9: Integration Tests
+
+Add integration tests that invoke the CLI.
+
+**Do:**
+- Create `cmd/fractals/main_test.go` or `test/integration_test.go`
+- Test full CLI invocation for both commands
+- Verify output format and exit codes
+- Test error cases return non-zero exit
+
+**Verify:**
+- `go test ./...` passes all tests including integration tests
+
+---
+
+### Task 10: README
+
+Document usage and examples.
+
+**Do:**
+- Create `README.md` with:
+  - Project description
+  - Installation: `go install ./cmd/fractals`
+  - Usage examples for both commands
+  - Example output (small samples)
+
+**Verify:**
+- README accurately describes the tool
+- Examples in README actually work

+ 28 - 0
tests/subagent-driven-dev/go-fractals/scaffold.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+# Scaffold the Go Fractals test project
+# Usage: ./scaffold.sh /path/to/target/directory
+
+set -e
+
+TARGET_DIR="${1:?Usage: $0 <target-directory>}"
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+
+# Create target directory
+mkdir -p "$TARGET_DIR"
+cd "$TARGET_DIR"
+
+# Initialize git repo
+git init
+
+# Copy design and plan
+cp "$SCRIPT_DIR/design.md" .
+cp "$SCRIPT_DIR/plan.md" .
+
+# Create initial commit
+git add .
+git commit -m "Initial project setup with design and plan"
+
+echo "Scaffolded Go Fractals project at: $TARGET_DIR"
+echo ""
+echo "To run the test:"
+echo "  claude -p \"Execute this plan using superpowers:subagent-driven-development. Plan: $TARGET_DIR/plan.md\" --plugin-dir /path/to/superpowers"

+ 102 - 0
tests/subagent-driven-dev/run-test.sh

@@ -0,0 +1,102 @@
+#!/bin/bash
+# Run a subagent-driven-development test
+# Usage: ./run-test.sh <test-name> [--plugin-dir <path>]
+#
+# Example:
+#   ./run-test.sh go-fractals
+#   ./run-test.sh svelte-todo --plugin-dir /path/to/superpowers
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+TEST_NAME="${1:?Usage: $0 <test-name> [--plugin-dir <path>]}"
+shift
+
+# Parse optional arguments
+PLUGIN_DIR=""
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --plugin-dir)
+      PLUGIN_DIR="$2"
+      shift 2
+      ;;
+    *)
+      echo "Unknown option: $1"
+      exit 1
+      ;;
+  esac
+done
+
+# Default plugin dir to parent of tests directory
+if [[ -z "$PLUGIN_DIR" ]]; then
+  PLUGIN_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
+fi
+
+# Verify test exists
+TEST_DIR="$SCRIPT_DIR/$TEST_NAME"
+if [[ ! -d "$TEST_DIR" ]]; then
+  echo "Error: Test '$TEST_NAME' not found at $TEST_DIR"
+  echo "Available tests:"
+  ls -1 "$SCRIPT_DIR" | grep -v '\.sh$' | grep -v '\.md$'
+  exit 1
+fi
+
+# Create timestamped output directory
+TIMESTAMP=$(date +%s)
+OUTPUT_BASE="/tmp/superpowers-tests/$TIMESTAMP/subagent-driven-development"
+OUTPUT_DIR="$OUTPUT_BASE/$TEST_NAME"
+mkdir -p "$OUTPUT_DIR"
+
+echo "=== Subagent-Driven Development Test ==="
+echo "Test: $TEST_NAME"
+echo "Output: $OUTPUT_DIR"
+echo "Plugin: $PLUGIN_DIR"
+echo ""
+
+# Scaffold the project
+echo ">>> Scaffolding project..."
+"$TEST_DIR/scaffold.sh" "$OUTPUT_DIR/project"
+echo ""
+
+# Prepare the prompt
+PLAN_PATH="$OUTPUT_DIR/project/plan.md"
+PROMPT="Execute this plan using superpowers:subagent-driven-development. The plan is at: $PLAN_PATH"
+
+# Run Claude with JSON output for token tracking
+LOG_FILE="$OUTPUT_DIR/claude-output.json"
+echo ">>> Running Claude..."
+echo "Prompt: $PROMPT"
+echo "Log file: $LOG_FILE"
+echo ""
+
+# Run claude and capture output
+# Using stream-json to get token usage stats
+claude -p "$PROMPT" \
+  --plugin-dir "$PLUGIN_DIR" \
+  --output-format stream-json \
+  > "$LOG_FILE" 2>&1 || true
+
+# Extract final stats
+echo ""
+echo ">>> Test complete"
+echo "Project directory: $OUTPUT_DIR/project"
+echo "Claude log: $LOG_FILE"
+echo ""
+
+# Show token usage if available
+if command -v jq &> /dev/null; then
+  echo ">>> Token usage:"
+  # Extract usage from the last message with usage info
+  jq -s '[.[] | select(.type == "result")] | last | .usage' "$LOG_FILE" 2>/dev/null || echo "(could not parse usage)"
+  echo ""
+fi
+
+echo ">>> Next steps:"
+echo "1. Review the project: cd $OUTPUT_DIR/project"
+echo "2. Review Claude's log: less $LOG_FILE"
+echo "3. Check if tests pass:"
+if [[ "$TEST_NAME" == "go-fractals" ]]; then
+  echo "   cd $OUTPUT_DIR/project && go test ./..."
+elif [[ "$TEST_NAME" == "svelte-todo" ]]; then
+  echo "   cd $OUTPUT_DIR/project && npm test && npx playwright test"
+fi

+ 70 - 0
tests/subagent-driven-dev/svelte-todo/design.md

@@ -0,0 +1,70 @@
+# Svelte Todo List - Design
+
+## Overview
+
+A simple todo list application built with Svelte. Supports creating, completing, and deleting todos with localStorage persistence.
+
+## Features
+
+- Add new todos
+- Mark todos as complete/incomplete
+- Delete todos
+- Filter by: All / Active / Completed
+- Clear all completed todos
+- Persist to localStorage
+- Show count of remaining items
+
+## User Interface
+
+```
+┌─────────────────────────────────────────┐
+│  Svelte Todos                           │
+├─────────────────────────────────────────┤
+│  [________________________] [Add]       │
+├─────────────────────────────────────────┤
+│  [ ] Buy groceries                  [x] │
+│  [✓] Walk the dog                   [x] │
+│  [ ] Write code                     [x] │
+├─────────────────────────────────────────┤
+│  2 items left                           │
+│  [All] [Active] [Completed]  [Clear ✓]  │
+└─────────────────────────────────────────┘
+```
+
+## Components
+
+```
+src/
+  App.svelte           # Main app, state management
+  lib/
+    TodoInput.svelte   # Text input + Add button
+    TodoList.svelte    # List container
+    TodoItem.svelte    # Single todo with checkbox, text, delete
+    FilterBar.svelte   # Filter buttons + clear completed
+    store.ts           # Svelte store for todos
+    storage.ts         # localStorage persistence
+```
+
+## Data Model
+
+```typescript
+interface Todo {
+  id: string;        // UUID
+  text: string;      // Todo text
+  completed: boolean;
+}
+
+type Filter = 'all' | 'active' | 'completed';
+```
+
+## Acceptance Criteria
+
+1. Can add a todo by typing and pressing Enter or clicking Add
+2. Can toggle todo completion by clicking checkbox
+3. Can delete a todo by clicking X button
+4. Filter buttons show correct subset of todos
+5. "X items left" shows count of incomplete todos
+6. "Clear completed" removes all completed todos
+7. Todos persist across page refresh (localStorage)
+8. Empty state shows helpful message
+9. All tests pass

+ 222 - 0
tests/subagent-driven-dev/svelte-todo/plan.md

@@ -0,0 +1,222 @@
+# Svelte Todo List - Implementation Plan
+
+Execute this plan using the `superpowers:subagent-driven-development` skill.
+
+## Context
+
+Building a todo list app with Svelte. See `design.md` for full specification.
+
+## Tasks
+
+### Task 1: Project Setup
+
+Create the Svelte project with Vite.
+
+**Do:**
+- Run `npm create vite@latest . -- --template svelte-ts`
+- Install dependencies with `npm install`
+- Verify dev server works
+- Clean up default Vite template content from App.svelte
+
+**Verify:**
+- `npm run dev` starts server
+- App shows minimal "Svelte Todos" heading
+- `npm run build` succeeds
+
+---
+
+### Task 2: Todo Store
+
+Create the Svelte store for todo state management.
+
+**Do:**
+- Create `src/lib/store.ts`
+- Define `Todo` interface with id, text, completed
+- Create writable store with initial empty array
+- Export functions: `addTodo(text)`, `toggleTodo(id)`, `deleteTodo(id)`, `clearCompleted()`
+- Create `src/lib/store.test.ts` with tests for each function
+
+**Verify:**
+- Tests pass: `npm run test` (install vitest if needed)
+
+---
+
+### Task 3: localStorage Persistence
+
+Add persistence layer for todos.
+
+**Do:**
+- Create `src/lib/storage.ts`
+- Implement `loadTodos(): Todo[]` and `saveTodos(todos: Todo[])`
+- Handle JSON parse errors gracefully (return empty array)
+- Integrate with store: load on init, save on change
+- Add tests for load/save/error handling
+
+**Verify:**
+- Tests pass
+- Manual test: add todo, refresh page, todo persists
+
+---
+
+### Task 4: TodoInput Component
+
+Create the input component for adding todos.
+
+**Do:**
+- Create `src/lib/TodoInput.svelte`
+- Text input bound to local state
+- Add button calls `addTodo()` and clears input
+- Enter key also submits
+- Disable Add button when input is empty
+- Add component tests
+
+**Verify:**
+- Tests pass
+- Component renders input and button
+
+---
+
+### Task 5: TodoItem Component
+
+Create the single todo item component.
+
+**Do:**
+- Create `src/lib/TodoItem.svelte`
+- Props: `todo: Todo`
+- Checkbox toggles completion (calls `toggleTodo`)
+- Text with strikethrough when completed
+- Delete button (X) calls `deleteTodo`
+- Add component tests
+
+**Verify:**
+- Tests pass
+- Component renders checkbox, text, delete button
+
+---
+
+### Task 6: TodoList Component
+
+Create the list container component.
+
+**Do:**
+- Create `src/lib/TodoList.svelte`
+- Props: `todos: Todo[]`
+- Renders TodoItem for each todo
+- Shows "No todos yet" when empty
+- Add component tests
+
+**Verify:**
+- Tests pass
+- Component renders list of TodoItems
+
+---
+
+### Task 7: FilterBar Component
+
+Create the filter and status bar component.
+
+**Do:**
+- Create `src/lib/FilterBar.svelte`
+- Props: `todos: Todo[]`, `filter: Filter`, `onFilterChange: (f: Filter) => void`
+- Show count: "X items left" (incomplete count)
+- Three filter buttons: All, Active, Completed
+- Active filter is visually highlighted
+- "Clear completed" button (hidden when no completed todos)
+- Add component tests
+
+**Verify:**
+- Tests pass
+- Component renders count, filters, clear button
+
+---
+
+### Task 8: App Integration
+
+Wire all components together in App.svelte.
+
+**Do:**
+- Import all components and store
+- Add filter state (default: 'all')
+- Compute filtered todos based on filter state
+- Render: heading, TodoInput, TodoList, FilterBar
+- Pass appropriate props to each component
+
+**Verify:**
+- App renders all components
+- Adding todos works
+- Toggling works
+- Deleting works
+
+---
+
+### Task 9: Filter Functionality
+
+Ensure filtering works end-to-end.
+
+**Do:**
+- Verify filter buttons change displayed todos
+- 'all' shows all todos
+- 'active' shows only incomplete todos
+- 'completed' shows only completed todos
+- Clear completed removes completed todos and resets filter if needed
+- Add integration tests
+
+**Verify:**
+- Filter tests pass
+- Manual verification of all filter states
+
+---
+
+### Task 10: Styling and Polish
+
+Add CSS styling for usability.
+
+**Do:**
+- Style the app to match the design mockup
+- Completed todos have strikethrough and muted color
+- Active filter button is highlighted
+- Input has focus styles
+- Delete button appears on hover (or always on mobile)
+- Responsive layout
+
+**Verify:**
+- App is visually usable
+- Styles don't break functionality
+
+---
+
+### Task 11: End-to-End Tests
+
+Add Playwright tests for full user flows.
+
+**Do:**
+- Install Playwright: `npm init playwright@latest`
+- Create `tests/todo.spec.ts`
+- Test flows:
+  - Add a todo
+  - Complete a todo
+  - Delete a todo
+  - Filter todos
+  - Clear completed
+  - Persistence (add, reload, verify)
+
+**Verify:**
+- `npx playwright test` passes
+
+---
+
+### Task 12: README
+
+Document the project.
+
+**Do:**
+- Create `README.md` with:
+  - Project description
+  - Setup: `npm install`
+  - Development: `npm run dev`
+  - Testing: `npm test` and `npx playwright test`
+  - Build: `npm run build`
+
+**Verify:**
+- README accurately describes the project
+- Instructions work

+ 28 - 0
tests/subagent-driven-dev/svelte-todo/scaffold.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+# Scaffold the Svelte Todo test project
+# Usage: ./scaffold.sh /path/to/target/directory
+
+set -e
+
+TARGET_DIR="${1:?Usage: $0 <target-directory>}"
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+
+# Create target directory
+mkdir -p "$TARGET_DIR"
+cd "$TARGET_DIR"
+
+# Initialize git repo
+git init
+
+# Copy design and plan
+cp "$SCRIPT_DIR/design.md" .
+cp "$SCRIPT_DIR/plan.md" .
+
+# Create initial commit
+git add .
+git commit -m "Initial project setup with design and plan"
+
+echo "Scaffolded Svelte Todo project at: $TARGET_DIR"
+echo ""
+echo "To run the test:"
+echo "  claude -p \"Execute this plan using superpowers:subagent-driven-development. Plan: $TARGET_DIR/plan.md\" --plugin-dir /path/to/superpowers"