create-quiver 0.14.1 → 0.15.1
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 +22 -0
- package/README.md +35 -0
- package/README_FOR_AI.md +15 -4
- package/ROADMAP.md +13 -2
- package/docs/AI_CONTEXT.md.template +4 -0
- package/docs/AI_ONBOARDING_PROMPT.md.template +8 -0
- package/docs/CLI_UX_GUIDE.md +79 -4
- package/docs/COMMANDS.md.template +21 -5
- package/docs/TROUBLESHOOTING.md +70 -0
- package/docs/TROUBLESHOOTING.md.template +20 -0
- package/docs/getting-started/installation.md +86 -0
- package/docs/reference/commands.md +33 -1
- 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/specs/quiver-v31-ai-model-catalog-agent-selection/EVIDENCE_REPORT.md +185 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/EXECUTION_PLAN.md +85 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/SPEC.md +337 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/STATUS.md +30 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/pr.md +98 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +51 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-00-spec-foundation/slice.json +62 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-01-model-catalog-alias-normalization/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-01-model-catalog-alias-normalization/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-01-model-catalog-alias-normalization/slice.json +72 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-02-interactive-agent-set-selectors/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-02-interactive-agent-set-selectors/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-02-interactive-agent-set-selectors/slice.json +78 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-03-agent-doctor-repair/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-03-agent-doctor-repair/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-03-agent-doctor-repair/slice.json +77 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-04-shared-preflight-provider-errors/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-04-shared-preflight-provider-errors/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-04-shared-preflight-provider-errors/slice.json +84 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-05-ai-models-list/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-05-ai-models-list/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-05-ai-models-list/slice.json +72 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-06-docs-templates-alignment/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-06-docs-templates-alignment/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-06-docs-templates-alignment/slice.json +84 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-07-tests-smokes-release-readiness/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-07-tests-smokes-release-readiness/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v31-ai-model-catalog-agent-selection/slices/slice-07-tests-smokes-release-readiness/slice.json +94 -0
- package/specs/quiver-v32-npx-installation-guidance/EVIDENCE_REPORT.md +26 -0
- package/specs/quiver-v32-npx-installation-guidance/SPEC.md +55 -0
- package/specs/quiver-v32-npx-installation-guidance/STATUS.md +23 -0
- package/specs/quiver-v32-npx-installation-guidance/pr.md +72 -0
- package/specs/quiver-v32-npx-installation-guidance/slices/slice-00-installation-docs/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v32-npx-installation-guidance/slices/slice-00-installation-docs/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v32-npx-installation-guidance/slices/slice-00-installation-docs/slice.json +75 -0
- package/src/create-quiver/commands/ai.js +797 -99
- package/src/create-quiver/commands/flow.js +2 -2
- package/src/create-quiver/commands/spec.js +106 -6
- package/src/create-quiver/index.js +557 -78
- package/src/create-quiver/lib/agent-profiles.js +440 -11
- package/src/create-quiver/lib/ai/execution-plan.js +111 -8
- package/src/create-quiver/lib/ai/executor.js +291 -28
- package/src/create-quiver/lib/ai/model-catalog.js +333 -0
- package/src/create-quiver/lib/ai/providers.js +211 -2
- package/src/create-quiver/lib/cli/selectors.js +160 -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
|
@@ -13,10 +13,17 @@ const {
|
|
|
13
13
|
const { buildContextPackMetadata, normalizeRole } = require('../lib/ai/context-packs');
|
|
14
14
|
const { parseContextProposalOutput } = require('../lib/ai/context-proposal');
|
|
15
15
|
const { openEditor } = require('../lib/cli/editor');
|
|
16
|
+
const { selectOption, promptText } = require('../lib/cli/selectors');
|
|
16
17
|
const { createUx } = require('../lib/cli/ux');
|
|
17
18
|
const { runExecuteSlice, runPromptSlice } = require('../lib/ai/executor');
|
|
18
19
|
const { runExecutePlan } = require('../lib/ai/execution-plan');
|
|
19
20
|
const { buildPrCreatePlan, formatPreflightReport, formatPrCreateReport, preflightGitHubPr, runGhPrCreate } = require('../lib/ai/github');
|
|
21
|
+
const {
|
|
22
|
+
MODEL_CATALOG_LAST_UPDATED,
|
|
23
|
+
MODEL_CATALOG_VERSION,
|
|
24
|
+
getKnownModelsForProvider,
|
|
25
|
+
listCatalogProviders,
|
|
26
|
+
} = require('../lib/ai/model-catalog');
|
|
20
27
|
const { buildContextPreparationDrafts, buildPlannerOnboardingPrompt } = require('../lib/ai/onboarding-template');
|
|
21
28
|
const {
|
|
22
29
|
collectLifecycleExport,
|
|
@@ -43,6 +50,7 @@ const {
|
|
|
43
50
|
validateTechnicalPlanSpecContract,
|
|
44
51
|
} = require('../lib/ai/spec-generator');
|
|
45
52
|
const { buildProviderInvocation, runProvider } = require('../lib/ai/providers');
|
|
53
|
+
const { preflightProvider } = require('../lib/ai/preflight');
|
|
46
54
|
const {
|
|
47
55
|
createAiRun,
|
|
48
56
|
ensureAiRun,
|
|
@@ -55,9 +63,15 @@ const {
|
|
|
55
63
|
} = require('../lib/ai/run-state');
|
|
56
64
|
const {
|
|
57
65
|
agentProfilesPath,
|
|
66
|
+
buildAgentProfileDoctorReport,
|
|
67
|
+
buildAgentProfileRepairPlan,
|
|
58
68
|
buildAgentProfileState,
|
|
59
69
|
getAgentProfile,
|
|
70
|
+
getAgentProfileById,
|
|
71
|
+
getAgentProfilesForRole,
|
|
60
72
|
listAgentProfiles,
|
|
73
|
+
normalizeAgentProfileRole,
|
|
74
|
+
resolveAgentProfileDisplayName,
|
|
61
75
|
resolveProfileProvider,
|
|
62
76
|
setAgentProfile,
|
|
63
77
|
} = require('../lib/agent-profiles');
|
|
@@ -122,11 +136,126 @@ function normalizeTimeout(timeoutMs) {
|
|
|
122
136
|
return parsed;
|
|
123
137
|
}
|
|
124
138
|
|
|
125
|
-
function
|
|
126
|
-
|
|
127
|
-
|
|
139
|
+
function profileOptionForRole(options, role) {
|
|
140
|
+
const normalized = normalizeAgentProfileRole(role);
|
|
141
|
+
if (normalized === 'planner') {
|
|
142
|
+
return options.plannerProfile || options.profileId || '';
|
|
143
|
+
}
|
|
144
|
+
if (normalized === 'executor') {
|
|
145
|
+
return options.executorProfile || options.profileId || '';
|
|
146
|
+
}
|
|
147
|
+
if (normalized === 'reviewer') {
|
|
148
|
+
return options.reviewerProfile || options.profileId || '';
|
|
149
|
+
}
|
|
150
|
+
if (normalized === 'doctor') {
|
|
151
|
+
return options.doctorProfile || options.profileId || '';
|
|
152
|
+
}
|
|
153
|
+
return options.profileId || '';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function resolveRuntimeAgentProfile(repoRoot, role, options = {}, fallbackProvider = DEFAULT_PLAN_PROVIDER) {
|
|
157
|
+
const normalizedRole = normalizeAgentProfileRole(role);
|
|
158
|
+
const explicitProvider = options.providerExplicit === true || (options.provider && options.providerExplicit !== false);
|
|
159
|
+
const explicitModel = String(options.model || '').trim();
|
|
160
|
+
|
|
161
|
+
if (explicitProvider) {
|
|
162
|
+
const provider = String(options.provider || fallbackProvider).trim().toLowerCase();
|
|
163
|
+
return {
|
|
164
|
+
role: normalizedRole,
|
|
165
|
+
profile: null,
|
|
166
|
+
profileId: '',
|
|
167
|
+
displayName: provider,
|
|
168
|
+
provider,
|
|
169
|
+
model: explicitModel,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const profileId = profileOptionForRole(options, normalizedRole);
|
|
174
|
+
const profile = profileId
|
|
175
|
+
? getAgentProfileById(repoRoot, normalizedRole, profileId)
|
|
176
|
+
: getAgentProfile(repoRoot, normalizedRole);
|
|
177
|
+
const provider = profile?.provider || resolveProfileProvider(repoRoot, normalizedRole, fallbackProvider);
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
role: normalizedRole,
|
|
181
|
+
profile,
|
|
182
|
+
profileId: profile?.id || profileId || '',
|
|
183
|
+
displayName: profile ? resolveAgentProfileDisplayName(profile) : provider,
|
|
184
|
+
provider,
|
|
185
|
+
model: explicitModel || profile?.model || '',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function runtimeModelExecutionOptions(runtimeProfile, options = {}) {
|
|
190
|
+
return {
|
|
191
|
+
model: runtimeProfile.model,
|
|
192
|
+
blockModelAlias: Boolean(runtimeProfile.profile && !String(options.model || '').trim()),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function createCommandUx(options = {}) {
|
|
197
|
+
if (options.ux) {
|
|
198
|
+
return options.ux;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return createUx({
|
|
202
|
+
env: options.env || process.env,
|
|
203
|
+
input: options.inputStream,
|
|
204
|
+
output: options.outputStream,
|
|
205
|
+
error: options.errorStream,
|
|
206
|
+
interactive: options.interactive,
|
|
207
|
+
json: options.json,
|
|
208
|
+
noColor: options.noColor,
|
|
209
|
+
prompts: options.prompts,
|
|
210
|
+
spinner: options.spinner,
|
|
211
|
+
stdinIsTTY: options.stdinIsTTY,
|
|
212
|
+
stdoutIsTTY: options.stdoutIsTTY,
|
|
213
|
+
stderrIsTTY: options.stderrIsTTY,
|
|
214
|
+
write: options.write,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function shouldShowHumanProgress(ux, options = {}) {
|
|
219
|
+
return options.progress !== false
|
|
220
|
+
&& options.dryRun !== true
|
|
221
|
+
&& options.printPrompt !== true
|
|
222
|
+
&& ux?.mode?.decoration === true;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function plannerProgressTitle(action, runtimeProfile) {
|
|
226
|
+
return `${action} con ${runtimeProfile.displayName || runtimeProfile.model || runtimeProfile.provider}`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function writeProgressChecks(ux, enabled, title, checks = []) {
|
|
230
|
+
if (!enabled) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
ux.heading(title);
|
|
234
|
+
for (const check of checks) {
|
|
235
|
+
ux.check(check);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function runProviderWithProgress({ ux, enabled, message = 'Ejecutando agente...', successMessage = 'Agente finalizado', failureMessage = 'Fallo ejecutando agente', run }) {
|
|
240
|
+
async function runAndFailOnProviderResult() {
|
|
241
|
+
const result = await run();
|
|
242
|
+
if (result && result.ok === false) {
|
|
243
|
+
const error = new Error(result.error?.message || 'provider run failed');
|
|
244
|
+
error.code = result.error?.code || 'AI_PROVIDER_RUN_FAILED';
|
|
245
|
+
error.providerResult = result;
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!enabled) {
|
|
252
|
+
return run();
|
|
128
253
|
}
|
|
129
|
-
|
|
254
|
+
|
|
255
|
+
return ux.withSpinner(message, runAndFailOnProviderResult, {
|
|
256
|
+
successMessage,
|
|
257
|
+
failureMessage,
|
|
258
|
+
});
|
|
130
259
|
}
|
|
131
260
|
|
|
132
261
|
function buildPlanContext({ role, context, phase, inputText, inputPath, repoRoot, revise = false }) {
|
|
@@ -210,6 +339,10 @@ function formatDryRunReport({ task, provider, role, contextPack, phase, invocati
|
|
|
210
339
|
lines.push(`Timeout: ${invocation.timeoutMs}ms`);
|
|
211
340
|
lines.push(`Prompt transport: ${invocation.promptTransport.mode}`);
|
|
212
341
|
lines.push(`Prompt length: ${invocation.promptLength} bytes`);
|
|
342
|
+
if (invocation.modelSelection && invocation.modelSelection.model) {
|
|
343
|
+
lines.push(`Model: ${invocation.modelSelection.model}`);
|
|
344
|
+
lines.push(`Model support: ${invocation.modelSelection.supported ? 'supported' : 'unsupported'} (${invocation.modelSelection.reason})`);
|
|
345
|
+
}
|
|
213
346
|
|
|
214
347
|
if (onboardingPlan) {
|
|
215
348
|
lines.push(`Prompt source: ${onboardingPlan.promptSource}`);
|
|
@@ -236,6 +369,10 @@ function formatPromptOnlyReport({ task, provider, role, contextPack, phase, invo
|
|
|
236
369
|
lines.push(`Timeout: ${invocation.timeoutMs}ms`);
|
|
237
370
|
lines.push(`Prompt transport: ${invocation.promptTransport.mode}`);
|
|
238
371
|
lines.push(`Prompt length: ${invocation.promptLength} bytes`);
|
|
372
|
+
if (invocation.modelSelection && invocation.modelSelection.model) {
|
|
373
|
+
lines.push(`Model: ${invocation.modelSelection.model}`);
|
|
374
|
+
lines.push(`Model support: ${invocation.modelSelection.supported ? 'supported' : 'unsupported'} (${invocation.modelSelection.reason})`);
|
|
375
|
+
}
|
|
239
376
|
|
|
240
377
|
if (onboardingPlan) {
|
|
241
378
|
lines.push(`Prompt source: ${onboardingPlan.promptSource}`);
|
|
@@ -407,6 +544,12 @@ function formatPrepareContextPlannerDryRunReport({ provider, role, context, invo
|
|
|
407
544
|
`Context pack: ${context}`,
|
|
408
545
|
`Command: ${invocation.command} ${invocation.args.join(' ')}`.trim(),
|
|
409
546
|
`Prompt bytes: ${invocation.promptLength}`,
|
|
547
|
+
invocation.modelSelection && invocation.modelSelection.model
|
|
548
|
+
? `Model: ${invocation.modelSelection.model}`
|
|
549
|
+
: '',
|
|
550
|
+
invocation.modelSelection && invocation.modelSelection.model
|
|
551
|
+
? `Model support: ${invocation.modelSelection.supported ? 'supported' : 'unsupported'} (${invocation.modelSelection.reason})`
|
|
552
|
+
: '',
|
|
410
553
|
`Prompt source: ${promptInfo.promptSource}`,
|
|
411
554
|
`Review requested: ${review ? 'yes' : 'no'}`,
|
|
412
555
|
`Interactive requested: ${interactive ? 'yes' : 'no'}`,
|
|
@@ -424,7 +567,7 @@ function formatPrepareContextPlannerDryRunReport({ provider, role, context, invo
|
|
|
424
567
|
'- npx create-quiver ai prepare-context --with-planner',
|
|
425
568
|
];
|
|
426
569
|
|
|
427
|
-
return `${lines.join('\n')}\n`;
|
|
570
|
+
return `${lines.filter(Boolean).join('\n')}\n`;
|
|
428
571
|
}
|
|
429
572
|
|
|
430
573
|
function serializeProposalForReview(proposal) {
|
|
@@ -1108,7 +1251,8 @@ function annotateGitHubError(error, scope) {
|
|
|
1108
1251
|
|
|
1109
1252
|
async function runOnboard(repoRoot, options = {}) {
|
|
1110
1253
|
const role = normalizeRole(options.role || DEFAULT_ONBOARD_ROLE);
|
|
1111
|
-
const
|
|
1254
|
+
const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_ONBOARD_PROVIDER);
|
|
1255
|
+
const provider = runtimeProfile.provider;
|
|
1112
1256
|
const context = options.context || DEFAULT_ONBOARD_CONTEXT;
|
|
1113
1257
|
const timeoutMs = normalizeTimeout(options.timeout);
|
|
1114
1258
|
const inputText = readTextFile(options.input, repoRoot);
|
|
@@ -1121,9 +1265,15 @@ async function runOnboard(repoRoot, options = {}) {
|
|
|
1121
1265
|
prompt,
|
|
1122
1266
|
cwd: repoRoot,
|
|
1123
1267
|
timeoutMs,
|
|
1268
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1269
|
+
enforceModelSelection: false,
|
|
1124
1270
|
});
|
|
1125
1271
|
} catch (error) {
|
|
1126
|
-
|
|
1272
|
+
if (error.providerResult) {
|
|
1273
|
+
result = error.providerResult;
|
|
1274
|
+
} else {
|
|
1275
|
+
throw annotateProviderError(error, 'onboard');
|
|
1276
|
+
}
|
|
1127
1277
|
}
|
|
1128
1278
|
|
|
1129
1279
|
if (options.dryRun) {
|
|
@@ -1134,6 +1284,7 @@ async function runOnboard(repoRoot, options = {}) {
|
|
|
1134
1284
|
contextPack: context,
|
|
1135
1285
|
invocation,
|
|
1136
1286
|
onboardingPlan: contextInfo.plan,
|
|
1287
|
+
profile: runtimeProfile,
|
|
1137
1288
|
};
|
|
1138
1289
|
process.stdout.write(formatDryRunReport(report));
|
|
1139
1290
|
return report;
|
|
@@ -1148,23 +1299,39 @@ async function runOnboard(repoRoot, options = {}) {
|
|
|
1148
1299
|
invocation,
|
|
1149
1300
|
onboardingPlan: contextInfo.plan,
|
|
1150
1301
|
prompt,
|
|
1302
|
+
profile: runtimeProfile,
|
|
1151
1303
|
};
|
|
1152
1304
|
process.stdout.write(formatPromptOnlyReport(report));
|
|
1153
1305
|
return report;
|
|
1154
1306
|
}
|
|
1155
1307
|
|
|
1308
|
+
const ux = createCommandUx(options);
|
|
1309
|
+
const showProgress = shouldShowHumanProgress(ux, options);
|
|
1310
|
+
writeProgressChecks(
|
|
1311
|
+
ux,
|
|
1312
|
+
showProgress,
|
|
1313
|
+
plannerProgressTitle('Ejecutando onboarding', runtimeProfile),
|
|
1314
|
+
['Leyendo docs base', 'Detectando estructura', 'Preparando prompt'],
|
|
1315
|
+
);
|
|
1316
|
+
|
|
1156
1317
|
let result;
|
|
1157
1318
|
try {
|
|
1158
|
-
result = await (
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1319
|
+
result = await runProviderWithProgress({
|
|
1320
|
+
ux,
|
|
1321
|
+
enabled: showProgress,
|
|
1322
|
+
run: () => (options.runProviderFn || runProvider)(provider, {
|
|
1323
|
+
prompt,
|
|
1324
|
+
cwd: repoRoot,
|
|
1325
|
+
timeoutMs,
|
|
1326
|
+
dryRun: false,
|
|
1327
|
+
probe: options.probe,
|
|
1328
|
+
spawn: options.spawn,
|
|
1329
|
+
tempRoot: options.tempRoot,
|
|
1330
|
+
tempFileName: options.tempFileName,
|
|
1331
|
+
tempFilePrefix: options.tempFilePrefix,
|
|
1332
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1333
|
+
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
1334
|
+
}),
|
|
1168
1335
|
});
|
|
1169
1336
|
} catch (error) {
|
|
1170
1337
|
throw annotateProviderError(error, 'onboard');
|
|
@@ -1185,6 +1352,7 @@ async function runOnboard(repoRoot, options = {}) {
|
|
|
1185
1352
|
contextPack: context,
|
|
1186
1353
|
invocation,
|
|
1187
1354
|
onboardingPlan: contextInfo.plan,
|
|
1355
|
+
profile: runtimeProfile,
|
|
1188
1356
|
result,
|
|
1189
1357
|
};
|
|
1190
1358
|
}
|
|
@@ -1257,7 +1425,8 @@ async function runPrepareContext(repoRoot, options = {}) {
|
|
|
1257
1425
|
|
|
1258
1426
|
async function runPrepareContextWithPlanner(repoRoot, options = {}) {
|
|
1259
1427
|
const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
|
|
1260
|
-
const
|
|
1428
|
+
const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_PLAN_PROVIDER);
|
|
1429
|
+
const provider = runtimeProfile.provider;
|
|
1261
1430
|
const context = options.context || DEFAULT_PLAN_CONTEXT;
|
|
1262
1431
|
const timeoutMs = normalizeTimeout(options.timeout);
|
|
1263
1432
|
const draftPack = buildContextPreparationDrafts(repoRoot);
|
|
@@ -1276,9 +1445,15 @@ async function runPrepareContextWithPlanner(repoRoot, options = {}) {
|
|
|
1276
1445
|
prompt,
|
|
1277
1446
|
cwd: repoRoot,
|
|
1278
1447
|
timeoutMs,
|
|
1448
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1449
|
+
enforceModelSelection: false,
|
|
1279
1450
|
});
|
|
1280
1451
|
} catch (error) {
|
|
1281
|
-
|
|
1452
|
+
if (error.providerResult) {
|
|
1453
|
+
result = error.providerResult;
|
|
1454
|
+
} else {
|
|
1455
|
+
throw annotateProviderError(error, 'prepare-context');
|
|
1456
|
+
}
|
|
1282
1457
|
}
|
|
1283
1458
|
|
|
1284
1459
|
if (options.dryRun) {
|
|
@@ -1292,6 +1467,7 @@ async function runPrepareContextWithPlanner(repoRoot, options = {}) {
|
|
|
1292
1467
|
invocation,
|
|
1293
1468
|
candidateDocs: promptInfo.allowedPaths,
|
|
1294
1469
|
plan: draftPack.plan,
|
|
1470
|
+
profile: runtimeProfile,
|
|
1295
1471
|
};
|
|
1296
1472
|
process.stdout.write(formatPrepareContextPlannerDryRunReport({
|
|
1297
1473
|
provider,
|
|
@@ -1314,23 +1490,39 @@ async function runPrepareContextWithPlanner(repoRoot, options = {}) {
|
|
|
1314
1490
|
invocation,
|
|
1315
1491
|
prompt,
|
|
1316
1492
|
promptSource: promptInfo.promptSource,
|
|
1493
|
+
profile: runtimeProfile,
|
|
1317
1494
|
};
|
|
1318
1495
|
process.stdout.write(formatPromptOnlyReport(report));
|
|
1319
1496
|
return report;
|
|
1320
1497
|
}
|
|
1321
1498
|
|
|
1499
|
+
const ux = createCommandUx(options);
|
|
1500
|
+
const showProgress = shouldShowHumanProgress(ux, options);
|
|
1501
|
+
writeProgressChecks(
|
|
1502
|
+
ux,
|
|
1503
|
+
showProgress,
|
|
1504
|
+
plannerProgressTitle('Ejecutando onboarding', runtimeProfile),
|
|
1505
|
+
['Leyendo docs base', 'Detectando estructura', 'Preparando prompt'],
|
|
1506
|
+
);
|
|
1507
|
+
|
|
1322
1508
|
let result;
|
|
1323
1509
|
try {
|
|
1324
|
-
result = await (
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1510
|
+
result = await runProviderWithProgress({
|
|
1511
|
+
ux,
|
|
1512
|
+
enabled: showProgress,
|
|
1513
|
+
run: () => (options.runProviderFn || runProvider)(provider, {
|
|
1514
|
+
prompt,
|
|
1515
|
+
cwd: repoRoot,
|
|
1516
|
+
timeoutMs,
|
|
1517
|
+
dryRun: false,
|
|
1518
|
+
probe: options.probe,
|
|
1519
|
+
spawn: options.spawn,
|
|
1520
|
+
tempRoot: options.tempRoot,
|
|
1521
|
+
tempFileName: options.tempFileName,
|
|
1522
|
+
tempFilePrefix: options.tempFilePrefix,
|
|
1523
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1524
|
+
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
1525
|
+
}),
|
|
1334
1526
|
});
|
|
1335
1527
|
} catch (error) {
|
|
1336
1528
|
throw annotateProviderError(error, 'prepare-context');
|
|
@@ -1404,7 +1596,8 @@ async function runPrepareContextWithPlanner(repoRoot, options = {}) {
|
|
|
1404
1596
|
async function runPlan(repoRoot, options = {}) {
|
|
1405
1597
|
const phase = normalizePlannerPhase(options.phase || DEFAULT_PLAN_PHASE);
|
|
1406
1598
|
const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
|
|
1407
|
-
const
|
|
1599
|
+
const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_PLAN_PROVIDER);
|
|
1600
|
+
const provider = runtimeProfile.provider;
|
|
1408
1601
|
const context = options.context || DEFAULT_PLAN_CONTEXT;
|
|
1409
1602
|
const timeoutMs = normalizeTimeout(options.timeout);
|
|
1410
1603
|
let inputPath = options.input || '';
|
|
@@ -1506,9 +1699,15 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
1506
1699
|
prompt,
|
|
1507
1700
|
cwd: repoRoot,
|
|
1508
1701
|
timeoutMs,
|
|
1702
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1703
|
+
enforceModelSelection: false,
|
|
1509
1704
|
});
|
|
1510
1705
|
} catch (error) {
|
|
1511
|
-
|
|
1706
|
+
if (error.providerResult) {
|
|
1707
|
+
result = error.providerResult;
|
|
1708
|
+
} else {
|
|
1709
|
+
throw annotateProviderError(error, 'plan', phase);
|
|
1710
|
+
}
|
|
1512
1711
|
}
|
|
1513
1712
|
|
|
1514
1713
|
if (options.dryRun) {
|
|
@@ -1519,6 +1718,7 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
1519
1718
|
contextPack: contextInfo.pack.packName,
|
|
1520
1719
|
phase,
|
|
1521
1720
|
invocation,
|
|
1721
|
+
profile: runtimeProfile,
|
|
1522
1722
|
};
|
|
1523
1723
|
process.stdout.write(formatDryRunReport(report));
|
|
1524
1724
|
if (options.withPlanner === true) {
|
|
@@ -1542,23 +1742,39 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
1542
1742
|
phase,
|
|
1543
1743
|
invocation,
|
|
1544
1744
|
prompt,
|
|
1745
|
+
profile: runtimeProfile,
|
|
1545
1746
|
};
|
|
1546
1747
|
process.stdout.write(formatPromptOnlyReport(report));
|
|
1547
1748
|
return report;
|
|
1548
1749
|
}
|
|
1549
1750
|
|
|
1751
|
+
const ux = createCommandUx(options);
|
|
1752
|
+
const showProgress = shouldShowHumanProgress(ux, options);
|
|
1753
|
+
writeProgressChecks(
|
|
1754
|
+
ux,
|
|
1755
|
+
showProgress,
|
|
1756
|
+
plannerProgressTitle(`Ejecutando plan ${phase}`, runtimeProfile),
|
|
1757
|
+
['Leyendo entrada', 'Preparando contexto', 'Preparando prompt'],
|
|
1758
|
+
);
|
|
1759
|
+
|
|
1550
1760
|
let result;
|
|
1551
1761
|
try {
|
|
1552
|
-
result = await (
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1762
|
+
result = await runProviderWithProgress({
|
|
1763
|
+
ux,
|
|
1764
|
+
enabled: showProgress,
|
|
1765
|
+
run: () => (options.runProviderFn || runProvider)(provider, {
|
|
1766
|
+
prompt,
|
|
1767
|
+
cwd: repoRoot,
|
|
1768
|
+
timeoutMs,
|
|
1769
|
+
dryRun: false,
|
|
1770
|
+
probe: options.probe,
|
|
1771
|
+
spawn: options.spawn,
|
|
1772
|
+
tempRoot: options.tempRoot,
|
|
1773
|
+
tempFileName: options.tempFileName,
|
|
1774
|
+
tempFilePrefix: options.tempFilePrefix,
|
|
1775
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1776
|
+
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
1777
|
+
}),
|
|
1562
1778
|
});
|
|
1563
1779
|
} catch (error) {
|
|
1564
1780
|
throw annotateProviderError(error, 'plan', phase);
|
|
@@ -1625,7 +1841,8 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
1625
1841
|
|
|
1626
1842
|
async function runReviewPlan(repoRoot, options = {}) {
|
|
1627
1843
|
const role = 'planner';
|
|
1628
|
-
const
|
|
1844
|
+
const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, 'reviewer', options, DEFAULT_PLAN_PROVIDER);
|
|
1845
|
+
const provider = runtimeProfile.provider;
|
|
1629
1846
|
const context = options.context || DEFAULT_PLAN_CONTEXT;
|
|
1630
1847
|
const timeoutMs = normalizeTimeout(options.timeout);
|
|
1631
1848
|
const resolved = resolveTechnicalPlanReviewInput(repoRoot, options.input || undefined);
|
|
@@ -1649,9 +1866,15 @@ async function runReviewPlan(repoRoot, options = {}) {
|
|
|
1649
1866
|
prompt: built.prompt,
|
|
1650
1867
|
cwd: repoRoot,
|
|
1651
1868
|
timeoutMs,
|
|
1869
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1870
|
+
enforceModelSelection: false,
|
|
1652
1871
|
});
|
|
1653
1872
|
} catch (error) {
|
|
1654
|
-
|
|
1873
|
+
if (error.providerResult) {
|
|
1874
|
+
result = error.providerResult;
|
|
1875
|
+
} else {
|
|
1876
|
+
throw annotateProviderError(error, 'review-plan');
|
|
1877
|
+
}
|
|
1655
1878
|
}
|
|
1656
1879
|
|
|
1657
1880
|
if (options.dryRun) {
|
|
@@ -1665,6 +1888,7 @@ async function runReviewPlan(repoRoot, options = {}) {
|
|
|
1665
1888
|
inputPath,
|
|
1666
1889
|
inputKind: resolved.kind,
|
|
1667
1890
|
inputVersion: resolved.version,
|
|
1891
|
+
profile: runtimeProfile,
|
|
1668
1892
|
};
|
|
1669
1893
|
process.stdout.write(formatDryRunReport({
|
|
1670
1894
|
task: 'review-plan',
|
|
@@ -1696,23 +1920,39 @@ async function runReviewPlan(repoRoot, options = {}) {
|
|
|
1696
1920
|
inputPath,
|
|
1697
1921
|
inputKind: resolved.kind,
|
|
1698
1922
|
inputVersion: resolved.version,
|
|
1923
|
+
profile: runtimeProfile,
|
|
1699
1924
|
};
|
|
1700
1925
|
process.stdout.write(formatPromptOnlyReport(report));
|
|
1701
1926
|
return report;
|
|
1702
1927
|
}
|
|
1703
1928
|
|
|
1929
|
+
const ux = createCommandUx(options);
|
|
1930
|
+
const showProgress = shouldShowHumanProgress(ux, options);
|
|
1931
|
+
writeProgressChecks(
|
|
1932
|
+
ux,
|
|
1933
|
+
showProgress,
|
|
1934
|
+
plannerProgressTitle('Ejecutando revisión del plan', runtimeProfile),
|
|
1935
|
+
['Leyendo plan técnico', 'Preparando contexto', 'Preparando prompt'],
|
|
1936
|
+
);
|
|
1937
|
+
|
|
1704
1938
|
let result;
|
|
1705
1939
|
try {
|
|
1706
|
-
result = await (
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1940
|
+
result = await runProviderWithProgress({
|
|
1941
|
+
ux,
|
|
1942
|
+
enabled: showProgress,
|
|
1943
|
+
run: () => (options.runProviderFn || runProvider)(provider, {
|
|
1944
|
+
prompt: built.prompt,
|
|
1945
|
+
cwd: repoRoot,
|
|
1946
|
+
timeoutMs,
|
|
1947
|
+
dryRun: false,
|
|
1948
|
+
probe: options.probe,
|
|
1949
|
+
spawn: options.spawn,
|
|
1950
|
+
tempRoot: options.tempRoot,
|
|
1951
|
+
tempFileName: options.tempFileName,
|
|
1952
|
+
tempFilePrefix: options.tempFilePrefix,
|
|
1953
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1954
|
+
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
1955
|
+
}),
|
|
1716
1956
|
});
|
|
1717
1957
|
} catch (error) {
|
|
1718
1958
|
throw annotateProviderError(error, 'review-plan');
|
|
@@ -1770,7 +2010,8 @@ async function runReviewPlan(repoRoot, options = {}) {
|
|
|
1770
2010
|
|
|
1771
2011
|
async function runRepairPlan(repoRoot, options = {}) {
|
|
1772
2012
|
const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
|
|
1773
|
-
const
|
|
2013
|
+
const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_PLAN_PROVIDER);
|
|
2014
|
+
const provider = runtimeProfile.provider;
|
|
1774
2015
|
const context = options.context || DEFAULT_PLAN_CONTEXT;
|
|
1775
2016
|
const timeoutMs = normalizeTimeout(options.timeout);
|
|
1776
2017
|
const source = resolveApprovedTechnicalPlanForRepair(repoRoot, options.input || '');
|
|
@@ -1790,9 +2031,15 @@ async function runRepairPlan(repoRoot, options = {}) {
|
|
|
1790
2031
|
prompt: built.prompt,
|
|
1791
2032
|
cwd: repoRoot,
|
|
1792
2033
|
timeoutMs,
|
|
2034
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
2035
|
+
enforceModelSelection: false,
|
|
1793
2036
|
});
|
|
1794
2037
|
} catch (error) {
|
|
1795
|
-
|
|
2038
|
+
if (error.providerResult) {
|
|
2039
|
+
providerResult = error.providerResult;
|
|
2040
|
+
} else {
|
|
2041
|
+
throw annotateProviderError(error, 'repair-plan');
|
|
2042
|
+
}
|
|
1796
2043
|
}
|
|
1797
2044
|
|
|
1798
2045
|
if (options.dryRun) {
|
|
@@ -1803,6 +2050,7 @@ async function runRepairPlan(repoRoot, options = {}) {
|
|
|
1803
2050
|
contextPack: built.pack.packName,
|
|
1804
2051
|
phase: 'technical-plan',
|
|
1805
2052
|
invocation,
|
|
2053
|
+
profile: runtimeProfile,
|
|
1806
2054
|
};
|
|
1807
2055
|
process.stdout.write(formatDryRunReport(report));
|
|
1808
2056
|
process.stdout.write(`Source approved artifact: ${source.path}\n`);
|
|
@@ -1822,23 +2070,39 @@ async function runRepairPlan(repoRoot, options = {}) {
|
|
|
1822
2070
|
inputPath: source.path,
|
|
1823
2071
|
inputKind: 'approved',
|
|
1824
2072
|
inputVersion: source.approval.meta?.approved?.version || null,
|
|
2073
|
+
profile: runtimeProfile,
|
|
1825
2074
|
};
|
|
1826
2075
|
process.stdout.write(formatPromptOnlyReport(report));
|
|
1827
2076
|
return report;
|
|
1828
2077
|
}
|
|
1829
2078
|
|
|
2079
|
+
const ux = createCommandUx(options);
|
|
2080
|
+
const showProgress = shouldShowHumanProgress(ux, options);
|
|
2081
|
+
writeProgressChecks(
|
|
2082
|
+
ux,
|
|
2083
|
+
showProgress,
|
|
2084
|
+
plannerProgressTitle('Ejecutando reparación del plan', runtimeProfile),
|
|
2085
|
+
['Leyendo plan aprobado', 'Preparando contexto', 'Preparando prompt'],
|
|
2086
|
+
);
|
|
2087
|
+
|
|
1830
2088
|
let providerResult;
|
|
1831
2089
|
try {
|
|
1832
|
-
providerResult = await (
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
2090
|
+
providerResult = await runProviderWithProgress({
|
|
2091
|
+
ux,
|
|
2092
|
+
enabled: showProgress,
|
|
2093
|
+
run: () => (options.runProviderFn || runProvider)(provider, {
|
|
2094
|
+
prompt: built.prompt,
|
|
2095
|
+
cwd: repoRoot,
|
|
2096
|
+
timeoutMs,
|
|
2097
|
+
dryRun: false,
|
|
2098
|
+
probe: options.probe,
|
|
2099
|
+
spawn: options.spawn,
|
|
2100
|
+
tempRoot: options.tempRoot,
|
|
2101
|
+
tempFileName: options.tempFileName,
|
|
2102
|
+
tempFilePrefix: options.tempFilePrefix,
|
|
2103
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
2104
|
+
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
2105
|
+
}),
|
|
1842
2106
|
});
|
|
1843
2107
|
} catch (error) {
|
|
1844
2108
|
throw annotateProviderError(error, 'repair-plan');
|
|
@@ -2172,12 +2436,221 @@ function runLifecycleRun(repoRoot, options = {}) {
|
|
|
2172
2436
|
};
|
|
2173
2437
|
}
|
|
2174
2438
|
|
|
2439
|
+
function isInteractiveAgentPromptAvailable(options = {}) {
|
|
2440
|
+
const stdinIsTTY = options.stdinIsTTY ?? Boolean((options.input || process.stdin).isTTY);
|
|
2441
|
+
const stdoutIsTTY = options.stdoutIsTTY ?? Boolean((options.output || process.stdout).isTTY);
|
|
2442
|
+
const ci = String((options.env || process.env).CI || '').trim().toLowerCase();
|
|
2443
|
+
return stdinIsTTY && stdoutIsTTY && ci !== '1' && ci !== 'true';
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
function providerInstallHint(repoRoot, providerId, options = {}) {
|
|
2447
|
+
const probe = options.preflightProvider || preflightProvider;
|
|
2448
|
+
try {
|
|
2449
|
+
probe(providerId, {
|
|
2450
|
+
cwd: repoRoot,
|
|
2451
|
+
probe: options.providerProbe,
|
|
2452
|
+
probeArgs: options.providerProbeArgs,
|
|
2453
|
+
});
|
|
2454
|
+
return 'installed';
|
|
2455
|
+
} catch (error) {
|
|
2456
|
+
if (error && error.code === 'MISSING_PROVIDER_CLI') {
|
|
2457
|
+
return 'not installed';
|
|
2458
|
+
}
|
|
2459
|
+
return 'not verified';
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2462
|
+
|
|
2463
|
+
function buildAgentProviderChoices(repoRoot, options = {}) {
|
|
2464
|
+
return listCatalogProviders().map((provider) => {
|
|
2465
|
+
const status = providerInstallHint(repoRoot, provider.id, options);
|
|
2466
|
+
return {
|
|
2467
|
+
label: provider.displayName,
|
|
2468
|
+
value: provider.id,
|
|
2469
|
+
hint: `${provider.modelCount} models, ${status}`,
|
|
2470
|
+
raw: {
|
|
2471
|
+
...provider,
|
|
2472
|
+
installStatus: status,
|
|
2473
|
+
},
|
|
2474
|
+
};
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
function buildAgentModelChoices(provider, role) {
|
|
2479
|
+
return getKnownModelsForProvider(provider, { role }).map((model) => {
|
|
2480
|
+
const recommended = model.recommendedFor.includes(role) ? 'recommended' : 'available';
|
|
2481
|
+
const tier = [model.costTier, model.qualityTier, model.stability].filter(Boolean).join('/');
|
|
2482
|
+
return {
|
|
2483
|
+
label: model.displayName,
|
|
2484
|
+
value: model.id,
|
|
2485
|
+
hint: [recommended, tier].filter(Boolean).join(', '),
|
|
2486
|
+
default: model.recommendedFor.includes(role),
|
|
2487
|
+
raw: model,
|
|
2488
|
+
};
|
|
2489
|
+
});
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
async function resolveInteractiveAgentSetOptions(repoRoot, options = {}) {
|
|
2493
|
+
const role = normalizeAgentProfileRole(options.role);
|
|
2494
|
+
const hasProvider = Boolean(String(options.provider || '').trim());
|
|
2495
|
+
const hasModel = Boolean(String(options.model || '').trim());
|
|
2496
|
+
if (hasProvider && hasModel) {
|
|
2497
|
+
return {
|
|
2498
|
+
...options,
|
|
2499
|
+
role,
|
|
2500
|
+
};
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
const canPrompt = isInteractiveAgentPromptAvailable(options);
|
|
2504
|
+
const shouldPrompt = options.interactive === true || canPrompt;
|
|
2505
|
+
if (!shouldPrompt || !canPrompt) {
|
|
2506
|
+
throw new Error(formatActionableError({
|
|
2507
|
+
failure: `ai agent set ${role} requires --provider and --model when prompts are not available.`,
|
|
2508
|
+
impact: 'Quiver cannot safely guess the provider or technical model id for an agent profile.',
|
|
2509
|
+
fix: 'Pass both flags explicitly, or rerun from an interactive terminal with --interactive.',
|
|
2510
|
+
nextCommand: `npx create-quiver ai agent set ${role} --provider codex --model gpt-5.5`,
|
|
2511
|
+
}));
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
const promptOptions = {
|
|
2515
|
+
env: options.env,
|
|
2516
|
+
error: options.error,
|
|
2517
|
+
input: options.input,
|
|
2518
|
+
interactive: true,
|
|
2519
|
+
noColor: options.noColor,
|
|
2520
|
+
output: options.output,
|
|
2521
|
+
prompts: options.prompts,
|
|
2522
|
+
promptSelect: options.promptSelect,
|
|
2523
|
+
promptText: options.promptText,
|
|
2524
|
+
stdinIsTTY: options.stdinIsTTY,
|
|
2525
|
+
stdoutIsTTY: options.stdoutIsTTY,
|
|
2526
|
+
stderrIsTTY: options.stderrIsTTY,
|
|
2527
|
+
write: options.write,
|
|
2528
|
+
};
|
|
2529
|
+
|
|
2530
|
+
const existingProfiles = getAgentProfilesForRole(repoRoot, role);
|
|
2531
|
+
let next = { ...options, role };
|
|
2532
|
+
if (existingProfiles.length > 0 && !options.id && !options.defaultProfile) {
|
|
2533
|
+
const ux = createCommandUx(promptOptions);
|
|
2534
|
+
ux.summary(existingProfiles.map((profile) => ({
|
|
2535
|
+
label: profile.id,
|
|
2536
|
+
value: `${profile.provider} ${profile.model || '(no model)'}${profile.default ? ' default' : ''}`,
|
|
2537
|
+
})), {
|
|
2538
|
+
title: `Existing ${role} profiles`,
|
|
2539
|
+
});
|
|
2540
|
+
|
|
2541
|
+
const action = await selectOption(`Ya existe al menos un perfil ${role}. ¿Qué querés hacer?`, [
|
|
2542
|
+
{ label: 'Actualizar perfil actual', value: 'update-current', hint: 'Reutiliza el perfil default', default: true },
|
|
2543
|
+
{ label: 'Crear perfil nuevo', value: 'create-new', hint: 'Permite guardar otro modelo o provider' },
|
|
2544
|
+
{ label: 'Cambiar default', value: 'change-default', hint: 'Marca un perfil existente como default' },
|
|
2545
|
+
{ label: 'Cancelar', value: 'cancel', hint: 'No escribe archivos' },
|
|
2546
|
+
], {
|
|
2547
|
+
...promptOptions,
|
|
2548
|
+
name: 'agent profile action',
|
|
2549
|
+
flag: '--id',
|
|
2550
|
+
});
|
|
2551
|
+
|
|
2552
|
+
if (action.value === 'cancel') {
|
|
2553
|
+
throw new Error(formatError('ai agent set canceled. No files were written.'));
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
if (action.value === 'change-default') {
|
|
2557
|
+
const profile = await selectOption(`Elegí el perfil ${role} default`, existingProfiles.map((item) => ({
|
|
2558
|
+
label: resolveAgentProfileDisplayName(item),
|
|
2559
|
+
value: item.id,
|
|
2560
|
+
hint: `${item.provider} ${item.model || '(no model)'}`,
|
|
2561
|
+
default: item.default === true,
|
|
2562
|
+
raw: item,
|
|
2563
|
+
})), {
|
|
2564
|
+
...promptOptions,
|
|
2565
|
+
name: 'agent profile default',
|
|
2566
|
+
flag: '--id',
|
|
2567
|
+
});
|
|
2568
|
+
return {
|
|
2569
|
+
...next,
|
|
2570
|
+
id: profile.raw.id,
|
|
2571
|
+
provider: profile.raw.provider,
|
|
2572
|
+
model: profile.raw.model,
|
|
2573
|
+
displayName: profile.raw.displayName,
|
|
2574
|
+
label: profile.raw.label,
|
|
2575
|
+
context: profile.raw.context,
|
|
2576
|
+
defaultProfile: true,
|
|
2577
|
+
};
|
|
2578
|
+
}
|
|
2579
|
+
|
|
2580
|
+
if (action.value === 'update-current') {
|
|
2581
|
+
const current = existingProfiles.find((profile) => profile.default) || existingProfiles[0];
|
|
2582
|
+
next = {
|
|
2583
|
+
...next,
|
|
2584
|
+
id: current.id,
|
|
2585
|
+
context: next.context || current.context,
|
|
2586
|
+
label: next.label || current.label,
|
|
2587
|
+
};
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
if (action.value === 'create-new') {
|
|
2591
|
+
const id = await promptText(`ID para el nuevo perfil ${role}`, {
|
|
2592
|
+
...promptOptions,
|
|
2593
|
+
name: 'agent profile id',
|
|
2594
|
+
flag: '--id',
|
|
2595
|
+
placeholder: `${role}-gpt-55`,
|
|
2596
|
+
});
|
|
2597
|
+
next.id = id;
|
|
2598
|
+
next.defaultProfile = options.defaultProfile === true;
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
if (!next.provider) {
|
|
2603
|
+
const selectedProvider = await selectOption(`Elegí un provider para ${role}`, buildAgentProviderChoices(repoRoot, options), {
|
|
2604
|
+
...promptOptions,
|
|
2605
|
+
name: 'agent provider',
|
|
2606
|
+
flag: '--provider',
|
|
2607
|
+
});
|
|
2608
|
+
next.provider = selectedProvider.value;
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
if (!next.model) {
|
|
2612
|
+
const selectedModel = await selectOption(`Elegí un modelo para ${role}`, buildAgentModelChoices(next.provider, role), {
|
|
2613
|
+
...promptOptions,
|
|
2614
|
+
name: 'agent model',
|
|
2615
|
+
flag: '--model',
|
|
2616
|
+
});
|
|
2617
|
+
if (selectedModel.value === 'custom') {
|
|
2618
|
+
const model = await promptText(`Modelo custom para ${next.provider}`, {
|
|
2619
|
+
...promptOptions,
|
|
2620
|
+
name: 'agent model',
|
|
2621
|
+
flag: '--model',
|
|
2622
|
+
placeholder: `${next.provider}-model-id`,
|
|
2623
|
+
});
|
|
2624
|
+
const displayName = await promptText('Nombre visible del modelo custom', {
|
|
2625
|
+
...promptOptions,
|
|
2626
|
+
name: 'agent model display name',
|
|
2627
|
+
flag: '--display-name',
|
|
2628
|
+
initialValue: model,
|
|
2629
|
+
required: false,
|
|
2630
|
+
});
|
|
2631
|
+
next.model = model;
|
|
2632
|
+
next.displayName = next.displayName || displayName || model;
|
|
2633
|
+
} else {
|
|
2634
|
+
next.model = selectedModel.value;
|
|
2635
|
+
next.displayName = next.displayName || selectedModel.raw.displayName;
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
return {
|
|
2640
|
+
...next,
|
|
2641
|
+
interactiveResolved: true,
|
|
2642
|
+
};
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2175
2645
|
function formatAgentProfile(profile) {
|
|
2176
2646
|
const lines = [
|
|
2647
|
+
`ID: ${profile.id || 'default'}`,
|
|
2177
2648
|
`Role: ${profile.role}`,
|
|
2178
2649
|
`Provider: ${profile.provider}`,
|
|
2179
2650
|
`Model: ${profile.model || '(not set)'}`,
|
|
2180
2651
|
`Label: ${profile.label || '(not set)'}`,
|
|
2652
|
+
`Display name: ${resolveAgentProfileDisplayName(profile) || '(not set)'}`,
|
|
2653
|
+
`Default: ${profile.default === true ? 'yes' : 'no'}`,
|
|
2181
2654
|
`Context: ${profile.context || '(not set)'}`,
|
|
2182
2655
|
`Updated: ${profile.updated_at}`,
|
|
2183
2656
|
];
|
|
@@ -2193,7 +2666,9 @@ function formatAgentProfileList(profiles) {
|
|
|
2193
2666
|
}
|
|
2194
2667
|
const model = item.profile.model ? ` model=${item.profile.model}` : '';
|
|
2195
2668
|
const label = item.profile.label ? ` label=${item.profile.label}` : '';
|
|
2196
|
-
|
|
2669
|
+
const displayName = resolveAgentProfileDisplayName(item.profile);
|
|
2670
|
+
const alternatives = item.profiles.length > 1 ? ` options=${item.profiles.length}` : '';
|
|
2671
|
+
lines.push(`- ${item.role}: provider=${item.profile.provider}${model}${label} displayName=${displayName}${alternatives}`);
|
|
2197
2672
|
}
|
|
2198
2673
|
return `${lines.join('\n')}\n`;
|
|
2199
2674
|
}
|
|
@@ -2213,22 +2688,156 @@ function formatAgentProfileDryRun(repoRoot, result) {
|
|
|
2213
2688
|
].join('\n');
|
|
2214
2689
|
}
|
|
2215
2690
|
|
|
2216
|
-
function
|
|
2691
|
+
function agentDoctorSymbol(status) {
|
|
2692
|
+
if (status === 'error') return 'x';
|
|
2693
|
+
if (status === 'warning') return '!';
|
|
2694
|
+
return 'OK';
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2697
|
+
function formatAgentDoctorReport(report) {
|
|
2698
|
+
const lines = [
|
|
2699
|
+
'Quiver Agent Doctor',
|
|
2700
|
+
'',
|
|
2701
|
+
'Checks',
|
|
2702
|
+
];
|
|
2703
|
+
|
|
2704
|
+
if (report.checks.length === 0) {
|
|
2705
|
+
lines.push(' ! No agent profiles configured');
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
for (const check of report.checks) {
|
|
2709
|
+
const target = `${check.role}/${check.id}`;
|
|
2710
|
+
const model = check.model || '(no model)';
|
|
2711
|
+
const provider = check.provider || '(no provider)';
|
|
2712
|
+
const defaultText = check.default ? ' default' : '';
|
|
2713
|
+
lines.push(` ${agentDoctorSymbol(check.status)} ${target}: provider=${provider} model=${model}${defaultText}`);
|
|
2714
|
+
for (const finding of check.findings.filter((item) => item.severity !== 'info')) {
|
|
2715
|
+
lines.push(` - ${finding.severity}: ${finding.message}`);
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
|
|
2719
|
+
lines.push('', 'Suggested fixes');
|
|
2720
|
+
if (report.suggestedFixes.length === 0) {
|
|
2721
|
+
lines.push(' OK No fixes suggested.');
|
|
2722
|
+
} else {
|
|
2723
|
+
for (const fix of report.suggestedFixes) {
|
|
2724
|
+
lines.push(` - ${fix}`);
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
lines.push('');
|
|
2728
|
+
lines.push(`Summary: profiles=${report.summary.profiles} errors=${report.summary.errors} warnings=${report.summary.warnings} info=${report.summary.info}`);
|
|
2729
|
+
lines.push('');
|
|
2730
|
+
return `${lines.join('\n')}\n`;
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
function formatAgentRepairPlan(plan) {
|
|
2734
|
+
const lines = [
|
|
2735
|
+
'AI agent profile repair dry-run',
|
|
2736
|
+
'- Writes: none',
|
|
2737
|
+
'',
|
|
2738
|
+
'Proposed changes',
|
|
2739
|
+
];
|
|
2740
|
+
|
|
2741
|
+
if (plan.changes.length === 0) {
|
|
2742
|
+
lines.push(' OK No safe repairs found.');
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
for (const change of plan.changes) {
|
|
2746
|
+
lines.push(` - ${change.role}/${change.profileId}: ${change.reason}`);
|
|
2747
|
+
lines.push(` Before: model=${change.before.model || '(not set)'} displayName=${change.before.displayName || '(not set)'}`);
|
|
2748
|
+
lines.push(` After: model=${change.after.model || '(not set)'} displayName=${change.after.displayName || '(not set)'}`);
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
lines.push('');
|
|
2752
|
+
return `${lines.join('\n')}\n`;
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
function buildModelsListReport(options = {}) {
|
|
2756
|
+
const providerFilter = String(options.provider || '').trim().toLowerCase();
|
|
2757
|
+
const providers = providerFilter
|
|
2758
|
+
? [listCatalogProviders().find((provider) => provider.id === providerFilter)].filter(Boolean)
|
|
2759
|
+
: listCatalogProviders();
|
|
2760
|
+
|
|
2761
|
+
if (providerFilter && providers.length === 0) {
|
|
2762
|
+
throw new Error(formatError(`unsupported provider filter '${options.provider}'. Supported providers: ${listCatalogProviders().map((provider) => provider.id).join(', ')}.`));
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
return {
|
|
2766
|
+
catalogVersion: MODEL_CATALOG_VERSION,
|
|
2767
|
+
lastUpdated: MODEL_CATALOG_LAST_UPDATED,
|
|
2768
|
+
note: 'Models are known by Quiver. This does not guarantee provider account access.',
|
|
2769
|
+
providers: providers.map((provider) => ({
|
|
2770
|
+
id: provider.id,
|
|
2771
|
+
displayName: provider.displayName,
|
|
2772
|
+
models: getKnownModelsForProvider(provider.id).map((model) => ({
|
|
2773
|
+
id: model.id,
|
|
2774
|
+
displayName: model.displayName,
|
|
2775
|
+
recommendedFor: model.recommendedFor,
|
|
2776
|
+
costTier: model.costTier,
|
|
2777
|
+
qualityTier: model.qualityTier,
|
|
2778
|
+
stability: model.stability,
|
|
2779
|
+
custom: model.custom === true,
|
|
2780
|
+
})),
|
|
2781
|
+
})),
|
|
2782
|
+
};
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
function formatModelsListReport(report) {
|
|
2786
|
+
const lines = [
|
|
2787
|
+
'AI models known by Quiver',
|
|
2788
|
+
`Catalog version: ${report.catalogVersion}`,
|
|
2789
|
+
`Last updated: ${report.lastUpdated}`,
|
|
2790
|
+
'Note: Models are known by Quiver; provider account access is not guaranteed.',
|
|
2791
|
+
'',
|
|
2792
|
+
];
|
|
2793
|
+
|
|
2794
|
+
for (const provider of report.providers) {
|
|
2795
|
+
lines.push(`${provider.displayName} (${provider.id})`);
|
|
2796
|
+
for (const model of provider.models) {
|
|
2797
|
+
const roles = model.recommendedFor.length > 0 ? model.recommendedFor.join(', ') : 'custom/manual';
|
|
2798
|
+
lines.push(` - ${model.id} (${model.displayName})`);
|
|
2799
|
+
lines.push(` roles: ${roles}`);
|
|
2800
|
+
lines.push(` cost=${model.costTier} quality=${model.qualityTier} stability=${model.stability}`);
|
|
2801
|
+
}
|
|
2802
|
+
lines.push('');
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
return `${lines.join('\n')}\n`;
|
|
2806
|
+
}
|
|
2807
|
+
|
|
2808
|
+
function runModelsList(options = {}) {
|
|
2809
|
+
const report = buildModelsListReport({
|
|
2810
|
+
provider: options.provider,
|
|
2811
|
+
});
|
|
2812
|
+
if (options.json) {
|
|
2813
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
2814
|
+
} else {
|
|
2815
|
+
process.stdout.write(formatModelsListReport(report));
|
|
2816
|
+
}
|
|
2817
|
+
return {
|
|
2818
|
+
task: 'models',
|
|
2819
|
+
command: 'list',
|
|
2820
|
+
report,
|
|
2821
|
+
};
|
|
2822
|
+
}
|
|
2823
|
+
|
|
2824
|
+
async function runAgent(repoRoot, options = {}) {
|
|
2217
2825
|
const command = String(options.command || '').trim().toLowerCase();
|
|
2218
2826
|
|
|
2219
2827
|
if (command === 'set') {
|
|
2220
2828
|
if (!options.role) {
|
|
2221
|
-
throw new Error(formatError('missing agent role. Use: npx create-quiver ai agent set <planner|executor|reviewer|doctor> --provider <provider>'));
|
|
2222
|
-
}
|
|
2223
|
-
if (!options.provider) {
|
|
2224
|
-
throw new Error(formatError('ai agent set requires --provider. Supported providers: codex, claude, gemini.'));
|
|
2829
|
+
throw new Error(formatError('missing agent role. Use: npx create-quiver ai agent set <planner|executor|reviewer|doctor> --provider <provider> --model <model>'));
|
|
2225
2830
|
}
|
|
2831
|
+
const profileOptions = await resolveInteractiveAgentSetOptions(repoRoot, options);
|
|
2226
2832
|
if (options.dryRun) {
|
|
2227
|
-
const preview = buildAgentProfileState(repoRoot,
|
|
2228
|
-
context:
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2833
|
+
const preview = buildAgentProfileState(repoRoot, profileOptions.role, {
|
|
2834
|
+
context: profileOptions.context,
|
|
2835
|
+
default: profileOptions.defaultProfile,
|
|
2836
|
+
displayName: profileOptions.displayName,
|
|
2837
|
+
id: profileOptions.id,
|
|
2838
|
+
label: profileOptions.label,
|
|
2839
|
+
model: profileOptions.model,
|
|
2840
|
+
provider: profileOptions.provider,
|
|
2232
2841
|
});
|
|
2233
2842
|
process.stdout.write(formatAgentProfileDryRun(repoRoot, preview));
|
|
2234
2843
|
return {
|
|
@@ -2239,11 +2848,35 @@ function runAgent(repoRoot, options = {}) {
|
|
|
2239
2848
|
filePath: path.relative(repoRoot, preview.filePath).split(path.sep).join('/'),
|
|
2240
2849
|
};
|
|
2241
2850
|
}
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2851
|
+
if (profileOptions.interactiveResolved === true) {
|
|
2852
|
+
const preview = buildAgentProfileState(repoRoot, profileOptions.role, {
|
|
2853
|
+
context: profileOptions.context,
|
|
2854
|
+
default: profileOptions.defaultProfile,
|
|
2855
|
+
displayName: profileOptions.displayName,
|
|
2856
|
+
id: profileOptions.id,
|
|
2857
|
+
label: profileOptions.label,
|
|
2858
|
+
model: profileOptions.model,
|
|
2859
|
+
provider: profileOptions.provider,
|
|
2860
|
+
});
|
|
2861
|
+
const ux = createCommandUx(profileOptions);
|
|
2862
|
+
ux.summary([
|
|
2863
|
+
{ label: 'Role', value: preview.profile.role },
|
|
2864
|
+
{ label: 'Provider', value: preview.profile.provider },
|
|
2865
|
+
{ label: 'Model', value: preview.profile.model || '(not set)' },
|
|
2866
|
+
{ label: 'Display name', value: resolveAgentProfileDisplayName(preview.profile) || '(not set)' },
|
|
2867
|
+
{ label: 'Default', value: preview.profile.default === true ? 'yes' : 'no' },
|
|
2868
|
+
], {
|
|
2869
|
+
title: 'Profile to save',
|
|
2870
|
+
});
|
|
2871
|
+
}
|
|
2872
|
+
const result = setAgentProfile(repoRoot, profileOptions.role, {
|
|
2873
|
+
context: profileOptions.context,
|
|
2874
|
+
default: profileOptions.defaultProfile,
|
|
2875
|
+
displayName: profileOptions.displayName,
|
|
2876
|
+
id: profileOptions.id,
|
|
2877
|
+
label: profileOptions.label,
|
|
2878
|
+
model: profileOptions.model,
|
|
2879
|
+
provider: profileOptions.provider,
|
|
2247
2880
|
});
|
|
2248
2881
|
process.stdout.write('AI agent profile saved\n');
|
|
2249
2882
|
process.stdout.write(formatAgentProfile(result.profile));
|
|
@@ -2260,13 +2893,17 @@ function runAgent(repoRoot, options = {}) {
|
|
|
2260
2893
|
if (!options.role) {
|
|
2261
2894
|
throw new Error(formatError('missing agent role. Use: npx create-quiver ai agent show <planner|executor|reviewer|doctor>'));
|
|
2262
2895
|
}
|
|
2263
|
-
const profile =
|
|
2896
|
+
const profile = options.id
|
|
2897
|
+
? getAgentProfileById(repoRoot, options.role, options.id)
|
|
2898
|
+
: getAgentProfile(repoRoot, options.role);
|
|
2264
2899
|
if (!profile) {
|
|
2265
2900
|
throw new Error(formatActionableError({
|
|
2266
|
-
failure:
|
|
2901
|
+
failure: options.id
|
|
2902
|
+
? `agent profile '${options.role}/${options.id}' is not configured.`
|
|
2903
|
+
: `agent profile '${options.role}' is not configured.`,
|
|
2267
2904
|
impact: 'Quiver will fall back to default provider behavior and may use the wrong model/cost profile.',
|
|
2268
|
-
fix: `Configure the ${options.role} profile with a supported provider and
|
|
2269
|
-
nextCommand: `npx create-quiver ai agent set ${options.role} --provider <provider> --model <
|
|
2905
|
+
fix: `Configure the ${options.role} profile with a supported provider and technical model id.`,
|
|
2906
|
+
nextCommand: `npx create-quiver ai agent set ${options.role} --provider <provider> --model <model-id>`,
|
|
2270
2907
|
}));
|
|
2271
2908
|
}
|
|
2272
2909
|
process.stdout.write(formatAgentProfile(profile));
|
|
@@ -2288,7 +2925,44 @@ function runAgent(repoRoot, options = {}) {
|
|
|
2288
2925
|
};
|
|
2289
2926
|
}
|
|
2290
2927
|
|
|
2291
|
-
|
|
2928
|
+
if (command === 'doctor') {
|
|
2929
|
+
const report = buildAgentProfileDoctorReport(repoRoot);
|
|
2930
|
+
if (options.json) {
|
|
2931
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
2932
|
+
} else {
|
|
2933
|
+
process.stdout.write(formatAgentDoctorReport(report));
|
|
2934
|
+
}
|
|
2935
|
+
if (report.summary.errors > 0) {
|
|
2936
|
+
process.exitCode = 1;
|
|
2937
|
+
}
|
|
2938
|
+
return {
|
|
2939
|
+
task: 'agent',
|
|
2940
|
+
command,
|
|
2941
|
+
report,
|
|
2942
|
+
};
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2945
|
+
if (command === 'repair') {
|
|
2946
|
+
if (options.dryRun !== true) {
|
|
2947
|
+
throw new Error(formatError('ai agent repair only supports --dry-run for now. No files were written.'));
|
|
2948
|
+
}
|
|
2949
|
+
const plan = buildAgentProfileRepairPlan(repoRoot, {
|
|
2950
|
+
includeState: options.json === true,
|
|
2951
|
+
});
|
|
2952
|
+
if (options.json) {
|
|
2953
|
+
process.stdout.write(`${JSON.stringify(plan, null, 2)}\n`);
|
|
2954
|
+
} else {
|
|
2955
|
+
process.stdout.write(formatAgentRepairPlan(plan));
|
|
2956
|
+
}
|
|
2957
|
+
return {
|
|
2958
|
+
task: 'agent',
|
|
2959
|
+
command,
|
|
2960
|
+
dryRun: true,
|
|
2961
|
+
plan,
|
|
2962
|
+
};
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2965
|
+
throw new Error(formatError(`unsupported ai agent subcommand: ${command}. Supported tasks: set, list, show, doctor, repair`));
|
|
2292
2966
|
}
|
|
2293
2967
|
|
|
2294
2968
|
async function runGitHubTask(repoRoot, options = {}, mode = 'pr') {
|
|
@@ -2324,20 +2998,32 @@ async function runGitHubTask(repoRoot, options = {}, mode = 'pr') {
|
|
|
2324
2998
|
async function runPr(repoRoot, options = {}) {
|
|
2325
2999
|
const dryRun = options.dryRun === true;
|
|
2326
3000
|
const create = options.create === true;
|
|
3001
|
+
const ux = createCommandUx(options);
|
|
3002
|
+
const showProgress = create && !dryRun && shouldShowHumanProgress(ux, options);
|
|
3003
|
+
if (showProgress) {
|
|
3004
|
+
ux.heading('Creando PR con gh');
|
|
3005
|
+
}
|
|
2327
3006
|
let preflight;
|
|
2328
3007
|
|
|
2329
3008
|
try {
|
|
2330
|
-
preflight = await (
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
3009
|
+
preflight = await runProviderWithProgress({
|
|
3010
|
+
ux,
|
|
3011
|
+
enabled: showProgress,
|
|
3012
|
+
message: 'Ejecutando preflight de GitHub...',
|
|
3013
|
+
successMessage: 'Preflight de GitHub listo',
|
|
3014
|
+
failureMessage: 'Falló preflight de GitHub',
|
|
3015
|
+
run: () => (options.preflightFn || preflightGitHubPr)(repoRoot, {
|
|
3016
|
+
remote: options.remote,
|
|
3017
|
+
sshHostAlias: options.sshHostAlias,
|
|
3018
|
+
identityFile: options.identityFile,
|
|
3019
|
+
gitFlowGuidePath: options.gitFlowGuidePath,
|
|
3020
|
+
ghCommand: options.ghCommand,
|
|
3021
|
+
ghProbe: options.ghProbe,
|
|
3022
|
+
ghAuthProbe: options.ghAuthProbe,
|
|
3023
|
+
ghProbeArgs: options.ghProbeArgs,
|
|
3024
|
+
ghAuthArgs: options.ghAuthArgs,
|
|
3025
|
+
blockedBranches: options.blockedBranches,
|
|
3026
|
+
}),
|
|
2341
3027
|
});
|
|
2342
3028
|
} catch (error) {
|
|
2343
3029
|
throw annotateGitHubError(error, 'pr');
|
|
@@ -2352,6 +3038,9 @@ async function runPr(repoRoot, options = {}) {
|
|
|
2352
3038
|
prBodyPath: options.prBodyPath,
|
|
2353
3039
|
title: options.title,
|
|
2354
3040
|
});
|
|
3041
|
+
if (showProgress) {
|
|
3042
|
+
ux.check('Cuerpo del PR preparado');
|
|
3043
|
+
}
|
|
2355
3044
|
} catch (error) {
|
|
2356
3045
|
throw annotateGitHubError(error, 'pr');
|
|
2357
3046
|
}
|
|
@@ -2396,8 +3085,15 @@ async function runPr(repoRoot, options = {}) {
|
|
|
2396
3085
|
|
|
2397
3086
|
let result;
|
|
2398
3087
|
try {
|
|
2399
|
-
result =
|
|
2400
|
-
|
|
3088
|
+
result = await runProviderWithProgress({
|
|
3089
|
+
ux,
|
|
3090
|
+
enabled: showProgress,
|
|
3091
|
+
message: 'Creando PR en GitHub...',
|
|
3092
|
+
successMessage: 'PR creado',
|
|
3093
|
+
failureMessage: 'Falló creación del PR',
|
|
3094
|
+
run: () => runGhPrCreate(plan, {
|
|
3095
|
+
ghCreateRunner: options.ghCreateRunner,
|
|
3096
|
+
}),
|
|
2401
3097
|
});
|
|
2402
3098
|
} catch (error) {
|
|
2403
3099
|
throw annotateGitHubError(error, 'pr');
|
|
@@ -2435,6 +3131,7 @@ module.exports = {
|
|
|
2435
3131
|
formatSpecDryRunReport,
|
|
2436
3132
|
normalizeTimeout,
|
|
2437
3133
|
readTextFile,
|
|
3134
|
+
resolveInteractiveAgentSetOptions,
|
|
2438
3135
|
runAgent,
|
|
2439
3136
|
runActiveSlice,
|
|
2440
3137
|
runDoctor,
|
|
@@ -2443,6 +3140,7 @@ module.exports = {
|
|
|
2443
3140
|
runLifecycleResume,
|
|
2444
3141
|
runLifecycleRun,
|
|
2445
3142
|
runLifecycleStatus,
|
|
3143
|
+
runModelsList,
|
|
2446
3144
|
runExport,
|
|
2447
3145
|
runInspect,
|
|
2448
3146
|
runPromptSlice,
|