diff --git a/.changeset/auto-b2febcaa83c70990.md b/.changeset/auto-b2febcaa83c70990.md new file mode 100644 index 0000000..12dd8ec --- /dev/null +++ b/.changeset/auto-b2febcaa83c70990.md @@ -0,0 +1,9 @@ +--- +"ketchup": minor +--- + +- Rebranded the project to Ketchup, renaming the package, plugin, slash commands, data directory (.ketchup), and all documentation +- Switched to plugin-only installation via the marketplace, removing the legacy npx CLI, install/doctor/repair commands, and symlink setup +- Added automatic migration so existing setups upgrade in place, moving the data directory, state file, and deny-list to their new .ketchup locations +- Removed the auto-continue feature in favor of parallel sub-agent planning, with config and docs updated to match +- Added runtime configuration for validators and reminders, plus a config skill and first-setup guidance diff --git a/TODO.md b/TODO.md index 35df3a5..8df759b 100644 --- a/TODO.md +++ b/TODO.md @@ -6,4 +6,3 @@ cjs for auto-engineer <<< look into this http server do not give reminders to validator subagents -do not run auto continue for validator subagents (also otehr lifecycle hooks) diff --git a/dist/bundle/scripts/config.js b/dist/bundle/scripts/config.js index 3bd68eb..a8279d8 100755 --- a/dist/bundle/scripts/config.js +++ b/dist/bundle/scripts/config.js @@ -3845,7 +3845,7 @@ function usage() { Subcommands: show Show all current configuration - set Set a config value (e.g., autoContinue.mode off) + set Set a config value (e.g., validateCommit.mode off) validators List all validators with status validators enable Enable a validator validators disable Disable a validator diff --git a/docs/architecture.md b/docs/architecture.md index a1ebbfa..fb496ff 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -280,44 +280,6 @@ if (subagentType === 'work' && state.validateCommitOnWork) { --- -## Clue Collection - -The clue collector analyzes Claude transcripts for continuation signals. - -``` -transcript.jsonl - │ - ▼ -┌─────────────────────────┐ -│ Parse JSONL lines │ -│ Extract entries │ -└──────────┬──────────────┘ - │ - ├─────────────────────────────────────────┐ - │ │ - ▼ ▼ -┌─────────────────────────┐ ┌─────────────────────────┐ -│ Pattern Detection │ │ Metadata Extraction │ -│ ├─► CONTINUE_PATTERNS │ │ ├─► ketchup-plan paths │ -│ ├─► ketchup mentions │ │ ├─► working directories │ -│ └─► plan mentions │ │ └─► current cwd │ -└──────────┬──────────────┘ └──────────┬──────────────┘ - │ │ - └─────────────┬───────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ ClueCollectorResult │ -│ ├─► clues: Array Detected patterns │ -│ ├─► lastChats: Array Last 5 exchanges │ -│ ├─► ketchupPlanPaths Found plan files │ -│ ├─► workingDirs Detected directories │ -│ └─► summary: string Human-readable summary │ -└─────────────────────────────────────────────────────────────┘ -``` - ---- - ## Directory Structure ### Plugin Structure @@ -335,7 +297,6 @@ ketchup/ │ ├── debug-logger.ts Debug output (internal) │ ├── clean-logs.ts Log cleanup (internal) │ ├── subagent-classifier.ts Task classification (internal) -│ ├── clue-collector.ts Transcript analysis (internal) │ │ │ └── hooks/ │ ├── session-start.ts SessionStart handler @@ -439,8 +400,7 @@ Unit Tests (vitest) ├── Deny-list (load patterns, match files) ├── Hook state (read, write, update) ├── Subagent classifier (patterns, extraction) -├── Path resolver (environment-based resolution) -└── Clue collector (transcript analysis) +└── Path resolver (environment-based resolution) E2E Tests (scripts/test-hooks.sh) ├── Deny-list blocking diff --git a/docs/getting-started.md b/docs/getting-started.md index 0b004b4..12eb842 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -50,7 +50,7 @@ This creates `.ketchup/` with default configuration. Then verify: /ketchup:config show ``` -Ketchup is now active with commit validation, reminders, deny-lists, and auto-continue. +Ketchup is now active with commit validation, reminders, and deny-lists. --- @@ -101,7 +101,6 @@ Start a Claude Code session. The supervisor will: 1. **Inject** your guidelines at session start 2. **Validate** every commit against your rules 3. **ACK** clean commits, **NACK** rule violations -4. **Auto-continue** until the plan is complete --- @@ -148,7 +147,6 @@ You installed Ketchup: | Validators | ACK/NACK every commit via LLM | PreToolUse hooks | | Reminders | Your rules, every session + prompt | SessionStart + prompt | | Deny-list | Structural file protection | PreToolUse deny-list | -| Auto-Continue | Agent keeps working while plan has work | Stop hooks | | TCR gate | `test && commit revert` enforced | TCR Workflow validator | --- diff --git a/scripts/config.ts b/scripts/config.ts index f6210b3..db06501 100644 --- a/scripts/config.ts +++ b/scripts/config.ts @@ -28,7 +28,7 @@ function usage(): string { Subcommands: show Show all current configuration - set Set a config value (e.g., autoContinue.mode off) + set Set a config value (e.g., validateCommit.mode off) validators List all validators with status validators enable Enable a validator validators disable Disable a validator diff --git a/scripts/test-hooks.sh b/scripts/test-hooks.sh index 19a57d4..5f94008 100755 --- a/scripts/test-hooks.sh +++ b/scripts/test-hooks.sh @@ -18,147 +18,6 @@ pass() { echo -e "${GREEN}✓${NC} $1"; ((PASSED++)) || true; } fail() { echo -e "${RED}✗${NC} $1: $2"; ((FAILED++)) || true; } skip() { echo -e "${YELLOW}○${NC} $1 (skipped)"; } -#----------------------------------------------------------- -# Test: auto-continue respects mode=off (no transcript needed) -#----------------------------------------------------------- -test_autocontinue_mode_off() { - local name="auto-continue respects mode=off" - - # Backup current state - local state_file="$PROJECT_ROOT/.claude.hooks.json" - local backup="" - if [[ -f "$state_file" ]]; then - backup=$(cat "$state_file") - fi - - # Set mode to off - echo '{"autoContinue":{"mode":"off"}}' > "$state_file" - - local input='{"session_id":"test-off","permission_mode":"code"}' - - cd "$PROJECT_ROOT" - local output - output=$(echo "$input" | npx tsx "$PROJECT_ROOT/.claude/scripts/auto-continue.ts" 2>/dev/null) || true - - # Restore state - if [[ -n "$backup" ]]; then - echo "$backup" > "$state_file" - else - rm -f "$state_file" - fi - - if echo "$output" | grep -q '"decision":"block"'; then - fail "$name" "should not block when mode=off" - else - pass "$name" - fi -} - -#----------------------------------------------------------- -# Test: auto-continue skips plan permission mode -#----------------------------------------------------------- -test_autocontinue_skips_plan_mode() { - local name="auto-continue skips plan permission mode" - - # Backup current state - local state_file="$PROJECT_ROOT/.claude.hooks.json" - local backup="" - if [[ -f "$state_file" ]]; then - backup=$(cat "$state_file") - fi - - # Set mode to smart (but plan mode should be skipped) - echo '{"autoContinue":{"mode":"smart"}}' > "$state_file" - - # permission_mode="plan" should be skipped by default - local input='{"session_id":"test-plan","permission_mode":"plan"}' - - cd "$PROJECT_ROOT" - local output - output=$(echo "$input" | npx tsx "$PROJECT_ROOT/.claude/scripts/auto-continue.ts" 2>/dev/null) || true - - # Restore state - if [[ -n "$backup" ]]; then - echo "$backup" > "$state_file" - else - rm -f "$state_file" - fi - - if echo "$output" | grep -q '"decision":"block"'; then - fail "$name" "should skip plan mode" - else - pass "$name" - fi -} - -#----------------------------------------------------------- -# Test: non-stop mode blocks and counts iterations -#----------------------------------------------------------- -test_autocontinue_nonstop_iterations() { - local name="auto-continue non-stop mode counts iterations" - - # Backup current state - local state_file="$PROJECT_ROOT/.claude.hooks.json" - local backup="" - if [[ -f "$state_file" ]]; then - backup=$(cat "$state_file") - fi - - # Set non-stop mode with limit of 2 - echo '{"autoContinue":{"mode":"non-stop","maxIterations":2,"iteration":0}}' > "$state_file" - - local input='{"session_id":"test-nonstop","permission_mode":"code"}' - - cd "$PROJECT_ROOT" - - # First call: should block and increment - local output1 - output1=$(echo "$input" | npx tsx "$PROJECT_ROOT/.claude/scripts/auto-continue.ts" 2>/dev/null) - - if ! echo "$output1" | grep -q '"decision":"block"'; then - # Restore state - if [[ -n "$backup" ]]; then - echo "$backup" > "$state_file" - else - rm -f "$state_file" - fi - fail "$name" "iteration 1 should block" - return - fi - - # Second call: should block again - local output2 - output2=$(echo "$input" | npx tsx "$PROJECT_ROOT/.claude/scripts/auto-continue.ts" 2>/dev/null) - - if ! echo "$output2" | grep -q '"decision":"block"'; then - # Restore state - if [[ -n "$backup" ]]; then - echo "$backup" > "$state_file" - else - rm -f "$state_file" - fi - fail "$name" "iteration 2 should block" - return - fi - - # Third call: should allow (maxIterations reached) - local output3 - output3=$(echo "$input" | npx tsx "$PROJECT_ROOT/.claude/scripts/auto-continue.ts" 2>/dev/null) || true - - # Restore state - if [[ -n "$backup" ]]; then - echo "$backup" > "$state_file" - else - rm -f "$state_file" - fi - - if echo "$output3" | grep -q '"decision":"block"'; then - fail "$name" "iteration 3 should allow (limit reached)" - else - pass "$name" - fi -} - #----------------------------------------------------------- # Test: deny-list denies paths on deny list #----------------------------------------------------------- @@ -329,124 +188,6 @@ test_subagent_inherits_denylist() { fi } -#----------------------------------------------------------- -# Test: sub-agent state modifications persist -#----------------------------------------------------------- -test_subagent_state_persists() { - local name="sub-agent state modifications persist" - - # Backup current state - local state_file="$PROJECT_ROOT/.claude.hooks.json" - local backup="" - if [[ -f "$state_file" ]]; then - backup=$(cat "$state_file") - fi - - # Set initial state with iteration=5 - echo '{"autoContinue":{"mode":"non-stop","maxIterations":10,"iteration":5}}' > "$state_file" - - # Simulate a sub-agent call that would increment iteration - # (non-stop mode increments on each block) - local input='{"session_id":"subagent-test","permission_mode":"code"}' - - cd "$PROJECT_ROOT" - echo "$input" | npx tsx "$PROJECT_ROOT/.claude/scripts/auto-continue.ts" 2>/dev/null || true - - # Read back the state - iteration should now be 6 - local new_state - new_state=$(cat "$state_file") - - # Restore original state - if [[ -n "$backup" ]]; then - echo "$backup" > "$state_file" - else - rm -f "$state_file" - fi - - if echo "$new_state" | grep -q '"iteration": 6'; then - pass "$name" - else - fail "$name" "state should persist iteration increment, got: $new_state" - fi -} - -#----------------------------------------------------------- -# Test: sub-agent respects skipModes configuration -#----------------------------------------------------------- -test_subagent_respects_skipmodes() { - local name="sub-agent respects custom skipModes" - - # Backup current state - local state_file="$PROJECT_ROOT/.claude.hooks.json" - local backup="" - if [[ -f "$state_file" ]]; then - backup=$(cat "$state_file") - fi - - # Set mode to non-stop but add "explore" to skipModes - # This simulates skipping auto-continue for explore sub-agents - echo '{"autoContinue":{"mode":"non-stop","skipModes":["plan","explore"]}}' > "$state_file" - - # Simulate a sub-agent with permission_mode="explore" - local input='{"session_id":"explore-agent","permission_mode":"explore"}' - - cd "$PROJECT_ROOT" - local output - output=$(echo "$input" | npx tsx "$PROJECT_ROOT/.claude/scripts/auto-continue.ts" 2>/dev/null) || true - - # Restore state - if [[ -n "$backup" ]]; then - echo "$backup" > "$state_file" - else - rm -f "$state_file" - fi - - # Should NOT block because "explore" is in skipModes - if echo "$output" | grep -q '"decision":"block"'; then - fail "$name" "should skip auto-continue for explore permission_mode" - else - pass "$name" - fi -} - -#----------------------------------------------------------- -# Test: sub-agent non-skipped mode still blocks -#----------------------------------------------------------- -test_subagent_nonskipped_blocks() { - local name="sub-agent non-skipped mode blocks correctly" - - # Backup current state - local state_file="$PROJECT_ROOT/.claude.hooks.json" - local backup="" - if [[ -f "$state_file" ]]; then - backup=$(cat "$state_file") - fi - - # Set mode to non-stop with only "plan" in skipModes - echo '{"autoContinue":{"mode":"non-stop","maxIterations":10,"skipModes":["plan"]}}' > "$state_file" - - # Simulate a sub-agent with permission_mode="code" (NOT in skipModes) - local input='{"session_id":"code-agent","permission_mode":"code"}' - - cd "$PROJECT_ROOT" - local output - output=$(echo "$input" | npx tsx "$PROJECT_ROOT/.claude/scripts/auto-continue.ts" 2>/dev/null) || true - - # Restore state - if [[ -n "$backup" ]]; then - echo "$backup" > "$state_file" - else - rm -f "$state_file" - fi - - # SHOULD block because "code" is not in skipModes - if echo "$output" | grep -q '"decision":"block"'; then - pass "$name" - else - fail "$name" "should block for non-skipped permission_mode" - fi -} - #----------------------------------------------------------- # Test: subagent-classifier classifies explore tasks #----------------------------------------------------------- @@ -872,9 +613,6 @@ echo "Running hook E2E tests..." echo "" echo "=== Basic Hook Tests ===" -test_autocontinue_mode_off -test_autocontinue_skips_plan_mode -test_autocontinue_nonstop_iterations test_denylist_denies test_denylist_allows_normal test_prompt_reminder_returns_context @@ -882,9 +620,6 @@ test_prompt_reminder_returns_context echo "" echo "=== Sub-Agent Hook Tests ===" test_subagent_inherits_denylist -test_subagent_state_persists -test_subagent_respects_skipmodes -test_subagent_nonskipped_blocks echo "" echo "=== Sub-Agent Classification Tests ==="