cralph 1.0.0-beta.5 → 1.0.0-beta.7

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
@@ -62,8 +62,9 @@ cralph --yes
62
62
  2. Looks for `.ralph/` in current directory only (not subdirectories)
63
63
  3. Loads config from `.ralph/paths.json` or creates starter structure
64
64
  4. Runs `claude -p --dangerously-skip-permissions` in a loop
65
- 5. Claude updates `.ralph/TODO.md` after each iteration
66
- 6. Stops when Claude outputs `<promise>COMPLETE</promise>`
65
+ 5. Claude completes **ONE task per iteration**, marks it done, then stops
66
+ 6. Auto-commits progress after each iteration (fails gracefully if no git)
67
+ 7. Stops when Claude outputs `<promise>COMPLETE</promise>`
67
68
 
68
69
  ## Config
69
70
 
@@ -90,7 +91,7 @@ Save as `.ralph/paths.json`. Refs are optional reference material (read-only).
90
91
 
91
92
  ### TODO Format
92
93
 
93
- Claude maintains this structure:
94
+ Claude maintains this structure (one task per iteration):
94
95
 
95
96
  ```markdown
96
97
  # Tasks
@@ -98,9 +99,17 @@ Claude maintains this structure:
98
99
  - [ ] Pending task
99
100
  - [x] Completed task
100
101
 
102
+ ---
103
+
101
104
  # Notes
102
105
 
103
- Any relevant context
106
+ ## Task 1 - Done
107
+ - What was implemented
108
+ - Files changed
109
+ - Learnings: patterns discovered, gotchas encountered
110
+
111
+ ## Task 2 - Done
112
+ - ...
104
113
  ```
105
114
 
106
115
  ## First Run (No .ralph/ in cwd)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cralph",
3
- "version": "1.0.0-beta.5",
3
+ "version": "1.0.0-beta.7",
4
4
  "description": "Claude in a loop. Point at refs, give it a rule, let it cook.",
5
5
  "author": "mguleryuz",
6
6
  "license": "MIT",
