create-quiver 0.17.1 → 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 +4 -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 +353 -70
  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 +5 -0
  86. package/src/create-quiver/lib/i18n/messages/es.js +5 -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');
@@ -166,22 +179,23 @@ function limitList(items, maxItems = 30) {
166
179
  }
167
180
 
168
181
  function formatAnalyzeProjectIssues(issues = [], maxIssues = 8) {
169
- const list = Array.isArray(issues) ? issues : [];
170
- const visible = list.slice(0, maxIssues);
171
- const lines = visible.map((issue) => {
172
- const location = issue.path || 'analysis';
173
- const code = issue.issue || 'invalid';
174
- const message = issue.message || 'Invalid provider analysis output.';
175
- return `- ${location}: ${code} - ${message}`;
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}`;
176
190
  });
177
- const hidden = list.length - visible.length;
191
+ const hidden = groups.length - visible.length;
178
192
  if (hidden > 0) {
179
- lines.push(`- ... ${hidden} more issue${hidden === 1 ? '' : 's'}`);
193
+ lines.push(`- ... ${hidden} more issue group${hidden === 1 ? '' : 's'}`);
180
194
  }
181
195
  return lines;
182
196
  }
183
197
 
184
- function enhanceAnalyzeProjectAnalysisError(error) {
198
+ function enhanceAnalyzeProjectAnalysisError(error, options = {}) {
185
199
  if (!error || error.code !== 'AI_ANALYZE_PROJECT_INVALID') {
186
200
  return error;
187
201
  }
@@ -195,13 +209,19 @@ function enhanceAnalyzeProjectAnalysisError(error) {
195
209
  error.message,
196
210
  'Issues:',
197
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}` : '',
198
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.',
199
- ].join('\n'));
216
+ ].filter(Boolean).join('\n'));
200
217
  wrapped.name = error.name;
201
218
  wrapped.code = error.code;
202
219
  wrapped.cause = error;
203
220
  wrapped.issues = error.issues;
204
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;
205
225
  return wrapped;
206
226
  }
207
227
 
