create-quiver 0.17.0 → 0.17.2

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.
Files changed (86) hide show
  1. package/ACTIVE_SLICES.md +43 -0
  2. package/CHANGELOG.md +8 -0
  3. package/auditoria-ux-ui-performance-documentacion.md +705 -0
  4. package/copys-landing-page.md +244 -0
  5. package/docs/TROUBLESHOOTING.md +53 -0
  6. package/docs/reference/commands.md +42 -0
  7. package/docs/workflows/existing-project-ai-quiver-setup.md +552 -0
  8. package/docs/workflows/existing-project.md +21 -0
  9. package/package.json +1 -1
  10. package/specs/quiver-v43-cli-i18n-audit-release-readiness/command-language-mode-matrix.json +1 -0
  11. package/specs/quiver-v53-reliable-deep-project-analysis/EVIDENCE_REPORT.md +151 -0
  12. package/specs/quiver-v53-reliable-deep-project-analysis/EXECUTION_PLAN.md +50 -0
  13. package/specs/quiver-v53-reliable-deep-project-analysis/SPEC.md +207 -0
  14. package/specs/quiver-v53-reliable-deep-project-analysis/STATUS.md +32 -0
  15. package/specs/quiver-v53-reliable-deep-project-analysis/pr.md +73 -0
  16. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-00-analysis-run-contract/CLOSURE_BRIEF.md +32 -0
  17. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-00-analysis-run-contract/EXECUTION_BRIEF.md +63 -0
  18. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-00-analysis-run-contract/slice.json +70 -0
  19. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-01-provider-fixture-harness/CLOSURE_BRIEF.md +38 -0
  20. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-01-provider-fixture-harness/EXECUTION_BRIEF.md +60 -0
  21. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-01-provider-fixture-harness/slice.json +74 -0
  22. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-02-safe-context-boundary/CLOSURE_BRIEF.md +33 -0
  23. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-02-safe-context-boundary/EXECUTION_BRIEF.md +68 -0
  24. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-02-safe-context-boundary/slice.json +85 -0
  25. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-03-schema-error-grouping/CLOSURE_BRIEF.md +34 -0
  26. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-03-schema-error-grouping/EXECUTION_BRIEF.md +65 -0
  27. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-03-schema-error-grouping/slice.json +80 -0
  28. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-04-safe-repair-layer/CLOSURE_BRIEF.md +34 -0
  29. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-04-safe-repair-layer/EXECUTION_BRIEF.md +63 -0
  30. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-04-safe-repair-layer/slice.json +80 -0
  31. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-05-controlled-retry-layer/CLOSURE_BRIEF.md +34 -0
  32. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-05-controlled-retry-layer/EXECUTION_BRIEF.md +65 -0
  33. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-05-controlled-retry-layer/slice.json +81 -0
  34. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-06-audit-review-transaction/CLOSURE_BRIEF.md +35 -0
  35. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-06-audit-review-transaction/EXECUTION_BRIEF.md +71 -0
  36. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-06-audit-review-transaction/slice.json +88 -0
  37. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-07-semantic-validation-docs/CLOSURE_BRIEF.md +32 -0
  38. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-07-semantic-validation-docs/EXECUTION_BRIEF.md +66 -0
  39. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-07-semantic-validation-docs/slice.json +86 -0
  40. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-08-structural-map-hardening/CLOSURE_BRIEF.md +34 -0
  41. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-08-structural-map-hardening/EXECUTION_BRIEF.md +67 -0
  42. package/specs/quiver-v53-reliable-deep-project-analysis/slices/slice-08-structural-map-hardening/slice.json +81 -0
  43. package/specs/quiver-v54-deep-project-analysis-hardening/EVIDENCE_REPORT.md +53 -0
  44. package/specs/quiver-v54-deep-project-analysis-hardening/EXECUTION_PLAN.md +55 -0
  45. package/specs/quiver-v54-deep-project-analysis-hardening/SPEC.md +184 -0
  46. package/specs/quiver-v54-deep-project-analysis-hardening/STATUS.md +34 -0
  47. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-01-contract-regression-harness/CLOSURE_BRIEF.md +10 -0
  48. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-01-contract-regression-harness/EXECUTION_BRIEF.md +54 -0
  49. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-01-contract-regression-harness/slice.json +72 -0
  50. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-02-safe-discovery-sampling/CLOSURE_BRIEF.md +11 -0
  51. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-02-safe-discovery-sampling/EXECUTION_BRIEF.md +53 -0
  52. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-02-safe-discovery-sampling/slice.json +69 -0
  53. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-03-run-lifecycle-cli-io/CLOSURE_BRIEF.md +10 -0
  54. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-03-run-lifecycle-cli-io/EXECUTION_BRIEF.md +53 -0
  55. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-03-run-lifecycle-cli-io/slice.json +69 -0
  56. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-04-artifact-store-redaction/CLOSURE_BRIEF.md +10 -0
  57. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-04-artifact-store-redaction/EXECUTION_BRIEF.md +54 -0
  58. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-04-artifact-store-redaction/slice.json +73 -0
  59. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-05-path-aware-repair-engine/CLOSURE_BRIEF.md +10 -0
  60. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-05-path-aware-repair-engine/EXECUTION_BRIEF.md +57 -0
  61. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-05-path-aware-repair-engine/slice.json +72 -0
  62. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-06-retry-controller/CLOSURE_BRIEF.md +9 -0
  63. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-06-retry-controller/EXECUTION_BRIEF.md +52 -0
  64. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-06-retry-controller/slice.json +70 -0
  65. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-07-final-validation-review-write-gate/CLOSURE_BRIEF.md +10 -0
  66. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-07-final-validation-review-write-gate/EXECUTION_BRIEF.md +57 -0
  67. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-07-final-validation-review-write-gate/slice.json +75 -0
  68. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-08-doctor-agents-guidance/CLOSURE_BRIEF.md +9 -0
  69. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-08-doctor-agents-guidance/EXECUTION_BRIEF.md +51 -0
  70. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-08-doctor-agents-guidance/slice.json +66 -0
  71. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-09-release-smoke-rollback-docs/CLOSURE_BRIEF.md +10 -0
  72. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-09-release-smoke-rollback-docs/EXECUTION_BRIEF.md +54 -0
  73. package/specs/quiver-v54-deep-project-analysis-hardening/slices/slice-09-release-smoke-rollback-docs/slice.json +69 -0
  74. package/src/create-quiver/commands/ai.js +383 -34
  75. package/src/create-quiver/index.js +3 -0
  76. package/src/create-quiver/lib/ai/analyze-project-discovery.js +213 -2
  77. package/src/create-quiver/lib/ai/analyze-project-docs.js +3 -1
  78. package/src/create-quiver/lib/ai/analyze-project-parser.js +1 -0
  79. package/src/create-quiver/lib/ai/analyze-project-prompts.js +130 -0
  80. package/src/create-quiver/lib/ai/analyze-project-repair.js +402 -0
  81. package/src/create-quiver/lib/ai/analyze-project-sampling.js +31 -4
  82. package/src/create-quiver/lib/ai/analyze-project-validation.js +168 -0
  83. package/src/create-quiver/lib/ai/artifacts.js +83 -2
  84. package/src/create-quiver/lib/doctor.js +107 -12
  85. package/src/create-quiver/lib/i18n/messages/en.js +6 -0
  86. package/src/create-quiver/lib/i18n/messages/es.js +6 -0
