bmalph 2.7.2 → 2.7.4

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.
Files changed (46) hide show
  1. package/README.md +14 -4
  2. package/dist/commands/doctor-checks.js +17 -10
  3. package/dist/commands/doctor-checks.js.map +1 -1
  4. package/dist/run/ralph-process.js +101 -7
  5. package/dist/run/ralph-process.js.map +1 -1
  6. package/dist/transition/artifact-collection.js +74 -0
  7. package/dist/transition/artifact-collection.js.map +1 -0
  8. package/dist/transition/artifacts.js +12 -1
  9. package/dist/transition/artifacts.js.map +1 -1
  10. package/dist/transition/context.js +17 -25
  11. package/dist/transition/context.js.map +1 -1
  12. package/dist/transition/fix-plan.js +12 -7
  13. package/dist/transition/fix-plan.js.map +1 -1
  14. package/dist/transition/orchestration.js +213 -116
  15. package/dist/transition/orchestration.js.map +1 -1
  16. package/dist/transition/preflight.js +30 -17
  17. package/dist/transition/preflight.js.map +1 -1
  18. package/dist/transition/section-patterns.js +56 -4
  19. package/dist/transition/section-patterns.js.map +1 -1
  20. package/dist/transition/specs-index.js +5 -2
  21. package/dist/transition/specs-index.js.map +1 -1
  22. package/dist/transition/specs-sync.js +23 -0
  23. package/dist/transition/specs-sync.js.map +1 -0
  24. package/dist/transition/sprint-status.js +91 -0
  25. package/dist/transition/sprint-status.js.map +1 -0
  26. package/dist/transition/story-id.js +46 -0
  27. package/dist/transition/story-id.js.map +1 -0
  28. package/dist/transition/story-parsing.js +7 -7
  29. package/dist/transition/story-parsing.js.map +1 -1
  30. package/dist/transition/tech-stack.js +1 -7
  31. package/dist/transition/tech-stack.js.map +1 -1
  32. package/package.json +1 -1
  33. package/ralph/RALPH-REFERENCE.md +50 -46
  34. package/ralph/drivers/claude-code.sh +44 -2
  35. package/ralph/drivers/codex.sh +10 -1
  36. package/ralph/drivers/copilot.sh +5 -0
  37. package/ralph/drivers/cursor-agent-wrapper.sh +13 -0
  38. package/ralph/drivers/cursor.sh +178 -14
  39. package/ralph/lib/circuit_breaker.sh +5 -5
  40. package/ralph/lib/enable_core.sh +10 -10
  41. package/ralph/lib/response_analyzer.sh +357 -111
  42. package/ralph/ralph_import.sh +14 -10
  43. package/ralph/ralph_loop.sh +168 -119
  44. package/ralph/ralph_monitor.sh +4 -4
  45. package/ralph/templates/AGENT.md +7 -7
  46. package/ralph/templates/PROMPT.md +13 -13
@@ -2,10 +2,12 @@
2
2
 
3
3
  This reference guide provides essential information for troubleshooting and understanding Ralph's autonomous development loop.
4
4
 
5
+ In bmalph-managed projects, start Ralph with `bmalph run`. When you need direct loop flags such as `--reset-circuit` or `--live`, invoke `bash .ralph/ralph_loop.sh ...` from the project root.
6
+
5
7
  ## Table of Contents
6
8
 
