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.
Files changed (242) hide show
  1. package/BACKLOG.md +16 -17
  2. package/CHANGELOG.md +78 -0
  3. package/README.md +208 -41
  4. package/README_FOR_AI.md +50 -24
  5. package/ROADMAP.md +34 -11
  6. package/docs/AI_CONTEXT.md.template +2 -0
  7. package/docs/AI_ONBOARDING_PROMPT.md.template +31 -18
  8. package/docs/COMMANDS.md.template +90 -16
  9. package/docs/CONTEXTO.md.template +2 -0
  10. package/docs/DECISIONS.md.template +1 -0
  11. package/docs/INDEX.md.template +20 -18
  12. package/docs/STATUS.md.template +6 -1
  13. package/docs/SUPPORT_MATRIX.md.template +2 -2
  14. package/docs/TROUBLESHOOTING.md.template +50 -0
  15. package/docs/WORKFLOW.md.template +27 -17
  16. package/package.json +27 -4
  17. package/package.template.json +13 -1
  18. package/scripts/init-docs.sh +11 -4
  19. package/scripts/package-quiver.sh +18 -2
  20. package/specs/quiver-v22-guided-ai-workflow/EVIDENCE_REPORT.md +58 -0
  21. package/specs/quiver-v22-guided-ai-workflow/EXECUTION_PLAN.md +88 -0
  22. package/specs/quiver-v22-guided-ai-workflow/SPEC.md +228 -0
  23. package/specs/quiver-v22-guided-ai-workflow/STATUS.md +42 -0
  24. package/specs/quiver-v22-guided-ai-workflow/pr.md +104 -0
  25. package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +35 -0
  26. package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
  27. package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/slice.json +51 -0
  28. package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/CLOSURE_BRIEF.md +31 -0
  29. package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/EXECUTION_BRIEF.md +58 -0
  30. package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/slice.json +55 -0
  31. package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/CLOSURE_BRIEF.md +30 -0
  32. package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/EXECUTION_BRIEF.md +57 -0
  33. package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/slice.json +57 -0
  34. package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/CLOSURE_BRIEF.md +32 -0
  35. package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/EXECUTION_BRIEF.md +56 -0
  36. package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/slice.json +56 -0
  37. package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/CLOSURE_BRIEF.md +33 -0
  38. package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/EXECUTION_BRIEF.md +56 -0
  39. package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/slice.json +58 -0
  40. package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/CLOSURE_BRIEF.md +32 -0
  41. package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/EXECUTION_BRIEF.md +56 -0
  42. package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/slice.json +54 -0
  43. package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/CLOSURE_BRIEF.md +32 -0
  44. package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/EXECUTION_BRIEF.md +58 -0
  45. package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/slice.json +57 -0
  46. package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/CLOSURE_BRIEF.md +32 -0
  47. package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/EXECUTION_BRIEF.md +58 -0
  48. package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/slice.json +55 -0
  49. package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/CLOSURE_BRIEF.md +32 -0
  50. package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/EXECUTION_BRIEF.md +58 -0
  51. package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/slice.json +53 -0
  52. package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/CLOSURE_BRIEF.md +33 -0
  53. package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/EXECUTION_BRIEF.md +59 -0
  54. package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/slice.json +59 -0
  55. package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +34 -0
  56. package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +58 -0
  57. package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/slice.json +60 -0
  58. package/specs/quiver-v23-guided-flow-productization/EVIDENCE_REPORT.md +80 -0
  59. package/specs/quiver-v23-guided-flow-productization/EXECUTION_PLAN.md +80 -0
  60. package/specs/quiver-v23-guided-flow-productization/SPEC.md +203 -0
  61. package/specs/quiver-v23-guided-flow-productization/STATUS.md +39 -0
  62. package/specs/quiver-v23-guided-flow-productization/pr.md +119 -0
  63. package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
  64. package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
  65. package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/slice.json +51 -0
  66. package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/CLOSURE_BRIEF.md +33 -0
  67. package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/EXECUTION_BRIEF.md +35 -0
  68. package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/slice.json +56 -0
  69. package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/CLOSURE_BRIEF.md +31 -0
  70. package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/EXECUTION_BRIEF.md +29 -0
  71. package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/slice.json +55 -0
  72. package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/CLOSURE_BRIEF.md +33 -0
  73. package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/EXECUTION_BRIEF.md +29 -0
  74. package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/slice.json +54 -0
  75. package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/CLOSURE_BRIEF.md +32 -0
  76. package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/EXECUTION_BRIEF.md +30 -0
  77. package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/slice.json +59 -0
  78. package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/CLOSURE_BRIEF.md +31 -0
  79. package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/EXECUTION_BRIEF.md +29 -0
  80. package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/slice.json +53 -0
  81. package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/CLOSURE_BRIEF.md +33 -0
  82. package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/EXECUTION_BRIEF.md +30 -0
  83. package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/slice.json +54 -0
  84. package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/CLOSURE_BRIEF.md +33 -0
  85. package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/EXECUTION_BRIEF.md +30 -0
  86. package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/slice.json +55 -0
  87. package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/CLOSURE_BRIEF.md +32 -0
  88. package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/EXECUTION_BRIEF.md +30 -0
  89. package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/slice.json +55 -0
  90. package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/CLOSURE_BRIEF.md +33 -0
  91. package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/EXECUTION_BRIEF.md +34 -0
  92. package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/slice.json +57 -0
  93. package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
  94. package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +32 -0
  95. package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/slice.json +63 -0
  96. package/specs/quiver-v24-dx-onboarding-hardening/EVIDENCE_REPORT.md +55 -0
  97. package/specs/quiver-v24-dx-onboarding-hardening/EXECUTION_PLAN.md +43 -0
  98. package/specs/quiver-v24-dx-onboarding-hardening/SPEC.md +149 -0
  99. package/specs/quiver-v24-dx-onboarding-hardening/STATUS.md +31 -0
  100. package/specs/quiver-v24-dx-onboarding-hardening/pr.md +76 -0
  101. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +31 -0
  102. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
  103. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/slice.json +51 -0
  104. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/CLOSURE_BRIEF.md +38 -0
  105. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/EXECUTION_BRIEF.md +53 -0
  106. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/slice.json +55 -0
  107. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/CLOSURE_BRIEF.md +33 -0
  108. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/EXECUTION_BRIEF.md +50 -0
  109. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/slice.json +52 -0
  110. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/CLOSURE_BRIEF.md +33 -0
  111. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/EXECUTION_BRIEF.md +50 -0
  112. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/slice.json +53 -0
  113. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/CLOSURE_BRIEF.md +33 -0
  114. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/EXECUTION_BRIEF.md +50 -0
  115. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/slice.json +70 -0
  116. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/CLOSURE_BRIEF.md +36 -0
  117. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/EXECUTION_BRIEF.md +49 -0
  118. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/slice.json +52 -0
  119. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/CLOSURE_BRIEF.md +43 -0
  120. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/EXECUTION_BRIEF.md +53 -0
  121. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/slice.json +60 -0
  122. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/CLOSURE_BRIEF.md +32 -0
  123. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/EXECUTION_BRIEF.md +50 -0
  124. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/slice.json +51 -0
  125. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/CLOSURE_BRIEF.md +34 -0
  126. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/EXECUTION_BRIEF.md +52 -0
  127. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/slice.json +54 -0
  128. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/CLOSURE_BRIEF.md +34 -0
  129. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/EXECUTION_BRIEF.md +51 -0
  130. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/slice.json +59 -0
  131. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
  132. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +54 -0
  133. package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/slice.json +76 -0
  134. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/EVIDENCE_REPORT.md +293 -0
  135. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/EXECUTION_PLAN.md +58 -0
  136. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/SPEC.md +242 -0
  137. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/STATUS.md +35 -0
  138. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/pr.md +77 -0
  139. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +34 -0
  140. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
  141. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/slice.json +52 -0
  142. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/CLOSURE_BRIEF.md +36 -0
  143. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/EXECUTION_BRIEF.md +52 -0
  144. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/slice.json +56 -0
  145. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/CLOSURE_BRIEF.md +43 -0
  146. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/EXECUTION_BRIEF.md +54 -0
  147. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/slice.json +52 -0
  148. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/CLOSURE_BRIEF.md +35 -0
  149. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/EXECUTION_BRIEF.md +53 -0
  150. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/slice.json +54 -0
  151. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/CLOSURE_BRIEF.md +34 -0
  152. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/EXECUTION_BRIEF.md +54 -0
  153. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/slice.json +52 -0
  154. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/CLOSURE_BRIEF.md +34 -0
  155. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/EXECUTION_BRIEF.md +54 -0
  156. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/slice.json +53 -0
  157. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/CLOSURE_BRIEF.md +33 -0
  158. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/EXECUTION_BRIEF.md +56 -0
  159. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/slice.json +55 -0
  160. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/CLOSURE_BRIEF.md +33 -0
  161. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/EXECUTION_BRIEF.md +54 -0
  162. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/slice.json +52 -0
  163. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/CLOSURE_BRIEF.md +39 -0
  164. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/EXECUTION_BRIEF.md +56 -0
  165. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/slice.json +53 -0
  166. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/CLOSURE_BRIEF.md +38 -0
  167. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/EXECUTION_BRIEF.md +57 -0
  168. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/slice.json +52 -0
  169. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/CLOSURE_BRIEF.md +39 -0
  170. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/EXECUTION_BRIEF.md +55 -0
  171. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/slice.json +56 -0
  172. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/CLOSURE_BRIEF.md +36 -0
  173. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/EXECUTION_BRIEF.md +54 -0
  174. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/slice.json +53 -0
  175. package/specs/quiver-v26-0121-smoke-hardening/EVIDENCE_REPORT.md +208 -0
  176. package/specs/quiver-v26-0121-smoke-hardening/EXECUTION_PLAN.md +57 -0
  177. package/specs/quiver-v26-0121-smoke-hardening/SPEC.md +137 -0
  178. package/specs/quiver-v26-0121-smoke-hardening/STATUS.md +32 -0
  179. package/specs/quiver-v26-0121-smoke-hardening/pr.md +96 -0
  180. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/CLOSURE_BRIEF.md +35 -0
  181. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/EXECUTION_BRIEF.md +55 -0
  182. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/slice.json +73 -0
  183. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/CLOSURE_BRIEF.md +38 -0
  184. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/EXECUTION_BRIEF.md +51 -0
  185. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/slice.json +76 -0
  186. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/CLOSURE_BRIEF.md +37 -0
  187. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/EXECUTION_BRIEF.md +52 -0
  188. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/slice.json +75 -0
  189. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/CLOSURE_BRIEF.md +37 -0
  190. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/EXECUTION_BRIEF.md +53 -0
  191. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/slice.json +77 -0
  192. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/CLOSURE_BRIEF.md +35 -0
  193. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/EXECUTION_BRIEF.md +52 -0
  194. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/slice.json +77 -0
  195. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/CLOSURE_BRIEF.md +34 -0
  196. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/EXECUTION_BRIEF.md +54 -0
  197. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/slice.json +84 -0
  198. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/CLOSURE_BRIEF.md +35 -0
  199. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/EXECUTION_BRIEF.md +53 -0
  200. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/slice.json +82 -0
  201. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/CLOSURE_BRIEF.md +35 -0
  202. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/EXECUTION_BRIEF.md +55 -0
  203. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/slice.json +92 -0
  204. package/src/create-quiver/commands/ai.js +1060 -37
  205. package/src/create-quiver/commands/demo.js +22 -0
  206. package/src/create-quiver/commands/evidence.js +37 -0
  207. package/src/create-quiver/commands/flow.js +562 -0
  208. package/src/create-quiver/commands/graph.js +19 -4
  209. package/src/create-quiver/commands/next.js +28 -0
  210. package/src/create-quiver/commands/plan.js +9 -6
  211. package/src/create-quiver/commands/prepare.js +236 -0
  212. package/src/create-quiver/commands/spec.js +133 -0
  213. package/src/create-quiver/index.js +1010 -31
  214. package/src/create-quiver/lib/actionable-error.js +27 -0
  215. package/src/create-quiver/lib/agent-profiles.js +148 -0
  216. package/src/create-quiver/lib/ai/context-packs.js +16 -0
  217. package/src/create-quiver/lib/ai/execution-plan.js +377 -11
  218. package/src/create-quiver/lib/ai/executor.js +633 -24
  219. package/src/create-quiver/lib/ai/export-state.js +534 -0
  220. package/src/create-quiver/lib/ai/github.js +279 -0
  221. package/src/create-quiver/lib/ai/onboarding-template.js +578 -0
  222. package/src/create-quiver/lib/ai/plan-review.js +286 -0
  223. package/src/create-quiver/lib/ai/providers.js +5 -3
  224. package/src/create-quiver/lib/ai/run-state.js +414 -0
  225. package/src/create-quiver/lib/ai/safety.js +5 -0
  226. package/src/create-quiver/lib/ai/spec-generator.js +12 -0
  227. package/src/create-quiver/lib/ai/spec-templates.js +80 -11
  228. package/src/create-quiver/lib/approvals.js +369 -0
  229. package/src/create-quiver/lib/demo.js +832 -0
  230. package/src/create-quiver/lib/doctor.js +309 -0
  231. package/src/create-quiver/lib/evidence.js +115 -0
  232. package/src/create-quiver/lib/handoff.js +81 -12
  233. package/src/create-quiver/lib/init-docs.js +302 -17
  234. package/src/create-quiver/lib/init-layout.js +34 -1
  235. package/src/create-quiver/lib/json.js +53 -3
  236. package/src/create-quiver/lib/lifecycle.js +6 -0
  237. package/src/create-quiver/lib/package-safety.js +117 -0
  238. package/src/create-quiver/lib/readiness.js +103 -21
  239. package/src/create-quiver/lib/scope.js +50 -7
  240. package/src/create-quiver/lib/slice-graph.js +138 -37
  241. package/src/create-quiver/lib/slice.js +14 -9
  242. package/src/create-quiver/lib/spec-worktrees.js +363 -0