@@ -22,8 +22,16 @@ const {
22
22
  formatAnalyzeProjectDiffPreview,
23
23
  writeAnalyzeProjectDocs,
24
24
  } = require('../lib/ai/analyze-project-docs');
25
- const { parseAnalyzeProjectOutput } = require('../lib/ai/analyze-project-parser');
26
- const { buildAnalyzeProjectPrompt } = require('../lib/ai/analyze-project-prompts');
25
+ const {
26
+ buildAnalyzeProjectPrompt,
27
+ buildAnalyzeProjectRetryPrompt,
28
+ buildSelectedContextManifest,
29
+ writeSelectedContextManifest,
30
+ } = require('../lib/ai/analyze-project-prompts');
31
+ const {
32
+ parseAnalyzeProjectOutputWithRepair,
33
+ writeAnalyzeProjectRepairManifest,
34
+ } = require('../lib/ai/analyze-project-repair');
27
35
  const {
28
36
  confirmAnalyzeProjectWrites,
29
37
  reviewAnalyzeProjectDocProposal,
@@ -33,7 +41,12 @@ const {
33
41
  DEFAULT_MAX_FILES: DEFAULT_ANALYZE_MAX_FILES,
34
42
  sampleProjectFiles,
35
43
  } = require('../lib/ai/analyze-project-sampling');
36
- const { validateAnalyzeProjectPostWrite } = require('../lib/ai/analyze-project-validation');
44
+ const {
45
+ groupAnalyzeProjectIssues,
46
+ validateAnalyzeProjectPostWrite,
47
+ writeAnalyzeProjectRetryManifest,
48
+ writeAnalyzeProjectValidationManifest,
49
+ } = require('../lib/ai/analyze-project-validation');
37
50
  const { openEditor } = require('../lib/cli/editor');
38
51
  const { selectOption, promptText } = require('../lib/cli/selectors');
39
52
  const { createUx } = require('../lib/cli/ux');
@@ -165,6 +178,53 @@ function limitList(items, maxItems = 30) {
165
178
  };
166
179
  }
