@graypark/ralph-codex 0.4.3 → 0.5.1

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 CHANGED
@@ -69,6 +69,16 @@ node bin/install.mjs --global
69
69
  /ralph-interview Refactor the auth module across 3 services, run immediately
70
70
  ```
71
71
 
72
+ **Multi-phase pipeline:** When multiple phases are generated, choose how to run:
73
+
74
+ ```
75
+ Ready to run?
76
+ - y → Pipeline mode: all phases run automatically (1 → 2 → 3)
77
+ - step → Manual mode: run one phase at a time, confirm between each
78
+ - n → Copy-paste commands yourself
79
+ - edit → Modify the generated commands
80
+ ```
81
+
72
82
  ### `/ralph-orchestrator` — Multi-Agent Patterns
73
83
 
74
84
  Analyzes your task and recommends the best orchestration strategy:
package/lib/state.mjs CHANGED
@@ -8,6 +8,7 @@ const DEFAULT_STATE = {
8
8
  maxIterations: 20,
9
9
  currentIteration: 0,
10
10
  sessionId: "",
11
+ queue: [],
11
12
  };
12
13
 
13
14
  export function getStatePath() {
@@ -75,7 +75,40 @@ export async function processStopHook(hookInput, readStateFn, writeStateFn) {
75
75
  stderr.push(
76
76
  `Ralph loop: max iterations (${state.maxIterations}) reached.\n`,
77
77
  );
78
+
79
+ // On max iterations, also check queue for next phase
80
+ const queue = Array.isArray(state.queue) ? state.queue : [];
81
+ if (queue.length > 0) {
82
+ const next = queue.shift();
83
+ state.prompt = next.prompt;
84
+ state.completionPromise = next.completionPromise || "TADA";
85
+ state.maxIterations = next.maxIterations || 20;
86
+ state.currentIteration = 0;
87
+ state.queue = queue;
88
+ await writeStateFn(state);
89
+
90
+ stderr.push(
91
+ `Ralph loop: advancing to next phase (${queue.length} remaining).\n`,
92
+ );
93
+ const reason = [
94
+ state.prompt,
95
+ "",
96
+ "---",
97
+ `Ralph Loop — new phase started (iteration 1/${state.maxIterations}). Previous phase hit max iterations. Work on the task above.`,
98
+ ].join("\n");
99
+ const output = { decision: "block", reason };
100
+ if (state.completionPromise) {
101
+ output.systemMessage = `Ralph phase started (${queue.length} more queued) | To complete: output <promise>${state.completionPromise}</promise>`;
102
+ }
103
+ return {
104
+ exitCode: 0,
105
+ stdout: JSON.stringify(output),
106
+ stderr: stderr.join(""),
107
+ };
108
+ }
109
+
78
110
  state.active = false;
111
+ state.queue = [];
79
112
  await writeStateFn(state);
80
113
  return { exitCode: 0, stdout: "", stderr: stderr.join("") };
81
114
  }
@@ -91,7 +124,45 @@ export async function processStopHook(hookInput, readStateFn, writeStateFn) {
91
124
  stderr.push(
92
125
  `Ralph loop: completion promise "${state.completionPromise}" detected.\n`,
93
126
  );
127
+
128
+ // Check queue for next phase
129
+ const queue = Array.isArray(state.queue) ? state.queue : [];
130
+ if (queue.length > 0) {
131
+ const next = queue.shift();
132
+ state.prompt = next.prompt;
133
+ state.completionPromise = next.completionPromise || "TADA";
134
+ state.maxIterations = next.maxIterations || 20;
135
+ state.currentIteration = 0;
136
+ state.queue = queue;
137
+ await writeStateFn(state);
138
+
139
+ const phasesLeft = queue.length;
140
+ stderr.push(
141
+ `Ralph loop: advancing to next phase (${phasesLeft} remaining in queue).\n`,
142
+ );
143
+
144
+ const nextIterInfo =
145
+ state.maxIterations > 0 ? `1/${state.maxIterations}` : "1";
146
+ const reason = [
147
+ state.prompt,
148
+ "",
149
+ "---",
150
+ `Ralph Loop — new phase started (iteration ${nextIterInfo}). Work on the task above.`,
151
+ ].join("\n");
152
+
153
+ const output = { decision: "block", reason };
154
+ if (state.completionPromise) {
155
+ output.systemMessage = `Ralph phase started (${phasesLeft} more queued) | To complete: output <promise>${state.completionPromise}</promise> (ONLY when TRUE)`;
156
+ }
157
+ return {
158
+ exitCode: 0,
159
+ stdout: JSON.stringify(output),
160
+ stderr: stderr.join(""),
161
+ };
162
+ }
163
+
94
164
  state.active = false;
165
+ state.queue = [];
95
166
  await writeStateFn(state);
96
167
  return { exitCode: 0, stdout: "", stderr: stderr.join("") };
97
168
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graypark/ralph-codex",
3
- "version": "0.4.3",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
5
  "description": "Ralph Loop for Codex CLI & Claude Code — iterative dev loops with multi-agent orchestration, interactive interview, and stop hooks",
6
6
  "license": "MIT",
@@ -154,9 +154,52 @@ Read .ralph/reports/merged.md, then for each item:
154
154
  Output <promise>[PROMISE]</promise>" --max-iterations [N] --completion-promise "[PROMISE]"
155
155
  ```