package/src/prompt.ts CHANGED
@@ -8,19 +8,19 @@ const BASE_PROMPT = `You are an autonomous coding agent running in a loop.
8
8
 
9
9
  FIRST: Read and internalize the rules provided below.
10
10
 
11
- ## Your Task Each Iteration
11
+ ## Your Task This Iteration
12
12
 
13
- 1. Read the TODO file and check the Patterns section first
13
+ 1. Read the TODO file
14
14
  2. Pick the FIRST uncompleted task (marked with [ ])
15
15
  3. Implement that SINGLE task
16
16
  4. Run quality checks (typecheck, lint, test - whatever the project requires)
17
17
  5. If checks pass, mark the task [x] complete
18
- 6. Append your progress with learnings (see format below)
19
- 7. If ALL tasks are complete, output the completion signal
18
+ 6. Append your progress to the Notes section
19
+ 7. **STOP** - End your response. Another iteration will handle the next task.
20
20
 
21
21
  ## Critical Rules
22
22
 
23
- - **ONE task per iteration** - Do not try to complete multiple tasks
23
+ - **ONE task per iteration** - Complete exactly ONE task, then STOP. Do NOT continue to the next task.
24
24
  - **Quality first** - Do NOT mark a task complete if tests/typecheck fail
25
25
  - **Keep changes focused** - Minimal, targeted changes only
26
26
  - **Follow existing patterns** - Match the codebase style
@@ -38,31 +38,21 @@ After completing a task, APPEND to the Notes section:
38
38
  - Gotchas encountered
39
39
  \`\`\`
40
40
 
41
- ## Consolidate Patterns
42
-
43
- If you discover a REUSABLE pattern, add it to the **# Patterns** section at the TOP of the TODO file:
44
-
45
- \`\`\`
46
- # Patterns
47
- - Example: Use \`sql<number>\` template for aggregations
48
- - Example: Always update X when changing Y
49
- \`\`\`
50
-
51
- Only add patterns that are general and reusable, not task-specific details.
52
-
53
41
  ## Refs (Read-Only)
54
42
 
55
43
  If refs paths are provided, they are READ-ONLY reference material. Never modify files in refs.
56
44
 
57
45
  ## Stop Condition
58
46
 
59
- After completing a task, check if ALL tasks are marked [x] complete.
47
+ After completing ONE task, check the TODO file:
48
+
49
+ - If there are still tasks marked [ ] (pending): **END your response normally.** Another iteration will pick up the next task.
60
50
 
61
- If ALL tasks are done, output exactly:
51
+ - If ALL tasks are marked [x] (complete): Output exactly:
62
52
 
63
53
  <promise>COMPLETE</promise>
64
54
 
65
- If there are still pending tasks, end your response normally (the loop will continue).`;
55
+ **IMPORTANT:** Do NOT continue to the next task. Complete ONE task, then STOP.`;
66
56
 
67
57
  /**
68
58
  * Build the complete prompt with config and rules injected
package/src/runner.ts CHANGED
@@ -9,13 +9,7 @@ import { setCurrentProcess, throwIfCancelled } from "./state";
9
9
  const COMPLETION_SIGNAL = "<promise>COMPLETE</promise>";
10
10
  const AUTH_CACHE_TTL_MS = 6 * 60 * 60 * 1000; // 6 hours
11
11
 
12
- const INITIAL_TODO_CONTENT = `# Patterns
13
-
14
- _None yet - add reusable patterns discovered during work_
15
-
16
- ---
17
-
18
- # Tasks
12
+ const INITIAL_TODO_CONTENT = `# Tasks
19
13
 
20
14
  - [ ] Task 1
21
15
  - [ ] Task 2
@@ -186,6 +180,48 @@ async function log(state: RunnerState, message: string): Promise<void> {
186
180
  await Bun.write(state.logFile, existing + logLine);
187
181
  }
188
182
 
183
+ /**
184
+ * Try to commit progress after each iteration
185
+ * Fails gracefully - logs warning and continues if commit fails
186
+ */
187
+ async function tryCommitProgress(state: RunnerState, cwd: string): Promise<void> {
188
+ try {
189
+ // Stage all changes
190
+ const addProc = Bun.spawn(["git", "add", "-A"], {
191
+ cwd,
192
+ stdout: "pipe",
193
+ stderr: "pipe",
194
+ });
195
+ await addProc.exited;
196
+
197
+ // Commit with iteration number
198
+ const commitMessage = `chore(ralph): iteration ${state.iteration} progress`;
199
+ const commitProc = Bun.spawn(
200
+ ["git", "commit", "-m", commitMessage, "--no-verify"],
201
+ {
202
+ cwd,
203
+ stdout: "pipe",
204
+ stderr: "pipe",
205
+ }
206
+ );
207
+
208
+ const exitCode = await commitProc.exited;
209
+
210
+ if (exitCode === 0) {
211
+ consola.info(`Committed iteration ${state.iteration} progress`);
212
+ await log(state, `Committed: ${commitMessage}`);
213
+ } else {
214
+ // Exit code 1 usually means nothing to commit
215
+ await log(state, `No changes to commit for iteration ${state.iteration}`);
216
+ }
217
+ } catch (error) {
218
+ // Gracefully fail - just log and continue
219
+ const errorMsg = error instanceof Error ? error.message : String(error);
220
+ consola.warn(`Could not commit progress: ${errorMsg}`);
221
+ await log(state, `Commit failed: ${errorMsg}`);
222
+ }
223
+ }
224
+
189
225
  /**
190
226
  * Run a single Claude iteration
191
227
  */
@@ -268,6 +304,9 @@ export async function run(config: RalphConfig): Promise<void> {
268
304
 
269
305
  const result = await runIteration(prompt, state, cwd);
270
306
 
307
+ // Try to commit progress after each iteration (fails gracefully)
308
+ await tryCommitProgress(state, cwd);
309
+
271
310
  if (result.isComplete) {
272
311
  break;
273
312
  }