167
180
 
181
+ function formatAnalyzeProjectIssues(issues = [], maxIssues = 8) {
182
+ const groups = groupAnalyzeProjectIssues(issues, { maxExamplesPerGroup: 1 });
183
+ const visible = groups.slice(0, maxIssues);
184
+ const lines = visible.map((group) => {
185
+ const example = group.examples[0];
186
+ const exampleText = example
187
+ ? ` Example: ${example.path || 'analysis'} - ${example.message}`
188
+ : '';
189
+ return `- ${group.path_family}: ${group.type} (${group.count} issue${group.count === 1 ? '' : 's'}). Cause: ${group.cause_hint}${exampleText}`;
190
+ });
191
+ const hidden = groups.length - visible.length;
192
+ if (hidden > 0) {
193
+ lines.push(`- ... ${hidden} more issue group${hidden === 1 ? '' : 's'}`);
194
+ }
195
+ return lines;
196
+ }
197
+
198
+ function enhanceAnalyzeProjectAnalysisError(error, options = {}) {
199
+ if (!error || error.code !== 'AI_ANALYZE_PROJECT_INVALID') {
200
+ return error;
201
+ }
202
+
203
+ const issueLines = formatAnalyzeProjectIssues(error.issues);
204
+ if (issueLines.length === 0) {
205
+ return error;
206
+ }
207
+
208
+ const wrapped = new Error([
209
+ error.message,
210
+ 'Issues:',
211
+ ...issueLines,
212
+ options.repairManifest?.path ? `Repair manifest: ${options.repairManifest.path}` : '',
213
+ options.retryManifest?.path ? `Retry manifest: ${options.retryManifest.path}` : '',
214
+ options.validationManifest?.path ? `Validation manifest: ${options.validationManifest.path}` : '',
215
+ 'Next safe step: inspect the selected evidence with `npx create-quiver ai analyze-project --deep --dry-run --json`, then rerun live. If provider drift repeats, reduce --max-files or --max-bytes.',
216
+ ].filter(Boolean).join('\n'));
217
+ wrapped.name = error.name;
218
+ wrapped.code = error.code;
219
+ wrapped.cause = error;
220
+ wrapped.issues = error.issues;
221
+ wrapped.details = error.issues;
222
+ wrapped.repair_manifest = options.repairManifest || null;
223
+ wrapped.retry_manifest = options.retryManifest || null;
224
+ wrapped.validation_manifest = options.validationManifest || null;
225
+ return wrapped;
226
+ }
227
+
168
228
  function formatAnalyzeProjectFileLine(file) {
169
229
  const details = [];
170
230
  if (Array.isArray(file.signals) && file.signals.length > 0) {
@@ -211,6 +271,9 @@ function formatAnalyzeProjectReport(report) {
211
271
  lines.push(`Source roots: ${report.detected.source_roots.length > 0 ? report.detected.source_roots.join(', ') : 'none'}`);
212
272
  lines.push(`Entrypoints: ${report.detected.entrypoints.length > 0 ? report.detected.entrypoints.join(', ') : 'none'}`);
213
273
  lines.push(`Configs: ${report.detected.configs.length > 0 ? report.detected.configs.join(', ') : 'none'}`);
274
+ lines.push(`Lockfiles: ${(report.detected.lockfiles || []).length > 0
275
+ ? report.detected.lockfiles.map((file) => `${file.path} (${file.package_manager}; metadata only)`).join(', ')
276
+ : 'none'}`);
214
277
 
215
278
  lines.push('', 'Selected files:');
216
279
  for (const file of selected.items) {
@@ -357,6 +420,60 @@ function buildAnalyzeProjectProviderArtifact(result, clean, repoRoot, options =
357
420
  };
358
421
  }
359
422
 
423
+ function createAnalyzeProjectAuditRunId(now = new Date()) {
424
+ const date = now instanceof Date ? now : new Date(now || Date.now());
425
+ return `run-${date.toISOString()
426
+ .replace(/\.\d{3}Z$/, 'z')
427
+ .replace(/[^0-9a-z]+/gi, '-')
428
+ .toLowerCase()
429
+ .replace(/^-+|-+$/g, '')}`;
430
+ }
431
+
432
+ function writeAnalyzeProjectRunStatus(repoRoot, runId, status, details = {}) {
433
+ const statusPath = path.join(repoRoot, '.quiver', 'runs', runId, 'status.json');
434
+ fs.mkdirSync(path.dirname(statusPath), { recursive: true });
435
+ fs.writeFileSync(statusPath, `${JSON.stringify({
436
+ schema_version: 1,
437
+ kind: 'quiver-analyze-project-run-status',
438
+ run_id: runId,
439
+ status,
440
+ updated_at: (details.now instanceof Date ? details.now : new Date(details.now || Date.now())).toISOString(),
441
+ provider: details.provider || null,
442
+ attempts: details.attempts || [],
443
+ artifacts: details.artifacts || {},
444
+ }, null, 2)}\n`);
445
+ return path.relative(repoRoot, statusPath).split(path.sep).join('/');
446
+ }
447
+
448
+ function normalizeAnalyzeProjectMaxRetries(value) {
449
+ if (value === undefined || value === null || value === '') {
450
+ return 1;
451
+ }
452
+ const parsed = Number(value);
453
+ if (!Number.isFinite(parsed) || parsed < 0) {
454
+ return 1;
455
+ }
456
+ return Math.min(2, Math.floor(parsed));
457
+ }
458
+
459
+ function isAnalyzeProjectRetryableError(error) {
460
+ if (!error || error.code !== 'AI_ANALYZE_PROJECT_INVALID') {
461
+ return false;
462
+ }
463
+ const retryableIssues = new Set([
464
+ 'empty-output',
465
+ 'malformed-json',
466
+ 'invalid_type',
467
+ 'invalid_value',
468
+ 'unrecognized_keys',
469
+ 'missing-evidence',
470
+ 'evidence-not-selected',
471
+ 'unapproved-doc-update-path',
472
+ ]);
473
+ const issues = Array.isArray(error.issues) ? error.issues : [];
474
+ return issues.length > 0 && issues.every((issue) => retryableIssues.has(issue.issue || ''));
475
+ }
476
+
360
477
  function formatAnalyzeProjectLiveReport(report) {
361
478
  const warningCount = report.analysis_validation?.warnings?.length || 0;
362
479
  const docUpdatePaths = report.analysis_validation?.doc_update_paths || [];
@@ -365,6 +482,7 @@ function formatAnalyzeProjectLiveReport(report) {
365
482
  `Mode: ${report.mode}`,
366
483
  `Provider: ${report.provider}`,
367
484
  `Provider execution: ${report.provider_execution}`,
485
+ `Provider attempts: ${report.provider_attempts?.length || 1}`,
368
486
  `Writes: ${report.writes.length === 0 ? 'none' : report.writes.join(', ')}`,
369
487
  `Privacy preflight: ${report.privacy_preflight.ok ? 'passed' : 'failed'}`,
370
488
  `Prompt bytes: ${report.prompt.bytes}/${report.prompt.max_provider_prompt_bytes}`,
@@ -569,7 +687,8 @@ function shouldShowHumanProgress(ux, options = {}) {
569
687
  return options.progress !== false
570
688
  && options.dryRun !== true
571
689
  && options.printPrompt !== true
572
- && ux?.mode?.decoration === true;
690
+ && ux?.mode?.json !== true
691
+ && (ux?.mode?.decoration === true || options.linearProgress === true);
573
692
  }
574
693
 
575
694
  function plannerProgressTitle(action, runtimeProfile, options = {}) {
@@ -590,10 +709,32 @@ function writeProgressChecks(ux, enabled, title, checks = []) {
590
709
  }
591
710
  }
592
711
 
593
- async function runProviderWithProgress({ ux, enabled, message = 'Running agent...', successMessage = 'Agent finished', failureMessage = 'Agent failed', run }) {
712
+ function writeProgressCheck(ux, enabled, check) {
713
+ if (!enabled || !check) {
714
+ return;
715
+ }
716
+ ux.check(check);
717
+ }
718
+
719
+ function writeProgressInfo(ux, enabled, message) {
720
+ if (!enabled || !message) {
721
+ return;
722
+ }
723
+ ux.info(message);
724
+ }
725
+
726
+ async function runProviderWithProgress({
727
+ ux,
728
+ enabled,
729
+ message = 'Running agent...',
730
+ successMessage = 'Agent finished',
731
+ failureMessage = 'Agent failed',
732
+ failOnProviderResult = true,
733
+ run,
734
+ }) {
594
735
  async function runAndFailOnProviderResult() {
595
736
  const result = await run();
596
- if (result && result.ok === false) {
737
+ if (failOnProviderResult && result && result.ok === false) {
597
738
  const error = new Error(result.error?.message || 'provider run failed');
598
739
  error.code = result.error?.code || 'AI_PROVIDER_RUN_FAILED';
599
740
  error.providerResult = result;
@@ -1869,6 +2010,22 @@ async function runPrepareContext(repoRoot, options = {}) {
1869
2010
  }
1870
2011
 
1871
2012
  async function runAnalyzeProject(repoRoot, options = {}) {
2013
+ const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
2014
+ const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_PLAN_PROVIDER);
2015
+ const provider = runtimeProfile.provider;
2016
+ const ux = createCommandUx(options);
2017
+ const showProgress = shouldShowHumanProgress(ux, { ...options, linearProgress: true });
2018
+ const progressTranslator = createTranslator(options.language);
2019
+ const progressTitle = plannerProgressTitle(
2020
+ progressTranslator.t('ai.planner.progress.analyze_project'),
2021
+ runtimeProfile,
2022
+ options,
2023
+ );
2024
+
2025
+ if (showProgress) {
2026
+ ux.heading(progressTitle);
2027
+ }
2028
+
1872
2029
  const report = buildAnalyzeProjectReport(repoRoot, options);
1873
2030
  if (options.dryRun === true) {
1874
2031
  if (options.json === true) {
@@ -1879,10 +2036,10 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1879
2036
  return report;
1880
2037
  }
1881
2038
 
1882
- const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
1883
- const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_PLAN_PROVIDER);
1884
- const provider = runtimeProfile.provider;
1885
2039
  const timeoutMs = normalizeTimeout(options.timeout);
2040
+ writeProgressCheck(ux, showProgress, progressTranslator.t('ai.planner.progress.reading_base_docs'));
2041
+ writeProgressCheck(ux, showProgress, progressTranslator.t('ai.planner.progress.detecting_structure'));
2042
+ writeProgressCheck(ux, showProgress, progressTranslator.t('ai.planner.progress.selecting_sample'));
1886
2043
  const promptPackage = buildAnalyzeProjectPrompt({
1887
2044
  analysisPlan: report,
1888
2045
  repoRoot,
@@ -1892,6 +2049,8 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1892
2049
  const prompt = promptPackage.prompt;
1893
2050
  const promptLimit = assertProviderPromptWithinLimit(prompt, options.promptLimitOptions || {});
1894
2051
  const privacyPreflight = promptPackage.privacyPreflight;
2052
+ const auditRunId = options.runId || createAnalyzeProjectAuditRunId(options.now || new Date());
2053
+ writeProgressCheck(ux, showProgress, progressTranslator.t('ai.planner.progress.preparing_prompt'));
1895
2054
 
1896
2055
  if (!privacyPreflight.ok) {
1897
2056
  const error = new Error(formatError('ai analyze-project privacy preflight failed; provider execution was blocked before sending repository content.'));
@@ -1929,34 +2088,216 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1929
2088
  };
1930
2089
  }
1931
2090
 
2091
+ const selectedContextManifest = writeSelectedContextManifest(
2092
+ repoRoot,
2093
+ buildSelectedContextManifest({
2094
+ analysisPlan: report,
2095
+ promptPackage,
2096
+ promptLimit,
2097
+ provider,
2098
+ runId: auditRunId,
2099
+ now: options.now,
2100
+ }),
2101
+ {
2102
+ runId: auditRunId,
2103
+ now: options.now,
2104
+ },
2105
+ );
2106
+
2107
+ const maxRetries = normalizeAnalyzeProjectMaxRetries(options.maxAnalyzeProjectRetries);
2108
+ const providerAttempts = [];
1932
2109
  let result;
1933
- try {
1934
- result = await (options.runProviderFn || runProvider)(provider, {
1935
- prompt,
1936
- cwd: repoRoot,
1937
- timeoutMs,
1938
- dryRun: false,
1939
- probe: options.probe,
1940
- spawn: options.spawn,
1941
- tempRoot: options.tempRoot,
1942
- tempFileName: options.tempFileName,
1943
- tempFilePrefix: options.tempFilePrefix,
1944
- ...runtimeModelExecutionOptions(runtimeProfile, options),
1945
- enforceModelSelection: false,
1946
- });
1947
- } catch (error) {
1948
- throw annotateProviderError(error, 'analyze-project');
1949
- }
2110
+ let clean;
2111
+ let parsed;
2112
+ let repairManifest = null;
2113
+ let retryManifest = null;
2114
+ let currentPrompt = prompt;
2115
+ const rawProviderArtifacts = [];
2116
+
2117
+ for (let attemptIndex = 0; attemptIndex <= maxRetries; attemptIndex += 1) {
2118
+ try {
2119
+ result = await runProviderWithProgress({
2120
+ ux,
2121
+ enabled: showProgress,
2122
+ message: attemptIndex === 0
2123
+ ? progressTranslator.t('ai.planner.progress.running_agent')
2124
+ : `Retrying agent (${attemptIndex}/${maxRetries})...`,
2125
+ successMessage: progressTranslator.t('ai.planner.progress.agent_finished'),
2126
+ failureMessage: progressTranslator.t('ai.planner.progress.agent_failed'),
2127
+ failOnProviderResult: false,
2128
+ run: () => (options.runProviderFn || runProvider)(provider, {
2129
+ prompt: currentPrompt,
2130
+ cwd: repoRoot,
2131
+ timeoutMs,
2132
+ dryRun: false,
2133
+ probe: options.probe,
2134
+ spawn: options.spawn,
2135
+ tempRoot: options.tempRoot,
2136
+ tempFileName: options.tempFileName,
2137
+ tempFilePrefix: options.tempFilePrefix,
2138
+ ...runtimeModelExecutionOptions(runtimeProfile, options),
2139
+ enforceModelSelection: false,
2140
+ }),
2141
+ });
2142
+ } catch (error) {
2143
+ throw annotateProviderError(error, 'analyze-project');
2144
+ }
1950
2145
 
1951
- if (!result.ok) {
1952
- throw annotateProviderError(result.error || new Error('provider run failed'), 'analyze-project');
1953
- }
2146
+ rawProviderArtifacts.push(writeRawProviderArtifact(repoRoot, auditRunId, `analyze-project-provider-attempt-${attemptIndex + 1}`, result, {
2147
+ now: options.now,
2148
+ metadata: {
2149
+ attempt: attemptIndex + 1,
2150
+ retry: attemptIndex > 0,
2151
+ },
2152
+ }));
2153
+ writeProgressCheck(ux, showProgress, progressTranslator.t('ai.planner.progress.writing_artifacts'));
2154
+ if (!result.ok) {
2155
+ writeProgressInfo(ux, showProgress, progressTranslator.t('ai.planner.progress.agent_failed'));
2156
+ writeAnalyzeProjectRunStatus(repoRoot, auditRunId, 'failed', {
2157
+ now: options.now,
2158
+ provider,
2159
+ attempts: [{
2160
+ attempt: attemptIndex + 1,
2161
+ status: 'provider-failed',
2162
+ retry: attemptIndex > 0,
2163
+ }],
2164
+ artifacts: {
2165
+ selected_context: selectedContextManifest,
2166
+ raw_provider: rawProviderArtifacts.map((artifact) => artifact.path),
2167
+ },
2168
+ });
2169
+ throw annotateProviderError(result.error || new Error('provider run failed'), 'analyze-project');
2170
+ }
1954
2171
 
1955
- const clean = extractCleanProviderOutput(result, { prompt, projectRoot: repoRoot });
1956
- const parsed = parseAnalyzeProjectOutput(clean.cleanOutput, {
1957
- selectedFiles: report.selected_files,
1958
- promptFiles: promptPackage.files,
1959
- });
2172
+ clean = extractCleanProviderOutput(result, { prompt: currentPrompt, projectRoot: repoRoot });
2173
+ try {
2174
+ parsed = parseAnalyzeProjectOutputWithRepair(clean.cleanOutput, {
2175
+ selectedFiles: report.selected_files,
2176
+ promptFiles: promptPackage.files,
2177
+ });
2178
+ writeProgressCheck(ux, showProgress, progressTranslator.t('ai.planner.progress.validating_schema'));
2179
+ if (parsed.repairManifest) {
2180
+ repairManifest = writeAnalyzeProjectRepairManifest(repoRoot, parsed.repairManifest, {
2181
+ runId: auditRunId,
2182
+ now: options.now,
2183
+ });
2184
+ writeProgressCheck(ux, showProgress, progressTranslator.t('ai.planner.progress.repairing_schema'));
2185
+ }
2186
+ providerAttempts.push({
2187
+ attempt: attemptIndex + 1,
2188
+ status: 'valid',
2189
+ retry: attemptIndex > 0,
2190
+ parse_source: parsed.parseSource,
2191
+ repaired: parsed.repaired === true,
2192
+ repair_manifest: repairManifest,
2193
+ });
2194
+ if (providerAttempts.length > 1) {
2195
+ retryManifest = writeAnalyzeProjectRetryManifest(repoRoot, {
2196
+ provider,
2197
+ command: 'ai analyze-project',
2198
+ runId: auditRunId,
2199
+ now: options.now,
2200
+ maxRetries,
2201
+ finalStatus: 'valid',
2202
+ attempts: providerAttempts,
2203
+ });
2204
+ }
2205
+ writeAnalyzeProjectRunStatus(repoRoot, auditRunId, 'completed', {
2206
+ now: options.now,
2207
+ provider,
2208
+ attempts: providerAttempts,
2209
+ artifacts: {
2210
+ selected_context: selectedContextManifest,
2211
+ raw_provider: rawProviderArtifacts.map((artifact) => artifact.path),
2212
+ repair: repairManifest,
2213
+ retry: retryManifest,
2214
+ },
2215
+ });
2216
+ break;
2217
+ } catch (error) {
2218
+ let attemptRepairManifest = null;
2219
+ if (error.repair_manifest) {
2220
+ try {
2221
+ attemptRepairManifest = writeAnalyzeProjectRepairManifest(repoRoot, error.repair_manifest, {
2222
+ runId: auditRunId,
2223
+ now: options.now,
2224
+ });
2225
+ } catch {
2226
+ attemptRepairManifest = null;
2227
+ }
2228
+ }
2229
+ const retryable = isAnalyzeProjectRetryableError(error);
2230
+ providerAttempts.push({
2231
+ attempt: attemptIndex + 1,
2232
+ status: 'invalid',
2233
+ retry: attemptIndex > 0,
2234
+ retryable,
2235
+ issue_count: Array.isArray(error.issues) ? error.issues.length : 0,
2236
+ groups: groupAnalyzeProjectIssues(error.issues, { maxExamplesPerGroup: 2 }),
2237
+ repair_manifest: attemptRepairManifest,
2238
+ });
2239
+
2240
+ if (retryable && attemptIndex < maxRetries) {
2241
+ writeProgressInfo(ux, showProgress, progressTranslator.t('ai.planner.progress.retrying_agent'));
2242
+ currentPrompt = buildAnalyzeProjectRetryPrompt({
2243
+ previousOutput: clean.cleanOutput,
2244
+ issueLines: formatAnalyzeProjectIssues(error.issues, 6),
2245
+ attempt: attemptIndex + 1,
2246
+ maxRetries,
2247
+ });
2248
+ continue;
2249
+ }
2250
+
2251
+ if (providerAttempts.length > 1) {
2252
+ retryManifest = writeAnalyzeProjectRetryManifest(repoRoot, {
2253
+ provider,
2254
+ command: 'ai analyze-project',
2255
+ runId: auditRunId,
2256
+ now: options.now,
2257
+ maxRetries,
2258
+ finalStatus: 'invalid',
2259
+ attempts: providerAttempts,
2260
+ });
2261
+ }
2262
+
2263
+ let validationManifest = null;
2264
+ try {
2265
+ validationManifest = writeAnalyzeProjectValidationManifest(repoRoot, {
2266
+ error,
2267
+ provider,
2268
+ command: 'ai analyze-project',
2269
+ runId: auditRunId,
2270
+ now: options.now,
2271
+ retry: {
2272
+ attempts: providerAttempts.length,
2273
+ max_retries: maxRetries,
2274
+ retryable,
2275
+ exhausted: retryable && attemptIndex >= maxRetries,
2276
+ manifest: retryManifest,
2277
+ },
2278
+ });
2279
+ } catch {
2280
+ validationManifest = null;
2281
+ }
2282
+ writeAnalyzeProjectRunStatus(repoRoot, auditRunId, 'failed', {
2283
+ now: options.now,
2284
+ provider,
2285
+ attempts: providerAttempts,
2286
+ artifacts: {
2287
+ selected_context: selectedContextManifest,
2288
+ raw_provider: rawProviderArtifacts.map((artifact) => artifact.path),
2289
+ repair: attemptRepairManifest,
2290
+ retry: retryManifest,
2291
+ validation: validationManifest,
2292
+ },
2293
+ });
2294
+ throw enhanceAnalyzeProjectAnalysisError(error, {
2295
+ validationManifest,
2296
+ repairManifest: attemptRepairManifest,
2297
+ retryManifest,
2298
+ });
2299
+ }
2300
+ }
1960
2301
  const completedReport = {
1961
2302
  ...report,
1962
2303
  provider,
@@ -1974,8 +2315,16 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1974
2315
  parse_source: parsed.parseSource,
1975
2316
  warnings: parsed.warnings,
1976
2317
  doc_update_paths: parsed.docUpdatePaths,
2318
+ repaired: parsed.repaired === true,
2319
+ repair_manifest: repairManifest,
2320
+ retry_count: Math.max(0, providerAttempts.length - 1),
2321
+ retry_manifest: retryManifest,
1977
2322
  },
1978
2323
  provider_artifact: buildAnalyzeProjectProviderArtifact(result, clean, repoRoot),
2324
+ raw_provider_artifacts: rawProviderArtifacts.map((artifact) => artifact.path),
2325
+ provider_attempts: providerAttempts,
2326
+ run_status_path: path.join('.quiver', 'runs', auditRunId, 'status.json').split(path.sep).join('/'),
2327
+ selected_context_manifest: selectedContextManifest,
1979
2328
  };
1980
2329
 
1981
2330
  if (options.review === true) {
@@ -2862,6 +2862,9 @@ function buildDoctorCommandReport(projectRoot) {
2862
2862
 
2863
2863
  const suggestedFixes = [
2864
2864
  ...doctorReport.recommendations,
2865
+ doctorReport.warnings.some((warning) => String(warning).includes('AGENTS.md'))
2866
+ ? 'Repair AGENTS.md contract: npx create-quiver doctor --fix --dry-run, then npx create-quiver doctor --fix'
2867
+ : '',
2865
2868
  !hasQuiverState
2866
2869
  ? 'Run migration first: npx create-quiver migrate'
2867
2870
  : !hasScanArtifacts