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
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
function formatActionableError({ failure, impact, fix, nextCommand } = {}) {
|
|
2
|
+
const lines = [`create-quiver: ${String(failure || 'operation failed').trim()}`];
|
|
3
|
+
|
|
4
|
+
if (impact) {
|
|
5
|
+
lines.push(`Impact: ${String(impact).trim()}`);
|
|
6
|
+
}
|
|
7
|
+
if (fix) {
|
|
8
|
+
lines.push(`Fix: ${String(fix).trim()}`);
|
|
9
|
+
}
|
|
10
|
+
if (nextCommand) {
|
|
11
|
+
lines.push(`Next command: ${String(nextCommand).trim()}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return lines.join('\n');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createActionableError(code, fields = {}, details = {}) {
|
|
18
|
+
const error = new Error(formatActionableError(fields));
|
|
19
|
+
error.code = code;
|
|
20
|
+
error.details = details;
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
createActionableError,
|
|
26
|
+
formatActionableError,
|
|
27
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
|
|
4
|
+
const { assertSupportedProvider, formatProviderList } = require('./ai/providers');
|
|
5
|
+
const { quiverInternalPaths } = require('./init-layout');
|
|
6
|
+
|
|
7
|
+
const AGENT_PROFILE_ROLES = Object.freeze(['planner', 'executor', 'reviewer', 'doctor']);
|
|
8
|
+
const PROFILE_STATE_VERSION = 1;
|
|
9
|
+
|
|
10
|
+
function formatError(message) {
|
|
11
|
+
return `create-quiver: ${message}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function agentProfilesPath(projectRoot) {
|
|
15
|
+
return path.join(quiverInternalPaths(projectRoot).root, 'agents', 'profiles.json');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function normalizeAgentProfileRole(role) {
|
|
19
|
+
const normalized = String(role || '').trim().toLowerCase();
|
|
20
|
+
if (!AGENT_PROFILE_ROLES.includes(normalized)) {
|
|
21
|
+
throw new Error(formatError(`unsupported agent profile role '${role}'. Expected one of: ${AGENT_PROFILE_ROLES.join(', ')}`));
|
|
22
|
+
}
|
|
23
|
+
return normalized;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeOptionalText(value, fieldName) {
|
|
27
|
+
if (value === undefined || value === null) {
|
|
28
|
+
return '';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const normalized = String(value).trim();
|
|
32
|
+
if (normalized.length > 160) {
|
|
33
|
+
throw new Error(formatError(`agent profile ${fieldName} is too long`));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
assertNotSecretLike(normalized, fieldName);
|
|
37
|
+
return normalized;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function assertNotSecretLike(value, fieldName) {
|
|
41
|
+
const text = String(value || '');
|
|
42
|
+
const secretPatterns = [
|
|
43
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
44
|
+
/\bsk-[A-Za-z0-9_-]{16,}\b/,
|
|
45
|
+
/\bghp_[A-Za-z0-9_]{16,}\b/,
|
|
46
|
+
/\bgithub_pat_[A-Za-z0-9_]{16,}\b/,
|
|
47
|
+
/\bxox[baprs]-[A-Za-z0-9-]{16,}\b/,
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
if (secretPatterns.some((pattern) => pattern.test(text))) {
|
|
51
|
+
throw new Error(formatError(`agent profile ${fieldName} looks like a secret; store provider credentials in the provider CLI, not in Quiver profiles`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function emptyProfilesState() {
|
|
56
|
+
return {
|
|
57
|
+
version: PROFILE_STATE_VERSION,
|
|
58
|
+
profiles: {},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function readAgentProfiles(projectRoot) {
|
|
63
|
+
const filePath = agentProfilesPath(projectRoot);
|
|
64
|
+
if (!fs.existsSync(filePath)) {
|
|
65
|
+
return emptyProfilesState();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const state = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
69
|
+
return {
|
|
70
|
+
version: state.version || PROFILE_STATE_VERSION,
|
|
71
|
+
profiles: state.profiles && typeof state.profiles === 'object' ? state.profiles : {},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function writeAgentProfiles(projectRoot, state) {
|
|
76
|
+
const filePath = agentProfilesPath(projectRoot);
|
|
77
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
78
|
+
fs.writeFileSync(filePath, `${JSON.stringify(state, null, 2)}\n`);
|
|
79
|
+
return filePath;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getAgentProfile(projectRoot, role) {
|
|
83
|
+
const normalizedRole = normalizeAgentProfileRole(role);
|
|
84
|
+
const state = readAgentProfiles(projectRoot);
|
|
85
|
+
return state.profiles[normalizedRole] || null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function listAgentProfiles(projectRoot) {
|
|
89
|
+
const state = readAgentProfiles(projectRoot);
|
|
90
|
+
return AGENT_PROFILE_ROLES.map((role) => ({
|
|
91
|
+
role,
|
|
92
|
+
configured: Boolean(state.profiles[role]),
|
|
93
|
+
profile: state.profiles[role] || null,
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function setAgentProfile(projectRoot, role, options = {}) {
|
|
98
|
+
const normalizedRole = normalizeAgentProfileRole(role);
|
|
99
|
+
const provider = assertSupportedProvider(options.provider);
|
|
100
|
+
const model = normalizeOptionalText(options.model, 'model');
|
|
101
|
+
const label = normalizeOptionalText(options.label, 'label');
|
|
102
|
+
const context = normalizeOptionalText(options.context, 'context');
|
|
103
|
+
const state = readAgentProfiles(projectRoot);
|
|
104
|
+
const current = state.profiles[normalizedRole] || {};
|
|
105
|
+
const now = new Date().toISOString();
|
|
106
|
+
const profile = {
|
|
107
|
+
role: normalizedRole,
|
|
108
|
+
provider,
|
|
109
|
+
model: model || current.model || '',
|
|
110
|
+
label: label || current.label || '',
|
|
111
|
+
context: context || current.context || '',
|
|
112
|
+
updated_at: now,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
state.version = PROFILE_STATE_VERSION;
|
|
116
|
+
state.profiles = {
|
|
117
|
+
...state.profiles,
|
|
118
|
+
[normalizedRole]: profile,
|
|
119
|
+
};
|
|
120
|
+
state.updated_at = now;
|
|
121
|
+
|
|
122
|
+
const filePath = writeAgentProfiles(projectRoot, state);
|
|
123
|
+
return {
|
|
124
|
+
filePath,
|
|
125
|
+
profile,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function resolveProfileProvider(projectRoot, role, fallbackProvider) {
|
|
130
|
+
const profile = getAgentProfile(projectRoot, role);
|
|
131
|
+
if (profile?.provider) {
|
|
132
|
+
return assertSupportedProvider(profile.provider);
|
|
133
|
+
}
|
|
134
|
+
return assertSupportedProvider(fallbackProvider);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
module.exports = {
|
|
138
|
+
AGENT_PROFILE_ROLES,
|
|
139
|
+
PROFILE_STATE_VERSION,
|
|
140
|
+
agentProfilesPath,
|
|
141
|
+
formatProviderList,
|
|
142
|
+
getAgentProfile,
|
|
143
|
+
listAgentProfiles,
|
|
144
|
+
normalizeAgentProfileRole,
|
|
145
|
+
readAgentProfiles,
|
|
146
|
+
resolveProfileProvider,
|
|
147
|
+
setAgentProfile,
|
|
148
|
+
};
|
|
@@ -44,6 +44,17 @@ const DEFAULT_CONTEXT_PACK_BY_ROLE = Object.freeze({
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
const PACK_ORDER = ['full', 'planning', 'slice', 'minimal'];
|
|
47
|
+
const CONTEXT_PREPARED_DOC_PATHS = Object.freeze([
|
|
48
|
+
'docs/INDEX.md',
|
|
49
|
+
'docs/PROJECT_MAP.md',
|
|
50
|
+
'docs/AI_CONTEXT.md',
|
|
51
|
+
'docs/AI_ONBOARDING_PROMPT.md',
|
|
52
|
+
'docs/CONTEXTO.md',
|
|
53
|
+
'docs/WORKFLOW.md',
|
|
54
|
+
'docs/ARCHITECTURE.md',
|
|
55
|
+
'docs/STATUS.md',
|
|
56
|
+
'docs/DECISIONS.md',
|
|
57
|
+
]);
|
|
47
58
|
|
|
48
59
|
function normalizeRole(role) {
|
|
49
60
|
const value = String(role || '').trim().toLowerCase();
|
|
@@ -66,6 +77,10 @@ function getDefaultContextPack(role) {
|
|
|
66
77
|
return DEFAULT_CONTEXT_PACK_BY_ROLE[normalizedRole];
|
|
67
78
|
}
|
|
68
79
|
|
|
80
|
+
function getPreparedContextDocPaths() {
|
|
81
|
+
return CONTEXT_PREPARED_DOC_PATHS.slice();
|
|
82
|
+
}
|
|
83
|
+
|
|
69
84
|
function resolveContextPack({ role, packName } = {}) {
|
|
70
85
|
const normalizedRole = normalizeRole(role);
|
|
71
86
|
const defaultPack = getDefaultContextPack(normalizedRole);
|
|
@@ -148,6 +163,7 @@ module.exports = {
|
|
|
148
163
|
ROLES,
|
|
149
164
|
buildContextPackMetadata,
|
|
150
165
|
buildPackSelection,
|
|
166
|
+
getPreparedContextDocPaths,
|
|
151
167
|
getDefaultContextPack,
|
|
152
168
|
normalizePackName,
|
|
153
169
|
normalizeRole,
|
|
@@ -1,19 +1,43 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
|
|
4
|
+
const { resolveProfileProvider } = require('../agent-profiles');
|
|
5
|
+
const { branchDelete, runGit, statusPorcelain, worktreeAdd, worktreePrune, worktreeRemove } = require('../git');
|
|
6
|
+
const { safeBranchName, worktreesRootForRepo } = require('../slice');
|
|
1
7
|
const { buildGraph, computeLevels, detectFileConflicts, isFoundationSliceId, readAllSlices, topoSort, SliceGraphError } = require('../slice-graph');
|
|
8
|
+
const { runExecuteSlice } = require('./executor');
|
|
2
9
|
|
|
3
10
|
const EXCLUDED_STATUSES = new Set(['completed', 'skipped', 'cancelled']);
|
|
11
|
+
const EXECUTION_MODES = new Set(['auto', 'manual', 'delegated']);
|
|
4
12
|
|
|
5
13
|
function formatError(message) {
|
|
6
14
|
return `create-quiver: ${message}`;
|
|
7
15
|
}
|
|
8
16
|
|
|
9
|
-
function
|
|
17
|
+
function toRelativePath(repoRoot, filePath) {
|
|
18
|
+
return path.relative(repoRoot, filePath).split(path.sep).join('/');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function normalizeExecutionMode(mode) {
|
|
22
|
+
const value = String(mode || 'auto').trim().toLowerCase() || 'auto';
|
|
23
|
+
if (!EXECUTION_MODES.has(value)) {
|
|
24
|
+
throw new Error(formatError(`unsupported execution mode: ${mode}. Use auto, manual, or delegated.`));
|
|
25
|
+
}
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function summarizeSlice(node, repoRoot) {
|
|
10
30
|
return {
|
|
11
31
|
ref: node.ref,
|
|
12
32
|
spec_slug: node.specSlug,
|
|
13
33
|
slice_id: node.sliceId,
|
|
34
|
+
slice_path: node.slicePath ? toRelativePath(repoRoot, node.slicePath) : '',
|
|
14
35
|
title: node.title || node.sliceId,
|
|
15
36
|
status: node.status || 'draft',
|
|
16
37
|
files: Array.isArray(node.files) ? node.files : [],
|
|
38
|
+
expected_read_paths: Array.isArray(node.expected_read_paths) ? node.expected_read_paths : [],
|
|
39
|
+
allowed_write_paths: Array.isArray(node.allowed_write_paths) ? node.allowed_write_paths : [],
|
|
40
|
+
validation_hints: Array.isArray(node.validation_hints) ? node.validation_hints : [],
|
|
17
41
|
depends_on: Array.isArray(node.depends_on) ? node.depends_on : [],
|
|
18
42
|
parallel_safe: node.parallel_safe || null,
|
|
19
43
|
parallel_safe_reason: node.parallel_safe_reason || null,
|
|
@@ -92,8 +116,18 @@ function buildPendingGraph(graph, options = {}) {
|
|
|
92
116
|
};
|
|
93
117
|
}
|
|
94
118
|
|
|
95
|
-
function
|
|
96
|
-
if (
|
|
119
|
+
function buildFallbackReason({ conflicts, unknownScopeSlices }) {
|
|
120
|
+
if (unknownScopeSlices.length > 0) {
|
|
121
|
+
return `Unknown file scope: ${unknownScopeSlices.join(', ')}`;
|
|
122
|
+
}
|
|
123
|
+
if (conflicts.length > 0) {
|
|
124
|
+
return `File conflicts: ${conflicts.map((conflict) => conflict.slices.join(', ')).join('; ')}`;
|
|
125
|
+
}
|
|
126
|
+
return '';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function buildLevelStrategy(levelNodes, { parallelReady, conflicts, unknownScopeSlices }) {
|
|
130
|
+
if (parallelReady) {
|
|
97
131
|
return {
|
|
98
132
|
mode: 'temporary-per-slice',
|
|
99
133
|
temporary_worktrees: true,
|
|
@@ -101,6 +135,14 @@ function buildLevelStrategy(levelNodes) {
|
|
|
101
135
|
};
|
|
102
136
|
}
|
|
103
137
|
|
|
138
|
+
if (levelNodes.length > 1) {
|
|
139
|
+
return {
|
|
140
|
+
mode: 'sequential-fallback',
|
|
141
|
+
temporary_worktrees: false,
|
|
142
|
+
reason: buildFallbackReason({ conflicts, unknownScopeSlices }) || 'Run sequentially because this level is not parallel-ready.',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
104
146
|
return {
|
|
105
147
|
mode: 'shared-worktree',
|
|
106
148
|
temporary_worktrees: false,
|
|
@@ -108,21 +150,45 @@ function buildLevelStrategy(levelNodes) {
|
|
|
108
150
|
};
|
|
109
151
|
}
|
|
110
152
|
|
|
111
|
-
function
|
|
112
|
-
|
|
153
|
+
function buildExecutionGroups(slices, parallelReady, fallbackReason) {
|
|
154
|
+
if (parallelReady) {
|
|
155
|
+
return [{
|
|
156
|
+
mode: 'parallel',
|
|
157
|
+
reason: 'No file-scope conflicts detected.',
|
|
158
|
+
slice_refs: slices.map((slice) => slice.ref),
|
|
159
|
+
}];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return slices.map((slice) => ({
|
|
163
|
+
mode: 'sequential',
|
|
164
|
+
reason: fallbackReason || 'Sequential execution is the safe default.',
|
|
165
|
+
slice_refs: [slice.ref],
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function summarizeLevel(levelNodes, index, repoRoot) {
|
|
170
|
+
const slices = levelNodes.map((node) => summarizeSlice(node, repoRoot));
|
|
113
171
|
const sliceRefs = slices.map((slice) => slice.ref);
|
|
114
172
|
const conflicts = detectFileConflicts(levelNodes).map((group) => ({
|
|
115
173
|
files: group.files,
|
|
116
174
|
slices: group.slices,
|
|
117
175
|
}));
|
|
176
|
+
const unknownScopeSlices = slices
|
|
177
|
+
.filter((slice) => !Array.isArray(slice.files) || slice.files.length === 0)
|
|
178
|
+
.map((slice) => slice.ref);
|
|
179
|
+
const fallbackReason = buildFallbackReason({ conflicts, unknownScopeSlices });
|
|
180
|
+
const parallelReady = levelNodes.length > 1 && conflicts.length === 0 && unknownScopeSlices.length === 0;
|
|
118
181
|
|
|
119
182
|
return {
|
|
120
183
|
index,
|
|
121
184
|
slice_refs: sliceRefs,
|
|
122
|
-
parallel_ready:
|
|
123
|
-
requires_temporary_worktrees:
|
|
124
|
-
worktree_strategy: buildLevelStrategy(levelNodes),
|
|
185
|
+
parallel_ready: parallelReady,
|
|
186
|
+
requires_temporary_worktrees: parallelReady,
|
|
187
|
+
worktree_strategy: buildLevelStrategy(levelNodes, { parallelReady, conflicts, unknownScopeSlices }),
|
|
125
188
|
conflicts,
|
|
189
|
+
unknown_scope_slices: unknownScopeSlices,
|
|
190
|
+
fallback_reason: fallbackReason || null,
|
|
191
|
+
execution_groups: buildExecutionGroups(slices, parallelReady, fallbackReason),
|
|
126
192
|
slices,
|
|
127
193
|
};
|
|
128
194
|
}
|
|
@@ -153,7 +219,7 @@ function collectExecutionPlan(repoRoot, options = {}) {
|
|
|
153
219
|
}
|
|
154
220
|
|
|
155
221
|
const readyLevels = computeLevels(pendingGraph);
|
|
156
|
-
const readyLevelReports = readyLevels.map((levelNodes, index) => summarizeLevel(levelNodes, index));
|
|
222
|
+
const readyLevelReports = readyLevels.map((levelNodes, index) => summarizeLevel(levelNodes, index, repoRoot));
|
|
157
223
|
const executionOrder = topoSort(pendingGraph).map((node) => node.ref);
|
|
158
224
|
const integrationOrder = readyLevelReports.flatMap((level) => level.slice_refs);
|
|
159
225
|
const foundationRefs = pendingGraph.foundationRefs;
|
|
@@ -210,12 +276,16 @@ function formatHumanExecutionPlan(report) {
|
|
|
210
276
|
}
|
|
211
277
|
|
|
212
278
|
for (const level of report.ready_levels) {
|
|
213
|
-
const modeLabel = level.parallel_ready ? 'parallel' : 'sequential';
|
|
214
|
-
lines.push(`
|
|
279
|
+
const modeLabel = level.parallel_ready ? 'parallel-ready' : 'sequential';
|
|
280
|
+
lines.push(`Wave ${level.index} (${modeLabel})`);
|
|
215
281
|
lines.push(`Worktree strategy: ${level.worktree_strategy.mode}`);
|
|
282
|
+
if (level.fallback_reason) {
|
|
283
|
+
lines.push(`Fallback: ${level.fallback_reason}`);
|
|
284
|
+
}
|
|
216
285
|
|
|
217
286
|
for (const slice of level.slices) {
|
|
218
287
|
lines.push(`- ${slice.ref} [${slice.status}]`);
|
|
288
|
+
lines.push(` parallel_safe: ${slice.parallel_safe || 'unspecified'}${slice.parallel_safe_reason ? ` (${slice.parallel_safe_reason})` : ''}`);
|
|
219
289
|
}
|
|
220
290
|
|
|
221
291
|
if (level.conflicts.length > 0) {
|
|
@@ -225,6 +295,13 @@ function formatHumanExecutionPlan(report) {
|
|
|
225
295
|
}
|
|
226
296
|
}
|
|
227
297
|
|
|
298
|
+
if (level.unknown_scope_slices.length > 0) {
|
|
299
|
+
lines.push('Unknown scope:');
|
|
300
|
+
for (const ref of level.unknown_scope_slices) {
|
|
301
|
+
lines.push(`- ${ref}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
228
305
|
lines.push('');
|
|
229
306
|
}
|
|
230
307
|
|
|
@@ -236,6 +313,292 @@ function formatHumanExecutionPlan(report) {
|
|
|
236
313
|
return `${lines.join('\n')}\n`;
|
|
237
314
|
}
|
|
238
315
|
|
|
316
|
+
function formatExecutePlanDryRun(report, options = {}) {
|
|
317
|
+
const provider = options.resolvedProvider || options.provider || 'codex';
|
|
318
|
+
const commitEnabled = options.commit === true;
|
|
319
|
+
const executionMode = normalizeExecutionMode(options.mode || options.executionMode);
|
|
320
|
+
const lines = [
|
|
321
|
+
'AI execute-plan dry-run',
|
|
322
|
+
`Execution mode: ${executionMode}`,
|
|
323
|
+
`Provider: ${provider}`,
|
|
324
|
+
`Commit after each slice: ${commitEnabled ? 'enabled' : 'disabled'}`,
|
|
325
|
+
`Total slices: ${report.summary.total_slices}`,
|
|
326
|
+
'',
|
|
327
|
+
'Waves',
|
|
328
|
+
];
|
|
329
|
+
|
|
330
|
+
const commandForSlice = (slice) => {
|
|
331
|
+
const parts = [
|
|
332
|
+
'npx create-quiver ai execute-slice',
|
|
333
|
+
`--slice ${JSON.stringify(slice.slice_path)}`,
|
|
334
|
+
`--provider ${provider}`,
|
|
335
|
+
];
|
|
336
|
+
if (commitEnabled) {
|
|
337
|
+
parts.push('--commit');
|
|
338
|
+
}
|
|
339
|
+
return parts.join(' ');
|
|
340
|
+
};
|
|
341
|
+
const promptCommandForSlice = (slice) => [
|
|
342
|
+
'npx create-quiver ai prompt-slice',
|
|
343
|
+
`--slice ${JSON.stringify(slice.slice_path)}`,
|
|
344
|
+
'--dry-run',
|
|
345
|
+
].join(' ');
|
|
346
|
+
|
|
347
|
+
for (const level of report.ready_levels) {
|
|
348
|
+
lines.push(`Wave ${level.index}: ${level.parallel_ready ? 'parallel-ready' : 'sequential'}`);
|
|
349
|
+
lines.push(`Workspace strategy: ${level.worktree_strategy.mode}`);
|
|
350
|
+
if (level.fallback_reason) {
|
|
351
|
+
lines.push(`Fallback: ${level.fallback_reason}`);
|
|
352
|
+
}
|
|
353
|
+
for (const group of level.execution_groups) {
|
|
354
|
+
lines.push(`Group: ${group.mode}`);
|
|
355
|
+
for (const ref of group.slice_refs) {
|
|
356
|
+
const slice = level.slices.find((item) => item.ref === ref);
|
|
357
|
+
lines.push(`- Prompt: ${promptCommandForSlice(slice)}`);
|
|
358
|
+
if (executionMode !== 'manual') {
|
|
359
|
+
lines.push(` Execute: ${commandForSlice(slice)}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return `${lines.join('\n')}\n`;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function buildRecoveryGuidance(ref, workspaces = []) {
|
|
369
|
+
const lines = [
|
|
370
|
+
'Recovery:',
|
|
371
|
+
`- Retry slice: npx create-quiver ai prompt-slice --slice <slice.json> --dry-run, then rerun only ${ref}.`,
|
|
372
|
+
'- Abort: inspect the active checkout and temporary worktrees before reverting, stashing, or removing anything.',
|
|
373
|
+
];
|
|
374
|
+
|
|
375
|
+
if (workspaces.length > 0) {
|
|
376
|
+
lines.push('- Temporary worktrees left for inspection:');
|
|
377
|
+
for (const workspace of workspaces) {
|
|
378
|
+
lines.push(` - ${workspace.worktreePath}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return lines.join('\n');
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function appendRecovery(error, ref, workspaces = []) {
|
|
386
|
+
const message = error && error.message ? error.message : String(error);
|
|
387
|
+
if (message.includes('Recovery:')) {
|
|
388
|
+
return error;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const wrapped = new Error(`${message}\n\n${buildRecoveryGuidance(ref, workspaces)}`);
|
|
392
|
+
wrapped.cause = error;
|
|
393
|
+
wrapped.code = error && error.code ? error.code : undefined;
|
|
394
|
+
wrapped.details = error && error.details ? error.details : undefined;
|
|
395
|
+
return wrapped;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function ensureCleanIntegrationWorktree(repoRoot) {
|
|
399
|
+
const status = statusPorcelain(repoRoot);
|
|
400
|
+
if (status !== '') {
|
|
401
|
+
throw new Error(formatError(`delegated parallel execution requires a clean active worktree before integration. Dirty files: ${status.split('\n').join(', ')}`));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function buildDelegatedRunId() {
|
|
406
|
+
return new Date().toISOString().replace(/[^0-9A-Za-z]/g, '');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function buildDelegatedWorkspace(repoRoot, slice, runId, index, options = {}) {
|
|
410
|
+
const safeRef = safeBranchName(slice.ref).slice(0, 80);
|
|
411
|
+
const branchName = `quiver-exec-${runId}-${index + 1}-${safeRef}`;
|
|
412
|
+
const worktreesRoot = options.worktreesRoot || path.join(worktreesRootForRepo(repoRoot, branchName), 'execute-plan');
|
|
413
|
+
const worktreePath = path.join(worktreesRoot, runId, safeRef);
|
|
414
|
+
|
|
415
|
+
return {
|
|
416
|
+
branchName,
|
|
417
|
+
ref: slice.ref,
|
|
418
|
+
slice,
|
|
419
|
+
worktreePath,
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function createDelegatedWorkspace(repoRoot, workspace, baseRef) {
|
|
424
|
+
if (fs.existsSync(workspace.worktreePath)) {
|
|
425
|
+
throw new Error(formatError(`temporary worktree path already exists: ${workspace.worktreePath}`));
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
fs.mkdirSync(path.dirname(workspace.worktreePath), { recursive: true });
|
|
429
|
+
worktreeAdd(repoRoot, workspace.worktreePath, baseRef, { branch: workspace.branchName });
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function cleanupDelegatedWorkspace(repoRoot, workspace) {
|
|
433
|
+
try {
|
|
434
|
+
worktreeRemove(repoRoot, workspace.worktreePath);
|
|
435
|
+
} catch {
|
|
436
|
+
// Keep cleanup best-effort after successful integration.
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
branchDelete(repoRoot, workspace.branchName, true);
|
|
440
|
+
} catch {
|
|
441
|
+
// The committed changes were already integrated; a leftover temp branch is non-blocking.
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
async function runSequentialGroup(repoRoot, level, group, options = {}) {
|
|
446
|
+
const runSlice = options.runExecuteSliceFn || runExecuteSlice;
|
|
447
|
+
const results = [];
|
|
448
|
+
|
|
449
|
+
for (const ref of group.slice_refs) {
|
|
450
|
+
const slice = level.slices.find((item) => item.ref === ref);
|
|
451
|
+
try {
|
|
452
|
+
const result = await runSlice(repoRoot, {
|
|
453
|
+
allowDirty: options.allowDirty === true,
|
|
454
|
+
commit: true,
|
|
455
|
+
context: options.context,
|
|
456
|
+
dryRun: false,
|
|
457
|
+
provider: options.provider,
|
|
458
|
+
providerExplicit: options.providerExplicit,
|
|
459
|
+
role: options.role,
|
|
460
|
+
slice: slice.slice_path,
|
|
461
|
+
skipWorktreeBranchCheck: true,
|
|
462
|
+
timeout: options.timeout,
|
|
463
|
+
});
|
|
464
|
+
results.push({
|
|
465
|
+
level: level.index,
|
|
466
|
+
mode: 'sequential',
|
|
467
|
+
ref,
|
|
468
|
+
ok: true,
|
|
469
|
+
result,
|
|
470
|
+
workspace: repoRoot,
|
|
471
|
+
});
|
|
472
|
+
} catch (error) {
|
|
473
|
+
throw appendRecovery(error, ref);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return results;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async function runParallelGroupInWorktrees(repoRoot, level, group, options = {}) {
|
|
481
|
+
ensureCleanIntegrationWorktree(repoRoot);
|
|
482
|
+
|
|
483
|
+
const runSlice = options.runExecuteSliceFn || runExecuteSlice;
|
|
484
|
+
const baseRef = runGit(['rev-parse', 'HEAD'], repoRoot);
|
|
485
|
+
const runId = options.runId || buildDelegatedRunId();
|
|
486
|
+
const slices = group.slice_refs.map((ref) => level.slices.find((item) => item.ref === ref));
|
|
487
|
+
const workspaces = slices.map((slice, index) => buildDelegatedWorkspace(repoRoot, slice, runId, index, options));
|
|
488
|
+
|
|
489
|
+
let runResults;
|
|
490
|
+
try {
|
|
491
|
+
worktreePrune(repoRoot);
|
|
492
|
+
for (const workspace of workspaces) {
|
|
493
|
+
createDelegatedWorkspace(repoRoot, workspace, baseRef);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
runResults = await Promise.all(workspaces.map(async (workspace) => {
|
|
497
|
+
const result = await runSlice(workspace.worktreePath, {
|
|
498
|
+
allowDirty: false,
|
|
499
|
+
commit: true,
|
|
500
|
+
context: options.context,
|
|
501
|
+
dryRun: false,
|
|
502
|
+
provider: options.provider,
|
|
503
|
+
providerExplicit: options.providerExplicit,
|
|
504
|
+
role: options.role,
|
|
505
|
+
slice: workspace.slice.slice_path,
|
|
506
|
+
skipWorktreeBranchCheck: true,
|
|
507
|
+
timeout: options.timeout,
|
|
508
|
+
});
|
|
509
|
+
const commit = runGit(['rev-parse', 'HEAD'], workspace.worktreePath);
|
|
510
|
+
if (commit === baseRef) {
|
|
511
|
+
throw new Error(formatError(`delegated slice ${workspace.ref} finished without creating a slice commit.`));
|
|
512
|
+
}
|
|
513
|
+
return {
|
|
514
|
+
commit,
|
|
515
|
+
level: level.index,
|
|
516
|
+
mode: 'parallel-worktree',
|
|
517
|
+
ok: true,
|
|
518
|
+
ref: workspace.ref,
|
|
519
|
+
result,
|
|
520
|
+
workspace,
|
|
521
|
+
};
|
|
522
|
+
}));
|
|
523
|
+
|
|
524
|
+
ensureCleanIntegrationWorktree(repoRoot);
|
|
525
|
+
for (const item of runResults) {
|
|
526
|
+
runGit(['cherry-pick', item.commit], repoRoot);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
for (const workspace of workspaces) {
|
|
530
|
+
cleanupDelegatedWorkspace(repoRoot, workspace);
|
|
531
|
+
}
|
|
532
|
+
} catch (error) {
|
|
533
|
+
throw appendRecovery(error, group.slice_refs.join(', '), workspaces);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
return runResults.map((item) => ({
|
|
537
|
+
level: item.level,
|
|
538
|
+
mode: item.mode,
|
|
539
|
+
ref: item.ref,
|
|
540
|
+
ok: item.ok,
|
|
541
|
+
result: item.result,
|
|
542
|
+
workspace: item.workspace.worktreePath,
|
|
543
|
+
integratedCommit: item.commit,
|
|
544
|
+
}));
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async function runExecutePlan(repoRoot, options = {}) {
|
|
548
|
+
const report = collectExecutionPlan(repoRoot, options);
|
|
549
|
+
const execute = options.execute === true;
|
|
550
|
+
const executionMode = normalizeExecutionMode(options.mode || options.executionMode);
|
|
551
|
+
const provider = options.providerExplicit === true || (options.provider && options.providerExplicit !== false)
|
|
552
|
+
? options.provider
|
|
553
|
+
: resolveProfileProvider(repoRoot, options.role || 'executor', 'codex');
|
|
554
|
+
const resolvedOptions = {
|
|
555
|
+
...options,
|
|
556
|
+
mode: executionMode,
|
|
557
|
+
provider,
|
|
558
|
+
resolvedProvider: provider,
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
if (options.json && !execute) {
|
|
562
|
+
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
563
|
+
return { task: 'execute-plan', dryRun: true, report };
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (!execute || options.dryRun === true) {
|
|
567
|
+
process.stdout.write(formatExecutePlanDryRun(report, resolvedOptions));
|
|
568
|
+
return { task: 'execute-plan', dryRun: true, report };
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (executionMode === 'manual') {
|
|
572
|
+
throw new Error(formatError('ai execute-plan --execute does not support --mode manual. Use the printed prompt-slice commands, or choose --mode delegated.'));
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (options.commit !== true) {
|
|
576
|
+
throw new Error(formatError('ai execute-plan --execute requires --commit so each successful slice creates one commit.'));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const results = [];
|
|
580
|
+
|
|
581
|
+
for (const level of report.ready_levels) {
|
|
582
|
+
for (const group of level.execution_groups) {
|
|
583
|
+
try {
|
|
584
|
+
const groupResults = executionMode === 'delegated' && group.mode === 'parallel' && group.slice_refs.length > 1
|
|
585
|
+
? await runParallelGroupInWorktrees(repoRoot, level, group, resolvedOptions)
|
|
586
|
+
: await runSequentialGroup(repoRoot, level, group, resolvedOptions);
|
|
587
|
+
results.push(...groupResults);
|
|
588
|
+
} catch (error) {
|
|
589
|
+
const wrapped = new Error(formatError(`ai execute-plan stopped at wave ${level.index} group ${group.slice_refs.join(', ')}: ${error.message || error}`));
|
|
590
|
+
wrapped.cause = error;
|
|
591
|
+
wrapped.code = error.code || 'AI_EXECUTE_PLAN_FAILED';
|
|
592
|
+
wrapped.details = { level: level.index, group, results };
|
|
593
|
+
throw wrapped;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
process.stdout.write(`AI execute-plan completed\nSlices executed: ${results.length}\n`);
|
|
599
|
+
return { task: 'execute-plan', dryRun: false, report, results };
|
|
600
|
+
}
|
|
601
|
+
|
|
239
602
|
function runExecutionPlan(repoRoot, options = {}) {
|
|
240
603
|
const report = collectExecutionPlan(repoRoot, options);
|
|
241
604
|
if (options.json) {
|
|
@@ -249,6 +612,9 @@ function runExecutionPlan(repoRoot, options = {}) {
|
|
|
249
612
|
|
|
250
613
|
module.exports = {
|
|
251
614
|
collectExecutionPlan,
|
|
615
|
+
formatExecutePlanDryRun,
|
|
252
616
|
formatHumanExecutionPlan,
|
|
617
|
+
normalizeExecutionMode,
|
|
618
|
+
runExecutePlan,
|
|
253
619
|
runExecutionPlan,
|
|
254
620
|
};
|