156
156
 
157
- ### Multi-Phase
157
+ ### Multi-Phase (Pipeline Mode — DEFAULT)
158
+
159
+ When a task requires multiple phases, generate a **single** `/ralph-loop:ralph-loop` command with a `queue` in the state file. The stop hook automatically advances to the next phase when a completion promise is detected.
160
+
161
+ **How to set up pipeline mode:**
162
+
163
+ Create the state file at `.codex/ralph-loop.state.json` with a queue:
164
+
165
+ ```json
166
+ {
167
+ "active": true,
168
+ "prompt": "Phase 1 prompt here...",
169
+ "completionPromise": "PHASE1_DONE",
170
+ "maxIterations": 10,
171
+ "currentIteration": 0,
172
+ "sessionId": "",
173
+ "queue": [
174
+ {
175
+ "prompt": "Phase 2 prompt here...",
176
+ "completionPromise": "PHASE2_DONE",
177
+ "maxIterations": 20
178
+ },
179
+ {
180
+ "prompt": "Phase 3 prompt here...",
181
+ "completionPromise": "TADA",
182
+ "maxIterations": 15
183
+ }
184
+ ]
185
+ }
186
+ ```
187
+
188
+ Then start with:
189
+
190
+ ```
191
+ /ralph-loop:ralph-loop "Phase 1 prompt here..." --max-iterations 10 --completion-promise "PHASE1_DONE"
192
+ ```
193
+
194
+ When Phase 1 completes, the stop hook will automatically:
158
195
 
159
- Generate each Phase as a separate `/ralph-loop:ralph-loop` command:
196
+ 1. Detect the completion promise
197
+ 2. Load Phase 2 from the queue
198
+ 3. Re-inject Phase 2's prompt as a new loop — no user intervention needed
199
+
200
+ ### Multi-Phase (Manual Mode)
201
+
202
+ If the user chooses manual mode, generate each Phase as a separate `/ralph-loop:ralph-loop` command:
160
203
 
161
204
  - State Phase number and dependencies explicitly.
162
205
  - Link prior Phase outputs as references in the next Phase.
@@ -215,30 +258,63 @@ To cancel at any time: `/ralph-loop:cancel-ralph`
215
258
  [Assistant] → Asks interview questions (1 round, max 5 questions)
216
259
  [User] → Answers
217
260
  [Assistant] → Generates Phase plan + command blocks
