create-quiver 0.10.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BACKLOG.md +16 -17
- package/CHANGELOG.md +78 -0
- package/README.md +208 -41
- package/README_FOR_AI.md +50 -24
- package/ROADMAP.md +34 -11
- package/docs/AI_CONTEXT.md.template +2 -0
- package/docs/AI_ONBOARDING_PROMPT.md.template +31 -18
- package/docs/COMMANDS.md.template +90 -16
- 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 +6 -1
- package/docs/SUPPORT_MATRIX.md.template +2 -2
- package/docs/TROUBLESHOOTING.md.template +50 -0
- package/docs/WORKFLOW.md.template +27 -17
- package/package.json +27 -4
- 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/specs/quiver-v25-ai-first-lifecycle-orchestrator/EVIDENCE_REPORT.md +293 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/EXECUTION_PLAN.md +58 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/SPEC.md +242 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/STATUS.md +35 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/pr.md +77 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/slice.json +56 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/slice.json +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/slice.json +53 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/slice.json +55 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/CLOSURE_BRIEF.md +39 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/slice.json +53 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/CLOSURE_BRIEF.md +39 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/slice.json +56 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/slice.json +53 -0
- package/specs/quiver-v26-0121-smoke-hardening/EVIDENCE_REPORT.md +208 -0
- package/specs/quiver-v26-0121-smoke-hardening/EXECUTION_PLAN.md +57 -0
- package/specs/quiver-v26-0121-smoke-hardening/SPEC.md +137 -0
- package/specs/quiver-v26-0121-smoke-hardening/STATUS.md +32 -0
- package/specs/quiver-v26-0121-smoke-hardening/pr.md +96 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/slice.json +73 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/EXECUTION_BRIEF.md +51 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/slice.json +76 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/CLOSURE_BRIEF.md +37 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/slice.json +75 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/CLOSURE_BRIEF.md +37 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/slice.json +77 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/slice.json +77 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/slice.json +84 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/slice.json +82 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/slice.json +92 -0
- package/src/create-quiver/commands/ai.js +1060 -37
- 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 +562 -0
- package/src/create-quiver/commands/graph.js +19 -4
- package/src/create-quiver/commands/next.js +28 -0
- package/src/create-quiver/commands/plan.js +9 -6
- package/src/create-quiver/commands/prepare.js +236 -0
- package/src/create-quiver/commands/spec.js +133 -0
- package/src/create-quiver/index.js +1010 -31
- package/src/create-quiver/lib/actionable-error.js +27 -0
- package/src/create-quiver/lib/agent-profiles.js +148 -0
- package/src/create-quiver/lib/ai/context-packs.js +16 -0
- package/src/create-quiver/lib/ai/execution-plan.js +377 -11
- package/src/create-quiver/lib/ai/executor.js +633 -24
- package/src/create-quiver/lib/ai/export-state.js +534 -0
- package/src/create-quiver/lib/ai/github.js +279 -0
- package/src/create-quiver/lib/ai/onboarding-template.js +578 -0
- package/src/create-quiver/lib/ai/plan-review.js +286 -0
- package/src/create-quiver/lib/ai/providers.js +5 -3
- package/src/create-quiver/lib/ai/run-state.js +414 -0
- package/src/create-quiver/lib/ai/safety.js +5 -0
- package/src/create-quiver/lib/ai/spec-generator.js +12 -0
- package/src/create-quiver/lib/ai/spec-templates.js +80 -11
- package/src/create-quiver/lib/approvals.js +369 -0
- package/src/create-quiver/lib/demo.js +832 -0
- package/src/create-quiver/lib/doctor.js +309 -0
- package/src/create-quiver/lib/evidence.js +115 -0
- package/src/create-quiver/lib/handoff.js +81 -12
- package/src/create-quiver/lib/init-docs.js +302 -17
- package/src/create-quiver/lib/init-layout.js +34 -1
- package/src/create-quiver/lib/json.js +53 -3
- 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 +103 -21
- package/src/create-quiver/lib/scope.js +50 -7
- package/src/create-quiver/lib/slice-graph.js +138 -37
- package/src/create-quiver/lib/slice.js +14 -9
- package/src/create-quiver/lib/spec-worktrees.js +363 -0
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
const fs = require('node:fs');
|
|
2
2
|
const path = require('node:path');
|
|
3
|
+
const cp = require('node:child_process');
|
|
3
4
|
|
|
4
5
|
const { buildContextPackMetadata, normalizeRole } = require('./context-packs');
|
|
5
6
|
const { buildProviderInvocation, runProvider } = require('./providers');
|
|
7
|
+
const { resolveProfileProvider } = require('../agent-profiles');
|
|
8
|
+
const { currentBranch, runGit } = require('../git');
|
|
9
|
+
const { redactSecrets, truncateText } = require('../evidence');
|
|
6
10
|
const { captureWorktreeSnapshot, validateScopeSnapshot } = require('../scope');
|
|
7
11
|
const { resolveSliceContext } = require('../slice');
|
|
8
12
|
|
|
@@ -74,6 +78,213 @@ function formatList(items) {
|
|
|
74
78
|
return items.map((item) => `- ${item}`);
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
function uniqueList(items) {
|
|
82
|
+
return Array.from(new Set((Array.isArray(items) ? items : []).map((item) => String(item)).filter(Boolean)));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function escapeRegex(value) {
|
|
86
|
+
return String(value || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function extractMarkdownHeading(text) {
|
|
90
|
+
const match = String(text || '').match(/^#\s+(.+)$/m);
|
|
91
|
+
return match ? match[1].trim() : '';
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function extractMarkdownSection(text, headings) {
|
|
95
|
+
const lines = String(text || '').split(/\r?\n/);
|
|
96
|
+
const normalized = new Set(headings.map((heading) => String(heading).trim().toLowerCase()));
|
|
97
|
+
const section = [];
|
|
98
|
+
let capture = false;
|
|
99
|
+
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
const heading = line.match(/^##\s+(.+)$/);
|
|
102
|
+
if (heading) {
|
|
103
|
+
const key = heading[1].trim().toLowerCase();
|
|
104
|
+
if (normalized.has(key)) {
|
|
105
|
+
capture = true;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (capture) {
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (capture) {
|
|
114
|
+
section.push(line);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return section.join('\n').trim();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function buildSpecExcerpt(repoRoot, slice) {
|
|
122
|
+
const specPath = path.join(slice.specDirAbs, 'SPEC.md');
|
|
123
|
+
if (!fs.existsSync(specPath)) {
|
|
124
|
+
return {
|
|
125
|
+
path: toRelativePath(repoRoot, specPath),
|
|
126
|
+
lines: ['- n/a'],
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const text = fs.readFileSync(specPath, 'utf8');
|
|
131
|
+
const title = extractMarkdownHeading(text);
|
|
132
|
+
const objective = extractMarkdownSection(text, ['Objective', 'Objetivo']);
|
|
133
|
+
const lines = [];
|
|
134
|
+
|
|
135
|
+
if (title) {
|
|
136
|
+
lines.push(`- Title: ${title}`);
|
|
137
|
+
}
|
|
138
|
+
if (objective) {
|
|
139
|
+
lines.push(`- Objective: ${objective.replace(/\s+/g, ' ').slice(0, 500)}`);
|
|
140
|
+
}
|
|
141
|
+
if (lines.length === 0) {
|
|
142
|
+
lines.push('- SPEC.md exists, but no short title/objective excerpt was found.');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
path: toRelativePath(repoRoot, specPath),
|
|
147
|
+
lines,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function buildManualExecutorPrompt({ repoRoot, slicePath, role, context, tokenLimit } = {}) {
|
|
152
|
+
const executorContext = buildExecuteSliceContext({
|
|
153
|
+
repoRoot,
|
|
154
|
+
slicePath,
|
|
155
|
+
role: role || DEFAULT_EXECUTE_ROLE,
|
|
156
|
+
context: context || DEFAULT_EXECUTE_CONTEXT,
|
|
157
|
+
});
|
|
158
|
+
const canonicalRepoRoot = canonicalizeRepoRoot(repoRoot);
|
|
159
|
+
const closurePath = path.join(path.dirname(executorContext.slice.sliceAbs), 'CLOSURE_BRIEF.md');
|
|
160
|
+
const closureText = readTextFile(closurePath, canonicalRepoRoot);
|
|
161
|
+
const relativeClosurePath = toRelativePath(canonicalRepoRoot, closurePath);
|
|
162
|
+
const specExcerpt = buildSpecExcerpt(canonicalRepoRoot, executorContext.slice);
|
|
163
|
+
const slice = executorContext.slice;
|
|
164
|
+
const objective = String(slice.json.objective || slice.json.description || slice.sliceId).trim();
|
|
165
|
+
const restrictions = [
|
|
166
|
+
'Do not read the whole repo.',
|
|
167
|
+
'Do not modify files outside the allowed files.',
|
|
168
|
+
'Before editing, list the files you will read and the files you expect to modify.',
|
|
169
|
+
'Do not add unrequested features.',
|
|
170
|
+
'Do not refactor architecture unless the slice explicitly requires it.',
|
|
171
|
+
'If another file is needed, justify why before reading it.',
|
|
172
|
+
'If blocked, stop and report the blocker before improvising.',
|
|
173
|
+
];
|
|
174
|
+
const outputFormat = [
|
|
175
|
+
'## Cambios realizados',
|
|
176
|
+
'## Archivos modificados',
|
|
177
|
+
'## Comandos ejecutados',
|
|
178
|
+
'## Validaciones',
|
|
179
|
+
'## Riesgos pendientes',
|
|
180
|
+
'## Proximo paso recomendado',
|
|
181
|
+
];
|
|
182
|
+
const promptLines = [
|
|
183
|
+
'Act as a WDD + SDD executor agent.',
|
|
184
|
+
'',
|
|
185
|
+
'MODE: controlled SLICE execution.',
|
|
186
|
+
'',
|
|
187
|
+
'Slice objective:',
|
|
188
|
+
objective || 'n/a',
|
|
189
|
+
'',
|
|
190
|
+
'Minimal context:',
|
|
191
|
+
`- Spec: ${slice.specSlug}`,
|
|
192
|
+
`- Slice: ${slice.sliceId}`,
|
|
193
|
+
`- Slice file: ${slice.sliceRel}`,
|
|
194
|
+
`- Execution brief: ${executorContext.briefPath}`,
|
|
195
|
+
`- Closure brief: ${relativeClosurePath}`,
|
|
196
|
+
'',
|
|
197
|
+
'Relevant SPEC excerpts:',
|
|
198
|
+
`- Source: ${specExcerpt.path}`,
|
|
199
|
+
...specExcerpt.lines,
|
|
200
|
+
'',
|
|
201
|
+
'Expected read paths:',
|
|
202
|
+
...formatList(executorContext.expectedReadPaths),
|
|
203
|
+
'',
|
|
204
|
+
'Allowed files:',
|
|
205
|
+
...formatList(executorContext.allowedFiles),
|
|
206
|
+
'',
|
|
207
|
+
'Restrictions:',
|
|
208
|
+
...formatList(restrictions),
|
|
209
|
+
'',
|
|
210
|
+
'Acceptance criteria:',
|
|
211
|
+
...formatList(slice.acceptance),
|
|
212
|
+
'',
|
|
213
|
+
'Validation commands:',
|
|
214
|
+
...formatList(executorContext.validationCommands),
|
|
215
|
+
'',
|
|
216
|
+
'Validation hints:',
|
|
217
|
+
...formatList(executorContext.validationHints),
|
|
218
|
+
'',
|
|
219
|
+
'Exact deliverable expected:',
|
|
220
|
+
'- Implement only this slice.',
|
|
221
|
+
'- Keep the change inside the allowed files.',
|
|
222
|
+
'- Leave evidence in the final report.',
|
|
223
|
+
'',
|
|
224
|
+
'Required final report format:',
|
|
225
|
+
...outputFormat.map((line) => `- ${line}`),
|
|
226
|
+
'',
|
|
227
|
+
`Suggested token limit: ${Number(tokenLimit) > 0 ? Number(tokenLimit) : 3000}`,
|
|
228
|
+
'',
|
|
229
|
+
'Execution brief content:',
|
|
230
|
+
executorContext.briefText.trimEnd(),
|
|
231
|
+
'',
|
|
232
|
+
'Closure brief content:',
|
|
233
|
+
closureText.trimEnd(),
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
allowedFiles: executorContext.allowedFiles,
|
|
238
|
+
closurePath: relativeClosurePath,
|
|
239
|
+
prompt: `${promptLines.join('\n')}\n`,
|
|
240
|
+
slice,
|
|
241
|
+
specExcerpt,
|
|
242
|
+
validationCommands: executorContext.validationCommands,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function runPromptSlice(repoRoot, options = {}) {
|
|
247
|
+
if (!options.slice) {
|
|
248
|
+
throw new Error(formatError('missing required --slice path for ai prompt-slice'));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const built = buildManualExecutorPrompt({
|
|
252
|
+
repoRoot,
|
|
253
|
+
slicePath: options.slice,
|
|
254
|
+
tokenLimit: options.tokenLimit,
|
|
255
|
+
});
|
|
256
|
+
process.stdout.write(built.prompt);
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
task: 'prompt-slice',
|
|
260
|
+
slice: built.slice.sliceId,
|
|
261
|
+
specSlug: built.slice.specSlug,
|
|
262
|
+
prompt: built.prompt,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function buildRecoveryGuidance(slice) {
|
|
267
|
+
const sliceRef = slice && slice.sliceRel ? slice.sliceRel : '<slice.json>';
|
|
268
|
+
return [
|
|
269
|
+
'Recovery:',
|
|
270
|
+
`- Retry: npx create-quiver ai execute-slice --slice ${sliceRef}`,
|
|
271
|
+
'- Abort: inspect the local changes, then manually revert or stash anything you do not want to keep.',
|
|
272
|
+
'- Commit: rerun with --commit only after provider, scope, and validation pass.',
|
|
273
|
+
].join('\n');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function appendRecovery(error, slice) {
|
|
277
|
+
if (!error || !error.message || error.message.includes('Recovery:')) {
|
|
278
|
+
return error;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const wrapped = new Error(`${error.message}\n\n${buildRecoveryGuidance(slice)}`);
|
|
282
|
+
wrapped.cause = error;
|
|
283
|
+
wrapped.code = error.code;
|
|
284
|
+
wrapped.details = error.details;
|
|
285
|
+
return wrapped;
|
|
286
|
+
}
|
|
287
|
+
|
|
77
288
|
function buildExecuteSliceContext({ repoRoot, slicePath, role, context }) {
|
|
78
289
|
const canonicalRepoRoot = canonicalizeRepoRoot(repoRoot);
|
|
79
290
|
const resolvedRole = normalizeRole(role || DEFAULT_EXECUTE_ROLE);
|
|
@@ -93,8 +304,10 @@ function buildExecuteSliceContext({ repoRoot, slicePath, role, context }) {
|
|
|
93
304
|
const relativeSlicePath = toRelativePath(canonicalRepoRoot, slice.sliceAbs);
|
|
94
305
|
const relativeBriefPath = toRelativePath(canonicalRepoRoot, briefPath);
|
|
95
306
|
const allowedFiles = Array.isArray(slice.files) ? slice.files.map((file) => String(file)) : [];
|
|
307
|
+
const expectedReadPaths = Array.isArray(slice.expectedReadPaths) ? slice.expectedReadPaths.map((file) => String(file)) : [];
|
|
96
308
|
const acceptance = Array.isArray(slice.acceptance) ? slice.acceptance.map((item) => String(item)) : [];
|
|
97
309
|
const validationCommands = Array.isArray(slice.tests) ? slice.tests.map((item) => String(item)) : [];
|
|
310
|
+
const validationHints = Array.isArray(slice.validationHints) ? slice.validationHints.map((item) => String(item)) : [];
|
|
98
311
|
const mustItems = Array.isArray(slice.json.must) ? slice.json.must.map((item) => String(item)) : [];
|
|
99
312
|
const excludedItems = Array.isArray(slice.json.not_included) ? slice.json.not_included.map((item) => String(item)) : [];
|
|
100
313
|
|
|
@@ -105,6 +318,8 @@ function buildExecuteSliceContext({ repoRoot, slicePath, role, context }) {
|
|
|
105
318
|
`Spec: ${slice.specSlug}`,
|
|
106
319
|
`Slice file: ${relativeSlicePath}`,
|
|
107
320
|
`Execution brief: ${relativeBriefPath}`,
|
|
321
|
+
'Expected read paths:',
|
|
322
|
+
...formatList(expectedReadPaths),
|
|
108
323
|
'Allowed files:',
|
|
109
324
|
...formatList(allowedFiles),
|
|
110
325
|
'Acceptance criteria:',
|
|
@@ -121,9 +336,13 @@ function buildExecuteSliceContext({ repoRoot, slicePath, role, context }) {
|
|
|
121
336
|
sections.push('Not included:', ...formatList(excludedItems));
|
|
122
337
|
}
|
|
123
338
|
|
|
339
|
+
if (validationHints.length > 0) {
|
|
340
|
+
sections.push('Validation hints:', ...formatList(validationHints));
|
|
341
|
+
}
|
|
342
|
+
|
|
124
343
|
sections.push(
|
|
125
344
|
'Constraints:',
|
|
126
|
-
'- Do not commit
|
|
345
|
+
'- Do not commit manually. Quiver can create the slice commit after scope and validation pass when the user enables --commit.',
|
|
127
346
|
'- Do not fix scope violations automatically.',
|
|
128
347
|
'- Do not run multiple executors concurrently.',
|
|
129
348
|
'- Stay inside the allowed files declared by slice.json.',
|
|
@@ -136,13 +355,15 @@ function buildExecuteSliceContext({ repoRoot, slicePath, role, context }) {
|
|
|
136
355
|
briefPath: relativeBriefPath,
|
|
137
356
|
briefText,
|
|
138
357
|
context: pack,
|
|
358
|
+
expectedReadPaths,
|
|
139
359
|
prompt: sections.join('\n\n'),
|
|
140
360
|
slice,
|
|
361
|
+
validationHints,
|
|
141
362
|
validationCommands,
|
|
142
363
|
};
|
|
143
364
|
}
|
|
144
365
|
|
|
145
|
-
function formatExecuteSliceDryRunReport({ provider, role, contextPack, slice, briefPath, invocation, validationCommands, allowedFiles }) {
|
|
366
|
+
function formatExecuteSliceDryRunReport({ provider, role, contextPack, slice, briefPath, invocation, validationCommands, allowedFiles, commitEnabled }) {
|
|
146
367
|
const lines = [
|
|
147
368
|
'AI execute-slice dry-run',
|
|
148
369
|
`Provider: ${provider}`,
|
|
@@ -155,6 +376,7 @@ function formatExecuteSliceDryRunReport({ provider, role, contextPack, slice, br
|
|
|
155
376
|
`Timeout: ${invocation.timeoutMs}ms`,
|
|
156
377
|
`Prompt transport: ${invocation.promptTransport.mode}`,
|
|
157
378
|
`Prompt length: ${invocation.promptLength} bytes`,
|
|
379
|
+
`Commit after validation: ${commitEnabled ? 'enabled' : 'disabled'}`,
|
|
158
380
|
'Allowed files:',
|
|
159
381
|
...formatList(allowedFiles),
|
|
160
382
|
'Validation commands:',
|
|
@@ -164,7 +386,7 @@ function formatExecuteSliceDryRunReport({ provider, role, contextPack, slice, br
|
|
|
164
386
|
return `${lines.join('\n')}\n`;
|
|
165
387
|
}
|
|
166
388
|
|
|
167
|
-
function formatExecuteSliceResult({ slice, changedFiles, scopeResult }) {
|
|
389
|
+
function formatExecuteSliceResult({ slice, changedFiles, scopeResult, validationResults, commitResult, commitEnabled }) {
|
|
168
390
|
const lines = [
|
|
169
391
|
'AI execute-slice completed',
|
|
170
392
|
`Slice: ${slice.sliceId}`,
|
|
@@ -177,6 +399,17 @@ function formatExecuteSliceResult({ slice, changedFiles, scopeResult }) {
|
|
|
177
399
|
}
|
|
178
400
|
|
|
179
401
|
lines.push(`Scope validation: ${scopeResult.ok ? 'passed' : 'failed'}`);
|
|
402
|
+
if (!Array.isArray(validationResults) || validationResults.length === 0) {
|
|
403
|
+
lines.push('Validation commands: skipped (none declared)');
|
|
404
|
+
} else {
|
|
405
|
+
lines.push(`Validation commands: passed (${validationResults.length})`);
|
|
406
|
+
}
|
|
407
|
+
if (commitResult) {
|
|
408
|
+
lines.push(`Commit: created ${commitResult.hash}`);
|
|
409
|
+
lines.push(`Commit message: ${commitResult.message}`);
|
|
410
|
+
} else {
|
|
411
|
+
lines.push(`Commit: ${commitEnabled ? 'not created' : 'skipped'}`);
|
|
412
|
+
}
|
|
180
413
|
|
|
181
414
|
return `${lines.join('\n')}\n`;
|
|
182
415
|
}
|
|
@@ -190,9 +423,296 @@ function annotateProviderError(error, scope) {
|
|
|
190
423
|
return wrapped;
|
|
191
424
|
}
|
|
192
425
|
|
|
426
|
+
function runValidationCommand(command, repoRoot) {
|
|
427
|
+
try {
|
|
428
|
+
const stdout = cp.execSync(command, {
|
|
429
|
+
cwd: repoRoot,
|
|
430
|
+
encoding: 'utf8',
|
|
431
|
+
shell: true,
|
|
432
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
433
|
+
});
|
|
434
|
+
return {
|
|
435
|
+
command: redactSecrets(command),
|
|
436
|
+
ok: true,
|
|
437
|
+
stdout: redactSecrets(stdout),
|
|
438
|
+
stderr: '',
|
|
439
|
+
exitCode: 0,
|
|
440
|
+
};
|
|
441
|
+
} catch (error) {
|
|
442
|
+
return {
|
|
443
|
+
command: redactSecrets(command),
|
|
444
|
+
ok: false,
|
|
445
|
+
stdout: redactSecrets(error.stdout ? String(error.stdout) : ''),
|
|
446
|
+
stderr: redactSecrets(error.stderr ? String(error.stderr) : ''),
|
|
447
|
+
exitCode: Number.isInteger(error.status) ? error.status : 1,
|
|
448
|
+
error,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function runValidationCommands(repoRoot, commands, runner = runValidationCommand) {
|
|
454
|
+
const results = [];
|
|
455
|
+
for (const command of commands) {
|
|
456
|
+
const rawResult = runner(command, repoRoot);
|
|
457
|
+
const result = {
|
|
458
|
+
...rawResult,
|
|
459
|
+
command: redactSecrets(rawResult.command || command),
|
|
460
|
+
stderr: redactSecrets(rawResult.stderr || ''),
|
|
461
|
+
stdout: redactSecrets(rawResult.stdout || ''),
|
|
462
|
+
};
|
|
463
|
+
results.push(result);
|
|
464
|
+
if (!result.ok) {
|
|
465
|
+
const details = [
|
|
466
|
+
formatError(`validation command failed: ${command}`),
|
|
467
|
+
`Exit code: ${result.exitCode}`,
|
|
468
|
+
];
|
|
469
|
+
if (result.stderr) {
|
|
470
|
+
details.push(`stderr:\n${result.stderr.trimEnd()}`);
|
|
471
|
+
}
|
|
472
|
+
if (result.stdout) {
|
|
473
|
+
details.push(`stdout:\n${result.stdout.trimEnd()}`);
|
|
474
|
+
}
|
|
475
|
+
const error = new Error(details.join('\n'));
|
|
476
|
+
error.code = 'VALIDATION_FAILED';
|
|
477
|
+
error.details = { command, result, results };
|
|
478
|
+
throw error;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return results;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function commitTypeForSlice(slice) {
|
|
485
|
+
const type = String(slice.json.type || slice.json.git?.branch_type || '').trim().toLowerCase();
|
|
486
|
+
if (type === 'bugfix' || type === 'hotfix' || type === 'fix') {
|
|
487
|
+
return 'fix';
|
|
488
|
+
}
|
|
489
|
+
if (type === 'docs' || type === 'documentation') {
|
|
490
|
+
return 'docs';
|
|
491
|
+
}
|
|
492
|
+
if (type === 'test' || type === 'tests') {
|
|
493
|
+
return 'test';
|
|
494
|
+
}
|
|
495
|
+
if (type === 'chore') {
|
|
496
|
+
return 'chore';
|
|
497
|
+
}
|
|
498
|
+
return 'feat';
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function buildSliceCommitMessage(slice) {
|
|
502
|
+
const title = String(slice.json.title || slice.sliceId || 'slice').trim();
|
|
503
|
+
const ticket = String(slice.ticket || '').trim();
|
|
504
|
+
const subject = ticket ? `${ticket} ${title}` : title;
|
|
505
|
+
return `${commitTypeForSlice(slice)}: ${subject}`;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
function commitSliceChanges(repoRoot, slice, changedFiles, options = {}) {
|
|
509
|
+
if (!Array.isArray(changedFiles) || changedFiles.length === 0) {
|
|
510
|
+
const error = new Error(formatError('commit requested but provider produced no changed files.'));
|
|
511
|
+
error.code = 'NO_CHANGES_TO_COMMIT';
|
|
512
|
+
throw error;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const message = options.message || buildSliceCommitMessage(slice);
|
|
516
|
+
runGit(['add', '--', ...changedFiles], repoRoot);
|
|
517
|
+
runGit(['commit', '-m', message], repoRoot);
|
|
518
|
+
|
|
519
|
+
return {
|
|
520
|
+
files: changedFiles,
|
|
521
|
+
hash: runGit(['rev-parse', '--short', 'HEAD'], repoRoot),
|
|
522
|
+
message,
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function assertCorrectSliceWorktree(repoRoot, slice, options = {}) {
|
|
527
|
+
if (options.skipWorktreeBranchCheck === true) {
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const expectedBranch = String(slice.branchName || slice.json.git?.branch_name || '').trim();
|
|
532
|
+
if (!expectedBranch) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
const actualBranch = currentBranch(repoRoot);
|
|
537
|
+
if (actualBranch !== expectedBranch) {
|
|
538
|
+
const error = new Error(formatError(`ai execute-slice must run from the slice worktree branch. Current branch: ${actualBranch || '(detached or unavailable)'}. Expected: ${expectedBranch}.`));
|
|
539
|
+
error.code = 'WRONG_WORKTREE';
|
|
540
|
+
error.details = {
|
|
541
|
+
actualBranch,
|
|
542
|
+
expectedBranch,
|
|
543
|
+
slice: slice.sliceRel,
|
|
544
|
+
};
|
|
545
|
+
throw error;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return {
|
|
549
|
+
actualBranch,
|
|
550
|
+
expectedBranch,
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
function sliceLifecycleArtifactPaths(repoRoot, slice) {
|
|
555
|
+
const closureAbs = path.join(path.dirname(slice.sliceAbs), 'CLOSURE_BRIEF.md');
|
|
556
|
+
return {
|
|
557
|
+
closure: toRelativePath(repoRoot, closureAbs),
|
|
558
|
+
commandLog: toRelativePath(repoRoot, path.join(slice.specDirAbs, 'COMMAND_LOG.md')),
|
|
559
|
+
evidence: toRelativePath(repoRoot, path.join(slice.specDirAbs, 'EVIDENCE_REPORT.md')),
|
|
560
|
+
sliceJson: toRelativePath(repoRoot, slice.sliceAbs),
|
|
561
|
+
status: toRelativePath(repoRoot, path.join(slice.specDirAbs, 'STATUS.md')),
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function renderClosureBrief({ slice, changedFiles, validationResults, completedAt }) {
|
|
566
|
+
const criteria = Array.isArray(slice.acceptance) ? slice.acceptance : [];
|
|
567
|
+
const validationLines = Array.isArray(validationResults) && validationResults.length > 0
|
|
568
|
+
? validationResults.map((result) => `- [x] \`${result.command}\` exited ${result.exitCode}`)
|
|
569
|
+
: ['- [x] No validation commands declared.'];
|
|
570
|
+
|
|
571
|
+
return `${[
|
|
572
|
+
`# CLOSURE BRIEF - ${slice.sliceId}: ${slice.json.title || slice.sliceId}`,
|
|
573
|
+
'',
|
|
574
|
+
'## Summary of Work',
|
|
575
|
+
'',
|
|
576
|
+
`Executed controlled slice closure at ${completedAt}. Quiver validated scope, validation commands, and lifecycle evidence for this slice.`,
|
|
577
|
+
'',
|
|
578
|
+
'## Validation Against Acceptance Criteria',
|
|
579
|
+
'',
|
|
580
|
+
...(criteria.length > 0 ? criteria.map((item) => `- [x] ${item}`) : ['- [x] Slice execution completed with scope validation.']),
|
|
581
|
+
'',
|
|
582
|
+
'## Relevant Changes',
|
|
583
|
+
'',
|
|
584
|
+
...formatList(changedFiles),
|
|
585
|
+
'',
|
|
586
|
+
'## Validation Commands',
|
|
587
|
+
'',
|
|
588
|
+
...validationLines,
|
|
589
|
+
'',
|
|
590
|
+
'## Pending',
|
|
591
|
+
'',
|
|
592
|
+
'None recorded by Quiver.',
|
|
593
|
+
'',
|
|
594
|
+
'## Remaining Risks',
|
|
595
|
+
'',
|
|
596
|
+
'None recorded by Quiver.',
|
|
597
|
+
'',
|
|
598
|
+
'## Future Recommendations',
|
|
599
|
+
'',
|
|
600
|
+
'Review the evidence report and commit diff before opening the PR.',
|
|
601
|
+
'',
|
|
602
|
+
].join('\n')}\n`;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
function appendSection(filePath, fallbackTitle, section) {
|
|
606
|
+
const current = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8').trimEnd() : fallbackTitle;
|
|
607
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
608
|
+
fs.writeFileSync(filePath, `${current}\n\n${section.trimEnd()}\n`);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function updateStatusMarkdown(filePath, slice, completedAt) {
|
|
612
|
+
const fallback = `# Status - ${slice.specSlug}\n`;
|
|
613
|
+
let text = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf8') : fallback;
|
|
614
|
+
const rowRegex = new RegExp(`(\\|\\s*${escapeRegex(slice.sliceId)}\\s*\\|\\s*)[^|\\n]+(\\|[^\\n]*\\|)`);
|
|
615
|
+
if (rowRegex.test(text)) {
|
|
616
|
+
text = text.replace(rowRegex, '$1Completed $2');
|
|
617
|
+
}
|
|
618
|
+
text = text.replace(/\*\*Current slice:\*\*\s*[^\n]*/i, `**Current slice:** ${slice.sliceId} completed`);
|
|
619
|
+
if (!text.endsWith('\n')) {
|
|
620
|
+
text += '\n';
|
|
621
|
+
}
|
|
622
|
+
const section = [
|
|
623
|
+
'',
|
|
624
|
+
`## Execution Update - ${slice.sliceId}`,
|
|
625
|
+
'',
|
|
626
|
+
`- Status: Completed`,
|
|
627
|
+
`- Completed at: ${completedAt}`,
|
|
628
|
+
`- Source: \`npx create-quiver ai execute-slice --slice ${slice.sliceRel}\``,
|
|
629
|
+
].join('\n');
|
|
630
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
631
|
+
fs.writeFileSync(filePath, `${text}${section}\n`);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function updateSliceJson(filePath, completedAt) {
|
|
635
|
+
const json = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
636
|
+
json.status = 'completed';
|
|
637
|
+
json.completed_at = completedAt;
|
|
638
|
+
fs.writeFileSync(filePath, `${JSON.stringify(json, null, 2)}\n`);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function writeExecutionArtifacts(repoRoot, executorContext, details) {
|
|
642
|
+
const { slice } = executorContext;
|
|
643
|
+
const completedAt = details.completedAt || new Date().toISOString();
|
|
644
|
+
const artifacts = sliceLifecycleArtifactPaths(repoRoot, slice);
|
|
645
|
+
const changedFiles = uniqueList(details.changedFiles);
|
|
646
|
+
const closurePath = path.join(repoRoot, artifacts.closure);
|
|
647
|
+
const evidencePath = path.join(repoRoot, artifacts.evidence);
|
|
648
|
+
const commandLogPath = path.join(repoRoot, artifacts.commandLog);
|
|
649
|
+
const statusPath = path.join(repoRoot, artifacts.status);
|
|
650
|
+
const validationResults = Array.isArray(details.validationResults) ? details.validationResults : [];
|
|
651
|
+
const providerStdout = truncateText(redactSecrets(details.providerOutput?.stdout || ''), 1200).text;
|
|
652
|
+
const providerStderr = truncateText(redactSecrets(details.providerOutput?.stderr || ''), 1200).text;
|
|
653
|
+
|
|
654
|
+
fs.mkdirSync(path.dirname(closurePath), { recursive: true });
|
|
655
|
+
fs.writeFileSync(closurePath, renderClosureBrief({
|
|
656
|
+
slice,
|
|
657
|
+
changedFiles,
|
|
658
|
+
validationResults,
|
|
659
|
+
completedAt,
|
|
660
|
+
}));
|
|
661
|
+
|
|
662
|
+
const validationLines = validationResults.length > 0
|
|
663
|
+
? validationResults.map((result) => `- \`${result.command}\` -> exit ${result.exitCode}`)
|
|
664
|
+
: ['- No validation commands declared.'];
|
|
665
|
+
appendSection(evidencePath, `# Evidence Report - ${slice.specSlug}`, [
|
|
666
|
+
`## ${slice.sliceId} - Execution Evidence`,
|
|
667
|
+
'',
|
|
668
|
+
`- Completed at: ${completedAt}`,
|
|
669
|
+
`- Changed files: ${changedFiles.length}`,
|
|
670
|
+
...changedFiles.map((file) => ` - \`${file}\``),
|
|
671
|
+
`- Scope validation: passed`,
|
|
672
|
+
`- Provider stdout redacted: ${providerStdout ? 'yes' : 'n/a'}`,
|
|
673
|
+
`- Provider stderr redacted: ${providerStderr ? 'yes' : 'n/a'}`,
|
|
674
|
+
'',
|
|
675
|
+
'### Validation',
|
|
676
|
+
'',
|
|
677
|
+
...validationLines,
|
|
678
|
+
'',
|
|
679
|
+
'### Provider Output',
|
|
680
|
+
'',
|
|
681
|
+
'```text',
|
|
682
|
+
providerStdout || 'n/a',
|
|
683
|
+
providerStderr ? `\n${providerStderr}` : '',
|
|
684
|
+
'```',
|
|
685
|
+
].join('\n'));
|
|
686
|
+
|
|
687
|
+
const commandLogRows = [
|
|
688
|
+
`| ${completedAt} | ${slice.sliceId} | \`npx create-quiver ai execute-slice --slice ${slice.sliceRel}\` | passed |`,
|
|
689
|
+
...validationResults.map((result) => `| ${completedAt} | ${slice.sliceId} | \`${result.command}\` | exit ${result.exitCode} |`),
|
|
690
|
+
];
|
|
691
|
+
const commandLogHeader = [
|
|
692
|
+
'# Command Log',
|
|
693
|
+
'',
|
|
694
|
+
'| Timestamp | Slice | Command | Result |',
|
|
695
|
+
'|---|---|---|---|',
|
|
696
|
+
].join('\n');
|
|
697
|
+
const currentCommandLog = fs.existsSync(commandLogPath) ? fs.readFileSync(commandLogPath, 'utf8').trimEnd() : commandLogHeader;
|
|
698
|
+
fs.mkdirSync(path.dirname(commandLogPath), { recursive: true });
|
|
699
|
+
fs.writeFileSync(commandLogPath, `${currentCommandLog}\n${commandLogRows.join('\n')}\n`);
|
|
700
|
+
|
|
701
|
+
updateStatusMarkdown(statusPath, slice, completedAt);
|
|
702
|
+
updateSliceJson(path.join(repoRoot, artifacts.sliceJson), completedAt);
|
|
703
|
+
|
|
704
|
+
return {
|
|
705
|
+
completedAt,
|
|
706
|
+
files: Object.values(artifacts),
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
|
|
193
710
|
async function runExecuteSlice(repoRoot, options = {}) {
|
|
194
|
-
const
|
|
711
|
+
const canonicalRepoRoot = canonicalizeRepoRoot(repoRoot);
|
|
195
712
|
const role = normalizeRole(options.role || DEFAULT_EXECUTE_ROLE);
|
|
713
|
+
const provider = options.providerExplicit === true || (options.provider && options.providerExplicit !== false)
|
|
714
|
+
? String(options.provider || DEFAULT_EXECUTE_PROVIDER).trim().toLowerCase()
|
|
715
|
+
: resolveProfileProvider(canonicalRepoRoot, role, DEFAULT_EXECUTE_PROVIDER);
|
|
196
716
|
const context = options.context || DEFAULT_EXECUTE_CONTEXT;
|
|
197
717
|
const timeoutMs = normalizeTimeout(options.timeout);
|
|
198
718
|
|
|
@@ -201,7 +721,7 @@ async function runExecuteSlice(repoRoot, options = {}) {
|
|
|
201
721
|
}
|
|
202
722
|
|
|
203
723
|
const executorContext = buildExecuteSliceContext({
|
|
204
|
-
repoRoot,
|
|
724
|
+
repoRoot: canonicalRepoRoot,
|
|
205
725
|
slicePath: options.slice,
|
|
206
726
|
role,
|
|
207
727
|
context,
|
|
@@ -213,7 +733,7 @@ async function runExecuteSlice(repoRoot, options = {}) {
|
|
|
213
733
|
try {
|
|
214
734
|
invocation = buildProviderInvocation(provider, {
|
|
215
735
|
prompt,
|
|
216
|
-
cwd:
|
|
736
|
+
cwd: canonicalRepoRoot,
|
|
217
737
|
timeoutMs,
|
|
218
738
|
});
|
|
219
739
|
} catch (error) {
|
|
@@ -231,6 +751,7 @@ async function runExecuteSlice(repoRoot, options = {}) {
|
|
|
231
751
|
briefPath: executorContext.briefPath,
|
|
232
752
|
allowedFiles: executorContext.allowedFiles,
|
|
233
753
|
validationCommands: executorContext.validationCommands,
|
|
754
|
+
commitEnabled: options.commit === true,
|
|
234
755
|
};
|
|
235
756
|
process.stdout.write(formatExecuteSliceDryRunReport({
|
|
236
757
|
provider,
|
|
@@ -241,20 +762,30 @@ async function runExecuteSlice(repoRoot, options = {}) {
|
|
|
241
762
|
invocation,
|
|
242
763
|
validationCommands: executorContext.validationCommands,
|
|
243
764
|
allowedFiles: executorContext.allowedFiles,
|
|
765
|
+
commitEnabled: options.commit === true,
|
|
244
766
|
}));
|
|
245
767
|
return report;
|
|
246
768
|
}
|
|
247
769
|
|
|
248
|
-
|
|
770
|
+
try {
|
|
771
|
+
assertCorrectSliceWorktree(canonicalRepoRoot, executorContext.slice, options);
|
|
772
|
+
} catch (error) {
|
|
773
|
+
throw appendRecovery(error, executorContext.slice);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const beforeSnapshot = captureWorktreeSnapshot(canonicalRepoRoot);
|
|
777
|
+
if (beforeSnapshot.files.length > 0 && options.commit === true) {
|
|
778
|
+
throw appendRecovery(new Error(formatError(`ai execute-slice --commit requires a clean worktree before running. Commit or stash first: ${beforeSnapshot.files.join(', ')}`)), executorContext.slice);
|
|
779
|
+
}
|
|
249
780
|
if (beforeSnapshot.files.length > 0 && options.allowDirty !== true) {
|
|
250
|
-
throw new Error(formatError(`ai execute-slice requires a clean worktree before running. Commit or stash first: ${beforeSnapshot.files.join(', ')}`));
|
|
781
|
+
throw appendRecovery(new Error(formatError(`ai execute-slice requires a clean worktree before running. Commit or stash first: ${beforeSnapshot.files.join(', ')}`)), executorContext.slice);
|
|
251
782
|
}
|
|
252
783
|
|
|
253
784
|
let result;
|
|
254
785
|
try {
|
|
255
786
|
result = await (options.runProviderFn || runProvider)(provider, {
|
|
256
787
|
prompt,
|
|
257
|
-
cwd:
|
|
788
|
+
cwd: canonicalRepoRoot,
|
|
258
789
|
timeoutMs,
|
|
259
790
|
dryRun: false,
|
|
260
791
|
probe: options.probe,
|
|
@@ -264,32 +795,97 @@ async function runExecuteSlice(repoRoot, options = {}) {
|
|
|
264
795
|
tempFilePrefix: options.tempFilePrefix,
|
|
265
796
|
});
|
|
266
797
|
} catch (error) {
|
|
267
|
-
throw annotateProviderError(error, 'execute-slice');
|
|
798
|
+
throw appendRecovery(annotateProviderError(error, 'execute-slice'), executorContext.slice);
|
|
268
799
|
}
|
|
269
800
|
|
|
270
801
|
if (result.stdout) {
|
|
271
|
-
process.stdout.write(result.stdout);
|
|
802
|
+
process.stdout.write(redactSecrets(result.stdout));
|
|
272
803
|
}
|
|
273
804
|
if (result.stderr) {
|
|
274
|
-
process.stderr.write(result.stderr);
|
|
805
|
+
process.stderr.write(redactSecrets(result.stderr));
|
|
275
806
|
}
|
|
276
807
|
|
|
277
808
|
if (!result.ok) {
|
|
278
|
-
throw annotateProviderError(result.error || new Error('provider run failed'), 'execute-slice');
|
|
809
|
+
throw appendRecovery(annotateProviderError(result.error || new Error('provider run failed'), 'execute-slice'), executorContext.slice);
|
|
279
810
|
}
|
|
280
811
|
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
812
|
+
const providerOutput = {
|
|
813
|
+
stdout: redactSecrets(result.stdout || ''),
|
|
814
|
+
stderr: redactSecrets(result.stderr || ''),
|
|
815
|
+
};
|
|
816
|
+
const sanitizedResult = {
|
|
817
|
+
...result,
|
|
818
|
+
stdout: providerOutput.stdout,
|
|
819
|
+
stderr: providerOutput.stderr,
|
|
820
|
+
};
|
|
821
|
+
|
|
822
|
+
const afterSnapshot = captureWorktreeSnapshot(canonicalRepoRoot);
|
|
823
|
+
let scopeResult;
|
|
824
|
+
try {
|
|
825
|
+
scopeResult = validateScopeSnapshot({
|
|
826
|
+
allowedFiles: executorContext.allowedFiles,
|
|
827
|
+
beforeSnapshot,
|
|
828
|
+
afterSnapshot,
|
|
829
|
+
strict: true,
|
|
830
|
+
});
|
|
831
|
+
} catch (error) {
|
|
832
|
+
throw appendRecovery(error, executorContext.slice);
|
|
833
|
+
}
|
|
834
|
+
if (scopeResult.changedFiles.length === 0) {
|
|
835
|
+
const error = new Error(formatError('provider produced no changed files; slice closure was not updated.'));
|
|
836
|
+
error.code = 'NO_CHANGES_TO_CLOSE';
|
|
837
|
+
throw appendRecovery(error, executorContext.slice);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
let validationResults = [];
|
|
841
|
+
try {
|
|
842
|
+
validationResults = runValidationCommands(
|
|
843
|
+
canonicalRepoRoot,
|
|
844
|
+
executorContext.validationCommands,
|
|
845
|
+
options.runValidationCommandFn,
|
|
846
|
+
);
|
|
847
|
+
} catch (error) {
|
|
848
|
+
throw appendRecovery(error, executorContext.slice);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
const artifacts = writeExecutionArtifacts(canonicalRepoRoot, executorContext, {
|
|
852
|
+
changedFiles: scopeResult.changedFiles,
|
|
853
|
+
completedAt: new Date().toISOString(),
|
|
854
|
+
providerOutput,
|
|
855
|
+
validationResults,
|
|
287
856
|
});
|
|
288
857
|
|
|
858
|
+
const finalSnapshot = captureWorktreeSnapshot(canonicalRepoRoot);
|
|
859
|
+
let finalScopeResult;
|
|
860
|
+
try {
|
|
861
|
+
finalScopeResult = validateScopeSnapshot({
|
|
862
|
+
allowedFiles: uniqueList([...executorContext.allowedFiles, ...artifacts.files]),
|
|
863
|
+
beforeSnapshot,
|
|
864
|
+
afterSnapshot: finalSnapshot,
|
|
865
|
+
strict: true,
|
|
866
|
+
});
|
|
867
|
+
} catch (error) {
|
|
868
|
+
throw appendRecovery(error, executorContext.slice);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
let commitResult = null;
|
|
872
|
+
if (options.commit === true) {
|
|
873
|
+
try {
|
|
874
|
+
commitResult = commitSliceChanges(canonicalRepoRoot, executorContext.slice, finalScopeResult.changedFiles, {
|
|
875
|
+
message: options.commitMessage,
|
|
876
|
+
});
|
|
877
|
+
} catch (error) {
|
|
878
|
+
throw appendRecovery(error, executorContext.slice);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
289
882
|
process.stdout.write(formatExecuteSliceResult({
|
|
290
883
|
slice: executorContext.slice,
|
|
291
|
-
changedFiles:
|
|
292
|
-
scopeResult,
|
|
884
|
+
changedFiles: finalScopeResult.changedFiles,
|
|
885
|
+
scopeResult: finalScopeResult,
|
|
886
|
+
validationResults,
|
|
887
|
+
commitResult,
|
|
888
|
+
commitEnabled: options.commit === true,
|
|
293
889
|
}));
|
|
294
890
|
|
|
295
891
|
return {
|
|
@@ -300,10 +896,13 @@ async function runExecuteSlice(repoRoot, options = {}) {
|
|
|
300
896
|
slice: executorContext.slice.sliceId,
|
|
301
897
|
specSlug: executorContext.slice.specSlug,
|
|
302
898
|
invocation,
|
|
303
|
-
result,
|
|
899
|
+
result: sanitizedResult,
|
|
304
900
|
beforeSnapshot,
|
|
305
|
-
afterSnapshot,
|
|
306
|
-
scopeResult,
|
|
901
|
+
afterSnapshot: finalSnapshot,
|
|
902
|
+
scopeResult: finalScopeResult,
|
|
903
|
+
validationResults,
|
|
904
|
+
commitResult,
|
|
905
|
+
artifacts,
|
|
307
906
|
};
|
|
308
907
|
}
|
|
309
908
|
|
|
@@ -312,12 +911,22 @@ module.exports = {
|
|
|
312
911
|
DEFAULT_EXECUTE_PROVIDER,
|
|
313
912
|
DEFAULT_EXECUTE_ROLE,
|
|
314
913
|
annotateProviderError,
|
|
914
|
+
appendRecovery,
|
|
315
915
|
buildExecuteSliceContext,
|
|
916
|
+
buildManualExecutorPrompt,
|
|
917
|
+
buildRecoveryGuidance,
|
|
918
|
+
buildSliceCommitMessage,
|
|
316
919
|
canonicalizeRepoRoot,
|
|
920
|
+
commitSliceChanges,
|
|
317
921
|
formatExecuteSliceDryRunReport,
|
|
318
922
|
formatExecuteSliceResult,
|
|
923
|
+
assertCorrectSliceWorktree,
|
|
924
|
+
writeExecutionArtifacts,
|
|
925
|
+
runValidationCommand,
|
|
926
|
+
runValidationCommands,
|
|
319
927
|
normalizeTimeout,
|
|
320
928
|
readTextFile,
|
|
321
929
|
resolveSliceJsonPath,
|
|
322
930
|
runExecuteSlice,
|
|
931
|
+
runPromptSlice,
|
|
323
932
|
};
|