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
|
@@ -22,6 +22,7 @@ const {
|
|
|
22
22
|
runLifecycleResume: runAiLifecycleResume,
|
|
23
23
|
runLifecycleRun: runAiLifecycleRun,
|
|
24
24
|
runLifecycleStatus: runAiLifecycleStatus,
|
|
25
|
+
runModelsList: runAiModelsList,
|
|
25
26
|
runOnboard,
|
|
26
27
|
runPlan: runAiPlan,
|
|
27
28
|
runPrepareContext: runAiPrepareContext,
|
|
@@ -53,6 +54,8 @@ const { checkPrReadiness, checkScope, checkSliceReadiness } = require('./lib/rea
|
|
|
53
54
|
const { cleanupSlice, refreshActiveSlicesBoard, startSlice } = require('./lib/lifecycle');
|
|
54
55
|
const { buildSpecStatus, closeSpecWorktree, formatSpecCloseResult, formatSpecStartResult, formatSpecStatus, startSpecWorktree } = require('./lib/spec-worktrees');
|
|
55
56
|
const { getContextPathExclusionReason } = require('./lib/ai/safety');
|
|
57
|
+
const { selectOption } = require('./lib/cli/selectors');
|
|
58
|
+
const { createUx } = require('./lib/cli/ux');
|
|
56
59
|
const { validateUxFlags } = require('./lib/cli/ux-flags');
|
|
57
60
|
const { relativePosixPath, resolveTargetRoot } = require('./lib/paths');
|
|
58
61
|
const {
|
|
@@ -170,7 +173,8 @@ const COMMAND_HELP_GROUPS = [
|
|
|
170
173
|
['ai resume', 'Resume guidance from the last valid lifecycle phase without chat memory.'],
|
|
171
174
|
['ai onboard', 'Run or print the planner onboarding prompt with a token-aware context pack.'],
|
|
172
175
|
['ai prepare-context', 'Preview or write docs-only AI context updates with assumptions and risks.'],
|
|
173
|
-
['ai agent set|list|show', 'Manage planner, executor, reviewer, and doctor provider profiles without secrets
|
|
176
|
+
['ai agent set|list|show|doctor|repair', 'Manage, diagnose, and dry-run repair planner, executor, reviewer, and doctor provider profiles without secrets.'],
|
|
177
|
+
['ai models list', 'List provider/model ids known by Quiver without claiming account availability.'],
|
|
174
178
|
['ai plan', 'Generate versioned planner drafts for acceptance criteria, technical plan, or spec phase.'],
|
|
175
179
|
['ai revise', 'Create a new planner draft from human feedback without approving it.'],
|
|
176
180
|
['ai repair-plan', 'Repair an approved technical plan into a new structured draft without mutating the approved artifact.'],
|
|
@@ -259,7 +263,8 @@ function printUsage() {
|
|
|
259
263
|
npx create-quiver ai specs list [--json]
|
|
260
264
|
npx create-quiver ai slices list [--json]
|
|
261
265
|
npx create-quiver ai trace report [options]
|
|
262
|
-
npx create-quiver ai agent <set|list|show> [role] [options]
|
|
266
|
+
npx create-quiver ai agent <set|list|show|doctor|repair> [role] [options]
|
|
267
|
+
npx create-quiver ai models list [--provider codex|claude|gemini] [--json]
|
|
263
268
|
npx create-quiver ai prepare-context [options]
|
|
264
269
|
npx create-quiver ai revise [options]
|
|
265
270
|
npx create-quiver ai repair-plan [options]
|
|
@@ -310,6 +315,7 @@ Options:
|
|
|
310
315
|
--with-planner Enable planner-assisted behavior on commands that explicitly support it
|
|
311
316
|
--interactive Enable prompts on commands that explicitly support interactive choices
|
|
312
317
|
--review Open or prepare human review before persistent writes where supported
|
|
318
|
+
--methodology <name> Select methodology where supported (currently wdd-sdd)
|
|
313
319
|
--no-color Disable ANSI colors in human output
|
|
314
320
|
--fix For doctor, apply safe non-destructive repairs
|
|
315
321
|
--execute For ai execute-plan, run the planned slices instead of printing commands
|
|
@@ -318,7 +324,7 @@ Options:
|
|
|
318
324
|
--allow-dirty For ai execute-slice, allow pre-existing dirty files and ignore them for scope diff
|
|
319
325
|
--mode <name> Execution mode for ai execute-plan (auto, manual, delegated)
|
|
320
326
|
--provider <name> Provider CLI to preflight for prepare or AI commands
|
|
321
|
-
--model <
|
|
327
|
+
--model <model-id> Technical model id for AI agent profiles or provider-backed AI commands
|
|
322
328
|
--version <n> Draft version to approve for AI planner phases
|
|
323
329
|
--run <id> AI lifecycle run id
|
|
324
330
|
--ssh-host-alias <name> SSH host alias to validate for prepare or AI commands
|
|
@@ -334,6 +340,7 @@ Options:
|
|
|
334
340
|
|
|
335
341
|
Examples:
|
|
336
342
|
npx create-quiver init --name "My Project"
|
|
343
|
+
npx create-quiver init --interactive
|
|
337
344
|
npx create-quiver init --name "My Project" --dry-run
|
|
338
345
|
npx create-quiver --name "My Project"
|
|
339
346
|
npx create-quiver --name "My Project" --dir ./my-project
|
|
@@ -355,7 +362,10 @@ Examples:
|
|
|
355
362
|
cd ./my-project && npx create-quiver ai trace report
|
|
356
363
|
cd ./my-project && npx create-quiver ai agent set planner --provider codex --model gpt-5.5 --dry-run
|
|
357
364
|
cd ./my-project && npx create-quiver ai agent set planner --provider codex --model gpt-5.5
|
|
365
|
+
cd ./my-project && npx create-quiver ai agent doctor
|
|
366
|
+
cd ./my-project && npx create-quiver ai agent repair --dry-run
|
|
358
367
|
cd ./my-project && npx create-quiver ai agent list
|
|
368
|
+
cd ./my-project && npx create-quiver ai models list --provider codex
|
|
359
369
|
cd ./my-project && npx create-quiver ai plan --phase acceptance --input requirements.md --dry-run
|
|
360
370
|
cd ./my-project && npx create-quiver ai revise --phase acceptance --input feedback.md --dry-run
|
|
361
371
|
cd ./my-project && npx create-quiver ai approve --phase acceptance --version 1
|
|
@@ -434,6 +444,7 @@ function parseArgs(argv) {
|
|
|
434
444
|
format: 'tree',
|
|
435
445
|
formatExplicit: false,
|
|
436
446
|
showConflicts: false,
|
|
447
|
+
methodology: '',
|
|
437
448
|
level: null,
|
|
438
449
|
unicode: false,
|
|
439
450
|
aiCommand: '',
|
|
@@ -749,6 +760,74 @@ function parseArgs(argv) {
|
|
|
749
760
|
continue;
|
|
750
761
|
}
|
|
751
762
|
|
|
763
|
+
if (arg === '--id') {
|
|
764
|
+
const value = args[++index];
|
|
765
|
+
if (!value) {
|
|
766
|
+
throw new Error(formatError('missing value for --id'));
|
|
767
|
+
}
|
|
768
|
+
result.aiProfileId = value;
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (arg === '--display-name') {
|
|
773
|
+
const value = args[++index];
|
|
774
|
+
if (!value) {
|
|
775
|
+
throw new Error(formatError('missing value for --display-name'));
|
|
776
|
+
}
|
|
777
|
+
result.aiDisplayName = value;
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
if (arg === '--default') {
|
|
782
|
+
result.aiDefaultProfile = true;
|
|
783
|
+
continue;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
if (arg === '--planner') {
|
|
787
|
+
const value = args[++index];
|
|
788
|
+
if (!value) {
|
|
789
|
+
throw new Error(formatError('missing value for --planner'));
|
|
790
|
+
}
|
|
791
|
+
result.aiPlannerProfile = value;
|
|
792
|
+
continue;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (arg === '--executor') {
|
|
796
|
+
const value = args[++index];
|
|
797
|
+
if (!value) {
|
|
798
|
+
throw new Error(formatError('missing value for --executor'));
|
|
799
|
+
}
|
|
800
|
+
result.aiExecutorProfile = value;
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
if (arg === '--reviewer') {
|
|
805
|
+
const value = args[++index];
|
|
806
|
+
if (!value) {
|
|
807
|
+
throw new Error(formatError('missing value for --reviewer'));
|
|
808
|
+
}
|
|
809
|
+
result.aiReviewerProfile = value;
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (arg === '--doctor') {
|
|
814
|
+
const value = args[++index];
|
|
815
|
+
if (!value) {
|
|
816
|
+
throw new Error(formatError('missing value for --doctor'));
|
|
817
|
+
}
|
|
818
|
+
result.aiDoctorProfile = value;
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
if (arg === '--methodology') {
|
|
823
|
+
const value = args[++index];
|
|
824
|
+
if (!value) {
|
|
825
|
+
throw new Error(formatError('missing value for --methodology'));
|
|
826
|
+
}
|
|
827
|
+
result.methodology = value;
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
|
|
752
831
|
if (arg === '--label') {
|
|
753
832
|
const value = args[++index];
|
|
754
833
|
if (!value) {
|
|
@@ -977,10 +1056,10 @@ function parseArgs(argv) {
|
|
|
977
1056
|
if (result.aiCommand === 'run' && !result.aiRunCommand && positional.length > 0) {
|
|
978
1057
|
result.aiRunCommand = positional.shift();
|
|
979
1058
|
}
|
|
980
|
-
if ((result.aiCommand === 'specs' || result.aiCommand === 'slices' || result.aiCommand === 'trace' || result.aiCommand === 'active-slice') && !result.aiSecondaryCommand && positional.length > 0) {
|
|
1059
|
+
if ((result.aiCommand === 'specs' || result.aiCommand === 'slices' || result.aiCommand === 'models' || result.aiCommand === 'trace' || result.aiCommand === 'active-slice') && !result.aiSecondaryCommand && positional.length > 0) {
|
|
981
1060
|
result.aiSecondaryCommand = positional.shift();
|
|
982
1061
|
}
|
|
983
|
-
if ((result.aiCommand === 'specs' || result.aiCommand === 'slices') && result.aiSecondaryCommand && result.aiSecondaryCommand !== 'list') {
|
|
1062
|
+
if ((result.aiCommand === 'specs' || result.aiCommand === 'slices' || result.aiCommand === 'models') && result.aiSecondaryCommand && result.aiSecondaryCommand !== 'list') {
|
|
984
1063
|
throw new Error(formatError(`unsupported ai ${result.aiCommand} subcommand: ${result.aiSecondaryCommand}. Supported tasks: list`));
|
|
985
1064
|
}
|
|
986
1065
|
if (result.aiCommand === 'trace' && result.aiSecondaryCommand && result.aiSecondaryCommand !== 'report') {
|
|
@@ -2174,28 +2253,21 @@ function runMigrate(targetDir, options = {}) {
|
|
|
2174
2253
|
}
|
|
2175
2254
|
}
|
|
2176
2255
|
|
|
2177
|
-
function
|
|
2178
|
-
const
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
if (!hasQuiverInitializationEvidence(projectRoot)) {
|
|
2185
|
-
throw new Error(formatError('doctor requires a project previously initialized by Quiver.\nRun init first: npx create-quiver --name "Project Name"'));
|
|
2186
|
-
}
|
|
2187
|
-
|
|
2188
|
-
const fixPlan = buildDoctorFixPlan(projectRoot);
|
|
2189
|
-
if (options.fix) {
|
|
2190
|
-
if (options.dryRun) {
|
|
2191
|
-
console.log(formatDoctorFixPlan(fixPlan, { dryRun: true }));
|
|
2192
|
-
return;
|
|
2256
|
+
function uniqueLines(lines) {
|
|
2257
|
+
const seen = new Set();
|
|
2258
|
+
const unique = [];
|
|
2259
|
+
for (const line of lines) {
|
|
2260
|
+
const value = String(line || '').trim();
|
|
2261
|
+
if (!value || seen.has(value)) {
|
|
2262
|
+
continue;
|
|
2193
2263
|
}
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
console.log(formatDoctorFixPlan(fixPlan));
|
|
2264
|
+
seen.add(value);
|
|
2265
|
+
unique.push(value);
|
|
2197
2266
|
}
|
|
2267
|
+
return unique;
|
|
2268
|
+
}
|
|
2198
2269
|
|
|
2270
|
+
function buildDoctorCommandReport(projectRoot) {
|
|
2199
2271
|
const doctorReport = collectDoctorReport(projectRoot);
|
|
2200
2272
|
const specSlugs = doctorReport.specSlugs;
|
|
2201
2273
|
const doctorExampleTarget = doctorReport.exampleTarget || {
|
|
@@ -2282,65 +2354,425 @@ function runDoctor(targetDir, options = {}) {
|
|
|
2282
2354
|
...nonExecutableScripts.map((file) => `missing executable bit: ${file}`),
|
|
2283
2355
|
...missingScripts.map((name) => `missing package.json script: ${name}`),
|
|
2284
2356
|
];
|
|
2285
|
-
const
|
|
2357
|
+
const checks = [];
|
|
2358
|
+
|
|
2359
|
+
const addCheck = (id, status, message, details = {}) => {
|
|
2360
|
+
checks.push({
|
|
2361
|
+
id,
|
|
2362
|
+
status,
|
|
2363
|
+
message,
|
|
2364
|
+
...details,
|
|
2365
|
+
});
|
|
2366
|
+
};
|
|
2286
2367
|
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2368
|
+
addCheck('project-root', 'ok', `Quiver doctor passed for ${projectRoot}`);
|
|
2369
|
+
addCheck(
|
|
2370
|
+
'layout',
|
|
2371
|
+
doctorReport.layout === 'incomplete' ? 'error' : 'ok',
|
|
2372
|
+
`Layout: ${doctorReport.layout}`,
|
|
2373
|
+
);
|
|
2374
|
+
addCheck('specs', 'ok', specSlugs.length > 0 ? `Specs: ${specSlugs.join(', ')}` : 'Specs: none yet');
|
|
2290
2375
|
|
|
2291
|
-
console.log(`Quiver doctor passed for ${projectRoot}`);
|
|
2292
|
-
console.log(`Layout: ${doctorReport.layout}`);
|
|
2293
|
-
if (specSlugs.length > 0) {
|
|
2294
|
-
console.log(`Specs: ${specSlugs.join(', ')}`);
|
|
2295
|
-
} else {
|
|
2296
|
-
console.log('Specs: none yet');
|
|
2297
|
-
}
|
|
2298
2376
|
if (doctorReport.legacySignals.length > 0) {
|
|
2299
|
-
|
|
2300
|
-
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2377
|
+
addCheck('legacy-signals', doctorReport.layout === 'legacy' || doctorReport.layout === 'hybrid' ? 'warning' : 'ok', `Legacy signals: ${doctorReport.legacySignals.join(', ')}`);
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
addCheck(
|
|
2381
|
+
'required-files',
|
|
2382
|
+
missingFiles.length > 0 ? 'error' : 'ok',
|
|
2383
|
+
missingFiles.length > 0 ? `Missing required files: ${missingFiles.join(', ')}` : 'Required files found',
|
|
2384
|
+
{ missing: missingFiles },
|
|
2385
|
+
);
|
|
2386
|
+
|
|
2387
|
+
if (requiredExecutables.length > 0 || nonExecutableScripts.length > 0) {
|
|
2388
|
+
addCheck(
|
|
2389
|
+
'legacy-executables',
|
|
2390
|
+
nonExecutableScripts.length > 0 ? 'error' : 'ok',
|
|
2391
|
+
nonExecutableScripts.length > 0 ? `Missing executable bit: ${nonExecutableScripts.join(', ')}` : 'Legacy executable scripts are runnable',
|
|
2392
|
+
{ missing: nonExecutableScripts },
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
addCheck(
|
|
2397
|
+
'workflow-scripts',
|
|
2398
|
+
missingScripts.length > 0 ? 'error' : 'ok',
|
|
2399
|
+
missingScripts.length > 0 ? `Missing package.json workflow scripts: ${missingScripts.join(', ')}` : 'Workflow scripts available',
|
|
2400
|
+
{ missing: missingScripts },
|
|
2401
|
+
);
|
|
2402
|
+
|
|
2403
|
+
addCheck(
|
|
2404
|
+
'state',
|
|
2405
|
+
hasQuiverState ? 'ok' : 'warning',
|
|
2406
|
+
hasQuiverState ? 'Quiver state metadata found' : 'Warning: missing Quiver state metadata: .quiver/state.json',
|
|
2407
|
+
);
|
|
2408
|
+
|
|
2409
|
+
addCheck(
|
|
2410
|
+
'project-scan',
|
|
2411
|
+
hasScanArtifacts ? 'ok' : 'warning',
|
|
2412
|
+
hasScanArtifacts ? 'Project analysis artifacts found' : 'Warning: project analysis artifacts not found; run analyze when you need the visible project map',
|
|
2413
|
+
);
|
|
2414
|
+
|
|
2308
2415
|
for (const scriptName of missingNodeNativeScripts) {
|
|
2309
|
-
|
|
2416
|
+
addCheck(`node-script:${scriptName}`, 'warning', `Warning: missing Node-native script: ${scriptName}`);
|
|
2310
2417
|
}
|
|
2418
|
+
|
|
2311
2419
|
for (const scriptName of missingAiScripts) {
|
|
2312
|
-
|
|
2420
|
+
addCheck(`ai-script:${scriptName}`, 'warning', `Warning: missing AI orchestration script: ${scriptName}`);
|
|
2313
2421
|
}
|
|
2422
|
+
|
|
2314
2423
|
if (legacyOnlyScripts.length > 0) {
|
|
2315
|
-
|
|
2424
|
+
addCheck(
|
|
2425
|
+
'legacy-only-scripts',
|
|
2426
|
+
'warning',
|
|
2427
|
+
`Warning: legacy Bash workflow scripts detected for ${legacyOnlyScripts.join(', ')}. Run npx create-quiver migrate to add quiver:* npm scripts.`,
|
|
2428
|
+
);
|
|
2316
2429
|
}
|
|
2430
|
+
|
|
2317
2431
|
for (const script of unsupportedCreateQuiverScripts) {
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2432
|
+
addCheck(
|
|
2433
|
+
`unsupported-script:${script.scriptName}`,
|
|
2434
|
+
'warning',
|
|
2435
|
+
`Warning: package.json script ${script.scriptName} targets ${script.reason}: \`${script.command}\`. Update create-quiver or regenerate scripts with npx create-quiver migrate.`,
|
|
2436
|
+
{ script_name: script.scriptName, command: script.command, reason: script.reason },
|
|
2437
|
+
);
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
for (const warning of doctorReport.warnings) {
|
|
2441
|
+
addCheck(`warning:${checks.length + 1}`, 'warning', `Warning: ${warning}`);
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
const suggestedFixes = [
|
|
2445
|
+
...doctorReport.recommendations,
|
|
2446
|
+
!hasQuiverState
|
|
2447
|
+
? 'Run migration first: npx create-quiver migrate'
|
|
2448
|
+
: !hasScanArtifacts
|
|
2449
|
+
? 'Analyze the project first: npx create-quiver analyze'
|
|
2450
|
+
: 'Ask your AI agent: Read AGENTS.md, then docs/AI_ONBOARDING_PROMPT.md and execute it.',
|
|
2451
|
+
'Check the next ready slice: npx create-quiver next',
|
|
2452
|
+
];
|
|
2453
|
+
|
|
2331
2454
|
if (specSlugs.length > 0) {
|
|
2332
2455
|
const projectSlug = doctorExampleTarget.specSlug;
|
|
2333
2456
|
const sliceId = doctorExampleTarget.sliceId || '<slice-id>';
|
|
2334
2457
|
if (doctorExampleTarget.source === 'active-slice') {
|
|
2335
|
-
|
|
2458
|
+
suggestedFixes.push(`Example target: ${projectSlug}/${sliceId} (${doctorExampleTarget.status})`);
|
|
2336
2459
|
} else if (doctorExampleTarget.source === 'generic-multiple-specs') {
|
|
2337
|
-
|
|
2460
|
+
suggestedFixes.push('Example target: specs/<spec-slug>/slices/<slice-id>/slice.json (generic because no active slice is obvious)');
|
|
2338
2461
|
}
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2462
|
+
suggestedFixes.push(`Start a slice: npx create-quiver start-slice specs/${projectSlug}/slices/${sliceId}/slice.json`);
|
|
2463
|
+
suggestedFixes.push(`Validate a slice: npx create-quiver check-slice specs/${projectSlug}/slices/${sliceId}/slice.json`);
|
|
2464
|
+
suggestedFixes.push(`Validate the PR gate: npx create-quiver check-pr specs/${projectSlug}/slices/${sliceId}/slice.json`);
|
|
2342
2465
|
} else {
|
|
2343
|
-
|
|
2466
|
+
suggestedFixes.push('Create real specs and slices only after acceptance criteria are approved and the technical plan is reviewed and approved.');
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
const errors = checks.filter((check) => check.status === 'error').map((check) => check.message);
|
|
2470
|
+
const warnings = checks.filter((check) => check.status === 'warning').map((check) => check.message);
|
|
2471
|
+
const status = errors.length > 0 ? 'error' : warnings.length > 0 ? 'warning' : 'ok';
|
|
2472
|
+
|
|
2473
|
+
return {
|
|
2474
|
+
schema_version: 1,
|
|
2475
|
+
command: 'doctor',
|
|
2476
|
+
project_root: projectRoot,
|
|
2477
|
+
status,
|
|
2478
|
+
exit_code: errors.length > 0 ? 1 : 0,
|
|
2479
|
+
layout: doctorReport.layout,
|
|
2480
|
+
specs: specSlugs,
|
|
2481
|
+
legacy_signals: doctorReport.legacySignals,
|
|
2482
|
+
checks,
|
|
2483
|
+
suggested_fixes: uniqueLines(suggestedFixes),
|
|
2484
|
+
warnings,
|
|
2485
|
+
errors: migrationProblems.length > 0 ? uniqueLines([...migrationProblems, ...errors]) : errors,
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
function formatDoctorHumanReport(report, options = {}) {
|
|
2490
|
+
const lines = [];
|
|
2491
|
+
const ux = createUx({
|
|
2492
|
+
...options,
|
|
2493
|
+
spinner: false,
|
|
2494
|
+
write: (text) => lines.push(String(text)),
|
|
2495
|
+
});
|
|
2496
|
+
const symbolForStatus = (status) => {
|
|
2497
|
+
if (status === 'ok') return ux.theme.symbols.success;
|
|
2498
|
+
if (status === 'error') return ux.theme.symbols.error;
|
|
2499
|
+
return ux.theme.symbols.warning;
|
|
2500
|
+
};
|
|
2501
|
+
const colorForStatus = (status) => {
|
|
2502
|
+
if (status === 'ok') return 'success';
|
|
2503
|
+
if (status === 'error') return 'error';
|
|
2504
|
+
return 'warning';
|
|
2505
|
+
};
|
|
2506
|
+
|
|
2507
|
+
ux.section('Quiver Doctor');
|
|
2508
|
+
ux.line('');
|
|
2509
|
+
ux.line('Checks');
|
|
2510
|
+
for (const check of report.checks) {
|
|
2511
|
+
const line = ` ${symbolForStatus(check.status)} ${check.message}`;
|
|
2512
|
+
ux.line(ux.mode.decoration ? ux.theme.status(colorForStatus(check.status), line) : line);
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
ux.line('');
|
|
2516
|
+
ux.line('Suggested fixes');
|
|
2517
|
+
for (const fix of report.suggested_fixes) {
|
|
2518
|
+
const line = ` ${ux.theme.symbols.bullet} ${fix}`;
|
|
2519
|
+
ux.line(ux.mode.decoration ? ux.theme.status('command', line) : line);
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
return lines.join('');
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
const METHODOLOGY_OPTIONS = Object.freeze([
|
|
2526
|
+
{
|
|
2527
|
+
label: 'WDD + SDD',
|
|
2528
|
+
value: 'wdd-sdd',
|
|
2529
|
+
hint: 'Workflow Driven Development + Spec Driven Development',
|
|
2530
|
+
default: true,
|
|
2531
|
+
},
|
|
2532
|
+
]);
|
|
2533
|
+
|
|
2534
|
+
const INIT_MODE_OPTIONS = Object.freeze([
|
|
2535
|
+
{
|
|
2536
|
+
label: 'Proyecto existente',
|
|
2537
|
+
value: 'existing',
|
|
2538
|
+
hint: 'Agrega Quiver sin sobrescribir archivos existentes',
|
|
2539
|
+
default: true,
|
|
2540
|
+
},
|
|
2541
|
+
{
|
|
2542
|
+
label: 'Proyecto nuevo',
|
|
2543
|
+
value: 'new',
|
|
2544
|
+
hint: 'Crea el contrato base en una carpeta nueva o vacia',
|
|
2545
|
+
},
|
|
2546
|
+
{
|
|
2547
|
+
label: 'Solo validar estructura',
|
|
2548
|
+
value: 'validate',
|
|
2549
|
+
hint: 'Ejecuta Doctor en lugar de escribir archivos',
|
|
2550
|
+
},
|
|
2551
|
+
]);
|
|
2552
|
+
|
|
2553
|
+
const INIT_PROFILE_OPTIONS = Object.freeze([
|
|
2554
|
+
{
|
|
2555
|
+
label: 'Default',
|
|
2556
|
+
value: 'default',
|
|
2557
|
+
hint: 'Contrato AI-first recomendado',
|
|
2558
|
+
default: true,
|
|
2559
|
+
},
|
|
2560
|
+
{
|
|
2561
|
+
label: 'Minimal',
|
|
2562
|
+
value: 'minimal',
|
|
2563
|
+
hint: 'Solo documentos esenciales',
|
|
2564
|
+
},
|
|
2565
|
+
{
|
|
2566
|
+
label: 'Full compatibility',
|
|
2567
|
+
value: 'full',
|
|
2568
|
+
hint: 'Incluye compatibilidad historica y templates visibles',
|
|
2569
|
+
},
|
|
2570
|
+
]);
|
|
2571
|
+
|
|
2572
|
+
function hasDirectoryContent(dirPath) {
|
|
2573
|
+
return fs.existsSync(dirPath)
|
|
2574
|
+
&& fs.statSync(dirPath).isDirectory()
|
|
2575
|
+
&& fs.readdirSync(dirPath).length > 0;
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
function assertSupportedMethodology(value) {
|
|
2579
|
+
const normalized = String(value || '').trim();
|
|
2580
|
+
if (!normalized) {
|
|
2581
|
+
return 'wdd-sdd';
|
|
2582
|
+
}
|
|
2583
|
+
if (normalized !== 'wdd-sdd') {
|
|
2584
|
+
throw new Error(formatError(`unsupported methodology '${normalized}'. Supported methodologies: wdd-sdd.`));
|
|
2585
|
+
}
|
|
2586
|
+
return normalized;
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
async function resolveInteractiveInitOptions(args, targetDir, projectName, options = {}) {
|
|
2590
|
+
const explicitMethodology = assertSupportedMethodology(args.methodology);
|
|
2591
|
+
|
|
2592
|
+
if (args.interactive !== true) {
|
|
2593
|
+
return {
|
|
2594
|
+
action: 'init',
|
|
2595
|
+
full: args.initFull,
|
|
2596
|
+
includeTemplates: args.initIncludeTemplates,
|
|
2597
|
+
legacyScripts: args.initLegacyScripts,
|
|
2598
|
+
methodology: explicitMethodology,
|
|
2599
|
+
minimal: args.initMinimal,
|
|
2600
|
+
projectName,
|
|
2601
|
+
};
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
const ux = createUx({
|
|
2605
|
+
env: options.env,
|
|
2606
|
+
input: options.input,
|
|
2607
|
+
interactive: true,
|
|
2608
|
+
noColor: args.noColor,
|
|
2609
|
+
output: options.output,
|
|
2610
|
+
promptConfirm: options.promptConfirm,
|
|
2611
|
+
stderrIsTTY: options.stderrIsTTY,
|
|
2612
|
+
stdinIsTTY: options.stdinIsTTY,
|
|
2613
|
+
stdoutIsTTY: options.stdoutIsTTY,
|
|
2614
|
+
write: options.write,
|
|
2615
|
+
});
|
|
2616
|
+
|
|
2617
|
+
if (!ux.mode.usePrompts) {
|
|
2618
|
+
throw new Error(formatError('init --interactive requires an interactive TTY. Use explicit flags such as --name, --minimal, --full, --legacy-scripts, --include-templates, or run doctor to validate structure.'));
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
const selectorOptions = {
|
|
2622
|
+
env: options.env,
|
|
2623
|
+
input: options.input,
|
|
2624
|
+
interactive: true,
|
|
2625
|
+
noColor: args.noColor,
|
|
2626
|
+
output: options.output,
|
|
2627
|
+
prompts: options.prompts,
|
|
2628
|
+
promptSelect: options.promptSelect,
|
|
2629
|
+
stderrIsTTY: options.stderrIsTTY,
|
|
2630
|
+
stdinIsTTY: options.stdinIsTTY,
|
|
2631
|
+
stdoutIsTTY: options.stdoutIsTTY,
|
|
2632
|
+
};
|
|
2633
|
+
|
|
2634
|
+
ux.heading('Bienvenido a Quiver');
|
|
2635
|
+
const selectedMode = await selectOption('¿Qué querés configurar?', INIT_MODE_OPTIONS, {
|
|
2636
|
+
...selectorOptions,
|
|
2637
|
+
defaultValue: hasDirectoryContent(targetDir) ? 'existing' : 'new',
|
|
2638
|
+
flag: 'init|doctor',
|
|
2639
|
+
name: 'init mode',
|
|
2640
|
+
});
|
|
2641
|
+
const selectedMethodology = await selectOption('¿Qué metodología vas a usar?', METHODOLOGY_OPTIONS, {
|
|
2642
|
+
...selectorOptions,
|
|
2643
|
+
defaultValue: explicitMethodology,
|
|
2644
|
+
flag: '--methodology',
|
|
2645
|
+
name: 'methodology',
|
|
2646
|
+
value: args.methodology || '',
|
|
2647
|
+
});
|
|
2648
|
+
|
|
2649
|
+
assertSupportedMethodology(selectedMethodology.value);
|
|
2650
|
+
|
|
2651
|
+
if (selectedMode.value === 'validate') {
|
|
2652
|
+
ux.summary([
|
|
2653
|
+
{ label: 'Modo', value: 'Solo validar estructura' },
|
|
2654
|
+
{ label: 'Metodologia', value: selectedMethodology.label },
|
|
2655
|
+
{ label: 'Comando equivalente', value: 'npx create-quiver doctor' },
|
|
2656
|
+
], { title: 'Configuracion elegida' });
|
|
2657
|
+
if (!args.force && !args.dryRun) {
|
|
2658
|
+
const confirmed = await ux.promptConfirm('Ejecutar Doctor ahora?', { initialValue: true });
|
|
2659
|
+
if (!confirmed) {
|
|
2660
|
+
throw new Error(formatError('init interactive validation declined. No files were written.'));
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
return {
|
|
2664
|
+
action: 'doctor',
|
|
2665
|
+
methodology: selectedMethodology.value,
|
|
2666
|
+
projectName,
|
|
2667
|
+
};
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
const defaultProfile = args.initFull ? 'full' : args.initMinimal ? 'minimal' : 'default';
|
|
2671
|
+
const selectedProfile = await selectOption('¿Qué contrato inicial querés crear?', INIT_PROFILE_OPTIONS, {
|
|
2672
|
+
...selectorOptions,
|
|
2673
|
+
defaultValue: defaultProfile,
|
|
2674
|
+
flag: '--minimal|--full',
|
|
2675
|
+
name: 'init profile',
|
|
2676
|
+
});
|
|
2677
|
+
const agentGuidance = await selectOption('¿Querés ver el próximo paso para perfiles de agentes?', [
|
|
2678
|
+
{
|
|
2679
|
+
label: 'Mostrar comandos sugeridos',
|
|
2680
|
+
value: 'show',
|
|
2681
|
+
hint: 'No guarda credenciales ni ejecuta proveedores',
|
|
2682
|
+
default: true,
|
|
2683
|
+
},
|
|
2684
|
+
{
|
|
2685
|
+
label: 'Omitir por ahora',
|
|
2686
|
+
value: 'skip',
|
|
2687
|
+
},
|
|
2688
|
+
], {
|
|
2689
|
+
...selectorOptions,
|
|
2690
|
+
defaultValue: 'show',
|
|
2691
|
+
flag: 'ai agent set',
|
|
2692
|
+
name: 'agent profile guidance',
|
|
2693
|
+
});
|
|
2694
|
+
const nextFlags = {
|
|
2695
|
+
full: selectedProfile.value === 'full',
|
|
2696
|
+
includeTemplates: args.initIncludeTemplates || selectedProfile.value === 'full',
|
|
2697
|
+
legacyScripts: args.initLegacyScripts,
|
|
2698
|
+
methodology: selectedMethodology.value,
|
|
2699
|
+
minimal: selectedProfile.value === 'minimal',
|
|
2700
|
+
projectName,
|
|
2701
|
+
};
|
|
2702
|
+
|
|
2703
|
+
ux.summary([
|
|
2704
|
+
{ label: 'Proyecto', value: projectName },
|
|
2705
|
+
{ label: 'Modo', value: selectedMode.label },
|
|
2706
|
+
{ label: 'Metodologia', value: selectedMethodology.label },
|
|
2707
|
+
{ label: 'Perfil', value: selectedProfile.label },
|
|
2708
|
+
{ label: 'Perfiles de agentes', value: agentGuidance.value === 'show' ? 'mostrar proximo paso' : 'omitir' },
|
|
2709
|
+
], { title: 'Configuracion elegida' });
|
|
2710
|
+
|
|
2711
|
+
if (agentGuidance.value === 'show') {
|
|
2712
|
+
ux.nextSteps([
|
|
2713
|
+
'npx create-quiver ai agent set planner --provider codex --model gpt-5.5 --dry-run',
|
|
2714
|
+
'npx create-quiver ai agent set executor --provider claude --model claude-sonnet-4-6 --dry-run',
|
|
2715
|
+
], { title: 'Despues de inicializar' });
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
if (!args.force && !args.dryRun) {
|
|
2719
|
+
const confirmed = await ux.promptConfirm(`Inicializar Quiver en ${targetDir}?`, { initialValue: true });
|
|
2720
|
+
if (!confirmed) {
|
|
2721
|
+
throw new Error(formatError('init interactive approval declined. No files were written.'));
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
return {
|
|
2726
|
+
action: 'init',
|
|
2727
|
+
...nextFlags,
|
|
2728
|
+
};
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
function runDoctor(targetDir, options = {}) {
|
|
2732
|
+
const projectRoot = resolveTargetRoot(process.cwd(), targetDir);
|
|
2733
|
+
|
|
2734
|
+
if (!fs.existsSync(projectRoot)) {
|
|
2735
|
+
throw new Error(formatError(`target directory does not exist: ${projectRoot}`));
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
if (!hasQuiverInitializationEvidence(projectRoot)) {
|
|
2739
|
+
throw new Error(formatError('doctor requires a project previously initialized by Quiver.\nRun init first: npx create-quiver --name "Project Name"'));
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2742
|
+
const fixPlan = buildDoctorFixPlan(projectRoot);
|
|
2743
|
+
if (options.fix) {
|
|
2744
|
+
if (options.dryRun) {
|
|
2745
|
+
if (options.json) {
|
|
2746
|
+
console.log(JSON.stringify({
|
|
2747
|
+
schema_version: 1,
|
|
2748
|
+
command: 'doctor fix',
|
|
2749
|
+
dry_run: true,
|
|
2750
|
+
fixes: fixPlan,
|
|
2751
|
+
}, null, 2));
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
console.log(formatDoctorFixPlan(fixPlan, { dryRun: true }));
|
|
2755
|
+
return;
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2758
|
+
applyDoctorFixPlan(projectRoot, fixPlan);
|
|
2759
|
+
if (!options.json) {
|
|
2760
|
+
console.log(formatDoctorFixPlan(fixPlan));
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
const commandReport = buildDoctorCommandReport(projectRoot);
|
|
2765
|
+
if (options.json) {
|
|
2766
|
+
console.log(JSON.stringify(commandReport, null, 2));
|
|
2767
|
+
} else {
|
|
2768
|
+
process.stdout.write(formatDoctorHumanReport(commandReport, {
|
|
2769
|
+
noColor: options.noColor,
|
|
2770
|
+
unicode: options.unicode,
|
|
2771
|
+
}));
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
if (commandReport.exit_code !== 0) {
|
|
2775
|
+
process.exitCode = commandReport.exit_code;
|
|
2344
2776
|
}
|
|
2345
2777
|
}
|
|
2346
2778
|
|
|
@@ -2410,7 +2842,7 @@ async function run(argv) {
|
|
|
2410
2842
|
|
|
2411
2843
|
if (args.mode === 'ai') {
|
|
2412
2844
|
if (!args.aiCommand) {
|
|
2413
|
-
throw new Error(formatError('missing ai subcommand. Use: npx create-quiver ai onboard | prepare-context | run | active-slice | status | resume | inspect | export | specs | slices | trace | plan | revise | repair-plan | review-plan | approve | approvals | agent | prompt-slice | execute-slice | execute-plan | doctor | pr'));
|
|
2845
|
+
throw new Error(formatError('missing ai subcommand. Use: npx create-quiver ai onboard | prepare-context | run | active-slice | status | resume | inspect | export | specs | slices | models | trace | plan | revise | repair-plan | review-plan | approve | approvals | agent | prompt-slice | execute-slice | execute-plan | doctor | pr'));
|
|
2414
2846
|
}
|
|
2415
2847
|
|
|
2416
2848
|
if (args.aiCommand === 'run') {
|
|
@@ -2483,10 +2915,23 @@ async function run(argv) {
|
|
|
2483
2915
|
return;
|
|
2484
2916
|
}
|
|
2485
2917
|
|
|
2918
|
+
if (args.aiCommand === 'models') {
|
|
2919
|
+
runAiModelsList({
|
|
2920
|
+
json: args.json,
|
|
2921
|
+
provider: args.aiProviderExplicit ? args.aiProvider : undefined,
|
|
2922
|
+
});
|
|
2923
|
+
return;
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2486
2926
|
if (args.aiCommand === 'agent') {
|
|
2487
|
-
runAiAgent(process.cwd(), {
|
|
2927
|
+
await runAiAgent(process.cwd(), {
|
|
2488
2928
|
command: args.aiAgentCommand,
|
|
2489
2929
|
context: args.aiContext || undefined,
|
|
2930
|
+
defaultProfile: args.aiDefaultProfile,
|
|
2931
|
+
displayName: args.aiDisplayName || undefined,
|
|
2932
|
+
id: args.aiProfileId || undefined,
|
|
2933
|
+
interactive: args.interactive,
|
|
2934
|
+
json: args.json,
|
|
2490
2935
|
label: args.aiLabel || undefined,
|
|
2491
2936
|
model: args.aiModel || undefined,
|
|
2492
2937
|
provider: args.aiProviderExplicit ? args.aiProvider : undefined,
|
|
@@ -2504,6 +2949,8 @@ async function run(argv) {
|
|
|
2504
2949
|
printPrompt: args.aiPrintPrompt,
|
|
2505
2950
|
provider: args.aiProvider,
|
|
2506
2951
|
providerExplicit: args.aiProviderExplicit,
|
|
2952
|
+
model: args.aiModel || undefined,
|
|
2953
|
+
plannerProfile: args.aiPlannerProfile || undefined,
|
|
2507
2954
|
role: args.aiRole,
|
|
2508
2955
|
timeout: args.aiTimeout,
|
|
2509
2956
|
});
|
|
@@ -2518,6 +2965,8 @@ async function run(argv) {
|
|
|
2518
2965
|
printPrompt: args.aiPrintPrompt,
|
|
2519
2966
|
provider: args.aiProvider,
|
|
2520
2967
|
providerExplicit: args.aiProviderExplicit,
|
|
2968
|
+
model: args.aiModel || undefined,
|
|
2969
|
+
plannerProfile: args.aiPlannerProfile || undefined,
|
|
2521
2970
|
review: args.review,
|
|
2522
2971
|
role: args.aiRole,
|
|
2523
2972
|
runId: args.aiRunId || undefined,
|
|
@@ -2536,6 +2985,8 @@ async function run(argv) {
|
|
|
2536
2985
|
printPrompt: args.aiPrintPrompt,
|
|
2537
2986
|
provider: args.aiProvider,
|
|
2538
2987
|
providerExplicit: args.aiProviderExplicit,
|
|
2988
|
+
model: args.aiModel || undefined,
|
|
2989
|
+
plannerProfile: args.aiPlannerProfile || undefined,
|
|
2539
2990
|
interactive: args.interactive,
|
|
2540
2991
|
review: args.review,
|
|
2541
2992
|
role: args.aiRole,
|
|
@@ -2555,6 +3006,8 @@ async function run(argv) {
|
|
|
2555
3006
|
printPrompt: args.aiPrintPrompt,
|
|
2556
3007
|
provider: args.aiProvider,
|
|
2557
3008
|
providerExplicit: args.aiProviderExplicit,
|
|
3009
|
+
model: args.aiModel || undefined,
|
|
3010
|
+
reviewerProfile: args.aiReviewerProfile || undefined,
|
|
2558
3011
|
timeout: args.aiTimeout,
|
|
2559
3012
|
});
|
|
2560
3013
|
return;
|
|
@@ -2568,6 +3021,8 @@ async function run(argv) {
|
|
|
2568
3021
|
printPrompt: args.aiPrintPrompt,
|
|
2569
3022
|
provider: args.aiProvider,
|
|
2570
3023
|
providerExplicit: args.aiProviderExplicit,
|
|
3024
|
+
model: args.aiModel || undefined,
|
|
3025
|
+
plannerProfile: args.aiPlannerProfile || undefined,
|
|
2571
3026
|
role: args.aiRole,
|
|
2572
3027
|
runId: args.aiRunId || undefined,
|
|
2573
3028
|
timeout: args.aiTimeout,
|
|
@@ -2584,6 +3039,8 @@ async function run(argv) {
|
|
|
2584
3039
|
printPrompt: args.aiPrintPrompt,
|
|
2585
3040
|
provider: args.aiProvider,
|
|
2586
3041
|
providerExplicit: args.aiProviderExplicit,
|
|
3042
|
+
model: args.aiModel || undefined,
|
|
3043
|
+
plannerProfile: args.aiPlannerProfile || undefined,
|
|
2587
3044
|
role: args.aiRole,
|
|
2588
3045
|
runId: args.aiRunId || undefined,
|
|
2589
3046
|
timeout: args.aiTimeout,
|
|
@@ -2613,6 +3070,9 @@ async function run(argv) {
|
|
|
2613
3070
|
commit: args.aiCommit,
|
|
2614
3071
|
context: args.aiContext || undefined,
|
|
2615
3072
|
dryRun: args.dryRun,
|
|
3073
|
+
executorProfile: args.aiExecutorProfile || undefined,
|
|
3074
|
+
interactive: args.interactive,
|
|
3075
|
+
model: args.aiModel || undefined,
|
|
2616
3076
|
provider: args.aiProvider,
|
|
2617
3077
|
providerExplicit: args.aiProviderExplicit,
|
|
2618
3078
|
role: args.aiRole,
|
|
@@ -2636,7 +3096,10 @@ async function run(argv) {
|
|
|
2636
3096
|
context: args.aiContext || undefined,
|
|
2637
3097
|
dryRun: args.dryRun,
|
|
2638
3098
|
execute: args.aiExecute,
|
|
3099
|
+
executorProfile: args.aiExecutorProfile || undefined,
|
|
3100
|
+
interactive: args.interactive,
|
|
2639
3101
|
json: args.json,
|
|
3102
|
+
model: args.aiModel || undefined,
|
|
2640
3103
|
mode: args.aiExecutionMode,
|
|
2641
3104
|
provider: args.aiProvider,
|
|
2642
3105
|
providerExplicit: args.aiProviderExplicit,
|
|
@@ -2673,7 +3136,7 @@ async function run(argv) {
|
|
|
2673
3136
|
return;
|
|
2674
3137
|
}
|
|
2675
3138
|
|
|
2676
|
-
throw new Error(formatError(`unsupported ai subcommand: ${args.aiCommand}. Supported tasks: onboard, prepare-context, run, active-slice, status, resume, inspect, export, specs, slices, trace, plan, revise, repair-plan, review-plan, approve, approvals, agent, prompt-slice, execute-slice, execute-plan, doctor, pr`));
|
|
3139
|
+
throw new Error(formatError(`unsupported ai subcommand: ${args.aiCommand}. Supported tasks: onboard, prepare-context, run, active-slice, status, resume, inspect, export, specs, slices, models, trace, plan, revise, repair-plan, review-plan, approve, approvals, agent, prompt-slice, execute-slice, execute-plan, doctor, pr`));
|
|
2677
3140
|
}
|
|
2678
3141
|
|
|
2679
3142
|
if (args.mode === 'graph') {
|
|
@@ -2734,6 +3197,9 @@ async function run(argv) {
|
|
|
2734
3197
|
runDoctor(args.targetDir, {
|
|
2735
3198
|
dryRun: args.dryRun,
|
|
2736
3199
|
fix: args.doctorFix,
|
|
3200
|
+
json: args.json,
|
|
3201
|
+
noColor: args.noColor,
|
|
3202
|
+
unicode: args.unicode,
|
|
2737
3203
|
});
|
|
2738
3204
|
return;
|
|
2739
3205
|
}
|
|
@@ -2809,6 +3275,7 @@ async function run(argv) {
|
|
|
2809
3275
|
dryRun: args.dryRun,
|
|
2810
3276
|
input: args.aiInput || undefined,
|
|
2811
3277
|
interactive: args.interactive,
|
|
3278
|
+
methodology: args.methodology || undefined,
|
|
2812
3279
|
review: args.review,
|
|
2813
3280
|
specSlug: args.specSlug || undefined,
|
|
2814
3281
|
withPlanner: args.withPlanner,
|
|
@@ -2859,14 +3326,25 @@ async function run(argv) {
|
|
|
2859
3326
|
const packageRoot = path.resolve(__dirname, '../..');
|
|
2860
3327
|
const targetDir = resolveTargetRoot(process.cwd(), args.targetDir);
|
|
2861
3328
|
const projectName = args.projectName || path.basename(targetDir) || 'Quiver Project';
|
|
3329
|
+
const initOptions = await resolveInteractiveInitOptions(args, targetDir, projectName);
|
|
3330
|
+
if (initOptions.action === 'doctor') {
|
|
3331
|
+
runDoctor(targetDir, {
|
|
3332
|
+
dryRun: args.dryRun,
|
|
3333
|
+
fix: false,
|
|
3334
|
+
json: args.json,
|
|
3335
|
+
noColor: args.noColor,
|
|
3336
|
+
unicode: args.unicode,
|
|
3337
|
+
});
|
|
3338
|
+
return;
|
|
3339
|
+
}
|
|
2862
3340
|
const initLayout = buildInitLayout(targetDir, {
|
|
2863
3341
|
compatibilityAlias: !args.explicitInit,
|
|
2864
3342
|
dryRun: args.dryRun,
|
|
2865
|
-
full:
|
|
2866
|
-
includeTemplates:
|
|
2867
|
-
legacyScripts:
|
|
2868
|
-
minimal:
|
|
2869
|
-
projectName,
|
|
3343
|
+
full: initOptions.full,
|
|
3344
|
+
includeTemplates: initOptions.includeTemplates,
|
|
3345
|
+
legacyScripts: initOptions.legacyScripts,
|
|
3346
|
+
minimal: initOptions.minimal,
|
|
3347
|
+
projectName: initOptions.projectName,
|
|
2870
3348
|
skipInstall: args.skipInstall,
|
|
2871
3349
|
});
|
|
2872
3350
|
|
|
@@ -2884,9 +3362,9 @@ async function run(argv) {
|
|
|
2884
3362
|
if (initLayout.profile === 'full') {
|
|
2885
3363
|
exportTemplatesToLegacyRoot(templateRoot, targetDir);
|
|
2886
3364
|
}
|
|
2887
|
-
runInitDocs(targetDir, projectName, {
|
|
2888
|
-
includeTemplates:
|
|
2889
|
-
legacyScripts:
|
|
3365
|
+
runInitDocs(targetDir, initOptions.projectName, {
|
|
3366
|
+
includeTemplates: initOptions.includeTemplates,
|
|
3367
|
+
legacyScripts: initOptions.legacyScripts,
|
|
2890
3368
|
profile: initLayout.profile,
|
|
2891
3369
|
templateRoot,
|
|
2892
3370
|
});
|
|
@@ -2901,13 +3379,14 @@ async function run(argv) {
|
|
|
2901
3379
|
}
|
|
2902
3380
|
|
|
2903
3381
|
console.log(`Installed Quiver into ${targetDir}`);
|
|
2904
|
-
printInitNextSteps(targetDir, projectName);
|
|
3382
|
+
printInitNextSteps(targetDir, initOptions.projectName);
|
|
2905
3383
|
} finally {
|
|
2906
3384
|
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
2907
3385
|
}
|
|
2908
3386
|
}
|
|
2909
3387
|
|
|
2910
3388
|
module.exports = {
|
|
3389
|
+
resolveInteractiveInitOptions,
|
|
2911
3390
|
runAnalyze,
|
|
2912
3391
|
runDoctor,
|
|
2913
3392
|
runFlow,
|