create-quiver 0.15.0 → 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 +6 -0
- package/README.md +31 -0
- package/README_FOR_AI.md +8 -3
- package/ROADMAP.md +5 -0
- package/docs/AI_CONTEXT.md.template +4 -0
- package/docs/AI_ONBOARDING_PROMPT.md.template +8 -0
- package/docs/CLI_UX_GUIDE.md +16 -1
- package/docs/COMMANDS.md.template +14 -4
- 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 +29 -1
- package/package.json +1 -1
- 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 +449 -34
- package/src/create-quiver/commands/flow.js +2 -2
- package/src/create-quiver/index.js +26 -10
- package/src/create-quiver/lib/agent-profiles.js +332 -4
- package/src/create-quiver/lib/ai/execution-plan.js +7 -2
- package/src/create-quiver/lib/ai/executor.js +9 -2
- package/src/create-quiver/lib/ai/model-catalog.js +333 -0
- package/src/create-quiver/lib/ai/providers.js +143 -4
- package/src/create-quiver/lib/cli/selectors.js +53 -0
|
@@ -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,12 @@ const {
|
|
|
55
63
|
} = require('../lib/ai/run-state');
|
|
56
64
|
const {
|
|
57
65
|
agentProfilesPath,
|
|
66
|
+
buildAgentProfileDoctorReport,
|
|
67
|
+
buildAgentProfileRepairPlan,
|
|
58
68
|
buildAgentProfileState,
|
|
59
69
|
getAgentProfile,
|
|
60
70
|
getAgentProfileById,
|
|
71
|
+
getAgentProfilesForRole,
|
|
61
72
|
listAgentProfiles,
|
|
62
73
|
normalizeAgentProfileRole,
|
|
63
74
|
resolveAgentProfileDisplayName,
|
|
@@ -175,6 +186,13 @@ function resolveRuntimeAgentProfile(repoRoot, role, options = {}, fallbackProvid
|
|
|
175
186
|
};
|
|
176
187
|
}
|
|
177
188
|
|
|
189
|
+
function runtimeModelExecutionOptions(runtimeProfile, options = {}) {
|
|
190
|
+
return {
|
|
191
|
+
model: runtimeProfile.model,
|
|
192
|
+
blockModelAlias: Boolean(runtimeProfile.profile && !String(options.model || '').trim()),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
178
196
|
function createCommandUx(options = {}) {
|
|
179
197
|
if (options.ux) {
|
|
180
198
|
return options.ux;
|
|
@@ -1247,7 +1265,7 @@ async function runOnboard(repoRoot, options = {}) {
|
|
|
1247
1265
|
prompt,
|
|
1248
1266
|
cwd: repoRoot,
|
|
1249
1267
|
timeoutMs,
|
|
1250
|
-
|
|
1268
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1251
1269
|
enforceModelSelection: false,
|
|
1252
1270
|
});
|
|
1253
1271
|
} catch (error) {
|
|
@@ -1311,7 +1329,7 @@ async function runOnboard(repoRoot, options = {}) {
|
|
|
1311
1329
|
tempRoot: options.tempRoot,
|
|
1312
1330
|
tempFileName: options.tempFileName,
|
|
1313
1331
|
tempFilePrefix: options.tempFilePrefix,
|
|
1314
|
-
|
|
1332
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1315
1333
|
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
1316
1334
|
}),
|
|
1317
1335
|
});
|
|
@@ -1427,7 +1445,7 @@ async function runPrepareContextWithPlanner(repoRoot, options = {}) {
|
|
|
1427
1445
|
prompt,
|
|
1428
1446
|
cwd: repoRoot,
|
|
1429
1447
|
timeoutMs,
|
|
1430
|
-
|
|
1448
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1431
1449
|
enforceModelSelection: false,
|
|
1432
1450
|
});
|
|
1433
1451
|
} catch (error) {
|
|
@@ -1502,7 +1520,7 @@ async function runPrepareContextWithPlanner(repoRoot, options = {}) {
|
|
|
1502
1520
|
tempRoot: options.tempRoot,
|
|
1503
1521
|
tempFileName: options.tempFileName,
|
|
1504
1522
|
tempFilePrefix: options.tempFilePrefix,
|
|
1505
|
-
|
|
1523
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1506
1524
|
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
1507
1525
|
}),
|
|
1508
1526
|
});
|
|
@@ -1681,7 +1699,7 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
1681
1699
|
prompt,
|
|
1682
1700
|
cwd: repoRoot,
|
|
1683
1701
|
timeoutMs,
|
|
1684
|
-
|
|
1702
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1685
1703
|
enforceModelSelection: false,
|
|
1686
1704
|
});
|
|
1687
1705
|
} catch (error) {
|
|
@@ -1754,7 +1772,7 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
1754
1772
|
tempRoot: options.tempRoot,
|
|
1755
1773
|
tempFileName: options.tempFileName,
|
|
1756
1774
|
tempFilePrefix: options.tempFilePrefix,
|
|
1757
|
-
|
|
1775
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1758
1776
|
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
1759
1777
|
}),
|
|
1760
1778
|
});
|
|
@@ -1848,7 +1866,7 @@ async function runReviewPlan(repoRoot, options = {}) {
|
|
|
1848
1866
|
prompt: built.prompt,
|
|
1849
1867
|
cwd: repoRoot,
|
|
1850
1868
|
timeoutMs,
|
|
1851
|
-
|
|
1869
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1852
1870
|
enforceModelSelection: false,
|
|
1853
1871
|
});
|
|
1854
1872
|
} catch (error) {
|
|
@@ -1932,7 +1950,7 @@ async function runReviewPlan(repoRoot, options = {}) {
|
|
|
1932
1950
|
tempRoot: options.tempRoot,
|
|
1933
1951
|
tempFileName: options.tempFileName,
|
|
1934
1952
|
tempFilePrefix: options.tempFilePrefix,
|
|
1935
|
-
|
|
1953
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
1936
1954
|
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
1937
1955
|
}),
|
|
1938
1956
|
});
|
|
@@ -2013,7 +2031,7 @@ async function runRepairPlan(repoRoot, options = {}) {
|
|
|
2013
2031
|
prompt: built.prompt,
|
|
2014
2032
|
cwd: repoRoot,
|
|
2015
2033
|
timeoutMs,
|
|
2016
|
-
|
|
2034
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
2017
2035
|
enforceModelSelection: false,
|
|
2018
2036
|
});
|
|
2019
2037
|
} catch (error) {
|
|
@@ -2082,7 +2100,7 @@ async function runRepairPlan(repoRoot, options = {}) {
|
|
|
2082
2100
|
tempRoot: options.tempRoot,
|
|
2083
2101
|
tempFileName: options.tempFileName,
|
|
2084
2102
|
tempFilePrefix: options.tempFilePrefix,
|
|
2085
|
-
|
|
2103
|
+
...runtimeModelExecutionOptions(runtimeProfile, options),
|
|
2086
2104
|
enforceModelSelection: Boolean(runtimeProfile.model),
|
|
2087
2105
|
}),
|
|
2088
2106
|
});
|
|
@@ -2418,6 +2436,212 @@ function runLifecycleRun(repoRoot, options = {}) {
|
|
|
2418
2436
|
};
|
|
2419
2437
|
}
|
|
2420
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
|
+
|
|
2421
2645
|
function formatAgentProfile(profile) {
|
|
2422
2646
|
const lines = [
|
|
2423
2647
|
`ID: ${profile.id || 'default'}`,
|
|
@@ -2464,25 +2688,156 @@ function formatAgentProfileDryRun(repoRoot, result) {
|
|
|
2464
2688
|
].join('\n');
|
|
2465
2689
|
}
|
|
2466
2690
|
|
|
2467
|
-
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 = {}) {
|
|
2468
2825
|
const command = String(options.command || '').trim().toLowerCase();
|
|
2469
2826
|
|
|
2470
2827
|
if (command === 'set') {
|
|
2471
2828
|
if (!options.role) {
|
|
2472
|
-
throw new Error(formatError('missing agent role. Use: npx create-quiver ai agent set <planner|executor|reviewer|doctor> --provider <provider>'));
|
|
2473
|
-
}
|
|
2474
|
-
if (!options.provider) {
|
|
2475
|
-
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>'));
|
|
2476
2830
|
}
|
|
2831
|
+
const profileOptions = await resolveInteractiveAgentSetOptions(repoRoot, options);
|
|
2477
2832
|
if (options.dryRun) {
|
|
2478
|
-
const preview = buildAgentProfileState(repoRoot,
|
|
2479
|
-
context:
|
|
2480
|
-
default:
|
|
2481
|
-
displayName:
|
|
2482
|
-
id:
|
|
2483
|
-
label:
|
|
2484
|
-
model:
|
|
2485
|
-
provider:
|
|
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,
|
|
2486
2841
|
});
|
|
2487
2842
|
process.stdout.write(formatAgentProfileDryRun(repoRoot, preview));
|
|
2488
2843
|
return {
|
|
@@ -2493,14 +2848,35 @@ function runAgent(repoRoot, options = {}) {
|
|
|
2493
2848
|
filePath: path.relative(repoRoot, preview.filePath).split(path.sep).join('/'),
|
|
2494
2849
|
};
|
|
2495
2850
|
}
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
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,
|
|
2504
2880
|
});
|
|
2505
2881
|
process.stdout.write('AI agent profile saved\n');
|
|
2506
2882
|
process.stdout.write(formatAgentProfile(result.profile));
|
|
@@ -2526,8 +2902,8 @@ function runAgent(repoRoot, options = {}) {
|
|
|
2526
2902
|
? `agent profile '${options.role}/${options.id}' is not configured.`
|
|
2527
2903
|
: `agent profile '${options.role}' is not configured.`,
|
|
2528
2904
|
impact: 'Quiver will fall back to default provider behavior and may use the wrong model/cost profile.',
|
|
2529
|
-
fix: `Configure the ${options.role} profile with a supported provider and
|
|
2530
|
-
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>`,
|
|
2531
2907
|
}));
|
|
2532
2908
|
}
|
|
2533
2909
|
process.stdout.write(formatAgentProfile(profile));
|
|
@@ -2549,7 +2925,44 @@ function runAgent(repoRoot, options = {}) {
|
|
|
2549
2925
|
};
|
|
2550
2926
|
}
|
|
2551
2927
|
|
|
2552
|
-
|
|
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`));
|
|
2553
2966
|
}
|
|
2554
2967
|
|
|
2555
2968
|
async function runGitHubTask(repoRoot, options = {}, mode = 'pr') {
|
|
@@ -2718,6 +3131,7 @@ module.exports = {
|
|
|
2718
3131
|
formatSpecDryRunReport,
|
|
2719
3132
|
normalizeTimeout,
|
|
2720
3133
|
readTextFile,
|
|
3134
|
+
resolveInteractiveAgentSetOptions,
|
|
2721
3135
|
runAgent,
|
|
2722
3136
|
runActiveSlice,
|
|
2723
3137
|
runDoctor,
|
|
@@ -2726,6 +3140,7 @@ module.exports = {
|
|
|
2726
3140
|
runLifecycleResume,
|
|
2727
3141
|
runLifecycleRun,
|
|
2728
3142
|
runLifecycleStatus,
|
|
3143
|
+
runModelsList,
|
|
2729
3144
|
runExport,
|
|
2730
3145
|
runInspect,
|
|
2731
3146
|
runPromptSlice,
|
|
@@ -321,10 +321,10 @@ function detectFlowState(projectRoot) {
|
|
|
321
321
|
stage: 'agent-profiles-needed',
|
|
322
322
|
label: 'agent profiles need setup',
|
|
323
323
|
blockers: [`Missing ${agents.missingCore.join(' and ')} agent profile${agents.missingCore.length > 1 ? 's' : ''}.`],
|
|
324
|
-
nextCommand: `npx create-quiver ai agent set ${role} --provider codex --model
|
|
324
|
+
nextCommand: `npx create-quiver ai agent set ${role} --provider codex --model gpt-5.5`,
|
|
325
325
|
suggestedCommands: [
|
|
326
326
|
'npx create-quiver ai agent list',
|
|
327
|
-
`npx create-quiver ai agent set ${role} --provider codex --model
|
|
327
|
+
`npx create-quiver ai agent set ${role} --provider codex --model gpt-5.5`,
|
|
328
328
|
],
|
|
329
329
|
facts,
|
|
330
330
|
});
|