create-quiver 0.17.2 → 0.17.4
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 +4 -0
- package/docs/CLI_UX_GUIDE.md +13 -3
- package/docs/TROUBLESHOOTING.md +42 -3
- package/docs/reference/commands.md +33 -12
- package/docs/workflows/existing-project.md +18 -3
- package/package.json +1 -1
- package/specs/quiver-v43-cli-i18n-audit-release-readiness/command-language-mode-matrix.json +4 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/EVIDENCE_REPORT.md +209 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/EXECUTION_PLAN.md +49 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/SPEC.md +276 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/STATUS.md +29 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-01-cli-proposal-contract/CLOSURE_BRIEF.md +47 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-01-cli-proposal-contract/EXECUTION_BRIEF.md +67 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-01-cli-proposal-contract/pr.md +129 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-01-cli-proposal-contract/slice.json +82 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-02-save-proposal-flow/CLOSURE_BRIEF.md +39 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-02-save-proposal-flow/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-02-save-proposal-flow/pr.md +116 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-02-save-proposal-flow/slice.json +69 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-03-noninteractive-apply-engine/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-03-noninteractive-apply-engine/EXECUTION_BRIEF.md +62 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-03-noninteractive-apply-engine/pr.md +132 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-03-noninteractive-apply-engine/slice.json +76 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-04-interactive-apply-ux/CLOSURE_BRIEF.md +47 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-04-interactive-apply-ux/EXECUTION_BRIEF.md +70 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-04-interactive-apply-ux/pr.md +141 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-04-interactive-apply-ux/slice.json +72 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-05-apply-saved-proposal/CLOSURE_BRIEF.md +42 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-05-apply-saved-proposal/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-05-apply-saved-proposal/pr.md +129 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-05-apply-saved-proposal/slice.json +67 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-06-i18n-docs-release-smoke/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-06-i18n-docs-release-smoke/EXECUTION_BRIEF.md +64 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-06-i18n-docs-release-smoke/pr.md +123 -0
- package/specs/quiver-v55-analyze-project-doc-apply-ux/slices/slice-06-i18n-docs-release-smoke/slice.json +76 -0
- package/src/create-quiver/commands/ai.js +648 -65
- package/src/create-quiver/index.js +80 -1
- package/src/create-quiver/lib/ai/analyze-project-apply.js +269 -0
- package/src/create-quiver/lib/ai/analyze-project-docs.js +16 -1
- package/src/create-quiver/lib/ai/analyze-project-interactive.js +241 -0
- package/src/create-quiver/lib/ai/analyze-project-proposal.js +582 -0
- package/src/create-quiver/lib/ai/analyze-project-validation.js +10 -8
- package/src/create-quiver/lib/cli/ux-flags.js +6 -0
- package/src/create-quiver/lib/i18n/messages/en.js +28 -0
- package/src/create-quiver/lib/i18n/messages/es.js +29 -0
|
@@ -36,6 +36,18 @@ const {
|
|
|
36
36
|
confirmAnalyzeProjectWrites,
|
|
37
37
|
reviewAnalyzeProjectDocProposal,
|
|
38
38
|
} = require('../lib/ai/analyze-project-review');
|
|
39
|
+
const {
|
|
40
|
+
findLatestAnalyzeProjectSavedProposalRun,
|
|
41
|
+
readAnalyzeProjectSavedProposal,
|
|
42
|
+
writeAnalyzeProjectProposalArtifacts,
|
|
43
|
+
} = require('../lib/ai/analyze-project-proposal');
|
|
44
|
+
const {
|
|
45
|
+
applyAnalyzeProjectDocProposal,
|
|
46
|
+
} = require('../lib/ai/analyze-project-apply');
|
|
47
|
+
const {
|
|
48
|
+
canUseAnalyzeProjectInteractiveSelector,
|
|
49
|
+
runAnalyzeProjectInteractiveApplySelector,
|
|
50
|
+
} = require('../lib/ai/analyze-project-interactive');
|
|
39
51
|
const {
|
|
40
52
|
DEFAULT_MAX_BYTES: DEFAULT_ANALYZE_MAX_BYTES,
|
|
41
53
|
DEFAULT_MAX_FILES: DEFAULT_ANALYZE_MAX_FILES,
|
|
@@ -501,12 +513,46 @@ function formatAnalyzeProjectLiveReport(report) {
|
|
|
501
513
|
}
|
|
502
514
|
|
|
503
515
|
lines.push('', 'Next commands:');
|
|
516
|
+
lines.push('- npx create-quiver ai analyze-project --deep --save-proposal --provider <provider> --model <model>');
|
|
504
517
|
lines.push('- npx create-quiver ai analyze-project --deep --review');
|
|
505
518
|
lines.push('- npx create-quiver ai analyze-project --deep --json');
|
|
506
519
|
|
|
507
520
|
return `${lines.join('\n')}\n`;
|
|
508
521
|
}
|
|
509
522
|
|
|
523
|
+
function summarizeAnalyzeProjectWritePlan(writePlan = []) {
|
|
524
|
+
return writePlan.map((item) => ({
|
|
525
|
+
path: item.path,
|
|
526
|
+
action: item.action,
|
|
527
|
+
dirty: item.dirty,
|
|
528
|
+
before_sha256: item.before_sha256,
|
|
529
|
+
after_sha256: item.after_sha256,
|
|
530
|
+
reason: item.reason,
|
|
531
|
+
}));
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
function formatAnalyzeProjectSavedProposalReport(report = {}) {
|
|
535
|
+
const artifacts = report.proposal_artifacts || {};
|
|
536
|
+
const changed = report.write_plan?.filter((item) => item.action !== 'skip') || [];
|
|
537
|
+
const lines = [
|
|
538
|
+
'AI analyze-project proposal saved',
|
|
539
|
+
`Run: ${report.run_id || 'unknown'}`,
|
|
540
|
+
`Provider: ${report.provider || 'unknown'}`,
|
|
541
|
+
`Writes: none (final docs were not modified)`,
|
|
542
|
+
`Proposed docs: ${report.doc_paths?.length || 0}`,
|
|
543
|
+
`Docs with changes: ${changed.length}`,
|
|
544
|
+
`Proposal JSON: ${artifacts.proposal_json || 'none'}`,
|
|
545
|
+
`Proposal summary: ${artifacts.proposal_markdown || 'none'}`,
|
|
546
|
+
`Proposal diff: ${artifacts.proposal_diff || 'none'}`,
|
|
547
|
+
`Manifest: ${artifacts.manifest || 'none'}`,
|
|
548
|
+
'',
|
|
549
|
+
'Next commands:',
|
|
550
|
+
`- npx create-quiver ai analyze-project apply --run ${report.run_id || '<run-id>'}`,
|
|
551
|
+
'- npx create-quiver ai analyze-project --deep --apply-docs --provider <provider> --model <model>',
|
|
552
|
+
];
|
|
553
|
+
return `${lines.join('\n')}\n`;
|
|
554
|
+
}
|
|
555
|
+
|
|
510
556
|
function formatAnalyzeProjectPostWriteValidation(validation) {
|
|
511
557
|
if (!validation) {
|
|
512
558
|
return [];
|
|
@@ -553,6 +599,430 @@ function formatAnalyzeProjectReviewPlan({ writePlan, reviewPath, snapshot, writt
|
|
|
553
599
|
return `${lines.join('\n')}\n`;
|
|
554
600
|
}
|
|
555
601
|
|
|
602
|
+
function formatAnalyzeProjectApplyReport(report = {}) {
|
|
603
|
+
const artifacts = report.proposal_artifacts || {};
|
|
604
|
+
const writeManifest = report.write_manifest || {};
|
|
605
|
+
const changed = report.write_plan?.filter((item) => item.action !== 'skip') || [];
|
|
606
|
+
const dirty = changed.filter((item) => item.dirty);
|
|
607
|
+
const lines = [
|
|
608
|
+
'AI analyze-project docs applied',
|
|
609
|
+
`Run: ${report.run_id || 'unknown'}`,
|
|
610
|
+
`Provider: ${report.provider || 'unknown'}`,
|
|
611
|
+
report.provider_execution ? `Provider execution: ${report.provider_execution}` : '',
|
|
612
|
+
report.apply_run ? `Saved proposal edited: ${report.saved_proposal?.proposal_edited ? 'yes' : 'no'}` : '',
|
|
613
|
+
`Writes: ${changed.length > 0 ? changed.map((item) => item.path).join(', ') : 'none'}`,
|
|
614
|
+
`Dirty target docs: ${dirty.length > 0 ? dirty.map((item) => item.path).join(', ') : 'none'}`,
|
|
615
|
+
`Written docs: ${report.written_docs?.length > 0 ? report.written_docs.join(', ') : 'none'}`,
|
|
616
|
+
`Snapshot: ${report.snapshot?.root || 'none'}`,
|
|
617
|
+
`Proposal manifest: ${artifacts.manifest || 'none'}`,
|
|
618
|
+
`Write manifest: ${writeManifest.path || 'none'}`,
|
|
619
|
+
].filter(Boolean);
|
|
620
|
+
lines.push(...formatAnalyzeProjectPostWriteValidation(report.post_write_validation));
|
|
621
|
+
return `${lines.join('\n')}\n`;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function formatAnalyzeProjectApplyPreflightError(error) {
|
|
625
|
+
if (!error || error.code !== 'AI_ANALYZE_PROJECT_APPLY_BLOCKED') {
|
|
626
|
+
return error;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
const issueLines = (error.issues || []).slice(0, 12).map((issue) => {
|
|
630
|
+
const hashes = issue.expected_sha256 || issue.current_sha256
|
|
631
|
+
? ` expected=${issue.expected_sha256 || 'none'} current=${issue.current_sha256 || 'none'}`
|
|
632
|
+
: '';
|
|
633
|
+
return `- ${issue.path || 'docs'}: ${issue.issue}${hashes} - ${issue.message}`;
|
|
634
|
+
});
|
|
635
|
+
const wrapped = new Error([
|
|
636
|
+
error.message,
|
|
637
|
+
'Issues:',
|
|
638
|
+
...issueLines,
|
|
639
|
+
error.apply_run
|
|
640
|
+
? 'Next safe step: inspect `.quiver/runs/<run-id>/proposal/analyze-project-doc-proposal.diff`, then rerun with an explicit run id. Add `--allow-dirty-docs` only if overwriting existing managed docs is intended.'
|
|
641
|
+
: 'Next safe step: rerun with `--review`, or inspect with `--save-proposal`, or add `--allow-dirty-docs` if overwriting existing managed docs is intended.',
|
|
642
|
+
].join('\n'));
|
|
643
|
+
wrapped.name = error.name;
|
|
644
|
+
wrapped.code = error.code;
|
|
645
|
+
wrapped.cause = error;
|
|
646
|
+
wrapped.issues = error.issues;
|
|
647
|
+
return wrapped;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function resolveAnalyzeProjectSavedProposalRunId(repoRoot, options = {}) {
|
|
651
|
+
const requestedRunId = String(options.runId || '').trim();
|
|
652
|
+
if (requestedRunId !== 'latest') {
|
|
653
|
+
return { runId: requestedRunId, requestedRunId };
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
if (!canUseInteractiveTerminal(options)) {
|
|
657
|
+
throw analyzeProjectContractError(
|
|
658
|
+
'ai analyze-project apply --run latest requires an interactive terminal.',
|
|
659
|
+
'Use an explicit run id for automation: `npx create-quiver ai analyze-project apply --run <run-id>`.',
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const latestRunId = findLatestAnalyzeProjectSavedProposalRun(repoRoot);
|
|
664
|
+
if (!latestRunId) {
|
|
665
|
+
throw analyzeProjectContractError(
|
|
666
|
+
'ai analyze-project apply --run latest could not find a saved proposal.',
|
|
667
|
+
'Create one first: `npx create-quiver ai analyze-project --deep --save-proposal --provider <provider> --model <model>`.',
|
|
668
|
+
);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
if (options.json !== true) {
|
|
672
|
+
process.stdout.write(`Resolved latest analyze-project proposal: ${latestRunId}\n`);
|
|
673
|
+
}
|
|
674
|
+
return { runId: latestRunId, requestedRunId };
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function analyzeProjectRawProviderArtifactPaths(rawProviderArtifacts = []) {
|
|
678
|
+
return (Array.isArray(rawProviderArtifacts) ? rawProviderArtifacts : [])
|
|
679
|
+
.map((artifact) => (typeof artifact === 'string' ? artifact : artifact?.path))
|
|
680
|
+
.filter(Boolean);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function summarizeAnalyzeProjectProposalArtifacts(proposalArtifacts = {}) {
|
|
684
|
+
return {
|
|
685
|
+
root: proposalArtifacts.root,
|
|
686
|
+
proposal_json: proposalArtifacts.proposal_json,
|
|
687
|
+
proposal_markdown: proposalArtifacts.proposal_markdown,
|
|
688
|
+
proposal_diff: proposalArtifacts.proposal_diff,
|
|
689
|
+
manifest: proposalArtifacts.manifest,
|
|
690
|
+
proposal_sha256: proposalArtifacts.proposal_sha256,
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function listAnalyzeProjectProposalArtifactFiles(proposalArtifacts = {}) {
|
|
695
|
+
if (Array.isArray(proposalArtifacts.files)) {
|
|
696
|
+
return proposalArtifacts.files.filter(Boolean);
|
|
697
|
+
}
|
|
698
|
+
return [
|
|
699
|
+
proposalArtifacts.proposal_json,
|
|
700
|
+
proposalArtifacts.proposal_markdown,
|
|
701
|
+
proposalArtifacts.proposal_diff,
|
|
702
|
+
proposalArtifacts.manifest,
|
|
703
|
+
].filter(Boolean);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function saveAnalyzeProjectDocProposalReport(repoRoot, options = {}) {
|
|
707
|
+
const proposalArtifacts = writeAnalyzeProjectProposalArtifacts(repoRoot, {
|
|
708
|
+
runId: options.auditRunId,
|
|
709
|
+
now: options.commandOptions?.now || new Date(),
|
|
710
|
+
provider: options.provider,
|
|
711
|
+
language: options.commandOptions?.language,
|
|
712
|
+
proposal: options.proposal,
|
|
713
|
+
writePlan: options.writePlan,
|
|
714
|
+
selectedContextManifest: options.selectedContextManifest,
|
|
715
|
+
repairManifest: options.repairManifest,
|
|
716
|
+
events: options.interactiveAction ? [{
|
|
717
|
+
type: 'interactive-action',
|
|
718
|
+
action: options.interactiveAction,
|
|
719
|
+
at: (options.commandOptions?.now instanceof Date
|
|
720
|
+
? options.commandOptions.now
|
|
721
|
+
: new Date(options.commandOptions?.now || Date.now())).toISOString(),
|
|
722
|
+
}] : [],
|
|
723
|
+
});
|
|
724
|
+
const saveReport = {
|
|
725
|
+
...options.completedReport,
|
|
726
|
+
save_proposal: true,
|
|
727
|
+
interactive_action: options.interactiveAction || undefined,
|
|
728
|
+
doc_proposal: options.proposal,
|
|
729
|
+
doc_paths: proposalArtifacts.doc_paths,
|
|
730
|
+
proposal_artifacts: summarizeAnalyzeProjectProposalArtifacts(proposalArtifacts),
|
|
731
|
+
write_plan: summarizeAnalyzeProjectWritePlan(options.writePlan),
|
|
732
|
+
};
|
|
733
|
+
writeAnalyzeProjectRunStatus(repoRoot, options.auditRunId, 'proposal-saved', {
|
|
734
|
+
now: options.commandOptions?.now,
|
|
735
|
+
provider: options.provider,
|
|
736
|
+
attempts: options.providerAttempts,
|
|
737
|
+
artifacts: {
|
|
738
|
+
selected_context: options.selectedContextManifest,
|
|
739
|
+
raw_provider: analyzeProjectRawProviderArtifactPaths(options.rawProviderArtifacts),
|
|
740
|
+
repair: options.repairManifest,
|
|
741
|
+
retry: options.retryManifest,
|
|
742
|
+
proposal_manifest: proposalArtifacts.manifest,
|
|
743
|
+
proposal_files: proposalArtifacts.files,
|
|
744
|
+
},
|
|
745
|
+
});
|
|
746
|
+
return saveReport;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
function applyAnalyzeProjectDocProposalReport(repoRoot, options = {}) {
|
|
750
|
+
let applyReport;
|
|
751
|
+
try {
|
|
752
|
+
applyReport = applyAnalyzeProjectDocProposal(repoRoot, {
|
|
753
|
+
report: options.completedReport,
|
|
754
|
+
runId: options.auditRunId,
|
|
755
|
+
now: options.commandOptions?.now || new Date(),
|
|
756
|
+
provider: options.provider,
|
|
757
|
+
language: options.commandOptions?.language,
|
|
758
|
+
proposal: options.proposal,
|
|
759
|
+
providerArtifact: options.completedReport.provider_artifact,
|
|
760
|
+
selectedContextManifest: options.selectedContextManifest,
|
|
761
|
+
repairManifest: options.repairManifest,
|
|
762
|
+
strict: options.commandOptions?.strict === true,
|
|
763
|
+
allowDirtyDocs: options.allowDirtyDocs === true,
|
|
764
|
+
summarizeWritePlan: summarizeAnalyzeProjectWritePlan,
|
|
765
|
+
});
|
|
766
|
+
} catch (error) {
|
|
767
|
+
const proposalArtifacts = error.proposal_artifacts || {};
|
|
768
|
+
writeAnalyzeProjectRunStatus(repoRoot, options.auditRunId, error.code === 'AI_ANALYZE_PROJECT_APPLY_BLOCKED' ? 'apply-blocked' : 'apply-failed', {
|
|
769
|
+
now: options.commandOptions?.now,
|
|
770
|
+
provider: options.provider,
|
|
771
|
+
attempts: options.providerAttempts,
|
|
772
|
+
artifacts: {
|
|
773
|
+
selected_context: options.selectedContextManifest,
|
|
774
|
+
raw_provider: analyzeProjectRawProviderArtifactPaths(options.rawProviderArtifacts),
|
|
775
|
+
repair: options.repairManifest,
|
|
776
|
+
retry: options.retryManifest,
|
|
777
|
+
proposal_manifest: proposalArtifacts.manifest || null,
|
|
778
|
+
proposal_files: listAnalyzeProjectProposalArtifactFiles(proposalArtifacts),
|
|
779
|
+
write_manifest: error.write_manifest?.path || null,
|
|
780
|
+
snapshot_manifest: error.snapshot?.manifestPath || null,
|
|
781
|
+
},
|
|
782
|
+
});
|
|
783
|
+
throw formatAnalyzeProjectApplyPreflightError(error);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
applyReport = {
|
|
787
|
+
...applyReport,
|
|
788
|
+
interactive_action: options.interactiveAction || applyReport.interactive_action,
|
|
789
|
+
};
|
|
790
|
+
writeAnalyzeProjectRunStatus(repoRoot, options.auditRunId, applyReport.post_write_validation?.ok ? 'docs-applied' : 'apply-validation-failed', {
|
|
791
|
+
now: options.commandOptions?.now,
|
|
792
|
+
provider: options.provider,
|
|
793
|
+
attempts: options.providerAttempts,
|
|
794
|
+
artifacts: {
|
|
795
|
+
selected_context: options.selectedContextManifest,
|
|
796
|
+
raw_provider: analyzeProjectRawProviderArtifactPaths(options.rawProviderArtifacts),
|
|
797
|
+
repair: options.repairManifest,
|
|
798
|
+
retry: options.retryManifest,
|
|
799
|
+
proposal_manifest: applyReport.proposal_artifacts?.manifest,
|
|
800
|
+
proposal_files: listAnalyzeProjectProposalArtifactFiles(applyReport.proposal_artifacts),
|
|
801
|
+
write_manifest: applyReport.write_manifest?.path,
|
|
802
|
+
snapshot_manifest: applyReport.snapshot?.manifestPath,
|
|
803
|
+
},
|
|
804
|
+
});
|
|
805
|
+
return applyReport;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
function applyAnalyzeProjectSavedProposalRun(repoRoot, options = {}) {
|
|
809
|
+
const { runId, requestedRunId } = resolveAnalyzeProjectSavedProposalRunId(repoRoot, options);
|
|
810
|
+
const now = options.now instanceof Date ? options.now : new Date(options.now || Date.now());
|
|
811
|
+
const saved = readAnalyzeProjectSavedProposal(repoRoot, runId);
|
|
812
|
+
const provider = saved.manifest.provider || null;
|
|
813
|
+
const runStatusPath = path.join('.quiver', 'runs', runId, 'status.json').split(path.sep).join('/');
|
|
814
|
+
const baseReport = {
|
|
815
|
+
schema_version: 1,
|
|
816
|
+
kind: 'quiver-project-analysis-apply-saved-proposal',
|
|
817
|
+
command: 'ai analyze-project apply',
|
|
818
|
+
mode: 'apply-saved-proposal',
|
|
819
|
+
apply_run: true,
|
|
820
|
+
requested_run_id: requestedRunId,
|
|
821
|
+
run_id: runId,
|
|
822
|
+
provider,
|
|
823
|
+
provider_execution: 'skipped',
|
|
824
|
+
writes: [],
|
|
825
|
+
doc_proposal: saved.proposal,
|
|
826
|
+
saved_proposal: {
|
|
827
|
+
requested_run_id: requestedRunId,
|
|
828
|
+
run_id: runId,
|
|
829
|
+
manifest: saved.artifacts.manifest,
|
|
830
|
+
proposal_json: saved.artifacts.proposal_json,
|
|
831
|
+
proposal_sha256: saved.proposal_sha256,
|
|
832
|
+
proposal_edited: saved.proposal_edited,
|
|
833
|
+
},
|
|
834
|
+
run_status_path: runStatusPath,
|
|
835
|
+
};
|
|
836
|
+
const events = [
|
|
837
|
+
{
|
|
838
|
+
type: 'saved-proposal-apply',
|
|
839
|
+
at: now.toISOString(),
|
|
840
|
+
requested_run_id: requestedRunId,
|
|
841
|
+
run_id: runId,
|
|
842
|
+
},
|
|
843
|
+
];
|
|
844
|
+
if (saved.proposal_edited) {
|
|
845
|
+
events.push({
|
|
846
|
+
type: 'saved-proposal-edited',
|
|
847
|
+
at: now.toISOString(),
|
|
848
|
+
original_sha256: saved.manifest.proposal_sha256,
|
|
849
|
+
current_sha256: saved.proposal_sha256,
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
let applyReport;
|
|
854
|
+
try {
|
|
855
|
+
applyReport = applyAnalyzeProjectDocProposal(repoRoot, {
|
|
856
|
+
report: baseReport,
|
|
857
|
+
runId,
|
|
858
|
+
now,
|
|
859
|
+
provider,
|
|
860
|
+
language: saved.manifest.language,
|
|
861
|
+
proposal: saved.proposal,
|
|
862
|
+
proposalArtifacts: saved.artifacts,
|
|
863
|
+
proposalManifest: saved.manifest,
|
|
864
|
+
proposalEdited: saved.proposal_edited,
|
|
865
|
+
strict: options.strict === true,
|
|
866
|
+
allowDirtyDocs: options.allowDirtyDocs === true,
|
|
867
|
+
summarizeWritePlan: summarizeAnalyzeProjectWritePlan,
|
|
868
|
+
events,
|
|
869
|
+
});
|
|
870
|
+
} catch (error) {
|
|
871
|
+
error.apply_run = true;
|
|
872
|
+
const proposalArtifacts = error.proposal_artifacts || saved.artifacts || {};
|
|
873
|
+
writeAnalyzeProjectRunStatus(repoRoot, runId, error.code === 'AI_ANALYZE_PROJECT_APPLY_BLOCKED' ? 'apply-blocked' : 'apply-failed', {
|
|
874
|
+
now,
|
|
875
|
+
provider,
|
|
876
|
+
attempts: [],
|
|
877
|
+
artifacts: {
|
|
878
|
+
proposal_manifest: proposalArtifacts.manifest || saved.artifacts.manifest,
|
|
879
|
+
proposal_files: listAnalyzeProjectProposalArtifactFiles(proposalArtifacts),
|
|
880
|
+
write_manifest: error.write_manifest?.path || null,
|
|
881
|
+
snapshot_manifest: error.snapshot?.manifestPath || null,
|
|
882
|
+
},
|
|
883
|
+
});
|
|
884
|
+
throw formatAnalyzeProjectApplyPreflightError(error);
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
applyReport = {
|
|
888
|
+
...applyReport,
|
|
889
|
+
apply_run: true,
|
|
890
|
+
requested_run_id: requestedRunId,
|
|
891
|
+
saved_proposal: baseReport.saved_proposal,
|
|
892
|
+
run_status_path: runStatusPath,
|
|
893
|
+
};
|
|
894
|
+
writeAnalyzeProjectRunStatus(repoRoot, runId, applyReport.post_write_validation?.ok ? 'docs-applied' : 'apply-validation-failed', {
|
|
895
|
+
now,
|
|
896
|
+
provider,
|
|
897
|
+
attempts: [],
|
|
898
|
+
artifacts: {
|
|
899
|
+
proposal_manifest: applyReport.proposal_artifacts?.manifest,
|
|
900
|
+
proposal_files: listAnalyzeProjectProposalArtifactFiles(applyReport.proposal_artifacts),
|
|
901
|
+
write_manifest: applyReport.write_manifest?.path,
|
|
902
|
+
snapshot_manifest: applyReport.snapshot?.manifestPath,
|
|
903
|
+
},
|
|
904
|
+
});
|
|
905
|
+
return emitAnalyzeProjectApplyReport(applyReport, options);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
function emitAnalyzeProjectApplyReport(applyReport, options = {}) {
|
|
909
|
+
if (options.json === true) {
|
|
910
|
+
process.stdout.write(`${JSON.stringify(applyReport, null, 2)}\n`);
|
|
911
|
+
} else {
|
|
912
|
+
process.stdout.write(formatAnalyzeProjectApplyReport(applyReport));
|
|
913
|
+
}
|
|
914
|
+
if (!applyReport.post_write_validation?.ok) {
|
|
915
|
+
const error = new Error(formatError('ai analyze-project post-write validation failed.'));
|
|
916
|
+
error.code = 'AI_ANALYZE_PROJECT_POST_WRITE_VALIDATION_FAILED';
|
|
917
|
+
error.validation = applyReport.post_write_validation;
|
|
918
|
+
throw error;
|
|
919
|
+
}
|
|
920
|
+
return applyReport;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
async function reviewAndWriteAnalyzeProjectDocs(repoRoot, options = {}) {
|
|
924
|
+
const commandOptions = options.commandOptions || {};
|
|
925
|
+
const reviewed = await reviewAnalyzeProjectDocProposal(repoRoot, options.initialProposal, commandOptions);
|
|
926
|
+
const writePlan = buildAnalyzeProjectWritePlan(repoRoot, reviewed.proposal);
|
|
927
|
+
process.stdout.write(formatAnalyzeProjectReviewPlan({
|
|
928
|
+
writePlan,
|
|
929
|
+
reviewPath: reviewed.reviewPath,
|
|
930
|
+
}));
|
|
931
|
+
await confirmAnalyzeProjectWrites(writePlan, commandOptions);
|
|
932
|
+
const lifecycleRun = ensureAiRun(repoRoot, {
|
|
933
|
+
command: 'ai analyze-project',
|
|
934
|
+
input: reviewed.reviewPath,
|
|
935
|
+
runId: commandOptions.runId,
|
|
936
|
+
phase: 'created',
|
|
937
|
+
});
|
|
938
|
+
const snapshot = createAnalyzeProjectSnapshot(repoRoot, lifecycleRun, writePlan, {
|
|
939
|
+
providerArtifact: options.completedReport.provider_artifact,
|
|
940
|
+
proposal: reviewed.proposal,
|
|
941
|
+
now: commandOptions.now || new Date(),
|
|
942
|
+
});
|
|
943
|
+
const writtenDocs = writeAnalyzeProjectDocs(writePlan);
|
|
944
|
+
let writeReport = {
|
|
945
|
+
...options.completedReport,
|
|
946
|
+
review: true,
|
|
947
|
+
interactive_action: options.interactiveAction || undefined,
|
|
948
|
+
review_path: reviewed.reviewPath,
|
|
949
|
+
doc_proposal: reviewed.proposal,
|
|
950
|
+
write_plan: summarizeAnalyzeProjectWritePlan(writePlan),
|
|
951
|
+
snapshot,
|
|
952
|
+
written_docs: writtenDocs,
|
|
953
|
+
run_id: lifecycleRun.run_id,
|
|
954
|
+
};
|
|
955
|
+
const postWriteValidation = validateAnalyzeProjectPostWrite(repoRoot, writeReport, {
|
|
956
|
+
strict: commandOptions.strict === true,
|
|
957
|
+
});
|
|
958
|
+
writeReport = {
|
|
959
|
+
...writeReport,
|
|
960
|
+
post_write_validation: postWriteValidation,
|
|
961
|
+
};
|
|
962
|
+
|
|
963
|
+
if (commandOptions.json === true) {
|
|
964
|
+
process.stdout.write(`${JSON.stringify(writeReport, null, 2)}\n`);
|
|
965
|
+
if (!postWriteValidation.ok) {
|
|
966
|
+
const error = new Error(formatError('ai analyze-project post-write validation failed.'));
|
|
967
|
+
error.code = 'AI_ANALYZE_PROJECT_POST_WRITE_VALIDATION_FAILED';
|
|
968
|
+
error.validation = postWriteValidation;
|
|
969
|
+
throw error;
|
|
970
|
+
}
|
|
971
|
+
return writeReport;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
process.stdout.write(formatAnalyzeProjectReviewPlan({
|
|
975
|
+
writePlan,
|
|
976
|
+
reviewPath: reviewed.reviewPath,
|
|
977
|
+
snapshot,
|
|
978
|
+
writtenDocs,
|
|
979
|
+
validation: postWriteValidation,
|
|
980
|
+
completed: true,
|
|
981
|
+
}));
|
|
982
|
+
if (!postWriteValidation.ok) {
|
|
983
|
+
const error = new Error(formatError('ai analyze-project post-write validation failed.'));
|
|
984
|
+
error.code = 'AI_ANALYZE_PROJECT_POST_WRITE_VALIDATION_FAILED';
|
|
985
|
+
error.validation = postWriteValidation;
|
|
986
|
+
throw error;
|
|
987
|
+
}
|
|
988
|
+
return writeReport;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
function cancelAnalyzeProjectInteractiveApplyReport(repoRoot, options = {}) {
|
|
992
|
+
const translator = createTranslator(options.commandOptions?.language);
|
|
993
|
+
const savedArtifacts = options.savedReport?.proposal_artifacts || null;
|
|
994
|
+
const cancelReport = {
|
|
995
|
+
...options.completedReport,
|
|
996
|
+
apply_docs: true,
|
|
997
|
+
interactive_action: options.interactiveAction || 'cancel',
|
|
998
|
+
cancelled: true,
|
|
999
|
+
writes: [],
|
|
1000
|
+
written_docs: [],
|
|
1001
|
+
doc_proposal: options.proposal,
|
|
1002
|
+
proposal_artifacts: savedArtifacts || undefined,
|
|
1003
|
+
write_plan: summarizeAnalyzeProjectWritePlan(options.writePlan),
|
|
1004
|
+
};
|
|
1005
|
+
writeAnalyzeProjectRunStatus(repoRoot, options.auditRunId, 'apply-canceled', {
|
|
1006
|
+
now: options.commandOptions?.now,
|
|
1007
|
+
provider: options.provider,
|
|
1008
|
+
attempts: options.providerAttempts,
|
|
1009
|
+
artifacts: {
|
|
1010
|
+
selected_context: options.selectedContextManifest,
|
|
1011
|
+
raw_provider: analyzeProjectRawProviderArtifactPaths(options.rawProviderArtifacts),
|
|
1012
|
+
repair: options.repairManifest,
|
|
1013
|
+
retry: options.retryManifest,
|
|
1014
|
+
proposal_manifest: savedArtifacts?.manifest || null,
|
|
1015
|
+
proposal_files: savedArtifacts ? listAnalyzeProjectProposalArtifactFiles(savedArtifacts) : [],
|
|
1016
|
+
},
|
|
1017
|
+
});
|
|
1018
|
+
process.stdout.write([
|
|
1019
|
+
translator.t('ai.analyze_project.apply.cancelled'),
|
|
1020
|
+
translator.t('ai.analyze_project.apply.cancelled_writes'),
|
|
1021
|
+
'',
|
|
1022
|
+
].join('\n'));
|
|
1023
|
+
return cancelReport;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
556
1026
|
function formatLocalizedActionableError({ failure, impact, fix, nextCommand } = {}, options = {}) {
|
|
557
1027
|
const translator = createTranslator(options.language);
|
|
558
1028
|
const lines = [`create-quiver: ${String(failure || 'operation failed').trim()}`];
|
|
@@ -570,6 +1040,84 @@ function formatLocalizedActionableError({ failure, impact, fix, nextCommand } =
|
|
|
570
1040
|
return lines.join('\n');
|
|
571
1041
|
}
|
|
572
1042
|
|
|
1043
|
+
function analyzeProjectContractError(message, nextCommand) {
|
|
1044
|
+
const error = new Error(formatError([
|
|
1045
|
+
message,
|
|
1046
|
+
nextCommand ? `Next safe step: ${nextCommand}` : '',
|
|
1047
|
+
].filter(Boolean).join('\n')));
|
|
1048
|
+
error.code = 'AI_ANALYZE_PROJECT_CONTRACT_UNAVAILABLE';
|
|
1049
|
+
return error;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
function canUseInteractiveTerminal(options = {}) {
|
|
1053
|
+
return options.stdinIsTTY === true || (options.stdinIsTTY !== false && Boolean(process.stdin.isTTY));
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function assertAnalyzeProjectCommandContract(options = {}) {
|
|
1057
|
+
if (options.review === true && options.applyDocs === true) {
|
|
1058
|
+
throw analyzeProjectContractError(
|
|
1059
|
+
'ai analyze-project --apply-docs cannot be combined with --review.',
|
|
1060
|
+
'Use either `npx create-quiver ai analyze-project --deep --review` or `npx create-quiver ai analyze-project --deep --apply-docs`.',
|
|
1061
|
+
);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
if (options.dryRun === true && options.applyDocs === true) {
|
|
1065
|
+
throw analyzeProjectContractError(
|
|
1066
|
+
'ai analyze-project --dry-run cannot be combined with --apply-docs.',
|
|
1067
|
+
'Preview with `npx create-quiver ai analyze-project --deep --dry-run`, then rerun without --dry-run.',
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
if (options.dryRun === true && options.saveProposal === true) {
|
|
1072
|
+
throw analyzeProjectContractError(
|
|
1073
|
+
'ai analyze-project --dry-run cannot be combined with --save-proposal.',
|
|
1074
|
+
'Preview with `npx create-quiver ai analyze-project --deep --dry-run`, then rerun with --save-proposal.',
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
if (options.applyRun === true && options.dryRun === true) {
|
|
1079
|
+
throw analyzeProjectContractError(
|
|
1080
|
+
'ai analyze-project apply --run cannot be combined with --dry-run.',
|
|
1081
|
+
'Inspect the saved proposal under `.quiver/runs/<run-id>/proposal/`, then rerun without --dry-run.',
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
if (options.applyRun === true && (options.applyDocs === true || options.saveProposal === true || options.review === true)) {
|
|
1086
|
+
throw analyzeProjectContractError(
|
|
1087
|
+
'ai analyze-project apply --run cannot be combined with --apply-docs, --save-proposal, or --review.',
|
|
1088
|
+
'Use `npx create-quiver ai analyze-project apply --run <run-id>` to apply a saved proposal, or rerun `ai analyze-project --deep` for a fresh proposal.',
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
if (options.json === true && options.applyDocs === true && options.force !== true) {
|
|
1093
|
+
throw analyzeProjectContractError(
|
|
1094
|
+
'ai analyze-project --json with --apply-docs requires --yes because JSON output cannot include an interactive selector.',
|
|
1095
|
+
'Use `npx create-quiver ai analyze-project --deep --apply-docs --yes --json` for automation.',
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
if (options.applyRun === true && !String(options.runId || '').trim()) {
|
|
1100
|
+
throw analyzeProjectContractError(
|
|
1101
|
+
'ai analyze-project apply requires --run <run-id>.',
|
|
1102
|
+
'Use `npx create-quiver ai analyze-project apply --run <run-id>`.',
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
if (options.applyRun === true && String(options.runId || '').trim() === 'latest' && options.force === true) {
|
|
1107
|
+
throw analyzeProjectContractError(
|
|
1108
|
+
'ai analyze-project apply --run latest cannot be combined with --yes.',
|
|
1109
|
+
'Use an explicit run id for automation: `npx create-quiver ai analyze-project apply --run <run-id> --yes`.',
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
if (options.applyRun === true && String(options.runId || '').trim() === 'latest' && options.json === true) {
|
|
1114
|
+
throw analyzeProjectContractError(
|
|
1115
|
+
'ai analyze-project apply --run latest cannot be combined with --json.',
|
|
1116
|
+
'Use an explicit run id for JSON automation: `npx create-quiver ai analyze-project apply --run <run-id> --json`.',
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
573
1121
|
function readTextFile(filePath, repoRoot) {
|
|
574
1122
|
if (!filePath) {
|
|
575
1123
|
return '';
|
|
@@ -2010,6 +2558,17 @@ async function runPrepareContext(repoRoot, options = {}) {
|
|
|
2010
2558
|
}
|
|
2011
2559
|
|
|
2012
2560
|
async function runAnalyzeProject(repoRoot, options = {}) {
|
|
2561
|
+
assertAnalyzeProjectCommandContract(options);
|
|
2562
|
+
if (options.applyRun === true) {
|
|
2563
|
+
return applyAnalyzeProjectSavedProposalRun(repoRoot, options);
|
|
2564
|
+
}
|
|
2565
|
+
if (options.applyDocs === true && options.force !== true && !canUseAnalyzeProjectInteractiveSelector(options)) {
|
|
2566
|
+
throw analyzeProjectContractError(
|
|
2567
|
+
'ai analyze-project --apply-docs requires an interactive TTY unless --yes is passed. No provider was run and no files were written.',
|
|
2568
|
+
'Use `npx create-quiver ai analyze-project --deep --apply-docs --yes --provider <provider> --model <model>` for automation, or rerun from an interactive terminal.',
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2013
2572
|
const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
|
|
2014
2573
|
const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_PLAN_PROVIDER);
|
|
2015
2574
|
const provider = runtimeProfile.provider;
|
|
@@ -2323,82 +2882,106 @@ async function runAnalyzeProject(repoRoot, options = {}) {
|
|
|
2323
2882
|
provider_artifact: buildAnalyzeProjectProviderArtifact(result, clean, repoRoot),
|
|
2324
2883
|
raw_provider_artifacts: rawProviderArtifacts.map((artifact) => artifact.path),
|
|
2325
2884
|
provider_attempts: providerAttempts,
|
|
2885
|
+
run_id: auditRunId,
|
|
2326
2886
|
run_status_path: path.join('.quiver', 'runs', auditRunId, 'status.json').split(path.sep).join('/'),
|
|
2327
2887
|
selected_context_manifest: selectedContextManifest,
|
|
2328
2888
|
};
|
|
2889
|
+
const autoApplyDocs = options.applyDocs !== true
|
|
2890
|
+
&& options.saveProposal !== true
|
|
2891
|
+
&& options.review !== true
|
|
2892
|
+
&& options.json !== true;
|
|
2893
|
+
const needsDocProposal = autoApplyDocs || options.applyDocs === true || options.saveProposal === true || options.review === true;
|
|
2894
|
+
const docProposal = needsDocProposal ? buildAnalyzeProjectDocProposal(parsed.analysis) : null;
|
|
2895
|
+
const docWritePlan = docProposal ? buildAnalyzeProjectWritePlan(repoRoot, docProposal) : [];
|
|
2896
|
+
const docActionContext = {
|
|
2897
|
+
auditRunId,
|
|
2898
|
+
commandOptions: options,
|
|
2899
|
+
completedReport,
|
|
2900
|
+
proposal: docProposal,
|
|
2901
|
+
writePlan: docWritePlan,
|
|
2902
|
+
provider,
|
|
2903
|
+
providerAttempts,
|
|
2904
|
+
rawProviderArtifacts,
|
|
2905
|
+
selectedContextManifest,
|
|
2906
|
+
repairManifest,
|
|
2907
|
+
retryManifest,
|
|
2908
|
+
};
|
|
2329
2909
|
|
|
2330
|
-
if (options.
|
|
2331
|
-
const
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
process.stdout.write(formatAnalyzeProjectReviewPlan({
|
|
2335
|
-
writePlan,
|
|
2336
|
-
reviewPath: reviewed.reviewPath,
|
|
2337
|
-
}));
|
|
2338
|
-
await confirmAnalyzeProjectWrites(writePlan, options);
|
|
2339
|
-
const lifecycleRun = ensureAiRun(repoRoot, {
|
|
2340
|
-
command: 'ai analyze-project',
|
|
2341
|
-
input: reviewed.reviewPath,
|
|
2342
|
-
runId: options.runId,
|
|
2343
|
-
phase: 'created',
|
|
2910
|
+
if (options.applyDocs === true && options.force === true) {
|
|
2911
|
+
const applyReport = applyAnalyzeProjectDocProposalReport(repoRoot, {
|
|
2912
|
+
...docActionContext,
|
|
2913
|
+
allowDirtyDocs: options.allowDirtyDocs === true,
|
|
2344
2914
|
});
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2915
|
+
return emitAnalyzeProjectApplyReport(applyReport, options);
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
if (autoApplyDocs) {
|
|
2919
|
+
const applyReport = applyAnalyzeProjectDocProposalReport(repoRoot, {
|
|
2920
|
+
...docActionContext,
|
|
2921
|
+
allowDirtyDocs: true,
|
|
2922
|
+
interactiveAction: 'auto-apply',
|
|
2349
2923
|
});
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2924
|
+
return emitAnalyzeProjectApplyReport(applyReport, options);
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
if (options.applyDocs === true) {
|
|
2928
|
+
return runAnalyzeProjectInteractiveApplySelector({
|
|
2929
|
+
report: completedReport,
|
|
2930
|
+
proposal: docProposal,
|
|
2931
|
+
writePlan: docWritePlan,
|
|
2932
|
+
options,
|
|
2933
|
+
actions: {
|
|
2934
|
+
apply: ({ allowDirtyDocs, interactiveAction }) => {
|
|
2935
|
+
const applyReport = applyAnalyzeProjectDocProposalReport(repoRoot, {
|
|
2936
|
+
...docActionContext,
|
|
2937
|
+
allowDirtyDocs,
|
|
2938
|
+
interactiveAction,
|
|
2939
|
+
});
|
|
2940
|
+
return emitAnalyzeProjectApplyReport(applyReport, options);
|
|
2941
|
+
},
|
|
2942
|
+
save: ({ interactiveAction, silent, savedReport } = {}) => {
|
|
2943
|
+
const saveReport = savedReport || saveAnalyzeProjectDocProposalReport(repoRoot, {
|
|
2944
|
+
...docActionContext,
|
|
2945
|
+
interactiveAction,
|
|
2946
|
+
});
|
|
2947
|
+
if (silent !== true) {
|
|
2948
|
+
process.stdout.write(formatAnalyzeProjectSavedProposalReport(saveReport));
|
|
2949
|
+
}
|
|
2950
|
+
return saveReport;
|
|
2951
|
+
},
|
|
2952
|
+
edit: ({ interactiveAction } = {}) => reviewAndWriteAnalyzeProjectDocs(repoRoot, {
|
|
2953
|
+
commandOptions: options,
|
|
2954
|
+
completedReport,
|
|
2955
|
+
initialProposal: docProposal,
|
|
2956
|
+
interactiveAction,
|
|
2957
|
+
}),
|
|
2958
|
+
cancel: ({ interactiveAction, savedReport } = {}) => cancelAnalyzeProjectInteractiveApplyReport(repoRoot, {
|
|
2959
|
+
...docActionContext,
|
|
2960
|
+
interactiveAction,
|
|
2961
|
+
savedReport,
|
|
2962
|
+
}),
|
|
2963
|
+
},
|
|
2370
2964
|
});
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2967
|
+
if (options.saveProposal === true) {
|
|
2968
|
+
const saveReport = saveAnalyzeProjectDocProposalReport(repoRoot, docActionContext);
|
|
2375
2969
|
|
|
2376
2970
|
if (options.json === true) {
|
|
2377
|
-
process.stdout.write(`${JSON.stringify(
|
|
2378
|
-
|
|
2379
|
-
const error = new Error(formatError('ai analyze-project post-write validation failed.'));
|
|
2380
|
-
error.code = 'AI_ANALYZE_PROJECT_POST_WRITE_VALIDATION_FAILED';
|
|
2381
|
-
error.validation = postWriteValidation;
|
|
2382
|
-
throw error;
|
|
2383
|
-
}
|
|
2384
|
-
return writeReport;
|
|
2971
|
+
process.stdout.write(`${JSON.stringify(saveReport, null, 2)}\n`);
|
|
2972
|
+
return saveReport;
|
|
2385
2973
|
}
|
|
2386
2974
|
|
|
2387
|
-
process.stdout.write(
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
error.code = 'AI_ANALYZE_PROJECT_POST_WRITE_VALIDATION_FAILED';
|
|
2398
|
-
error.validation = postWriteValidation;
|
|
2399
|
-
throw error;
|
|
2400
|
-
}
|
|
2401
|
-
return writeReport;
|
|
2975
|
+
process.stdout.write(formatAnalyzeProjectSavedProposalReport(saveReport));
|
|
2976
|
+
return saveReport;
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
if (options.review === true) {
|
|
2980
|
+
return reviewAndWriteAnalyzeProjectDocs(repoRoot, {
|
|
2981
|
+
commandOptions: options,
|
|
2982
|
+
completedReport,
|
|
2983
|
+
initialProposal: docProposal,
|
|
2984
|
+
});
|
|
2402
2985
|
}
|
|
2403
2986
|
|
|
2404
2987
|
if (options.json === true) {
|