7
9
  1. [Configuration Files](#configuration-files)
8
- 2. [Project Configuration (.ralphrc)](#project-configuration-ralphrc)
10
+ 2. [Project Configuration (.ralph/.ralphrc)](#project-configuration-ralphralphrc)
9
11
  3. [Session Management](#session-management)
10
12
  4. [Circuit Breaker](#circuit-breaker)
11
13
  5. [Exit Detection](#exit-detection)
@@ -16,12 +18,12 @@ This reference guide provides essential information for troubleshooting and unde
16
18
 
17
19
  ## Configuration Files
18
20
 
19
- Ralph uses several files within the `.ralph/` directory:
21
+ Ralph uses several files within the `.ralph/` directory, plus an optional legacy fallback config at the project root:
20
22
 
21
23
  | File | Purpose |
22
24
  |------|---------|
23
25
  | `.ralph/PROMPT.md` | Main prompt that drives each loop iteration |
24
- | `.ralph/fix_plan.md` | Prioritized task list that Ralph follows |
26
+ | `.ralph/@fix_plan.md` | Prioritized task list that Ralph follows |
25
27
  | `.ralph/@AGENT.md` | Build and run instructions maintained by Ralph |
26
28
  | `.ralph/status.json` | Real-time status tracking (JSON format) |
27
29
  | `.ralph/logs/` | Execution logs for each loop iteration |
@@ -29,23 +31,25 @@ Ralph uses several files within the `.ralph/` directory:
29
31
  | `.ralph/.circuit_breaker_state` | Circuit breaker state |
30
32
  | `.ralph/live.log` | Live streaming output file for monitoring |
31
33
  | `.ralph/.loop_start_sha` | Git HEAD SHA captured at loop start for progress detection |
32
- | `.ralphrc` (project root) | Project-specific configuration (tools, thresholds, session settings) |
34
+ | `.ralph/.ralphrc` | Project-specific configuration installed by bmalph |
35
+ | `.ralphrc` (project root, legacy fallback) | Optional legacy configuration for older standalone Ralph layouts |
33
36
 
34
37
  ### Rate Limiting
35
38
 
36
- - Default: 100 API calls per hour (configurable via `--calls` flag or `.ralphrc`)
39
+ - Default: 100 API calls per hour (configurable via `--calls` flag or `.ralph/.ralphrc`)
37
40
  - Automatic hourly reset with countdown display
38
41
  - Call tracking persists across script restarts
39
42
 
40
43
  ---
41
44
 
42
- ## Project Configuration (.ralphrc)
45
+ ## Project Configuration (.ralph/.ralphrc)
43
46
 
44
- Ralph supports a `.ralphrc` configuration file at the project root for per-project settings.
47
+ In bmalph-managed projects, Ralph reads `.ralph/.ralphrc` for per-project settings.
48
+ For backward compatibility with older standalone Ralph layouts, it also falls back to a project-root `.ralphrc` when the bundled config file is missing.
45
49
 
46
50
  ### Precedence
47
51
 
48
- Environment variables > `.ralphrc` > script defaults
52
+ Environment variables > Ralph config file > script defaults
49
53
 
50
54
  ### Available Settings
51
55
 
@@ -54,7 +58,7 @@ Environment variables > `.ralphrc` > script defaults
54
58
  | `PROJECT_NAME` | `my-project` | Project name for prompts and logging |
55
59
  | `PROJECT_TYPE` | `unknown` | Project type (javascript, typescript, python, rust, go) |
56
60
  | `MAX_CALLS_PER_HOUR` | `100` | Rate limit for API calls |
57
- | `CLAUDE_TIMEOUT_MINUTES` | `15` | Timeout per Claude Code invocation |
61
+ | `CLAUDE_TIMEOUT_MINUTES` | `15` | Timeout per loop driver invocation |
58
62
  | `CLAUDE_OUTPUT_FORMAT` | `json` | Output format (json or text) |
59
63
  | `ALLOWED_TOOLS` | `Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)` | Comma-separated allowed tools |
60
64
  | `SESSION_CONTINUITY` | `true` | Maintain context across loops |
@@ -69,7 +73,7 @@ Environment variables > `.ralphrc` > script defaults
69
73
 
70
74
  ### Generation
71
75
 
72
- bmalph copies `ralphrc.template` to `.ralph/.ralphrc` during `bmalph init`. Existing `.ralphrc` files are preserved during upgrades.
76
+ bmalph copies `ralphrc.template` to `.ralph/.ralphrc` during `bmalph init`. Existing `.ralph/.ralphrc` files are preserved during upgrades.
73
77
 
74
78
  ---
75
79
 
@@ -79,7 +83,7 @@ Ralph maintains session continuity across loop iterations using `--resume` with
79
83
 
80
84
  ### Session Continuity
81
85
 
82
- Ralph uses `--resume <session_id>` instead of `--continue` to resume sessions. This ensures Ralph only resumes its own sessions and avoids hijacking active Claude Code sessions the user may have open.
86
+ Ralph uses `--resume <session_id>` instead of `--continue` to resume sessions. This ensures Ralph only resumes its own saved sessions and avoids hijacking unrelated active sessions.
83
87
 
84
88
  ### Session Files
85
89
 
@@ -87,7 +91,7 @@ Ralph uses `--resume <session_id>` instead of `--continue` to resume sessions. T
87
91
  |------|---------|
88
92
  | `.ralph/.ralph_session` | Current session ID and timestamps |
89
93
  | `.ralph/.ralph_session_history` | History of last 50 session transitions |
90
- | `.ralph/.claude_session_id` | Claude Code CLI session persistence |
94
+ | `.ralph/.claude_session_id` | Persisted driver session ID (shared filename for historical reasons) |
91
95
 
92
96
  ### Session Lifecycle
93
97
 
@@ -95,12 +99,12 @@ Sessions are automatically reset when:
95
99
  - Circuit breaker opens (stagnation detected)
96
100
  - Manual interrupt (Ctrl+C / SIGINT)
97
101
  - Project completion (graceful exit)
98
- - Manual circuit breaker reset (`ralph --reset-circuit`)
99
- - Manual session reset (`ralph --reset-session`)
102
+ - Manual circuit breaker reset (`bash .ralph/ralph_loop.sh --reset-circuit`)
103
+ - Manual session reset (`bash .ralph/ralph_loop.sh --reset-session`)
100
104
 
101
105
  ### Session Expiration
102
106
 
103
- Sessions expire after 24 hours (configurable via `SESSION_EXPIRY_HOURS` in `.ralphrc`). When expired:
107
+ Sessions expire after 24 hours (configurable via `SESSION_EXPIRY_HOURS` in `.ralph/.ralphrc`). When expired:
104
108
  - A new session is created automatically
105
109
  - Previous context is not preserved
106
110
  - Session history records the transition
@@ -144,16 +148,16 @@ The circuit breaker prevents runaway loops by detecting stagnation.
144
148
 
145
149
  ### Permission Denial Detection
146
150
 
147
- When Claude Code is denied permission to execute commands, Ralph:
151
+ When the active driver is denied permission to execute commands, Ralph:
148
152
  1. Detects permission denials from the JSON output
149
153
  2. Halts the loop with reason `permission_denied`
150
- 3. Displays guidance to update `ALLOWED_TOOLS` in `.ralphrc`
154
+ 3. Displays guidance to update `ALLOWED_TOOLS` in `.ralph/.ralphrc`
151
155
 
152
156
  ### Auto-Recovery Cooldown
153
157
 
154
158
  After `CB_COOLDOWN_MINUTES` (default: 30) in OPEN state, the circuit auto-transitions to HALF_OPEN. From HALF_OPEN, if progress is detected, circuit goes to CLOSED; otherwise back to OPEN.
155
159
 
156
- Set `CB_AUTO_RESET=true` in `.ralphrc` to bypass cooldown entirely and reset to CLOSED on startup.
160
+ Set `CB_AUTO_RESET=true` in `.ralph/.ralphrc` to bypass cooldown entirely and reset to CLOSED on startup.
157
161
 
158
162
  ### Circuit Breaker State Structure
159
163
 
@@ -175,7 +179,7 @@ Set `CB_AUTO_RESET=true` in `.ralphrc` to bypass cooldown entirely and reset to
175
179
 
176
180
  To reset the circuit breaker:
177
181
  ```bash
178
- ralph --reset-circuit
182
+ bash .ralph/ralph_loop.sh --reset-circuit
179
183
  ```
180
184
 
181
185
  ---
@@ -200,17 +204,17 @@ The `completion_indicators` exit condition requires dual verification:
200
204
  | completion_indicators | EXIT_SIGNAL | Result |
201
205
  |-----------------------|-------------|--------|
202
206
  | >= 2 | `true` | **Exit** ("project_complete") |
203
- | >= 2 | `false` | **Continue** (Claude still working) |
207
+ | >= 2 | `false` | **Continue** (agent still working) |
204
208
  | >= 2 | missing | **Continue** (defaults to false) |
205
209
  | < 2 | `true` | **Continue** (threshold not met) |
206
210
 
207
- **Rationale:** Natural language patterns like "done" or "complete" can trigger false positives during productive work. By requiring Claude's explicit EXIT_SIGNAL confirmation, Ralph avoids exiting mid-iteration.
211
+ **Rationale:** Natural language patterns like "done" or "complete" can trigger false positives during productive work. By requiring an explicit `EXIT_SIGNAL` confirmation, Ralph avoids exiting mid-iteration.
208
212
 
209
- When Claude outputs `STATUS: COMPLETE` with `EXIT_SIGNAL: false`, the explicit `false` takes precedence. This allows marking a phase complete while indicating more phases remain.
213
+ When the agent outputs `STATUS: COMPLETE` with `EXIT_SIGNAL: false`, the explicit `false` takes precedence. This allows marking a phase complete while indicating more phases remain.
210
214
 
211
215
  ### RALPH_STATUS Block
212
216
 
213
- Claude should include this status block at the end of each response:
217
+ The coding agent should include this status block at the end of each response:
214
218
 
215
219
  ```
216
220
  ---RALPH_STATUS---
@@ -227,7 +231,7 @@ RECOMMENDATION: <one line summary of what to do next>
227
231
  ### When to Set EXIT_SIGNAL: true
228
232
 
229
233
  Set EXIT_SIGNAL to **true** when ALL conditions are met:
230
- 1. All items in fix_plan.md are marked [x]
234
+ 1. All items in `@fix_plan.md` are marked `[x]`
231
235
  2. All tests are passing (or no tests exist for valid reasons)
232
236
  3. No errors or warnings in the last execution
233
237
  4. All requirements from specs/ are implemented
@@ -246,8 +250,8 @@ Ralph supports real-time streaming output with the `--live` flag.
246
250
  ### Usage
247
251
 
248
252
  ```bash
249
- ralph --live # Live streaming output
250
- ralph --monitor --live # Live streaming with tmux monitoring
253
+ bash .ralph/ralph_loop.sh --live # Live streaming output
254
+ bash .ralph/ralph_loop.sh --monitor --live # Live streaming with tmux monitoring
251
255
  ```
252
256
 
253
257
  ### How It Works
@@ -260,8 +264,8 @@ ralph --monitor --live # Live streaming with tmux monitoring
260
264
 
261
265
  When using `--monitor` with `--live`, tmux creates a 3-pane layout:
262
266
  - **Left pane:** Ralph loop with live streaming
263
- - **Right-top pane:** `tail -f .ralph/live.log` (Claude Code live output)
264
- - **Right-bottom pane:** `ralph-monitor` (status dashboard)
267
+ - **Right-top pane:** `tail -f .ralph/live.log` (live driver output)
268
+ - **Right-bottom pane:** status dashboard (`bmalph watch` when available)
265
269
 
266
270
  ---
267
271
 
@@ -276,11 +280,11 @@ When using `--monitor` with `--live`, tmux creates a 3-pane layout:
276
280
  **Causes:**
277
281
  - EXIT_SIGNAL set to true prematurely
278
282
  - completion_indicators triggered by natural language
279
- - All fix_plan.md items marked complete
283
+ - All `@fix_plan.md` items marked complete
280
284
 
281
285
  **Solutions:**
282
286
  1. Ensure EXIT_SIGNAL is only true when genuinely complete
283
- 2. Add remaining tasks to fix_plan.md
287
+ 2. Add remaining tasks to `@fix_plan.md`
284
288
  3. Check `.ralph/.response_analysis` for exit reasons
285
289
 
286
290
  #### Ralph doesn't exit when complete
@@ -289,13 +293,13 @@ When using `--monitor` with `--live`, tmux creates a 3-pane layout:
289
293
 
290
294
  **Causes:**
291
295
  - EXIT_SIGNAL not being set to true
292
- - fix_plan.md has unmarked items
296
+ - `@fix_plan.md` has unmarked items
293
297
  - completion_indicators threshold not met
294
298
 
295
299
  **Solutions:**
296
300
  1. Ensure RALPH_STATUS block is included in responses
297
301
  2. Set EXIT_SIGNAL: true when all work is done
298
- 3. Mark all completed items in fix_plan.md
302
+ 3. Mark all completed items in `@fix_plan.md`
299
303
 
300
304
  #### Circuit breaker opens unexpectedly
301
305
 
@@ -309,19 +313,19 @@ When using `--monitor` with `--live`, tmux creates a 3-pane layout:
309
313
  **Solutions:**
310
314
  1. Check `.ralph/logs/` for the recurring error
311
315
  2. Fix the underlying issue causing the error
312
- 3. Reset circuit breaker: `ralph --reset-circuit`
316
+ 3. Reset circuit breaker: `bash .ralph/ralph_loop.sh --reset-circuit`
313
317
 
314
318
  #### Permission denied halts loop
315
319
 
316
320
  **Symptoms:** "OPEN - permission_denied" message
317
321
 
318
322
  **Causes:**
319
- - Claude Code denied permission to run commands
320
- - `ALLOWED_TOOLS` in `.ralphrc` too restrictive
323
+ - The active driver denied permission to run commands
324
+ - `ALLOWED_TOOLS` in `.ralph/.ralphrc` too restrictive
321
325
 
322
326
  **Solutions:**
323
- 1. Update `ALLOWED_TOOLS` in `.ralphrc` to include needed tools
324
- 2. Reset circuit breaker: `ralph --reset-circuit`
327
+ 1. Update `ALLOWED_TOOLS` in `.ralph/.ralphrc` to include needed tools
328
+ 2. Reset circuit breaker: `bash .ralph/ralph_loop.sh --reset-circuit`
325
329
  3. Common tools: `Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)`
326
330
 
327
331
  #### Session expires mid-project
@@ -334,32 +338,32 @@ When using `--monitor` with `--live`, tmux creates a 3-pane layout:
334
338
 
335
339
  **Solutions:**
336
340
  1. Sessions are designed to expire after 24h (configurable via `SESSION_EXPIRY_HOURS`)
337
- 2. Start a new session with `ralph --reset-session`
338
- 3. Context will be rebuilt from fix_plan.md and specs/
341
+ 2. Start a new session with `bash .ralph/ralph_loop.sh --reset-session`
342
+ 3. Context will be rebuilt from `@fix_plan.md` and `specs/`
339
343
 
340
344
  ### Diagnostic Commands
341
345
 
342
346
  ```bash
343
347
  # Check Ralph status
344
- ralph --status
348
+ bash .ralph/ralph_loop.sh --status
345
349
 
346
350
  # Check circuit breaker state
347
- ralph --circuit-status
351
+ bash .ralph/ralph_loop.sh --circuit-status
348
352
 
349
353
  # Reset circuit breaker
350
- ralph --reset-circuit
354
+ bash .ralph/ralph_loop.sh --reset-circuit
351
355
 
352
356
  # Auto-reset circuit breaker (bypasses cooldown)
353
- ralph --auto-reset-circuit
357
+ bash .ralph/ralph_loop.sh --auto-reset-circuit
354
358
 
355
359
  # Reset session
356
- ralph --reset-session
360
+ bash .ralph/ralph_loop.sh --reset-session
357
361
 
358
362
  # Enable live streaming
359
- ralph --live
363
+ bash .ralph/ralph_loop.sh --live
360
364
 
361
365
  # Live streaming with monitoring
362
- ralph --monitor --live
366
+ bash .ralph/ralph_loop.sh --monitor --live
363
367
  ```
364
368
 
365
369
  ### Log Files
@@ -112,7 +112,49 @@ driver_supports_sessions() {
112
112
  return 0 # true
113
113
  }
114
114
 
115
- # Stream filter for live output (jq filter for JSON streaming)
115
+ # Claude Code supports stream-json live output.
116
+ driver_supports_live_output() {
117
+ return 0 # true
118
+ }
119
+
120
+ # Prepare command arguments for live stream-json output.
121
+ driver_prepare_live_command() {
122
+ LIVE_CMD_ARGS=()
123
+ local skip_next=false
124
+
125
+ for arg in "${CLAUDE_CMD_ARGS[@]}"; do
126
+ if [[ "$skip_next" == "true" ]]; then
127
+ LIVE_CMD_ARGS+=("stream-json")
128
+ skip_next=false
129
+ elif [[ "$arg" == "--output-format" ]]; then
130
+ LIVE_CMD_ARGS+=("$arg")
131
+ skip_next=true
132
+ else
133
+ LIVE_CMD_ARGS+=("$arg")
134
+ fi
135
+ done
136
+
137
+ if [[ "$skip_next" == "true" ]]; then
138
+ return 1
139
+ fi
140
+
141
+ LIVE_CMD_ARGS+=("--verbose" "--include-partial-messages")
142
+ }
143
+
144
+ # Stream filter for raw Claude stream-json events.
116
145
  driver_stream_filter() {
117
- echo '.content // empty | select(type == "string")'
146
+ echo '
147
+ if .type == "stream_event" then
148
+ if .event.type == "content_block_delta" and .event.delta.type == "text_delta" then
149
+ .event.delta.text
150
+ elif .event.type == "content_block_start" and .event.content_block.type == "tool_use" then
151
+ "\n\n⚡ [" + .event.content_block.name + "]\n"
152
+ elif .event.type == "content_block_stop" then
153
+ "\n"
154
+ else
155
+ empty
156
+ end
157
+ else
158
+ empty
159
+ end'
118
160
  }
@@ -75,7 +75,16 @@ driver_supports_sessions() {
75
75
  return 0 # true - Codex supports session resume
76
76
  }
77
77
 
78
+ # Codex JSONL output is already suitable for live display.
79
+ driver_supports_live_output() {
80
+ return 0 # true
81
+ }
82
+
83
+ driver_prepare_live_command() {
84
+ LIVE_CMD_ARGS=("${CLAUDE_CMD_ARGS[@]}")
85
+ }
86
+
78
87
  # Codex outputs JSONL events
79
88
  driver_stream_filter() {
80
- echo 'select(.type == "message") | .content // empty'
89
+ echo 'select(.type == "item.completed" and .item.type == "agent_message") | (.item.text // ([.item.content[]? | select(.type == "output_text") | .text] | join("\n")) // empty)'
81
90
  }
@@ -82,6 +82,11 @@ driver_supports_sessions() {
82
82
  return 1 # false — session IDs not capturable from -p output
83
83
  }
84
84
 
85
+ # Copilot CLI does not expose structured live output for jq streaming.
86
+ driver_supports_live_output() {
87
+ return 1 # false
88
+ }
89
+
85
90
  # Copilot CLI outputs plain text only (no JSON streaming).
86
91
  # Passthrough filter — no transformation needed.
87
92
  driver_stream_filter() {
@@ -0,0 +1,13 @@
1
+ #!/bin/bash
2
+ # Wrap Windows .cmd execution so GNU timeout launches a bash script instead of the .cmd directly.
3
+
4
+ set -euo pipefail
5
+
6
+ cli_path=${1:-}
7
+ if [[ -z "$cli_path" ]]; then
8
+ echo "ERROR: Missing Cursor CLI path" >&2
9
+ exit 1
10
+ fi
11
+
12
+ shift
13
+ exec "$cli_path" "$@"
@@ -5,7 +5,7 @@
5
5
  # Known limitations:
6
6
  # - CLI is in beta — binary name and flags may change
7
7
  # - NDJSON stream format assumes {type: "text", content: "..."} events
8
- # - Session ID capture from output not yet validated
8
+ # - Session continuity is disabled until Cursor exposes a stable capturable session ID
9
9
 
10
10
  driver_name() {
11
11
  echo "cursor"
@@ -16,7 +16,15 @@ driver_display_name() {
16
16
  }
17
17
 
18
18
  driver_cli_binary() {
19
- echo "agent"
19
+ local binary
20
+ binary=$(driver_resolve_cli_binary)
21
+
22
+ if [[ -n "$binary" ]]; then
23
+ echo "$binary"
24
+ return 0
25
+ fi
26
+
27
+ echo "cursor-agent"
20
28
  }
21
29
 
22
30
  driver_min_version() {
@@ -24,7 +32,14 @@ driver_min_version() {
24
32
  }
25
33
 
26
34
  driver_check_available() {
27
- command -v "$(driver_cli_binary)" &>/dev/null
35
+ local cli_binary
36
+ cli_binary=$(driver_cli_binary)
37
+
38
+ if [[ -f "$cli_binary" ]]; then
39
+ return 0
40
+ fi
41
+
42
+ command -v "$cli_binary" &>/dev/null
28
43
  }
29
44
 
30
45
  # Cursor CLI tool names
@@ -46,14 +61,21 @@ driver_build_command() {
46
61
  local prompt_file=$1
47
62
  local loop_context=$2
48
63
  local session_id=$3
49
-
50
- CLAUDE_CMD_ARGS=("$(driver_cli_binary)")
64
+ local cli_binary
65
+ cli_binary=$(driver_cli_binary)
51
66
 
52
67
  if [[ ! -f "$prompt_file" ]]; then
53
68
  echo "ERROR: Prompt file not found: $prompt_file" >&2
54
69
  return 1
55
70
  fi
56
71
 
72
+ CLAUDE_CMD_ARGS=()
73
+ if [[ "$cli_binary" == *.cmd ]]; then
74
+ CLAUDE_CMD_ARGS+=("$(driver_wrapper_path)" "$cli_binary")
75
+ else
76
+ CLAUDE_CMD_ARGS+=("$cli_binary")
77
+ fi
78
+
57
79
  # Headless mode
58
80
  CLAUDE_CMD_ARGS+=("--print")
59
81
 
@@ -63,28 +85,170 @@ driver_build_command() {
63
85
  # NDJSON streaming output
64
86
  CLAUDE_CMD_ARGS+=("--output-format" "stream-json")
65
87
 
66
- # Session resume — gated on CLAUDE_USE_CONTINUE to respect --no-continue flag
67
- if [[ "$CLAUDE_USE_CONTINUE" == "true" && -n "$session_id" ]]; then
68
- CLAUDE_CMD_ARGS+=("--resume" "$session_id")
69
- fi
70
-
71
88
  # Build prompt with context prepended
72
89
  local prompt_content
73
- prompt_content=$(cat "$prompt_file")
74
- if [[ -n "$loop_context" ]]; then
75
- prompt_content="$loop_context
90
+ if driver_running_on_windows; then
91
+ prompt_content=$(driver_build_windows_bootstrap_prompt "$loop_context" "$prompt_file")
92
+ else
93
+ prompt_content=$(cat "$prompt_file")
94
+ if [[ -n "$loop_context" ]]; then
95
+ prompt_content="$loop_context
76
96
 
77
97
  $prompt_content"
98
+ fi
78
99
  fi
79
100
 
80
101
  CLAUDE_CMD_ARGS+=("$prompt_content")
81
102
  }
82
103
 
83
104
  driver_supports_sessions() {
84
- return 0 # trueCursor supports --resume
105
+ return 1 # falsesession IDs are not capturable from current NDJSON output
106
+ }
107
+
108
+ driver_supports_live_output() {
109
+ return 0 # true
110
+ }
111
+
112
+ driver_prepare_live_command() {
113
+ LIVE_CMD_ARGS=("${CLAUDE_CMD_ARGS[@]}")
85
114
  }
86
115
 
87
116
  # Cursor CLI outputs NDJSON events
88
117
  driver_stream_filter() {
89
118
  echo 'select(.type == "text") | .content // empty'
90
119
  }
120
+
121
+ driver_running_on_windows() {
122
+ [[ "${OS:-}" == "Windows_NT" || "${OSTYPE:-}" == msys* || "${OSTYPE:-}" == cygwin* || "${OSTYPE:-}" == win32* ]]
123
+ }
124
+
125
+ driver_resolve_cli_binary() {
126
+ local candidate
127
+ local resolved
128
+ local fallback
129
+ local candidates=(
130
+ "cursor-agent"
131
+ "cursor-agent.cmd"
132
+ "agent"
133
+ "agent.cmd"
134
+ )
135
+
136
+ for candidate in "${candidates[@]}"; do
137
+ resolved=$(driver_lookup_cli_candidate "$candidate")
138
+ if [[ -n "$resolved" ]]; then
139
+ echo "$resolved"
140
+ return 0
141
+ fi
142
+ done
143
+
144
+ fallback=$(driver_localappdata_cli_binary)
145
+ if [[ -n "$fallback" ]]; then
146
+ echo "$fallback"
147
+ return 0
148
+ fi
149
+
150
+ echo ""
151
+ }
152
+
153
+ driver_lookup_cli_candidate() {
154
+ local candidate=$1
155
+ local resolved
156
+
157
+ resolved=$(command -v "$candidate" 2>/dev/null || true)
158
+ if [[ -n "$resolved" ]]; then
159
+ echo "$resolved"
160
+ return 0
161
+ fi
162
+
163
+ if ! driver_running_on_windows; then
164
+ return 0
165
+ fi
166
+
167
+ driver_find_windows_path_candidate "$candidate"
168
+ }
169
+
170
+ driver_find_windows_path_candidate() {
171
+ local candidate=$1
172
+ local path_entry
173
+ local normalized_entry
174
+ local resolved_candidate
175
+ local path_entries="${PATH:-}"
176
+ local -a path_parts=()
177
+
178
+ if [[ "$path_entries" == *";"* ]]; then
179
+ IFS=';' read -r -a path_parts <<< "$path_entries"
180
+ else
181
+ IFS=':' read -r -a path_parts <<< "$path_entries"
182
+ fi
183
+
184
+ for path_entry in "${path_parts[@]}"; do
185
+ [[ -z "$path_entry" ]] && continue
186
+
187
+ normalized_entry=$path_entry
188
+ if command -v cygpath &>/dev/null && [[ "$normalized_entry" =~ ^[A-Za-z]:\\ ]]; then
189
+ normalized_entry=$(cygpath -u "$normalized_entry")
190
+ fi
191
+
192
+ resolved_candidate="$normalized_entry/$candidate"
193
+ if [[ -f "$resolved_candidate" ]]; then
194
+ echo "$resolved_candidate"
195
+ return 0
196
+ fi
197
+ done
198
+ }
199
+
200
+ driver_localappdata_cli_binary() {
201
+ local local_app_data="${LOCALAPPDATA:-}"
202
+
203
+ if [[ -z "$local_app_data" ]] || ! driver_running_on_windows; then
204
+ return 0
205
+ fi
206
+
207
+ if command -v cygpath &>/dev/null && [[ "$local_app_data" =~ ^[A-Za-z]:\\ ]]; then
208
+ local_app_data=$(cygpath -u "$local_app_data")
209
+ fi
210
+
211
+ local candidate="$local_app_data/cursor-agent/agent.cmd"
212
+ if [[ -f "$candidate" ]]; then
213
+ echo "$candidate"
214
+ fi
215
+ }
216
+
217
+ driver_wrapper_path() {
218
+ local driver_dir
219
+ driver_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
220
+ echo "$driver_dir/cursor-agent-wrapper.sh"
221
+ }
222
+
223
+ driver_build_windows_bootstrap_prompt() {
224
+ local loop_context=$1
225
+ local prompt_file=$2
226
+
227
+ cat <<EOF
228
+ Read these Ralph workspace files before taking action:
229
+ - .ralph/PROMPT.md
230
+ - .ralph/PROJECT_CONTEXT.md
231
+ - .ralph/SPECS_INDEX.md
232
+ - .ralph/@fix_plan.md
233
+ - .ralph/@AGENT.md
234
+ - relevant files under .ralph/specs/
235
+
236
+ Then follow the Ralph instructions from those files and continue the next task.
237
+ EOF
238
+
239
+ if [[ -n "$loop_context" ]]; then
240
+ cat <<EOF
241
+
242
+ Current loop context:
243
+ $loop_context
244
+ EOF
245
+ fi
246
+
247
+ if [[ "$prompt_file" != ".ralph/PROMPT.md" ]]; then
248
+ cat <<EOF
249
+
250
+ Also read the active prompt file if it differs:
251
+ - $prompt_file
252
+ EOF
253
+ fi
254
+ }
@@ -463,16 +463,16 @@ should_halt_execution() {
463
463
  echo -e "${YELLOW}Ralph has detected that no progress is being made.${NC}"
464
464
  echo ""
465
465
  echo -e "${YELLOW}Possible reasons:${NC}"
466
- echo " • Project may be complete (check .ralph/fix_plan.md)"
467
- echo " • Claude may be stuck on an error"
466
+ echo " • Project may be complete (check .ralph/@fix_plan.md)"
467
+ echo " • The active driver may be stuck on an error"
468
468
  echo " • .ralph/PROMPT.md may need clarification"
469
469
  echo " • Manual intervention may be required"
470
470
  echo ""
471
471
  echo -e "${YELLOW}To continue:${NC}"
472
472
  echo " 1. Review recent logs: tail -20 .ralph/logs/ralph.log"
473
- echo " 2. Check Claude output: ls -lt .ralph/logs/claude_output_*.log | head -1"
474
- echo " 3. Update .ralph/fix_plan.md if needed"
475
- echo " 4. Reset circuit breaker: ralph --reset-circuit"
473
+ echo " 2. Check recent driver output: ls -lt .ralph/logs/claude_output_*.log | head -1"
474
+ echo " 3. Update .ralph/@fix_plan.md if needed"
475
+ echo " 4. Reset circuit breaker: bash .ralph/ralph_loop.sh --reset-circuit"
476
476
  echo ""
477
477
  return 0 # Signal to halt
478
478
  else