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/commands/config.ts
CHANGED
|
@@ -8,9 +8,10 @@ import { shutdownHandler } from '../core/shutdown-handler.js';
|
|
|
8
8
|
import { logger } from '../utils/logger.js';
|
|
9
9
|
import {
|
|
10
10
|
getConfigPath,
|
|
11
|
+
formatModelDisplay,
|
|
11
12
|
getModel,
|
|
12
|
-
getModelShortName,
|
|
13
13
|
validateConfig,
|
|
14
|
+
collectConfigValidationWarnings,
|
|
14
15
|
ConfigValidationError,
|
|
15
16
|
resetConfigCache,
|
|
16
17
|
resolveConfig,
|
|
@@ -18,12 +19,7 @@ import {
|
|
|
18
19
|
} from '../utils/config.js';
|
|
19
20
|
import { DEFAULT_CONFIG } from '../types/config.js';
|
|
20
21
|
import type { UserConfig } from '../types/config.js';
|
|
21
|
-
|
|
22
|
-
interface ConfigCommandOptions {
|
|
23
|
-
reset?: boolean;
|
|
24
|
-
get?: true | string; // true when --get with no key, string when --get <key>
|
|
25
|
-
set?: string[]; // [key, value]
|
|
26
|
-
}
|
|
22
|
+
import { createPresetCommand } from './preset.js';
|
|
27
23
|
|
|
28
24
|
/**
|
|
29
25
|
* Load the config documentation markdown from src/prompts/config-docs.md.
|
|
@@ -92,10 +88,10 @@ function postSessionValidation(configPath: string): void {
|
|
|
92
88
|
} catch (error) {
|
|
93
89
|
if (error instanceof ConfigValidationError) {
|
|
94
90
|
logger.warn(`Config validation warning: ${error.message}`);
|
|
95
|
-
logger.warn('The file was not deleted — you can fix it manually or run `raf config` again.');
|
|
91
|
+
logger.warn('The file was not deleted — you can fix it manually or run `raf config wizard` again.');
|
|
96
92
|
} else if (error instanceof SyntaxError) {
|
|
97
93
|
logger.warn('Config file contains invalid JSON.');
|
|
98
|
-
logger.warn('The file was not deleted — you can fix it manually or run `raf config` again.');
|
|
94
|
+
logger.warn('The file was not deleted — you can fix it manually or run `raf config wizard` again.');
|
|
99
95
|
} else {
|
|
100
96
|
logger.warn(`Could not validate config: ${error}`);
|
|
101
97
|
}
|
|
@@ -242,18 +238,16 @@ function formatValue(value: unknown): string {
|
|
|
242
238
|
// ---- Config get/set handlers ----
|
|
243
239
|
|
|
244
240
|
/**
|
|
245
|
-
*
|
|
241
|
+
* Print config value(s).
|
|
246
242
|
*/
|
|
247
|
-
function handleGet(key
|
|
243
|
+
function handleGet(key?: string): void {
|
|
248
244
|
const config = resolveConfig();
|
|
249
245
|
|
|
250
|
-
if (key ===
|
|
251
|
-
// No key specified: print full config
|
|
246
|
+
if (key === undefined) {
|
|
252
247
|
console.log(JSON.stringify(config, null, 2));
|
|
253
248
|
return;
|
|
254
249
|
}
|
|
255
250
|
|
|
256
|
-
// Specific key requested
|
|
257
251
|
const value = getNestedValue(config, key);
|
|
258
252
|
|
|
259
253
|
if (value === undefined) {
|
|
@@ -265,15 +259,9 @@ function handleGet(key: true | string): void {
|
|
|
265
259
|
}
|
|
266
260
|
|
|
267
261
|
/**
|
|
268
|
-
*
|
|
262
|
+
* Update config file with a new value.
|
|
269
263
|
*/
|
|
270
|
-
function handleSet(
|
|
271
|
-
if (args.length !== 2) {
|
|
272
|
-
logger.error('--set requires exactly 2 arguments: key and value');
|
|
273
|
-
process.exit(1);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const [key, rawValue] = args as [string, string];
|
|
264
|
+
function handleSet(key: string, rawValue: string): void {
|
|
277
265
|
const value = parseValue(rawValue);
|
|
278
266
|
const configPath = getConfigPath();
|
|
279
267
|
|
|
@@ -312,7 +300,10 @@ function handleSet(args: string[]): void {
|
|
|
312
300
|
|
|
313
301
|
// Validate the resulting config
|
|
314
302
|
try {
|
|
315
|
-
validateConfig(userConfig);
|
|
303
|
+
const validated = validateConfig(userConfig);
|
|
304
|
+
for (const warning of collectConfigValidationWarnings(validated)) {
|
|
305
|
+
logger.warn(`Config validation warning: ${warning}`);
|
|
306
|
+
}
|
|
316
307
|
} catch (error) {
|
|
317
308
|
if (error instanceof ConfigValidationError) {
|
|
318
309
|
logger.error(`Validation error: ${error.message}`);
|
|
@@ -336,41 +327,47 @@ function handleSet(args: string[]): void {
|
|
|
336
327
|
|
|
337
328
|
export function createConfigCommand(): Command {
|
|
338
329
|
const command = new Command('config')
|
|
339
|
-
.description('
|
|
340
|
-
.
|
|
341
|
-
|
|
342
|
-
.option('--get [key]', 'Show config value (all config if no key, or specific dot-notation key)')
|
|
343
|
-
.option('--set <items...>', 'Set a config value using dot-notation key and value')
|
|
344
|
-
.action(async (promptParts: string[], options: ConfigCommandOptions) => {
|
|
345
|
-
// --reset takes precedence
|
|
346
|
-
if (options.reset) {
|
|
347
|
-
await handleReset();
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// --get and --set are mutually exclusive
|
|
352
|
-
if (options.get !== undefined && options.set !== undefined) {
|
|
353
|
-
logger.error('Cannot use --get and --set together');
|
|
354
|
-
process.exit(1);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
// Handle --get
|
|
358
|
-
if (options.get !== undefined) {
|
|
359
|
-
handleGet(options.get);
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Handle --set
|
|
364
|
-
if (options.set !== undefined) {
|
|
365
|
-
handleSet(options.set);
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
// Default: run interactive session
|
|
370
|
-
const initialPrompt = promptParts.length > 0 ? promptParts.join(' ') : undefined;
|
|
371
|
-
await runConfigSession(initialPrompt);
|
|
330
|
+
.description('Manage RAF configuration with get, set, reset, wizard, and preset subcommands')
|
|
331
|
+
.action(function(this: Command) {
|
|
332
|
+
this.outputHelp();
|
|
372
333
|
});
|
|
373
334
|
|
|
335
|
+
command
|
|
336
|
+
.addCommand(
|
|
337
|
+
new Command('get')
|
|
338
|
+
.description('Print the resolved config or one resolved dot-notation value')
|
|
339
|
+
.argument('[key]', 'Optional dot-notation key to read')
|
|
340
|
+
.action((key?: string) => {
|
|
341
|
+
handleGet(key);
|
|
342
|
+
})
|
|
343
|
+
)
|
|
344
|
+
.addCommand(
|
|
345
|
+
new Command('set')
|
|
346
|
+
.description('Write a config value using a dot-notation key')
|
|
347
|
+
.argument('<key>', 'Dot-notation key to write')
|
|
348
|
+
.argument('<value>', 'Value to write; parsed as JSON when possible')
|
|
349
|
+
.action((key: string, value: string) => {
|
|
350
|
+
handleSet(key, value);
|
|
351
|
+
})
|
|
352
|
+
)
|
|
353
|
+
.addCommand(
|
|
354
|
+
new Command('reset')
|
|
355
|
+
.description('Delete the config file and restore all defaults')
|
|
356
|
+
.action(async () => {
|
|
357
|
+
await handleReset();
|
|
358
|
+
})
|
|
359
|
+
)
|
|
360
|
+
.addCommand(
|
|
361
|
+
new Command('wizard')
|
|
362
|
+
.description('Launch the interactive config editor session')
|
|
363
|
+
.argument('[prompt...]', 'Optional initial prompt for the config session')
|
|
364
|
+
.action(async (promptParts: string[]) => {
|
|
365
|
+
const initialPrompt = promptParts.length > 0 ? promptParts.join(' ') : undefined;
|
|
366
|
+
await runConfigSession(initialPrompt);
|
|
367
|
+
})
|
|
368
|
+
)
|
|
369
|
+
.addCommand(createPresetCommand());
|
|
370
|
+
|
|
374
371
|
return command;
|
|
375
372
|
}
|
|
376
373
|
|
|
@@ -399,16 +396,16 @@ async function runConfigSession(initialPrompt?: string): Promise<void> {
|
|
|
399
396
|
const configPath = getConfigPath();
|
|
400
397
|
|
|
401
398
|
// Try to load config, but fall back to defaults if it's broken
|
|
402
|
-
// This allows raf config to be used to fix a broken config file
|
|
403
|
-
let
|
|
399
|
+
// This allows raf config wizard to be used to fix a broken config file
|
|
400
|
+
let modelEntry: import('../types/config.js').ModelEntry;
|
|
404
401
|
let configError: Error | null = null;
|
|
405
402
|
|
|
406
403
|
try {
|
|
407
|
-
|
|
404
|
+
modelEntry = getModel('config');
|
|
408
405
|
} catch (error) {
|
|
409
406
|
// Config file has errors - fall back to defaults so the session can launch
|
|
410
407
|
configError = error instanceof Error ? error : new Error(String(error));
|
|
411
|
-
|
|
408
|
+
modelEntry = DEFAULT_CONFIG.models.config;
|
|
412
409
|
// Clear the cached config so subsequent calls don't use the broken cache
|
|
413
410
|
resetConfigCache();
|
|
414
411
|
}
|
|
@@ -416,7 +413,7 @@ async function runConfigSession(initialPrompt?: string): Promise<void> {
|
|
|
416
413
|
// Warn user if config has errors, before starting the session
|
|
417
414
|
if (configError) {
|
|
418
415
|
logger.warn(`Config file has errors, using defaults: ${configError.message}`);
|
|
419
|
-
logger.warn('Fix the config in this session or run `raf config
|
|
416
|
+
logger.warn('Fix the config in this session or run `raf config reset` to start fresh.');
|
|
420
417
|
logger.newline();
|
|
421
418
|
}
|
|
422
419
|
|
|
@@ -438,11 +435,11 @@ async function runConfigSession(initialPrompt?: string): Promise<void> {
|
|
|
438
435
|
?? 'Show me my current config and help me make changes.';
|
|
439
436
|
|
|
440
437
|
// Set up runner
|
|
441
|
-
const claudeRunner = createRunner({ model });
|
|
438
|
+
const claudeRunner = createRunner({ model: modelEntry.model, harness: modelEntry.harness, reasoningEffort: modelEntry.reasoningEffort, fast: modelEntry.fast });
|
|
442
439
|
shutdownHandler.init();
|
|
443
440
|
shutdownHandler.registerClaudeRunner(claudeRunner);
|
|
444
441
|
|
|
445
|
-
const configModel =
|
|
442
|
+
const configModel = formatModelDisplay(modelEntry.model);
|
|
446
443
|
logger.info(`Starting config session with ${configModel}...`);
|
|
447
444
|
logger.newline();
|
|
448
445
|
|
package/src/commands/do.ts
CHANGED
|
@@ -8,18 +8,19 @@ import { shutdownHandler } from '../core/shutdown-handler.js';
|
|
|
8
8
|
import { stashChanges, hasUncommittedChanges, isGitRepo, getHeadCommitHash } from '../core/git.js';
|
|
9
9
|
import { getExecutionPrompt } from '../prompts/execution.js';
|
|
10
10
|
import { parseOutput, isRetryableFailure } from '../parsers/output-parser.js';
|
|
11
|
-
import { validatePlansExist
|
|
11
|
+
import { validatePlansExist } from '../utils/validation.js';
|
|
12
12
|
import { getRafDir, extractProjectNumber, extractProjectName, extractTaskNameFromPlanFile, resolveProjectIdentifierWithDetails, getOutcomeFilePath } from '../utils/paths.js';
|
|
13
13
|
import { pickPendingProject, getPendingProjects, getPendingWorktreeProjects } from '../ui/project-picker.js';
|
|
14
14
|
import type { PendingProjectInfo } from '../ui/project-picker.js';
|
|
15
15
|
import { logger } from '../utils/logger.js';
|
|
16
|
-
import { getConfig, getModel,
|
|
16
|
+
import { formatModelDisplay, getConfig, getModel, getSyncMainBranch, resolveEffortToModel, applyModelCeiling, getShowCacheTokens, parseModelSpec, resolveFullModelId } from '../utils/config.js';
|
|
17
17
|
import type { PlanFrontmatter } from '../utils/frontmatter.js';
|
|
18
18
|
import { getVersion } from '../utils/version.js';
|
|
19
19
|
import { createTaskTimer, formatElapsedTime } from '../utils/timer.js';
|
|
20
20
|
import { createStatusLine } from '../utils/status-line.js';
|
|
21
21
|
import {
|
|
22
22
|
formatProjectHeader,
|
|
23
|
+
formatModelMetadata,
|
|
23
24
|
formatSummary,
|
|
24
25
|
formatTaskProgress,
|
|
25
26
|
formatTaskTokenSummary,
|
|
@@ -52,7 +53,7 @@ import {
|
|
|
52
53
|
rebaseOntoMain,
|
|
53
54
|
} from '../core/worktree.js';
|
|
54
55
|
import { createPullRequest, prPreflight } from '../core/pull-request.js';
|
|
55
|
-
import type { DoCommandOptions } from '../types/config.js';
|
|
56
|
+
import type { DoCommandOptions, ModelEntry } from '../types/config.js';
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
* Post-execution action chosen by the user before task execution begins.
|
|
@@ -66,8 +67,8 @@ export type PostExecutionAction = 'merge' | 'pr' | 'leave';
|
|
|
66
67
|
* Result of resolving a task's model from frontmatter.
|
|
67
68
|
*/
|
|
68
69
|
interface TaskModelResolution {
|
|
69
|
-
/** The resolved model (after ceiling is applied). */
|
|
70
|
-
|
|
70
|
+
/** The resolved model entry (after ceiling is applied). */
|
|
71
|
+
entry: ModelEntry;
|
|
71
72
|
/** Whether a warning should be logged about missing frontmatter. */
|
|
72
73
|
missingFrontmatter: boolean;
|
|
73
74
|
/** Frontmatter parsing warnings to log. */
|
|
@@ -84,27 +85,26 @@ interface TaskModelResolution {
|
|
|
84
85
|
*
|
|
85
86
|
* @param frontmatter - Parsed frontmatter from the plan file
|
|
86
87
|
* @param frontmatterWarnings - Warnings from frontmatter parsing
|
|
87
|
-
* @param
|
|
88
|
+
* @param ceilingEntry - The ceiling model entry (usually models.execute from config)
|
|
88
89
|
* @param isRetry - Whether this is a retry attempt (escalates to ceiling)
|
|
89
90
|
*/
|
|
90
91
|
function resolveTaskModel(
|
|
91
92
|
frontmatter: PlanFrontmatter | undefined,
|
|
92
93
|
frontmatterWarnings: string[] | undefined,
|
|
93
|
-
|
|
94
|
+
ceilingEntry: ModelEntry,
|
|
94
95
|
isRetry: boolean,
|
|
95
|
-
provider?: import('../types/config.js').HarnessProvider,
|
|
96
96
|
): TaskModelResolution {
|
|
97
97
|
const warnings = frontmatterWarnings ? [...frontmatterWarnings] : [];
|
|
98
98
|
|
|
99
99
|
// Retry escalation: always use the ceiling model on retry
|
|
100
100
|
if (isRetry) {
|
|
101
|
-
return {
|
|
101
|
+
return { entry: ceilingEntry, missingFrontmatter: false, warnings };
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// No frontmatter - fallback to ceiling with warning
|
|
105
105
|
if (!frontmatter) {
|
|
106
106
|
return {
|
|
107
|
-
|
|
107
|
+
entry: ceilingEntry,
|
|
108
108
|
missingFrontmatter: true,
|
|
109
109
|
warnings,
|
|
110
110
|
};
|
|
@@ -112,20 +112,25 @@ function resolveTaskModel(
|
|
|
112
112
|
|
|
113
113
|
// Explicit model in frontmatter - apply ceiling
|
|
114
114
|
if (frontmatter.model) {
|
|
115
|
-
const
|
|
116
|
-
|
|
115
|
+
const parsed = parseModelSpec(frontmatter.model);
|
|
116
|
+
const fmEntry: ModelEntry = {
|
|
117
|
+
model: parsed.model,
|
|
118
|
+
harness: parsed.harness,
|
|
119
|
+
};
|
|
120
|
+
const result = applyModelCeiling(fmEntry, ceilingEntry);
|
|
121
|
+
return { entry: result, missingFrontmatter: false, warnings };
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
// Effort-based resolution - apply ceiling
|
|
120
125
|
if (frontmatter.effort) {
|
|
121
|
-
const
|
|
122
|
-
const
|
|
123
|
-
return {
|
|
126
|
+
const mappedEntry = resolveEffortToModel(frontmatter.effort);
|
|
127
|
+
const result = applyModelCeiling(mappedEntry, ceilingEntry);
|
|
128
|
+
return { entry: result, missingFrontmatter: false, warnings };
|
|
124
129
|
}
|
|
125
130
|
|
|
126
131
|
// Frontmatter present but no effort or model - fallback to ceiling with warning
|
|
127
132
|
return {
|
|
128
|
-
|
|
133
|
+
entry: ceilingEntry,
|
|
129
134
|
missingFrontmatter: true,
|
|
130
135
|
warnings,
|
|
131
136
|
};
|
|
@@ -186,6 +191,13 @@ interface ProjectExecutionResult {
|
|
|
186
191
|
retryHistory?: TaskRetryHistory[];
|
|
187
192
|
}
|
|
188
193
|
|
|
194
|
+
export function formatResolvedTaskModel(entry: ModelEntry): string {
|
|
195
|
+
return formatModelMetadata(resolveFullModelId(entry.model), {
|
|
196
|
+
effort: entry.reasoningEffort,
|
|
197
|
+
fast: entry.fast === true,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
189
201
|
export function createDoCommand(): Command {
|
|
190
202
|
const command = new Command('do')
|
|
191
203
|
.description('Execute planned tasks for a project')
|
|
@@ -195,9 +207,6 @@ export function createDoCommand(): Command {
|
|
|
195
207
|
.option('-v, --verbose', 'Show full LLM output')
|
|
196
208
|
.option('-d, --debug', 'Save all logs and show debug output')
|
|
197
209
|
.option('-f, --force', 'Re-run all tasks regardless of status')
|
|
198
|
-
.option('-m, --model <name>', 'Model to use (sonnet, haiku, opus)')
|
|
199
|
-
.option('--sonnet', 'Use Sonnet model (shorthand for --model sonnet)')
|
|
200
|
-
.option('-p, --provider <provider>', 'CLI provider to use (claude, codex)')
|
|
201
210
|
.action(async (project: string | undefined, options: DoCommandOptions) => {
|
|
202
211
|
await runDoCommand(project, options);
|
|
203
212
|
});
|
|
@@ -208,14 +217,7 @@ export function createDoCommand(): Command {
|
|
|
208
217
|
async function runDoCommand(projectIdentifierArg: string | undefined, options: DoCommandOptions): Promise<void> {
|
|
209
218
|
const rafDir = getRafDir();
|
|
210
219
|
let projectIdentifier = projectIdentifierArg;
|
|
211
|
-
|
|
212
|
-
let model: string;
|
|
213
|
-
try {
|
|
214
|
-
model = resolveModelOption(options.model as string | undefined, options.sonnet, 'execute');
|
|
215
|
-
} catch (error) {
|
|
216
|
-
logger.error((error as Error).message);
|
|
217
|
-
process.exit(1);
|
|
218
|
-
}
|
|
220
|
+
const executeEntry = getModel('execute');
|
|
219
221
|
|
|
220
222
|
// Variables for worktree context (derived from where the project is found)
|
|
221
223
|
let worktreeRoot: string | undefined;
|
|
@@ -398,8 +400,7 @@ async function runDoCommand(projectIdentifierArg: string | undefined, options: D
|
|
|
398
400
|
force,
|
|
399
401
|
maxRetries,
|
|
400
402
|
autoCommit,
|
|
401
|
-
|
|
402
|
-
provider: options.provider,
|
|
403
|
+
executeEntry,
|
|
403
404
|
worktreeCwd: worktreeRoot,
|
|
404
405
|
}
|
|
405
406
|
);
|
|
@@ -558,9 +559,8 @@ interface SingleProjectOptions {
|
|
|
558
559
|
force: boolean;
|
|
559
560
|
maxRetries: number;
|
|
560
561
|
autoCommit: boolean;
|
|
561
|
-
model
|
|
562
|
-
|
|
563
|
-
provider?: import('../types/config.js').HarnessProvider;
|
|
562
|
+
/** The resolved execute model entry (acts as ceiling for per-task resolution). */
|
|
563
|
+
executeEntry: ModelEntry;
|
|
564
564
|
/** Worktree root directory. When set, the runner uses cwd in the worktree. */
|
|
565
565
|
worktreeCwd?: string;
|
|
566
566
|
}
|
|
@@ -570,7 +570,7 @@ async function executeSingleProject(
|
|
|
570
570
|
projectName: string,
|
|
571
571
|
options: SingleProjectOptions
|
|
572
572
|
): Promise<ProjectExecutionResult> {
|
|
573
|
-
const { timeout, verbose, debug, force, maxRetries, autoCommit,
|
|
573
|
+
const { timeout, verbose, debug, force, maxRetries, autoCommit, executeEntry, worktreeCwd } = options;
|
|
574
574
|
|
|
575
575
|
if (!validatePlansExist(projectPath)) {
|
|
576
576
|
return {
|
|
@@ -614,8 +614,8 @@ async function executeSingleProject(
|
|
|
614
614
|
const projectManager = new ProjectManager();
|
|
615
615
|
shutdownHandler.init();
|
|
616
616
|
|
|
617
|
-
// The ceiling model for all tasks (can be overridden per-task, subject to this ceiling)
|
|
618
|
-
const
|
|
617
|
+
// The ceiling model entry for all tasks (can be overridden per-task, subject to this ceiling)
|
|
618
|
+
const ceilingEntry = executeEntry;
|
|
619
619
|
|
|
620
620
|
// Initialize token tracker for usage reporting
|
|
621
621
|
const tokenTracker = new TokenTracker();
|
|
@@ -628,8 +628,8 @@ async function executeSingleProject(
|
|
|
628
628
|
const projectStartTime = Date.now();
|
|
629
629
|
|
|
630
630
|
// Resolve and display version + ceiling model info (before any tasks run)
|
|
631
|
-
const fullCeilingModelId = resolveFullModelId(
|
|
632
|
-
logger.dim(`RAF v${getVersion()} | Ceiling: ${fullCeilingModelId}`);
|
|
631
|
+
const fullCeilingModelId = resolveFullModelId(ceilingEntry.model);
|
|
632
|
+
logger.dim(`RAF v${getVersion()} | Ceiling: ${fullCeilingModelId} (${ceilingEntry.harness})`);
|
|
633
633
|
|
|
634
634
|
if (verbose) {
|
|
635
635
|
logger.info(`Executing project: ${projectName}`);
|
|
@@ -811,6 +811,8 @@ async function executeSingleProject(
|
|
|
811
811
|
const failureHistory: Array<{ attempt: number; reason: string }> = [];
|
|
812
812
|
// Track current model for display in status line (updated in retry loop)
|
|
813
813
|
let currentModel: string | undefined;
|
|
814
|
+
let currentEffort: string | undefined;
|
|
815
|
+
let currentModelFast = false;
|
|
814
816
|
|
|
815
817
|
// Set up timer for elapsed time tracking
|
|
816
818
|
const statusLine = createStatusLine();
|
|
@@ -821,8 +823,11 @@ async function executeSingleProject(
|
|
|
821
823
|
return;
|
|
822
824
|
}
|
|
823
825
|
// Show running status with task name and timer (updates in place)
|
|
824
|
-
const modelShortName = currentModel ?
|
|
825
|
-
statusLine.update(formatTaskProgress(taskNumber, totalTasks, 'running', displayName, elapsed, taskId, modelShortName
|
|
826
|
+
const modelShortName = currentModel ? formatModelDisplay(currentModel) : undefined;
|
|
827
|
+
statusLine.update(formatTaskProgress(taskNumber, totalTasks, 'running', displayName, elapsed, taskId, modelShortName, {
|
|
828
|
+
effort: currentEffort,
|
|
829
|
+
fast: currentModelFast,
|
|
830
|
+
}));
|
|
826
831
|
});
|
|
827
832
|
timer.start();
|
|
828
833
|
|
|
@@ -841,13 +846,14 @@ async function executeSingleProject(
|
|
|
841
846
|
const modelResolution = resolveTaskModel(
|
|
842
847
|
task.frontmatter,
|
|
843
848
|
undefined, // warnings already logged above
|
|
844
|
-
|
|
849
|
+
ceilingEntry,
|
|
845
850
|
isRetry,
|
|
846
|
-
provider,
|
|
847
851
|
);
|
|
848
852
|
|
|
849
853
|
// Update current model for timer callback display
|
|
850
|
-
currentModel = modelResolution.model;
|
|
854
|
+
currentModel = modelResolution.entry.model;
|
|
855
|
+
currentEffort = task.frontmatter?.effort;
|
|
856
|
+
currentModelFast = modelResolution.entry.fast === true;
|
|
851
857
|
|
|
852
858
|
// Log missing frontmatter warning on first attempt only
|
|
853
859
|
if (!isRetry && modelResolution.missingFrontmatter) {
|
|
@@ -855,14 +861,14 @@ async function executeSingleProject(
|
|
|
855
861
|
}
|
|
856
862
|
|
|
857
863
|
// Create a runner for this attempt's model
|
|
858
|
-
const taskRunner = createRunner({ model: modelResolution.model,
|
|
864
|
+
const taskRunner = createRunner({ model: modelResolution.entry.model, harness: modelResolution.entry.harness, reasoningEffort: modelResolution.entry.reasoningEffort, fast: modelResolution.entry.fast });
|
|
859
865
|
shutdownHandler.registerClaudeRunner(taskRunner);
|
|
860
866
|
|
|
861
867
|
if (verbose && isRetry) {
|
|
862
|
-
const retryModel =
|
|
868
|
+
const retryModel = formatResolvedTaskModel(modelResolution.entry);
|
|
863
869
|
logger.info(` Retry ${attempts}/${maxRetries} for task ${taskLabel} (model: ${retryModel})...`);
|
|
864
870
|
} else if (verbose && !isRetry) {
|
|
865
|
-
const taskModel =
|
|
871
|
+
const taskModel = formatResolvedTaskModel(modelResolution.entry);
|
|
866
872
|
logger.info(` Model: ${taskModel}`);
|
|
867
873
|
}
|
|
868
874
|
|
|
@@ -1024,8 +1030,11 @@ Task completed. No detailed report provided.
|
|
|
1024
1030
|
logger.success(` Task ${taskLabel} completed (${elapsedFormatted})`);
|
|
1025
1031
|
} else {
|
|
1026
1032
|
// Minimal mode: show completed task line
|
|
1027
|
-
const modelShortName = currentModel ?
|
|
1028
|
-
logger.info(formatTaskProgress(taskNumber, totalTasks, 'completed', displayName, elapsedMs, task.id, modelShortName
|
|
1033
|
+
const modelShortName = currentModel ? formatModelDisplay(currentModel) : undefined;
|
|
1034
|
+
logger.info(formatTaskProgress(taskNumber, totalTasks, 'completed', displayName, elapsedMs, task.id, modelShortName, {
|
|
1035
|
+
effort: currentEffort,
|
|
1036
|
+
fast: currentModelFast,
|
|
1037
|
+
}));
|
|
1029
1038
|
}
|
|
1030
1039
|
|
|
1031
1040
|
// Track and display token usage for this task
|
|
@@ -1051,12 +1060,16 @@ Task completed. No detailed report provided.
|
|
|
1051
1060
|
|
|
1052
1061
|
if (verbose) {
|
|
1053
1062
|
logger.error(` Task ${taskLabel} failed: ${failureReason} (${elapsedFormatted})`);
|
|
1054
|
-
const
|
|
1063
|
+
const analysisEntry = getModel('failureAnalysis');
|
|
1064
|
+
const analysisModel = formatModelDisplay(analysisEntry.model);
|
|
1055
1065
|
logger.info(` Analyzing failure with ${analysisModel}...`);
|
|
1056
1066
|
} else {
|
|
1057
1067
|
// Minimal mode: show failed task line
|
|
1058
|
-
const modelShortName = currentModel ?
|
|
1059
|
-
logger.info(formatTaskProgress(taskNumber, totalTasks, 'failed', displayName, elapsedMs, task.id, modelShortName
|
|
1068
|
+
const modelShortName = currentModel ? formatModelDisplay(currentModel) : undefined;
|
|
1069
|
+
logger.info(formatTaskProgress(taskNumber, totalTasks, 'failed', displayName, elapsedMs, task.id, modelShortName, {
|
|
1070
|
+
effort: currentEffort,
|
|
1071
|
+
fast: currentModelFast,
|
|
1072
|
+
}));
|
|
1060
1073
|
}
|
|
1061
1074
|
|
|
1062
1075
|
// Track token usage even for failed tasks (partial data still useful for totals)
|
|
@@ -1209,4 +1222,3 @@ ${stashName ? `- Stash: ${stashName}` : ''}
|
|
|
1209
1222
|
retryHistory: projectRetryHistory,
|
|
1210
1223
|
};
|
|
1211
1224
|
}
|
|
1212
|
-
|