rafcode 3.0.0 → 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/38-dual-wielder/decisions.md +9 -0
- package/RAF/38-dual-wielder/input.md +6 -1
- package/RAF/38-dual-wielder/outcomes/8-e2e-test-codex-provider.md +139 -0
- package/RAF/38-dual-wielder/plans/8-e2e-test-codex-provider.md +95 -0
- package/RAF/39-pathless-rover/decisions.md +16 -0
- package/RAF/39-pathless-rover/input.md +2 -0
- package/RAF/39-pathless-rover/outcomes/1-fix-codex-stream-renderer.md +21 -0
- package/RAF/39-pathless-rover/outcomes/2-wire-provider-flag.md +28 -0
- package/RAF/39-pathless-rover/outcomes/3-remove-worktree-flag-do.md +41 -0
- package/RAF/39-pathless-rover/outcomes/4-remove-worktree-flag-plan-amend.md +30 -0
- package/RAF/39-pathless-rover/outcomes/5-update-prompts-and-docs.md +26 -0
- package/RAF/39-pathless-rover/plans/1-fix-codex-stream-renderer.md +43 -0
- package/RAF/39-pathless-rover/plans/2-wire-provider-flag.md +48 -0
- package/RAF/39-pathless-rover/plans/3-remove-worktree-flag-do.md +41 -0
- package/RAF/39-pathless-rover/plans/4-remove-worktree-flag-plan-amend.md +43 -0
- package/RAF/39-pathless-rover/plans/5-update-prompts-and-docs.md +31 -0
- package/RAF/40-numeric-order-fix/decisions.md +7 -0
- package/RAF/40-numeric-order-fix/input.md +19 -0
- package/RAF/40-numeric-order-fix/outcomes/1-fix-numeric-sort-order.md +18 -0
- package/RAF/40-numeric-order-fix/outcomes/2-add-npm-keywords.md +10 -0
- package/RAF/40-numeric-order-fix/plans/1-fix-numeric-sort-order.md +48 -0
- package/RAF/40-numeric-order-fix/plans/2-add-npm-keywords.md +23 -0
- 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 +50 -63
- 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 +91 -230
- package/dist/commands/do.js.map +1 -1
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +54 -259
- 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/project-manager.d.ts.map +1 -1
- package/dist/core/project-manager.js +2 -2
- package/dist/core/project-manager.js.map +1 -1
- package/dist/core/pull-request.js +5 -5
- 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/core/state-derivation.js +3 -3
- package/dist/core/state-derivation.js.map +1 -1
- package/dist/parsers/codex-stream-renderer.d.ts +28 -4
- package/dist/parsers/codex-stream-renderer.d.ts.map +1 -1
- package/dist/parsers/codex-stream-renderer.js +110 -0
- package/dist/parsers/codex-stream-renderer.js.map +1 -1
- package/dist/prompts/amend.d.ts +0 -1
- package/dist/prompts/amend.d.ts.map +1 -1
- package/dist/prompts/amend.js +31 -104
- 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 +23 -123
- package/dist/prompts/planning.js.map +1 -1
- package/dist/types/config.d.ts +33 -32
- 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/paths.d.ts +5 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +9 -0
- package/dist/utils/paths.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 +7 -2
- package/src/commands/config.ts +60 -63
- package/src/commands/do.ts +96 -262
- package/src/commands/plan.ts +55 -279
- 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/project-manager.ts +2 -1
- package/src/core/pull-request.ts +5 -5
- 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/core/state-derivation.ts +3 -3
- package/src/parsers/codex-stream-renderer.ts +149 -4
- package/src/prompts/amend.ts +30 -105
- package/src/prompts/config-docs.md +206 -62
- package/src/prompts/execution.ts +17 -34
- package/src/prompts/planning.ts +23 -124
- package/src/types/config.ts +47 -59
- package/src/utils/config.ts +248 -115
- package/src/utils/name-generator.ts +29 -13
- package/src/utils/paths.ts +10 -0
- 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/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
|
-
import { pickPendingProject, getPendingProjects, getPendingWorktreeProjects
|
|
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 {
|
|
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,
|
|
@@ -29,7 +30,6 @@ import { TokenTracker } from '../utils/token-tracker.js';
|
|
|
29
30
|
import { VerboseToggle } from '../utils/verbose-toggle.js';
|
|
30
31
|
import {
|
|
31
32
|
deriveProjectState,
|
|
32
|
-
discoverProjects,
|
|
33
33
|
getNextExecutableTask,
|
|
34
34
|
getDerivedStats,
|
|
35
35
|
getDerivedStatsForTasks,
|
|
@@ -44,10 +44,6 @@ import {
|
|
|
44
44
|
getRepoRoot,
|
|
45
45
|
getRepoBasename,
|
|
46
46
|
getCurrentBranch,
|
|
47
|
-
computeWorktreePath,
|
|
48
|
-
computeWorktreeBaseDir,
|
|
49
|
-
validateWorktree,
|
|
50
|
-
listWorktreeProjects,
|
|
51
47
|
mergeWorktreeBranch,
|
|
52
48
|
removeWorktree,
|
|
53
49
|
resolveWorktreeProjectByIdentifier,
|
|
@@ -57,7 +53,7 @@ import {
|
|
|
57
53
|
rebaseOntoMain,
|
|
58
54
|
} from '../core/worktree.js';
|
|
59
55
|
import { createPullRequest, prPreflight } from '../core/pull-request.js';
|
|
60
|
-
import type { DoCommandOptions } from '../types/config.js';
|
|
56
|
+
import type { DoCommandOptions, ModelEntry } from '../types/config.js';
|
|
61
57
|
|
|
62
58
|
/**
|
|
63
59
|
* Post-execution action chosen by the user before task execution begins.
|
|
@@ -71,8 +67,8 @@ export type PostExecutionAction = 'merge' | 'pr' | 'leave';
|
|
|
71
67
|
* Result of resolving a task's model from frontmatter.
|
|
72
68
|
*/
|
|
73
69
|
interface TaskModelResolution {
|
|
74
|
-
/** The resolved model (after ceiling is applied). */
|
|
75
|
-
|
|
70
|
+
/** The resolved model entry (after ceiling is applied). */
|
|
71
|
+
entry: ModelEntry;
|
|
76
72
|
/** Whether a warning should be logged about missing frontmatter. */
|
|
77
73
|
missingFrontmatter: boolean;
|
|
78
74
|
/** Frontmatter parsing warnings to log. */
|
|
@@ -89,26 +85,26 @@ interface TaskModelResolution {
|
|
|
89
85
|
*
|
|
90
86
|
* @param frontmatter - Parsed frontmatter from the plan file
|
|
91
87
|
* @param frontmatterWarnings - Warnings from frontmatter parsing
|
|
92
|
-
* @param
|
|
88
|
+
* @param ceilingEntry - The ceiling model entry (usually models.execute from config)
|
|
93
89
|
* @param isRetry - Whether this is a retry attempt (escalates to ceiling)
|
|
94
90
|
*/
|
|
95
91
|
function resolveTaskModel(
|
|
96
92
|
frontmatter: PlanFrontmatter | undefined,
|
|
97
93
|
frontmatterWarnings: string[] | undefined,
|
|
98
|
-
|
|
94
|
+
ceilingEntry: ModelEntry,
|
|
99
95
|
isRetry: boolean,
|
|
100
96
|
): TaskModelResolution {
|
|
101
97
|
const warnings = frontmatterWarnings ? [...frontmatterWarnings] : [];
|
|
102
98
|
|
|
103
99
|
// Retry escalation: always use the ceiling model on retry
|
|
104
100
|
if (isRetry) {
|
|
105
|
-
return {
|
|
101
|
+
return { entry: ceilingEntry, missingFrontmatter: false, warnings };
|
|
106
102
|
}
|
|
107
103
|
|
|
108
104
|
// No frontmatter - fallback to ceiling with warning
|
|
109
105
|
if (!frontmatter) {
|
|
110
106
|
return {
|
|
111
|
-
|
|
107
|
+
entry: ceilingEntry,
|
|
112
108
|
missingFrontmatter: true,
|
|
113
109
|
warnings,
|
|
114
110
|
};
|
|
@@ -116,20 +112,25 @@ function resolveTaskModel(
|
|
|
116
112
|
|
|
117
113
|
// Explicit model in frontmatter - apply ceiling
|
|
118
114
|
if (frontmatter.model) {
|
|
119
|
-
const
|
|
120
|
-
|
|
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 };
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
// Effort-based resolution - apply ceiling
|
|
124
125
|
if (frontmatter.effort) {
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
return {
|
|
126
|
+
const mappedEntry = resolveEffortToModel(frontmatter.effort);
|
|
127
|
+
const result = applyModelCeiling(mappedEntry, ceilingEntry);
|
|
128
|
+
return { entry: result, missingFrontmatter: false, warnings };
|
|
128
129
|
}
|
|
129
130
|
|
|
130
131
|
// Frontmatter present but no effort or model - fallback to ceiling with warning
|
|
131
132
|
return {
|
|
132
|
-
|
|
133
|
+
entry: ceilingEntry,
|
|
133
134
|
missingFrontmatter: true,
|
|
134
135
|
warnings,
|
|
135
136
|
};
|
|
@@ -190,6 +191,13 @@ interface ProjectExecutionResult {
|
|
|
190
191
|
retryHistory?: TaskRetryHistory[];
|
|
191
192
|
}
|
|
192
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
|
+
|
|
193
201
|
export function createDoCommand(): Command {
|
|
194
202
|
const command = new Command('do')
|
|
195
203
|
.description('Execute planned tasks for a project')
|
|
@@ -199,11 +207,6 @@ export function createDoCommand(): Command {
|
|
|
199
207
|
.option('-v, --verbose', 'Show full LLM output')
|
|
200
208
|
.option('-d, --debug', 'Save all logs and show debug output')
|
|
201
209
|
.option('-f, --force', 'Re-run all tasks regardless of status')
|
|
202
|
-
.option('-m, --model <name>', 'Model to use (sonnet, haiku, opus)')
|
|
203
|
-
.option('--sonnet', 'Use Sonnet model (shorthand for --model sonnet)')
|
|
204
|
-
.option('-w, --worktree', 'Execute tasks in a git worktree')
|
|
205
|
-
.option('--no-worktree', 'Disable worktree mode (overrides config)')
|
|
206
|
-
.option('-p, --provider <provider>', 'CLI provider to use (claude, codex)')
|
|
207
210
|
.action(async (project: string | undefined, options: DoCommandOptions) => {
|
|
208
211
|
await runDoCommand(project, options);
|
|
209
212
|
});
|
|
@@ -214,59 +217,13 @@ export function createDoCommand(): Command {
|
|
|
214
217
|
async function runDoCommand(projectIdentifierArg: string | undefined, options: DoCommandOptions): Promise<void> {
|
|
215
218
|
const rafDir = getRafDir();
|
|
216
219
|
let projectIdentifier = projectIdentifierArg;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// Validate and resolve model option
|
|
220
|
-
let model: string;
|
|
221
|
-
try {
|
|
222
|
-
model = resolveModelOption(options.model as string | undefined, options.sonnet, 'execute');
|
|
223
|
-
} catch (error) {
|
|
224
|
-
logger.error((error as Error).message);
|
|
225
|
-
process.exit(1);
|
|
226
|
-
}
|
|
220
|
+
const executeEntry = getModel('execute');
|
|
227
221
|
|
|
228
|
-
// Variables for worktree context (
|
|
222
|
+
// Variables for worktree context (derived from where the project is found)
|
|
229
223
|
let worktreeRoot: string | undefined;
|
|
230
224
|
let originalBranch: string | undefined;
|
|
231
225
|
let mainBranchName: string | null = null;
|
|
232
226
|
|
|
233
|
-
if (worktreeMode) {
|
|
234
|
-
// Validate git repo
|
|
235
|
-
const repoRoot = getRepoRoot();
|
|
236
|
-
if (!repoRoot) {
|
|
237
|
-
logger.error('--worktree requires a git repository');
|
|
238
|
-
process.exit(1);
|
|
239
|
-
}
|
|
240
|
-
const repoBasename = getRepoBasename()!;
|
|
241
|
-
const rafRelativePath = path.relative(repoRoot, rafDir);
|
|
242
|
-
|
|
243
|
-
// Record original branch before any worktree operations
|
|
244
|
-
originalBranch = getCurrentBranch() ?? undefined;
|
|
245
|
-
|
|
246
|
-
// Sync main branch before worktree operations (if enabled)
|
|
247
|
-
if (getSyncMainBranch()) {
|
|
248
|
-
const syncResult = pullMainBranch();
|
|
249
|
-
mainBranchName = syncResult.mainBranch;
|
|
250
|
-
if (syncResult.success) {
|
|
251
|
-
if (syncResult.hadChanges) {
|
|
252
|
-
logger.info(`Synced ${syncResult.mainBranch} from remote`);
|
|
253
|
-
}
|
|
254
|
-
} else {
|
|
255
|
-
logger.warn(`Could not sync main branch: ${syncResult.error}`);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
if (!projectIdentifier) {
|
|
260
|
-
// Auto-discovery flow
|
|
261
|
-
const selected = await discoverAndPickWorktreeProject(repoBasename, rafDir, rafRelativePath);
|
|
262
|
-
if (!selected) {
|
|
263
|
-
process.exit(0);
|
|
264
|
-
}
|
|
265
|
-
worktreeRoot = selected.worktreeRoot;
|
|
266
|
-
projectIdentifier = selected.projectFolder;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
227
|
// Handle no project identifier (non-worktree mode) - show interactive picker
|
|
271
228
|
if (!projectIdentifier) {
|
|
272
229
|
// Discover worktree projects for the current repo (if in a git repo)
|
|
@@ -298,9 +255,8 @@ async function runDoCommand(projectIdentifierArg: string | undefined, options: D
|
|
|
298
255
|
// Use the selected project
|
|
299
256
|
projectIdentifier = selectedProject.folder;
|
|
300
257
|
|
|
301
|
-
// If a worktree project was selected,
|
|
258
|
+
// If a worktree project was selected, record worktree context
|
|
302
259
|
if (selectedProject.source === 'worktree' && selectedProject.worktreeRoot) {
|
|
303
|
-
worktreeMode = true;
|
|
304
260
|
worktreeRoot = selectedProject.worktreeRoot;
|
|
305
261
|
originalBranch = getCurrentBranch() ?? undefined;
|
|
306
262
|
}
|
|
@@ -316,89 +272,20 @@ async function runDoCommand(projectIdentifierArg: string | undefined, options: D
|
|
|
316
272
|
// Resolve project identifier
|
|
317
273
|
let resolvedProject: { identifier: string; path: string; name: string } | undefined;
|
|
318
274
|
|
|
319
|
-
if (
|
|
320
|
-
// Worktree
|
|
275
|
+
if (worktreeRoot) {
|
|
276
|
+
// Worktree was set by the picker — resolve project inside the worktree
|
|
321
277
|
const repoRoot = getRepoRoot()!;
|
|
322
|
-
const repoBasename = getRepoBasename()!;
|
|
323
278
|
const rafRelativePath = path.relative(repoRoot, rafDir);
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
if (
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
if (!result.path) {
|
|
330
|
-
logger.error(`Project not found in worktree: ${projectIdentifier}`);
|
|
331
|
-
process.exit(1);
|
|
332
|
-
}
|
|
333
|
-
const projectName = extractProjectName(result.path) ?? projectIdentifier;
|
|
334
|
-
resolvedProject = { identifier: projectIdentifier, path: result.path, name: projectName };
|
|
335
|
-
} else {
|
|
336
|
-
// Explicit identifier: resolve from main repo to get folder name, then validate worktree
|
|
337
|
-
const mainResult = resolveProjectIdentifierWithDetails(rafDir, projectIdentifier);
|
|
338
|
-
|
|
339
|
-
let projectFolderName: string;
|
|
340
|
-
if (mainResult.path) {
|
|
341
|
-
// Found in main repo - use its folder name
|
|
342
|
-
projectFolderName = path.basename(mainResult.path);
|
|
343
|
-
} else {
|
|
344
|
-
// Not found in main repo - try to find it in worktrees directly
|
|
345
|
-
// This handles projects that only exist in worktrees
|
|
346
|
-
const worktreeBaseDir = computeWorktreeBaseDir(repoBasename);
|
|
347
|
-
if (!fs.existsSync(worktreeBaseDir)) {
|
|
348
|
-
logger.error(`No worktree found for project "${projectIdentifier}". Did you plan with --worktree?`);
|
|
349
|
-
process.exit(1);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// Search worktrees for the project
|
|
353
|
-
const wtProjects = listWorktreeProjects(repoBasename);
|
|
354
|
-
let found = false;
|
|
355
|
-
for (const wtProjectDir of wtProjects) {
|
|
356
|
-
const wtPath = computeWorktreePath(repoBasename, wtProjectDir);
|
|
357
|
-
const wtRafDir = path.join(wtPath, rafRelativePath);
|
|
358
|
-
if (!fs.existsSync(wtRafDir)) continue;
|
|
359
|
-
|
|
360
|
-
const resolution = resolveProjectIdentifierWithDetails(wtRafDir, projectIdentifier);
|
|
361
|
-
if (resolution.path) {
|
|
362
|
-
projectFolderName = path.basename(resolution.path);
|
|
363
|
-
worktreeRoot = wtPath;
|
|
364
|
-
found = true;
|
|
365
|
-
break;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (!found) {
|
|
370
|
-
logger.error(`No worktree found for project "${projectIdentifier}". Did you plan with --worktree?`);
|
|
371
|
-
process.exit(1);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Compute worktree path if not already set
|
|
376
|
-
if (!worktreeRoot) {
|
|
377
|
-
worktreeRoot = computeWorktreePath(repoBasename, projectFolderName!);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Validate the worktree
|
|
381
|
-
const wtProjectRelPath = path.join(rafRelativePath, projectFolderName!);
|
|
382
|
-
const validation = validateWorktree(worktreeRoot, wtProjectRelPath);
|
|
383
|
-
|
|
384
|
-
if (!validation.exists || !validation.isValidWorktree) {
|
|
385
|
-
logger.error(`No worktree found for project "${projectIdentifier}". Did you plan with --worktree?`);
|
|
386
|
-
logger.error(`Expected worktree at: ${worktreeRoot}`);
|
|
387
|
-
process.exit(1);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (!validation.hasProjectFolder || !validation.hasPlans) {
|
|
391
|
-
logger.error(`Worktree exists but project content is missing.`);
|
|
392
|
-
logger.error(`Expected project folder at: ${validation.projectPath ?? path.join(worktreeRoot, wtProjectRelPath)}`);
|
|
393
|
-
process.exit(1);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
const projectPath = validation.projectPath!;
|
|
397
|
-
const projectName = extractProjectName(projectPath) ?? projectIdentifier;
|
|
398
|
-
resolvedProject = { identifier: projectIdentifier, path: projectPath, name: projectName };
|
|
279
|
+
const wtRafDir = path.join(worktreeRoot, rafRelativePath);
|
|
280
|
+
const result = resolveProjectIdentifierWithDetails(wtRafDir, projectIdentifier);
|
|
281
|
+
if (!result.path) {
|
|
282
|
+
logger.error(`Project not found in worktree: ${projectIdentifier}`);
|
|
283
|
+
process.exit(1);
|
|
399
284
|
}
|
|
285
|
+
const projectName = extractProjectName(result.path) ?? projectIdentifier;
|
|
286
|
+
resolvedProject = { identifier: projectIdentifier, path: result.path, name: projectName };
|
|
400
287
|
} else {
|
|
401
|
-
//
|
|
288
|
+
// Auto-detect: check worktrees first (worktree takes priority), then main repo
|
|
402
289
|
const repoRoot = getRepoRoot();
|
|
403
290
|
const repoBasename = repoRoot ? getRepoBasename() : null;
|
|
404
291
|
|
|
@@ -411,8 +298,6 @@ async function runDoCommand(projectIdentifierArg: string | undefined, options: D
|
|
|
411
298
|
const wtProjectPath = path.join(wtRafDir, wtResolution.folder);
|
|
412
299
|
|
|
413
300
|
if (fs.existsSync(wtProjectPath)) {
|
|
414
|
-
// Auto-switch to worktree mode
|
|
415
|
-
worktreeMode = true;
|
|
416
301
|
worktreeRoot = wtResolution.worktreeRoot;
|
|
417
302
|
originalBranch = getCurrentBranch() ?? undefined;
|
|
418
303
|
|
|
@@ -456,9 +341,26 @@ async function runDoCommand(projectIdentifierArg: string | undefined, options: D
|
|
|
456
341
|
// Configure logger
|
|
457
342
|
logger.configure({ verbose, debug });
|
|
458
343
|
|
|
459
|
-
//
|
|
344
|
+
// Worktree setup: sync main branch and show post-execution picker
|
|
460
345
|
let postAction: PostExecutionAction = 'leave';
|
|
461
|
-
if (
|
|
346
|
+
if (worktreeRoot) {
|
|
347
|
+
if (!originalBranch) {
|
|
348
|
+
originalBranch = getCurrentBranch() ?? undefined;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Sync main branch before worktree operations (if enabled)
|
|
352
|
+
if (getSyncMainBranch()) {
|
|
353
|
+
const syncResult = pullMainBranch();
|
|
354
|
+
mainBranchName = syncResult.mainBranch;
|
|
355
|
+
if (syncResult.success) {
|
|
356
|
+
if (syncResult.hadChanges) {
|
|
357
|
+
logger.info(`Synced ${syncResult.mainBranch} from remote`);
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
logger.warn(`Could not sync main branch: ${syncResult.error}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
462
364
|
try {
|
|
463
365
|
postAction = await pickPostExecutionAction(worktreeRoot);
|
|
464
366
|
} catch (error) {
|
|
@@ -498,7 +400,7 @@ async function runDoCommand(projectIdentifierArg: string | undefined, options: D
|
|
|
498
400
|
force,
|
|
499
401
|
maxRetries,
|
|
500
402
|
autoCommit,
|
|
501
|
-
|
|
403
|
+
executeEntry,
|
|
502
404
|
worktreeCwd: worktreeRoot,
|
|
503
405
|
}
|
|
504
406
|
);
|
|
@@ -509,7 +411,7 @@ async function runDoCommand(projectIdentifierArg: string | undefined, options: D
|
|
|
509
411
|
}
|
|
510
412
|
|
|
511
413
|
// Execute post-execution action based on picker choice
|
|
512
|
-
if (
|
|
414
|
+
if (worktreeRoot) {
|
|
513
415
|
const worktreeBranch = path.basename(worktreeRoot);
|
|
514
416
|
|
|
515
417
|
if (result.success) {
|
|
@@ -650,88 +552,6 @@ async function executePostAction(
|
|
|
650
552
|
}
|
|
651
553
|
}
|
|
652
554
|
|
|
653
|
-
/**
|
|
654
|
-
* Auto-discovery flow for `raf do --worktree` without a project identifier.
|
|
655
|
-
* Shows both worktree AND main-repo pending projects in an interactive picker.
|
|
656
|
-
* Worktree projects above a threshold filter are included; main-repo projects
|
|
657
|
-
* are always included. Duplicates are deduped with worktree taking precedence.
|
|
658
|
-
*
|
|
659
|
-
* @returns Selected project info or null if cancelled/no projects
|
|
660
|
-
*/
|
|
661
|
-
async function discoverAndPickWorktreeProject(
|
|
662
|
-
repoBasename: string,
|
|
663
|
-
rafDir: string,
|
|
664
|
-
rafRelativePath: string,
|
|
665
|
-
): Promise<{ worktreeRoot?: string; projectFolder: string } | null> {
|
|
666
|
-
// Get worktree pending projects (uses shared utility from project-picker)
|
|
667
|
-
const wtPendingProjects = getPendingWorktreeProjects(repoBasename, rafRelativePath);
|
|
668
|
-
|
|
669
|
-
// Find the highest-numbered completed project in the MAIN tree for threshold filter
|
|
670
|
-
const mainProjects = discoverProjects(rafDir);
|
|
671
|
-
let highestCompletedNumber = 0;
|
|
672
|
-
|
|
673
|
-
for (const project of mainProjects) {
|
|
674
|
-
const state = deriveProjectState(project.path);
|
|
675
|
-
if (isProjectComplete(state) && state.tasks.length > 0) {
|
|
676
|
-
if (project.number > highestCompletedNumber) {
|
|
677
|
-
highestCompletedNumber = project.number;
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
// Filter threshold: highest completed - 3 (or 0 if none completed)
|
|
683
|
-
const threshold = highestCompletedNumber > 3 ? highestCompletedNumber - 3 : 0;
|
|
684
|
-
|
|
685
|
-
// Apply threshold filter to worktree projects only
|
|
686
|
-
const filteredWtProjects = wtPendingProjects.filter((p) => p.number >= threshold);
|
|
687
|
-
|
|
688
|
-
// Get main-repo pending projects (no threshold filter)
|
|
689
|
-
const mainPendingProjects = getPendingProjects(rafDir);
|
|
690
|
-
|
|
691
|
-
// Merge and deduplicate: worktree versions take precedence
|
|
692
|
-
const allProjects = [...mainPendingProjects, ...filteredWtProjects];
|
|
693
|
-
const seen = new Map<string, PendingProjectInfo>();
|
|
694
|
-
for (const project of allProjects) {
|
|
695
|
-
const existing = seen.get(project.folder);
|
|
696
|
-
if (!existing || project.source === 'worktree') {
|
|
697
|
-
seen.set(project.folder, project);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
const deduped = Array.from(seen.values());
|
|
701
|
-
|
|
702
|
-
// Sort by project number
|
|
703
|
-
deduped.sort((a, b) => a.number - b.number);
|
|
704
|
-
|
|
705
|
-
if (deduped.length === 0) {
|
|
706
|
-
logger.info('No pending projects found.');
|
|
707
|
-
return null;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
// Show interactive picker
|
|
711
|
-
const choices = deduped.map((p) => ({
|
|
712
|
-
name: formatProjectChoice(p),
|
|
713
|
-
value: p,
|
|
714
|
-
}));
|
|
715
|
-
|
|
716
|
-
try {
|
|
717
|
-
const selected = await select({
|
|
718
|
-
message: 'Select a project to execute:',
|
|
719
|
-
choices,
|
|
720
|
-
});
|
|
721
|
-
|
|
722
|
-
return {
|
|
723
|
-
worktreeRoot: selected.worktreeRoot,
|
|
724
|
-
projectFolder: selected.folder,
|
|
725
|
-
};
|
|
726
|
-
} catch (error) {
|
|
727
|
-
// Handle Ctrl+C (user cancellation)
|
|
728
|
-
if (error instanceof Error && error.message.includes('User force closed')) {
|
|
729
|
-
return null;
|
|
730
|
-
}
|
|
731
|
-
throw error;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
|
|
735
555
|
interface SingleProjectOptions {
|
|
736
556
|
timeout: number;
|
|
737
557
|
verbose: boolean;
|
|
@@ -739,7 +559,8 @@ interface SingleProjectOptions {
|
|
|
739
559
|
force: boolean;
|
|
740
560
|
maxRetries: number;
|
|
741
561
|
autoCommit: boolean;
|
|
742
|
-
model
|
|
562
|
+
/** The resolved execute model entry (acts as ceiling for per-task resolution). */
|
|
563
|
+
executeEntry: ModelEntry;
|
|
743
564
|
/** Worktree root directory. When set, the runner uses cwd in the worktree. */
|
|
744
565
|
worktreeCwd?: string;
|
|
745
566
|
}
|
|
@@ -749,7 +570,7 @@ async function executeSingleProject(
|
|
|
749
570
|
projectName: string,
|
|
750
571
|
options: SingleProjectOptions
|
|
751
572
|
): Promise<ProjectExecutionResult> {
|
|
752
|
-
const { timeout, verbose, debug, force, maxRetries, autoCommit,
|
|
573
|
+
const { timeout, verbose, debug, force, maxRetries, autoCommit, executeEntry, worktreeCwd } = options;
|
|
753
574
|
|
|
754
575
|
if (!validatePlansExist(projectPath)) {
|
|
755
576
|
return {
|
|
@@ -793,8 +614,8 @@ async function executeSingleProject(
|
|
|
793
614
|
const projectManager = new ProjectManager();
|
|
794
615
|
shutdownHandler.init();
|
|
795
616
|
|
|
796
|
-
// The ceiling model for all tasks (can be overridden per-task, subject to this ceiling)
|
|
797
|
-
const
|
|
617
|
+
// The ceiling model entry for all tasks (can be overridden per-task, subject to this ceiling)
|
|
618
|
+
const ceilingEntry = executeEntry;
|
|
798
619
|
|
|
799
620
|
// Initialize token tracker for usage reporting
|
|
800
621
|
const tokenTracker = new TokenTracker();
|
|
@@ -807,8 +628,8 @@ async function executeSingleProject(
|
|
|
807
628
|
const projectStartTime = Date.now();
|
|
808
629
|
|
|
809
630
|
// Resolve and display version + ceiling model info (before any tasks run)
|
|
810
|
-
const fullCeilingModelId = resolveFullModelId(
|
|
811
|
-
logger.dim(`RAF v${getVersion()} | Ceiling: ${fullCeilingModelId}`);
|
|
631
|
+
const fullCeilingModelId = resolveFullModelId(ceilingEntry.model);
|
|
632
|
+
logger.dim(`RAF v${getVersion()} | Ceiling: ${fullCeilingModelId} (${ceilingEntry.harness})`);
|
|
812
633
|
|
|
813
634
|
if (verbose) {
|
|
814
635
|
logger.info(`Executing project: ${projectName}`);
|
|
@@ -990,6 +811,8 @@ async function executeSingleProject(
|
|
|
990
811
|
const failureHistory: Array<{ attempt: number; reason: string }> = [];
|
|
991
812
|
// Track current model for display in status line (updated in retry loop)
|
|
992
813
|
let currentModel: string | undefined;
|
|
814
|
+
let currentEffort: string | undefined;
|
|
815
|
+
let currentModelFast = false;
|
|
993
816
|
|
|
994
817
|
// Set up timer for elapsed time tracking
|
|
995
818
|
const statusLine = createStatusLine();
|
|
@@ -1000,8 +823,11 @@ async function executeSingleProject(
|
|
|
1000
823
|
return;
|
|
1001
824
|
}
|
|
1002
825
|
// Show running status with task name and timer (updates in place)
|
|
1003
|
-
const modelShortName = currentModel ?
|
|
1004
|
-
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
|
+
}));
|
|
1005
831
|
});
|
|
1006
832
|
timer.start();
|
|
1007
833
|
|
|
@@ -1020,12 +846,14 @@ async function executeSingleProject(
|
|
|
1020
846
|
const modelResolution = resolveTaskModel(
|
|
1021
847
|
task.frontmatter,
|
|
1022
848
|
undefined, // warnings already logged above
|
|
1023
|
-
|
|
849
|
+
ceilingEntry,
|
|
1024
850
|
isRetry,
|
|
1025
851
|
);
|
|
1026
852
|
|
|
1027
853
|
// Update current model for timer callback display
|
|
1028
|
-
currentModel = modelResolution.model;
|
|
854
|
+
currentModel = modelResolution.entry.model;
|
|
855
|
+
currentEffort = task.frontmatter?.effort;
|
|
856
|
+
currentModelFast = modelResolution.entry.fast === true;
|
|
1029
857
|
|
|
1030
858
|
// Log missing frontmatter warning on first attempt only
|
|
1031
859
|
if (!isRetry && modelResolution.missingFrontmatter) {
|
|
@@ -1033,14 +861,14 @@ async function executeSingleProject(
|
|
|
1033
861
|
}
|
|
1034
862
|
|
|
1035
863
|
// Create a runner for this attempt's model
|
|
1036
|
-
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 });
|
|
1037
865
|
shutdownHandler.registerClaudeRunner(taskRunner);
|
|
1038
866
|
|
|
1039
867
|
if (verbose && isRetry) {
|
|
1040
|
-
const retryModel =
|
|
868
|
+
const retryModel = formatResolvedTaskModel(modelResolution.entry);
|
|
1041
869
|
logger.info(` Retry ${attempts}/${maxRetries} for task ${taskLabel} (model: ${retryModel})...`);
|
|
1042
870
|
} else if (verbose && !isRetry) {
|
|
1043
|
-
const taskModel =
|
|
871
|
+
const taskModel = formatResolvedTaskModel(modelResolution.entry);
|
|
1044
872
|
logger.info(` Model: ${taskModel}`);
|
|
1045
873
|
}
|
|
1046
874
|
|
|
@@ -1202,8 +1030,11 @@ Task completed. No detailed report provided.
|
|
|
1202
1030
|
logger.success(` Task ${taskLabel} completed (${elapsedFormatted})`);
|
|
1203
1031
|
} else {
|
|
1204
1032
|
// Minimal mode: show completed task line
|
|
1205
|
-
const modelShortName = currentModel ?
|
|
1206
|
-
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
|
+
}));
|
|
1207
1038
|
}
|
|
1208
1039
|
|
|
1209
1040
|
// Track and display token usage for this task
|
|
@@ -1229,12 +1060,16 @@ Task completed. No detailed report provided.
|
|
|
1229
1060
|
|
|
1230
1061
|
if (verbose) {
|
|
1231
1062
|
logger.error(` Task ${taskLabel} failed: ${failureReason} (${elapsedFormatted})`);
|
|
1232
|
-
const
|
|
1063
|
+
const analysisEntry = getModel('failureAnalysis');
|
|
1064
|
+
const analysisModel = formatModelDisplay(analysisEntry.model);
|
|
1233
1065
|
logger.info(` Analyzing failure with ${analysisModel}...`);
|
|
1234
1066
|
} else {
|
|
1235
1067
|
// Minimal mode: show failed task line
|
|
1236
|
-
const modelShortName = currentModel ?
|
|
1237
|
-
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
|
+
}));
|
|
1238
1073
|
}
|
|
1239
1074
|
|
|
1240
1075
|
// Track token usage even for failed tasks (partial data still useful for totals)
|
|
@@ -1387,4 +1222,3 @@ ${stashName ? `- Stash: ${stashName}` : ''}
|
|
|
1387
1222
|
retryHistory: projectRetryHistory,
|
|
1388
1223
|
};
|
|
1389
1224
|
}
|
|
1390
|
-
|