@@ -1,11 +1,56 @@
1
1
  const fs = require('node:fs');
2
2
  const path = require('node:path');
3
3
 
4
+ const { redactSecrets } = require('../lib/evidence');
5
+ const { formatActionableError } = require('../lib/actionable-error');
4
6
  const { buildContextPackMetadata, normalizeRole } = require('../lib/ai/context-packs');
5
- const { runExecuteSlice } = require('../lib/ai/executor');
6
- const { formatPreflightReport, preflightGitHubPr } = require('../lib/ai/github');
7
+ const { runExecuteSlice, runPromptSlice } = require('../lib/ai/executor');
8
+ const { runExecutePlan } = require('../lib/ai/execution-plan');
9
+ const { buildPrCreatePlan, formatPreflightReport, formatPrCreateReport, preflightGitHubPr, runGhPrCreate } = require('../lib/ai/github');
10
+ const { buildContextPreparationDrafts, buildPlannerOnboardingPrompt } = require('../lib/ai/onboarding-template');
11
+ const {
12
+ collectLifecycleExport,
13
+ formatLifecycleExportMarkdown,
14
+ formatLifecycleInspect,
15
+ formatSlicesList,
16
+ formatSpecsList,
17
+ formatTraceReport,
18
+ } = require('../lib/ai/export-state');
19
+ const {
20
+ PLAN_REVIEW_PROMPT_SOURCE,
21
+ buildPlanReviewPrompt,
22
+ readPlanReview,
23
+ resolveReviewedTechnicalPlanInput,
24
+ resolveTechnicalPlanReviewInput,
25
+ savePlanReview,
26
+ summarizePlanReview,
27
+ } = require('../lib/ai/plan-review');
7
28
  const { buildSpecGenerationManifest, describeSpecGeneration, generateSpecArtifacts } = require('../lib/ai/spec-generator');
8
29
  const { buildProviderInvocation, runProvider } = require('../lib/ai/providers');
30
+ const {
31
+ createAiRun,
32
+ ensureAiRun,
33
+ formatAiRunResume,
34
+ formatAiRunStatus,
35
+ recordAiRunApproval,
36
+ resolveAiRun,
37
+ updateAiRunPhase,
38
+ } = require('../lib/ai/run-state');
39
+ const {
40
+ agentProfilesPath,
41
+ getAgentProfile,
42
+ listAgentProfiles,
43
+ resolveProfileProvider,
44
+ setAgentProfile,
45
+ } = require('../lib/agent-profiles');
46
+ const {
47
+ PLANNER_APPROVAL_PHASES,
48
+ approvePlannerPhase,
49
+ readPhaseApproval,
50
+ resolveApprovedPlannerInput,
51
+ savePlannerDraft,
52
+ summarizePlannerApproval,
53
+ } = require('../lib/approvals');
9
54
  const { assertPlannerPhaseReady, getPlannerPhaseDetails, normalizePlannerPhase, PlannerPhaseError } = require('../lib/ai/phase-gates');
10
55
 
11
56
  const DEFAULT_ONBOARD_PROVIDER = 'codex';
