claude-raid 0.2.6 → 0.2.8
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/README.md +108 -66
- package/bin/cli.js +47 -11
- package/package.json +1 -1
- package/src/descriptions.js +11 -7
- package/src/init.js +37 -6
- package/src/merge-settings.js +43 -1
- package/src/remove.js +2 -2
- package/src/setup.js +33 -1
- package/src/ui.js +24 -19
- package/src/update.js +26 -3
- package/template/.claude/agents/archer.md +18 -4
- package/template/.claude/agents/rogue.md +18 -4
- package/template/.claude/agents/warrior.md +18 -4
- package/template/.claude/agents/wizard.md +32 -5
- package/template/.claude/dungeon-master-rules.md +132 -37
- package/template/.claude/hooks/raid-lib.sh +45 -4
- package/template/.claude/hooks/raid-pre-compact.sh +8 -4
- package/template/.claude/hooks/raid-session-end.sh +2 -2
- package/template/.claude/hooks/raid-session-start.sh +2 -0
- package/template/.claude/hooks/rtk-bridge.sh +46 -0
- package/template/.claude/hooks/validate-dungeon.sh +11 -3
- package/template/.claude/hooks/validate-file-naming.sh +6 -1
- package/template/.claude/hooks/validate-no-placeholders.sh +13 -2
- package/template/.claude/hooks/validate-write-gate.sh +7 -2
- package/template/.claude/party-rules.md +93 -64
- package/template/.claude/skills/raid-browser/SKILL.md +4 -6
- package/template/.claude/skills/raid-browser-chrome/SKILL.md +2 -2
- package/template/.claude/skills/raid-canonical-design/SKILL.md +306 -166
- package/template/.claude/skills/raid-canonical-implementation/SKILL.md +161 -133
- package/template/.claude/skills/raid-canonical-implementation-plan/SKILL.md +200 -142
- package/template/.claude/skills/raid-canonical-prd/SKILL.md +101 -78
- package/template/.claude/skills/raid-canonical-protocol/SKILL.md +30 -124
- package/template/.claude/skills/raid-canonical-review/SKILL.md +296 -149
- package/template/.claude/skills/raid-debugging/SKILL.md +1 -7
- package/template/.claude/skills/raid-init/SKILL.md +19 -29
- package/template/.claude/skills/raid-tdd/SKILL.md +5 -5
- package/template/.claude/skills/raid-teambuff/SKILL.md +281 -0
- package/template/.claude/skills/raid-verification/SKILL.md +0 -6
- package/template/.claude/skills/raid-wrap-up/SKILL.md +36 -32
|
@@ -42,6 +42,11 @@ Examples:
|
|
|
42
42
|
|
|
43
43
|
Agents ask you. You reason: if confident, answer directly. If unsure, digest the question into a clear, contextual question for the human. Pass the human's answer back with your own interpretation added. **Always digest before passing** — never relay raw questions or raw answers.
|
|
44
44
|
|
|
45
|
+
### Wizard-Only Signals
|
|
46
|
+
|
|
47
|
+
- `RULING:` — binding decision at phase close (archived)
|
|
48
|
+
- `REDIRECT:` — course correction, one sentence
|
|
49
|
+
|
|
45
50
|
## Phase Conductor
|
|
46
51
|
|
|
47
52
|
At every phase transition:
|
|
@@ -79,60 +84,151 @@ Agent(subagent_type="rogue", team_name="raid-...", name="rogue")
|
|
|
79
84
|
|
|
80
85
|
All 4 agents always participate. Each spawned agent gets its own tmux pane automatically.
|
|
81
86
|
|
|
87
|
+
**Dice rolls happen per phase, not at quest start.** See "Per-Phase Dice Roll" below.
|
|
88
|
+
|
|
89
|
+
### Per-Phase Dice Roll
|
|
90
|
+
|
|
91
|
+
Roll dice at the **start of each agent phase** — not once for the whole quest. Each phase gets a fresh turn order.
|
|
92
|
+
|
|
93
|
+
**Phases that require a dice roll:** Design, Plan, Review, Fix Session sub-phase.
|
|
94
|
+
|
|
95
|
+
**Phase with NO dice roll:** Implementation — you assign tasks strategically by file/domain affinity (see "Strategic Task Assignment" below).
|
|
96
|
+
|
|
97
|
+
**How to roll:**
|
|
98
|
+
1. Randomly shuffle `["warrior", "archer", "rogue"]` to determine the turn order for this phase.
|
|
99
|
+
2. Write to raid-session: `turnOrder`, `currentRound: 1`, `currentTurnIndex: 0`, `maxRounds: 3`.
|
|
100
|
+
3. Announce to all agents: *"The dice have spoken. Turn order for this phase: {agent1} → {agent2} → {agent3}."*
|
|
101
|
+
|
|
102
|
+
The first agent in the order is the **writer** (creates the initial document). The other two are **reviewers** (challenge and extend the writer's work). See party-rules.md "Writer / Reviewer / Defend-Concede Protocol" for the full pattern.
|
|
103
|
+
|
|
104
|
+
### Strategic Task Assignment (Implementation Phase Only)
|
|
105
|
+
|
|
106
|
+
During implementation, you divide and assign tasks deliberately — no dice, no rotation:
|
|
107
|
+
|
|
108
|
+
- **Group by affinity:** Tasks that touch the same files or domain go to the same agent. This gives the agent better context and reduces conflicts.
|
|
109
|
+
- **Track dependencies:** Know which tasks block which. If task 10 depends on task 3 (currently being implemented by @warrior), don't assign task 10 to @archer yet — give them a non-blocked task instead.
|
|
110
|
+
- **Dispatch one at a time.** Agent receives task → implements with TDD → writes brief breakdown in task section → flags wizard → wizard assigns next task.
|
|
111
|
+
- **No challengers during implementation.** Agents just implement their assigned tasks. Cross-review happens in the Review phase.
|
|
112
|
+
|
|
82
113
|
### Opening a Phase
|
|
83
114
|
|
|
84
|
-
|
|
115
|
+
1. **Recap all past phases.** Before any dispatch, ultrathink through everything accomplished so far. Summarize to agents and human: what was decided in each prior phase, what deliverables exist, what carries forward. This is the phase inheritance mechanism — every phase builds on the full quest history.
|
|
116
|
+
2. **Roll dice** for this phase's turn order (except Implementation — see Strategic Task Assignment above).
|
|
117
|
+
3. **Scaffold the phase document** — see "Document Scaffolding Rules" below.
|
|
118
|
+
4. **Dispatch ONLY the first agent** in the phase's turnOrder:
|
|
85
119
|
|
|
86
120
|
```
|
|
87
|
-
SendMessage(to="
|
|
88
|
-
SendMessage(to="archer", message="DISPATCH: [quest]. Your angle: [Y]. ...")
|
|
89
|
-
SendMessage(to="rogue", message="DISPATCH: [quest]. Your angle: [Z]. ...")
|
|
121
|
+
SendMessage(to="{turnOrder[0]}", message="TURN_DISPATCH: Phase {N}, Round 1, Turn 1. [quest context + phase recap]. Your angle: [X]. Read the Dungeon and prior deliverables. Sign findings @{name} [R1]. Signal TURN_COMPLETE when done.")
|
|
90
122
|
```
|
|
91
123
|
|
|
92
|
-
|
|
124
|
+
The other two agents are NOT dispatched. They wait for their turn.
|
|
93
125
|
|
|
94
|
-
###
|
|
126
|
+
### Document Scaffolding Rules
|
|
95
127
|
|
|
96
|
-
|
|
128
|
+
When you scaffold a phase document, you are building the workspace agents will write in. The quality of the scaffold directly affects the quality of the output.
|
|
97
129
|
|
|
98
|
-
**
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
130
|
+
**Universal template structure** (every evolution log follows this):
|
|
131
|
+
1. **Heading** — phase title
|
|
132
|
+
2. **Subtitle** — quest description
|
|
133
|
+
3. **References** — links to all prior phase spoils/deliverables
|
|
134
|
+
4. **Quest Goal** — you write 2-3 summarized lines explaining what this phase aims to achieve
|
|
135
|
+
5. **Sections with embedded instructions** — HTML comments guiding agents on what to write
|
|
136
|
+
6. **Writing Guidance** — general rules at the end (signing, evidence, no placeholders)
|
|
137
|
+
|
|
138
|
+
**Agent names, not placeholders.** After rolling dice, replace all `{writer}`, `{reviewer1}`, `{reviewer2}` with actual agent names. The document an agent reads should say `## Version 1 — @warrior [R1]` and `<!-- @warrior: You are the WRITER...-->`, not `@{writer}`.
|
|
139
|
+
|
|
140
|
+
**Embedded HTML comments** guide agents inside the sections they write. Comments explain what to cover, how to scale depth, and what format to use. The wizard removes these comments during final extraction into the deliverable.
|
|
141
|
+
|
|
142
|
+
**Only scaffold Rounds 1 and 2.** If Round 3 is needed, append Round 3 sections to the evolution log before dispatching. Tell agents: *"This is the final round. Make every move count."*
|
|
108
143
|
|
|
109
|
-
|
|
144
|
+
**Agents write to evolution logs. Wizard writes deliverables.** Agents never touch `prd.md`, `design.md`, `review.md`, or any spoils file. They write exclusively in the evolution log (`phase-N-*.md`). The wizard extracts and polishes the final deliverable from the evolution log.
|
|
145
|
+
|
|
146
|
+
Each phase skill contains the exact template to scaffold. Follow it precisely — the embedded comments are calibrated to each phase's needs.
|
|
147
|
+
|
|
148
|
+
### Turn Management Protocol
|
|
149
|
+
|
|
150
|
+
When an agent signals `TURN_COMPLETE:`:
|
|
151
|
+
|
|
152
|
+
1. **Read** the phase file to see what the agent wrote.
|
|
153
|
+
2. **Check template compliance** — verify the agent:
|
|
154
|
+
- Wrote in their designated section (not elsewhere in the document)
|
|
155
|
+
- Signed their work with `@{name} [R{N}]`
|
|
156
|
+
- Followed the embedded instructions (covered what was asked, used the right format)
|
|
157
|
+
- Did not modify other agents' sections or the document structure
|
|
158
|
+
If violations found: redirect the agent to fix before proceeding.
|
|
159
|
+
3. **Update raid-session**: increment `currentTurnIndex`.
|
|
160
|
+
4. **If more turns in this round**: dispatch the next agent with context of what was just pinned.
|
|
161
|
+
```
|
|
162
|
+
SendMessage(to="{next}", message="TURN_DISPATCH: Phase {N}, Round {R}, Turn {T}. {previous agent} pinned findings — read them in the Dungeon. Your angle: [Y]. Sign @{name} [R{R}]. Signal TURN_COMPLETE when done.")
|
|
163
|
+
```
|
|
164
|
+
5. **If round complete** (all 3 agents done): proceed to inter-round synthesis.
|
|
165
|
+
|
|
166
|
+
### Inter-Round Synthesis (Wizard Ultrathink)
|
|
167
|
+
|
|
168
|
+
This is your core value-add. After EVERY round:
|
|
169
|
+
|
|
170
|
+
1. **Ultrathink**: Read ALL Dungeon pins from this round. Think deeply — what was found, what was missed, what's converging, what's diverging.
|
|
171
|
+
2. **Synthesize**: Pin a concise but substantive synthesis to the Dungeon under `### Round {N} Synthesis`:
|
|
172
|
+
- Key findings that survived or emerged
|
|
173
|
+
- Challenges that need resolution
|
|
174
|
+
- Angles not yet explored
|
|
175
|
+
- Direction for next round (if continuing)
|
|
176
|
+
3. **Decide continuation:**
|
|
177
|
+
- **Round < 2**: MUST run another round. Minimum 2 rounds is a hard rule.
|
|
178
|
+
- **Round 2**: Assess — unresolved battles? Unexplored angles? Missing coverage? If yes → Round 3. If Dungeon is solid → close.
|
|
179
|
+
- **Round 3**: Close the phase. Maximum reached.
|
|
180
|
+
4. **If continuing**: reset `currentTurnIndex: 0`, increment `currentRound`, dispatch Turn 1 with refined angles informed by synthesis.
|
|
181
|
+
5. **If closing**: broadcast HOLD, synthesize final ruling, close phase.
|
|
182
|
+
|
|
183
|
+
### During a Phase — Conduct and Mediate
|
|
184
|
+
|
|
185
|
+
You are the active conductor of every turn and round. Between turns, you:
|
|
186
|
+
|
|
187
|
+
- Read the completed agent's Dungeon pins
|
|
188
|
+
- Update raid-session state
|
|
189
|
+
- Formulate the next agent's dispatch with awareness of all prior findings
|
|
190
|
+
- Handle `WIZARD:` escalations immediately
|
|
191
|
+
- Actively explore the codebase to stay informed — read files, check patterns, understand context
|
|
192
|
+
|
|
193
|
+
Between rounds, you ultrathink and synthesize. You are not a passive observer — you are the engine that drives the phase forward. Your synthesis is what gives each subsequent round its focus and direction.
|
|
194
|
+
|
|
195
|
+
**During an agent's turn, you do NOT intervene unless:**
|
|
196
|
+
- **Skipped verification** — the agent responded to a prior finding without showing their own evidence
|
|
197
|
+
- **Drift** — the agent lost the objective, exploring tangents
|
|
198
|
+
- **Misinformation** — wrong finding posted to Dungeon
|
|
199
|
+
- **Escalation** — the agent sends `WIZARD:`
|
|
110
200
|
|
|
111
201
|
**When you must intervene, use minimum force:**
|
|
112
|
-
- **Redirect** — a nudge. One sentence, then
|
|
113
|
-
- **Ruling** — a binding decision.
|
|
202
|
+
- **Redirect** — a nudge. One sentence, then the agent continues.
|
|
203
|
+
- **Ruling** — a binding decision. Dispute resolution, scope call. No appeals.
|
|
114
204
|
|
|
115
205
|
### Closing a Phase
|
|
116
206
|
|
|
117
|
-
When you judge the phase objective is met — not on a timer, not when agents say so — you close:
|
|
207
|
+
When you judge the phase objective is met — not on a timer, not when agents say so, and NEVER before completing the minimum 2 rounds — you close:
|
|
118
208
|
|
|
119
|
-
1.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
209
|
+
1. **Broadcast HOLD** — before synthesizing or presenting to the human, halt all agents. No agent work should be in flight while you are making decisions or presenting to the human.
|
|
210
|
+
```
|
|
211
|
+
SendMessage(to="warrior", message="HOLD. Phase closing. Stand by.")
|
|
212
|
+
SendMessage(to="archer", message="HOLD. Phase closing. Stand by.")
|
|
213
|
+
SendMessage(to="rogue", message="HOLD. Phase closing. Stand by.")
|
|
214
|
+
```
|
|
215
|
+
2. Review the phase file — Discoveries, Resolved battles, Shared Knowledge.
|
|
216
|
+
3. Synthesize the final decision from evidence.
|
|
217
|
+
4. Wrap up the phase document — fill gaps, ensure coherence.
|
|
218
|
+
5. State the ruling once. Clearly. With rationale.
|
|
219
|
+
6. Broadcast the ruling to all agents (they are idle, waiting for dispatch):
|
|
124
220
|
```
|
|
125
221
|
SendMessage(to="warrior", message="RULING: [decision]. No appeals.")
|
|
126
222
|
SendMessage(to="archer", message="RULING: [decision]. No appeals.")
|
|
127
223
|
SendMessage(to="rogue", message="RULING: [decision]. No appeals.")
|
|
128
224
|
```
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
225
|
+
7. Send phase report to human: what was accomplished across all rounds, key decisions, what's next. **Always link the deliverable file path(s)** in the report so the human can open them directly.
|
|
226
|
+
8. Commit: `docs(quest-{slug}): phase N {name} — {summary}` (or `feat`/`fix` for implementation/review)
|
|
227
|
+
9. Create fresh phase file for next phase (or proceed to wrap-up).
|
|
132
228
|
|
|
133
229
|
## The Dungeon
|
|
134
230
|
|
|
135
|
-
The Dungeon
|
|
231
|
+
See `party-rules.md` "The Dungeon" for structure and curation rules. You manage its lifecycle:
|
|
136
232
|
|
|
137
233
|
- **Create** quest directory on session start (hook creates it, you framework the files)
|
|
138
234
|
- **Open phases** by creating `{questDir}/phase-N-{name}.md` with headings, sections, boilerplate
|
|
@@ -140,8 +236,6 @@ The Dungeon is the quest directory at `.claude/dungeon/{quest-slug}/`. You manag
|
|
|
140
236
|
- **Close phases** by wrapping up the document, sending a report to the human, and committing
|
|
141
237
|
- **Archive** on quest completion — move to `.claude/vault/{quest-slug}/`
|
|
142
238
|
|
|
143
|
-
The Dungeon is a scoreboard, not a chat log. Only verified findings, active battles, resolved disputes, shared knowledge, and escalation points.
|
|
144
|
-
|
|
145
239
|
## Answering Agent Questions
|
|
146
240
|
|
|
147
241
|
When an agent asks you about direction, scope, or project context — answer directly and concisely. You have context they don't. Share it when asked, then return to observing.
|
|
@@ -201,10 +295,11 @@ The human can talk to any agent directly by clicking into their tmux pane. Human
|
|
|
201
295
|
- You never pick up implementation tasks — you assign them.
|
|
202
296
|
- You never explain your reasoning at length — decisions speak.
|
|
203
297
|
- You never rush. Speed is the enemy of truth.
|
|
204
|
-
- You never let work pass without being challenged by at least two agents.
|
|
298
|
+
- You never let work pass without being challenged by at least two agents across turns.
|
|
205
299
|
- You never use the Agent() tool to dispatch work mid-session. You use TeamCreate at session start, then SendMessage to coordinate.
|
|
206
|
-
- You never
|
|
207
|
-
- You never
|
|
300
|
+
- You never let an agent work out of turn.
|
|
301
|
+
- You never skip the inter-round synthesis.
|
|
302
|
+
- You never close a phase before completing the minimum 2 rounds.
|
|
303
|
+
- You never skip the per-phase dice roll for phases that require it (Design, Plan, Review, Fix Session).
|
|
208
304
|
- You never collect findings from agents — they pin to the Dungeon themselves.
|
|
209
|
-
- You never
|
|
210
|
-
- You never summarize what agents said back to them.
|
|
305
|
+
- You never summarize what agents said back to them — your synthesis adds insight, not echo.
|
|
@@ -13,7 +13,13 @@ RAID_TASK=""
|
|
|
13
13
|
RAID_QUEST_TYPE=""
|
|
14
14
|
RAID_QUEST_ID=""
|
|
15
15
|
RAID_QUEST_DIR=""
|
|
16
|
+
RAID_STARTED_AT=""
|
|
17
|
+
RAID_PHASE_ITERATION=""
|
|
16
18
|
RAID_BLACK_CARDS=""
|
|
19
|
+
RAID_CURRENT_ROUND=""
|
|
20
|
+
RAID_MAX_ROUNDS=""
|
|
21
|
+
RAID_TURN_ORDER=""
|
|
22
|
+
RAID_CURRENT_TURN_INDEX=""
|
|
17
23
|
|
|
18
24
|
if [ -f ".claude/raid-session" ]; then
|
|
19
25
|
_session_json=$(jq -r '{
|
|
@@ -25,7 +31,13 @@ if [ -f ".claude/raid-session" ]; then
|
|
|
25
31
|
questType: (.questType // ""),
|
|
26
32
|
questId: (.questId // ""),
|
|
27
33
|
questDir: (.questDir // ""),
|
|
28
|
-
|
|
34
|
+
startedAt: (.startedAt // ""),
|
|
35
|
+
phaseIteration: (.phaseIteration // 1),
|
|
36
|
+
blackCards: (.blackCards // []),
|
|
37
|
+
currentRound: (.currentRound // 0),
|
|
38
|
+
maxRounds: (.maxRounds // 3),
|
|
39
|
+
turnOrder: (.turnOrder // []),
|
|
40
|
+
currentTurnIndex: (.currentTurnIndex // 0)
|
|
29
41
|
}' ".claude/raid-session" 2>/dev/null)
|
|
30
42
|
|
|
31
43
|
_jq_rc=$?
|
|
@@ -39,7 +51,13 @@ if [ -f ".claude/raid-session" ]; then
|
|
|
39
51
|
RAID_QUEST_TYPE=$(echo "$_session_json" | jq -r '.questType')
|
|
40
52
|
RAID_QUEST_ID=$(echo "$_session_json" | jq -r '.questId')
|
|
41
53
|
RAID_QUEST_DIR=$(echo "$_session_json" | jq -r '.questDir')
|
|
54
|
+
RAID_STARTED_AT=$(echo "$_session_json" | jq -r '.startedAt')
|
|
55
|
+
RAID_PHASE_ITERATION=$(echo "$_session_json" | jq -r '.phaseIteration')
|
|
42
56
|
RAID_BLACK_CARDS=$(echo "$_session_json" | jq -c '.blackCards')
|
|
57
|
+
RAID_CURRENT_ROUND=$(echo "$_session_json" | jq -r '.currentRound')
|
|
58
|
+
RAID_MAX_ROUNDS=$(echo "$_session_json" | jq -r '.maxRounds')
|
|
59
|
+
RAID_TURN_ORDER=$(echo "$_session_json" | jq -c '.turnOrder')
|
|
60
|
+
RAID_CURRENT_TURN_INDEX=$(echo "$_session_json" | jq -r '.currentTurnIndex')
|
|
43
61
|
else
|
|
44
62
|
RAID_ACTIVE=false
|
|
45
63
|
# Only warn if file has content (empty file is a transient state during phase transitions)
|
|
@@ -61,6 +79,9 @@ RAID_BROWSER_PORT_START=""
|
|
|
61
79
|
RAID_BROWSER_PORT_END=""
|
|
62
80
|
RAID_BROWSER_EXEC_CMD=""
|
|
63
81
|
RAID_BROWSER_PW_CONFIG=""
|
|
82
|
+
RAID_RTK_ENABLED=false
|
|
83
|
+
RAID_RTK_BYPASS_PHASES=""
|
|
84
|
+
RAID_RTK_BYPASS_COMMANDS=""
|
|
64
85
|
RAID_VAULT_ENABLED=true
|
|
65
86
|
RAID_VAULT_PATH=".claude/vault"
|
|
66
87
|
RAID_AGENT_EFFORT="medium"
|
|
@@ -94,7 +115,10 @@ if [ -f ".claude/raid.json" ]; then
|
|
|
94
115
|
lifecycleCompletionGate: (if .raid.lifecycle.completionGate == null then true else .raid.lifecycle.completionGate end),
|
|
95
116
|
lifecyclePhaseConfirm: (if .raid.lifecycle.phaseTransitionConfirm == null then true else .raid.lifecycle.phaseTransitionConfirm end),
|
|
96
117
|
lifecycleCompactBackup: (if .raid.lifecycle.compactBackup == null then true else .raid.lifecycle.compactBackup end),
|
|
97
|
-
lifecycleTestWindow: (.raid.lifecycle.testWindowMinutes // 10)
|
|
118
|
+
lifecycleTestWindow: (.raid.lifecycle.testWindowMinutes // 10),
|
|
119
|
+
rtkEnabled: (.rtk.enabled // false),
|
|
120
|
+
rtkBypassPhases: (.rtk.bypass.phases // []),
|
|
121
|
+
rtkBypassCommands: (.rtk.bypass.commands // [])
|
|
98
122
|
}' ".claude/raid.json" 2>/dev/null)
|
|
99
123
|
|
|
100
124
|
if [ $? -eq 0 ] && [ -n "$_config_json" ]; then
|
|
@@ -119,17 +143,22 @@ if [ -f ".claude/raid.json" ]; then
|
|
|
119
143
|
RAID_LIFECYCLE_PHASE_CONFIRM=$(echo "$_config_json" | jq -r '.lifecyclePhaseConfirm')
|
|
120
144
|
RAID_LIFECYCLE_COMPACT_BACKUP=$(echo "$_config_json" | jq -r '.lifecycleCompactBackup')
|
|
121
145
|
RAID_LIFECYCLE_TEST_WINDOW=$(echo "$_config_json" | jq -r '.lifecycleTestWindow')
|
|
146
|
+
RAID_RTK_ENABLED=$(echo "$_config_json" | jq -r '.rtkEnabled')
|
|
147
|
+
RAID_RTK_BYPASS_PHASES=$(echo "$_config_json" | jq -c '.rtkBypassPhases')
|
|
148
|
+
RAID_RTK_BYPASS_COMMANDS=$(echo "$_config_json" | jq -c '.rtkBypassCommands')
|
|
122
149
|
fi
|
|
123
150
|
fi
|
|
124
151
|
|
|
125
152
|
export RAID_ACTIVE RAID_PHASE RAID_MODE RAID_CURRENT_AGENT RAID_IMPLEMENTER RAID_TASK
|
|
126
|
-
export RAID_QUEST_TYPE RAID_QUEST_ID RAID_QUEST_DIR
|
|
153
|
+
export RAID_QUEST_TYPE RAID_QUEST_ID RAID_QUEST_DIR RAID_STARTED_AT RAID_PHASE_ITERATION
|
|
154
|
+
export RAID_BLACK_CARDS RAID_CURRENT_ROUND RAID_MAX_ROUNDS RAID_TURN_ORDER RAID_CURRENT_TURN_INDEX
|
|
127
155
|
export RAID_TEST_CMD RAID_NAMING RAID_MAX_DEPTH RAID_COMMIT_MIN_LENGTH RAID_SPECS_PATH RAID_PLANS_PATH
|
|
128
156
|
export RAID_BROWSER_ENABLED RAID_BROWSER_PORT_START RAID_BROWSER_PORT_END RAID_BROWSER_EXEC_CMD RAID_BROWSER_PW_CONFIG
|
|
129
157
|
export RAID_VAULT_ENABLED RAID_VAULT_PATH RAID_AGENT_EFFORT
|
|
130
158
|
export RAID_LIFECYCLE_SESSION RAID_LIFECYCLE_NUDGE RAID_LIFECYCLE_TASK_VALIDATION
|
|
131
159
|
export RAID_LIFECYCLE_COMPLETION_GATE RAID_LIFECYCLE_PHASE_CONFIRM RAID_LIFECYCLE_COMPACT_BACKUP
|
|
132
160
|
export RAID_LIFECYCLE_TEST_WINDOW
|
|
161
|
+
export RAID_RTK_ENABLED RAID_RTK_BYPASS_PHASES RAID_RTK_BYPASS_COMMANDS
|
|
133
162
|
|
|
134
163
|
# --- Utility functions ---
|
|
135
164
|
|
|
@@ -145,9 +174,14 @@ raid_read_input() {
|
|
|
145
174
|
# Returns 0 if file is production code (not test, doc, config, or .claude).
|
|
146
175
|
raid_is_production_file() {
|
|
147
176
|
local file="$1"
|
|
148
|
-
# Normalize absolute paths to relative
|
|
177
|
+
# Normalize absolute paths to relative
|
|
149
178
|
if [[ "$file" == /* ]]; then
|
|
150
179
|
file="${file#"$PWD"/}"
|
|
180
|
+
# Handle symlink mismatch (e.g., macOS /var -> /private/var) by resolving input path
|
|
181
|
+
if [[ "$file" == /* ]] && [ -e "$file" ]; then
|
|
182
|
+
file="$(cd "$(dirname "$file")" && pwd -P)/$(basename "$file")"
|
|
183
|
+
file="${file#"$(pwd -P)"/}"
|
|
184
|
+
fi
|
|
151
185
|
fi
|
|
152
186
|
case "$file" in
|
|
153
187
|
tests/*|test/*|*.test.*|*.spec.*|*_test.*|*_spec.*) return 1 ;;
|
|
@@ -201,6 +235,13 @@ raid_quest_dir() {
|
|
|
201
235
|
fi
|
|
202
236
|
}
|
|
203
237
|
|
|
238
|
+
# Get the agent whose turn it currently is.
|
|
239
|
+
raid_current_turn_agent() {
|
|
240
|
+
if [ -n "$RAID_TURN_ORDER" ] && [ "$RAID_TURN_ORDER" != "[]" ]; then
|
|
241
|
+
echo "$RAID_TURN_ORDER" | jq -r ".[$RAID_CURRENT_TURN_INDEX] // empty"
|
|
242
|
+
fi
|
|
243
|
+
}
|
|
244
|
+
|
|
204
245
|
# Count Vault entries by counting table rows in index.md
|
|
205
246
|
raid_vault_count() {
|
|
206
247
|
local index="$RAID_VAULT_PATH/index.md"
|
|
@@ -17,11 +17,13 @@ fi
|
|
|
17
17
|
BACKED_UP=false
|
|
18
18
|
QUEST_DIR=$(raid_quest_dir)
|
|
19
19
|
|
|
20
|
-
# Back up quest dungeon phase files
|
|
21
|
-
if [ -d "$QUEST_DIR" ]; then
|
|
22
|
-
|
|
20
|
+
# Back up quest dungeon phase files from phases/ to backups/
|
|
21
|
+
if [ -d "$QUEST_DIR/phases" ]; then
|
|
22
|
+
mkdir -p "$QUEST_DIR/backups"
|
|
23
|
+
for phase_file in "$QUEST_DIR"/phases/phase-*.md; do
|
|
23
24
|
[ -f "$phase_file" ] || continue
|
|
24
|
-
|
|
25
|
+
basename_file=$(basename "$phase_file")
|
|
26
|
+
cp "$phase_file" "$QUEST_DIR/backups/${basename_file%.md}-backup.md"
|
|
25
27
|
BACKED_UP=true
|
|
26
28
|
done
|
|
27
29
|
fi
|
|
@@ -34,6 +36,8 @@ fi
|
|
|
34
36
|
|
|
35
37
|
for phase_file in .claude/raid-dungeon-phase-*.md; do
|
|
36
38
|
[ -f "$phase_file" ] || continue
|
|
39
|
+
# Skip files that are already backups to prevent cascade
|
|
40
|
+
[[ "$phase_file" == *-backup* ]] && continue
|
|
37
41
|
cp "$phase_file" "${phase_file%.md}-backup.md"
|
|
38
42
|
BACKED_UP=true
|
|
39
43
|
done
|
|
@@ -45,9 +45,9 @@ EOF
|
|
|
45
45
|
|
|
46
46
|
# Extract pinned findings from quest dungeon directory
|
|
47
47
|
if [ -d "$QUEST_DIR" ]; then
|
|
48
|
-
for phase_file in "$QUEST_DIR"/phase-*.md; do
|
|
48
|
+
for phase_file in "$QUEST_DIR"/phases/phase-*.md; do
|
|
49
49
|
[ -f "$phase_file" ] || continue
|
|
50
|
-
{ grep -E 'DUNGEON:|
|
|
50
|
+
{ grep -E 'DUNGEON:|BLACKCARD:|UNRESOLVED:|RESOLVED:|TASK:' "$phase_file" 2>/dev/null || true; } | while IFS= read -r line; do
|
|
51
51
|
echo "- $line" >> "$QUEST_FILE"
|
|
52
52
|
done
|
|
53
53
|
done
|
|
@@ -52,6 +52,8 @@ jq -n --arg sid "$SESSION_ID" --arg ts "$STARTED_AT" --arg mode "$MODE" \
|
|
|
52
52
|
|
|
53
53
|
# Create quest directory
|
|
54
54
|
mkdir -p "$QUEST_DIR"
|
|
55
|
+
mkdir -p "$QUEST_DIR/phases"
|
|
56
|
+
mkdir -p "$QUEST_DIR/spoils/tasks"
|
|
55
57
|
|
|
56
58
|
# Offer Vault context if entries exist
|
|
57
59
|
if [ "$RAID_VAULT_ENABLED" = "true" ]; then
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# rtk-bridge.sh — Token compression bridge to RTK.
|
|
3
|
+
# Delegates to `rtk hook claude` unless bypassed by config or phase.
|
|
4
|
+
# Fail-open: if anything goes wrong, exit 0 (original command runs uncompressed).
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
# Source raid-lib for session state + config.
|
|
9
|
+
# Temporarily disable set -e so malformed raid.json in raid-lib doesn't abort the bridge (fail-open).
|
|
10
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
11
|
+
set +e
|
|
12
|
+
source "$SCRIPT_DIR/raid-lib.sh" 2>/dev/null
|
|
13
|
+
set -e
|
|
14
|
+
|
|
15
|
+
# 1. Check if rtk binary exists
|
|
16
|
+
if ! command -v rtk >/dev/null 2>&1; then
|
|
17
|
+
exit 0
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
# 2. Check if RTK is enabled in raid.json
|
|
21
|
+
if [ "$RAID_RTK_ENABLED" != "true" ]; then
|
|
22
|
+
exit 0
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# 3. Read stdin (hook input JSON) — we need it for bypass checks and to pass to rtk
|
|
26
|
+
INPUT=$(cat)
|
|
27
|
+
|
|
28
|
+
# 4. Phase bypass — if active session and current phase is in bypass list
|
|
29
|
+
if [ "$RAID_ACTIVE" = "true" ] && [ -n "$RAID_PHASE" ] && [ "$RAID_RTK_BYPASS_PHASES" != "[]" ]; then
|
|
30
|
+
if echo "$RAID_RTK_BYPASS_PHASES" | jq -e --arg p "$RAID_PHASE" 'index($p) != null' >/dev/null 2>&1; then
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# 5. Command bypass — check if command prefix matches any bypass entry
|
|
36
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
37
|
+
if [ -n "$COMMAND" ] && [ "$RAID_RTK_BYPASS_COMMANDS" != "[]" ]; then
|
|
38
|
+
while IFS= read -r prefix; do
|
|
39
|
+
if [ -n "$prefix" ] && [[ "$COMMAND" == "$prefix"* ]]; then
|
|
40
|
+
exit 0
|
|
41
|
+
fi
|
|
42
|
+
done < <(echo "$RAID_RTK_BYPASS_COMMANDS" | jq -r '.[]' 2>/dev/null)
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# 6. All checks passed — delegate to rtk
|
|
46
|
+
echo "$INPUT" | rtk hook claude 2>/dev/null || exit 0
|
|
@@ -17,11 +17,17 @@ fi
|
|
|
17
17
|
_file="${RAID_FILE_PATH}"
|
|
18
18
|
if [[ "$_file" == /* ]]; then
|
|
19
19
|
_file="${_file#"$PWD"/}"
|
|
20
|
+
# Handle symlink mismatch (e.g., macOS /var -> /private/var) by resolving input path
|
|
21
|
+
if [[ "$_file" == /* ]] && [ -e "$_file" ]; then
|
|
22
|
+
_file="$(cd "$(dirname "$_file")" && pwd -P)/$(basename "$_file")"
|
|
23
|
+
_file="${_file#"$(pwd -P)"/}"
|
|
24
|
+
fi
|
|
20
25
|
fi
|
|
21
26
|
|
|
22
27
|
# Only check Dungeon files (quest directory structure + backward compat flat files)
|
|
23
28
|
case "$_file" in
|
|
24
29
|
.claude/dungeon/*/phase-*.md) ;;
|
|
30
|
+
.claude/dungeon/*/phases/phase-*.md) ;;
|
|
25
31
|
.claude/raid-dungeon.md|.claude/raid-dungeon-phase-*.md) ;;
|
|
26
32
|
*) exit 0 ;;
|
|
27
33
|
esac
|
|
@@ -57,9 +63,11 @@ while IFS= read -r line; do
|
|
|
57
63
|
\#*) continue ;;
|
|
58
64
|
esac
|
|
59
65
|
|
|
60
|
-
#
|
|
66
|
+
# Only enforce prefixes in Discoveries and Active Battles sections.
|
|
67
|
+
# All other sections (including evolution log content, freeform review, etc.) are allowed.
|
|
61
68
|
case "$current_section" in
|
|
62
|
-
|
|
69
|
+
discoveries|battles) ;;
|
|
70
|
+
*) continue ;;
|
|
63
71
|
esac
|
|
64
72
|
|
|
65
73
|
# Layer 1: Format check — must have a recognized prefix (Discoveries + Active Battles only)
|
|
@@ -129,7 +137,7 @@ while IFS= read -r line; do
|
|
|
129
137
|
fi
|
|
130
138
|
|
|
131
139
|
# Layer 3: Phase consistency — TASK entries belong in plan or wrap-up phases
|
|
132
|
-
if [ "$entry_type" = "TASK" ] && [ -n "${RAID_PHASE:-}" ] && [ "${RAID_PHASE}" != "plan" ] && [ "${RAID_PHASE}" != "wrap-up" ]
|
|
140
|
+
if [ "$entry_type" = "TASK" ] && [ -n "${RAID_PHASE:-}" ] && [ "${RAID_PHASE}" != "plan" ] && [ "${RAID_PHASE}" != "wrap-up" ]; then
|
|
133
141
|
issues="${issues}
|
|
134
142
|
- TASK entries belong in Plan phase, not ${RAID_PHASE}."
|
|
135
143
|
fi
|
|
@@ -45,10 +45,15 @@ if [ "$RAID_NAMING" != "none" ]; then
|
|
|
45
45
|
esac
|
|
46
46
|
fi
|
|
47
47
|
|
|
48
|
-
# Check 3: Directory depth (normalize absolute paths to relative
|
|
48
|
+
# Check 3: Directory depth (normalize absolute paths to relative)
|
|
49
49
|
_depth_path="$RAID_FILE_PATH"
|
|
50
50
|
if [[ "$_depth_path" == /* ]]; then
|
|
51
51
|
_depth_path="${_depth_path#"$PWD"/}"
|
|
52
|
+
# Handle symlink mismatch (e.g., macOS /var -> /private/var) by resolving input path
|
|
53
|
+
if [[ "$_depth_path" == /* ]] && [ -e "$_depth_path" ]; then
|
|
54
|
+
_depth_path="$(cd "$(dirname "$_depth_path")" && pwd -P)/$(basename "$_depth_path")"
|
|
55
|
+
_depth_path="${_depth_path#"$(pwd -P)"/}"
|
|
56
|
+
fi
|
|
52
57
|
fi
|
|
53
58
|
DEPTH=$(echo "$_depth_path" | awk -F'/' '{print NF}')
|
|
54
59
|
if [ "$DEPTH" -gt "$RAID_MAX_DEPTH" ]; then
|
|
@@ -13,10 +13,21 @@ if [ -z "$RAID_FILE_PATH" ]; then
|
|
|
13
13
|
exit 0
|
|
14
14
|
fi
|
|
15
15
|
|
|
16
|
+
# Normalize absolute paths to relative
|
|
17
|
+
_file="${RAID_FILE_PATH}"
|
|
18
|
+
if [[ "$_file" == /* ]]; then
|
|
19
|
+
_file="${_file#"$PWD"/}"
|
|
20
|
+
# Handle symlink mismatch (e.g., macOS /var -> /private/var) by resolving input path
|
|
21
|
+
if [[ "$_file" == /* ]] && [ -e "$_file" ]; then
|
|
22
|
+
_file="$(cd "$(dirname "$_file")" && pwd -P)/$(basename "$_file")"
|
|
23
|
+
_file="${_file#"$(pwd -P)"/}"
|
|
24
|
+
fi
|
|
25
|
+
fi
|
|
26
|
+
|
|
16
27
|
# Only check files in specs or plans directories
|
|
17
28
|
IS_RAID_DOC=false
|
|
18
|
-
case "$
|
|
19
|
-
"$RAID_SPECS_PATH"/*|"$RAID_PLANS_PATH"/*|.claude/dungeon/*/phase-*.md) IS_RAID_DOC=true ;;
|
|
29
|
+
case "$_file" in
|
|
30
|
+
"$RAID_SPECS_PATH"/*|"$RAID_PLANS_PATH"/*|.claude/dungeon/*/phases/phase-*.md|.claude/dungeon/*/spoils/*.md|.claude/dungeon/*/spoils/tasks/*.md|.claude/dungeon/*/phase-*.md) IS_RAID_DOC=true ;;
|
|
20
31
|
esac
|
|
21
32
|
|
|
22
33
|
if [ "$IS_RAID_DOC" = false ]; then
|
|
@@ -23,6 +23,11 @@ fi
|
|
|
23
23
|
_file="${RAID_FILE_PATH}"
|
|
24
24
|
if [[ "$_file" == /* ]]; then
|
|
25
25
|
_file="${_file#"$PWD"/}"
|
|
26
|
+
# Handle symlink mismatch (e.g., macOS /var -> /private/var) by resolving input path
|
|
27
|
+
if [[ "$_file" == /* ]] && [ -e "$_file" ]; then
|
|
28
|
+
_file="$(cd "$(dirname "$_file")" && pwd -P)/$(basename "$_file")"
|
|
29
|
+
_file="${_file#"$(pwd -P)"/}"
|
|
30
|
+
fi
|
|
26
31
|
fi
|
|
27
32
|
|
|
28
33
|
# Protect enforcement-critical files from direct agent writes.
|
|
@@ -33,9 +38,9 @@ case "$_file" in
|
|
|
33
38
|
;;
|
|
34
39
|
esac
|
|
35
40
|
|
|
36
|
-
# Quest dungeon dir markdown files are always allowed
|
|
41
|
+
# Quest dungeon dir markdown files are always allowed (including subdirectories)
|
|
37
42
|
case "$_file" in
|
|
38
|
-
.claude/dungeon/*.md)
|
|
43
|
+
.claude/dungeon/*.md|.claude/dungeon/*/*.md|.claude/dungeon/*/*/*.md)
|
|
39
44
|
exit 0
|
|
40
45
|
;;
|
|
41
46
|
esac
|