create-quiver 0.14.1 → 0.15.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/CHANGELOG.md +16 -0
- package/README.md +4 -0
- package/README_FOR_AI.md +8 -2
- package/ROADMAP.md +8 -2
- package/docs/CLI_UX_GUIDE.md +64 -4
- package/docs/COMMANDS.md.template +7 -1
- package/docs/reference/commands.md +4 -0
- package/package.json +1 -1
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/EVIDENCE_REPORT.md +213 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/EXECUTION_PLAN.md +85 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/SPEC.md +213 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/STATUS.md +31 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/pr.md +103 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-00-spec-foundation/slice.json +71 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-01-cli-ux-runtime-progress-engine/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-01-cli-ux-runtime-progress-engine/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-01-cli-ux-runtime-progress-engine/slice.json +69 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-02-agent-profile-selection-selectors/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-02-agent-profile-selection-selectors/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-02-agent-profile-selection-selectors/slice.json +81 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-03-provider-model-selection-contract/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-03-provider-model-selection-contract/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-03-provider-model-selection-contract/slice.json +75 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-04-planner-ia-progress-flows/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-04-planner-ia-progress-flows/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-04-planner-ia-progress-flows/slice.json +85 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-05-executor-pr-progress-flows/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-05-executor-pr-progress-flows/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-05-executor-pr-progress-flows/slice.json +85 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-06-doctor-visual-json-contract/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-06-doctor-visual-json-contract/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-06-doctor-visual-json-contract/slice.json +81 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-07-interactive-init-spec-create/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-07-interactive-init-spec-create/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-07-interactive-init-spec-create/slice.json +85 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-08-tests-docs-cross-platform-release/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-08-tests-docs-cross-platform-release/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v30-interactive-cli-ux-agent-selection/slices/slice-08-tests-docs-cross-platform-release/slice.json +95 -0
- package/src/create-quiver/commands/ai.js +364 -81
- package/src/create-quiver/commands/spec.js +106 -6
- package/src/create-quiver/index.js +533 -70
- package/src/create-quiver/lib/agent-profiles.js +111 -10
- package/src/create-quiver/lib/ai/execution-plan.js +106 -8
- package/src/create-quiver/lib/ai/executor.js +284 -28
- package/src/create-quiver/lib/ai/providers.js +71 -1
- package/src/create-quiver/lib/cli/selectors.js +107 -0
- package/src/create-quiver/lib/cli/theme.js +5 -2
- package/src/create-quiver/lib/cli/ux-flags.js +18 -0
- package/src/create-quiver/lib/cli/ux.js +100 -5
|
@@ -5,7 +5,7 @@ const { assertSupportedProvider, formatProviderList } = require('./ai/providers'
|
|
|
5
5
|
const { quiverInternalPaths } = require('./init-layout');
|
|
6
6
|
|
|
7
7
|
const AGENT_PROFILE_ROLES = Object.freeze(['planner', 'executor', 'reviewer', 'doctor']);
|
|
8
|
-
const PROFILE_STATE_VERSION =
|
|
8
|
+
const PROFILE_STATE_VERSION = 2;
|
|
9
9
|
|
|
10
10
|
function formatError(message) {
|
|
11
11
|
return `create-quiver: ${message}`;
|
|
@@ -56,9 +56,46 @@ function emptyProfilesState() {
|
|
|
56
56
|
return {
|
|
57
57
|
version: PROFILE_STATE_VERSION,
|
|
58
58
|
profiles: {},
|
|
59
|
+
profile_sets: {},
|
|
59
60
|
};
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
function profileSetKey(role) {
|
|
64
|
+
return `${normalizeAgentProfileRole(role)}s`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function normalizeProfileId(value, fallback = 'default') {
|
|
68
|
+
const source = String(value || fallback || 'default').trim().toLowerCase();
|
|
69
|
+
const normalized = source
|
|
70
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
71
|
+
.replace(/^-+|-+$/g, '');
|
|
72
|
+
return normalized || 'default';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function resolveAgentProfileDisplayName(profile = {}) {
|
|
76
|
+
return profile.displayName || profile.model || profile.provider || profile.role || '';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeStoredProfile(profile, role, fallbackId = 'default') {
|
|
80
|
+
const normalizedRole = normalizeAgentProfileRole(role || profile?.role);
|
|
81
|
+
const provider = profile?.provider ? assertSupportedProvider(profile.provider) : '';
|
|
82
|
+
const normalized = {
|
|
83
|
+
id: normalizeProfileId(profile?.id || profile?.label, fallbackId),
|
|
84
|
+
role: normalizedRole,
|
|
85
|
+
provider,
|
|
86
|
+
model: normalizeOptionalText(profile?.model, 'model'),
|
|
87
|
+
label: normalizeOptionalText(profile?.label, 'label'),
|
|
88
|
+
displayName: normalizeOptionalText(profile?.displayName || profile?.display_name, 'displayName'),
|
|
89
|
+
context: normalizeOptionalText(profile?.context, 'context'),
|
|
90
|
+
default: profile?.default === true,
|
|
91
|
+
updated_at: profile?.updated_at || '',
|
|
92
|
+
};
|
|
93
|
+
if (!normalized.displayName) {
|
|
94
|
+
normalized.displayName = resolveAgentProfileDisplayName(normalized);
|
|
95
|
+
}
|
|
96
|
+
return normalized;
|
|
97
|
+
}
|
|
98
|
+
|
|
62
99
|
function readAgentProfiles(projectRoot) {
|
|
63
100
|
const filePath = agentProfilesPath(projectRoot);
|
|
64
101
|
if (!fs.existsSync(filePath)) {
|
|
@@ -69,6 +106,8 @@ function readAgentProfiles(projectRoot) {
|
|
|
69
106
|
return {
|
|
70
107
|
version: state.version || PROFILE_STATE_VERSION,
|
|
71
108
|
profiles: state.profiles && typeof state.profiles === 'object' ? state.profiles : {},
|
|
109
|
+
profile_sets: state.profile_sets && typeof state.profile_sets === 'object' ? state.profile_sets : {},
|
|
110
|
+
updated_at: state.updated_at || undefined,
|
|
72
111
|
};
|
|
73
112
|
}
|
|
74
113
|
|
|
@@ -80,18 +119,53 @@ function writeAgentProfiles(projectRoot, state) {
|
|
|
80
119
|
}
|
|
81
120
|
|
|
82
121
|
function getAgentProfile(projectRoot, role) {
|
|
122
|
+
const normalizedRole = normalizeAgentProfileRole(role);
|
|
123
|
+
const profiles = getAgentProfilesForRole(projectRoot, normalizedRole);
|
|
124
|
+
if (profiles.length === 0) return null;
|
|
125
|
+
return profiles.find((profile) => profile.default) || profiles[0];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getAgentProfileById(projectRoot, role, profileId) {
|
|
129
|
+
const normalizedRole = normalizeAgentProfileRole(role);
|
|
130
|
+
const normalizedId = normalizeProfileId(profileId);
|
|
131
|
+
return getAgentProfilesForRole(projectRoot, normalizedRole)
|
|
132
|
+
.find((profile) => profile.id === normalizedId) || null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function getAgentProfilesForRole(projectRoot, role) {
|
|
83
136
|
const normalizedRole = normalizeAgentProfileRole(role);
|
|
84
137
|
const state = readAgentProfiles(projectRoot);
|
|
85
|
-
|
|
138
|
+
const setKey = profileSetKey(normalizedRole);
|
|
139
|
+
const fromSet = Array.isArray(state.profile_sets[setKey])
|
|
140
|
+
? state.profile_sets[setKey].map((profile, index) => normalizeStoredProfile(profile, normalizedRole, index === 0 ? 'default' : `${normalizedRole}-${index + 1}`))
|
|
141
|
+
: [];
|
|
142
|
+
const legacy = state.profiles[normalizedRole]
|
|
143
|
+
? normalizeStoredProfile({ ...state.profiles[normalizedRole], default: true }, normalizedRole, 'default')
|
|
144
|
+
: null;
|
|
145
|
+
const merged = new Map();
|
|
146
|
+
|
|
147
|
+
if (legacy) merged.set(legacy.id, legacy);
|
|
148
|
+
for (const profile of fromSet) {
|
|
149
|
+
merged.set(profile.id, profile);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const profiles = Array.from(merged.values()).filter((profile) => profile.provider);
|
|
153
|
+
if (profiles.length > 0 && !profiles.some((profile) => profile.default)) {
|
|
154
|
+
profiles[0].default = true;
|
|
155
|
+
}
|
|
156
|
+
return profiles;
|
|
86
157
|
}
|
|
87
158
|
|
|
88
159
|
function listAgentProfiles(projectRoot) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
160
|
+
return AGENT_PROFILE_ROLES.map((role) => {
|
|
161
|
+
const profiles = getAgentProfilesForRole(projectRoot, role);
|
|
162
|
+
return {
|
|
163
|
+
role,
|
|
164
|
+
configured: profiles.length > 0,
|
|
165
|
+
profile: profiles.find((profile) => profile.default) || profiles[0] || null,
|
|
166
|
+
profiles,
|
|
167
|
+
};
|
|
168
|
+
});
|
|
95
169
|
}
|
|
96
170
|
|
|
97
171
|
function setAgentProfile(projectRoot, role, options = {}) {
|
|
@@ -109,23 +183,47 @@ function buildAgentProfileState(projectRoot, role, options = {}) {
|
|
|
109
183
|
const provider = assertSupportedProvider(options.provider);
|
|
110
184
|
const model = normalizeOptionalText(options.model, 'model');
|
|
111
185
|
const label = normalizeOptionalText(options.label, 'label');
|
|
186
|
+
const displayName = normalizeOptionalText(options.displayName || options.display_name, 'displayName');
|
|
112
187
|
const context = normalizeOptionalText(options.context, 'context');
|
|
113
188
|
const state = readAgentProfiles(projectRoot);
|
|
114
|
-
const
|
|
189
|
+
const currentProfiles = getAgentProfilesForRole(projectRoot, normalizedRole);
|
|
190
|
+
const currentDefault = currentProfiles.find((profile) => profile.default) || currentProfiles[0] || {};
|
|
191
|
+
const id = normalizeProfileId(options.id || currentDefault.id || label || model || provider);
|
|
192
|
+
const current = currentProfiles.find((profile) => profile.id === id) || {};
|
|
115
193
|
const now = options.now instanceof Date ? options.now.toISOString() : new Date().toISOString();
|
|
194
|
+
const shouldBeDefault = options.default === true || currentProfiles.length === 0 || (options.default !== false && current.default === true);
|
|
116
195
|
const profile = {
|
|
196
|
+
id,
|
|
117
197
|
role: normalizedRole,
|
|
118
198
|
provider,
|
|
119
199
|
model: model || current.model || '',
|
|
120
200
|
label: label || current.label || '',
|
|
201
|
+
displayName: displayName || current.displayName || model || label || provider,
|
|
121
202
|
context: context || current.context || '',
|
|
203
|
+
default: shouldBeDefault,
|
|
122
204
|
updated_at: now,
|
|
123
205
|
};
|
|
124
206
|
|
|
125
207
|
state.version = PROFILE_STATE_VERSION;
|
|
208
|
+
const setKey = profileSetKey(normalizedRole);
|
|
209
|
+
const nextProfiles = currentProfiles
|
|
210
|
+
.filter((item) => item.id !== id)
|
|
211
|
+
.map((item) => ({
|
|
212
|
+
...item,
|
|
213
|
+
default: shouldBeDefault ? false : item.default === true,
|
|
214
|
+
}))
|
|
215
|
+
.concat(profile);
|
|
216
|
+
if (!nextProfiles.some((item) => item.default)) {
|
|
217
|
+
nextProfiles[0].default = true;
|
|
218
|
+
}
|
|
219
|
+
state.profile_sets = {
|
|
220
|
+
...state.profile_sets,
|
|
221
|
+
[setKey]: nextProfiles,
|
|
222
|
+
};
|
|
223
|
+
const defaultProfile = nextProfiles.find((item) => item.default) || profile;
|
|
126
224
|
state.profiles = {
|
|
127
225
|
...state.profiles,
|
|
128
|
-
[normalizedRole]:
|
|
226
|
+
[normalizedRole]: defaultProfile,
|
|
129
227
|
};
|
|
130
228
|
state.updated_at = now;
|
|
131
229
|
|
|
@@ -149,6 +247,9 @@ module.exports = {
|
|
|
149
247
|
AGENT_PROFILE_ROLES,
|
|
150
248
|
PROFILE_STATE_VERSION,
|
|
151
249
|
agentProfilesPath,
|
|
250
|
+
getAgentProfileById,
|
|
251
|
+
getAgentProfilesForRole,
|
|
252
|
+
resolveAgentProfileDisplayName,
|
|
152
253
|
formatProviderList,
|
|
153
254
|
buildAgentProfileState,
|
|
154
255
|
getAgentProfile,
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
const fs = require('node:fs');
|
|
2
2
|
const path = require('node:path');
|
|
3
3
|
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
getAgentProfile,
|
|
6
|
+
getAgentProfileById,
|
|
7
|
+
resolveAgentProfileDisplayName,
|
|
8
|
+
resolveProfileProvider,
|
|
9
|
+
} = require('../agent-profiles');
|
|
10
|
+
const { createUx } = require('../cli/ux');
|
|
5
11
|
const { branchDelete, runGit, statusPorcelain, worktreeAdd, worktreePrune, worktreeRemove } = require('../git');
|
|
6
12
|
const { withLock } = require('../locks');
|
|
7
13
|
const { safeBranchName, worktreesRootForRepo } = require('../slice');
|
|
@@ -19,6 +25,71 @@ function toRelativePath(repoRoot, filePath) {
|
|
|
19
25
|
return path.relative(repoRoot, filePath).split(path.sep).join('/');
|
|
20
26
|
}
|
|
21
27
|
|
|
28
|
+
function resolveExecutorRuntimeProfile(repoRoot, options = {}) {
|
|
29
|
+
const explicitProvider = options.providerExplicit === true || (options.provider && options.providerExplicit !== false);
|
|
30
|
+
const explicitModel = String(options.model || '').trim();
|
|
31
|
+
|
|
32
|
+
if (explicitProvider) {
|
|
33
|
+
const provider = String(options.provider || 'codex').trim().toLowerCase();
|
|
34
|
+
return {
|
|
35
|
+
provider,
|
|
36
|
+
model: explicitModel,
|
|
37
|
+
displayName: explicitModel || provider,
|
|
38
|
+
profile: null,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const profile = options.executorProfile
|
|
43
|
+
? getAgentProfileById(repoRoot, 'executor', options.executorProfile)
|
|
44
|
+
: getAgentProfile(repoRoot, 'executor');
|
|
45
|
+
const provider = profile?.provider || resolveProfileProvider(repoRoot, options.role || 'executor', 'codex');
|
|
46
|
+
const model = explicitModel || profile?.model || '';
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
provider,
|
|
50
|
+
model,
|
|
51
|
+
displayName: profile ? resolveAgentProfileDisplayName(profile) : (model || provider),
|
|
52
|
+
profile,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function createCommandUx(options = {}) {
|
|
57
|
+
if (options.ux) {
|
|
58
|
+
return options.ux;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return createUx({
|
|
62
|
+
env: options.env || process.env,
|
|
63
|
+
interactive: options.interactive,
|
|
64
|
+
json: options.json,
|
|
65
|
+
noColor: options.noColor,
|
|
66
|
+
prompts: options.prompts,
|
|
67
|
+
spinner: options.spinner,
|
|
68
|
+
stdinIsTTY: options.stdinIsTTY,
|
|
69
|
+
stdoutIsTTY: options.stdoutIsTTY,
|
|
70
|
+
stderrIsTTY: options.stderrIsTTY,
|
|
71
|
+
write: options.write,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function shouldShowHumanProgress(ux, options = {}) {
|
|
76
|
+
return options.progress !== false
|
|
77
|
+
&& options.dryRun !== true
|
|
78
|
+
&& options.json !== true
|
|
79
|
+
&& ux?.mode?.decoration === true;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function runWithProgress({ ux, enabled, message, successMessage, failureMessage, run }) {
|
|
83
|
+
if (!enabled) {
|
|
84
|
+
return run();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return ux.withSpinner(message, run, {
|
|
88
|
+
successMessage,
|
|
89
|
+
failureMessage,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
22
93
|
function normalizeExecutionMode(mode) {
|
|
23
94
|
const value = String(mode || 'auto').trim().toLowerCase() || 'auto';
|
|
24
95
|
if (!EXECUTION_MODES.has(value)) {
|
|
@@ -316,12 +387,14 @@ function formatHumanExecutionPlan(report) {
|
|
|
316
387
|
|
|
317
388
|
function formatExecutePlanDryRun(report, options = {}) {
|
|
318
389
|
const provider = options.resolvedProvider || options.provider || 'codex';
|
|
390
|
+
const model = options.resolvedModel || options.model || '';
|
|
319
391
|
const commitEnabled = options.commit === true;
|
|
320
392
|
const executionMode = normalizeExecutionMode(options.mode || options.executionMode);
|
|
321
393
|
const lines = [
|
|
322
394
|
'AI execute-plan dry-run',
|
|
323
395
|
`Execution mode: ${executionMode}`,
|
|
324
396
|
`Provider: ${provider}`,
|
|
397
|
+
model ? `Model: ${model}` : '',
|
|
325
398
|
`Commit after each slice: ${commitEnabled ? 'enabled' : 'disabled'}`,
|
|
326
399
|
`Total slices: ${report.summary.total_slices}`,
|
|
327
400
|
'',
|
|
@@ -334,6 +407,9 @@ function formatExecutePlanDryRun(report, options = {}) {
|
|
|
334
407
|
`--slice ${JSON.stringify(slice.slice_path)}`,
|
|
335
408
|
`--provider ${provider}`,
|
|
336
409
|
];
|
|
410
|
+
if (model) {
|
|
411
|
+
parts.push(`--model ${JSON.stringify(model)}`);
|
|
412
|
+
}
|
|
337
413
|
if (commitEnabled) {
|
|
338
414
|
parts.push('--commit');
|
|
339
415
|
}
|
|
@@ -363,7 +439,7 @@ function formatExecutePlanDryRun(report, options = {}) {
|
|
|
363
439
|
}
|
|
364
440
|
}
|
|
365
441
|
|
|
366
|
-
return `${lines.join('\n')}\n`;
|
|
442
|
+
return `${lines.filter(Boolean).join('\n')}\n`;
|
|
367
443
|
}
|
|
368
444
|
|
|
369
445
|
function buildRecoveryGuidance(ref, workspaces = []) {
|
|
@@ -455,8 +531,11 @@ async function runSequentialGroup(repoRoot, level, group, options = {}) {
|
|
|
455
531
|
commit: true,
|
|
456
532
|
context: options.context,
|
|
457
533
|
dryRun: false,
|
|
534
|
+
executorProfile: options.executorProfile,
|
|
458
535
|
provider: options.provider,
|
|
459
536
|
providerExplicit: options.providerExplicit,
|
|
537
|
+
progress: false,
|
|
538
|
+
model: options.model,
|
|
460
539
|
role: options.role,
|
|
461
540
|
slice: slice.slice_path,
|
|
462
541
|
skipWorktreeBranchCheck: true,
|
|
@@ -507,8 +586,11 @@ async function runParallelGroupInWorktrees(repoRoot, level, group, options = {})
|
|
|
507
586
|
commit: true,
|
|
508
587
|
context: options.context,
|
|
509
588
|
dryRun: false,
|
|
589
|
+
executorProfile: options.executorProfile,
|
|
510
590
|
provider: options.provider,
|
|
511
591
|
providerExplicit: options.providerExplicit,
|
|
592
|
+
progress: false,
|
|
593
|
+
model: options.model,
|
|
512
594
|
role: options.role,
|
|
513
595
|
slice: workspace.slice.slice_path,
|
|
514
596
|
skipWorktreeBranchCheck: true,
|
|
@@ -557,13 +639,15 @@ async function runExecutePlan(repoRoot, options = {}) {
|
|
|
557
639
|
const report = collectExecutionPlan(repoRoot, options);
|
|
558
640
|
const execute = options.execute === true;
|
|
559
641
|
const executionMode = normalizeExecutionMode(options.mode || options.executionMode);
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
: resolveProfileProvider(repoRoot, options.role || 'executor', 'codex');
|
|
642
|
+
const runtimeProfile = resolveExecutorRuntimeProfile(repoRoot, options);
|
|
643
|
+
const provider = runtimeProfile.provider;
|
|
563
644
|
const resolvedOptions = {
|
|
564
645
|
...options,
|
|
565
646
|
mode: executionMode,
|
|
647
|
+
model: runtimeProfile.model,
|
|
566
648
|
provider,
|
|
649
|
+
profile: runtimeProfile,
|
|
650
|
+
resolvedModel: runtimeProfile.model,
|
|
567
651
|
resolvedProvider: provider,
|
|
568
652
|
};
|
|
569
653
|
|
|
@@ -586,13 +670,27 @@ async function runExecutePlan(repoRoot, options = {}) {
|
|
|
586
670
|
}
|
|
587
671
|
|
|
588
672
|
const results = [];
|
|
673
|
+
const ux = createCommandUx(options);
|
|
674
|
+
const showProgress = shouldShowHumanProgress(ux, options);
|
|
675
|
+
if (showProgress) {
|
|
676
|
+
ux.heading(`Ejecutando plan de slices con ${runtimeProfile.displayName}`);
|
|
677
|
+
ux.check(`Plan cargado: ${report.summary.total_slices} slice${report.summary.total_slices === 1 ? '' : 's'}`);
|
|
678
|
+
ux.check(`Modo: ${executionMode}`);
|
|
679
|
+
}
|
|
589
680
|
|
|
590
681
|
for (const level of report.ready_levels) {
|
|
591
682
|
for (const group of level.execution_groups) {
|
|
592
683
|
try {
|
|
593
|
-
const groupResults =
|
|
594
|
-
|
|
595
|
-
:
|
|
684
|
+
const groupResults = await runWithProgress({
|
|
685
|
+
ux,
|
|
686
|
+
enabled: showProgress,
|
|
687
|
+
message: `Ejecutando wave ${level.index}: ${group.slice_refs.join(', ')}`,
|
|
688
|
+
successMessage: `Wave ${level.index} completada`,
|
|
689
|
+
failureMessage: `Falló wave ${level.index}`,
|
|
690
|
+
run: () => (executionMode === 'delegated' && group.mode === 'parallel' && group.slice_refs.length > 1
|
|
691
|
+
? runParallelGroupInWorktrees(repoRoot, level, group, resolvedOptions)
|
|
692
|
+
: runSequentialGroup(repoRoot, level, group, resolvedOptions)),
|
|
693
|
+
});
|
|
596
694
|
results.push(...groupResults);
|
|
597
695
|
} catch (error) {
|
|
598
696
|
const wrapped = new Error(formatError(`ai execute-plan stopped at wave ${level.index} group ${group.slice_refs.join(', ')}: ${error.message || error}`));
|