218
- [Assistant] → Asks: "Run Phase 1 now? (y/n)"
219
- [User] → "y"
220
- [Assistant] → Executes the /ralph-loop:ralph-loop command immediately via Skill tool
261
+ [Assistant] → Asks: "Ready to run?" with options
262
+ [User] → Chooses an option
263
+ [Assistant] → Executes accordingly
221
264
  ```
222
265
 
223
266
  ### Quick-Run Flow
224
267
 
225
- If the user includes phrases like "run immediately", "just do it", "바로 실행", "바로 시작", or "--run" in their initial message:
268
+ If the user includes phrases like "run immediately", "just do it", "run it", "바로 실행", "바로 시작", or "--run" in their initial message:
226
269
 
227
270
  1. Conduct the interview as normal (skip if enough context is provided).
228
271
  2. Generate the command blocks.
229
- 3. **Immediately execute Phase 1** without asking for confirmation.
230
- 4. Show the command that was executed so the user can see what's running.
272
+ 3. For multi-phase: write state file with queue via Bash.
273
+ 4. Show the generated command briefly.
274
+ 5. Immediately call the Skill tool with skill="ralph-loop:ralph-loop" and the Phase 1 args. Do NOT wait for user confirmation.
231
275
 
232
276
  ### Post-Generation Action
233
277
 
234
278
  After generating all command blocks, ALWAYS end with this prompt:
235
279
 
280
+ **For multi-phase tasks:**
281
+
236
282
  ```
237
283
  ---
238
284
  **Ready to run?**
239
- - **y** / **yes** / **실행** → I'll start Phase 1 immediately
285
+ - **y** / **yes** / **실행** → Pipeline mode: run all phases automatically (Phase 1 → 2 → 3, no stops between phases)
286
+ - **step** / **단계별** → Manual mode: run Phase 1 only, I'll ask before each next phase
240
287
  - **n** / **no** / **아니오** → Commands are above, copy-paste when ready
241
288
  - **edit** / **수정** → Tell me what to change
242
289
  ```
243
290
 
244
- When the user confirms, execute the Phase 1 command by invoking the `ralph-loop:ralph-loop` skill with the generated arguments. For multi-phase work, after each Phase completes, prompt to run the next Phase.
291
+ **For single-phase tasks:**
292
+
293
+ ```
294
+ ---
295
+ **Ready to run?**
296
+ - **y** / **yes** / **실행** → Start immediately
297
+ - **n** / **no** / **아니오** → Command is above, copy-paste when ready
298
+ - **edit** / **수정** → Tell me what to change
299
+ ```
300
+
301
+ ### Execution Modes
302
+
303
+ IMPORTANT: When the user confirms execution, you MUST actually start the loop by calling the Skill tool with skill "ralph-loop:ralph-loop" and the generated args. Do NOT just write a state file or print the command. The Skill tool invocation is what triggers the real loop.
304
+
305
+ **Pipeline mode (default for "y"):**
306
+
307
+ 1. For multi-phase: write the state file with queue via Bash
308
+ 2. Call the Skill tool: skill="ralph-loop:ralph-loop", args="<Phase 1 prompt> --max-iterations N --completion-promise PROMISE"
309
+ 3. The stop hook handles phase transitions automatically
310
+
311
+ **Manual mode ("step"):**
312
+
313
+ 1. Call the Skill tool: skill="ralph-loop:ralph-loop", args="<Phase 1 prompt> --max-iterations N --completion-promise PROMISE"
314
+ 2. When Phase 1 completes, ask user before calling Skill tool again for Phase 2
315
+
316
+ **Single-phase ("y"):**
317
+
318
+ 1. Call the Skill tool: skill="ralph-loop:ralph-loop", args="<prompt> --max-iterations N --completion-promise PROMISE"
319
+
320
+ After the user says "y", "yes", or similar, you MUST immediately use the Skill tool. Do not just describe what would happen. Do not tell the user to copy-paste. Actually invoke the skill.