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
@@ -0,0 +1,117 @@
1
+ const PACKAGE_PREFIX = 'package/';
2
+
3
+ const SAFETY_RULES = [
4
+ {
5
+ code: 'env-file',
6
+ match(relativePath) {
7
+ return /(^|\/)\.env($|[./])/.test(relativePath);
8
+ },
9
+ },
10
+ {
11
+ code: 'npm-credentials',
12
+ match(relativePath) {
13
+ return /(^|\/)\.npmrc$/.test(relativePath) || /(^|\/)\.npm(\/|$)/.test(relativePath);
14
+ },
15
+ },
16
+ {
17
+ code: 'ai-tool-state',
18
+ match(relativePath) {
19
+ return /(^|\/)\.(claude|codex|quiver)(\/|$)/.test(relativePath);
20
+ },
21
+ },
22
+ {
23
+ code: 'worktree-state',
24
+ match(relativePath) {
25
+ return /(^|\/)\.worktrees(\/|$)/.test(relativePath);
26
+ },
27
+ },
28
+ {
29
+ code: 'worktree-context',
30
+ match(relativePath) {
31
+ return /(^|\/)WORKTREE_CONTEXT\.md$/.test(relativePath);
32
+ },
33
+ },
34
+ {
35
+ code: 'demo-output',
36
+ match(relativePath) {
37
+ return relativePath === 'quiver-spec-viewer' || relativePath.startsWith('quiver-spec-viewer/');
38
+ },
39
+ },
40
+ ];
41
+
42
+ function normalizeTarballPath(inputPath) {
43
+ return String(inputPath || '')
44
+ .trim()
45
+ .replace(/\\/g, '/')
46
+ .replace(/^\.\//, '')
47
+ .replace(/\/{2,}/g, '/');
48
+ }
49
+
50
+ function stripPackagePrefix(inputPath) {
51
+ const normalizedPath = normalizeTarballPath(inputPath);
52
+
53
+ if (normalizedPath.startsWith(PACKAGE_PREFIX)) {
54
+ return normalizedPath.slice(PACKAGE_PREFIX.length);
55
+ }
56
+
57
+ return normalizedPath;
58
+ }
59
+
60
+ function collectPackageSafetyViolations(paths) {
61
+ const violations = [];
62
+ const seen = new Set();
63
+
64
+ for (const rawPath of paths || []) {
65
+ const normalizedPath = normalizeTarballPath(rawPath);
66
+ const relativePath = stripPackagePrefix(normalizedPath);
67
+
68
+ for (const rule of SAFETY_RULES) {
69
+ if (!rule.match(relativePath)) {
70
+ continue;
71
+ }
72
+
73
+ const key = `${rule.code}:${normalizedPath}`;
74
+ if (seen.has(key)) {
75
+ continue;
76
+ }
77
+
78
+ seen.add(key);
79
+ violations.push({
80
+ code: rule.code,
81
+ path: normalizedPath,
82
+ });
83
+ }
84
+ }
85
+
86
+ return violations;
87
+ }
88
+
89
+ function formatPackageSafetyViolations(violations) {
90
+ return violations
91
+ .map((violation) => `${violation.path} [${violation.code}]`)
92
+ .join(', ');
93
+ }
94
+
95
+ function assertPackageSafety(paths) {
96
+ const violations = collectPackageSafetyViolations(paths);
97
+
98
+ if (violations.length === 0) {
99
+ return {
100
+ ok: true,
101
+ violations,
102
+ };
103
+ }
104
+
105
+ const error = new Error(`PACKAGE_SAFETY_FAILED: unsafe tarball contents detected: ${formatPackageSafetyViolations(violations)}`);
106
+ error.code = 'PACKAGE_SAFETY_FAILED';
107
+ error.violations = violations;
108
+ throw error;
109
+ }
110
+
111
+ module.exports = {
112
+ assertPackageSafety,
113
+ collectPackageSafetyViolations,
114
+ formatPackageSafetyViolations,
115
+ normalizeTarballPath,
116
+ stripPackagePrefix,
117
+ };
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { catFileExists, currentBranch, hasLocalBranch, hasRemoteBranch, mergeBaseIsAncestor, revListCount, runGit, statusPorcelain, worktreeList } = require('./git');
4
4
  const { parseJsonWithComments } = require('./json');
5
- const { buildGraph, readAllSlices, SliceGraphError, topoSort } = require('./slice-graph');
5
+ const { buildGraph, normalizeDeclaredDependencies, readAllSlices, SliceGraphError, topoSort } = require('./slice-graph');
6
6
  const { resolveSliceContext, toAlias } = require('./slice');
7
7
 
8
8
  function ensureExists(filePath, message) {
@@ -56,7 +56,7 @@ function parseWorktrees(text) {
56
56
  return entries;
57
57
  }
58
58
 
59
- function collectOverlapWarnings(repoRoot, currentBranchName, currentFiles) {
59
+ function collectOverlapWarnings(repoRoot, currentBranchName, currentFiles, baseRef = 'origin/develop') {
60
60
  const sliceMap = new Map();
61
61
  walkSlices(path.join(repoRoot, 'specs'), sliceMap, repoRoot);
62
62
  walkSlices(path.join(repoRoot, 'specs-fix'), sliceMap, repoRoot);
@@ -79,7 +79,7 @@ function collectOverlapWarnings(repoRoot, currentBranchName, currentFiles) {
79
79
  }
80
80
 
81
81
  const dirty = statusPorcelain(worktreePath) !== '';
82
- const aheadCount = revListCount(worktreePath, 'origin/develop..HEAD');
82
+ const aheadCount = revListCount(worktreePath, `${baseRef}..HEAD`);
83
83
  const active = dirty || aheadCount > 0;
84
84
 
85
85
  if (!active) {
@@ -95,6 +95,76 @@ function collectOverlapWarnings(repoRoot, currentBranchName, currentFiles) {
95
95
  return warnings;
96
96
  }
97
97
 
98
+ function validateLocalSliceArtifacts(repoRoot, slice) {
99
+ const sliceDir = path.dirname(slice.sliceAbs);
100
+ for (const file of ['EXECUTION_BRIEF.md', 'CLOSURE_BRIEF.md']) {
101
+ ensureExists(path.join(sliceDir, file), `create-quiver: falta '${path.posix.join(path.dirname(slice.sliceRel), file)}'.`);
102
+ }
103
+ console.log('PASS: El slice local tiene EXECUTION_BRIEF.md y CLOSURE_BRIEF.md.');
104
+
105
+ if (!Array.isArray(slice.json.files) || slice.json.files.length === 0) {
106
+ throw new Error('create-quiver: slice.json debe declarar al menos un archivo en files para validacion local.');
107
+ }
108
+
109
+ const invalidFiles = slice.json.files.filter((file) => typeof file !== 'string' || file.trim().length === 0);
110
+ if (invalidFiles.length > 0) {
111
+ throw new Error('create-quiver: slice.json.files contiene entradas invalidas.');
112
+ }
113
+ console.log('PASS: slice.json declara archivos de alcance.');
114
+ }
115
+
116
+ function baseRecoveryMessage(remote, baseBranch) {
117
+ return `No se encontro la base '${baseBranch}' como rama local ni como '${remote}/${baseBranch}'. Para validacion estructural usa --local; para validacion contra otra base usa --base <branch>; o configura/fetchea el remoto '${remote}'.`;
118
+ }
119
+
120
+ function resolveReadinessRoot(localMode) {
121
+ try {
122
+ return runGit(['rev-parse', '--show-toplevel'], process.cwd());
123
+ } catch (error) {
124
+ if (localMode) {
125
+ return process.cwd();
126
+ }
127
+ throw error;
128
+ }
129
+ }
130
+
131
+ function validateSliceDocumentedOnBase(repoRoot, slice, options = {}) {
132
+ const gate = options.gate || 'execution';
133
+ const remote = options.remote || 'origin';
134
+ const baseBranch = options.baseBranch || slice.baseBranch || 'develop';
135
+ const remoteRef = `${remote}/${baseBranch}`;
136
+ const hasRemoteBase = hasRemoteBranch(repoRoot, baseBranch, remote);
137
+ const hasLocalBase = hasLocalBranch(repoRoot, baseBranch);
138
+
139
+ if (hasRemoteBase && catFileExists(repoRoot, `${remoteRef}:${slice.sliceRel}`)) {
140
+ console.log(`PASS: El slice ya existe en ${remoteRef} (PR base documental mergeado).`);
141
+ return remoteRef;
142
+ }
143
+
144
+ if (hasLocalBase && catFileExists(repoRoot, `${baseBranch}:${slice.sliceRel}`)) {
145
+ console.log(`PASS: El slice ya existe en ${baseBranch} local (modo sin remote).`);
146
+ return baseBranch;
147
+ }
148
+
149
+ if (!hasRemoteBase && !hasLocalBase) {
150
+ const guidance = baseRecoveryMessage(remote, baseBranch);
151
+ if (gate === 'validation') {
152
+ console.log(`WARN: ${guidance}`);
153
+ return null;
154
+ }
155
+
156
+ throw new Error(`create-quiver: ${guidance}`);
157
+ }
158
+
159
+ const expectedBase = hasRemoteBase ? remoteRef : baseBranch;
160
+ if (gate === 'validation') {
161
+ console.log(`WARN: El slice no existe todavia en ${expectedBase}. El PR base documental sigue pendiente de merge. Podes abrir el PR del slice igual si el humano mergea en orden.`);
162
+ return expectedBase;
163
+ }
164
+
165
+ throw new Error(`create-quiver: el slice no existe en ${expectedBase}. Mergea primero el PR base documental o usa --local para validar solo estructura local.`);
166
+ }
167
+
98
168
  function validateDeclaredDependencyContract(repoRoot, slice) {
99
169
  const declaredDependsOn = Array.isArray(slice.json.depends_on) ? slice.json.depends_on : null;
100
170
  const declaredParallelSafe = typeof slice.json.parallel_safe === 'string' ? slice.json.parallel_safe.trim() : '';
@@ -119,8 +189,12 @@ function validateDeclaredDependencyContract(repoRoot, slice) {
119
189
  throw new Error(`create-quiver: depends_on contiene referencias duplicadas en ${currentRef}.`);
120
190
  }
121
191
 
192
+ const normalizedDeclared = normalizeDeclaredDependencies(currentNode, declared);
193
+ if (normalizedDeclared.length !== new Set(normalizedDeclared).size) {
194
+ throw new Error(`create-quiver: depends_on contiene referencias duplicadas en ${currentRef}.`);
195
+ }
122
196
  const currentSet = new Set(currentNode.depends_on || []);
123
- for (const dep of declared) {
197
+ for (const dep of normalizedDeclared) {
124
198
  if (!currentSet.has(dep)) {
125
199
  throw new Error(`create-quiver: depends_on apunta a una referencia inexistente o invalida: ${dep}`);
126
200
  }
@@ -147,35 +221,43 @@ function validateDeclaredDependencyContract(repoRoot, slice) {
147
221
 
148
222
  function checkSliceReadiness(sliceInput, options = {}) {
149
223
  const gate = options.gate || 'execution';
224
+ const localMode = options.local === true;
150
225
  const strictOverlap = options.strictOverlap === true;
151
- const repoRoot = runGit(['rev-parse', '--show-toplevel'], process.cwd());
226
+ const remote = options.remote || 'origin';
227
+ const repoRoot = resolveReadinessRoot(localMode);
152
228
  const slice = resolveSliceContext(repoRoot, sliceInput);
229
+ const baseBranch = options.baseBranch || slice.baseBranch || 'develop';
153
230
 
154
231
  for (const specFile of ['SPEC.md', 'STATUS.md', 'EVIDENCE_REPORT.md']) {
155
232
  ensureExists(path.join(repoRoot, slice.specDirRel, specFile), `create-quiver: falta '${slice.specDirRel}/${specFile}'.`);
156
233
  }
157
234
  console.log('PASS: El spec local tiene SPEC.md, STATUS.md y EVIDENCE_REPORT.md.');
158
235
 
159
- if (catFileExists(repoRoot, `origin/develop:${slice.sliceRel}`)) {
160
- console.log('PASS: El slice ya existe en origin/develop (PR base documental mergeado).');
161
- } else if (catFileExists(repoRoot, `develop:${slice.sliceRel}`)) {
162
- console.log('PASS: El slice ya existe en develop local (modo sin origin).');
163
- } else if (gate === 'validation') {
164
- console.log('WARN: El slice no existe todavia en origin/develop. El PR base documental sigue pendiente de merge. Podes abrir el PR del slice igual — el humano mergea en orden.');
236
+ let baseRef = null;
237
+ if (localMode) {
238
+ validateLocalSliceArtifacts(repoRoot, slice);
239
+ console.log(`INFO: Modo local: se omite validacion de existencia del slice en ${remote}/${baseBranch} o ${baseBranch}.`);
240
+ console.log('INFO: Modo local: se omite validacion de overlap contra worktrees activos basada en rama remota/base.');
165
241
  } else {
166
- throw new Error('create-quiver: el slice no existe en origin/develop. Mergea primero el PR base documental.');
242
+ baseRef = validateSliceDocumentedOnBase(repoRoot, slice, {
243
+ baseBranch,
244
+ gate,
245
+ remote,
246
+ });
167
247
  }
168
248
 
169
- const overlapWarnings = collectOverlapWarnings(repoRoot, currentBranch(repoRoot), slice.files);
170
- if (overlapWarnings.length === 0) {
171
- console.log('PASS: No se detecto overlap con worktrees activos.');
172
- } else {
173
- for (const warning of overlapWarnings) {
174
- const [overlapBranch, overlapFiles] = warning.split('|');
175
- if (strictOverlap) {
176
- throw new Error(`create-quiver: Overlap con worktree activo '${overlapBranch}': ${overlapFiles}`);
249
+ if (!localMode) {
250
+ const overlapWarnings = collectOverlapWarnings(repoRoot, currentBranch(repoRoot), slice.files, baseRef || `${remote}/${baseBranch}`);
251
+ if (overlapWarnings.length === 0) {
252
+ console.log('PASS: No se detecto overlap con worktrees activos.');
253
+ } else {
254
+ for (const warning of overlapWarnings) {
255
+ const [overlapBranch, overlapFiles] = warning.split('|');
256
+ if (strictOverlap) {
257
+ throw new Error(`create-quiver: Overlap con worktree activo '${overlapBranch}': ${overlapFiles}`);
258
+ }
259
+ console.log(`WARN: Overlap con worktree activo '${overlapBranch}': ${overlapFiles}`);
177
260
  }
178
- console.log(`WARN: Overlap con worktree activo '${overlapBranch}': ${overlapFiles}`);
179
261
  }
180
262
  }
181
263
 
@@ -19,6 +19,48 @@ function normalizeScopePath(filePath) {
19
19
  return normalizeContextPath(filePath);
20
20
  }
21
21
 
22
+ function globToRegExp(pattern) {
23
+ const source = String(pattern || '')
24
+ .split('')
25
+ .map((char, index, chars) => {
26
+ if (char === '*') {
27
+ return chars[index + 1] === '*' ? '\0' : '[^/]*';
28
+ }
29
+ if (char === '\0') {
30
+ return '.*';
31
+ }
32
+ return /[\\^$+?.()|[\]{}]/.test(char) ? `\\${char}` : char;
33
+ })
34
+ .join('')
35
+ .replace(/\0\[\^\/\]\*/g, '.*');
36
+
37
+ return new RegExp(`^${source}$`);
38
+ }
39
+
40
+ function allowedPathMatches(filePath, allowedPath) {
41
+ const file = normalizeScopePath(filePath);
42
+ const allowed = normalizeScopePath(allowedPath);
43
+
44
+ if (!file || !allowed) {
45
+ return false;
46
+ }
47
+
48
+ if (file === allowed) {
49
+ return true;
50
+ }
51
+
52
+ if (allowed.endsWith('/**')) {
53
+ const prefix = allowed.slice(0, -3);
54
+ return file === prefix || file.startsWith(`${prefix}/`);
55
+ }
56
+
57
+ if (allowed.includes('*')) {
58
+ return globToRegExp(allowed).test(file);
59
+ }
60
+
61
+ return false;
62
+ }
63
+
22
64
  function parseStatusPorcelain(text) {
23
65
  if (!text) {
24
66
  return [];
@@ -74,30 +116,30 @@ function diffWorktreeSnapshots(beforeSnapshot, afterSnapshot) {
74
116
  }
75
117
 
76
118
  function validateScopeSnapshot({ allowedFiles = [], beforeSnapshot, afterSnapshot, strict = true } = {}) {
77
- const normalizedAllowedFiles = new Set(
119
+ const normalizedAllowedFiles = Array.from(new Set(
78
120
  Array.isArray(allowedFiles)
79
121
  ? allowedFiles.map(normalizeScopePath).filter(Boolean)
80
122
  : [],
81
- );
123
+ ));
82
124
  const changedFiles = diffWorktreeSnapshots(beforeSnapshot, afterSnapshot);
83
- const outOfScopeFiles = changedFiles.filter((file) => !normalizedAllowedFiles.has(file));
125
+ const outOfScopeFiles = changedFiles.filter((file) => !normalizedAllowedFiles.some((allowedFile) => allowedPathMatches(file, allowedFile)));
84
126
 
85
127
  if (outOfScopeFiles.length === 0) {
86
128
  return {
87
129
  ok: true,
88
130
  changedFiles,
89
131
  outOfScopeFiles,
90
- allowedFiles: Array.from(normalizedAllowedFiles),
132
+ allowedFiles: normalizedAllowedFiles,
91
133
  beforeSnapshot,
92
134
  afterSnapshot,
93
135
  };
94
136
  }
95
137
 
96
138
  const message = formatError(
97
- `scope violation detected: changed files outside slice.json.files: ${outOfScopeFiles.join(', ')}`,
139
+ `scope violation detected: changed files outside declared slice scope: ${outOfScopeFiles.join(', ')}`,
98
140
  );
99
141
  const error = new ScopeValidationError('SCOPE_VIOLATION', message, {
100
- allowedFiles: Array.from(normalizedAllowedFiles),
142
+ allowedFiles: normalizedAllowedFiles,
101
143
  beforeSnapshot,
102
144
  afterSnapshot,
103
145
  changedFiles,
@@ -112,7 +154,7 @@ function validateScopeSnapshot({ allowedFiles = [], beforeSnapshot, afterSnapsho
112
154
  ok: false,
113
155
  changedFiles,
114
156
  outOfScopeFiles,
115
- allowedFiles: Array.from(normalizedAllowedFiles),
157
+ allowedFiles: normalizedAllowedFiles,
116
158
  beforeSnapshot,
117
159
  afterSnapshot,
118
160
  error,
@@ -121,6 +163,7 @@ function validateScopeSnapshot({ allowedFiles = [], beforeSnapshot, afterSnapsho
121
163
 
122
164
  module.exports = {
123
165
  ScopeValidationError,
166
+ allowedPathMatches,
124
167
  captureWorktreeSnapshot,
125
168
  diffWorktreeSnapshots,
126
169
  checkScope,
@@ -66,6 +66,15 @@ function sortFileList(files) {
66
66
  return Array.from(new Set((Array.isArray(files) ? files : []).map((file) => String(file)).filter(Boolean))).sort((a, b) => a.localeCompare(b));
67
67
  }
68
68
 
69
+ function resolveWriteScope(json) {
70
+ const allowedWritePaths = sortFileList(json?.allowed_write_paths);
71
+ if (allowedWritePaths.length > 0) {
72
+ return allowedWritePaths;
73
+ }
74
+
75
+ return sortFileList(json?.files);
76
+ }
77
+
69
78
  function normalizeDependencyRef(slice, dependency) {
70
79
  const dep = String(dependency || '').trim();
71
80
  if (!dep) {
@@ -95,6 +104,61 @@ function normalizeDependencyRef(slice, dependency) {
95
104
  return `${slice.specSlug}/${dep}`;
96
105
  }
97
106
 
107
+ function readSliceFile(rootDir, rootName, specSlug, sliceDirName) {
108
+ const sliceDir = path.join(rootDir, rootName, specSlug, 'slices', sliceDirName);
109
+ const slicePath = path.join(sliceDir, 'slice.json');
110
+ if (!fs.existsSync(slicePath)) {
111
+ return null;
112
+ }
113
+
114
+ const json = parseJsonWithComments(fs.readFileSync(slicePath, 'utf8'));
115
+ const sliceId = String(json.slice_id || sliceDirName).trim();
116
+ const ref = `${specSlug}/${sliceId}`;
117
+ return {
118
+ ref,
119
+ specFamily: rootName,
120
+ specSlug,
121
+ sliceId,
122
+ slicePath,
123
+ sliceDir,
124
+ files: resolveWriteScope(json),
125
+ expected_read_paths: sortFileList(json.expected_read_paths),
126
+ allowed_write_paths: sortFileList(json.allowed_write_paths),
127
+ validation_hints: sortFileList(json.validation_hints),
128
+ dependencies: Array.isArray(json.dependencies) ? json.dependencies.map((item) => String(item).trim()).filter(Boolean) : [],
129
+ depends_on: Array.isArray(json.depends_on) ? json.depends_on.map((item) => String(item).trim()).filter(Boolean) : [],
130
+ parallel_safe: typeof json.parallel_safe === 'string' ? json.parallel_safe : null,
131
+ parallel_safe_reason: typeof json.parallel_safe_reason === 'string' ? json.parallel_safe_reason : null,
132
+ status: typeof json.status === 'string' ? json.status : 'draft',
133
+ ticket: typeof json.ticket === 'string' ? json.ticket : '',
134
+ title: typeof json.title === 'string' ? json.title : sliceId,
135
+ json,
136
+ };
137
+ }
138
+
139
+ function readSpecSlices(rootDir, rootName, specSlug) {
140
+ const slicesDir = path.join(rootDir, rootName, specSlug, 'slices');
141
+ if (!fs.existsSync(slicesDir)) {
142
+ return [];
143
+ }
144
+
145
+ const slices = [];
146
+
147
+ for (const sliceEntry of fs.readdirSync(slicesDir, { withFileTypes: true })) {
148
+ if (!sliceEntry.isDirectory() || isPlaceholderSliceDir(sliceEntry.name)) {
149
+ continue;
150
+ }
151
+
152
+ const slice = readSliceFile(rootDir, rootName, specSlug, sliceEntry.name);
153
+ if (slice) {
154
+ slices.push(slice);
155
+ }
156
+ }
157
+
158
+ slices.sort((left, right) => compareSliceRefs(left.ref, right.ref));
159
+ return slices;
160
+ }
161
+
98
162
  function readAllSlices(rootDir) {
99
163
  const roots = ['specs', 'specs-fix'];
100
164
  const slices = [];
@@ -110,43 +174,7 @@ function readAllSlices(rootDir) {
110
174
  continue;
111
175
  }
112
176
 
113
- const specSlug = specEntry.name;
114
- const slicesDir = path.join(rootPath, specSlug, 'slices');
115
- if (!fs.existsSync(slicesDir)) {
116
- continue;
117
- }
118
-
119
- for (const sliceEntry of fs.readdirSync(slicesDir, { withFileTypes: true })) {
120
- if (!sliceEntry.isDirectory() || isPlaceholderSliceDir(sliceEntry.name)) {
121
- continue;
122
- }
123
-
124
- const sliceDir = path.join(slicesDir, sliceEntry.name);
125
- const slicePath = path.join(sliceDir, 'slice.json');
126
- if (!fs.existsSync(slicePath)) {
127
- continue;
128
- }
129
-
130
- const json = parseJsonWithComments(fs.readFileSync(slicePath, 'utf8'));
131
- const sliceId = String(json.slice_id || sliceEntry.name).trim();
132
- const ref = `${specSlug}/${sliceId}`;
133
- slices.push({
134
- ref,
135
- specFamily: rootName,
136
- specSlug,
137
- sliceId,
138
- slicePath,
139
- sliceDir,
140
- files: sortFileList(json.files),
141
- dependencies: Array.isArray(json.dependencies) ? json.dependencies.map((item) => String(item).trim()).filter(Boolean) : [],
142
- depends_on: Array.isArray(json.depends_on) ? json.depends_on.map((item) => String(item).trim()).filter(Boolean) : [],
143
- parallel_safe: typeof json.parallel_safe === 'string' ? json.parallel_safe : null,
144
- parallel_safe_reason: typeof json.parallel_safe_reason === 'string' ? json.parallel_safe_reason : null,
145
- status: typeof json.status === 'string' ? json.status : 'draft',
146
- title: typeof json.title === 'string' ? json.title : sliceId,
147
- json,
148
- });
149
- }
177
+ slices.push(...readSpecSlices(rootDir, rootName, specEntry.name));
150
178
  }
151
179
  }
152
180
 
@@ -170,6 +198,75 @@ function declaredDependenciesForSlice(slice) {
170
198
  return null;
171
199
  }
172
200
 
201
+ function readSliceByRef(rootDir, ref) {
202
+ const value = String(ref || '').trim();
203
+ const slashIndex = value.indexOf('/');
204
+ if (slashIndex === -1) {
205
+ return null;
206
+ }
207
+
208
+ const specSlug = value.slice(0, slashIndex);
209
+ const sliceId = value.slice(slashIndex + 1);
210
+ if (!specSlug || !sliceId) {
211
+ return null;
212
+ }
213
+
214
+ for (const rootName of ['specs', 'specs-fix']) {
215
+ const direct = readSliceFile(rootDir, rootName, specSlug, sliceId);
216
+ if (direct) {
217
+ return direct;
218
+ }
219
+
220
+ for (const slice of readSpecSlices(rootDir, rootName, specSlug)) {
221
+ if (slice.ref === value) {
222
+ return slice;
223
+ }
224
+ }
225
+ }
226
+
227
+ return null;
228
+ }
229
+
230
+ function readSlicesForSpec(rootDir, specSlug) {
231
+ const targetSpec = String(specSlug || '').trim();
232
+ if (!targetSpec) {
233
+ return readAllSlices(rootDir);
234
+ }
235
+
236
+ const byRef = new Map();
237
+ const queue = [];
238
+
239
+ function addSlice(slice) {
240
+ if (!slice || byRef.has(slice.ref)) {
241
+ return;
242
+ }
243
+ byRef.set(slice.ref, slice);
244
+ queue.push(slice);
245
+ }
246
+
247
+ for (const rootName of ['specs', 'specs-fix']) {
248
+ for (const slice of readSpecSlices(rootDir, rootName, targetSpec)) {
249
+ addSlice(slice);
250
+ }
251
+ }
252
+
253
+ while (queue.length > 0) {
254
+ const slice = queue.shift();
255
+ for (const dep of declaredDependenciesForSlice(slice) || []) {
256
+ if (byRef.has(dep)) {
257
+ continue;
258
+ }
259
+
260
+ const dependencySlice = readSliceByRef(rootDir, dep);
261
+ if (dependencySlice) {
262
+ addSlice(dependencySlice);
263
+ }
264
+ }
265
+ }
266
+
267
+ return Array.from(byRef.values()).sort((left, right) => compareSliceRefs(left.ref, right.ref));
268
+ }
269
+
173
270
  function inferDependencies(slices) {
174
271
  const bySpec = new Map();
175
272
  const normalized = slices.map((slice) => ({
@@ -453,7 +550,11 @@ module.exports = {
453
550
  detectFileConflicts,
454
551
  inferDependencies,
455
552
  isFoundationSliceId,
553
+ normalizeDeclaredDependencies,
554
+ normalizeDependencyRef,
456
555
  readAllSlices,
556
+ readSlicesForSpec,
457
557
  naturalNumberFromSliceId,
558
+ resolveWriteScope,
458
559
  topoSort,
459
560
  };
@@ -42,14 +42,18 @@ function readSliceMeta(slicePath) {
42
42
  const branchName = typeof git.branch_name === 'string' ? git.branch_name.trim() : '';
43
43
  const sliceId = typeof json.slice_id === 'string' ? json.slice_id.trim() : '';
44
44
  const status = String(json.status || 'draft').trim() || 'draft';
45
+ const allowedWritePaths = Array.isArray(json.allowed_write_paths) ? json.allowed_write_paths.map((item) => String(item)) : [];
46
+ const legacyFiles = Array.isArray(json.files) ? json.files.map((item) => String(item)) : [];
45
47
 
46
48
  return {
47
49
  acceptance: Array.isArray(json.acceptance) ? json.acceptance : [],
50
+ allowedWritePaths,
48
51
  baseBranch,
49
52
  branchName,
50
53
  branchSlug,
51
54
  branchType,
52
- files: Array.isArray(json.files) ? json.files : [],
55
+ expectedReadPaths: Array.isArray(json.expected_read_paths) ? json.expected_read_paths.map((item) => String(item)) : [],
56
+ files: allowedWritePaths.length > 0 ? allowedWritePaths : legacyFiles,
53
57
  git,
54
58
  isBaseline: sliceId.startsWith('slice-00'),
55
59
  json,
@@ -60,6 +64,7 @@ function readSliceMeta(slicePath) {
60
64
  status,
61
65
  tests: Array.isArray(json.tests) ? json.tests : [],
62
66
  ticket,
67
+ validationHints: Array.isArray(json.validation_hints) ? json.validation_hints.map((item) => String(item)) : [],
63
68
  };
64
69
  }
65
70
 
@@ -74,19 +79,19 @@ function validateSliceMetaForStart(slice) {
74
79
  throw new Error('create-quiver: el bloque "git" debe incluir "branch_type", "base_branch", "branch_slug" y "branch_name".');
75
80
  }
76
81
 
77
- const expectedBaseByType = {
78
- feature: 'develop',
79
- bugfix: 'develop',
80
- hotfix: 'main',
82
+ const allowedBaseByType = {
83
+ feature: ['main', 'develop'],
84
+ bugfix: ['main', 'develop'],
85
+ hotfix: ['main'],
81
86
  };
82
87
 
83
- if (!expectedBaseByType[slice.branchType]) {
88
+ if (!allowedBaseByType[slice.branchType]) {
84
89
  throw new Error(`create-quiver: git.branch_type invalido: "${slice.branchType}". Usa "feature", "bugfix" o "hotfix".`);
85
90
  }
86
91
 
87
- const expectedBaseBranch = expectedBaseByType[slice.branchType];
88
- if (slice.baseBranch !== expectedBaseBranch) {
89
- throw new Error(`create-quiver: git.base_branch invalido para ${slice.branchType}. Esperado: "${expectedBaseBranch}".`);
92
+ const allowedBaseBranches = allowedBaseByType[slice.branchType];
93
+ if (!allowedBaseBranches.includes(slice.baseBranch)) {
94
+ throw new Error(`create-quiver: git.base_branch invalido para ${slice.branchType}. Usa "${allowedBaseBranches.join('" o "')}".`);
90
95
  }
91
96
 
92
97
  const expectedBranchName = `${slice.branchType}/${slice.ticket}-${slice.branchSlug}`;