claude-raid 0.1.7 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +13 -1
- package/package.json +1 -1
- package/src/descriptions.js +26 -24
- package/src/init.js +6 -10
- package/src/merge-settings.js +0 -15
- package/src/remove.js +18 -16
- package/src/ui.js +1 -1
- package/src/update.js +28 -13
- package/template/.claude/agents/archer.md +10 -20
- package/template/.claude/agents/rogue.md +11 -21
- package/template/.claude/agents/warrior.md +8 -19
- package/template/.claude/agents/wizard.md +14 -247
- package/template/.claude/dungeon-master-rules.md +210 -0
- package/template/.claude/hooks/raid-lib.sh +29 -2
- package/template/.claude/hooks/raid-pre-compact.sh +12 -1
- package/template/.claude/hooks/raid-session-end.sh +23 -13
- package/template/.claude/hooks/raid-session-start.sh +21 -3
- package/template/.claude/hooks/validate-commit.sh +7 -74
- package/template/.claude/hooks/validate-dungeon.sh +30 -11
- package/template/.claude/hooks/validate-no-placeholders.sh +3 -3
- package/template/.claude/hooks/validate-write-gate.sh +45 -63
- package/template/.claude/{raid-rules.md → party-rules.md} +38 -13
- package/template/.claude/skills/raid-browser-chrome/SKILL.md +1 -1
- package/template/.claude/skills/{raid-design → raid-canonical-design}/SKILL.md +52 -16
- package/template/.claude/skills/{raid-implementation → raid-canonical-implementation}/SKILL.md +41 -14
- package/template/.claude/skills/{raid-implementation-plan → raid-canonical-implementation-plan}/SKILL.md +49 -17
- package/template/.claude/skills/raid-canonical-prd/SKILL.md +133 -0
- package/template/.claude/skills/raid-canonical-protocol/SKILL.md +211 -0
- package/template/.claude/skills/{raid-review → raid-canonical-review}/SKILL.md +78 -17
- package/template/.claude/skills/raid-debugging/SKILL.md +30 -5
- package/template/.claude/skills/raid-init/SKILL.md +130 -0
- package/template/.claude/skills/raid-tdd/SKILL.md +1 -1
- package/template/.claude/skills/raid-wrap-up/SKILL.md +184 -0
- package/template/.claude/hooks/raid-stop.sh +0 -20
- package/template/.claude/hooks/raid-task-completed.sh +0 -42
- package/template/.claude/hooks/validate-bash-writes.sh +0 -157
- package/template/.claude/skills/raid-browser-playwright/SKILL.md +0 -163
- package/template/.claude/skills/raid-finishing/SKILL.md +0 -140
- package/template/.claude/skills/raid-git-worktrees/SKILL.md +0 -96
- package/template/.claude/skills/raid-protocol/SKILL.md +0 -337
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: raid-wrap-up
|
|
3
|
+
description: "Phase 6 of Canonical Quest. Generates quest storyboard report, creates PR, archives dungeon to vault, dismisses party. No new code."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Raid Wrap Up — Phase 6
|
|
7
|
+
|
|
8
|
+
The quest ends. The bard sings the tale. The treasure is committed. The party rests.
|
|
9
|
+
|
|
10
|
+
<HARD-GATE>
|
|
11
|
+
Do NOT write new code. This phase is about reporting, cleanup, PR creation, and archival. Agents are dismissed, not dispatched.
|
|
12
|
+
</HARD-GATE>
|
|
13
|
+
|
|
14
|
+
## Mode Behavior
|
|
15
|
+
|
|
16
|
+
- **Full Raid**: Wizard writes full storyboard from all phase files. Full PR with narrative.
|
|
17
|
+
- **Skirmish**: Wizard writes condensed storyboard. Standard PR.
|
|
18
|
+
- **Scout**: Wizard writes brief summary. Quick PR.
|
|
19
|
+
|
|
20
|
+
## Process Flow
|
|
21
|
+
|
|
22
|
+
```dot
|
|
23
|
+
digraph wrapup {
|
|
24
|
+
"Wizard updates phase to wrap-up" -> "Create phase-6-wrap-up.md";
|
|
25
|
+
"Create phase-6-wrap-up.md" -> "Write phase-by-phase storyboard";
|
|
26
|
+
"Write phase-by-phase storyboard" -> "Cleanup temp files";
|
|
27
|
+
"Cleanup temp files" -> "Verify all tests pass (fresh run)";
|
|
28
|
+
"Verify all tests pass (fresh run)" -> "Tests pass?" [shape=diamond];
|
|
29
|
+
"Tests pass?" -> "Fix first. Do not proceed." [label="no"];
|
|
30
|
+
"Fix first. Do not proceed." -> "Verify all tests pass (fresh run)";
|
|
31
|
+
"Tests pass?" -> "Present merge options" [label="yes"];
|
|
32
|
+
"Present merge options" -> "Human chooses";
|
|
33
|
+
"Human chooses" -> "Execute choice";
|
|
34
|
+
"Execute choice" -> "Dismiss party";
|
|
35
|
+
"Dismiss party" -> "Archive to vault";
|
|
36
|
+
"Archive to vault" -> "Final commit + cleanup" [shape=doublecircle];
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Wizard Checklist
|
|
41
|
+
|
|
42
|
+
1. **Update raid-session** — set phase to `"wrap-up"`
|
|
43
|
+
2. **Create storyboard** — `{questDir}/phase-6-wrap-up.md`
|
|
44
|
+
3. **Write narrative** — phase-by-phase story from quest files
|
|
45
|
+
4. **Cleanup** — remove temp configs, debug files, stale artifacts
|
|
46
|
+
5. **Verify tests** — fresh full run, must pass
|
|
47
|
+
6. **Present options** — 4 merge choices
|
|
48
|
+
7. **Execute choice** — merge, PR, keep, or discard
|
|
49
|
+
8. **Dismiss party** — RPG flavor shutdown
|
|
50
|
+
9. **Archive** — move dungeon to vault
|
|
51
|
+
10. **Final commit** — `docs(quest-{slug}): phase 6 wrap-up — quest complete`
|
|
52
|
+
11. **Session cleanup** — remove `.claude/raid-session`
|
|
53
|
+
|
|
54
|
+
## Step 1: The Quest Storyboard
|
|
55
|
+
|
|
56
|
+
Create `{questDir}/phase-6-wrap-up.md` and write a phase-by-phase narrative:
|
|
57
|
+
|
|
58
|
+
```markdown
|
|
59
|
+
# Phase 6: Wrap Up — Quest Storyboard
|
|
60
|
+
## Quest: <quest name>
|
|
61
|
+
## Mode: <mode>
|
|
62
|
+
|
|
63
|
+
### Phase 1: PRD — Forging the Scroll
|
|
64
|
+
(if phase-1-prd.md exists)
|
|
65
|
+
- What requirements were established
|
|
66
|
+
- Key decisions from research
|
|
67
|
+
|
|
68
|
+
### Phase 2: Design — Charting the Map
|
|
69
|
+
- Architecture chosen and why
|
|
70
|
+
- Key trade-offs resolved
|
|
71
|
+
- Alternatives considered and rejected
|
|
72
|
+
|
|
73
|
+
### Phase 3: Implementation Plan — Marshaling the Forces
|
|
74
|
+
- Number of tasks, dependency structure
|
|
75
|
+
- Risk areas identified
|
|
76
|
+
|
|
77
|
+
### Phase 4: Implementation — Into the Fray
|
|
78
|
+
- What was built
|
|
79
|
+
- Challenges overcome
|
|
80
|
+
- Test coverage highlights
|
|
81
|
+
|
|
82
|
+
### Phase 5: Review — Inspecting the Treasure
|
|
83
|
+
(if phase-5-review.md exists)
|
|
84
|
+
- Findings pinned and resolved
|
|
85
|
+
- Black cards (if any)
|
|
86
|
+
- Fixes applied
|
|
87
|
+
|
|
88
|
+
### Summary
|
|
89
|
+
- Total phases completed
|
|
90
|
+
- Key achievements
|
|
91
|
+
- Known limitations
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Read all prior phase files from the quest directory to build this narrative.
|
|
95
|
+
|
|
96
|
+
## Step 2: Cleanup
|
|
97
|
+
|
|
98
|
+
Remove temporary artifacts:
|
|
99
|
+
- Debug files
|
|
100
|
+
- Temp configs
|
|
101
|
+
- Stale backups in the quest directory
|
|
102
|
+
|
|
103
|
+
## Step 3: Final Verification
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
1. IDENTIFY: test command from .claude/raid.json
|
|
107
|
+
2. RUN: Execute the FULL test suite (fresh, complete)
|
|
108
|
+
3. READ: Full output, check exit code, count failures
|
|
109
|
+
4. VERIFY: Zero failures?
|
|
110
|
+
If NO → STOP. Fix first. Do not present options.
|
|
111
|
+
If YES → Proceed with evidence.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Step 4: Present Options
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
RULING: The quest is complete and verified.
|
|
118
|
+
|
|
119
|
+
Tests: [N] passing, 0 failures (evidence: [command output])
|
|
120
|
+
|
|
121
|
+
Options:
|
|
122
|
+
1. Merge back to [base-branch] locally
|
|
123
|
+
2. Push and create a Pull Request
|
|
124
|
+
3. Keep the branch as-is (handle later)
|
|
125
|
+
4. Discard this work
|
|
126
|
+
|
|
127
|
+
Which option?
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**For option 2 (PR):** Create the PR with:
|
|
131
|
+
- **Title**: Descriptive, includes quest name
|
|
132
|
+
- **Body**: The phase-by-phase storyboard from the wrap-up doc
|
|
133
|
+
|
|
134
|
+
## Step 5: Execute
|
|
135
|
+
|
|
136
|
+
| Option | Actions |
|
|
137
|
+
|--------|---------|
|
|
138
|
+
| **1. Merge** | Checkout base -> pull -> merge -> run tests on merged result -> delete branch -> clean up |
|
|
139
|
+
| **2. PR** | Push with -u -> create PR via gh with storyboard body -> clean up |
|
|
140
|
+
| **3. Keep** | Report branch location. Done. |
|
|
141
|
+
| **4. Discard** | Require typed "discard" confirmation -> delete branch (force) -> clean up |
|
|
142
|
+
|
|
143
|
+
## Step 6: Dismiss the Party
|
|
144
|
+
|
|
145
|
+
Send shutdown to all teammates with RPG flavor:
|
|
146
|
+
|
|
147
|
+
> "The quest is done, brave engineers. The bards will sing of **{quest-name}**. Sheathe your tools — until the next adventure."
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
SendMessage(to="warrior", message={"type": "shutdown_request"})
|
|
151
|
+
SendMessage(to="archer", message={"type": "shutdown_request"})
|
|
152
|
+
SendMessage(to="rogue", message={"type": "shutdown_request"})
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Step 7: Archive to Vault
|
|
156
|
+
|
|
157
|
+
1. Move quest directory to vault:
|
|
158
|
+
```
|
|
159
|
+
mv .claude/dungeon/{quest-slug}/ .claude/vault/{quest-slug}/
|
|
160
|
+
```
|
|
161
|
+
2. Update vault index at `.claude/vault/index.md`:
|
|
162
|
+
```
|
|
163
|
+
| {date} | [{quest-name}]({quest-slug}/quest.md) | {mode} | {tags} |
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Step 8: Final Commit & Cleanup
|
|
167
|
+
|
|
168
|
+
1. **Commit**: `docs(quest-{slug}): phase 6 wrap-up — quest complete`
|
|
169
|
+
2. **Remove**: `.claude/raid-session`
|
|
170
|
+
3. **Session is over. No further skills to load.**
|
|
171
|
+
|
|
172
|
+
## Red Flags
|
|
173
|
+
|
|
174
|
+
| Thought | Reality |
|
|
175
|
+
|---------|---------|
|
|
176
|
+
| "Tests passed earlier, no need to re-run" | Fresh run or no claim. Always. |
|
|
177
|
+
| "Skip the storyboard, just make the PR" | The storyboard IS the PR body. It documents the journey. |
|
|
178
|
+
| "Leave the dungeon files, they might be useful" | Archive to vault. Session artifacts don't belong in the repo. |
|
|
179
|
+
| "Merge without testing the merged result" | Merges introduce conflicts. Test after merge. |
|
|
180
|
+
| "I'll write the code fix myself" | You are the Wizard. Dispatch the fix to an agent. |
|
|
181
|
+
|
|
182
|
+
## Phase Spoils
|
|
183
|
+
|
|
184
|
+
**Output**: `{questDir}/phase-6-wrap-up.md` — The complete quest narrative, phase by phase.
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Raid lifecycle hook: Stop
|
|
3
|
-
# Detects phase transitions and injects human confirmation gate.
|
|
4
|
-
set -euo pipefail
|
|
5
|
-
|
|
6
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
-
source "$SCRIPT_DIR/raid-lib.sh"
|
|
8
|
-
|
|
9
|
-
if [ "$RAID_ACTIVE" != "true" ]; then
|
|
10
|
-
exit 0
|
|
11
|
-
fi
|
|
12
|
-
|
|
13
|
-
if [ "$RAID_LIFECYCLE_PHASE_CONFIRM" != "true" ]; then
|
|
14
|
-
exit 0
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
# Phase transitions are managed by the Wizard via raid_session_set().
|
|
18
|
-
# No automatic detection needed — the Wizard explicitly updates the session.
|
|
19
|
-
|
|
20
|
-
exit 0
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Raid lifecycle hook: TaskCompleted
|
|
3
|
-
# Blocks task completion if tests haven't run recently.
|
|
4
|
-
set -euo pipefail
|
|
5
|
-
|
|
6
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
-
source "$SCRIPT_DIR/raid-lib.sh"
|
|
8
|
-
|
|
9
|
-
if [ "$RAID_ACTIVE" != "true" ]; then
|
|
10
|
-
exit 0
|
|
11
|
-
fi
|
|
12
|
-
|
|
13
|
-
if [ "$RAID_LIFECYCLE_COMPLETION_GATE" != "true" ]; then
|
|
14
|
-
exit 0
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
# Design and plan phases have no code to test — skip test-run requirement
|
|
18
|
-
case "${RAID_PHASE:-}" in
|
|
19
|
-
design|plan) exit 0 ;;
|
|
20
|
-
esac
|
|
21
|
-
|
|
22
|
-
TEST_RUN_FILE=".claude/raid-last-test-run"
|
|
23
|
-
|
|
24
|
-
if [ ! -f "$TEST_RUN_FILE" ]; then
|
|
25
|
-
raid_block "Tests must pass before marking a task complete. No test run recorded — run your test command first."
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
LAST_RUN=$(cat "$TEST_RUN_FILE" 2>/dev/null | tr -d '[:space:]')
|
|
29
|
-
NOW=$(date +%s)
|
|
30
|
-
WINDOW=$((RAID_LIFECYCLE_TEST_WINDOW * 60))
|
|
31
|
-
# Guard against corrupted/non-numeric timestamp
|
|
32
|
-
case "$LAST_RUN" in
|
|
33
|
-
''|*[!0-9]*) raid_block "Tests must pass before marking a task complete. Test run timestamp is invalid — run your test command first." ;;
|
|
34
|
-
esac
|
|
35
|
-
AGE=$((NOW - LAST_RUN))
|
|
36
|
-
|
|
37
|
-
if [ "$AGE" -gt "$WINDOW" ]; then
|
|
38
|
-
MINS_AGO=$((AGE / 60))
|
|
39
|
-
raid_block "Tests last ran $MINS_AGO minutes ago (window is $RAID_LIFECYCLE_TEST_WINDOW min). Run tests again before marking this task complete."
|
|
40
|
-
fi
|
|
41
|
-
|
|
42
|
-
exit 0
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Raid Bash write-gate: intercepts file-writing Bash commands
|
|
3
|
-
# PreToolUse hook for Bash operations — defense-in-depth layer.
|
|
4
|
-
# Detects: redirects (> >>), tee, sed -i, cp, mv, curl -o,
|
|
5
|
-
# and scripting language writes (python3/node/ruby/perl).
|
|
6
|
-
# Protects .claude/raid-session and .claude/raid-last-test-run from all Bash writes.
|
|
7
|
-
set -euo pipefail
|
|
8
|
-
|
|
9
|
-
HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
|
-
source "$HOOK_DIR/raid-lib.sh"
|
|
11
|
-
|
|
12
|
-
raid_read_input
|
|
13
|
-
|
|
14
|
-
# No command — nothing to gate
|
|
15
|
-
if [ -z "${RAID_COMMAND:-}" ]; then
|
|
16
|
-
exit 0
|
|
17
|
-
fi
|
|
18
|
-
|
|
19
|
-
# No active session — allow everything
|
|
20
|
-
if [ "$RAID_ACTIVE" = "false" ]; then
|
|
21
|
-
exit 0
|
|
22
|
-
fi
|
|
23
|
-
|
|
24
|
-
# --- Extract target file paths from known write patterns ---
|
|
25
|
-
|
|
26
|
-
# Collects candidate target paths from the command string.
|
|
27
|
-
# This is regex heuristics on a Bash command — it catches the 90% case,
|
|
28
|
-
# not arbitrary scripting. Defense in depth, not a security boundary.
|
|
29
|
-
_targets=()
|
|
30
|
-
|
|
31
|
-
_cmd="$RAID_COMMAND"
|
|
32
|
-
|
|
33
|
-
# Pattern 1: Redirects — command > file, command >> file
|
|
34
|
-
# Matches: > path, >> path (with optional whitespace)
|
|
35
|
-
while IFS= read -r _match; do
|
|
36
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
37
|
-
done < <(echo "$_cmd" | grep -oE '>{1,2}\s*[^ |;&)]+' | sed 's/^>*[[:space:]]*//')
|
|
38
|
-
|
|
39
|
-
# Pattern 2: tee [-a] file [file...]
|
|
40
|
-
while IFS= read -r _match; do
|
|
41
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
42
|
-
done < <(echo "$_cmd" | grep -oE 'tee\s+(-a\s+)?[^ |;&)]+' | sed 's/^tee\s\+\(-a\s\+\)\?//' | sed 's/^tee[[:space:]]*\(-a[[:space:]]*\)\{0,1\}//')
|
|
43
|
-
|
|
44
|
-
# Pattern 3: sed -i[suffix] 's/.../.../g' file
|
|
45
|
-
while IFS= read -r _match; do
|
|
46
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
47
|
-
done < <(echo "$_cmd" | grep -oE "sed\s+-i[^ ]*\s+'[^']*'\s+[^ |;&)]+" | rev | cut -d' ' -f1 | rev)
|
|
48
|
-
|
|
49
|
-
# Pattern 4: cp source target (last arg is target)
|
|
50
|
-
while IFS= read -r _match; do
|
|
51
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
52
|
-
done < <(echo "$_cmd" | grep -oE 'cp\s+(-[a-zA-Z]+\s+)*[^ |;&)]+\s+[^ |;&)]+' | rev | cut -d' ' -f1 | rev)
|
|
53
|
-
|
|
54
|
-
# Pattern 5: mv source target (last arg is target)
|
|
55
|
-
while IFS= read -r _match; do
|
|
56
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
57
|
-
done < <(echo "$_cmd" | grep -oE 'mv\s+(-[a-zA-Z]+\s+)*[^ |;&)]+\s+[^ |;&)]+' | rev | cut -d' ' -f1 | rev)
|
|
58
|
-
|
|
59
|
-
# Pattern 6: curl -o file / curl --output file
|
|
60
|
-
while IFS= read -r _match; do
|
|
61
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
62
|
-
done < <(echo "$_cmd" | grep -oE 'curl\s+.*-o\s+[^ |;&)]+' | grep -oE '\-o\s+[^ |;&)]+' | sed 's/^-o[[:space:]]*//')
|
|
63
|
-
|
|
64
|
-
# Pattern 7: Scripting language inline writes — extract quoted paths
|
|
65
|
-
# python3 -c "open('path', 'w')..."
|
|
66
|
-
while IFS= read -r _match; do
|
|
67
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
68
|
-
done < <(echo "$_cmd" | grep -oE "python3?\s+-c\s+['\"].*['\"]" | grep -oE "open\(['\"][^'\"]+['\"]" | sed "s/^open(['\"]//;s/['\"]$//")
|
|
69
|
-
|
|
70
|
-
# node -e "fs.writeFileSync('path', ...)"
|
|
71
|
-
while IFS= read -r _match; do
|
|
72
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
73
|
-
done < <(echo "$_cmd" | grep -oE "node\s+-e\s+['\"].*['\"]" | grep -oE "writeFileSync\(['\"][^'\"]+['\"]" | sed "s/^writeFileSync(['\"]//;s/['\"]$//")
|
|
74
|
-
|
|
75
|
-
# ruby -e "File.write('path', ...)"
|
|
76
|
-
while IFS= read -r _match; do
|
|
77
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
78
|
-
done < <(echo "$_cmd" | grep -oE "ruby\s+-e\s+['\"].*['\"]" | grep -oE "File\.write\(['\"][^'\"]+['\"]" | sed "s/^File\.write(['\"]//;s/['\"]$//")
|
|
79
|
-
|
|
80
|
-
# perl -e 'open(F,">path")...'
|
|
81
|
-
while IFS= read -r _match; do
|
|
82
|
-
[ -n "$_match" ] && _targets+=("$_match")
|
|
83
|
-
done < <(echo "$_cmd" | grep -oE "perl\s+-e\s+['\"].*['\"]" | grep -oE '>[^"'\'']+['\''"]' | sed "s/^>//;s/['\"]$//")
|
|
84
|
-
|
|
85
|
-
# No write targets detected — allow
|
|
86
|
-
if [ ${#_targets[@]} -eq 0 ]; then
|
|
87
|
-
exit 0
|
|
88
|
-
fi
|
|
89
|
-
|
|
90
|
-
# --- Check each target ---
|
|
91
|
-
|
|
92
|
-
for _target in "${_targets[@]}"; do
|
|
93
|
-
# Normalize path: resolve .., //, and strip absolute prefix
|
|
94
|
-
_norm="$_target"
|
|
95
|
-
# Convert to absolute for uniform handling
|
|
96
|
-
if [[ "$_norm" != /* ]]; then
|
|
97
|
-
_norm="$PWD/$_norm"
|
|
98
|
-
fi
|
|
99
|
-
# Collapse // and resolve /dir/../ components (portable — no GNU sed labels)
|
|
100
|
-
_norm=$(echo "$_norm" | sed 's|//\{1,\}|/|g' | while read -r _p; do
|
|
101
|
-
# Iteratively resolve ../ until none remain
|
|
102
|
-
while echo "$_p" | grep -q '/[^/][^/]*/\.\./'; do
|
|
103
|
-
_p=$(echo "$_p" | sed 's|/[^/][^/]*/\.\./|/|')
|
|
104
|
-
done
|
|
105
|
-
echo "$_p"
|
|
106
|
-
done)
|
|
107
|
-
# Strip PWD prefix to get relative path
|
|
108
|
-
_norm="${_norm#"$PWD"/}"
|
|
109
|
-
|
|
110
|
-
# Check 1: Protected files — always blocked during active session
|
|
111
|
-
case "$_norm" in
|
|
112
|
-
.claude/raid-session|.claude/raid-last-test-run)
|
|
113
|
-
raid_block "File '${_norm}' is protected. It is managed by hooks and the Wizard."
|
|
114
|
-
;;
|
|
115
|
-
esac
|
|
116
|
-
|
|
117
|
-
# Check 2: Non-production files — always allowed
|
|
118
|
-
if ! raid_is_production_file "$_norm"; then
|
|
119
|
-
continue
|
|
120
|
-
fi
|
|
121
|
-
|
|
122
|
-
# Check 3: Phase-based enforcement on production files
|
|
123
|
-
case "${RAID_PHASE:-}" in
|
|
124
|
-
design)
|
|
125
|
-
raid_block "Bash write to production file '${_norm}' blocked. Read-only phase (design)."
|
|
126
|
-
;;
|
|
127
|
-
plan)
|
|
128
|
-
raid_block "Bash write to production file '${_norm}' blocked. Read-only phase (plan)."
|
|
129
|
-
;;
|
|
130
|
-
implementation)
|
|
131
|
-
# Scout mode: skip implementer check
|
|
132
|
-
if [ "$RAID_MODE" = "scout" ]; then
|
|
133
|
-
continue
|
|
134
|
-
fi
|
|
135
|
-
# Only the designated implementer may write production code via Bash
|
|
136
|
-
if [ -n "$RAID_IMPLEMENTER" ] && [ "$RAID_CURRENT_AGENT" != "$RAID_IMPLEMENTER" ]; then
|
|
137
|
-
raid_block "Bash write to production file '${_norm}' blocked. Only ${RAID_IMPLEMENTER} writes production code this task."
|
|
138
|
-
fi
|
|
139
|
-
continue
|
|
140
|
-
;;
|
|
141
|
-
review)
|
|
142
|
-
raid_block "Bash write to production file '${_norm}' blocked. Read-only phase (review)."
|
|
143
|
-
;;
|
|
144
|
-
finishing)
|
|
145
|
-
raid_block "Bash write to production file '${_norm}' blocked. Finishing phase."
|
|
146
|
-
;;
|
|
147
|
-
"")
|
|
148
|
-
# Bootstrap — allow with warning (consistent with write-gate)
|
|
149
|
-
raid_warn "Session active but phase is empty — allowing Bash writes during bootstrap."
|
|
150
|
-
;;
|
|
151
|
-
*)
|
|
152
|
-
raid_block "Bash write to production file '${_norm}' blocked. Unknown phase '${RAID_PHASE}'."
|
|
153
|
-
;;
|
|
154
|
-
esac
|
|
155
|
-
done
|
|
156
|
-
|
|
157
|
-
exit 0
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: raid-browser-playwright
|
|
3
|
-
description: "Playwright MCP automated browser test authoring. Extends TDD RED-GREEN-REFACTOR with .spec.ts files. Console + network assertions mandatory. Invoked from raid-tdd and raid-implementation during Phase 3."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Raid Browser Playwright — Automated Test Authoring
|
|
7
|
-
|
|
8
|
-
Write browser tests as part of TDD. Use Playwright MCP to explore, then encode verified interactions into durable `.spec.ts` files.
|
|
9
|
-
|
|
10
|
-
<HARD-GATE>
|
|
11
|
-
Do NOT write browser tests without invoking `raid-browser` pre-flight first. Do NOT skip console/network assertions. Do NOT write tests without watching them fail first (TDD RED step). No subagents.
|
|
12
|
-
</HARD-GATE>
|
|
13
|
-
|
|
14
|
-
## When to Write Browser Tests vs Unit Tests
|
|
15
|
-
|
|
16
|
-
Not every task needs a browser test. The implementer decides and states reasoning. Challengers attack this decision.
|
|
17
|
-
|
|
18
|
-
| Write Browser Test | Write Unit Test Only |
|
|
19
|
-
|---|---|
|
|
20
|
-
| New user-facing flow (signup, checkout) | Pure utility function |
|
|
21
|
-
| UI interaction (drag-drop, modal, form) | API endpoint logic |
|
|
22
|
-
| Client-side routing / navigation | Data transformation |
|
|
23
|
-
| Visual state changes (loading, error, empty) | Business rule validation |
|
|
24
|
-
| Integration between frontend and API | Database queries |
|
|
25
|
-
|
|
26
|
-
**If unsure:** Write the browser test. It's easier to remove an unnecessary test than to find a bug in production.
|
|
27
|
-
|
|
28
|
-
## Browser TDD Cycle
|
|
29
|
-
|
|
30
|
-
### RED (browser)
|
|
31
|
-
|
|
32
|
-
1. Write Playwright test file: `tests/e2e/<feature>.spec.ts`
|
|
33
|
-
2. Test describes **user behavior**, not implementation:
|
|
34
|
-
- Navigate to page
|
|
35
|
-
- Interact (click, type, select, drag)
|
|
36
|
-
- Assert visible outcome (text appears, redirect happens, element state changes)
|
|
37
|
-
3. Include mandatory infrastructure assertions (see below)
|
|
38
|
-
4. Run test → **MUST fail**
|
|
39
|
-
5. Verify it fails for the **RIGHT reason** (page/element missing — not test syntax error)
|
|
40
|
-
|
|
41
|
-
### GREEN (browser)
|
|
42
|
-
|
|
43
|
-
1. Implement the feature code
|
|
44
|
-
2. Run Playwright test → **MUST pass**
|
|
45
|
-
3. Run full test suite (unit + browser) → all green
|
|
46
|
-
|
|
47
|
-
### REFACTOR
|
|
48
|
-
|
|
49
|
-
1. Clean up implementation and test code
|
|
50
|
-
2. Re-run all tests → still green
|
|
51
|
-
|
|
52
|
-
## Using Playwright MCP During Test Authoring
|
|
53
|
-
|
|
54
|
-
While writing the test, the implementer explores interactively to understand the current state and find correct selectors:
|
|
55
|
-
|
|
56
|
-
| Tool | Purpose |
|
|
57
|
-
|---|---|
|
|
58
|
-
| `browser_navigate` | Load the page, see what's there |
|
|
59
|
-
| `browser_snapshot` | Get DOM state, find correct selectors |
|
|
60
|
-
| `browser_click` / `browser_fill_form` | Test interactions manually first |
|
|
61
|
-
| `browser_console_messages` | Check for errors during interaction |
|
|
62
|
-
| `browser_network_requests` | Verify API calls, check payloads |
|
|
63
|
-
| `browser_take_screenshot` | Capture visual state for evidence |
|
|
64
|
-
|
|
65
|
-
**The MCP tools are the exploratory scratchpad. The `.spec.ts` file is the durable artifact.**
|
|
66
|
-
|
|
67
|
-
Encode what you verified interactively into the test file. The test must run headlessly in CI without MCP tools.
|
|
68
|
-
|
|
69
|
-
## Mandatory Assertions
|
|
70
|
-
|
|
71
|
-
Every browser test file MUST include at least:
|
|
72
|
-
|
|
73
|
-
### 1. Console-Clean Assertion
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
test('no console errors during <feature> flow', async ({ page }) => {
|
|
77
|
-
const errors: string[] = [];
|
|
78
|
-
page.on('console', msg => {
|
|
79
|
-
if (msg.type() === 'error') errors.push(msg.text());
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// ... perform the feature flow ...
|
|
83
|
-
|
|
84
|
-
expect(errors).toEqual([]);
|
|
85
|
-
});
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 2. Network-Health Assertion
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
test('API calls succeed during <feature> flow', async ({ page }) => {
|
|
92
|
-
const failures: string[] = [];
|
|
93
|
-
page.on('response', response => {
|
|
94
|
-
if (response.status() >= 400) {
|
|
95
|
-
failures.push(`${response.status()} ${response.url()}`);
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// ... perform the feature flow ...
|
|
100
|
-
|
|
101
|
-
expect(failures).toEqual([]);
|
|
102
|
-
});
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
**Missing either of these is an automatic challenge from any reviewer.**
|
|
106
|
-
|
|
107
|
-
## Selector Best Practices
|
|
108
|
-
|
|
109
|
-
| Prefer | Avoid | Why |
|
|
110
|
-
|---|---|---|
|
|
111
|
-
| `data-testid="submit-btn"` | `button.btn-primary` | CSS classes change for styling reasons |
|
|
112
|
-
| `getByRole('button', { name: 'Submit' })` | `#submit` | Accessible and resilient |
|
|
113
|
-
| `getByText('Welcome back')` | `.header > div:nth-child(2)` | Structural selectors break on layout changes |
|
|
114
|
-
|
|
115
|
-
## Challenger Attacks on Browser Tests (Phase 3)
|
|
116
|
-
|
|
117
|
-
**Warrior attacks:**
|
|
118
|
-
- "You only tested the happy path — what happens with network failure?"
|
|
119
|
-
- "No test for rapid double-submit on the form"
|
|
120
|
-
- "What about a 10,000-character input in the name field?"
|
|
121
|
-
- "You didn't test with JavaScript disabled / slow network"
|
|
122
|
-
|
|
123
|
-
**Archer attacks:**
|
|
124
|
-
- "Your selector `button[type=submit]` is fragile — use `data-testid`"
|
|
125
|
-
- "No assertion on console errors — the feature works but throws warnings"
|
|
126
|
-
- "Missing network assertion — you don't verify the POST payload"
|
|
127
|
-
- "Tested at desktop width only — what about mobile viewport?"
|
|
128
|
-
|
|
129
|
-
**Rogue attacks:**
|
|
130
|
-
- "What happens if the user is already logged in and hits /register?"
|
|
131
|
-
- "No test for XSS in the input fields"
|
|
132
|
-
- "What if the API returns 200 but with an error body?"
|
|
133
|
-
- "Race condition: what if the user navigates away during submission?"
|
|
134
|
-
|
|
135
|
-
**Each challenger BOOTS their own app instance** (on their own port via `raid-browser`), runs the tests independently, and verifies they pass without flakiness.
|
|
136
|
-
|
|
137
|
-
## Running Browser Tests
|
|
138
|
-
|
|
139
|
-
Use the test command from `.claude/raid.json`:
|
|
140
|
-
- Read `project.execCommand` (e.g., `pnpm dlx`, `npx`, `bunx`)
|
|
141
|
-
- Run: `{execCommand} playwright test`
|
|
142
|
-
- For a specific test: `{execCommand} playwright test tests/e2e/<feature>.spec.ts`
|
|
143
|
-
|
|
144
|
-
## Test File Organization
|
|
145
|
-
|
|
146
|
-
```
|
|
147
|
-
tests/
|
|
148
|
-
e2e/
|
|
149
|
-
<feature-name>.spec.ts # One file per feature/flow
|
|
150
|
-
auth/
|
|
151
|
-
login.spec.ts # Group related flows in directories
|
|
152
|
-
registration.spec.ts
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## Red Flags
|
|
156
|
-
|
|
157
|
-
| Thought | Reality |
|
|
158
|
-
|---------|---------|
|
|
159
|
-
| "The feature is too simple for a browser test" | Simple features break in the browser. If it's user-facing, test it. |
|
|
160
|
-
| "I'll add console assertions later" | Later never comes. Add them now. |
|
|
161
|
-
| "The unit tests cover this" | Unit tests don't catch hydration mismatches, missing CSS, broken routing. |
|
|
162
|
-
| "I tested it manually with MCP tools" | Manual verification isn't reproducible. Write the `.spec.ts`. |
|
|
163
|
-
| "Selectors are fine, they work" | They work today. Will they work after a CSS refactor? Use `data-testid`. |
|