rafcode 3.2.1 → 3.8.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/.claude/settings.local.json +3 -1
- package/CLAUDE.md +0 -1
- package/RAF/41-echo-chamber/decisions.md +13 -0
- package/RAF/41-echo-chamber/input.md +4 -0
- package/RAF/41-echo-chamber/outcomes/1-update-codex-model-defaults.md +24 -0
- package/RAF/41-echo-chamber/outcomes/2-e2e-test-codex-provider.md +74 -0
- package/RAF/41-echo-chamber/plans/1-update-codex-model-defaults.md +28 -0
- package/RAF/41-echo-chamber/plans/2-e2e-test-codex-provider.md +103 -0
- package/RAF/42-patch-parade/decisions.md +29 -0
- package/RAF/42-patch-parade/input.md +9 -0
- package/RAF/42-patch-parade/outcomes/1-fix-codex-model-resolution.md +36 -0
- package/RAF/42-patch-parade/outcomes/2-fix-provider-aware-name-generation.md +31 -0
- package/RAF/42-patch-parade/outcomes/3-fix-codex-error-event-rendering.md +32 -0
- package/RAF/42-patch-parade/outcomes/4-update-cli-help-docs.md +28 -0
- package/RAF/42-patch-parade/outcomes/5-update-default-codex-models-to-gpt-5-4.md +33 -0
- package/RAF/42-patch-parade/outcomes/6-unify-model-config-schema.md +89 -0
- package/RAF/42-patch-parade/plans/1-fix-codex-model-resolution.md +35 -0
- package/RAF/42-patch-parade/plans/2-fix-provider-aware-name-generation.md +38 -0
- package/RAF/42-patch-parade/plans/3-fix-codex-error-event-rendering.md +32 -0
- package/RAF/42-patch-parade/plans/4-update-cli-help-docs.md +31 -0
- package/RAF/42-patch-parade/plans/5-update-default-codex-models-to-gpt-5-4.md +35 -0
- package/RAF/42-patch-parade/plans/6-unify-model-config-schema.md +46 -0
- package/RAF/43-swiss-army/decisions.md +34 -0
- package/RAF/43-swiss-army/input.md +7 -0
- package/RAF/43-swiss-army/outcomes/1-fix-model-validation.md +21 -0
- package/RAF/43-swiss-army/outcomes/2-update-commit-format.md +31 -0
- package/RAF/43-swiss-army/outcomes/3-wire-reasoning-effort.md +28 -0
- package/RAF/43-swiss-army/outcomes/4-remove-provider-flag.md +27 -0
- package/RAF/43-swiss-army/outcomes/5-config-wizard-validation.md +23 -0
- package/RAF/43-swiss-army/outcomes/6-add-fast-mode.md +32 -0
- package/RAF/43-swiss-army/outcomes/7-config-preset.md +31 -0
- package/RAF/43-swiss-army/plans/1-fix-model-validation.md +38 -0
- package/RAF/43-swiss-army/plans/2-update-commit-format.md +46 -0
- package/RAF/43-swiss-army/plans/3-wire-reasoning-effort.md +39 -0
- package/RAF/43-swiss-army/plans/4-remove-provider-flag.md +43 -0
- package/RAF/43-swiss-army/plans/5-config-wizard-validation.md +42 -0
- package/RAF/43-swiss-army/plans/6-add-fast-mode.md +46 -0
- package/RAF/43-swiss-army/plans/7-config-preset.md +51 -0
- package/RAF/44-config-api-change/decisions.md +22 -0
- package/RAF/44-config-api-change/input.md +5 -0
- package/RAF/44-config-api-change/outcomes/1-restructure-config-subcommands.md +19 -0
- package/RAF/44-config-api-change/outcomes/2-move-preset-under-config.md +17 -0
- package/RAF/44-config-api-change/outcomes/3-update-existing-tests-for-config-api.md +14 -0
- package/RAF/44-config-api-change/outcomes/4-update-config-command-docs.md +11 -0
- package/RAF/44-config-api-change/outcomes/5-fix-codex-name-generation.md +18 -0
- package/RAF/44-config-api-change/plans/1-restructure-config-subcommands.md +37 -0
- package/RAF/44-config-api-change/plans/2-move-preset-under-config.md +38 -0
- package/RAF/44-config-api-change/plans/3-update-existing-tests-for-config-api.md +38 -0
- package/RAF/44-config-api-change/plans/4-update-config-command-docs.md +36 -0
- package/RAF/44-config-api-change/plans/5-fix-codex-name-generation.md +49 -0
- package/RAF/45-signal-cairn/decisions.md +7 -0
- package/RAF/45-signal-cairn/input.md +2 -0
- package/RAF/45-signal-cairn/outcomes/1-rename-provider-to-harness.md +19 -0
- package/RAF/45-signal-cairn/outcomes/2-normalize-model-display-names.md +18 -0
- package/RAF/45-signal-cairn/plans/1-rename-provider-to-harness.md +40 -0
- package/RAF/45-signal-cairn/plans/2-normalize-model-display-names.md +41 -0
- package/RAF/45-signal-lantern/decisions.md +10 -0
- package/RAF/45-signal-lantern/input.md +2 -0
- package/RAF/45-signal-lantern/outcomes/1-add-effort-and-fast-to-do-model-display.md +15 -0
- package/RAF/45-signal-lantern/outcomes/2-capture-codex-post-run-token-usage.md +15 -0
- package/RAF/45-signal-lantern/outcomes/3-show-codex-token-summaries-without-fake-cost.md +14 -0
- package/RAF/45-signal-lantern/plans/1-add-effort-and-fast-to-do-model-display.md +38 -0
- package/RAF/45-signal-lantern/plans/2-capture-codex-post-run-token-usage.md +37 -0
- package/RAF/45-signal-lantern/plans/3-show-codex-token-summaries-without-fake-cost.md +40 -0
- package/RAF/46-lantern-arc/decisions.md +19 -0
- package/RAF/46-lantern-arc/input.md +6 -0
- package/RAF/46-lantern-arc/outcomes/1-remove-spark-alias.md +16 -0
- package/RAF/46-lantern-arc/outcomes/2-clean-up-worktree-plan-command.md +30 -0
- package/RAF/46-lantern-arc/outcomes/3-fix-token-usage-accumulation.md +32 -0
- package/RAF/46-lantern-arc/outcomes/4-display-effort-in-compact-mode.md +22 -0
- package/RAF/46-lantern-arc/outcomes/5-codex-fast-mode-research.md +38 -0
- package/RAF/46-lantern-arc/outcomes/6-optimize-llm-prompts.md +39 -0
- package/RAF/46-lantern-arc/plans/1-remove-spark-alias.md +38 -0
- package/RAF/46-lantern-arc/plans/2-clean-up-worktree-plan-command.md +33 -0
- package/RAF/46-lantern-arc/plans/3-fix-token-usage-accumulation.md +33 -0
- package/RAF/46-lantern-arc/plans/4-display-effort-in-compact-mode.md +28 -0
- package/RAF/46-lantern-arc/plans/5-codex-fast-mode-research.md +34 -0
- package/RAF/46-lantern-arc/plans/6-optimize-llm-prompts.md +48 -0
- package/RAF/47-signal-trim/decisions.md +13 -0
- package/RAF/47-signal-trim/input.md +2 -0
- package/RAF/47-signal-trim/plans/1-remove-cache-from-status.md +73 -0
- package/README.md +47 -57
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +47 -49
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/do.d.ts +2 -0
- package/dist/commands/do.d.ts.map +1 -1
- package/dist/commands/do.js +57 -44
- package/dist/commands/do.js.map +1 -1
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +36 -153
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/preset.d.ts +3 -0
- package/dist/commands/preset.d.ts.map +1 -0
- package/dist/commands/preset.js +158 -0
- package/dist/commands/preset.js.map +1 -0
- package/dist/core/claude-runner.d.ts +2 -0
- package/dist/core/claude-runner.d.ts.map +1 -1
- package/dist/core/claude-runner.js +36 -12
- package/dist/core/claude-runner.js.map +1 -1
- package/dist/core/codex-runner.d.ts +1 -0
- package/dist/core/codex-runner.d.ts.map +1 -1
- package/dist/core/codex-runner.js +26 -7
- package/dist/core/codex-runner.js.map +1 -1
- package/dist/core/failure-analyzer.js +2 -1
- package/dist/core/failure-analyzer.js.map +1 -1
- package/dist/core/git.d.ts +2 -2
- package/dist/core/git.d.ts.map +1 -1
- package/dist/core/git.js +53 -3
- package/dist/core/git.js.map +1 -1
- package/dist/core/pull-request.js +3 -3
- package/dist/core/pull-request.js.map +1 -1
- package/dist/core/runner-factory.d.ts +4 -4
- package/dist/core/runner-factory.d.ts.map +1 -1
- package/dist/core/runner-factory.js +8 -8
- package/dist/core/runner-factory.js.map +1 -1
- package/dist/core/runner-interface.d.ts +1 -1
- package/dist/core/runner-types.d.ts +17 -4
- package/dist/core/runner-types.d.ts.map +1 -1
- package/dist/parsers/codex-stream-renderer.d.ts +7 -0
- package/dist/parsers/codex-stream-renderer.d.ts.map +1 -1
- package/dist/parsers/codex-stream-renderer.js +37 -4
- package/dist/parsers/codex-stream-renderer.js.map +1 -1
- package/dist/prompts/amend.d.ts.map +1 -1
- package/dist/prompts/amend.js +29 -101
- package/dist/prompts/amend.js.map +1 -1
- package/dist/prompts/execution.d.ts.map +1 -1
- package/dist/prompts/execution.js +17 -34
- package/dist/prompts/execution.js.map +1 -1
- package/dist/prompts/planning.d.ts.map +1 -1
- package/dist/prompts/planning.js +21 -120
- package/dist/prompts/planning.js.map +1 -1
- package/dist/types/config.d.ts +33 -31
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js +14 -28
- package/dist/types/config.js.map +1 -1
- package/dist/utils/config.d.ts +36 -16
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +209 -104
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/name-generator.d.ts.map +1 -1
- package/dist/utils/name-generator.js +25 -12
- package/dist/utils/name-generator.js.map +1 -1
- package/dist/utils/terminal-symbols.d.ts +15 -2
- package/dist/utils/terminal-symbols.d.ts.map +1 -1
- package/dist/utils/terminal-symbols.js +36 -4
- package/dist/utils/terminal-symbols.js.map +1 -1
- package/dist/utils/token-tracker.d.ts +6 -1
- package/dist/utils/token-tracker.d.ts.map +1 -1
- package/dist/utils/token-tracker.js +84 -51
- package/dist/utils/token-tracker.js.map +1 -1
- package/dist/utils/validation.d.ts +1 -2
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +4 -25
- package/dist/utils/validation.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/config.ts +60 -63
- package/src/commands/do.ts +63 -51
- package/src/commands/plan.ts +34 -165
- package/src/commands/preset.ts +186 -0
- package/src/core/claude-runner.ts +45 -5
- package/src/core/codex-runner.ts +32 -7
- package/src/core/failure-analyzer.ts +2 -1
- package/src/core/git.ts +57 -3
- package/src/core/pull-request.ts +3 -3
- package/src/core/runner-factory.ts +9 -9
- package/src/core/runner-interface.ts +1 -1
- package/src/core/runner-types.ts +17 -4
- package/src/parsers/codex-stream-renderer.ts +47 -4
- package/src/prompts/amend.ts +29 -101
- package/src/prompts/config-docs.md +206 -62
- package/src/prompts/execution.ts +17 -34
- package/src/prompts/planning.ts +21 -120
- package/src/types/config.ts +47 -58
- package/src/utils/config.ts +248 -115
- package/src/utils/name-generator.ts +29 -13
- package/src/utils/terminal-symbols.ts +46 -6
- package/src/utils/token-tracker.ts +96 -57
- package/src/utils/validation.ts +5 -30
- package/tests/unit/amend-prompt.test.ts +3 -2
- package/tests/unit/claude-runner-interactive.test.ts +21 -3
- package/tests/unit/claude-runner.test.ts +39 -0
- package/tests/unit/codex-runner.test.ts +163 -0
- package/tests/unit/codex-stream-renderer.test.ts +127 -0
- package/tests/unit/command-output.test.ts +57 -0
- package/tests/unit/commit-planning-artifacts-worktree.test.ts +24 -7
- package/tests/unit/commit-planning-artifacts.test.ts +26 -4
- package/tests/unit/config-command.test.ts +215 -303
- package/tests/unit/config.test.ts +319 -235
- package/tests/unit/dependency-integration.test.ts +27 -1
- package/tests/unit/do-model-display.test.ts +35 -0
- package/tests/unit/execution-prompt.test.ts +49 -19
- package/tests/unit/name-generator.test.ts +82 -12
- package/tests/unit/plan-command-auto-flag.test.ts +7 -10
- package/tests/unit/plan-command.test.ts +14 -17
- package/tests/unit/planning-prompt.test.ts +9 -8
- package/tests/unit/terminal-symbols.test.ts +94 -3
- package/tests/unit/token-tracker.test.ts +180 -1
- package/tests/unit/validation.test.ts +9 -41
- package/tests/unit/worktree-flag-override.test.ts +0 -186
package/src/core/codex-runner.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { execSync, spawn } from 'node:child_process';
|
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
5
|
import { renderCodexStreamEvent } from '../parsers/codex-stream-renderer.js';
|
|
6
6
|
import { getModel } from '../utils/config.js';
|
|
7
|
+
import { mergeUsageData } from '../utils/token-tracker.js';
|
|
7
8
|
import type { ICliRunner } from './runner-interface.js';
|
|
8
9
|
import type { RunnerOptions, RunnerConfig, RunResult } from './runner-types.js';
|
|
9
10
|
import { createCompletionDetector } from './completion-detector.js';
|
|
@@ -36,9 +37,11 @@ export class CodexRunner implements ICliRunner {
|
|
|
36
37
|
private activeProcess: pty.IPty | null = null;
|
|
37
38
|
private killed = false;
|
|
38
39
|
private model: string;
|
|
40
|
+
private reasoningEffort?: string;
|
|
39
41
|
|
|
40
42
|
constructor(config: RunnerConfig = {}) {
|
|
41
|
-
this.model = config.model ?? getModel('execute'
|
|
43
|
+
this.model = config.model ?? getModel('execute').model;
|
|
44
|
+
this.reasoningEffort = config.reasoningEffort;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
/**
|
|
@@ -54,7 +57,14 @@ export class CodexRunner implements ICliRunner {
|
|
|
54
57
|
|
|
55
58
|
return new Promise((resolve) => {
|
|
56
59
|
const combinedPrompt = buildCombinedPrompt(systemPrompt, userMessage);
|
|
57
|
-
const args = ['-m', this.model
|
|
60
|
+
const args = ['-m', this.model];
|
|
61
|
+
|
|
62
|
+
// Add reasoning effort via config override when configured
|
|
63
|
+
if (this.reasoningEffort) {
|
|
64
|
+
args.push('-c', `model_reasoning_effort="${this.reasoningEffort}"`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
args.push(combinedPrompt);
|
|
58
68
|
|
|
59
69
|
logger.debug(`Starting interactive Codex session with model: ${this.model}`);
|
|
60
70
|
|
|
@@ -167,6 +177,7 @@ export class CodexRunner implements ICliRunner {
|
|
|
167
177
|
let stderr = '';
|
|
168
178
|
let timedOut = false;
|
|
169
179
|
let contextOverflow = false;
|
|
180
|
+
let usageData: import('../types/config.js').UsageData | undefined;
|
|
170
181
|
|
|
171
182
|
const codexPath = getCodexPath();
|
|
172
183
|
|
|
@@ -175,15 +186,23 @@ export class CodexRunner implements ICliRunner {
|
|
|
175
186
|
logger.debug(`Codex path: ${codexPath}`);
|
|
176
187
|
|
|
177
188
|
logger.debug('Spawning process...');
|
|
178
|
-
const
|
|
189
|
+
const execArgs = [
|
|
179
190
|
'exec',
|
|
180
191
|
'--full-auto',
|
|
181
192
|
'--json',
|
|
182
193
|
'--ephemeral',
|
|
183
194
|
'-m',
|
|
184
195
|
this.model,
|
|
185
|
-
|
|
186
|
-
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
// Add reasoning effort via config override when configured
|
|
199
|
+
if (this.reasoningEffort) {
|
|
200
|
+
execArgs.push('-c', `model_reasoning_effort="${this.reasoningEffort}"`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
execArgs.push(prompt);
|
|
204
|
+
|
|
205
|
+
const proc = spawn(codexPath, execArgs, {
|
|
187
206
|
cwd,
|
|
188
207
|
env: process.env,
|
|
189
208
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -244,6 +263,10 @@ export class CodexRunner implements ICliRunner {
|
|
|
244
263
|
}
|
|
245
264
|
}
|
|
246
265
|
|
|
266
|
+
if (rendered.usageData) {
|
|
267
|
+
usageData = mergeUsageData(usageData, rendered.usageData);
|
|
268
|
+
}
|
|
269
|
+
|
|
247
270
|
if (shouldDisplay() && rendered.display) {
|
|
248
271
|
process.stdout.write(rendered.display);
|
|
249
272
|
}
|
|
@@ -262,6 +285,9 @@ export class CodexRunner implements ICliRunner {
|
|
|
262
285
|
if (rendered.textContent) {
|
|
263
286
|
output += rendered.textContent;
|
|
264
287
|
}
|
|
288
|
+
if (rendered.usageData) {
|
|
289
|
+
usageData = mergeUsageData(usageData, rendered.usageData);
|
|
290
|
+
}
|
|
265
291
|
if (shouldDisplay() && rendered.display) {
|
|
266
292
|
process.stdout.write(rendered.display);
|
|
267
293
|
}
|
|
@@ -281,8 +307,7 @@ export class CodexRunner implements ICliRunner {
|
|
|
281
307
|
exitCode: exitCode ?? (this.killed ? 130 : 1),
|
|
282
308
|
timedOut,
|
|
283
309
|
contextOverflow,
|
|
284
|
-
|
|
285
|
-
usageData: undefined,
|
|
310
|
+
usageData,
|
|
286
311
|
});
|
|
287
312
|
});
|
|
288
313
|
});
|
|
@@ -308,7 +308,8 @@ Respond with ONLY a markdown report in this exact format:
|
|
|
308
308
|
const claudePath = getClaudePath();
|
|
309
309
|
|
|
310
310
|
// Use configured model for failure analysis
|
|
311
|
-
const
|
|
311
|
+
const failureEntry = getModel('failureAnalysis');
|
|
312
|
+
const failureModel = failureEntry.model;
|
|
312
313
|
const proc = spawn(claudePath, [
|
|
313
314
|
'--model', failureModel,
|
|
314
315
|
'--no-session-persistence',
|
package/src/core/git.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
2
3
|
import * as path from 'node:path';
|
|
3
4
|
import { logger } from '../utils/logger.js';
|
|
4
5
|
import { extractProjectNumber, extractProjectName } from '../utils/paths.js';
|
|
@@ -213,10 +214,56 @@ export function isFileCommittedInHead(filePath: string): boolean {
|
|
|
213
214
|
}
|
|
214
215
|
}
|
|
215
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Extract a concise description from input.md for use in plan commit messages.
|
|
219
|
+
* Reads the first non-empty line and truncates to ~70 chars.
|
|
220
|
+
* Falls back to the project name if input.md can't be read.
|
|
221
|
+
*/
|
|
222
|
+
function extractPlanDescription(projectPath: string, fallback: string): string {
|
|
223
|
+
const inputPath = path.join(projectPath, 'input.md');
|
|
224
|
+
try {
|
|
225
|
+
const content = fs.readFileSync(inputPath, 'utf-8');
|
|
226
|
+
const firstLine = content.split('\n').find(line => line.trim().length > 0);
|
|
227
|
+
if (firstLine) {
|
|
228
|
+
// Strip leading markdown markers (-, *, [ ], [x], #, etc.)
|
|
229
|
+
let cleaned = firstLine.trim().replace(/^[-*#>\s]*(\[.\]\s*)?/, '').trim();
|
|
230
|
+
if (cleaned.length > 70) {
|
|
231
|
+
cleaned = cleaned.substring(0, 67) + '...';
|
|
232
|
+
}
|
|
233
|
+
if (cleaned.length > 0) {
|
|
234
|
+
return cleaned;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch {
|
|
238
|
+
// Can't read input.md, use fallback
|
|
239
|
+
}
|
|
240
|
+
return fallback;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Generate a description for amend commit messages.
|
|
245
|
+
* Uses the count and names of additional plan files if provided.
|
|
246
|
+
*/
|
|
247
|
+
function extractAmendDescription(additionalFiles?: string[]): string {
|
|
248
|
+
if (!additionalFiles || additionalFiles.length === 0) {
|
|
249
|
+
return 'updated plans';
|
|
250
|
+
}
|
|
251
|
+
// Extract task names from plan file paths (e.g., "plans/3-fix-bug.md" → "fix-bug")
|
|
252
|
+
const taskNames = additionalFiles
|
|
253
|
+
.map(f => path.basename(f, '.md'))
|
|
254
|
+
.map(name => name.replace(/^\d+-/, ''))
|
|
255
|
+
.filter(name => name.length > 0);
|
|
256
|
+
|
|
257
|
+
if (taskNames.length <= 3) {
|
|
258
|
+
return taskNames.join(', ');
|
|
259
|
+
}
|
|
260
|
+
return `${taskNames.length} tasks`;
|
|
261
|
+
}
|
|
262
|
+
|
|
216
263
|
/**
|
|
217
264
|
* Commit planning artifacts (input.md and decisions.md) for a project.
|
|
218
|
-
* Uses commit message format: RAF[
|
|
219
|
-
* For amendments: RAF[
|
|
265
|
+
* Uses commit message format: RAF[project-name] Plan: description
|
|
266
|
+
* For amendments: RAF[project-name] Amend: description
|
|
220
267
|
*
|
|
221
268
|
* @param projectPath - Full path to the project folder (e.g., /path/to/RAF/017-decision-vault)
|
|
222
269
|
* @param options - Optional settings
|
|
@@ -254,10 +301,17 @@ export async function commitPlanningArtifacts(projectPath: string, options?: { c
|
|
|
254
301
|
const formatType = options?.isAmend ? 'amend' as const : 'plan' as const;
|
|
255
302
|
const template = getCommitFormat(formatType);
|
|
256
303
|
const commitPrefix = getCommitPrefix();
|
|
304
|
+
|
|
305
|
+
// Auto-generate description based on commit type
|
|
306
|
+
const description = options?.isAmend
|
|
307
|
+
? extractAmendDescription(options?.additionalFiles)
|
|
308
|
+
: extractPlanDescription(projectPath, projectName);
|
|
309
|
+
|
|
257
310
|
const commitMessage = renderCommitMessage(template, {
|
|
258
311
|
prefix: commitPrefix,
|
|
259
|
-
projectId:
|
|
312
|
+
projectId: projectName, // backwards compat: {projectId} resolves to projectName
|
|
260
313
|
projectName,
|
|
314
|
+
description,
|
|
261
315
|
});
|
|
262
316
|
|
|
263
317
|
// Build list of files to stage (absolute paths)
|
package/src/core/pull-request.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as fs from 'node:fs';
|
|
|
3
3
|
import * as os from 'node:os';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import { logger } from '../utils/logger.js';
|
|
6
|
-
import {
|
|
6
|
+
import { formatModelDisplay, getModel } from '../utils/config.js';
|
|
7
7
|
import { extractProjectName, getInputPath, getDecisionsPath, getOutcomesDir, TASK_ID_PATTERN, numericFileSort } from '../utils/paths.js';
|
|
8
8
|
|
|
9
9
|
export interface PrCreateResult {
|
|
@@ -279,7 +279,7 @@ Respond with ONLY the PR body in this exact format (no extra text, no code fence
|
|
|
279
279
|
[1-3 bullet points describing how to verify these changes work correctly]`;
|
|
280
280
|
|
|
281
281
|
try {
|
|
282
|
-
const prModel =
|
|
282
|
+
const prModel = formatModelDisplay(getModel('prGeneration').model);
|
|
283
283
|
logger.info(`Generating PR with ${prModel}...`);
|
|
284
284
|
const body = await callClaudeForPrBody(prompt, timeoutMs);
|
|
285
285
|
return body;
|
|
@@ -365,7 +365,7 @@ async function callClaudeForPrBody(prompt: string, timeoutMs: number): Promise<s
|
|
|
365
365
|
let output = '';
|
|
366
366
|
let stderr = '';
|
|
367
367
|
|
|
368
|
-
const prModel = getModel('prGeneration');
|
|
368
|
+
const prModel = getModel('prGeneration').model;
|
|
369
369
|
const proc = spawn(claudePath, [
|
|
370
370
|
'--model', prModel,
|
|
371
371
|
'--no-session-persistence',
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { HarnessName } from '../types/config.js';
|
|
2
2
|
import type { ICliRunner } from './runner-interface.js';
|
|
3
3
|
import type { RunnerConfig } from './runner-types.js';
|
|
4
4
|
import { ClaudeRunner } from './claude-runner.js';
|
|
5
5
|
import { CodexRunner } from './codex-runner.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Create a CLI runner for the given
|
|
8
|
+
* Create a CLI runner for the given harness configuration.
|
|
9
9
|
*/
|
|
10
10
|
export function createRunner(config: RunnerConfig = {}): ICliRunner {
|
|
11
|
-
const
|
|
11
|
+
const harness = config.harness ?? 'claude';
|
|
12
12
|
|
|
13
|
-
switch (
|
|
13
|
+
switch (harness) {
|
|
14
14
|
case 'claude':
|
|
15
15
|
return new ClaudeRunner(config);
|
|
16
16
|
case 'codex':
|
|
17
17
|
return new CodexRunner(config);
|
|
18
18
|
default:
|
|
19
|
-
throw new Error(`Unknown
|
|
19
|
+
throw new Error(`Unknown harness: ${harness}`);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
* Get the binary name for a given
|
|
24
|
+
* Get the binary name for a given harness.
|
|
25
25
|
*/
|
|
26
|
-
export function
|
|
27
|
-
switch (
|
|
26
|
+
export function getHarnessBinaryName(harness: HarnessName): string {
|
|
27
|
+
switch (harness) {
|
|
28
28
|
case 'claude':
|
|
29
29
|
return 'claude';
|
|
30
30
|
case 'codex':
|
|
31
31
|
return 'codex';
|
|
32
32
|
default:
|
|
33
|
-
throw new Error(`Unknown
|
|
33
|
+
throw new Error(`Unknown harness: ${harness}`);
|
|
34
34
|
}
|
|
35
35
|
}
|
package/src/core/runner-types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { UsageData,
|
|
1
|
+
import type { UsageData, HarnessName } from '../types/config.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Options for a single runner execution (run, runVerbose, runInteractive, etc.).
|
|
@@ -52,14 +52,27 @@ export interface RunnerOptions {
|
|
|
52
52
|
export interface RunnerConfig {
|
|
53
53
|
/**
|
|
54
54
|
* Model to use (e.g., opus, sonnet, haiku, gpt-5.4).
|
|
55
|
-
* Default:
|
|
55
|
+
* Default: harness-specific default.
|
|
56
56
|
*/
|
|
57
57
|
model?: string;
|
|
58
58
|
/**
|
|
59
|
-
* CLI
|
|
59
|
+
* CLI harness to use.
|
|
60
60
|
* Default: 'claude'.
|
|
61
61
|
*/
|
|
62
|
-
|
|
62
|
+
harness?: HarnessName;
|
|
63
|
+
/**
|
|
64
|
+
* Reasoning effort level to pass to the CLI.
|
|
65
|
+
* Claude CLI: --effort <level>
|
|
66
|
+
* Codex CLI: -c model_reasoning_effort="<level>"
|
|
67
|
+
* Only included when explicitly set.
|
|
68
|
+
*/
|
|
69
|
+
reasoningEffort?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Enable fast mode for faster output.
|
|
72
|
+
* Claude CLI: --settings '{"fastMode": true}'
|
|
73
|
+
* Only included when explicitly set to true.
|
|
74
|
+
*/
|
|
75
|
+
fast?: boolean;
|
|
63
76
|
}
|
|
64
77
|
|
|
65
78
|
/**
|
|
@@ -9,10 +9,13 @@
|
|
|
9
9
|
* - TodoList: Task tracking (skipped)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import type { UsageData } from '../types/config.js';
|
|
12
13
|
import type { RenderResult } from './stream-renderer.js';
|
|
13
14
|
|
|
14
15
|
export interface CodexEvent {
|
|
15
16
|
type: string;
|
|
17
|
+
id?: string;
|
|
18
|
+
model?: string;
|
|
16
19
|
/** Claude flat-format fields (AgentMessage) */
|
|
17
20
|
content?: string;
|
|
18
21
|
/** Claude flat-format fields (CommandExecution) */
|
|
@@ -32,9 +35,12 @@ export interface CodexEvent {
|
|
|
32
35
|
exit_code?: number;
|
|
33
36
|
path?: string;
|
|
34
37
|
change_kind?: string;
|
|
38
|
+
message?: string;
|
|
35
39
|
};
|
|
36
40
|
/** Error message (for error / turn.failed events) */
|
|
37
41
|
message?: string;
|
|
42
|
+
/** Nested error object (for turn.failed events) */
|
|
43
|
+
error?: { message?: string };
|
|
38
44
|
/** Usage data (for turn.completed events) */
|
|
39
45
|
usage?: {
|
|
40
46
|
input_tokens?: number;
|
|
@@ -172,25 +178,62 @@ function renderItemCompleted(event: CodexEvent): RenderResult {
|
|
|
172
178
|
textContent: '',
|
|
173
179
|
};
|
|
174
180
|
}
|
|
181
|
+
case 'error': {
|
|
182
|
+
const msg = item.message ?? 'Unknown error';
|
|
183
|
+
return {
|
|
184
|
+
display: ` ✗ Error: ${msg}\n`,
|
|
185
|
+
textContent: msg,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
175
188
|
default:
|
|
176
189
|
return { display: '', textContent: '' };
|
|
177
190
|
}
|
|
178
191
|
}
|
|
179
192
|
|
|
180
193
|
function renderTurnCompleted(event: CodexEvent): RenderResult {
|
|
194
|
+
const usageData = extractUsageData(event);
|
|
195
|
+
|
|
181
196
|
if (event.usage) {
|
|
182
197
|
const { input_tokens, output_tokens } = event.usage;
|
|
183
198
|
const parts: string[] = [];
|
|
184
|
-
if (input_tokens) parts.push(`in: ${input_tokens}`);
|
|
185
|
-
if (output_tokens) parts.push(`out: ${output_tokens}`);
|
|
199
|
+
if (input_tokens !== undefined) parts.push(`in: ${input_tokens}`);
|
|
200
|
+
if (output_tokens !== undefined) parts.push(`out: ${output_tokens}`);
|
|
186
201
|
if (parts.length > 0) {
|
|
187
202
|
return {
|
|
188
203
|
display: ` → Usage: ${parts.join(', ')}\n`,
|
|
189
204
|
textContent: '',
|
|
205
|
+
usageData,
|
|
190
206
|
};
|
|
191
207
|
}
|
|
192
208
|
}
|
|
193
|
-
return { display: '', textContent: '' };
|
|
209
|
+
return { display: '', textContent: '', usageData };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function extractUsageData(event: CodexEvent): UsageData | undefined {
|
|
213
|
+
if (!event.usage) {
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const modelId = event.model ?? 'codex';
|
|
218
|
+
const inputTokens = event.usage.input_tokens ?? 0;
|
|
219
|
+
const outputTokens = event.usage.output_tokens ?? 0;
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
inputTokens,
|
|
223
|
+
outputTokens,
|
|
224
|
+
cacheReadInputTokens: 0,
|
|
225
|
+
cacheCreationInputTokens: 0,
|
|
226
|
+
modelUsage: {
|
|
227
|
+
[modelId]: {
|
|
228
|
+
inputTokens,
|
|
229
|
+
outputTokens,
|
|
230
|
+
cacheReadInputTokens: 0,
|
|
231
|
+
cacheCreationInputTokens: 0,
|
|
232
|
+
costUsd: null,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
totalCostUsd: null,
|
|
236
|
+
};
|
|
194
237
|
}
|
|
195
238
|
|
|
196
239
|
function renderError(event: CodexEvent): RenderResult {
|
|
@@ -202,7 +245,7 @@ function renderError(event: CodexEvent): RenderResult {
|
|
|
202
245
|
}
|
|
203
246
|
|
|
204
247
|
function renderTurnFailed(event: CodexEvent): RenderResult {
|
|
205
|
-
const msg = event.message ?? 'Turn failed';
|
|
248
|
+
const msg = event.error?.message ?? event.message ?? 'Turn failed';
|
|
206
249
|
return {
|
|
207
250
|
display: ` ✗ Failed: ${msg}\n`,
|
|
208
251
|
textContent: msg,
|
package/src/prompts/amend.ts
CHANGED
|
@@ -56,15 +56,14 @@ export function getAmendPrompt(params: AmendPromptParams): AmendPromptResult {
|
|
|
56
56
|
? modifiableTasks.map((t) => `- Task ${t.id}: ${t.taskName}`).join('\n')
|
|
57
57
|
: '(none)';
|
|
58
58
|
|
|
59
|
-
const systemPrompt = `You are a project planning assistant for RAF (Ralph's Automation Framework).
|
|
59
|
+
const systemPrompt = `You are a project planning assistant for RAF (Ralph's Automation Framework). Add new tasks or modify pending tasks in an existing project.
|
|
60
60
|
|
|
61
|
-
##
|
|
61
|
+
## Amendment Mode
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
- You can create NEW tasks starting from number ${encodeTaskId(nextTaskNumber)}
|
|
63
|
+
- [PROTECTED] tasks (completed): NEVER modify — their outcomes depend on the original plan
|
|
64
|
+
- [MODIFIABLE] tasks (pending/failed): MAY modify if the user requests changes
|
|
65
|
+
- Do NOT renumber existing tasks
|
|
66
|
+
- New tasks start from number ${encodeTaskId(nextTaskNumber)}
|
|
68
67
|
|
|
69
68
|
## Project Location
|
|
70
69
|
|
|
@@ -72,54 +71,30 @@ Project folder: ${projectPath}
|
|
|
72
71
|
|
|
73
72
|
## Existing Tasks
|
|
74
73
|
|
|
75
|
-
The following tasks already exist in this project:
|
|
76
|
-
|
|
77
74
|
${existingTasksSummary}
|
|
78
75
|
|
|
79
|
-
### Protected
|
|
76
|
+
### Protected (COMPLETED)
|
|
80
77
|
${protectedTasksList}
|
|
81
78
|
|
|
82
|
-
### Modifiable
|
|
79
|
+
### Modifiable (PENDING/FAILED)
|
|
83
80
|
${modifiableTasksList}
|
|
84
81
|
|
|
85
82
|
## Instructions
|
|
86
83
|
|
|
87
84
|
### Step 1: Read Context
|
|
88
85
|
|
|
89
|
-
|
|
90
|
-
- ${projectPath}/input.md
|
|
91
|
-
|
|
92
|
-
And review existing decisions from:
|
|
93
|
-
- ${projectPath}/decisions.md (if it exists)
|
|
86
|
+
Read the original project description (\`${projectPath}/input.md\`) and existing decisions (\`${projectPath}/decisions.md\`, if it exists).
|
|
94
87
|
|
|
95
88
|
### Step 2: Analyze New Requirements
|
|
96
89
|
|
|
97
|
-
|
|
98
|
-
- How the new tasks relate to existing ones
|
|
99
|
-
- Dependencies on completed tasks (check the ## Dependencies section in existing plan files)
|
|
100
|
-
- Whether new tasks should reference existing task outcomes
|
|
101
|
-
|
|
102
|
-
**Identifying Follow-up Tasks**: When a new task is a follow-up, fix, or iteration of a previously completed task, you MUST reference the previous task's outcome in the new plan's Context section. This gives the executing agent full context about what was done before.
|
|
103
|
-
|
|
104
|
-
Use this format in the Context section:
|
|
90
|
+
Consider how new tasks relate to existing ones and their dependencies. For follow-up/fix tasks, reference the previous task's outcome in the Context section:
|
|
105
91
|
\`This is a follow-up to task NN. See outcome: {projectPath}/outcomes/NN-task-name.md\`
|
|
106
92
|
|
|
107
|
-
The outcome file paths for completed tasks are listed above in the Existing Tasks section.
|
|
108
|
-
|
|
109
93
|
### Step 3: Interview the User
|
|
110
94
|
|
|
111
|
-
For EACH new task
|
|
112
|
-
- Specific requirements and constraints
|
|
113
|
-
- Technology preferences
|
|
114
|
-
- Any existing code or patterns to follow
|
|
115
|
-
- Edge cases to handle
|
|
116
|
-
|
|
117
|
-
### Step 3.5: Record Decisions
|
|
95
|
+
For EACH new task, use AskUserQuestion to gather specific requirements, technology preferences, existing patterns, and edge cases.
|
|
118
96
|
|
|
119
|
-
After EACH
|
|
120
|
-
- ${projectPath}/decisions.md
|
|
121
|
-
|
|
122
|
-
Use this format:
|
|
97
|
+
After EACH answer, append the Q&A to \`${projectPath}/decisions.md\`:
|
|
123
98
|
\`\`\`markdown
|
|
124
99
|
## [Question asked]
|
|
125
100
|
[User's answer]
|
|
@@ -127,12 +102,9 @@ Use this format:
|
|
|
127
102
|
|
|
128
103
|
### Step 4: Create New Plan Files
|
|
129
104
|
|
|
130
|
-
|
|
131
|
-
- ${projectPath}/plans/${encodeTaskId(nextTaskNumber)}-task-name.md
|
|
132
|
-
- ${projectPath}/plans/${encodeTaskId(nextTaskNumber + 1)}-task-name.md
|
|
133
|
-
- etc.
|
|
105
|
+
Create plan files starting from \`${projectPath}/plans/${encodeTaskId(nextTaskNumber)}-task-name.md\`. Use kebab-case names.
|
|
134
106
|
|
|
135
|
-
Each plan file MUST have
|
|
107
|
+
Each plan file MUST have this structure:
|
|
136
108
|
|
|
137
109
|
\`\`\`markdown
|
|
138
110
|
---
|
|
@@ -141,68 +113,38 @@ effort: medium
|
|
|
141
113
|
# Task: [Task Name]
|
|
142
114
|
|
|
143
115
|
## Objective
|
|
144
|
-
[Clear, one-sentence description
|
|
116
|
+
[Clear, one-sentence description]
|
|
145
117
|
|
|
146
118
|
## Context
|
|
147
|
-
[Why this task is needed,
|
|
148
|
-
[
|
|
149
|
-
[For follow-up/fix tasks: "This is a follow-up to task NN. See outcome: {projectPath}/outcomes/NN-task-name.md"]
|
|
119
|
+
[Why this task is needed, relation to existing tasks]
|
|
120
|
+
[For follow-ups: "This is a follow-up to task NN. See outcome: {projectPath}/outcomes/NN-task-name.md"]
|
|
150
121
|
|
|
151
122
|
## Dependencies
|
|
152
|
-
[Optional
|
|
153
|
-
[Comma-separated list of task IDs this task depends on, e.g., "1, 2"]
|
|
154
|
-
[If a dependency fails, this task will be automatically blocked]
|
|
123
|
+
[Optional — omit if none. Comma-separated task IDs, e.g., "1, 2"]
|
|
155
124
|
|
|
156
125
|
## Requirements
|
|
157
|
-
[Specific requirements gathered from the user interview]
|
|
158
126
|
- Requirement 1
|
|
159
127
|
- Requirement 2
|
|
160
|
-
- ...
|
|
161
128
|
|
|
162
129
|
## Implementation Steps
|
|
163
130
|
1. [Step 1]
|
|
164
131
|
2. [Step 2]
|
|
165
|
-
3. [Step 3]
|
|
166
|
-
...
|
|
167
132
|
|
|
168
133
|
## Acceptance Criteria
|
|
169
134
|
- [ ] Criterion 1
|
|
170
135
|
- [ ] Criterion 2
|
|
171
|
-
- [ ] All tests pass
|
|
172
136
|
|
|
173
137
|
## Notes
|
|
174
|
-
[
|
|
175
|
-
[Reference to existing task outcomes if relevant]
|
|
176
|
-
\`\`\`
|
|
177
|
-
|
|
178
|
-
### Frontmatter Requirements
|
|
179
|
-
|
|
180
|
-
The \`effort\` field is REQUIRED in every plan file. It indicates task complexity and determines which model will execute the task:
|
|
181
|
-
- \`effort: low\` — Trivial/mechanical changes, simple one-file edits, config changes
|
|
182
|
-
- \`effort: medium\` — Well-scoped feature work, bug fixes with clear plans, multi-file changes following existing patterns
|
|
183
|
-
- \`effort: high\` — Architectural changes, complex logic, tasks requiring deep codebase understanding
|
|
184
|
-
|
|
185
|
-
Optionally, you can add an explicit \`model\` field to override the effort-based model selection:
|
|
186
|
-
\`\`\`markdown
|
|
187
|
-
---
|
|
188
|
-
effort: medium
|
|
189
|
-
model: opus
|
|
190
|
-
---
|
|
191
|
-
# Task: ...
|
|
138
|
+
[Additional context, warnings, references to existing task outcomes]
|
|
192
139
|
\`\`\`
|
|
193
140
|
|
|
194
|
-
|
|
141
|
+
**Frontmatter fields:**
|
|
142
|
+
- \`effort\` (REQUIRED): \`low\` (trivial/mechanical), \`medium\` (well-scoped feature work), \`high\` (architectural/complex)
|
|
143
|
+
- \`model\` (optional): Override effort-based model selection. Rarely needed.
|
|
195
144
|
|
|
196
145
|
### Step 5: Confirm Completion
|
|
197
146
|
|
|
198
|
-
|
|
199
|
-
1. Provide a summary of:
|
|
200
|
-
- The new tasks you've created, including the effort level for each task. Example format:
|
|
201
|
-
- Task 2: add-caching (effort: medium)
|
|
202
|
-
- Task 3: update-docs (effort: low)
|
|
203
|
-
- How they relate to existing tasks
|
|
204
|
-
- Total task count in the project
|
|
205
|
-
2. Display this exit message to the user:
|
|
147
|
+
Summarize new tasks with effort levels, their relation to existing tasks, and total task count. Then display:
|
|
206
148
|
|
|
207
149
|
\`\`\`
|
|
208
150
|
Planning complete! To exit this session and run your tasks:
|
|
@@ -210,26 +152,12 @@ Planning complete! To exit this session and run your tasks:
|
|
|
210
152
|
2. Then run: raf do <project>
|
|
211
153
|
\`\`\`
|
|
212
154
|
|
|
213
|
-
##
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
5. Use descriptive, kebab-case names for plan files
|
|
220
|
-
6. Each plan should be self-contained with all context needed
|
|
221
|
-
7. Specify task dependencies using the ## Dependencies section with task IDs only (e.g., "1, 2")
|
|
222
|
-
8. Tasks without dependencies should omit the Dependencies section entirely
|
|
223
|
-
9. Be specific - vague plans lead to poor execution
|
|
224
|
-
10. ALWAYS include the \`effort\` frontmatter field in every plan file — assess each task's complexity
|
|
225
|
-
|
|
226
|
-
## Plan Output Style
|
|
227
|
-
|
|
228
|
-
Plans can include whatever level of detail you deem helpful for the executing agent. Use your judgment:
|
|
229
|
-
- Include implementation details when they clarify the approach
|
|
230
|
-
- Code snippets are acceptable when they help illustrate a specific pattern
|
|
231
|
-
- File paths are helpful when referencing existing project files, patterns, or directories
|
|
232
|
-
- Focus on clarity — the goal is for the executing agent to understand what needs to be done`;
|
|
155
|
+
## Rules
|
|
156
|
+
|
|
157
|
+
- Always interview the user before creating or modifying plans
|
|
158
|
+
- Each plan must be self-contained with all context needed
|
|
159
|
+
- Be specific — vague plans lead to poor execution
|
|
160
|
+
- Include implementation details, code snippets, and file paths when they clarify the approach`;
|
|
233
161
|
|
|
234
162
|
const userMessage = `I want to add the following new tasks to this project:
|
|
235
163
|
|