cralph 1.0.0-alpha.4 → 1.0.0-alpha.5
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 +70 -83
- package/package.json +1 -1
- package/src/paths.ts +45 -7
- package/src/prompt.ts +17 -11
- package/src/runner.ts +60 -46
package/README.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
<img src="assets/ralph.png" alt="Ralph cooking" width="500">
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
Claude in a loop.
|
|
7
|
+
Claude in a loop. Give it a rule, let it cook.
|
|
8
8
|
|
|
9
9
|
```
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
.ralph/
|
|
11
|
+
├── rule.md ──loop──> ./
|
|
12
|
+
├── refs/ (output)
|
|
13
|
+
└── TODO.md
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## What is Ralph?
|
|
@@ -21,7 +21,7 @@ refs/ ──loop──> ./
|
|
|
21
21
|
while :; do cat PROMPT.md | claude -p ; done
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
cralph wraps this into a CLI with
|
|
24
|
+
cralph wraps this into a CLI with config, logging, and TODO tracking.
|
|
25
25
|
|
|
26
26
|
## Install
|
|
27
27
|
|
|
@@ -35,121 +35,108 @@ Or with npm:
|
|
|
35
35
|
npm install -g cralph
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Quick Start
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
#
|
|
41
|
+
# In an empty directory - creates starter structure
|
|
42
|
+
cralph
|
|
43
|
+
|
|
44
|
+
# Edit rule.md with your instructions, then run again
|
|
42
45
|
cralph
|
|
46
|
+
```
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Auto-detects .ralph/paths.json in cwd
|
|
45
52
|
cralph
|
|
46
53
|
|
|
47
54
|
# Override with flags
|
|
48
55
|
cralph --refs ./source --rule ./rule.md --output .
|
|
49
|
-
```
|
|
50
56
|
|
|
51
|
-
|
|
57
|
+
# Auto-confirm prompts (CI/automation)
|
|
58
|
+
cralph --yes
|
|
59
|
+
```
|
|
52
60
|
|
|
53
|
-
|
|
61
|
+
## How It Works
|
|
54
62
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
1. Checks Claude CLI auth (cached for 6 hours)
|
|
64
|
+
2. Loads config from `.ralph/paths.json`
|
|
65
|
+
3. Runs `claude -p --dangerously-skip-permissions` in a loop
|
|
66
|
+
4. Claude updates `.ralph/TODO.md` after each iteration
|
|
67
|
+
5. Stops when Claude outputs `<promise>COMPLETE</promise>`
|
|
60
68
|
|
|
61
|
-
## Config
|
|
69
|
+
## Config
|
|
62
70
|
|
|
63
71
|
```json
|
|
64
72
|
{
|
|
65
|
-
"refs": ["
|
|
66
|
-
"rule": "./.
|
|
73
|
+
"refs": ["./.ralph/refs"],
|
|
74
|
+
"rule": "./.ralph/rule.md",
|
|
67
75
|
"output": "."
|
|
68
76
|
}
|
|
69
77
|
```
|
|
70
78
|
|
|
71
|
-
Save as `.ralph/paths.json
|
|
79
|
+
Save as `.ralph/paths.json`. Refs are optional reference material (read-only).
|
|
72
80
|
|
|
73
|
-
##
|
|
74
|
-
|
|
75
|
-
1. Checks if Claude CLI is authenticated (exits with instructions if not)
|
|
76
|
-
2. Reads your source material from `refs/`
|
|
77
|
-
3. Injects your rule into the prompt
|
|
78
|
-
4. Runs `claude -p --dangerously-skip-permissions` in a loop
|
|
79
|
-
5. Stops when Claude outputs `<promise>COMPLETE</promise>`
|
|
81
|
+
## Files
|
|
80
82
|
|
|
81
|
-
|
|
83
|
+
| File | Description |
|
|
84
|
+
|------|-------------|
|
|
85
|
+
| `.ralph/paths.json` | Configuration |
|
|
86
|
+
| `.ralph/rule.md` | Your instructions for Claude |
|
|
87
|
+
| `.ralph/refs/` | Optional reference material (read-only) |
|
|
88
|
+
| `.ralph/TODO.md` | Task tracking (updated by Claude) |
|
|
89
|
+
| `.ralph/ralph.log` | Session log |
|
|
90
|
+
| `~/.cralph/auth-cache.json` | Auth cache (6h TTL) |
|
|
82
91
|
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
◐ Checking Claude authentication...
|
|
86
|
-
✔ Claude authenticated
|
|
87
|
-
```
|
|
92
|
+
### TODO Format
|
|
88
93
|
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
◐ Checking Claude authentication...
|
|
92
|
-
✖ Claude CLI is not authenticated
|
|
94
|
+
Claude maintains this structure:
|
|
93
95
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
│ │
|
|
97
|
-
│ Then type: /login │
|
|
98
|
-
╰─────────────────────╯
|
|
96
|
+
```markdown
|
|
97
|
+
# Tasks
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
- [ ] Pending task
|
|
100
|
+
- [x] Completed task
|
|
102
101
|
|
|
103
|
-
|
|
104
|
-
```
|
|
105
|
-
❯ Found .ralph/paths.json. What would you like to do?
|
|
106
|
-
● 🚀 Run with this config
|
|
107
|
-
○ ✏️ Edit configuration
|
|
108
|
-
```
|
|
102
|
+
# Notes
|
|
109
103
|
|
|
110
|
-
|
|
104
|
+
Any relevant context
|
|
111
105
|
```
|
|
112
|
-
ℹ Interactive configuration mode
|
|
113
106
|
|
|
114
|
-
|
|
115
|
-
❯ Select refs directories:
|
|
116
|
-
◻ 📁 src
|
|
117
|
-
◻ 📁 src/components
|
|
118
|
-
◼ 📁 docs
|
|
107
|
+
## First Run (Empty Directory)
|
|
119
108
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
109
|
+
```
|
|
110
|
+
ℹ Created .ralph/refs/ directory
|
|
111
|
+
ℹ Created .ralph/rule.md with starter template
|
|
112
|
+
ℹ Created .ralph/paths.json
|
|
124
113
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
114
|
+
╭──────────────────────────────────────────────╮
|
|
115
|
+
│ 1. Add source files to .ralph/refs/ │
|
|
116
|
+
│ 2. Edit .ralph/rule.md with your instructions│
|
|
117
|
+
│ 3. Run cralph again │
|
|
118
|
+
╰──────────────────────────────────────────────╯
|
|
129
119
|
```
|
|
130
120
|
|
|
131
|
-
|
|
121
|
+
## Prompts
|
|
122
|
+
|
|
123
|
+
**Config detected:**
|
|
132
124
|
```
|
|
133
|
-
|
|
134
|
-
|
|
125
|
+
❯ Found .ralph/paths.json. What would you like to do?
|
|
126
|
+
● 🚀 Run with this config
|
|
127
|
+
○ ✏️ Edit configuration
|
|
135
128
|
```
|
|
136
129
|
|
|
137
|
-
**TODO
|
|
130
|
+
**TODO has progress:**
|
|
138
131
|
```
|
|
139
|
-
? Found existing TODO with progress. Reset to start fresh? (
|
|
132
|
+
? Found existing TODO with progress. Reset to start fresh? (Y/n)
|
|
140
133
|
```
|
|
141
|
-
- If the `.ralph/TODO.md` file has been modified from previous runs, you'll be asked whether to reset it
|
|
142
|
-
- Default is **No** (continue with existing progress)
|
|
143
|
-
- Choose **Yes** to start fresh with a clean TODO
|
|
144
134
|
|
|
145
|
-
|
|
146
|
-
- Press `Ctrl+C` at any time to exit
|
|
147
|
-
- Running Claude processes are terminated cleanly
|
|
135
|
+
## Path Selection
|
|
148
136
|
|
|
149
|
-
**
|
|
150
|
-
-
|
|
151
|
-
-
|
|
152
|
-
- `.ralph/TODO.md` - Agent status tracker
|
|
137
|
+
- **Space** - Toggle selection
|
|
138
|
+
- **Enter** - Confirm
|
|
139
|
+
- **Ctrl+C** - Exit
|
|
153
140
|
|
|
154
141
|
## Testing
|
|
155
142
|
|
|
@@ -157,8 +144,8 @@ If not authenticated:
|
|
|
157
144
|
bun test
|
|
158
145
|
```
|
|
159
146
|
|
|
160
|
-
- **Unit tests**
|
|
161
|
-
- **E2E tests**
|
|
147
|
+
- **Unit tests** - Config, prompt building, CLI
|
|
148
|
+
- **E2E tests** - Full loop with Claude (requires auth)
|
|
162
149
|
|
|
163
150
|
## Requirements
|
|
164
151
|
|
package/package.json
CHANGED
package/src/paths.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { consola } from "consola";
|
|
2
2
|
import { resolve, join } from "path";
|
|
3
|
-
import { readdir, stat } from "fs/promises";
|
|
3
|
+
import { readdir, stat, mkdir } from "fs/promises";
|
|
4
4
|
import type { PathsFileConfig, RalphConfig } from "./types";
|
|
5
5
|
|
|
6
6
|
// Dim text helper
|
|
@@ -105,16 +105,47 @@ export async function loadPathsFile(filePath: string): Promise<PathsFileConfig>
|
|
|
105
105
|
return content as PathsFileConfig;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Create starter structure for empty directories
|
|
110
|
+
*/
|
|
111
|
+
export async function createStarterStructure(cwd: string): Promise<void> {
|
|
112
|
+
// Create .ralph/
|
|
113
|
+
const ralphDir = join(cwd, ".ralph");
|
|
114
|
+
await mkdir(ralphDir, { recursive: true });
|
|
115
|
+
|
|
116
|
+
// Create .ralph/refs/
|
|
117
|
+
const refsDir = join(ralphDir, "refs");
|
|
118
|
+
await mkdir(refsDir, { recursive: true });
|
|
119
|
+
consola.info("Created .ralph/refs/ directory");
|
|
120
|
+
|
|
121
|
+
// Create .ralph/rule.md
|
|
122
|
+
const rulePath = join(ralphDir, "rule.md");
|
|
123
|
+
await Bun.write(rulePath, STARTER_RULE);
|
|
124
|
+
consola.info("Created .ralph/rule.md with starter template");
|
|
125
|
+
|
|
126
|
+
// Create .ralph/paths.json with default config
|
|
127
|
+
const pathsConfig = {
|
|
128
|
+
refs: ["./.ralph/refs"],
|
|
129
|
+
rule: "./.ralph/rule.md",
|
|
130
|
+
output: ".",
|
|
131
|
+
};
|
|
132
|
+
await Bun.write(join(ralphDir, "paths.json"), JSON.stringify(pathsConfig, null, 2));
|
|
133
|
+
consola.info("Created .ralph/paths.json");
|
|
134
|
+
|
|
135
|
+
consola.box("1. Add source files to .ralph/refs/\n2. Edit .ralph/rule.md with your instructions\n3. Run cralph again");
|
|
136
|
+
}
|
|
137
|
+
|
|
108
138
|
/**
|
|
109
139
|
* Prompt user to select refs directories (simple multiselect)
|
|
110
140
|
*/
|
|
111
141
|
export async function selectRefs(cwd: string, defaults?: string[]): Promise<string[]> {
|
|
112
142
|
// Get all directories up to 3 levels deep
|
|
113
|
-
|
|
143
|
+
let allDirs = await listDirectoriesRecursive(cwd, 3);
|
|
114
144
|
|
|
115
145
|
if (allDirs.length === 0) {
|
|
116
|
-
|
|
117
|
-
|
|
146
|
+
// Create starter structure and exit gracefully
|
|
147
|
+
await createStarterStructure(cwd);
|
|
148
|
+
process.exit(0);
|
|
118
149
|
}
|
|
119
150
|
|
|
120
151
|
// Convert to relative paths for display
|
|
@@ -146,14 +177,21 @@ export async function selectRefs(cwd: string, defaults?: string[]): Promise<stri
|
|
|
146
177
|
return selected as string[];
|
|
147
178
|
}
|
|
148
179
|
|
|
180
|
+
const STARTER_RULE = `I want a file named hello.txt
|
|
181
|
+
`;
|
|
182
|
+
|
|
149
183
|
/**
|
|
150
184
|
* Prompt user to select a rule file
|
|
151
185
|
*/
|
|
152
186
|
export async function selectRule(cwd: string, defaultRule?: string): Promise<string> {
|
|
153
|
-
|
|
187
|
+
let files = await listFilesRecursive(cwd, [".mdc", ".md"]);
|
|
154
188
|
if (files.length === 0) {
|
|
155
|
-
|
|
156
|
-
|
|
189
|
+
// This shouldn't happen if selectRefs ran first, but handle it just in case
|
|
190
|
+
const rulePath = join(cwd, "rule.md");
|
|
191
|
+
await Bun.write(rulePath, STARTER_RULE);
|
|
192
|
+
consola.info("Created rule.md with starter template");
|
|
193
|
+
consola.box("Edit rule.md with your instructions then run cralph again");
|
|
194
|
+
process.exit(0);
|
|
157
195
|
}
|
|
158
196
|
|
|
159
197
|
// Show relative paths for readability
|
package/src/prompt.ts
CHANGED
|
@@ -8,13 +8,16 @@ const BASE_PROMPT = `You are an autonomous agent running in a loop.
|
|
|
8
8
|
|
|
9
9
|
FIRST: Read and internalize the rules provided below.
|
|
10
10
|
|
|
11
|
-
Your job is to
|
|
11
|
+
Your job is to follow the rules and complete the task. Write output to the output directory.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
If refs paths are provided, they are READ-ONLY reference material. Never delete, move, or modify files in refs.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
**IMPORTANT: At the end of EVERY iteration, update the TODO file with your progress.**
|
|
16
|
+
Keep the TODO structure with these sections:
|
|
17
|
+
- **# Tasks** - Checklist with [ ] for pending and [x] for done
|
|
18
|
+
- **# Notes** - Any relevant notes or context
|
|
16
19
|
|
|
17
|
-
STOPPING CONDITION: When
|
|
20
|
+
STOPPING CONDITION: When done, update the TODO file, then output exactly:
|
|
18
21
|
|
|
19
22
|
<promise>COMPLETE</promise>
|
|
20
23
|
|
|
@@ -23,8 +26,10 @@ This signals the automation to stop. Only output this tag when truly done.`;
|
|
|
23
26
|
/**
|
|
24
27
|
* Build the complete prompt with config and rules injected
|
|
25
28
|
*/
|
|
26
|
-
export function buildPrompt(config: RalphConfig, rulesContent: string): string {
|
|
27
|
-
const refsList = config.refs.
|
|
29
|
+
export function buildPrompt(config: RalphConfig, rulesContent: string, todoFile: string): string {
|
|
30
|
+
const refsList = config.refs.length > 0
|
|
31
|
+
? config.refs.map((r) => `- ${r}`).join("\n")
|
|
32
|
+
: "_None_";
|
|
28
33
|
|
|
29
34
|
return `${BASE_PROMPT}
|
|
30
35
|
|
|
@@ -32,7 +37,10 @@ export function buildPrompt(config: RalphConfig, rulesContent: string): string {
|
|
|
32
37
|
|
|
33
38
|
## Configuration
|
|
34
39
|
|
|
35
|
-
**
|
|
40
|
+
**TODO file (update after each iteration):**
|
|
41
|
+
${todoFile}
|
|
42
|
+
|
|
43
|
+
**Refs paths (optional, read-only reference material):**
|
|
36
44
|
${refsList}
|
|
37
45
|
|
|
38
46
|
**Output directory:**
|
|
@@ -42,8 +50,6 @@ ${config.output}
|
|
|
42
50
|
|
|
43
51
|
## Rules
|
|
44
52
|
|
|
45
|
-
The following rules define how to classify, refine, and write documentation:
|
|
46
|
-
|
|
47
53
|
${rulesContent}
|
|
48
54
|
`;
|
|
49
55
|
}
|
|
@@ -51,9 +57,9 @@ ${rulesContent}
|
|
|
51
57
|
/**
|
|
52
58
|
* Read rule file and build complete prompt
|
|
53
59
|
*/
|
|
54
|
-
export async function createPrompt(config: RalphConfig): Promise<string> {
|
|
60
|
+
export async function createPrompt(config: RalphConfig, todoFile: string): Promise<string> {
|
|
55
61
|
const ruleFile = Bun.file(config.rule);
|
|
56
62
|
const ruleContent = await ruleFile.text();
|
|
57
63
|
|
|
58
|
-
return buildPrompt(config, ruleContent);
|
|
64
|
+
return buildPrompt(config, ruleContent, todoFile);
|
|
59
65
|
}
|
package/src/runner.ts
CHANGED
|
@@ -1,30 +1,73 @@
|
|
|
1
1
|
import { consola } from "consola";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { mkdir } from "fs/promises";
|
|
4
|
+
import { homedir } from "os";
|
|
4
5
|
import type { RalphConfig, RunnerState, IterationResult } from "./types";
|
|
5
6
|
import { createPrompt } from "./prompt";
|
|
6
7
|
|
|
7
8
|
const COMPLETION_SIGNAL = "<promise>COMPLETE</promise>";
|
|
9
|
+
const AUTH_CACHE_TTL_MS = 6 * 60 * 60 * 1000; // 6 hours
|
|
8
10
|
|
|
9
|
-
const INITIAL_TODO_CONTENT = `#
|
|
11
|
+
const INITIAL_TODO_CONTENT = `# Tasks
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
- [ ] Task 1
|
|
14
|
+
- [ ] Task 2
|
|
12
15
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## Processed Files
|
|
16
|
+
# Notes
|
|
16
17
|
|
|
17
18
|
_None yet_
|
|
19
|
+
`;
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Get the auth cache file path
|
|
23
|
+
*/
|
|
24
|
+
function getAuthCachePath(): string {
|
|
25
|
+
return join(homedir(), ".cralph", "auth-cache.json");
|
|
26
|
+
}
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Check if cached auth is still valid
|
|
30
|
+
*/
|
|
31
|
+
async function isAuthCacheValid(): Promise<boolean> {
|
|
32
|
+
try {
|
|
33
|
+
const cachePath = getAuthCachePath();
|
|
34
|
+
const file = Bun.file(cachePath);
|
|
35
|
+
if (!(await file.exists())) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const cache = await file.json();
|
|
39
|
+
const cachedAt = cache.timestamp;
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
return now - cachedAt < AUTH_CACHE_TTL_MS;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Save successful auth to cache
|
|
49
|
+
*/
|
|
50
|
+
async function saveAuthCache(): Promise<void> {
|
|
51
|
+
try {
|
|
52
|
+
const cachePath = getAuthCachePath();
|
|
53
|
+
const cacheDir = join(homedir(), ".cralph");
|
|
54
|
+
await mkdir(cacheDir, { recursive: true });
|
|
55
|
+
await Bun.write(cachePath, JSON.stringify({ timestamp: Date.now() }));
|
|
56
|
+
} catch {
|
|
57
|
+
// Ignore cache write errors
|
|
58
|
+
}
|
|
59
|
+
}
|
|
23
60
|
|
|
24
61
|
/**
|
|
25
62
|
* Check if Claude CLI is authenticated by sending a minimal test prompt
|
|
63
|
+
* Uses cache to avoid checking too frequently (6 hour TTL)
|
|
26
64
|
*/
|
|
27
65
|
export async function checkClaudeAuth(): Promise<boolean> {
|
|
66
|
+
// Check cache first
|
|
67
|
+
if (await isAuthCacheValid()) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
28
71
|
try {
|
|
29
72
|
// Send a minimal prompt to test auth
|
|
30
73
|
const proc = Bun.spawn(["claude", "-p"], {
|
|
@@ -47,8 +90,13 @@ export async function checkClaudeAuth(): Promise<boolean> {
|
|
|
47
90
|
return false;
|
|
48
91
|
}
|
|
49
92
|
|
|
50
|
-
// If exit code is 0, auth is working
|
|
51
|
-
|
|
93
|
+
// If exit code is 0, auth is working - save to cache
|
|
94
|
+
if (exitCode === 0) {
|
|
95
|
+
await saveAuthCache();
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return false;
|
|
52
100
|
} catch {
|
|
53
101
|
return false;
|
|
54
102
|
}
|
|
@@ -101,7 +149,7 @@ Ralph Session: ${state.startTime.toISOString()}
|
|
|
101
149
|
"Found existing TODO with progress. Reset to start fresh?",
|
|
102
150
|
{
|
|
103
151
|
type: "confirm",
|
|
104
|
-
initial:
|
|
152
|
+
initial: true,
|
|
105
153
|
}
|
|
106
154
|
);
|
|
107
155
|
|
|
@@ -127,28 +175,6 @@ async function log(state: RunnerState, message: string): Promise<void> {
|
|
|
127
175
|
await Bun.write(state.logFile, existing + logLine);
|
|
128
176
|
}
|
|
129
177
|
|
|
130
|
-
/**
|
|
131
|
-
* Count files in refs directories (excluding .gitkeep and hidden files)
|
|
132
|
-
*/
|
|
133
|
-
async function countRefs(refs: string[]): Promise<number> {
|
|
134
|
-
let count = 0;
|
|
135
|
-
|
|
136
|
-
for (const refPath of refs) {
|
|
137
|
-
try {
|
|
138
|
-
const entries = await Array.fromAsync(
|
|
139
|
-
new Bun.Glob("**/*").scan({ cwd: refPath, onlyFiles: true })
|
|
140
|
-
);
|
|
141
|
-
count += entries.filter(
|
|
142
|
-
(e) => !e.startsWith(".") && !e.includes("/.") && e !== ".gitkeep"
|
|
143
|
-
).length;
|
|
144
|
-
} catch {
|
|
145
|
-
// Directory might not exist or be empty
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return count;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
178
|
// Track current subprocess for cleanup
|
|
153
179
|
let currentProc: ReturnType<typeof Bun.spawn> | null = null;
|
|
154
180
|
|
|
@@ -234,17 +260,8 @@ export async function run(config: RalphConfig): Promise<void> {
|
|
|
234
260
|
consola.info(`Log: ${state.logFile}`);
|
|
235
261
|
consola.info(`TODO: ${state.todoFile}`);
|
|
236
262
|
|
|
237
|
-
// Count initial refs
|
|
238
|
-
const initialCount = await countRefs(config.refs);
|
|
239
|
-
consola.info(`Found ${initialCount} files to process`);
|
|
240
|
-
|
|
241
|
-
if (initialCount === 0) {
|
|
242
|
-
consola.warn("No files found in refs directories");
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
263
|
// Build prompt once
|
|
247
|
-
const prompt = await createPrompt(config);
|
|
264
|
+
const prompt = await createPrompt(config, state.todoFile);
|
|
248
265
|
|
|
249
266
|
// Ensure output directory exists
|
|
250
267
|
await mkdir(config.output, { recursive: true });
|
|
@@ -255,9 +272,6 @@ export async function run(config: RalphConfig): Promise<void> {
|
|
|
255
272
|
while (true) {
|
|
256
273
|
console.log("━".repeat(40));
|
|
257
274
|
|
|
258
|
-
const refCount = await countRefs(config.refs);
|
|
259
|
-
consola.info(`${refCount} ref files remaining`);
|
|
260
|
-
|
|
261
275
|
const result = await runIteration(prompt, state, cwd);
|
|
262
276
|
|
|
263
277
|
if (result.isComplete) {
|