@ai-dev-methodologies/rlp-desk 0.7.5 → 0.9.0
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 +58 -0
- package/docs/blueprints/blueprint-pivot-step.md +137 -0
- package/docs/plans/validated-snacking-crayon.md +407 -0
- package/package.json +5 -2
- package/scripts/postinstall.js +91 -51
- package/scripts/uninstall.js +18 -9
- package/src/commands/rlp-desk.md +10 -3
- package/src/governance.md +2 -1
- package/src/node/cli/command-builder.mjs +96 -0
- package/src/node/init/campaign-initializer.mjs +235 -0
- package/src/node/polling/signal-poller.mjs +106 -0
- package/src/node/prompts/prompt-assembler.mjs +213 -0
- package/src/node/reporting/campaign-reporting.mjs +257 -0
- package/src/node/run.mjs +234 -0
- package/src/node/runner/campaign-main-loop.mjs +624 -0
- package/src/node/shared/fs.mjs +23 -0
- package/src/node/shared/paths.mjs +28 -0
- package/src/node/tmux/pane-manager.mjs +77 -0
- package/docs/blueprints/blueprint-v0.4-evolution.md +0 -347
- package/docs/prompts/ralplan-codex-review.md +0 -55
- package/docs/superpowers/plans/2026-04-06-worker-verifier-prompt-restructure.md +0 -179
- package/src/scripts/init_ralph_desk.zsh +0 -885
- package/src/scripts/lib_ralph_desk.zsh +0 -904
- package/src/scripts/run_ralph_desk.zsh +0 -2750
package/src/node/run.mjs
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
|
|
4
|
+
import { initCampaign } from './init/campaign-initializer.mjs';
|
|
5
|
+
import { readStatus } from './reporting/campaign-reporting.mjs';
|
|
6
|
+
import { run as runCampaignMain } from './runner/campaign-main-loop.mjs';
|
|
7
|
+
|
|
8
|
+
const RUN_DEFAULTS = {
|
|
9
|
+
mode: 'agent',
|
|
10
|
+
workerModel: 'haiku',
|
|
11
|
+
verifierModel: 'sonnet',
|
|
12
|
+
finalVerifierModel: 'opus',
|
|
13
|
+
consensusMode: 'off',
|
|
14
|
+
consensusModel: 'gpt-5.4:medium',
|
|
15
|
+
finalConsensusModel: 'gpt-5.4:high',
|
|
16
|
+
verifyMode: 'per-us',
|
|
17
|
+
cbThreshold: 6,
|
|
18
|
+
maxIterations: 100,
|
|
19
|
+
iterTimeout: 600,
|
|
20
|
+
debug: false,
|
|
21
|
+
lockWorkerModel: false,
|
|
22
|
+
autonomous: false,
|
|
23
|
+
withSelfVerification: false,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function write(stream, value) {
|
|
27
|
+
stream.write(value.endsWith('\n') ? value : `${value}\n`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function buildHelpText() {
|
|
31
|
+
return [
|
|
32
|
+
'Usage:',
|
|
33
|
+
' node src/node/run.mjs <command> [args] [options]',
|
|
34
|
+
'',
|
|
35
|
+
'Commands:',
|
|
36
|
+
' brainstorm <description> Plan before init (not implemented in the Node rewrite yet)',
|
|
37
|
+
' init <slug> [objective] Create project scaffold',
|
|
38
|
+
' run <slug> [options] Run loop (agent=LLM leader, tmux=shell leader)',
|
|
39
|
+
' status <slug> Show loop status',
|
|
40
|
+
' logs <slug> [N] Show iteration log (not implemented in the Node rewrite yet)',
|
|
41
|
+
' clean <slug> [--kill-session] Reset for re-run (not implemented in the Node rewrite yet)',
|
|
42
|
+
' resume <slug> Resume loop (not implemented in the Node rewrite yet)',
|
|
43
|
+
'',
|
|
44
|
+
'Run Options:',
|
|
45
|
+
' --mode agent|tmux',
|
|
46
|
+
' --worker-model MODEL',
|
|
47
|
+
' --lock-worker-model',
|
|
48
|
+
' --verifier-model MODEL',
|
|
49
|
+
' --final-verifier-model MODEL',
|
|
50
|
+
' --consensus off|all|final-only',
|
|
51
|
+
' --consensus-model MODEL',
|
|
52
|
+
' --final-consensus-model MODEL',
|
|
53
|
+
' --verify-mode per-us|batch',
|
|
54
|
+
' --cb-threshold N',
|
|
55
|
+
' --max-iter N',
|
|
56
|
+
' --iter-timeout N',
|
|
57
|
+
' --debug',
|
|
58
|
+
' --autonomous',
|
|
59
|
+
' --with-self-verification',
|
|
60
|
+
' --help',
|
|
61
|
+
].join('\n');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function consumeValue(args, index, flag) {
|
|
65
|
+
const value = args[index + 1];
|
|
66
|
+
if (!value || value.startsWith('--')) {
|
|
67
|
+
throw new Error(`missing value for ${flag}`);
|
|
68
|
+
}
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseInteger(value, flag) {
|
|
73
|
+
const parsed = Number.parseInt(value, 10);
|
|
74
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
75
|
+
throw new Error(`${flag} must be a non-negative integer`);
|
|
76
|
+
}
|
|
77
|
+
return parsed;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function parseRunOptions(args, cwd) {
|
|
81
|
+
const options = {
|
|
82
|
+
rootDir: cwd,
|
|
83
|
+
...RUN_DEFAULTS,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
87
|
+
const token = args[index];
|
|
88
|
+
switch (token) {
|
|
89
|
+
case '--mode':
|
|
90
|
+
options.mode = consumeValue(args, index, token);
|
|
91
|
+
index += 1;
|
|
92
|
+
break;
|
|
93
|
+
case '--worker-model':
|
|
94
|
+
options.workerModel = consumeValue(args, index, token);
|
|
95
|
+
index += 1;
|
|
96
|
+
break;
|
|
97
|
+
case '--lock-worker-model':
|
|
98
|
+
options.lockWorkerModel = true;
|
|
99
|
+
break;
|
|
100
|
+
case '--verifier-model':
|
|
101
|
+
options.verifierModel = consumeValue(args, index, token);
|
|
102
|
+
index += 1;
|
|
103
|
+
break;
|
|
104
|
+
case '--final-verifier-model':
|
|
105
|
+
options.finalVerifierModel = consumeValue(args, index, token);
|
|
106
|
+
index += 1;
|
|
107
|
+
break;
|
|
108
|
+
case '--consensus':
|
|
109
|
+
options.consensusMode = consumeValue(args, index, token);
|
|
110
|
+
index += 1;
|
|
111
|
+
break;
|
|
112
|
+
case '--consensus-model':
|
|
113
|
+
options.consensusModel = consumeValue(args, index, token);
|
|
114
|
+
index += 1;
|
|
115
|
+
break;
|
|
116
|
+
case '--final-consensus-model':
|
|
117
|
+
options.finalConsensusModel = consumeValue(args, index, token);
|
|
118
|
+
index += 1;
|
|
119
|
+
break;
|
|
120
|
+
case '--verify-mode':
|
|
121
|
+
options.verifyMode = consumeValue(args, index, token);
|
|
122
|
+
index += 1;
|
|
123
|
+
break;
|
|
124
|
+
case '--cb-threshold':
|
|
125
|
+
options.cbThreshold = parseInteger(consumeValue(args, index, token), token);
|
|
126
|
+
index += 1;
|
|
127
|
+
break;
|
|
128
|
+
case '--max-iter':
|
|
129
|
+
options.maxIterations = parseInteger(consumeValue(args, index, token), token);
|
|
130
|
+
index += 1;
|
|
131
|
+
break;
|
|
132
|
+
case '--iter-timeout':
|
|
133
|
+
options.iterTimeout = parseInteger(consumeValue(args, index, token), token);
|
|
134
|
+
index += 1;
|
|
135
|
+
break;
|
|
136
|
+
case '--debug':
|
|
137
|
+
options.debug = true;
|
|
138
|
+
break;
|
|
139
|
+
case '--autonomous':
|
|
140
|
+
options.autonomous = true;
|
|
141
|
+
break;
|
|
142
|
+
case '--with-self-verification':
|
|
143
|
+
options.withSelfVerification = true;
|
|
144
|
+
break;
|
|
145
|
+
default:
|
|
146
|
+
throw new Error(`unknown option: ${token}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return options;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async function runInit(args, deps) {
|
|
154
|
+
if (args.length === 0 || args[0] === '--help') {
|
|
155
|
+
write(deps.stdout, 'Usage: node src/node/run.mjs init <slug> [objective]');
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const slug = args[0];
|
|
160
|
+
const objective = args.slice(1).join(' ').trim() || 'TBD - fill in the objective';
|
|
161
|
+
await deps.initCampaign(slug, objective, { rootDir: deps.cwd });
|
|
162
|
+
write(deps.stdout, `Initialized ${slug} in ${path.join(deps.cwd, '.claude', 'ralph-desk')}`);
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function runStatusCommand(args, deps) {
|
|
167
|
+
if (args.length === 0 || args[0] === '--help') {
|
|
168
|
+
write(deps.stdout, 'Usage: node src/node/run.mjs status <slug>');
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
write(deps.stdout, await deps.readStatus(args[0], { rootDir: deps.cwd }));
|
|
173
|
+
return 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function runRunCommand(args, deps) {
|
|
177
|
+
if (args.length === 0) {
|
|
178
|
+
throw new Error('run requires a slug');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (args[0] === '--help') {
|
|
182
|
+
write(deps.stdout, buildHelpText());
|
|
183
|
+
return 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const slug = args[0];
|
|
187
|
+
const options = parseRunOptions(args.slice(1), deps.cwd);
|
|
188
|
+
await deps.runCampaign(slug, options);
|
|
189
|
+
write(deps.stdout, `Campaign started for ${slug}`);
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export async function main(argv = process.argv.slice(2), overrides = {}) {
|
|
194
|
+
const deps = {
|
|
195
|
+
cwd: overrides.cwd ?? process.cwd(),
|
|
196
|
+
stdout: overrides.stdout ?? process.stdout,
|
|
197
|
+
stderr: overrides.stderr ?? process.stderr,
|
|
198
|
+
initCampaign: overrides.initCampaign ?? initCampaign,
|
|
199
|
+
readStatus: overrides.readStatus ?? readStatus,
|
|
200
|
+
runCampaign: overrides.runCampaign ?? runCampaignMain,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
|
|
205
|
+
write(deps.stdout, buildHelpText());
|
|
206
|
+
return 0;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const [command, ...rest] = argv;
|
|
210
|
+
switch (command) {
|
|
211
|
+
case 'init':
|
|
212
|
+
return await runInit(rest, deps);
|
|
213
|
+
case 'run':
|
|
214
|
+
return await runRunCommand(rest, deps);
|
|
215
|
+
case 'status':
|
|
216
|
+
return await runStatusCommand(rest, deps);
|
|
217
|
+
case 'brainstorm':
|
|
218
|
+
case 'logs':
|
|
219
|
+
case 'clean':
|
|
220
|
+
case 'resume':
|
|
221
|
+
throw new Error(`${command} is not implemented in the Node rewrite yet`);
|
|
222
|
+
default:
|
|
223
|
+
throw new Error(`unknown command: ${command}. Run with --help to see available commands.`);
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
write(deps.stderr, error.message);
|
|
227
|
+
return 1;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (process.argv[1] && path.basename(process.argv[1]) === path.basename(fileURLToPath(import.meta.url))) {
|
|
232
|
+
const exitCode = await main();
|
|
233
|
+
process.exitCode = exitCode;
|
|
234
|
+
}
|