@@ -251,6 +271,9 @@ function formatAnalyzeProjectReport(report) {
251
271
  lines.push(`Source roots: ${report.detected.source_roots.length > 0 ? report.detected.source_roots.join(', ') : 'none'}`);
252
272
  lines.push(`Entrypoints: ${report.detected.entrypoints.length > 0 ? report.detected.entrypoints.join(', ') : 'none'}`);
253
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'}`);
254
277
 
255
278
  lines.push('', 'Selected files:');
256
279
  for (const file of selected.items) {
@@ -397,6 +420,60 @@ function buildAnalyzeProjectProviderArtifact(result, clean, repoRoot, options =
397
420
  };
398
421
  }
399
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
+
400
477
  function formatAnalyzeProjectLiveReport(report) {
401
478
  const warningCount = report.analysis_validation?.warnings?.length || 0;
402
479
  const docUpdatePaths = report.analysis_validation?.doc_update_paths || [];
@@ -405,6 +482,7 @@ function formatAnalyzeProjectLiveReport(report) {
405
482
  `Mode: ${report.mode}`,
406
483
  `Provider: ${report.provider}`,
407
484
  `Provider execution: ${report.provider_execution}`,
485
+ `Provider attempts: ${report.provider_attempts?.length || 1}`,
408
486
  `Writes: ${report.writes.length === 0 ? 'none' : report.writes.join(', ')}`,
409
487
  `Privacy preflight: ${report.privacy_preflight.ok ? 'passed' : 'failed'}`,
410
488
  `Prompt bytes: ${report.prompt.bytes}/${report.prompt.max_provider_prompt_bytes}`,
@@ -609,7 +687,8 @@ function shouldShowHumanProgress(ux, options = {}) {
609
687
  return options.progress !== false
610
688
  && options.dryRun !== true
611
689
  && options.printPrompt !== true
612
- && ux?.mode?.decoration === true;
690
+ && ux?.mode?.json !== true
691
+ && (ux?.mode?.decoration === true || options.linearProgress === true);
613
692
  }
614
693
 
615
694
  function plannerProgressTitle(action, runtimeProfile, options = {}) {
@@ -630,10 +709,32 @@ function writeProgressChecks(ux, enabled, title, checks = []) {
630
709
  }
631
710
  }
632
711
 
633
- 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
+ }) {
634
735
  async function runAndFailOnProviderResult() {
635
736
  const result = await run();
636
- if (result && result.ok === false) {
737
+ if (failOnProviderResult && result && result.ok === false) {
637
738
  const error = new Error(result.error?.message || 'provider run failed');
638
739
  error.code = result.error?.code || 'AI_PROVIDER_RUN_FAILED';
639
740
  error.providerResult = result;
@@ -1909,6 +2010,22 @@ async function runPrepareContext(repoRoot, options = {}) {
1909
2010
  }
1910
2011
 
1911
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
+
1912
2029
  const report = buildAnalyzeProjectReport(repoRoot, options);
1913
2030
  if (options.dryRun === true) {
1914
2031
  if (options.json === true) {
@@ -1919,13 +2036,10 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1919
2036
  return report;
1920
2037
  }
1921
2038
 
1922
- const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
1923
- const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_PLAN_PROVIDER);
1924
- const provider = runtimeProfile.provider;
1925
2039
  const timeoutMs = normalizeTimeout(options.timeout);
1926
- const ux = createCommandUx(options);
1927
- const showProgress = shouldShowHumanProgress(ux, options);
1928
- const progressTranslator = createTranslator(options.language);
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'));
1929
2043
  const promptPackage = buildAnalyzeProjectPrompt({
1930
2044
  analysisPlan: report,
1931
2045
  repoRoot,
@@ -1935,17 +2049,8 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1935
2049
  const prompt = promptPackage.prompt;
1936
2050
  const promptLimit = assertProviderPromptWithinLimit(prompt, options.promptLimitOptions || {});
1937
2051
  const privacyPreflight = promptPackage.privacyPreflight;
1938
-
1939
- writeProgressChecks(
1940
- ux,
1941
- showProgress,
1942
- plannerProgressTitle(progressTranslator.t('ai.planner.progress.analyze_project'), runtimeProfile, options),
1943
- [
1944
- progressTranslator.t('ai.planner.progress.reading_base_docs'),
1945
- progressTranslator.t('ai.planner.progress.detecting_structure'),
1946
- progressTranslator.t('ai.planner.progress.preparing_prompt'),
1947
- ],
1948
- );
2052
+ const auditRunId = options.runId || createAnalyzeProjectAuditRunId(options.now || new Date());
2053
+ writeProgressCheck(ux, showProgress, progressTranslator.t('ai.planner.progress.preparing_prompt'));
1949
2054
 
1950
2055
  if (!privacyPreflight.ok) {
1951
2056
  const error = new Error(formatError('ai analyze-project privacy preflight failed; provider execution was blocked before sending repository content.'));
@@ -1983,45 +2088,215 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1983
2088
  };
1984
2089
  }
1985
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 = [];
1986
2109
  let result;
1987
- try {
1988
- result = await runProviderWithProgress({
1989
- ux,
1990
- enabled: showProgress,
1991
- message: progressTranslator.t('ai.planner.progress.running_agent'),
1992
- successMessage: progressTranslator.t('ai.planner.progress.agent_finished'),
1993
- failureMessage: progressTranslator.t('ai.planner.progress.agent_failed'),
1994
- run: () => (options.runProviderFn || runProvider)(provider, {
1995
- prompt,
1996
- cwd: repoRoot,
1997
- timeoutMs,
1998
- dryRun: false,
1999
- probe: options.probe,
2000
- spawn: options.spawn,
2001
- tempRoot: options.tempRoot,
2002
- tempFileName: options.tempFileName,
2003
- tempFilePrefix: options.tempFilePrefix,
2004
- ...runtimeModelExecutionOptions(runtimeProfile, options),
2005
- enforceModelSelection: false,
2006
- }),
2007
- });
2008
- } catch (error) {
2009
- throw annotateProviderError(error, 'analyze-project');
2010
- }
2110
+ let clean;
2111
+ let parsed;
2112
+ let repairManifest = null;
2113
+ let retryManifest = null;
2114
+ let currentPrompt = prompt;
2115
+ const rawProviderArtifacts = [];
2011
2116
 
2012
- if (!result.ok) {
2013
- throw annotateProviderError(result.error || new Error('provider run failed'), 'analyze-project');
2014
- }
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
+ }
2015
2145
 
2016
- const clean = extractCleanProviderOutput(result, { prompt, projectRoot: repoRoot });
2017
- let parsed;
2018
- try {
2019
- parsed = parseAnalyzeProjectOutput(clean.cleanOutput, {
2020
- selectedFiles: report.selected_files,
2021
- promptFiles: promptPackage.files,
2022
- });
2023
- } catch (error) {
2024
- throw enhanceAnalyzeProjectAnalysisError(error);
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
+ }
2171
+
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
+ }
2025
2300
  }
2026
2301
  const completedReport = {
2027
2302
  ...report,
@@ -2040,8 +2315,16 @@ async function runAnalyzeProject(repoRoot, options = {}) {
2040
2315
  parse_source: parsed.parseSource,
2041
2316
  warnings: parsed.warnings,
2042
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,
2043
2322
  },
2044
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,
2045
2328
  };
2046
2329
 
2047
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