create-quiver 0.10.0 → 0.12.0
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/BACKLOG.md +16 -17
- package/CHANGELOG.md +34 -0
- package/README.md +174 -39
- package/README_FOR_AI.md +48 -24
- package/ROADMAP.md +22 -11
- package/docs/AI_CONTEXT.md.template +2 -0
- package/docs/AI_ONBOARDING_PROMPT.md.template +25 -18
- package/docs/COMMANDS.md.template +59 -11
- package/docs/CONTEXTO.md.template +2 -0
- package/docs/DECISIONS.md.template +1 -0
- package/docs/INDEX.md.template +20 -18
- package/docs/STATUS.md.template +1 -0
- package/docs/SUPPORT_MATRIX.md.template +2 -2
- package/docs/TROUBLESHOOTING.md.template +50 -0
- package/docs/WORKFLOW.md.template +25 -17
- package/package.json +19 -2
- package/package.template.json +13 -1
- package/scripts/init-docs.sh +11 -4
- package/scripts/package-quiver.sh +18 -2
- package/specs/quiver-v22-guided-ai-workflow/EVIDENCE_REPORT.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/EXECUTION_PLAN.md +88 -0
- package/specs/quiver-v22-guided-ai-workflow/SPEC.md +228 -0
- package/specs/quiver-v22-guided-ai-workflow/STATUS.md +42 -0
- package/specs/quiver-v22-guided-ai-workflow/pr.md +104 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/slice.json +55 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/slice.json +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/slice.json +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/slice.json +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/slice.json +54 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/slice.json +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/slice.json +55 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/slice.json +53 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/slice.json +59 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/slice.json +60 -0
- package/specs/quiver-v23-guided-flow-productization/EVIDENCE_REPORT.md +80 -0
- package/specs/quiver-v23-guided-flow-productization/EXECUTION_PLAN.md +80 -0
- package/specs/quiver-v23-guided-flow-productization/SPEC.md +203 -0
- package/specs/quiver-v23-guided-flow-productization/STATUS.md +39 -0
- package/specs/quiver-v23-guided-flow-productization/pr.md +119 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/EXECUTION_BRIEF.md +35 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/slice.json +56 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/slice.json +54 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/slice.json +59 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/slice.json +53 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/slice.json +54 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/EXECUTION_BRIEF.md +34 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/slice.json +57 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/slice.json +63 -0
- package/specs/quiver-v24-dx-onboarding-hardening/EVIDENCE_REPORT.md +55 -0
- package/specs/quiver-v24-dx-onboarding-hardening/EXECUTION_PLAN.md +43 -0
- package/specs/quiver-v24-dx-onboarding-hardening/SPEC.md +149 -0
- package/specs/quiver-v24-dx-onboarding-hardening/STATUS.md +31 -0
- package/specs/quiver-v24-dx-onboarding-hardening/pr.md +76 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/slice.json +55 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/slice.json +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/slice.json +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/slice.json +70 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/EXECUTION_BRIEF.md +49 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/slice.json +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/slice.json +60 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/slice.json +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/slice.json +54 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/EXECUTION_BRIEF.md +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/slice.json +59 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/slice.json +76 -0
- package/src/create-quiver/commands/ai.js +508 -35
- package/src/create-quiver/commands/demo.js +22 -0
- package/src/create-quiver/commands/evidence.js +37 -0
- package/src/create-quiver/commands/flow.js +561 -0
- package/src/create-quiver/commands/graph.js +14 -1
- package/src/create-quiver/commands/next.js +28 -0
- package/src/create-quiver/commands/plan.js +6 -3
- package/src/create-quiver/commands/prepare.js +236 -0
- package/src/create-quiver/commands/spec.js +133 -0
- package/src/create-quiver/index.js +688 -25
- package/src/create-quiver/lib/agent-profiles.js +148 -0
- package/src/create-quiver/lib/ai/context-packs.js +12 -0
- package/src/create-quiver/lib/ai/execution-plan.js +370 -10
- package/src/create-quiver/lib/ai/executor.js +376 -17
- package/src/create-quiver/lib/ai/github.js +196 -0
- package/src/create-quiver/lib/ai/onboarding-template.js +365 -0
- package/src/create-quiver/lib/ai/plan-review.js +283 -0
- package/src/create-quiver/lib/ai/providers.js +1 -0
- package/src/create-quiver/lib/ai/safety.js +5 -0
- package/src/create-quiver/lib/ai/spec-templates.js +2 -2
- package/src/create-quiver/lib/approvals.js +350 -0
- package/src/create-quiver/lib/demo.js +657 -0
- package/src/create-quiver/lib/doctor.js +234 -0
- package/src/create-quiver/lib/evidence.js +115 -0
- package/src/create-quiver/lib/init-docs.js +284 -17
- package/src/create-quiver/lib/init-layout.js +26 -1
- package/src/create-quiver/lib/lifecycle.js +6 -0
- package/src/create-quiver/lib/package-safety.js +117 -0
- package/src/create-quiver/lib/readiness.js +85 -18
- package/src/create-quiver/lib/slice-graph.js +1 -0
- package/src/create-quiver/lib/slice.js +8 -8
- package/src/create-quiver/lib/spec-worktrees.js +349 -0
|
@@ -2,10 +2,34 @@ const fs = require('node:fs');
|
|
|
2
2
|
const path = require('node:path');
|
|
3
3
|
|
|
4
4
|
const { buildContextPackMetadata, normalizeRole } = require('../lib/ai/context-packs');
|
|
5
|
-
const { runExecuteSlice } = require('../lib/ai/executor');
|
|
6
|
-
const {
|
|
5
|
+
const { runExecuteSlice, runPromptSlice } = require('../lib/ai/executor');
|
|
6
|
+
const { runExecutePlan } = require('../lib/ai/execution-plan');
|
|
7
|
+
const { buildPrCreatePlan, formatPreflightReport, formatPrCreateReport, preflightGitHubPr, runGhPrCreate } = require('../lib/ai/github');
|
|
8
|
+
const { buildContextPreparationDrafts, buildPlannerOnboardingPrompt } = require('../lib/ai/onboarding-template');
|
|
9
|
+
const {
|
|
10
|
+
PLAN_REVIEW_PROMPT_SOURCE,
|
|
11
|
+
buildPlanReviewPrompt,
|
|
12
|
+
resolveReviewedTechnicalPlanInput,
|
|
13
|
+
resolveTechnicalPlanReviewInput,
|
|
14
|
+
savePlanReview,
|
|
15
|
+
summarizePlanReview,
|
|
16
|
+
} = require('../lib/ai/plan-review');
|
|
7
17
|
const { buildSpecGenerationManifest, describeSpecGeneration, generateSpecArtifacts } = require('../lib/ai/spec-generator');
|
|
8
18
|
const { buildProviderInvocation, runProvider } = require('../lib/ai/providers');
|
|
19
|
+
const {
|
|
20
|
+
agentProfilesPath,
|
|
21
|
+
getAgentProfile,
|
|
22
|
+
listAgentProfiles,
|
|
23
|
+
resolveProfileProvider,
|
|
24
|
+
setAgentProfile,
|
|
25
|
+
} = require('../lib/agent-profiles');
|
|
26
|
+
const {
|
|
27
|
+
PLANNER_APPROVAL_PHASES,
|
|
28
|
+
approvePlannerPhase,
|
|
29
|
+
resolveApprovedPlannerInput,
|
|
30
|
+
savePlannerDraft,
|
|
31
|
+
summarizePlannerApproval,
|
|
32
|
+
} = require('../lib/approvals');
|
|
9
33
|
const { assertPlannerPhaseReady, getPlannerPhaseDetails, normalizePlannerPhase, PlannerPhaseError } = require('../lib/ai/phase-gates');
|
|
10
34
|
|
|
11
35
|
const DEFAULT_ONBOARD_PROVIDER = 'codex';
|
|
@@ -33,6 +57,14 @@ function readTextFile(filePath, repoRoot) {
|
|
|
33
57
|
return fs.readFileSync(resolved, 'utf8');
|
|
34
58
|
}
|
|
35
59
|
|
|
60
|
+
function readTextFileOrEmpty(filePath, repoRoot) {
|
|
61
|
+
if (!filePath) {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return readTextFile(filePath, repoRoot);
|
|
66
|
+
}
|
|
67
|
+
|
|
36
68
|
function normalizeTimeout(timeoutMs) {
|
|
37
69
|
if (timeoutMs === undefined || timeoutMs === null || timeoutMs === '') {
|
|
38
70
|
return undefined;
|
|
@@ -46,6 +78,13 @@ function normalizeTimeout(timeoutMs) {
|
|
|
46
78
|
return parsed;
|
|
47
79
|
}
|
|
48
80
|
|
|
81
|
+
function resolveProviderForProfile(repoRoot, role, provider, providerExplicit, fallbackProvider) {
|
|
82
|
+
if (providerExplicit === true || (provider && providerExplicit !== false)) {
|
|
83
|
+
return String(provider || fallbackProvider).trim().toLowerCase();
|
|
84
|
+
}
|
|
85
|
+
return resolveProfileProvider(repoRoot, role, fallbackProvider);
|
|
86
|
+
}
|
|
87
|
+
|
|
49
88
|
function buildPlanContext({ role, context, phase, inputText, inputPath, repoRoot }) {
|
|
50
89
|
const phaseDetails = getPlannerPhaseDetails(phase);
|
|
51
90
|
const pack = buildContextPackMetadata({
|
|
@@ -88,32 +127,21 @@ function buildOnboardContext({ role, context, inputText, inputPath, repoRoot })
|
|
|
88
127
|
repoRoot,
|
|
89
128
|
});
|
|
90
129
|
const relativeInputPath = inputPath ? path.relative(repoRoot, path.resolve(repoRoot, inputPath)).split(path.sep).join('/') : '';
|
|
91
|
-
const
|
|
92
|
-
pack
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (relativeInputPath) {
|
|
99
|
-
sections.push(`Input file: ${relativeInputPath}`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (pack.scanArtifact) {
|
|
103
|
-
sections.push(`Project scan artifact: ${pack.scanArtifact.path} (${pack.scanArtifact.source})`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (inputText) {
|
|
107
|
-
sections.push('Input:', inputText.trimEnd());
|
|
108
|
-
}
|
|
130
|
+
const built = buildPlannerOnboardingPrompt({
|
|
131
|
+
pack,
|
|
132
|
+
inputText,
|
|
133
|
+
inputPath: relativeInputPath,
|
|
134
|
+
repoRoot,
|
|
135
|
+
});
|
|
109
136
|
|
|
110
137
|
return {
|
|
111
138
|
pack,
|
|
112
|
-
|
|
139
|
+
plan: built.plan,
|
|
140
|
+
prompt: built.prompt,
|
|
113
141
|
};
|
|
114
142
|
}
|
|
115
143
|
|
|
116
|
-
function formatDryRunReport({ task, provider, role, contextPack, phase, invocation }) {
|
|
144
|
+
function formatDryRunReport({ task, provider, role, contextPack, phase, invocation, onboardingPlan }) {
|
|
117
145
|
const lines = [
|
|
118
146
|
`AI ${task} dry-run`,
|
|
119
147
|
`Provider: ${provider}`,
|
|
@@ -130,6 +158,50 @@ function formatDryRunReport({ task, provider, role, contextPack, phase, invocati
|
|
|
130
158
|
lines.push(`Prompt transport: ${invocation.promptTransport.mode}`);
|
|
131
159
|
lines.push(`Prompt length: ${invocation.promptLength} bytes`);
|
|
132
160
|
|
|
161
|
+
if (onboardingPlan) {
|
|
162
|
+
lines.push(`Prompt source: ${onboardingPlan.promptSource}`);
|
|
163
|
+
lines.push(`Selected docs: ${onboardingPlan.selectedDocs.length}`);
|
|
164
|
+
lines.push(`Documentation debt: ${onboardingPlan.missingDocs.length}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return `${lines.join('\n')}\n`;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function formatPathList(items, emptyLabel = 'none') {
|
|
171
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
172
|
+
return [`- ${emptyLabel}`];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return items.map((item) => `- ${item}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function formatContextPreparationReport({ dryRun, plan, docs, writtenDocs }) {
|
|
179
|
+
const lines = [
|
|
180
|
+
dryRun ? 'AI prepare-context dry-run' : 'AI prepare-context completed',
|
|
181
|
+
`Mode: ${dryRun ? 'dry-run' : 'live'}`,
|
|
182
|
+
`Project: ${plan.projectName}`,
|
|
183
|
+
`Project slug: ${plan.projectSlug}`,
|
|
184
|
+
'Writes: docs-only',
|
|
185
|
+
'Product code: untouched',
|
|
186
|
+
`Proposed docs: ${docs.length > 0 ? docs.map((doc) => doc.path).join(', ') : 'none'}`,
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
if (!dryRun) {
|
|
190
|
+
lines.push(`Written docs: ${writtenDocs.length > 0 ? writtenDocs.join(', ') : 'none'}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
lines.push(
|
|
194
|
+
'Files considered:',
|
|
195
|
+
...plan.filesConsidered.map((item) => `- ${item.path}: ${item.present ? 'present' : 'absent'}${item.reason ? ` (${item.reason})` : ''}`),
|
|
196
|
+
'Assumptions:',
|
|
197
|
+
...formatPathList(plan.assumptions),
|
|
198
|
+
'Risks:',
|
|
199
|
+
...formatPathList(plan.risks),
|
|
200
|
+
'Omitted paths:',
|
|
201
|
+
...formatPathList(plan.omittedPaths),
|
|
202
|
+
'Uncertainty markers: TODO | Assumption | Pending confirmation',
|
|
203
|
+
);
|
|
204
|
+
|
|
133
205
|
return `${lines.join('\n')}\n`;
|
|
134
206
|
}
|
|
135
207
|
|
|
@@ -142,6 +214,17 @@ function writeProviderOutput(result) {
|
|
|
142
214
|
}
|
|
143
215
|
}
|
|
144
216
|
|
|
217
|
+
function writeDraftDocs(repoRoot, drafts) {
|
|
218
|
+
const writtenDocs = [];
|
|
219
|
+
for (const draft of drafts) {
|
|
220
|
+
const destinationPath = path.join(repoRoot, draft.path);
|
|
221
|
+
fs.mkdirSync(path.dirname(destinationPath), { recursive: true });
|
|
222
|
+
fs.writeFileSync(destinationPath, `${draft.content.replace(/\s+$/g, '')}\n`);
|
|
223
|
+
writtenDocs.push(draft.path);
|
|
224
|
+
}
|
|
225
|
+
return writtenDocs;
|
|
226
|
+
}
|
|
227
|
+
|
|
145
228
|
function formatSpecDryRunReport({ manifest, repoRoot }) {
|
|
146
229
|
const preview = describeSpecGeneration(manifest, repoRoot);
|
|
147
230
|
const relativeSpecDir = path.relative(repoRoot, preview.specDir).split(path.sep).join('/');
|
|
@@ -178,6 +261,43 @@ function formatSpecGenerationResult(result, repoRoot) {
|
|
|
178
261
|
return `${lines.join('\n')}\n`;
|
|
179
262
|
}
|
|
180
263
|
|
|
264
|
+
function formatApprovalResult(result, repoRoot) {
|
|
265
|
+
const relativePath = path.relative(repoRoot, result.filePath).split(path.sep).join('/');
|
|
266
|
+
const lines = [
|
|
267
|
+
'AI approval saved',
|
|
268
|
+
`Phase: ${result.phase}`,
|
|
269
|
+
`Status: approved`,
|
|
270
|
+
`Artifact: ${relativePath}`,
|
|
271
|
+
`Source file: ${result.sourceFile}`,
|
|
272
|
+
`Timestamp: ${result.createdAt}`,
|
|
273
|
+
];
|
|
274
|
+
if (result.version) {
|
|
275
|
+
lines.push(`Version: v${result.version}`);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return `${lines.join('\n')}\n`;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function formatApprovalDryRunResult({ phase, input, version }) {
|
|
282
|
+
const lines = ['AI approval dry-run', `Phase: ${phase}`];
|
|
283
|
+
if (version) {
|
|
284
|
+
lines.push(`Version: v${version}`);
|
|
285
|
+
}
|
|
286
|
+
if (input) {
|
|
287
|
+
lines.push(`Input file: ${input}`);
|
|
288
|
+
}
|
|
289
|
+
return `${lines.join('\n')}\n`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function formatApprovalStatusReport(repoRoot) {
|
|
293
|
+
const sections = ['AI approvals status'];
|
|
294
|
+
for (const phase of PLANNER_APPROVAL_PHASES) {
|
|
295
|
+
sections.push(summarizePlannerApproval(repoRoot, phase).trimEnd());
|
|
296
|
+
}
|
|
297
|
+
sections.push(summarizePlanReview(repoRoot).trimEnd());
|
|
298
|
+
return `${sections.join('\n\n')}\n`;
|
|
299
|
+
}
|
|
300
|
+
|
|
181
301
|
function annotateProviderError(error, scope, phase) {
|
|
182
302
|
const phaseLabel = phase ? ` phase '${phase}'` : '';
|
|
183
303
|
const message = error && error.message ? error.message : String(error);
|
|
@@ -198,12 +318,13 @@ function annotateGitHubError(error, scope) {
|
|
|
198
318
|
}
|
|
199
319
|
|
|
200
320
|
async function runOnboard(repoRoot, options = {}) {
|
|
201
|
-
const provider = String(options.provider || DEFAULT_ONBOARD_PROVIDER).trim().toLowerCase();
|
|
202
321
|
const role = normalizeRole(options.role || DEFAULT_ONBOARD_ROLE);
|
|
322
|
+
const provider = resolveProviderForProfile(repoRoot, role, options.provider, options.providerExplicit, DEFAULT_ONBOARD_PROVIDER);
|
|
203
323
|
const context = options.context || DEFAULT_ONBOARD_CONTEXT;
|
|
204
324
|
const timeoutMs = normalizeTimeout(options.timeout);
|
|
205
325
|
const inputText = readTextFile(options.input, repoRoot);
|
|
206
|
-
const
|
|
326
|
+
const contextInfo = buildOnboardContext({ role, context, inputText, inputPath: options.input, repoRoot });
|
|
327
|
+
const prompt = contextInfo.prompt;
|
|
207
328
|
let invocation;
|
|
208
329
|
|
|
209
330
|
try {
|
|
@@ -223,6 +344,7 @@ async function runOnboard(repoRoot, options = {}) {
|
|
|
223
344
|
role,
|
|
224
345
|
contextPack: context,
|
|
225
346
|
invocation,
|
|
347
|
+
onboardingPlan: contextInfo.plan,
|
|
226
348
|
};
|
|
227
349
|
process.stdout.write(formatDryRunReport(report));
|
|
228
350
|
return report;
|
|
@@ -257,25 +379,58 @@ async function runOnboard(repoRoot, options = {}) {
|
|
|
257
379
|
role,
|
|
258
380
|
contextPack: context,
|
|
259
381
|
invocation,
|
|
382
|
+
onboardingPlan: contextInfo.plan,
|
|
260
383
|
result,
|
|
261
384
|
};
|
|
262
385
|
}
|
|
263
386
|
|
|
387
|
+
async function runPrepareContext(repoRoot, options = {}) {
|
|
388
|
+
const draftPack = buildContextPreparationDrafts(repoRoot);
|
|
389
|
+
const report = {
|
|
390
|
+
task: 'prepare-context',
|
|
391
|
+
dryRun: options.dryRun === true,
|
|
392
|
+
docs: draftPack.docs.map((doc) => doc.path),
|
|
393
|
+
plan: draftPack.plan,
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
if (options.dryRun) {
|
|
397
|
+
process.stdout.write(formatContextPreparationReport({
|
|
398
|
+
dryRun: true,
|
|
399
|
+
docs: draftPack.docs,
|
|
400
|
+
plan: draftPack.plan,
|
|
401
|
+
writtenDocs: [],
|
|
402
|
+
}));
|
|
403
|
+
return report;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const writtenDocs = writeDraftDocs(repoRoot, draftPack.docs);
|
|
407
|
+
process.stdout.write(formatContextPreparationReport({
|
|
408
|
+
dryRun: false,
|
|
409
|
+
docs: draftPack.docs,
|
|
410
|
+
plan: draftPack.plan,
|
|
411
|
+
writtenDocs,
|
|
412
|
+
}));
|
|
413
|
+
|
|
414
|
+
return {
|
|
415
|
+
...report,
|
|
416
|
+
writtenDocs,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
264
420
|
async function runPlan(repoRoot, options = {}) {
|
|
265
421
|
const phase = normalizePlannerPhase(options.phase || DEFAULT_PLAN_PHASE);
|
|
266
422
|
const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
|
|
267
|
-
const provider =
|
|
423
|
+
const provider = resolveProviderForProfile(repoRoot, role, options.provider, options.providerExplicit, DEFAULT_PLAN_PROVIDER);
|
|
268
424
|
const context = options.context || DEFAULT_PLAN_CONTEXT;
|
|
269
425
|
const timeoutMs = normalizeTimeout(options.timeout);
|
|
270
|
-
|
|
271
|
-
if (!options.input) {
|
|
272
|
-
throw new Error(formatError(`missing input file for ai plan phase '${phase}'`));
|
|
273
|
-
}
|
|
426
|
+
let inputPath = options.input || '';
|
|
274
427
|
|
|
275
428
|
if (phase === 'spec') {
|
|
276
|
-
const
|
|
429
|
+
const resolved = resolveReviewedTechnicalPlanInput(repoRoot, inputPath || undefined);
|
|
430
|
+
inputPath = resolved.inputPath;
|
|
431
|
+
const inputText = readTextFileOrEmpty(inputPath, repoRoot);
|
|
277
432
|
const manifest = buildSpecGenerationManifest({
|
|
278
|
-
inputPath
|
|
433
|
+
inputPath,
|
|
279
434
|
inputText,
|
|
280
435
|
repoRoot,
|
|
281
436
|
specSlug: options.specSlug,
|
|
@@ -292,7 +447,7 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
292
447
|
}
|
|
293
448
|
|
|
294
449
|
const result = generateSpecArtifacts(repoRoot, {
|
|
295
|
-
input:
|
|
450
|
+
input: inputPath,
|
|
296
451
|
specSlug: options.specSlug,
|
|
297
452
|
});
|
|
298
453
|
process.stdout.write(formatSpecGenerationResult(result, repoRoot));
|
|
@@ -309,13 +464,22 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
309
464
|
|
|
310
465
|
assertPlannerPhaseReady(phase);
|
|
311
466
|
|
|
312
|
-
|
|
467
|
+
if (phase === 'technical-plan') {
|
|
468
|
+
const resolved = resolveApprovedPlannerInput(repoRoot, phase, inputPath || undefined);
|
|
469
|
+
inputPath = resolved.inputPath;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (!inputPath) {
|
|
473
|
+
throw new Error(formatError(`missing input file for ai plan phase '${phase}'`));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const inputText = readTextFile(inputPath, repoRoot);
|
|
313
477
|
const contextInfo = buildPlanContext({
|
|
314
478
|
role,
|
|
315
479
|
context,
|
|
316
480
|
phase,
|
|
317
481
|
inputText,
|
|
318
|
-
inputPath
|
|
482
|
+
inputPath,
|
|
319
483
|
repoRoot,
|
|
320
484
|
});
|
|
321
485
|
const prompt = contextInfo.prompt;
|
|
@@ -367,6 +531,8 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
367
531
|
throw annotateProviderError(result.error || new Error('provider run failed'), 'plan', phase);
|
|
368
532
|
}
|
|
369
533
|
|
|
534
|
+
savePlannerDraft(repoRoot, phase, inputPath, [result.stdout, result.stderr].filter(Boolean).join(''));
|
|
535
|
+
|
|
370
536
|
return {
|
|
371
537
|
task: 'plan',
|
|
372
538
|
provider,
|
|
@@ -378,6 +544,244 @@ async function runPlan(repoRoot, options = {}) {
|
|
|
378
544
|
};
|
|
379
545
|
}
|
|
380
546
|
|
|
547
|
+
async function runReviewPlan(repoRoot, options = {}) {
|
|
548
|
+
const role = 'planner';
|
|
549
|
+
const provider = resolveProviderForProfile(repoRoot, 'reviewer', options.provider, options.providerExplicit, DEFAULT_PLAN_PROVIDER);
|
|
550
|
+
const context = options.context || DEFAULT_PLAN_CONTEXT;
|
|
551
|
+
const timeoutMs = normalizeTimeout(options.timeout);
|
|
552
|
+
const resolved = resolveTechnicalPlanReviewInput(repoRoot, options.input || undefined);
|
|
553
|
+
const inputPath = resolved.inputPath;
|
|
554
|
+
const inputText = readTextFile(inputPath, repoRoot);
|
|
555
|
+
const pack = buildContextPackMetadata({
|
|
556
|
+
role,
|
|
557
|
+
packName: context,
|
|
558
|
+
repoRoot,
|
|
559
|
+
});
|
|
560
|
+
const built = buildPlanReviewPrompt({
|
|
561
|
+
pack,
|
|
562
|
+
inputText,
|
|
563
|
+
inputPath,
|
|
564
|
+
});
|
|
565
|
+
let invocation;
|
|
566
|
+
|
|
567
|
+
try {
|
|
568
|
+
invocation = buildProviderInvocation(provider, {
|
|
569
|
+
prompt: built.prompt,
|
|
570
|
+
cwd: repoRoot,
|
|
571
|
+
timeoutMs,
|
|
572
|
+
});
|
|
573
|
+
} catch (error) {
|
|
574
|
+
throw annotateProviderError(error, 'review-plan');
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (options.dryRun) {
|
|
578
|
+
const report = {
|
|
579
|
+
task: 'review-plan',
|
|
580
|
+
provider,
|
|
581
|
+
role: 'reviewer',
|
|
582
|
+
contextPack: pack.packName,
|
|
583
|
+
invocation,
|
|
584
|
+
promptSource: built.promptSource,
|
|
585
|
+
inputPath,
|
|
586
|
+
inputKind: resolved.kind,
|
|
587
|
+
inputVersion: resolved.version,
|
|
588
|
+
};
|
|
589
|
+
process.stdout.write(formatDryRunReport({
|
|
590
|
+
task: 'review-plan',
|
|
591
|
+
provider,
|
|
592
|
+
role: 'reviewer',
|
|
593
|
+
contextPack: pack.packName,
|
|
594
|
+
phase: 'plan-review',
|
|
595
|
+
invocation,
|
|
596
|
+
}));
|
|
597
|
+
process.stdout.write(`Prompt source: ${built.promptSource}\n`);
|
|
598
|
+
process.stdout.write(`Input file: ${inputPath}\n`);
|
|
599
|
+
process.stdout.write(`Input kind: ${resolved.kind}\n`);
|
|
600
|
+
if (resolved.version) {
|
|
601
|
+
process.stdout.write(`Input version: v${resolved.version}\n`);
|
|
602
|
+
}
|
|
603
|
+
return report;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
let result;
|
|
607
|
+
try {
|
|
608
|
+
result = await (options.runProviderFn || runProvider)(provider, {
|
|
609
|
+
prompt: built.prompt,
|
|
610
|
+
cwd: repoRoot,
|
|
611
|
+
timeoutMs,
|
|
612
|
+
dryRun: false,
|
|
613
|
+
probe: options.probe,
|
|
614
|
+
spawn: options.spawn,
|
|
615
|
+
tempRoot: options.tempRoot,
|
|
616
|
+
tempFileName: options.tempFileName,
|
|
617
|
+
tempFilePrefix: options.tempFilePrefix,
|
|
618
|
+
});
|
|
619
|
+
} catch (error) {
|
|
620
|
+
throw annotateProviderError(error, 'review-plan');
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
writeProviderOutput(result);
|
|
624
|
+
|
|
625
|
+
if (!result.ok) {
|
|
626
|
+
throw annotateProviderError(result.error || new Error('provider run failed'), 'review-plan');
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
const saved = savePlanReview(repoRoot, {
|
|
630
|
+
contents: [result.stdout, result.stderr].filter(Boolean).join(''),
|
|
631
|
+
inputPath,
|
|
632
|
+
inputKind: resolved.kind,
|
|
633
|
+
inputVersion: resolved.version,
|
|
634
|
+
});
|
|
635
|
+
const relativePath = path.relative(repoRoot, saved.filePath).split(path.sep).join('/');
|
|
636
|
+
process.stdout.write(`AI plan review saved\nArtifact: ${relativePath}\nPrompt source: ${PLAN_REVIEW_PROMPT_SOURCE}\n`);
|
|
637
|
+
|
|
638
|
+
return {
|
|
639
|
+
task: 'review-plan',
|
|
640
|
+
provider,
|
|
641
|
+
role: 'reviewer',
|
|
642
|
+
contextPack: pack.packName,
|
|
643
|
+
inputPath,
|
|
644
|
+
inputKind: resolved.kind,
|
|
645
|
+
inputVersion: resolved.version,
|
|
646
|
+
filePath: relativePath,
|
|
647
|
+
invocation,
|
|
648
|
+
result,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
async function runApprove(repoRoot, options = {}) {
|
|
653
|
+
const phase = normalizePlannerPhase(options.phase || DEFAULT_PLAN_PHASE);
|
|
654
|
+
if (phase === 'spec') {
|
|
655
|
+
throw new Error(formatError(`ai approve does not support phase '${phase}'`));
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if (!options.input && !options.version) {
|
|
659
|
+
throw new Error(formatError(`missing input file for ai approve phase '${phase}'`));
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
const inputText = options.version ? '' : readTextFile(options.input, repoRoot);
|
|
663
|
+
|
|
664
|
+
if (options.dryRun) {
|
|
665
|
+
process.stdout.write(formatApprovalDryRunResult({ phase, input: options.input, version: options.version }));
|
|
666
|
+
return {
|
|
667
|
+
task: 'approve',
|
|
668
|
+
phase,
|
|
669
|
+
input: options.input,
|
|
670
|
+
version: options.version || null,
|
|
671
|
+
dryRun: true,
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
const result = approvePlannerPhase(repoRoot, phase, options.input || '', inputText, {
|
|
676
|
+
version: options.version || undefined,
|
|
677
|
+
});
|
|
678
|
+
process.stdout.write(formatApprovalResult({
|
|
679
|
+
...result,
|
|
680
|
+
sourceFile: options.input || `draft version ${options.version}`,
|
|
681
|
+
}, repoRoot));
|
|
682
|
+
|
|
683
|
+
return {
|
|
684
|
+
task: 'approve',
|
|
685
|
+
phase,
|
|
686
|
+
input: options.input,
|
|
687
|
+
filePath: path.relative(repoRoot, result.filePath).split(path.sep).join('/'),
|
|
688
|
+
createdAt: result.createdAt,
|
|
689
|
+
version: result.version || null,
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
async function runApprovalStatus(repoRoot) {
|
|
694
|
+
const report = formatApprovalStatusReport(repoRoot);
|
|
695
|
+
process.stdout.write(report);
|
|
696
|
+
return {
|
|
697
|
+
task: 'approval-status',
|
|
698
|
+
report,
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
function formatAgentProfile(profile) {
|
|
703
|
+
const lines = [
|
|
704
|
+
`Role: ${profile.role}`,
|
|
705
|
+
`Provider: ${profile.provider}`,
|
|
706
|
+
`Model: ${profile.model || '(not set)'}`,
|
|
707
|
+
`Label: ${profile.label || '(not set)'}`,
|
|
708
|
+
`Context: ${profile.context || '(not set)'}`,
|
|
709
|
+
`Updated: ${profile.updated_at}`,
|
|
710
|
+
];
|
|
711
|
+
return `${lines.join('\n')}\n`;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function formatAgentProfileList(profiles) {
|
|
715
|
+
const lines = ['AI agent profiles'];
|
|
716
|
+
for (const item of profiles) {
|
|
717
|
+
if (!item.configured) {
|
|
718
|
+
lines.push(`- ${item.role}: not configured`);
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
const model = item.profile.model ? ` model=${item.profile.model}` : '';
|
|
722
|
+
const label = item.profile.label ? ` label=${item.profile.label}` : '';
|
|
723
|
+
lines.push(`- ${item.role}: provider=${item.profile.provider}${model}${label}`);
|
|
724
|
+
}
|
|
725
|
+
return `${lines.join('\n')}\n`;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
function runAgent(repoRoot, options = {}) {
|
|
729
|
+
const command = String(options.command || '').trim().toLowerCase();
|
|
730
|
+
|
|
731
|
+
if (command === 'set') {
|
|
732
|
+
if (!options.role) {
|
|
733
|
+
throw new Error(formatError('missing agent role. Use: npx create-quiver ai agent set <planner|executor|reviewer|researcher> --provider <provider>'));
|
|
734
|
+
}
|
|
735
|
+
if (!options.provider) {
|
|
736
|
+
throw new Error(formatError('ai agent set requires --provider. Supported providers: codex, claude, gemini.'));
|
|
737
|
+
}
|
|
738
|
+
const result = setAgentProfile(repoRoot, options.role, {
|
|
739
|
+
context: options.context,
|
|
740
|
+
label: options.label,
|
|
741
|
+
model: options.model,
|
|
742
|
+
provider: options.provider,
|
|
743
|
+
});
|
|
744
|
+
process.stdout.write('AI agent profile saved\n');
|
|
745
|
+
process.stdout.write(formatAgentProfile(result.profile));
|
|
746
|
+
process.stdout.write(`State: ${path.relative(repoRoot, result.filePath).split(path.sep).join('/')}\n`);
|
|
747
|
+
return {
|
|
748
|
+
task: 'agent',
|
|
749
|
+
command,
|
|
750
|
+
profile: result.profile,
|
|
751
|
+
filePath: path.relative(repoRoot, result.filePath).split(path.sep).join('/'),
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (command === 'show') {
|
|
756
|
+
if (!options.role) {
|
|
757
|
+
throw new Error(formatError('missing agent role. Use: npx create-quiver ai agent show <planner|executor|reviewer|researcher>'));
|
|
758
|
+
}
|
|
759
|
+
const profile = getAgentProfile(repoRoot, options.role);
|
|
760
|
+
if (!profile) {
|
|
761
|
+
throw new Error(formatError(`agent profile '${options.role}' is not configured. Run: npx create-quiver ai agent set ${options.role} --provider <provider> --model <label>`));
|
|
762
|
+
}
|
|
763
|
+
process.stdout.write(formatAgentProfile(profile));
|
|
764
|
+
return {
|
|
765
|
+
task: 'agent',
|
|
766
|
+
command,
|
|
767
|
+
profile,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (command === 'list' || command === 'ls' || command === '') {
|
|
772
|
+
const profiles = listAgentProfiles(repoRoot);
|
|
773
|
+
process.stdout.write(formatAgentProfileList(profiles));
|
|
774
|
+
process.stdout.write(`State: ${path.relative(repoRoot, agentProfilesPath(repoRoot)).split(path.sep).join('/')}\n`);
|
|
775
|
+
return {
|
|
776
|
+
task: 'agent',
|
|
777
|
+
command: 'list',
|
|
778
|
+
profiles,
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
throw new Error(formatError(`unsupported ai agent subcommand: ${command}. Supported tasks: set, list, show`));
|
|
783
|
+
}
|
|
784
|
+
|
|
381
785
|
async function runGitHubTask(repoRoot, options = {}, mode = 'pr') {
|
|
382
786
|
const dryRun = options.dryRun === true;
|
|
383
787
|
let report;
|
|
@@ -409,7 +813,69 @@ async function runGitHubTask(repoRoot, options = {}, mode = 'pr') {
|
|
|
409
813
|
}
|
|
410
814
|
|
|
411
815
|
async function runPr(repoRoot, options = {}) {
|
|
412
|
-
|
|
816
|
+
const dryRun = options.dryRun === true;
|
|
817
|
+
const create = options.create === true;
|
|
818
|
+
let preflight;
|
|
819
|
+
|
|
820
|
+
try {
|
|
821
|
+
preflight = await (options.preflightFn || preflightGitHubPr)(repoRoot, {
|
|
822
|
+
remote: options.remote,
|
|
823
|
+
sshHostAlias: options.sshHostAlias,
|
|
824
|
+
identityFile: options.identityFile,
|
|
825
|
+
gitFlowGuidePath: options.gitFlowGuidePath,
|
|
826
|
+
ghCommand: options.ghCommand,
|
|
827
|
+
ghProbe: options.ghProbe,
|
|
828
|
+
ghAuthProbe: options.ghAuthProbe,
|
|
829
|
+
ghProbeArgs: options.ghProbeArgs,
|
|
830
|
+
ghAuthArgs: options.ghAuthArgs,
|
|
831
|
+
blockedBranches: options.blockedBranches,
|
|
832
|
+
});
|
|
833
|
+
} catch (error) {
|
|
834
|
+
throw annotateGitHubError(error, 'pr');
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
let plan;
|
|
838
|
+
try {
|
|
839
|
+
plan = buildPrCreatePlan(repoRoot, preflight, {
|
|
840
|
+
baseBranch: options.baseBranch,
|
|
841
|
+
ghCommand: options.ghCommand,
|
|
842
|
+
input: options.input,
|
|
843
|
+
prBodyPath: options.prBodyPath,
|
|
844
|
+
title: options.title,
|
|
845
|
+
});
|
|
846
|
+
} catch (error) {
|
|
847
|
+
throw annotateGitHubError(error, 'pr');
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (dryRun || !create) {
|
|
851
|
+
process.stdout.write(formatPrCreateReport({ preflight, plan }, { dryRun, create }));
|
|
852
|
+
return {
|
|
853
|
+
task: 'pr',
|
|
854
|
+
dryRun,
|
|
855
|
+
create,
|
|
856
|
+
preflight,
|
|
857
|
+
plan,
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
let result;
|
|
862
|
+
try {
|
|
863
|
+
result = runGhPrCreate(plan, {
|
|
864
|
+
ghCreateRunner: options.ghCreateRunner,
|
|
865
|
+
});
|
|
866
|
+
} catch (error) {
|
|
867
|
+
throw annotateGitHubError(error, 'pr');
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
process.stdout.write(formatPrCreateReport({ preflight, plan, result }, { dryRun: false, create: true }));
|
|
871
|
+
return {
|
|
872
|
+
task: 'pr',
|
|
873
|
+
dryRun: false,
|
|
874
|
+
create: true,
|
|
875
|
+
preflight,
|
|
876
|
+
plan,
|
|
877
|
+
result,
|
|
878
|
+
};
|
|
413
879
|
}
|
|
414
880
|
|
|
415
881
|
async function runDoctor(repoRoot, options = {}) {
|
|
@@ -433,8 +899,15 @@ module.exports = {
|
|
|
433
899
|
formatSpecDryRunReport,
|
|
434
900
|
normalizeTimeout,
|
|
435
901
|
readTextFile,
|
|
902
|
+
runAgent,
|
|
436
903
|
runDoctor,
|
|
904
|
+
runExecutePlan,
|
|
437
905
|
runExecuteSlice,
|
|
906
|
+
runPromptSlice,
|
|
907
|
+
runApprove,
|
|
908
|
+
runApprovalStatus,
|
|
909
|
+
runPrepareContext,
|
|
910
|
+
runReviewPlan,
|
|
438
911
|
runPr,
|
|
439
912
|
runOnboard,
|
|
440
913
|
runPlan,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const { buildDemoPlan, formatDemoPlan, writeDemoPlan } = require('../lib/demo');
|
|
2
|
+
|
|
3
|
+
function runDemo(options = {}) {
|
|
4
|
+
if (options.command !== 'create') {
|
|
5
|
+
throw new Error(`create-quiver: unsupported demo subcommand: ${options.command || '(missing)'}. Supported tasks: create`);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const plan = buildDemoPlan(options.targetRoot, { demo: options.demo });
|
|
9
|
+
|
|
10
|
+
if (options.dryRun) {
|
|
11
|
+
console.log(formatDemoPlan(plan, { dryRun: true }));
|
|
12
|
+
return plan;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
writeDemoPlan(plan);
|
|
16
|
+
console.log(formatDemoPlan(plan));
|
|
17
|
+
return plan;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
runDemo,
|
|
22
|
+
};
|