@@ -15,6 +60,8 @@ const DEFAULT_PLAN_PROVIDER = 'codex';
15
60
  const DEFAULT_PLAN_ROLE = 'planner';
16
61
  const DEFAULT_PLAN_CONTEXT = 'planning';
17
62
  const DEFAULT_PLAN_PHASE = 'acceptance';
63
+ const CONTEXT_PREP_START = '<!-- quiver:context-prep:start -->';
64
+ const CONTEXT_PREP_END = '<!-- quiver:context-prep:end -->';
18
65
 
19
66
  function formatError(message) {
20
67
  return `create-quiver: ${message}`;
@@ -33,6 +80,14 @@ function readTextFile(filePath, repoRoot) {
33
80
  return fs.readFileSync(resolved, 'utf8');
34
81
  }
35
82
 
83
+ function readTextFileOrEmpty(filePath, repoRoot) {
84
+ if (!filePath) {
85
+ return '';
86
+ }
87
+
88
+ return readTextFile(filePath, repoRoot);
89
+ }
90
+
36
91
  function normalizeTimeout(timeoutMs) {
37
92
  if (timeoutMs === undefined || timeoutMs === null || timeoutMs === '') {
38
93
  return undefined;
@@ -46,7 +101,14 @@ function normalizeTimeout(timeoutMs) {
46
101
  return parsed;
47
102
  }
48
103
 
49
- function buildPlanContext({ role, context, phase, inputText, inputPath, repoRoot }) {
104
+ function resolveProviderForProfile(repoRoot, role, provider, providerExplicit, fallbackProvider) {
105
+ if (providerExplicit === true || (provider && providerExplicit !== false)) {
106
+ return String(provider || fallbackProvider).trim().toLowerCase();
107
+ }
108
+ return resolveProfileProvider(repoRoot, role, fallbackProvider);
109
+ }
110
+
111
+ function buildPlanContext({ role, context, phase, inputText, inputPath, repoRoot, revise = false }) {
50
112
  const phaseDetails = getPlannerPhaseDetails(phase);
51
113
  const pack = buildContextPackMetadata({
52
114
  role,
@@ -57,7 +119,9 @@ function buildPlanContext({ role, context, phase, inputText, inputPath, repoRoot
57
119
  const sections = [
58
120
  pack.prompt,
59
121
  `Phase: ${phaseDetails.phase}`,
60
- phaseDetails.phase === 'acceptance'
122
+ revise
123
+ ? 'Task: revise the current draft and produce a new version only. Do not advance phase, approve, create specs, or modify product code.'
124
+ : phaseDetails.phase === 'acceptance'
61
125
  ? 'Task: produce acceptance criteria only. Do not create files or modify product code.'
62
126
  : 'Task: produce a technical plan only. Do not create files or modify product code.',
63
127
  ];
@@ -88,34 +152,49 @@ function buildOnboardContext({ role, context, inputText, inputPath, repoRoot })
88
152
  repoRoot,
89
153
  });
90
154
  const relativeInputPath = inputPath ? path.relative(repoRoot, path.resolve(repoRoot, inputPath)).split(path.sep).join('/') : '';
91
- const sections = [
92
- pack.prompt,
93
- 'Task: onboard the project context for planning.',
94
- 'Read Quiver context, the WDD/SDD workflow, the project scan/map, assumptions, risks, and relevant docs.',
95
- 'Do not modify product code.',
155
+ const built = buildPlannerOnboardingPrompt({
156
+ pack,
157
+ inputText,
158
+ inputPath: relativeInputPath,
159
+ repoRoot,
160
+ });
161
+
162
+ return {
163
+ pack,
164
+ plan: built.plan,
165
+ prompt: built.prompt,
166
+ };
167
+ }
168
+
169
+ function formatDryRunReport({ task, provider, role, contextPack, phase, invocation, onboardingPlan }) {
170
+ const lines = [
171
+ `AI ${task} dry-run`,
172
+ `Provider: ${provider}`,
173
+ `Role: ${role}`,
174
+ `Context pack: ${contextPack}`,
96
175
  ];
97
176
 
98
- if (relativeInputPath) {
99
- sections.push(`Input file: ${relativeInputPath}`);
177
+ if (phase) {
178
+ lines.push(`Phase: ${phase}`);
100
179
  }
101
180
 
102
- if (pack.scanArtifact) {
103
- sections.push(`Project scan artifact: ${pack.scanArtifact.path} (${pack.scanArtifact.source})`);
104
- }
181
+ lines.push(`Command: ${invocation.command} ${invocation.args.join(' ')}`);
182
+ lines.push(`Timeout: ${invocation.timeoutMs}ms`);
183
+ lines.push(`Prompt transport: ${invocation.promptTransport.mode}`);
184
+ lines.push(`Prompt length: ${invocation.promptLength} bytes`);
105
185
 
106
- if (inputText) {
107
- sections.push('Input:', inputText.trimEnd());
186
+ if (onboardingPlan) {
187
+ lines.push(`Prompt source: ${onboardingPlan.promptSource}`);
188
+ lines.push(`Selected docs: ${onboardingPlan.selectedDocs.length}`);
189
+ lines.push(`Documentation debt: ${onboardingPlan.missingDocs.length}`);
108
190
  }
109
191
 
110
- return {
111
- pack,
112
- prompt: sections.join('\n\n'),
113
- };
192
+ return `${lines.join('\n')}\n`;
114
193
  }
115
194
 
116
- function formatDryRunReport({ task, provider, role, contextPack, phase, invocation }) {
195
+ function formatPromptOnlyReport({ task, provider, role, contextPack, phase, invocation, prompt, onboardingPlan, promptSource, inputPath, inputKind, inputVersion }) {
117
196
  const lines = [
118
- `AI ${task} dry-run`,
197
+ `AI ${task} prompt-only`,
119
198
  `Provider: ${provider}`,
120
199
  `Role: ${role}`,
121
200
  `Context pack: ${contextPack}`,
@@ -130,16 +209,276 @@ function formatDryRunReport({ task, provider, role, contextPack, phase, invocati
130
209
  lines.push(`Prompt transport: ${invocation.promptTransport.mode}`);
131
210
  lines.push(`Prompt length: ${invocation.promptLength} bytes`);
132
211
 
212
+ if (onboardingPlan) {
213
+ lines.push(`Prompt source: ${onboardingPlan.promptSource}`);
214
+ lines.push(`Selected docs: ${onboardingPlan.selectedDocs.length}`);
215
+ lines.push(`Documentation debt: ${onboardingPlan.missingDocs.length}`);
216
+ }
217
+
218
+ if (promptSource) {
219
+ lines.push(`Prompt source: ${promptSource}`);
220
+ }
221
+
222
+ if (inputPath) {
223
+ lines.push(`Input file: ${inputPath}`);
224
+ }
225
+
226
+ if (inputKind) {
227
+ lines.push(`Input kind: ${inputKind}`);
228
+ }
229
+
230
+ if (inputVersion) {
231
+ lines.push(`Input version: v${inputVersion}`);
232
+ }
233
+
234
+ lines.push('--- PROMPT START ---');
235
+ lines.push(String(prompt || '').trimEnd());
236
+ lines.push('--- PROMPT END ---');
237
+
238
+ return `${lines.join('\n')}\n`;
239
+ }
240
+
241
+ function formatPathList(items, emptyLabel = 'none') {
242
+ if (!Array.isArray(items) || items.length === 0) {
243
+ return [`- ${emptyLabel}`];
244
+ }
245
+
246
+ return items.map((item) => `- ${item}`);
247
+ }
248
+
249
+ function formatContextPreparationReport({ dryRun, plan, writePlan, writtenDocs, snapshot, completed = false }) {
250
+ const lines = [
251
+ dryRun ? 'AI prepare-context dry-run' : completed ? 'AI prepare-context completed' : 'AI prepare-context write plan',
252
+ `Mode: ${dryRun ? 'dry-run' : 'live'}`,
253
+ `Project: ${plan.projectName}`,
254
+ `Project slug: ${plan.projectSlug}`,
255
+ 'Writes: docs-only',
256
+ 'Product code: untouched',
257
+ `Proposed docs: ${writePlan.length > 0 ? writePlan.map((item) => item.path).join(', ') : 'none'}`,
258
+ ];
259
+
260
+ if (!dryRun) {
261
+ lines.push(`${completed ? 'Written docs' : 'Planned writes'}: ${writtenDocs.length > 0 ? writtenDocs.join(', ') : 'none'}`);
262
+ if (snapshot) {
263
+ lines.push(`Snapshot: ${snapshot.root}`);
264
+ }
265
+ }
266
+
267
+ if (completed) {
268
+ return `${lines.join('\n')}\n`;
269
+ }
270
+
271
+ lines.push(
272
+ 'Proposed changes:',
273
+ ...writePlan.map((item) => `- ${item.path}: ${item.action}${item.reason ? ` (${item.reason})` : ''}`),
274
+ 'Diff preview:',
275
+ ...formatDiffPreview(writePlan),
276
+ 'Files considered:',
277
+ ...plan.filesConsidered.map((item) => `- ${item.path}: ${item.present ? 'present' : 'absent'}${item.reason ? ` (${item.reason})` : ''}`),
278
+ 'Assumptions:',
279
+ ...formatPathList(plan.assumptions),
280
+ 'Risks:',
281
+ ...formatPathList(plan.risks),
282
+ 'Contradictions:',
283
+ ...formatPathList(plan.contradictions),
284
+ 'Omitted paths:',
285
+ ...formatPathList(plan.omittedPaths),
286
+ 'Uncertainty markers: TODO | Assumption | Pending confirmation',
287
+ );
288
+
133
289
  return `${lines.join('\n')}\n`;
134
290
  }
135
291
 
136
292
  function writeProviderOutput(result) {
137
293
  if (result.stdout) {
138
- process.stdout.write(result.stdout);
294
+ process.stdout.write(redactSecrets(result.stdout));
139
295
  }
140
296
  if (result.stderr) {
141
- process.stderr.write(result.stderr);
297
+ process.stderr.write(redactSecrets(result.stderr));
298
+ }
299
+ }
300
+
301
+ function getRedactedProviderText(result) {
302
+ return redactSecrets([result.stdout, result.stderr].filter(Boolean).join(''));
303
+ }
304
+
305
+ function normalizeText(value) {
306
+ return String(value || '').replace(/\r\n/g, '\n');
307
+ }
308
+
309
+ function buildRevisionInput({ phase, feedbackPath, feedbackText, repoRoot }) {
310
+ const current = readPhaseApproval(repoRoot, phase);
311
+ if (!current.draft) {
312
+ throw new Error(formatError(`ai revise --phase ${phase} requires an existing draft; current status is ${current.status}. Run \`npx create-quiver ai plan --phase ${phase} --input <file>\` first.`));
313
+ }
314
+
315
+ const sections = [];
316
+
317
+ if (phase === 'technical-plan') {
318
+ const acceptance = resolveApprovedPlannerInput(repoRoot, phase, undefined);
319
+ const acceptanceText = readTextFile(acceptance.inputPath, repoRoot);
320
+ sections.push(`Approved acceptance input (${acceptance.inputPath}):`, acceptanceText.trimEnd());
321
+ }
322
+
323
+ sections.push(
324
+ `Current ${phase} draft (${current.draft.path}):`,
325
+ current.draft.contents.trimEnd(),
326
+ `Human feedback (${feedbackPath}):`,
327
+ feedbackText.trimEnd(),
328
+ );
329
+
330
+ return sections.join('\n\n');
331
+ }
332
+
333
+ function buildManagedContextBlock(content) {
334
+ return `${CONTEXT_PREP_START}\n${String(content || '').trimEnd()}\n${CONTEXT_PREP_END}\n`;
335
+ }
336
+
337
+ function mergeContextDraft(existingContent, draftContent) {
338
+ const existing = normalizeText(existingContent);
339
+ const block = buildManagedContextBlock(draftContent);
340
+ const startIndex = existing.indexOf(CONTEXT_PREP_START);
341
+ const endIndex = existing.indexOf(CONTEXT_PREP_END);
342
+
343
+ if (startIndex >= 0 && endIndex > startIndex) {
344
+ const before = existing.slice(0, startIndex).trimEnd();
345
+ const after = existing.slice(endIndex + CONTEXT_PREP_END.length).trimStart();
346
+ return `${before}\n\n${block}${after ? `\n${after}` : ''}`;
347
+ }
348
+
349
+ return `${existing.trimEnd()}\n\n${block}`;
350
+ }
351
+
352
+ function firstChangedLineIndex(beforeLines, afterLines) {
353
+ const max = Math.max(beforeLines.length, afterLines.length);
354
+ for (let index = 0; index < max; index += 1) {
355
+ if (beforeLines[index] !== afterLines[index]) {
356
+ return index;
357
+ }
358
+ }
359
+ return -1;
360
+ }
361
+
362
+ function buildDiffSnippet(pathLabel, beforeContent, afterContent, maxLines = 10) {
363
+ const beforeLines = normalizeText(beforeContent).split('\n');
364
+ const afterLines = normalizeText(afterContent).split('\n');
365
+ const changedAt = firstChangedLineIndex(beforeLines, afterLines);
366
+
367
+ if (changedAt === -1) {
368
+ return [`diff -- ${pathLabel}`, ' no changes'];
369
+ }
370
+
371
+ const start = Math.max(0, changedAt - 2);
372
+ const beforeSnippet = beforeLines.slice(start, start + maxLines);
373
+ const afterSnippet = afterLines.slice(start, start + maxLines);
374
+ const lines = [
375
+ `--- ${pathLabel} (current)`,
376
+ `+++ ${pathLabel} (proposed)`,
377
+ ];
378
+
379
+ for (const line of beforeSnippet) {
380
+ if (line) {
381
+ lines.push(`- ${line}`);
382
+ }
142
383
  }
384
+
385
+ for (const line of afterSnippet) {
386
+ if (line) {
387
+ lines.push(`+ ${line}`);
388
+ }
389
+ }
390
+
391
+ return lines;
392
+ }
393
+
394
+ function buildContextWritePlan(repoRoot, drafts) {
395
+ return drafts.map((draft) => {
396
+ const destinationPath = path.join(repoRoot, draft.path);
397
+ const exists = fs.existsSync(destinationPath);
398
+ const currentContent = exists ? fs.readFileSync(destinationPath, 'utf8') : '';
399
+ const proposedContent = exists
400
+ ? mergeContextDraft(currentContent, draft.content)
401
+ : `${String(draft.content || '').replace(/\s+$/g, '')}\n`;
402
+ const changed = normalizeText(currentContent) !== normalizeText(proposedContent);
403
+
404
+ return {
405
+ path: draft.path,
406
+ destinationPath,
407
+ action: changed ? (exists ? 'update' : 'create') : 'skip',
408
+ reason: changed ? (exists ? 'human content preserved; Quiver block appended or refreshed' : 'missing approved context doc') : 'already up to date',
409
+ exists,
410
+ currentContent,
411
+ proposedContent,
412
+ diff: buildDiffSnippet(draft.path, currentContent, proposedContent),
413
+ };
414
+ });
415
+ }
416
+
417
+ function formatDiffPreview(writePlan) {
418
+ const lines = [];
419
+ for (const item of writePlan) {
420
+ if (item.action === 'skip') {
421
+ continue;
422
+ }
423
+ lines.push(...item.diff);
424
+ }
425
+ return lines.length > 0 ? lines : ['- no changes'];
426
+ }
427
+
428
+ function createContextSnapshots(repoRoot, run, writePlan, now = new Date()) {
429
+ const stamp = now.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}Z$/, 'Z');
430
+ const snapshotRoot = path.join(repoRoot, '.quiver', 'runs', run.run_id, 'snapshots', stamp);
431
+ const manifest = {
432
+ schema_version: 1,
433
+ run_id: run.run_id,
434
+ created_at: now.toISOString(),
435
+ entries: [],
436
+ };
437
+
438
+ fs.mkdirSync(snapshotRoot, { recursive: true });
439
+
440
+ for (const item of writePlan) {
441
+ if (item.action === 'skip') {
442
+ continue;
443
+ }
444
+ const entry = {
445
+ path: item.path,
446
+ action: item.action,
447
+ existed: item.exists,
448
+ snapshot_path: null,
449
+ };
450
+
451
+ if (item.exists) {
452
+ const snapshotPath = path.join(snapshotRoot, item.path);
453
+ fs.mkdirSync(path.dirname(snapshotPath), { recursive: true });
454
+ fs.copyFileSync(item.destinationPath, snapshotPath);
455
+ entry.snapshot_path = path.relative(repoRoot, snapshotPath).split(path.sep).join('/');
456
+ }
457
+
458
+ manifest.entries.push(entry);
459
+ }
460
+
461
+ const manifestPath = path.join(snapshotRoot, 'manifest.json');
462
+ fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
463
+
464
+ return {
465
+ root: path.relative(repoRoot, snapshotRoot).split(path.sep).join('/'),
466
+ manifestPath: path.relative(repoRoot, manifestPath).split(path.sep).join('/'),
467
+ entries: manifest.entries,
468
+ };
469
+ }
470
+
471
+ function writeDraftDocs(writePlan) {
472
+ const writtenDocs = [];
473
+ for (const item of writePlan) {
474
+ if (item.action === 'skip') {
475
+ continue;
476
+ }
477
+ fs.mkdirSync(path.dirname(item.destinationPath), { recursive: true });
478
+ fs.writeFileSync(item.destinationPath, item.proposedContent);
479
+ writtenDocs.push(item.path);
480
+ }
481
+ return writtenDocs;
143
482
  }
144
483
 
145
484
  function formatSpecDryRunReport({ manifest, repoRoot }) {
@@ -178,6 +517,43 @@ function formatSpecGenerationResult(result, repoRoot) {
178
517
  return `${lines.join('\n')}\n`;
179
518
  }
180
519
 
520
+ function formatApprovalResult(result, repoRoot) {
521
+ const relativePath = path.relative(repoRoot, result.filePath).split(path.sep).join('/');
522
+ const lines = [
523
+ 'AI approval saved',
524
+ `Phase: ${result.phase}`,
525
+ `Status: approved`,
526
+ `Artifact: ${relativePath}`,
527
+ `Source file: ${result.sourceFile}`,
528
+ `Timestamp: ${result.createdAt}`,
529
+ ];
530
+ if (result.version) {
531
+ lines.push(`Version: v${result.version}`);
532
+ }
533
+
534
+ return `${lines.join('\n')}\n`;
535
+ }
536
+
537
+ function formatApprovalDryRunResult({ phase, input, version }) {
538
+ const lines = ['AI approval dry-run', `Phase: ${phase}`];
539
+ if (version) {
540
+ lines.push(`Version: v${version}`);
541
+ }
542
+ if (input) {
543
+ lines.push(`Input file: ${input}`);
544
+ }
545
+ return `${lines.join('\n')}\n`;
546
+ }
547
+
548
+ function formatApprovalStatusReport(repoRoot) {
549
+ const sections = ['AI approvals status'];
550
+ for (const phase of PLANNER_APPROVAL_PHASES) {
551
+ sections.push(summarizePlannerApproval(repoRoot, phase).trimEnd());
552
+ }
553
+ sections.push(summarizePlanReview(repoRoot).trimEnd());
554
+ return `${sections.join('\n\n')}\n`;
555
+ }
556
+
181
557
  function annotateProviderError(error, scope, phase) {
182
558
  const phaseLabel = phase ? ` phase '${phase}'` : '';
183
559
  const message = error && error.message ? error.message : String(error);
@@ -198,12 +574,13 @@ function annotateGitHubError(error, scope) {
198
574
  }
199
575
 
200
576
  async function runOnboard(repoRoot, options = {}) {
201
- const provider = String(options.provider || DEFAULT_ONBOARD_PROVIDER).trim().toLowerCase();
202
577
  const role = normalizeRole(options.role || DEFAULT_ONBOARD_ROLE);
578
+ const provider = resolveProviderForProfile(repoRoot, role, options.provider, options.providerExplicit, DEFAULT_ONBOARD_PROVIDER);
203
579
  const context = options.context || DEFAULT_ONBOARD_CONTEXT;
204
580
  const timeoutMs = normalizeTimeout(options.timeout);
205
581
  const inputText = readTextFile(options.input, repoRoot);
206
- const prompt = buildOnboardContext({ role, context, inputText, inputPath: options.input, repoRoot }).prompt;
582
+ const contextInfo = buildOnboardContext({ role, context, inputText, inputPath: options.input, repoRoot });
583
+ const prompt = contextInfo.prompt;
207
584
  let invocation;
208
585
 
209
586
  try {
@@ -223,11 +600,26 @@ async function runOnboard(repoRoot, options = {}) {
223
600
  role,
224
601
  contextPack: context,
225
602
  invocation,
603
+ onboardingPlan: contextInfo.plan,
226
604
  };
227
605
  process.stdout.write(formatDryRunReport(report));
228
606
  return report;
229
607
  }
230
608
 
609
+ if (options.printPrompt) {
610
+ const report = {
611
+ task: 'onboard',
612
+ provider,
613
+ role,
614
+ contextPack: context,
615
+ invocation,
616
+ onboardingPlan: contextInfo.plan,
617
+ prompt,
618
+ };
619
+ process.stdout.write(formatPromptOnlyReport(report));
620
+ return report;
621
+ }
622
+
231
623
  let result;
232
624
  try {
233
625
  result = await (options.runProviderFn || runProvider)(provider, {
@@ -257,30 +649,103 @@ async function runOnboard(repoRoot, options = {}) {
257
649
  role,
258
650
  contextPack: context,
259
651
  invocation,
652
+ onboardingPlan: contextInfo.plan,
260
653
  result,
261
654
  };
262
655
  }
263
656
 
657
+ async function runPrepareContext(repoRoot, options = {}) {
658
+ const draftPack = buildContextPreparationDrafts(repoRoot);
659
+ const writePlan = buildContextWritePlan(repoRoot, draftPack.docs);
660
+ const report = {
661
+ task: 'prepare-context',
662
+ dryRun: options.dryRun === true,
663
+ docs: draftPack.docs.map((doc) => doc.path),
664
+ plan: draftPack.plan,
665
+ writePlan: writePlan.map((item) => ({
666
+ path: item.path,
667
+ action: item.action,
668
+ reason: item.reason,
669
+ })),
670
+ };
671
+
672
+ if (options.dryRun) {
673
+ process.stdout.write(formatContextPreparationReport({
674
+ dryRun: true,
675
+ plan: draftPack.plan,
676
+ writePlan,
677
+ writtenDocs: [],
678
+ }));
679
+ return report;
680
+ }
681
+
682
+ const lifecycleRun = ensureAiRun(repoRoot, {
683
+ command: 'ai prepare-context',
684
+ input: options.input || '',
685
+ runId: options.runId,
686
+ phase: 'created',
687
+ });
688
+ const snapshot = createContextSnapshots(repoRoot, lifecycleRun, writePlan, options.now || new Date());
689
+ const plannedDocs = writePlan.filter((item) => item.action !== 'skip').map((item) => item.path);
690
+ process.stdout.write(formatContextPreparationReport({
691
+ dryRun: false,
692
+ plan: draftPack.plan,
693
+ writePlan,
694
+ writtenDocs: plannedDocs,
695
+ snapshot,
696
+ }));
697
+ const writtenDocs = writeDraftDocs(writePlan);
698
+ updateAiRunPhase(repoRoot, lifecycleRun.run_id, 'onboarding-ready', {
699
+ artifact: snapshot.manifestPath,
700
+ command: 'ai prepare-context',
701
+ });
702
+ process.stdout.write(formatContextPreparationReport({
703
+ dryRun: false,
704
+ plan: draftPack.plan,
705
+ writePlan,
706
+ writtenDocs,
707
+ snapshot,
708
+ completed: true,
709
+ }));
710
+
711
+ return {
712
+ ...report,
713
+ runId: lifecycleRun.run_id,
714
+ snapshot,
715
+ writtenDocs,
716
+ };
717
+ }
718
+
264
719
  async function runPlan(repoRoot, options = {}) {
265
720
  const phase = normalizePlannerPhase(options.phase || DEFAULT_PLAN_PHASE);
266
721
  const role = normalizeRole(options.role || DEFAULT_PLAN_ROLE);
267
- const provider = String(options.provider || DEFAULT_PLAN_PROVIDER).trim().toLowerCase();
722
+ const provider = resolveProviderForProfile(repoRoot, role, options.provider, options.providerExplicit, DEFAULT_PLAN_PROVIDER);
268
723
  const context = options.context || DEFAULT_PLAN_CONTEXT;
269
724
  const timeoutMs = normalizeTimeout(options.timeout);
270
-
271
- if (!options.input) {
272
- throw new Error(formatError(`missing input file for ai plan phase '${phase}'`));
273
- }
725
+ let inputPath = options.input || '';
274
726
 
275
727
  if (phase === 'spec') {
276
- const inputText = readTextFile(options.input, repoRoot);
728
+ const resolved = resolveReviewedTechnicalPlanInput(repoRoot, inputPath || undefined);
729
+ inputPath = resolved.inputPath;
730
+ const inputText = readTextFileOrEmpty(inputPath, repoRoot);
277
731
  const manifest = buildSpecGenerationManifest({
278
- inputPath: options.input,
732
+ inputPath,
279
733
  inputText,
280
734
  repoRoot,
281
735
  specSlug: options.specSlug,
282
736
  });
283
737
 
738
+ if (options.printPrompt) {
739
+ const report = {
740
+ task: 'plan',
741
+ phase,
742
+ manifest,
743
+ };
744
+ process.stdout.write('AI plan prompt-only\nPhase: spec\nNo provider prompt is used for spec generation; showing the local generation plan instead.\n');
745
+ process.stdout.write(formatSpecDryRunReport({ manifest, repoRoot }));
746
+ return report;
747
+ }
748
+
284
749
  if (options.dryRun) {
285
750
  const report = {
286
751
  task: 'plan',
@@ -292,7 +757,7 @@ async function runPlan(repoRoot, options = {}) {
292
757
  }
293
758
 
294
759
  const result = generateSpecArtifacts(repoRoot, {
295
- input: options.input,
760
+ input: inputPath,
296
761
  specSlug: options.specSlug,
297
762
  });
298
763
  process.stdout.write(formatSpecGenerationResult(result, repoRoot));
@@ -309,14 +774,39 @@ async function runPlan(repoRoot, options = {}) {
309
774
 
310
775
  assertPlannerPhaseReady(phase);
311
776
 
312
- const inputText = readTextFile(options.input, repoRoot);
777
+ let inputText = '';
778
+
779
+ if (options.revise === true) {
780
+ if (!inputPath) {
781
+ throw new Error(formatError(`missing feedback input file for ai revise phase '${phase}'`));
782
+ }
783
+ const feedbackText = readTextFile(inputPath, repoRoot);
784
+ inputText = buildRevisionInput({
785
+ phase,
786
+ feedbackPath: inputPath,
787
+ feedbackText,
788
+ repoRoot,
789
+ });
790
+ } else if (phase === 'technical-plan') {
791
+ const resolved = resolveApprovedPlannerInput(repoRoot, phase, inputPath || undefined);
792
+ inputPath = resolved.inputPath;
793
+ }
794
+
795
+ if (!inputPath) {
796
+ throw new Error(formatError(`missing input file for ai plan phase '${phase}'`));
797
+ }
798
+
799
+ if (!inputText) {
800
+ inputText = readTextFile(inputPath, repoRoot);
801
+ }
313
802
  const contextInfo = buildPlanContext({
314
803
  role,
315
804
  context,
316
805
  phase,
317
806
  inputText,
318
- inputPath: options.input,
807
+ inputPath,
319
808
  repoRoot,
809
+ revise: options.revise === true,
320
810
  });
321
811
  const prompt = contextInfo.prompt;
322
812
  let invocation;
@@ -344,6 +834,20 @@ async function runPlan(repoRoot, options = {}) {
344
834
  return report;
345
835
  }
346
836
 
837
+ if (options.printPrompt) {
838
+ const report = {
839
+ task: 'plan',
840
+ provider,
841
+ role,
842
+ contextPack: contextInfo.pack.packName,
843
+ phase,
844
+ invocation,
845
+ prompt,
846
+ };
847
+ process.stdout.write(formatPromptOnlyReport(report));
848
+ return report;
849
+ }
850
+
347
851
  let result;
348
852
  try {
349
853
  result = await (options.runProviderFn || runProvider)(provider, {
@@ -367,6 +871,17 @@ async function runPlan(repoRoot, options = {}) {
367
871
  throw annotateProviderError(result.error || new Error('provider run failed'), 'plan', phase);
368
872
  }
369
873
 
874
+ const draft = savePlannerDraft(repoRoot, phase, inputPath, getRedactedProviderText(result));
875
+ const lifecycleRun = ensureAiRun(repoRoot, {
876
+ command: `ai plan --phase ${phase}`,
877
+ input: inputPath,
878
+ runId: options.runId,
879
+ });
880
+ updateAiRunPhase(repoRoot, lifecycleRun.run_id, phase === 'acceptance' ? 'acceptance-draft' : 'technical-plan-draft', {
881
+ artifact: path.relative(repoRoot, draft.filePath).split(path.sep).join('/'),
882
+ command: `ai plan --phase ${phase}`,
883
+ });
884
+
370
885
  return {
371
886
  task: 'plan',
372
887
  provider,
@@ -378,6 +893,436 @@ async function runPlan(repoRoot, options = {}) {
378
893
  };
379
894
  }
380
895
 
896
+ async function runReviewPlan(repoRoot, options = {}) {
897
+ const role = 'planner';
898
+ const provider = resolveProviderForProfile(repoRoot, 'reviewer', options.provider, options.providerExplicit, DEFAULT_PLAN_PROVIDER);
899
+ const context = options.context || DEFAULT_PLAN_CONTEXT;
900
+ const timeoutMs = normalizeTimeout(options.timeout);
901
+ const resolved = resolveTechnicalPlanReviewInput(repoRoot, options.input || undefined);
902
+ const inputPath = resolved.inputPath;
903
+ const inputText = readTextFile(inputPath, repoRoot);
904
+ const pack = buildContextPackMetadata({
905
+ role,
906
+ packName: context,
907
+ repoRoot,
908
+ });
909
+ const built = buildPlanReviewPrompt({
910
+ pack,
911
+ inputText,
912
+ inputPath,
913
+ });
914
+ let invocation;
915
+
916
+ try {
917
+ invocation = buildProviderInvocation(provider, {
918
+ prompt: built.prompt,
919
+ cwd: repoRoot,
920
+ timeoutMs,
921
+ });
922
+ } catch (error) {
923
+ throw annotateProviderError(error, 'review-plan');
924
+ }
925
+
926
+ if (options.dryRun) {
927
+ const report = {
928
+ task: 'review-plan',
929
+ provider,
930
+ role: 'reviewer',
931
+ contextPack: pack.packName,
932
+ invocation,
933
+ promptSource: built.promptSource,
934
+ inputPath,
935
+ inputKind: resolved.kind,
936
+ inputVersion: resolved.version,
937
+ };
938
+ process.stdout.write(formatDryRunReport({
939
+ task: 'review-plan',
940
+ provider,
941
+ role: 'reviewer',
942
+ contextPack: pack.packName,
943
+ phase: 'plan-review',
944
+ invocation,
945
+ }));
946
+ process.stdout.write(`Prompt source: ${built.promptSource}\n`);
947
+ process.stdout.write(`Input file: ${inputPath}\n`);
948
+ process.stdout.write(`Input kind: ${resolved.kind}\n`);
949
+ if (resolved.version) {
950
+ process.stdout.write(`Input version: v${resolved.version}\n`);
951
+ }
952
+ return report;
953
+ }
954
+
955
+ if (options.printPrompt) {
956
+ const report = {
957
+ task: 'review-plan',
958
+ provider,
959
+ role: 'reviewer',
960
+ contextPack: pack.packName,
961
+ phase: 'plan-review',
962
+ invocation,
963
+ prompt: built.prompt,
964
+ promptSource: built.promptSource,
965
+ inputPath,
966
+ inputKind: resolved.kind,
967
+ inputVersion: resolved.version,
968
+ };
969
+ process.stdout.write(formatPromptOnlyReport(report));
970
+ return report;
971
+ }
972
+
973
+ let result;
974
+ try {
975
+ result = await (options.runProviderFn || runProvider)(provider, {
976
+ prompt: built.prompt,
977
+ cwd: repoRoot,
978
+ timeoutMs,
979
+ dryRun: false,
980
+ probe: options.probe,
981
+ spawn: options.spawn,
982
+ tempRoot: options.tempRoot,
983
+ tempFileName: options.tempFileName,
984
+ tempFilePrefix: options.tempFilePrefix,
985
+ });
986
+ } catch (error) {
987
+ throw annotateProviderError(error, 'review-plan');
988
+ }
989
+
990
+ writeProviderOutput(result);
991
+
992
+ if (!result.ok) {
993
+ throw annotateProviderError(result.error || new Error('provider run failed'), 'review-plan');
994
+ }
995
+
996
+ const saved = savePlanReview(repoRoot, {
997
+ contents: getRedactedProviderText(result),
998
+ inputPath,
999
+ inputKind: resolved.kind,
1000
+ inputVersion: resolved.version,
1001
+ });
1002
+ const relativePath = path.relative(repoRoot, saved.filePath).split(path.sep).join('/');
1003
+ process.stdout.write(`AI plan review saved\nArtifact: ${relativePath}\nPrompt source: ${PLAN_REVIEW_PROMPT_SOURCE}\n`);
1004
+
1005
+ return {
1006
+ task: 'review-plan',
1007
+ provider,
1008
+ role: 'reviewer',
1009
+ contextPack: pack.packName,
1010
+ inputPath,
1011
+ inputKind: resolved.kind,
1012
+ inputVersion: resolved.version,
1013
+ filePath: relativePath,
1014
+ invocation,
1015
+ result,
1016
+ };
1017
+ }
1018
+
1019
+ async function runRevise(repoRoot, options = {}) {
1020
+ const phase = normalizePlannerPhase(options.phase || DEFAULT_PLAN_PHASE);
1021
+ if (phase === 'spec') {
1022
+ throw new Error(formatError(`ai revise does not support phase '${phase}'`));
1023
+ }
1024
+
1025
+ const approval = readPhaseApproval(repoRoot, phase);
1026
+ if (approval.status !== 'draft' && approval.status !== 'stale') {
1027
+ throw new Error(formatError(`ai revise --phase ${phase} requires an existing draft; current status is ${approval.status}. Run \`npx create-quiver ai plan --phase ${phase} --input <file>\` first.`));
1028
+ }
1029
+
1030
+ return runPlan(repoRoot, {
1031
+ ...options,
1032
+ phase,
1033
+ revise: true,
1034
+ });
1035
+ }
1036
+
1037
+ async function runApprove(repoRoot, options = {}) {
1038
+ const phase = normalizePlannerPhase(options.phase || DEFAULT_PLAN_PHASE);
1039
+ if (phase === 'spec') {
1040
+ throw new Error(formatError(`ai approve does not support phase '${phase}'`));
1041
+ }
1042
+
1043
+ if (!options.version) {
1044
+ throw new Error(formatError(`ai approve --phase ${phase} requires --version <n>. Review drafts with \`npx create-quiver ai approvals\`.`));
1045
+ }
1046
+
1047
+ if (options.input) {
1048
+ throw new Error(formatError(`ai approve --phase ${phase} approves saved draft versions only. Use \`npx create-quiver ai revise --phase ${phase} --input ${options.input}\` to create a new draft first.`));
1049
+ }
1050
+
1051
+ if (phase === 'technical-plan') {
1052
+ const review = readPlanReview(repoRoot);
1053
+ if (review.status !== 'unapproved' && review.status !== 'reviewed') {
1054
+ throw new Error(formatError(`ai approve --phase technical-plan requires a production review for the current draft; current review status is ${review.status}. Run \`npx create-quiver ai review-plan\`.`));
1055
+ }
1056
+ }
1057
+
1058
+ const inputText = '';
1059
+
1060
+ if (options.dryRun) {
1061
+ process.stdout.write(formatApprovalDryRunResult({ phase, input: options.input, version: options.version }));
1062
+ return {
1063
+ task: 'approve',
1064
+ phase,
1065
+ input: options.input,
1066
+ version: options.version || null,
1067
+ dryRun: true,
1068
+ };
1069
+ }
1070
+
1071
+ const result = approvePlannerPhase(repoRoot, phase, options.input || '', inputText, {
1072
+ version: options.version || undefined,
1073
+ });
1074
+ const lifecycleRun = ensureAiRun(repoRoot, {
1075
+ command: `ai approve --phase ${phase}`,
1076
+ input: options.input || result.filePath,
1077
+ runId: options.runId,
1078
+ });
1079
+ recordAiRunApproval(repoRoot, lifecycleRun.run_id, {
1080
+ artifact: path.relative(repoRoot, result.filePath).split(path.sep).join('/'),
1081
+ phase,
1082
+ source_file: options.input || `draft version ${options.version}`,
1083
+ version: result.version || null,
1084
+ });
1085
+ updateAiRunPhase(repoRoot, lifecycleRun.run_id, phase === 'acceptance' ? 'acceptance-approved' : 'technical-plan-approved', {
1086
+ artifact: path.relative(repoRoot, result.filePath).split(path.sep).join('/'),
1087
+ command: `ai approve --phase ${phase}`,
1088
+ });
1089
+ process.stdout.write(formatApprovalResult({
1090
+ ...result,
1091
+ sourceFile: options.input || `draft version ${options.version}`,
1092
+ }, repoRoot));
1093
+
1094
+ return {
1095
+ task: 'approve',
1096
+ phase,
1097
+ input: options.input,
1098
+ filePath: path.relative(repoRoot, result.filePath).split(path.sep).join('/'),
1099
+ createdAt: result.createdAt,
1100
+ version: result.version || null,
1101
+ };
1102
+ }
1103
+
1104
+ async function runApprovalStatus(repoRoot) {
1105
+ const report = formatApprovalStatusReport(repoRoot);
1106
+ process.stdout.write(report);
1107
+ return {
1108
+ task: 'approval-status',
1109
+ report,
1110
+ };
1111
+ }
1112
+
1113
+ function runLifecycleStatus(repoRoot, options = {}) {
1114
+ const run = resolveAiRun(repoRoot, options.runId || '');
1115
+ const report = formatAiRunStatus(repoRoot, run);
1116
+ process.stdout.write(report);
1117
+ return {
1118
+ task: 'status',
1119
+ run,
1120
+ report,
1121
+ };
1122
+ }
1123
+
1124
+ function runLifecycleResume(repoRoot, options = {}) {
1125
+ const run = resolveAiRun(repoRoot, options.runId || '');
1126
+ const report = formatAiRunResume(repoRoot, run);
1127
+ process.stdout.write(report);
1128
+ return {
1129
+ task: 'resume',
1130
+ run,
1131
+ report,
1132
+ };
1133
+ }
1134
+
1135
+ function runInspect(repoRoot, options = {}) {
1136
+ const report = collectLifecycleExport(repoRoot, {
1137
+ includeCompleted: options.includeCompleted === true,
1138
+ });
1139
+ process.stdout.write(formatLifecycleInspect(report));
1140
+ return {
1141
+ task: 'inspect',
1142
+ report,
1143
+ };
1144
+ }
1145
+
1146
+ function runExport(repoRoot, options = {}) {
1147
+ const report = collectLifecycleExport(repoRoot, {
1148
+ includeCompleted: options.includeCompleted === true,
1149
+ });
1150
+ const format = String(options.format || 'json').trim().toLowerCase();
1151
+
1152
+ if (format === 'json') {
1153
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
1154
+ return {
1155
+ task: 'export',
1156
+ format,
1157
+ report,
1158
+ };
1159
+ }
1160
+
1161
+ if (format === 'markdown' || format === 'md') {
1162
+ process.stdout.write(formatLifecycleExportMarkdown(report));
1163
+ return {
1164
+ task: 'export',
1165
+ format: 'markdown',
1166
+ report,
1167
+ };
1168
+ }
1169
+
1170
+ throw new Error(formatError(`unsupported ai export format: ${format}. Supported formats: json, markdown`));
1171
+ }
1172
+
1173
+ function runSpecsList(repoRoot, options = {}) {
1174
+ const report = collectLifecycleExport(repoRoot, {
1175
+ includeCompleted: options.includeCompleted === true,
1176
+ });
1177
+ if (options.json === true) {
1178
+ process.stdout.write(`${JSON.stringify({ specs: report.specs }, null, 2)}\n`);
1179
+ } else {
1180
+ process.stdout.write(formatSpecsList(report));
1181
+ }
1182
+ return {
1183
+ task: 'specs',
1184
+ specs: report.specs,
1185
+ };
1186
+ }
1187
+
1188
+ function runSlicesList(repoRoot, options = {}) {
1189
+ const report = collectLifecycleExport(repoRoot, {
1190
+ includeCompleted: options.includeCompleted === true,
1191
+ });
1192
+ if (options.json === true) {
1193
+ process.stdout.write(`${JSON.stringify({ slices: report.slices }, null, 2)}\n`);
1194
+ } else {
1195
+ process.stdout.write(formatSlicesList(report));
1196
+ }
1197
+ return {
1198
+ task: 'slices',
1199
+ slices: report.slices,
1200
+ };
1201
+ }
1202
+
1203
+ function runTraceReport(repoRoot, options = {}) {
1204
+ const report = collectLifecycleExport(repoRoot, {
1205
+ includeCompleted: options.includeCompleted === true,
1206
+ });
1207
+ process.stdout.write(formatTraceReport(report));
1208
+ return {
1209
+ task: 'trace',
1210
+ report,
1211
+ };
1212
+ }
1213
+
1214
+ function runLifecycleRun(repoRoot, options = {}) {
1215
+ const command = String(options.command || '').trim().toLowerCase();
1216
+ if (command !== 'create') {
1217
+ throw new Error(formatError(`unsupported ai run subcommand: ${command}. Supported tasks: create`));
1218
+ }
1219
+ if (!options.input) {
1220
+ throw new Error(formatError('ai run create requires --input <requirements.md>'));
1221
+ }
1222
+ const run = createAiRun(repoRoot, {
1223
+ command: 'ai run create',
1224
+ input: options.input,
1225
+ runId: options.runId,
1226
+ specSlug: options.specSlug,
1227
+ });
1228
+ const report = formatAiRunStatus(repoRoot, run);
1229
+ process.stdout.write(report);
1230
+ return {
1231
+ task: 'run',
1232
+ command,
1233
+ run,
1234
+ report,
1235
+ };
1236
+ }
1237
+
1238
+ function formatAgentProfile(profile) {
1239
+ const lines = [
1240
+ `Role: ${profile.role}`,
1241
+ `Provider: ${profile.provider}`,
1242
+ `Model: ${profile.model || '(not set)'}`,
1243
+ `Label: ${profile.label || '(not set)'}`,
1244
+ `Context: ${profile.context || '(not set)'}`,
1245
+ `Updated: ${profile.updated_at}`,
1246
+ ];
1247
+ return `${lines.join('\n')}\n`;
1248
+ }
1249
+
1250
+ function formatAgentProfileList(profiles) {
1251
+ const lines = ['AI agent profiles'];
1252
+ for (const item of profiles) {
1253
+ if (!item.configured) {
1254
+ lines.push(`- ${item.role}: not configured`);
1255
+ continue;
1256
+ }
1257
+ const model = item.profile.model ? ` model=${item.profile.model}` : '';
1258
+ const label = item.profile.label ? ` label=${item.profile.label}` : '';
1259
+ lines.push(`- ${item.role}: provider=${item.profile.provider}${model}${label}`);
1260
+ }
1261
+ return `${lines.join('\n')}\n`;
1262
+ }
1263
+
1264
+ function runAgent(repoRoot, options = {}) {
1265
+ const command = String(options.command || '').trim().toLowerCase();
1266
+
1267
+ if (command === 'set') {
1268
+ if (!options.role) {
1269
+ throw new Error(formatError('missing agent role. Use: npx create-quiver ai agent set <planner|executor|reviewer|doctor> --provider <provider>'));
1270
+ }
1271
+ if (!options.provider) {
1272
+ throw new Error(formatError('ai agent set requires --provider. Supported providers: codex, claude, gemini.'));
1273
+ }
1274
+ const result = setAgentProfile(repoRoot, options.role, {
1275
+ context: options.context,
1276
+ label: options.label,
1277
+ model: options.model,
1278
+ provider: options.provider,
1279
+ });
1280
+ process.stdout.write('AI agent profile saved\n');
1281
+ process.stdout.write(formatAgentProfile(result.profile));
1282
+ process.stdout.write(`State: ${path.relative(repoRoot, result.filePath).split(path.sep).join('/')}\n`);
1283
+ return {
1284
+ task: 'agent',
1285
+ command,
1286
+ profile: result.profile,
1287
+ filePath: path.relative(repoRoot, result.filePath).split(path.sep).join('/'),
1288
+ };
1289
+ }
1290
+
1291
+ if (command === 'show') {
1292
+ if (!options.role) {
1293
+ throw new Error(formatError('missing agent role. Use: npx create-quiver ai agent show <planner|executor|reviewer|doctor>'));
1294
+ }
1295
+ const profile = getAgentProfile(repoRoot, options.role);
1296
+ if (!profile) {
1297
+ throw new Error(formatActionableError({
1298
+ failure: `agent profile '${options.role}' is not configured.`,
1299
+ impact: 'Quiver will fall back to default provider behavior and may use the wrong model/cost profile.',
1300
+ fix: `Configure the ${options.role} profile with a supported provider and optional model label.`,
1301
+ nextCommand: `npx create-quiver ai agent set ${options.role} --provider <provider> --model <label>`,
1302
+ }));
1303
+ }
1304
+ process.stdout.write(formatAgentProfile(profile));
1305
+ return {
1306
+ task: 'agent',
1307
+ command,
1308
+ profile,
1309
+ };
1310
+ }
1311
+
1312
+ if (command === 'list' || command === 'ls' || command === '') {
1313
+ const profiles = listAgentProfiles(repoRoot);
1314
+ process.stdout.write(formatAgentProfileList(profiles));
1315
+ process.stdout.write(`State: ${path.relative(repoRoot, agentProfilesPath(repoRoot)).split(path.sep).join('/')}\n`);
1316
+ return {
1317
+ task: 'agent',
1318
+ command: 'list',
1319
+ profiles,
1320
+ };
1321
+ }
1322
+
1323
+ throw new Error(formatError(`unsupported ai agent subcommand: ${command}. Supported tasks: set, list, show`));
1324
+ }
1325
+
381
1326
  async function runGitHubTask(repoRoot, options = {}, mode = 'pr') {
382
1327
  const dryRun = options.dryRun === true;
383
1328
  let report;
@@ -409,7 +1354,69 @@ async function runGitHubTask(repoRoot, options = {}, mode = 'pr') {
409
1354
  }
410
1355
 
411
1356
  async function runPr(repoRoot, options = {}) {
412
- return runGitHubTask(repoRoot, options, 'pr');
1357
+ const dryRun = options.dryRun === true;
1358
+ const create = options.create === true;
1359
+ let preflight;
1360
+
1361
+ try {
1362
+ preflight = await (options.preflightFn || preflightGitHubPr)(repoRoot, {
1363
+ remote: options.remote,
1364
+ sshHostAlias: options.sshHostAlias,
1365
+ identityFile: options.identityFile,
1366
+ gitFlowGuidePath: options.gitFlowGuidePath,
1367
+ ghCommand: options.ghCommand,
1368
+ ghProbe: options.ghProbe,
1369
+ ghAuthProbe: options.ghAuthProbe,
1370
+ ghProbeArgs: options.ghProbeArgs,
1371
+ ghAuthArgs: options.ghAuthArgs,
1372
+ blockedBranches: options.blockedBranches,
1373
+ });
1374
+ } catch (error) {
1375
+ throw annotateGitHubError(error, 'pr');
1376
+ }
1377
+
1378
+ let plan;
1379
+ try {
1380
+ plan = buildPrCreatePlan(repoRoot, preflight, {
1381
+ baseBranch: options.baseBranch,
1382
+ ghCommand: options.ghCommand,
1383
+ input: options.input,
1384
+ prBodyPath: options.prBodyPath,
1385
+ title: options.title,
1386
+ });
1387
+ } catch (error) {
1388
+ throw annotateGitHubError(error, 'pr');
1389
+ }
1390
+
1391
+ if (dryRun || !create) {
1392
+ process.stdout.write(formatPrCreateReport({ preflight, plan }, { dryRun, create }));
1393
+ return {
1394
+ task: 'pr',
1395
+ dryRun,
1396
+ create,
1397
+ preflight,
1398
+ plan,
1399
+ };
1400
+ }
1401
+
1402
+ let result;
1403
+ try {
1404
+ result = runGhPrCreate(plan, {
1405
+ ghCreateRunner: options.ghCreateRunner,
1406
+ });
1407
+ } catch (error) {
1408
+ throw annotateGitHubError(error, 'pr');
1409
+ }
1410
+
1411
+ process.stdout.write(formatPrCreateReport({ preflight, plan, result }, { dryRun: false, create: true }));
1412
+ return {
1413
+ task: 'pr',
1414
+ dryRun: false,
1415
+ create: true,
1416
+ preflight,
1417
+ plan,
1418
+ result,
1419
+ };
413
1420
  }
414
1421
 
415
1422
  async function runDoctor(repoRoot, options = {}) {
@@ -433,9 +1440,25 @@ module.exports = {
433
1440
  formatSpecDryRunReport,
434
1441
  normalizeTimeout,
435
1442
  readTextFile,
1443
+ runAgent,
436
1444
  runDoctor,
1445
+ runExecutePlan,
437
1446
  runExecuteSlice,
1447
+ runLifecycleResume,
1448
+ runLifecycleRun,
1449
+ runLifecycleStatus,
1450
+ runExport,
1451
+ runInspect,
1452
+ runPromptSlice,
1453
+ runApprove,
1454
+ runApprovalStatus,
1455
+ runPrepareContext,
1456
+ runReviewPlan,
1457
+ runRevise,
438
1458
  runPr,
1459
+ runSlicesList,
1460
+ runSpecsList,
1461
+ runTraceReport,
439
1462
  runOnboard,
440
1463
  runPlan,
441
1464
  writeProviderOutput,