create-quiver 0.9.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BACKLOG.md +16 -17
- package/CHANGELOG.md +34 -0
- package/README.md +419 -330
- package/README_FOR_AI.md +93 -56
- package/ROADMAP.md +22 -11
- package/docs/AI_CONTEXT.md.template +2 -0
- package/docs/AI_ONBOARDING_PROMPT.md.template +36 -19
- package/docs/COMMANDS.md.template +73 -1
- package/docs/CONTEXTO.md.template +2 -0
- package/docs/DECISIONS.md.template +1 -0
- package/docs/GITFLOW_PR_GUIDE.md.template +11 -0
- package/docs/INDEX.md.template +20 -18
- package/docs/STANDARD.md.template +1 -1
- package/docs/STATUS.md.template +1 -0
- package/docs/SUPPORT_MATRIX.md.template +6 -2
- package/docs/TROUBLESHOOTING.md.template +79 -1
- package/docs/WORKFLOW.md.template +26 -18
- package/package.json +24 -2
- package/package.template.json +24 -7
- package/scripts/check-pr-readiness.sh +1 -1
- package/scripts/check-scope.sh +0 -1
- package/scripts/check-slice-readiness.sh +3 -4
- package/scripts/init-docs.sh +53 -6
- package/scripts/package-quiver.sh +18 -2
- package/specs/quiver-v20-ai-cli-orchestration/EVIDENCE_REPORT.md +23 -0
- package/specs/quiver-v20-ai-cli-orchestration/EXECUTION_PLAN.md +57 -0
- package/specs/quiver-v20-ai-cli-orchestration/SPEC.md +202 -0
- package/specs/quiver-v20-ai-cli-orchestration/STATUS.md +35 -0
- package/specs/quiver-v20-ai-cli-orchestration/pr.md +100 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/slice.json +54 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/CLOSURE_BRIEF.md +39 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/slice.json +55 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/CLOSURE_BRIEF.md +40 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/slice.json +54 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/EXECUTION_BRIEF.md +62 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/slice.json +62 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/slice.json +59 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/slice.json +59 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/EXECUTION_BRIEF.md +64 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/slice.json +65 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/EXECUTION_BRIEF.md +66 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/slice.json +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/EXECUTION_BRIEF.md +64 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/slice.json +77 -0
- package/specs/quiver-v21-ai-first-layout/EVIDENCE_REPORT.md +31 -0
- package/specs/quiver-v21-ai-first-layout/EXECUTION_PLAN.md +185 -0
- package/specs/quiver-v21-ai-first-layout/SPEC.md +212 -0
- package/specs/quiver-v21-ai-first-layout/STATUS.md +37 -0
- package/specs/quiver-v21-ai-first-layout/pr.md +110 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/slice.json +45 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/slice.json +57 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/slice.json +58 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/slice.json +64 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/slice.json +64 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/slice.json +65 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/EXECUTION_BRIEF.md +62 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/slice.json +66 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/slice.json +67 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/EXECUTION_BRIEF.md +66 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/slice.json +62 -0
- package/specs/quiver-v22-guided-ai-workflow/EVIDENCE_REPORT.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/EXECUTION_PLAN.md +88 -0
- package/specs/quiver-v22-guided-ai-workflow/SPEC.md +228 -0
- package/specs/quiver-v22-guided-ai-workflow/STATUS.md +42 -0
- package/specs/quiver-v22-guided-ai-workflow/pr.md +104 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/slice.json +55 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/slice.json +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/slice.json +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/slice.json +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/slice.json +54 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/slice.json +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/slice.json +55 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/slice.json +53 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/slice.json +59 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/slice.json +60 -0
- package/specs/quiver-v23-guided-flow-productization/EVIDENCE_REPORT.md +80 -0
- package/specs/quiver-v23-guided-flow-productization/EXECUTION_PLAN.md +80 -0
- package/specs/quiver-v23-guided-flow-productization/SPEC.md +203 -0
- package/specs/quiver-v23-guided-flow-productization/STATUS.md +39 -0
- package/specs/quiver-v23-guided-flow-productization/pr.md +119 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/EXECUTION_BRIEF.md +35 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/slice.json +56 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/slice.json +54 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/slice.json +59 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/slice.json +53 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/slice.json +54 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/EXECUTION_BRIEF.md +34 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/slice.json +57 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/slice.json +63 -0
- package/specs/quiver-v24-dx-onboarding-hardening/EVIDENCE_REPORT.md +55 -0
- package/specs/quiver-v24-dx-onboarding-hardening/EXECUTION_PLAN.md +43 -0
- package/specs/quiver-v24-dx-onboarding-hardening/SPEC.md +149 -0
- package/specs/quiver-v24-dx-onboarding-hardening/STATUS.md +31 -0
- package/specs/quiver-v24-dx-onboarding-hardening/pr.md +76 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/slice.json +55 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/slice.json +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/slice.json +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/slice.json +70 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/EXECUTION_BRIEF.md +49 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/slice.json +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/slice.json +60 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/slice.json +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/slice.json +54 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/EXECUTION_BRIEF.md +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/slice.json +59 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/slice.json +76 -0
- package/src/create-quiver/commands/ai.js +915 -0
- package/src/create-quiver/commands/demo.js +22 -0
- package/src/create-quiver/commands/evidence.js +37 -0
- package/src/create-quiver/commands/flow.js +561 -0
- package/src/create-quiver/commands/graph.js +14 -1
- package/src/create-quiver/commands/next.js +28 -0
- package/src/create-quiver/commands/plan.js +6 -3
- package/src/create-quiver/commands/prepare.js +236 -0
- package/src/create-quiver/commands/spec.js +133 -0
- package/src/create-quiver/index.js +1096 -96
- package/src/create-quiver/lib/agent-profiles.js +148 -0
- package/src/create-quiver/lib/ai/context-packs.js +170 -0
- package/src/create-quiver/lib/ai/execution-plan.js +614 -0
- package/src/create-quiver/lib/ai/executor.js +682 -0
- package/src/create-quiver/lib/ai/github.js +525 -0
- package/src/create-quiver/lib/ai/onboarding-template.js +365 -0
- package/src/create-quiver/lib/ai/phase-gates.js +72 -0
- package/src/create-quiver/lib/ai/plan-review.js +283 -0
- package/src/create-quiver/lib/ai/preflight.js +58 -0
- package/src/create-quiver/lib/ai/prompt-transport.js +81 -0
- package/src/create-quiver/lib/ai/prompts.js +39 -0
- package/src/create-quiver/lib/ai/providers.js +315 -0
- package/src/create-quiver/lib/ai/safety.js +156 -0
- package/src/create-quiver/lib/ai/spec-generator.js +314 -0
- package/src/create-quiver/lib/ai/spec-templates.js +715 -0
- package/src/create-quiver/lib/approvals.js +350 -0
- package/src/create-quiver/lib/demo.js +657 -0
- package/src/create-quiver/lib/doctor.js +348 -0
- package/src/create-quiver/lib/evidence.js +115 -0
- package/src/create-quiver/lib/git.js +21 -0
- package/src/create-quiver/lib/init-docs.js +545 -23
- package/src/create-quiver/lib/init-layout.js +451 -0
- package/src/create-quiver/lib/lifecycle.js +8 -2
- package/src/create-quiver/lib/package-safety.js +117 -0
- package/src/create-quiver/lib/paths.js +63 -2
- package/src/create-quiver/lib/project-scan.js +66 -0
- package/src/create-quiver/lib/readiness.js +87 -18
- package/src/create-quiver/lib/scope.js +125 -0
- package/src/create-quiver/lib/slice-graph.js +7 -0
- package/src/create-quiver/lib/slice.js +59 -16
- package/src/create-quiver/lib/spec-worktrees.js +349 -0
- package/src/create-quiver/lib/state.js +18 -1
- package/src/create-quiver/lib/template-resolver.js +74 -0
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
const fs = require('node:fs');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const cp = require('node:child_process');
|
|
4
|
+
|
|
5
|
+
const { buildContextPackMetadata, normalizeRole } = require('./context-packs');
|
|
6
|
+
const { buildProviderInvocation, runProvider } = require('./providers');
|
|
7
|
+
const { resolveProfileProvider } = require('../agent-profiles');
|
|
8
|
+
const { runGit } = require('../git');
|
|
9
|
+
const { captureWorktreeSnapshot, validateScopeSnapshot } = require('../scope');
|
|
10
|
+
const { resolveSliceContext } = require('../slice');
|
|
11
|
+
|
|
12
|
+
const DEFAULT_EXECUTE_PROVIDER = 'codex';
|
|
13
|
+
const DEFAULT_EXECUTE_ROLE = 'executor';
|
|
14
|
+
const DEFAULT_EXECUTE_CONTEXT = 'slice';
|
|
15
|
+
|
|
16
|
+
function formatError(message) {
|
|
17
|
+
return `create-quiver: ${message}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function canonicalizeRepoRoot(repoRoot) {
|
|
21
|
+
try {
|
|
22
|
+
return fs.realpathSync(repoRoot);
|
|
23
|
+
} catch {
|
|
24
|
+
return path.resolve(repoRoot);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function readTextFile(filePath, repoRoot) {
|
|
29
|
+
const resolved = path.resolve(repoRoot, filePath);
|
|
30
|
+
if (!fs.existsSync(resolved)) {
|
|
31
|
+
throw new Error(formatError(`missing required file: ${path.relative(repoRoot, resolved).split(path.sep).join('/')}`));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return fs.readFileSync(resolved, 'utf8');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizeTimeout(timeoutMs) {
|
|
38
|
+
if (timeoutMs === undefined || timeoutMs === null || timeoutMs === '') {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const parsed = Number(timeoutMs);
|
|
43
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
44
|
+
throw new Error(formatError(`invalid timeout value: ${timeoutMs}`));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return parsed;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function toRelativePath(repoRoot, absolutePath) {
|
|
51
|
+
return path.relative(repoRoot, absolutePath).split(path.sep).join('/');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function resolveSliceJsonPath(repoRoot, sliceInput) {
|
|
55
|
+
const value = String(sliceInput || '').trim();
|
|
56
|
+
if (!value) {
|
|
57
|
+
throw new Error(formatError('missing required --slice path for ai execute-slice'));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const resolved = path.resolve(repoRoot, value);
|
|
61
|
+
const slicePath = fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()
|
|
62
|
+
? path.join(resolved, 'slice.json')
|
|
63
|
+
: resolved;
|
|
64
|
+
|
|
65
|
+
if (!fs.existsSync(slicePath)) {
|
|
66
|
+
throw new Error(formatError(`missing slice.json at ${toRelativePath(repoRoot, slicePath)}`));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return slicePath;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function formatList(items) {
|
|
73
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
74
|
+
return ['- n/a'];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return items.map((item) => `- ${item}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function extractMarkdownHeading(text) {
|
|
81
|
+
const match = String(text || '').match(/^#\s+(.+)$/m);
|
|
82
|
+
return match ? match[1].trim() : '';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function extractMarkdownSection(text, headings) {
|
|
86
|
+
const lines = String(text || '').split(/\r?\n/);
|
|
87
|
+
const normalized = new Set(headings.map((heading) => String(heading).trim().toLowerCase()));
|
|
88
|
+
const section = [];
|
|
89
|
+
let capture = false;
|
|
90
|
+
|
|
91
|
+
for (const line of lines) {
|
|
92
|
+
const heading = line.match(/^##\s+(.+)$/);
|
|
93
|
+
if (heading) {
|
|
94
|
+
const key = heading[1].trim().toLowerCase();
|
|
95
|
+
if (normalized.has(key)) {
|
|
96
|
+
capture = true;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if (capture) {
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (capture) {
|
|
105
|
+
section.push(line);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return section.join('\n').trim();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function buildSpecExcerpt(repoRoot, slice) {
|
|
113
|
+
const specPath = path.join(slice.specDirAbs, 'SPEC.md');
|
|
114
|
+
if (!fs.existsSync(specPath)) {
|
|
115
|
+
return {
|
|
116
|
+
path: toRelativePath(repoRoot, specPath),
|
|
117
|
+
lines: ['- n/a'],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const text = fs.readFileSync(specPath, 'utf8');
|
|
122
|
+
const title = extractMarkdownHeading(text);
|
|
123
|
+
const objective = extractMarkdownSection(text, ['Objective', 'Objetivo']);
|
|
124
|
+
const lines = [];
|
|
125
|
+
|
|
126
|
+
if (title) {
|
|
127
|
+
lines.push(`- Title: ${title}`);
|
|
128
|
+
}
|
|
129
|
+
if (objective) {
|
|
130
|
+
lines.push(`- Objective: ${objective.replace(/\s+/g, ' ').slice(0, 500)}`);
|
|
131
|
+
}
|
|
132
|
+
if (lines.length === 0) {
|
|
133
|
+
lines.push('- SPEC.md exists, but no short title/objective excerpt was found.');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
path: toRelativePath(repoRoot, specPath),
|
|
138
|
+
lines,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function buildManualExecutorPrompt({ repoRoot, slicePath, role, context, tokenLimit } = {}) {
|
|
143
|
+
const executorContext = buildExecuteSliceContext({
|
|
144
|
+
repoRoot,
|
|
145
|
+
slicePath,
|
|
146
|
+
role: role || DEFAULT_EXECUTE_ROLE,
|
|
147
|
+
context: context || DEFAULT_EXECUTE_CONTEXT,
|
|
148
|
+
});
|
|
149
|
+
const canonicalRepoRoot = canonicalizeRepoRoot(repoRoot);
|
|
150
|
+
const closurePath = path.join(path.dirname(executorContext.slice.sliceAbs), 'CLOSURE_BRIEF.md');
|
|
151
|
+
const closureText = readTextFile(closurePath, canonicalRepoRoot);
|
|
152
|
+
const relativeClosurePath = toRelativePath(canonicalRepoRoot, closurePath);
|
|
153
|
+
const specExcerpt = buildSpecExcerpt(canonicalRepoRoot, executorContext.slice);
|
|
154
|
+
const slice = executorContext.slice;
|
|
155
|
+
const objective = String(slice.json.objective || slice.json.description || slice.sliceId).trim();
|
|
156
|
+
const restrictions = [
|
|
157
|
+
'Do not read the whole repo.',
|
|
158
|
+
'Do not modify files outside the allowed files.',
|
|
159
|
+
'Before editing, list the files you will read and the files you expect to modify.',
|
|
160
|
+
'Do not add unrequested features.',
|
|
161
|
+
'Do not refactor architecture unless the slice explicitly requires it.',
|
|
162
|
+
'If another file is needed, justify why before reading it.',
|
|
163
|
+
'If blocked, stop and report the blocker before improvising.',
|
|
164
|
+
];
|
|
165
|
+
const outputFormat = [
|
|
166
|
+
'## Cambios realizados',
|
|
167
|
+
'## Archivos modificados',
|
|
168
|
+
'## Comandos ejecutados',
|
|
169
|
+
'## Validaciones',
|
|
170
|
+
'## Riesgos pendientes',
|
|
171
|
+
'## Proximo paso recomendado',
|
|
172
|
+
];
|
|
173
|
+
const promptLines = [
|
|
174
|
+
'Act as a WDD + SDD executor agent.',
|
|
175
|
+
'',
|
|
176
|
+
'MODE: controlled SLICE execution.',
|
|
177
|
+
'',
|
|
178
|
+
'Slice objective:',
|
|
179
|
+
objective || 'n/a',
|
|
180
|
+
'',
|
|
181
|
+
'Minimal context:',
|
|
182
|
+
`- Spec: ${slice.specSlug}`,
|
|
183
|
+
`- Slice: ${slice.sliceId}`,
|
|
184
|
+
`- Slice file: ${slice.sliceRel}`,
|
|
185
|
+
`- Execution brief: ${executorContext.briefPath}`,
|
|
186
|
+
`- Closure brief: ${relativeClosurePath}`,
|
|
187
|
+
'',
|
|
188
|
+
'Relevant SPEC excerpts:',
|
|
189
|
+
`- Source: ${specExcerpt.path}`,
|
|
190
|
+
...specExcerpt.lines,
|
|
191
|
+
'',
|
|
192
|
+
'Allowed files:',
|
|
193
|
+
...formatList(executorContext.allowedFiles),
|
|
194
|
+
'',
|
|
195
|
+
'Restrictions:',
|
|
196
|
+
...formatList(restrictions),
|
|
197
|
+
'',
|
|
198
|
+
'Acceptance criteria:',
|
|
199
|
+
...formatList(slice.acceptance),
|
|
200
|
+
'',
|
|
201
|
+
'Validation commands:',
|
|
202
|
+
...formatList(executorContext.validationCommands),
|
|
203
|
+
'',
|
|
204
|
+
'Exact deliverable expected:',
|
|
205
|
+
'- Implement only this slice.',
|
|
206
|
+
'- Keep the change inside the allowed files.',
|
|
207
|
+
'- Leave evidence in the final report.',
|
|
208
|
+
'',
|
|
209
|
+
'Required final report format:',
|
|
210
|
+
...outputFormat.map((line) => `- ${line}`),
|
|
211
|
+
'',
|
|
212
|
+
`Suggested token limit: ${Number(tokenLimit) > 0 ? Number(tokenLimit) : 3000}`,
|
|
213
|
+
'',
|
|
214
|
+
'Execution brief content:',
|
|
215
|
+
executorContext.briefText.trimEnd(),
|
|
216
|
+
'',
|
|
217
|
+
'Closure brief content:',
|
|
218
|
+
closureText.trimEnd(),
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
allowedFiles: executorContext.allowedFiles,
|
|
223
|
+
closurePath: relativeClosurePath,
|
|
224
|
+
prompt: `${promptLines.join('\n')}\n`,
|
|
225
|
+
slice,
|
|
226
|
+
specExcerpt,
|
|
227
|
+
validationCommands: executorContext.validationCommands,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function runPromptSlice(repoRoot, options = {}) {
|
|
232
|
+
if (!options.slice) {
|
|
233
|
+
throw new Error(formatError('missing required --slice path for ai prompt-slice'));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const built = buildManualExecutorPrompt({
|
|
237
|
+
repoRoot,
|
|
238
|
+
slicePath: options.slice,
|
|
239
|
+
tokenLimit: options.tokenLimit,
|
|
240
|
+
});
|
|
241
|
+
process.stdout.write(built.prompt);
|
|
242
|
+
|
|
243
|
+
return {
|
|
244
|
+
task: 'prompt-slice',
|
|
245
|
+
slice: built.slice.sliceId,
|
|
246
|
+
specSlug: built.slice.specSlug,
|
|
247
|
+
prompt: built.prompt,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function buildRecoveryGuidance(slice) {
|
|
252
|
+
const sliceRef = slice && slice.sliceRel ? slice.sliceRel : '<slice.json>';
|
|
253
|
+
return [
|
|
254
|
+
'Recovery:',
|
|
255
|
+
`- Retry: npx create-quiver ai execute-slice --slice ${sliceRef}`,
|
|
256
|
+
'- Abort: inspect the local changes, then manually revert or stash anything you do not want to keep.',
|
|
257
|
+
'- Commit: rerun with --commit only after provider, scope, and validation pass.',
|
|
258
|
+
].join('\n');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function appendRecovery(error, slice) {
|
|
262
|
+
if (!error || !error.message || error.message.includes('Recovery:')) {
|
|
263
|
+
return error;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const wrapped = new Error(`${error.message}\n\n${buildRecoveryGuidance(slice)}`);
|
|
267
|
+
wrapped.cause = error;
|
|
268
|
+
wrapped.code = error.code;
|
|
269
|
+
wrapped.details = error.details;
|
|
270
|
+
return wrapped;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function buildExecuteSliceContext({ repoRoot, slicePath, role, context }) {
|
|
274
|
+
const canonicalRepoRoot = canonicalizeRepoRoot(repoRoot);
|
|
275
|
+
const resolvedRole = normalizeRole(role || DEFAULT_EXECUTE_ROLE);
|
|
276
|
+
if (resolvedRole !== DEFAULT_EXECUTE_ROLE) {
|
|
277
|
+
throw new Error(formatError('ai execute-slice requires role executor'));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const resolvedSlicePath = resolveSliceJsonPath(canonicalRepoRoot, slicePath);
|
|
281
|
+
const slice = resolveSliceContext(canonicalRepoRoot, resolvedSlicePath);
|
|
282
|
+
const briefPath = path.join(path.dirname(slice.sliceAbs), 'EXECUTION_BRIEF.md');
|
|
283
|
+
const briefText = readTextFile(briefPath, canonicalRepoRoot);
|
|
284
|
+
const pack = buildContextPackMetadata({
|
|
285
|
+
role: resolvedRole,
|
|
286
|
+
packName: context || DEFAULT_EXECUTE_CONTEXT,
|
|
287
|
+
repoRoot: canonicalRepoRoot,
|
|
288
|
+
});
|
|
289
|
+
const relativeSlicePath = toRelativePath(canonicalRepoRoot, slice.sliceAbs);
|
|
290
|
+
const relativeBriefPath = toRelativePath(canonicalRepoRoot, briefPath);
|
|
291
|
+
const allowedFiles = Array.isArray(slice.files) ? slice.files.map((file) => String(file)) : [];
|
|
292
|
+
const acceptance = Array.isArray(slice.acceptance) ? slice.acceptance.map((item) => String(item)) : [];
|
|
293
|
+
const validationCommands = Array.isArray(slice.tests) ? slice.tests.map((item) => String(item)) : [];
|
|
294
|
+
const mustItems = Array.isArray(slice.json.must) ? slice.json.must.map((item) => String(item)) : [];
|
|
295
|
+
const excludedItems = Array.isArray(slice.json.not_included) ? slice.json.not_included.map((item) => String(item)) : [];
|
|
296
|
+
|
|
297
|
+
const sections = [
|
|
298
|
+
pack.prompt,
|
|
299
|
+
'Task: execute the slice directly in the repository using only the handoff below.',
|
|
300
|
+
`Slice: ${slice.sliceId}`,
|
|
301
|
+
`Spec: ${slice.specSlug}`,
|
|
302
|
+
`Slice file: ${relativeSlicePath}`,
|
|
303
|
+
`Execution brief: ${relativeBriefPath}`,
|
|
304
|
+
'Allowed files:',
|
|
305
|
+
...formatList(allowedFiles),
|
|
306
|
+
'Acceptance criteria:',
|
|
307
|
+
...formatList(acceptance),
|
|
308
|
+
'Validation commands:',
|
|
309
|
+
...formatList(validationCommands),
|
|
310
|
+
];
|
|
311
|
+
|
|
312
|
+
if (mustItems.length > 0) {
|
|
313
|
+
sections.push('Must:', ...formatList(mustItems));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (excludedItems.length > 0) {
|
|
317
|
+
sections.push('Not included:', ...formatList(excludedItems));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
sections.push(
|
|
321
|
+
'Constraints:',
|
|
322
|
+
'- Do not commit manually. Quiver can create the slice commit after scope and validation pass when the user enables --commit.',
|
|
323
|
+
'- Do not fix scope violations automatically.',
|
|
324
|
+
'- Do not run multiple executors concurrently.',
|
|
325
|
+
'- Stay inside the allowed files declared by slice.json.',
|
|
326
|
+
'Execution brief:',
|
|
327
|
+
briefText.trimEnd(),
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
allowedFiles,
|
|
332
|
+
briefPath: relativeBriefPath,
|
|
333
|
+
briefText,
|
|
334
|
+
context: pack,
|
|
335
|
+
prompt: sections.join('\n\n'),
|
|
336
|
+
slice,
|
|
337
|
+
validationCommands,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function formatExecuteSliceDryRunReport({ provider, role, contextPack, slice, briefPath, invocation, validationCommands, allowedFiles, commitEnabled }) {
|
|
342
|
+
const lines = [
|
|
343
|
+
'AI execute-slice dry-run',
|
|
344
|
+
`Provider: ${provider}`,
|
|
345
|
+
`Role: ${role}`,
|
|
346
|
+
`Context pack: ${contextPack}`,
|
|
347
|
+
`Slice: ${slice.sliceId}`,
|
|
348
|
+
`Spec: ${slice.specSlug}`,
|
|
349
|
+
`Execution brief: ${briefPath}`,
|
|
350
|
+
`Command: ${invocation.command} ${invocation.args.join(' ')}`,
|
|
351
|
+
`Timeout: ${invocation.timeoutMs}ms`,
|
|
352
|
+
`Prompt transport: ${invocation.promptTransport.mode}`,
|
|
353
|
+
`Prompt length: ${invocation.promptLength} bytes`,
|
|
354
|
+
`Commit after validation: ${commitEnabled ? 'enabled' : 'disabled'}`,
|
|
355
|
+
'Allowed files:',
|
|
356
|
+
...formatList(allowedFiles),
|
|
357
|
+
'Validation commands:',
|
|
358
|
+
...formatList(validationCommands),
|
|
359
|
+
];
|
|
360
|
+
|
|
361
|
+
return `${lines.join('\n')}\n`;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function formatExecuteSliceResult({ slice, changedFiles, scopeResult, validationResults, commitResult, commitEnabled }) {
|
|
365
|
+
const lines = [
|
|
366
|
+
'AI execute-slice completed',
|
|
367
|
+
`Slice: ${slice.sliceId}`,
|
|
368
|
+
`Spec: ${slice.specSlug}`,
|
|
369
|
+
`Changed files: ${changedFiles.length}`,
|
|
370
|
+
];
|
|
371
|
+
|
|
372
|
+
for (const file of changedFiles) {
|
|
373
|
+
lines.push(`- ${file}`);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
lines.push(`Scope validation: ${scopeResult.ok ? 'passed' : 'failed'}`);
|
|
377
|
+
if (!Array.isArray(validationResults) || validationResults.length === 0) {
|
|
378
|
+
lines.push('Validation commands: skipped (none declared)');
|
|
379
|
+
} else {
|
|
380
|
+
lines.push(`Validation commands: passed (${validationResults.length})`);
|
|
381
|
+
}
|
|
382
|
+
if (commitResult) {
|
|
383
|
+
lines.push(`Commit: created ${commitResult.hash}`);
|
|
384
|
+
lines.push(`Commit message: ${commitResult.message}`);
|
|
385
|
+
} else {
|
|
386
|
+
lines.push(`Commit: ${commitEnabled ? 'not created' : 'skipped'}`);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return `${lines.join('\n')}\n`;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function annotateProviderError(error, scope) {
|
|
393
|
+
const message = error && error.message ? error.message : String(error);
|
|
394
|
+
const wrapped = new Error(formatError(`ai ${scope} failed: ${message}`));
|
|
395
|
+
wrapped.cause = error;
|
|
396
|
+
wrapped.code = error && error.code ? error.code : 'AI_PROVIDER_ERROR';
|
|
397
|
+
wrapped.details = error && error.details ? error.details : undefined;
|
|
398
|
+
return wrapped;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function runValidationCommand(command, repoRoot) {
|
|
402
|
+
try {
|
|
403
|
+
const stdout = cp.execSync(command, {
|
|
404
|
+
cwd: repoRoot,
|
|
405
|
+
encoding: 'utf8',
|
|
406
|
+
shell: true,
|
|
407
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
408
|
+
});
|
|
409
|
+
return {
|
|
410
|
+
command,
|
|
411
|
+
ok: true,
|
|
412
|
+
stdout,
|
|
413
|
+
stderr: '',
|
|
414
|
+
exitCode: 0,
|
|
415
|
+
};
|
|
416
|
+
} catch (error) {
|
|
417
|
+
return {
|
|
418
|
+
command,
|
|
419
|
+
ok: false,
|
|
420
|
+
stdout: error.stdout ? String(error.stdout) : '',
|
|
421
|
+
stderr: error.stderr ? String(error.stderr) : '',
|
|
422
|
+
exitCode: Number.isInteger(error.status) ? error.status : 1,
|
|
423
|
+
error,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function runValidationCommands(repoRoot, commands, runner = runValidationCommand) {
|
|
429
|
+
const results = [];
|
|
430
|
+
for (const command of commands) {
|
|
431
|
+
const result = runner(command, repoRoot);
|
|
432
|
+
results.push(result);
|
|
433
|
+
if (!result.ok) {
|
|
434
|
+
const details = [
|
|
435
|
+
formatError(`validation command failed: ${command}`),
|
|
436
|
+
`Exit code: ${result.exitCode}`,
|
|
437
|
+
];
|
|
438
|
+
if (result.stderr) {
|
|
439
|
+
details.push(`stderr:\n${result.stderr.trimEnd()}`);
|
|
440
|
+
}
|
|
441
|
+
if (result.stdout) {
|
|
442
|
+
details.push(`stdout:\n${result.stdout.trimEnd()}`);
|
|
443
|
+
}
|
|
444
|
+
const error = new Error(details.join('\n'));
|
|
445
|
+
error.code = 'VALIDATION_FAILED';
|
|
446
|
+
error.details = { command, result, results };
|
|
447
|
+
throw error;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return results;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function commitTypeForSlice(slice) {
|
|
454
|
+
const type = String(slice.json.type || slice.json.git?.branch_type || '').trim().toLowerCase();
|
|
455
|
+
if (type === 'bugfix' || type === 'hotfix' || type === 'fix') {
|
|
456
|
+
return 'fix';
|
|
457
|
+
}
|
|
458
|
+
if (type === 'docs' || type === 'documentation') {
|
|
459
|
+
return 'docs';
|
|
460
|
+
}
|
|
461
|
+
if (type === 'test' || type === 'tests') {
|
|
462
|
+
return 'test';
|
|
463
|
+
}
|
|
464
|
+
if (type === 'chore') {
|
|
465
|
+
return 'chore';
|
|
466
|
+
}
|
|
467
|
+
return 'feat';
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function buildSliceCommitMessage(slice) {
|
|
471
|
+
const title = String(slice.json.title || slice.sliceId || 'slice').trim();
|
|
472
|
+
const ticket = String(slice.ticket || '').trim();
|
|
473
|
+
const subject = ticket ? `${ticket} ${title}` : title;
|
|
474
|
+
return `${commitTypeForSlice(slice)}: ${subject}`;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function commitSliceChanges(repoRoot, slice, changedFiles, options = {}) {
|
|
478
|
+
if (!Array.isArray(changedFiles) || changedFiles.length === 0) {
|
|
479
|
+
const error = new Error(formatError('commit requested but provider produced no changed files.'));
|
|
480
|
+
error.code = 'NO_CHANGES_TO_COMMIT';
|
|
481
|
+
throw error;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const message = options.message || buildSliceCommitMessage(slice);
|
|
485
|
+
runGit(['add', '--', ...changedFiles], repoRoot);
|
|
486
|
+
runGit(['commit', '-m', message], repoRoot);
|
|
487
|
+
|
|
488
|
+
return {
|
|
489
|
+
files: changedFiles,
|
|
490
|
+
hash: runGit(['rev-parse', '--short', 'HEAD'], repoRoot),
|
|
491
|
+
message,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
async function runExecuteSlice(repoRoot, options = {}) {
|
|
496
|
+
const role = normalizeRole(options.role || DEFAULT_EXECUTE_ROLE);
|
|
497
|
+
const provider = options.providerExplicit === true || (options.provider && options.providerExplicit !== false)
|
|
498
|
+
? String(options.provider || DEFAULT_EXECUTE_PROVIDER).trim().toLowerCase()
|
|
499
|
+
: resolveProfileProvider(repoRoot, role, DEFAULT_EXECUTE_PROVIDER);
|
|
500
|
+
const context = options.context || DEFAULT_EXECUTE_CONTEXT;
|
|
501
|
+
const timeoutMs = normalizeTimeout(options.timeout);
|
|
502
|
+
|
|
503
|
+
if (!options.slice) {
|
|
504
|
+
throw new Error(formatError('missing required --slice path for ai execute-slice'));
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const executorContext = buildExecuteSliceContext({
|
|
508
|
+
repoRoot,
|
|
509
|
+
slicePath: options.slice,
|
|
510
|
+
role,
|
|
511
|
+
context,
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
const prompt = executorContext.prompt;
|
|
515
|
+
let invocation;
|
|
516
|
+
|
|
517
|
+
try {
|
|
518
|
+
invocation = buildProviderInvocation(provider, {
|
|
519
|
+
prompt,
|
|
520
|
+
cwd: repoRoot,
|
|
521
|
+
timeoutMs,
|
|
522
|
+
});
|
|
523
|
+
} catch (error) {
|
|
524
|
+
throw annotateProviderError(error, 'execute-slice');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (options.dryRun) {
|
|
528
|
+
const report = {
|
|
529
|
+
task: 'execute-slice',
|
|
530
|
+
provider,
|
|
531
|
+
role,
|
|
532
|
+
contextPack: executorContext.context.packName,
|
|
533
|
+
slice: executorContext.slice.sliceId,
|
|
534
|
+
invocation,
|
|
535
|
+
briefPath: executorContext.briefPath,
|
|
536
|
+
allowedFiles: executorContext.allowedFiles,
|
|
537
|
+
validationCommands: executorContext.validationCommands,
|
|
538
|
+
commitEnabled: options.commit === true,
|
|
539
|
+
};
|
|
540
|
+
process.stdout.write(formatExecuteSliceDryRunReport({
|
|
541
|
+
provider,
|
|
542
|
+
role,
|
|
543
|
+
contextPack: executorContext.context.packName,
|
|
544
|
+
slice: executorContext.slice,
|
|
545
|
+
briefPath: executorContext.briefPath,
|
|
546
|
+
invocation,
|
|
547
|
+
validationCommands: executorContext.validationCommands,
|
|
548
|
+
allowedFiles: executorContext.allowedFiles,
|
|
549
|
+
commitEnabled: options.commit === true,
|
|
550
|
+
}));
|
|
551
|
+
return report;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
const beforeSnapshot = captureWorktreeSnapshot(repoRoot);
|
|
555
|
+
if (beforeSnapshot.files.length > 0 && options.allowDirty !== true) {
|
|
556
|
+
throw appendRecovery(new Error(formatError(`ai execute-slice requires a clean worktree before running. Commit or stash first: ${beforeSnapshot.files.join(', ')}`)), executorContext.slice);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
let result;
|
|
560
|
+
try {
|
|
561
|
+
result = await (options.runProviderFn || runProvider)(provider, {
|
|
562
|
+
prompt,
|
|
563
|
+
cwd: repoRoot,
|
|
564
|
+
timeoutMs,
|
|
565
|
+
dryRun: false,
|
|
566
|
+
probe: options.probe,
|
|
567
|
+
spawn: options.spawn,
|
|
568
|
+
tempRoot: options.tempRoot,
|
|
569
|
+
tempFileName: options.tempFileName,
|
|
570
|
+
tempFilePrefix: options.tempFilePrefix,
|
|
571
|
+
});
|
|
572
|
+
} catch (error) {
|
|
573
|
+
throw appendRecovery(annotateProviderError(error, 'execute-slice'), executorContext.slice);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (result.stdout) {
|
|
577
|
+
process.stdout.write(result.stdout);
|
|
578
|
+
}
|
|
579
|
+
if (result.stderr) {
|
|
580
|
+
process.stderr.write(result.stderr);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
if (!result.ok) {
|
|
584
|
+
throw appendRecovery(annotateProviderError(result.error || new Error('provider run failed'), 'execute-slice'), executorContext.slice);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const afterSnapshot = captureWorktreeSnapshot(repoRoot);
|
|
588
|
+
let scopeResult;
|
|
589
|
+
try {
|
|
590
|
+
scopeResult = validateScopeSnapshot({
|
|
591
|
+
allowedFiles: executorContext.allowedFiles,
|
|
592
|
+
beforeSnapshot,
|
|
593
|
+
afterSnapshot,
|
|
594
|
+
strict: true,
|
|
595
|
+
});
|
|
596
|
+
} catch (error) {
|
|
597
|
+
throw appendRecovery(error, executorContext.slice);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
let validationResults = [];
|
|
601
|
+
try {
|
|
602
|
+
validationResults = runValidationCommands(
|
|
603
|
+
repoRoot,
|
|
604
|
+
executorContext.validationCommands,
|
|
605
|
+
options.runValidationCommandFn,
|
|
606
|
+
);
|
|
607
|
+
} catch (error) {
|
|
608
|
+
throw appendRecovery(error, executorContext.slice);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const finalSnapshot = captureWorktreeSnapshot(repoRoot);
|
|
612
|
+
let finalScopeResult;
|
|
613
|
+
try {
|
|
614
|
+
finalScopeResult = validateScopeSnapshot({
|
|
615
|
+
allowedFiles: executorContext.allowedFiles,
|
|
616
|
+
beforeSnapshot,
|
|
617
|
+
afterSnapshot: finalSnapshot,
|
|
618
|
+
strict: true,
|
|
619
|
+
});
|
|
620
|
+
} catch (error) {
|
|
621
|
+
throw appendRecovery(error, executorContext.slice);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
let commitResult = null;
|
|
625
|
+
if (options.commit === true) {
|
|
626
|
+
try {
|
|
627
|
+
commitResult = commitSliceChanges(repoRoot, executorContext.slice, finalScopeResult.changedFiles, {
|
|
628
|
+
message: options.commitMessage,
|
|
629
|
+
});
|
|
630
|
+
} catch (error) {
|
|
631
|
+
throw appendRecovery(error, executorContext.slice);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
process.stdout.write(formatExecuteSliceResult({
|
|
636
|
+
slice: executorContext.slice,
|
|
637
|
+
changedFiles: finalScopeResult.changedFiles,
|
|
638
|
+
scopeResult: finalScopeResult,
|
|
639
|
+
validationResults,
|
|
640
|
+
commitResult,
|
|
641
|
+
commitEnabled: options.commit === true,
|
|
642
|
+
}));
|
|
643
|
+
|
|
644
|
+
return {
|
|
645
|
+
task: 'execute-slice',
|
|
646
|
+
provider,
|
|
647
|
+
role,
|
|
648
|
+
contextPack: executorContext.context.packName,
|
|
649
|
+
slice: executorContext.slice.sliceId,
|
|
650
|
+
specSlug: executorContext.slice.specSlug,
|
|
651
|
+
invocation,
|
|
652
|
+
result,
|
|
653
|
+
beforeSnapshot,
|
|
654
|
+
afterSnapshot: finalSnapshot,
|
|
655
|
+
scopeResult: finalScopeResult,
|
|
656
|
+
validationResults,
|
|
657
|
+
commitResult,
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
module.exports = {
|
|
662
|
+
DEFAULT_EXECUTE_CONTEXT,
|
|
663
|
+
DEFAULT_EXECUTE_PROVIDER,
|
|
664
|
+
DEFAULT_EXECUTE_ROLE,
|
|
665
|
+
annotateProviderError,
|
|
666
|
+
appendRecovery,
|
|
667
|
+
buildExecuteSliceContext,
|
|
668
|
+
buildManualExecutorPrompt,
|
|
669
|
+
buildRecoveryGuidance,
|
|
670
|
+
buildSliceCommitMessage,
|
|
671
|
+
canonicalizeRepoRoot,
|
|
672
|
+
commitSliceChanges,
|
|
673
|
+
formatExecuteSliceDryRunReport,
|
|
674
|
+
formatExecuteSliceResult,
|
|
675
|
+
runValidationCommand,
|
|
676
|
+
runValidationCommands,
|
|
677
|
+
normalizeTimeout,
|
|
678
|
+
readTextFile,
|
|
679
|
+
resolveSliceJsonPath,
|
|
680
|
+
runExecuteSlice,
|
|
681
|
+
runPromptSlice,
|
|
682
|
+
};
|