create-quiver 0.10.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BACKLOG.md +16 -17
- package/CHANGELOG.md +78 -0
- package/README.md +208 -41
- package/README_FOR_AI.md +50 -24
- package/ROADMAP.md +34 -11
- package/docs/AI_CONTEXT.md.template +2 -0
- package/docs/AI_ONBOARDING_PROMPT.md.template +31 -18
- package/docs/COMMANDS.md.template +90 -16
- package/docs/CONTEXTO.md.template +2 -0
- package/docs/DECISIONS.md.template +1 -0
- package/docs/INDEX.md.template +20 -18
- package/docs/STATUS.md.template +6 -1
- package/docs/SUPPORT_MATRIX.md.template +2 -2
- package/docs/TROUBLESHOOTING.md.template +50 -0
- package/docs/WORKFLOW.md.template +27 -17
- package/package.json +27 -4
- package/package.template.json +13 -1
- package/scripts/init-docs.sh +11 -4
- package/scripts/package-quiver.sh +18 -2
- package/specs/quiver-v22-guided-ai-workflow/EVIDENCE_REPORT.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/EXECUTION_PLAN.md +88 -0
- package/specs/quiver-v22-guided-ai-workflow/SPEC.md +228 -0
- package/specs/quiver-v22-guided-ai-workflow/STATUS.md +42 -0
- package/specs/quiver-v22-guided-ai-workflow/pr.md +104 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/slice.json +55 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/slice.json +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/slice.json +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/slice.json +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/slice.json +54 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/slice.json +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/slice.json +55 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/slice.json +53 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/slice.json +59 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/slice.json +60 -0
- package/specs/quiver-v23-guided-flow-productization/EVIDENCE_REPORT.md +80 -0
- package/specs/quiver-v23-guided-flow-productization/EXECUTION_PLAN.md +80 -0
- package/specs/quiver-v23-guided-flow-productization/SPEC.md +203 -0
- package/specs/quiver-v23-guided-flow-productization/STATUS.md +39 -0
- package/specs/quiver-v23-guided-flow-productization/pr.md +119 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/EXECUTION_BRIEF.md +35 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/slice.json +56 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/slice.json +54 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/slice.json +59 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/slice.json +53 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/slice.json +54 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/EXECUTION_BRIEF.md +34 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/slice.json +57 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/slice.json +63 -0
- package/specs/quiver-v24-dx-onboarding-hardening/EVIDENCE_REPORT.md +55 -0
- package/specs/quiver-v24-dx-onboarding-hardening/EXECUTION_PLAN.md +43 -0
- package/specs/quiver-v24-dx-onboarding-hardening/SPEC.md +149 -0
- package/specs/quiver-v24-dx-onboarding-hardening/STATUS.md +31 -0
- package/specs/quiver-v24-dx-onboarding-hardening/pr.md +76 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/slice.json +55 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/slice.json +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/slice.json +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/slice.json +70 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/EXECUTION_BRIEF.md +49 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/slice.json +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/slice.json +60 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/slice.json +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/slice.json +54 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/EXECUTION_BRIEF.md +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/slice.json +59 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/slice.json +76 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/EVIDENCE_REPORT.md +293 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/EXECUTION_PLAN.md +58 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/SPEC.md +242 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/STATUS.md +35 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/pr.md +77 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/slice.json +56 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/slice.json +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/slice.json +53 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/slice.json +55 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/CLOSURE_BRIEF.md +39 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/slice.json +53 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/slice.json +52 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/CLOSURE_BRIEF.md +39 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/slice.json +56 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/slice.json +53 -0
- package/specs/quiver-v26-0121-smoke-hardening/EVIDENCE_REPORT.md +208 -0
- package/specs/quiver-v26-0121-smoke-hardening/EXECUTION_PLAN.md +57 -0
- package/specs/quiver-v26-0121-smoke-hardening/SPEC.md +137 -0
- package/specs/quiver-v26-0121-smoke-hardening/STATUS.md +32 -0
- package/specs/quiver-v26-0121-smoke-hardening/pr.md +96 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/slice.json +73 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/EXECUTION_BRIEF.md +51 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/slice.json +76 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/CLOSURE_BRIEF.md +37 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/slice.json +75 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/CLOSURE_BRIEF.md +37 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/slice.json +77 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/slice.json +77 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/slice.json +84 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/slice.json +82 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/EXECUTION_BRIEF.md +55 -0
- package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/slice.json +92 -0
- package/src/create-quiver/commands/ai.js +1060 -37
- package/src/create-quiver/commands/demo.js +22 -0
- package/src/create-quiver/commands/evidence.js +37 -0
- package/src/create-quiver/commands/flow.js +562 -0
- package/src/create-quiver/commands/graph.js +19 -4
- package/src/create-quiver/commands/next.js +28 -0
- package/src/create-quiver/commands/plan.js +9 -6
- package/src/create-quiver/commands/prepare.js +236 -0
- package/src/create-quiver/commands/spec.js +133 -0
- package/src/create-quiver/index.js +1010 -31
- package/src/create-quiver/lib/actionable-error.js +27 -0
- package/src/create-quiver/lib/agent-profiles.js +148 -0
- package/src/create-quiver/lib/ai/context-packs.js +16 -0
- package/src/create-quiver/lib/ai/execution-plan.js +377 -11
- package/src/create-quiver/lib/ai/executor.js +633 -24
- package/src/create-quiver/lib/ai/export-state.js +534 -0
- package/src/create-quiver/lib/ai/github.js +279 -0
- package/src/create-quiver/lib/ai/onboarding-template.js +578 -0
- package/src/create-quiver/lib/ai/plan-review.js +286 -0
- package/src/create-quiver/lib/ai/providers.js +5 -3
- package/src/create-quiver/lib/ai/run-state.js +414 -0
- package/src/create-quiver/lib/ai/safety.js +5 -0
- package/src/create-quiver/lib/ai/spec-generator.js +12 -0
- package/src/create-quiver/lib/ai/spec-templates.js +80 -11
- package/src/create-quiver/lib/approvals.js +369 -0
- package/src/create-quiver/lib/demo.js +832 -0
- package/src/create-quiver/lib/doctor.js +309 -0
- package/src/create-quiver/lib/evidence.js +115 -0
- package/src/create-quiver/lib/handoff.js +81 -12
- package/src/create-quiver/lib/init-docs.js +302 -17
- package/src/create-quiver/lib/init-layout.js +34 -1
- package/src/create-quiver/lib/json.js +53 -3
- package/src/create-quiver/lib/lifecycle.js +6 -0
- package/src/create-quiver/lib/package-safety.js +117 -0
- package/src/create-quiver/lib/readiness.js +103 -21
- package/src/create-quiver/lib/scope.js +50 -7
- package/src/create-quiver/lib/slice-graph.js +138 -37
- package/src/create-quiver/lib/slice.js +14 -9
- package/src/create-quiver/lib/spec-worktrees.js +363 -0
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { spawnSync } = require('child_process');
|
|
3
4
|
const { readAllSlices } = require('./slice-graph');
|
|
4
5
|
const { hasGeneratedProjectSpec, hasInitializedStateMetadata, readState } = require('./state');
|
|
5
6
|
const { worktreeList } = require('./git');
|
|
7
|
+
const {
|
|
8
|
+
buildQuiverConfig,
|
|
9
|
+
buildQuiverInternalGitignore,
|
|
10
|
+
resolveInitPackageScripts,
|
|
11
|
+
} = require('./init-layout');
|
|
6
12
|
|
|
7
13
|
const NEW_LAYOUT_REQUIRED_PATHS = [
|
|
8
14
|
'README.md',
|
|
@@ -26,6 +32,13 @@ const LEGACY_LAYOUT_PROBES = [
|
|
|
26
32
|
'docs/PROJECT_SCAN.json',
|
|
27
33
|
];
|
|
28
34
|
|
|
35
|
+
const ROOT_GITIGNORE_DEFAULTS = [
|
|
36
|
+
'node_modules/',
|
|
37
|
+
'.DS_Store',
|
|
38
|
+
'dist/',
|
|
39
|
+
'coverage/',
|
|
40
|
+
];
|
|
41
|
+
|
|
29
42
|
function readTextIfExists(filePath) {
|
|
30
43
|
if (!fs.existsSync(filePath)) {
|
|
31
44
|
return null;
|
|
@@ -34,6 +47,34 @@ function readTextIfExists(filePath) {
|
|
|
34
47
|
return fs.readFileSync(filePath, 'utf8');
|
|
35
48
|
}
|
|
36
49
|
|
|
50
|
+
function normalizeIgnorePattern(line) {
|
|
51
|
+
const trimmed = line.trim();
|
|
52
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
53
|
+
return trimmed;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return trimmed.replace(/\/+$/g, '');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function missingLineDefaults(existingText, defaults) {
|
|
60
|
+
const seen = new Set(
|
|
61
|
+
String(existingText || '')
|
|
62
|
+
.split(/\r?\n/)
|
|
63
|
+
.map(normalizeIgnorePattern)
|
|
64
|
+
.filter(Boolean),
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return defaults.filter((line) => !seen.has(normalizeIgnorePattern(line)));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function appendMissingLines(filePath, lines) {
|
|
71
|
+
const existingText = readTextIfExists(filePath) || '';
|
|
72
|
+
const trimmed = existingText.replace(/\s+$/g, '');
|
|
73
|
+
const prefix = trimmed.length > 0 ? `${trimmed}\n` : '';
|
|
74
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
75
|
+
fs.writeFileSync(filePath, `${prefix}${lines.join('\n')}\n`);
|
|
76
|
+
}
|
|
77
|
+
|
|
37
78
|
function countNonEmptyLines(text) {
|
|
38
79
|
return String(text || '')
|
|
39
80
|
.split(/\r?\n/)
|
|
@@ -210,6 +251,82 @@ function countStackInfoLeaks(projectRoot) {
|
|
|
210
251
|
return leaks;
|
|
211
252
|
}
|
|
212
253
|
|
|
254
|
+
function collectGeneratedMarkdownFiles(projectRoot) {
|
|
255
|
+
const files = [];
|
|
256
|
+
const rootFiles = ['README.md', 'AGENTS.md'];
|
|
257
|
+
|
|
258
|
+
for (const file of rootFiles) {
|
|
259
|
+
const absolutePath = path.join(projectRoot, file);
|
|
260
|
+
if (fs.existsSync(absolutePath)) {
|
|
261
|
+
files.push(absolutePath);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const docsDir = path.join(projectRoot, 'docs');
|
|
266
|
+
if (!fs.existsSync(docsDir)) {
|
|
267
|
+
return files;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const walk = (dirPath) => {
|
|
271
|
+
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
272
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
273
|
+
if (entry.isDirectory()) {
|
|
274
|
+
walk(fullPath);
|
|
275
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
276
|
+
files.push(fullPath);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
walk(docsDir);
|
|
282
|
+
|
|
283
|
+
return files;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function isExternalLink(target) {
|
|
287
|
+
return /^(?:[a-z][a-z0-9+.-]*:|#)/i.test(target);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function normalizeMarkdownLinkTarget(target) {
|
|
291
|
+
return target
|
|
292
|
+
.trim()
|
|
293
|
+
.replace(/^<|>$/g, '')
|
|
294
|
+
.split('#')[0]
|
|
295
|
+
.trim();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function collectMissingMarkdownLinks(projectRoot) {
|
|
299
|
+
const missing = [];
|
|
300
|
+
const linkPattern = /!?\[[^\]]*]\(([^)]+)\)/g;
|
|
301
|
+
|
|
302
|
+
for (const filePath of collectGeneratedMarkdownFiles(projectRoot)) {
|
|
303
|
+
const text = readTextIfExists(filePath);
|
|
304
|
+
if (!text) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
let match;
|
|
309
|
+
while ((match = linkPattern.exec(text)) !== null) {
|
|
310
|
+
const target = normalizeMarkdownLinkTarget(match[1]);
|
|
311
|
+
if (!target || isExternalLink(target)) {
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const resolved = path.resolve(path.dirname(filePath), target);
|
|
316
|
+
const relativeToRoot = path.relative(projectRoot, resolved);
|
|
317
|
+
if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (!fs.existsSync(resolved)) {
|
|
322
|
+
missing.push(`${normalizeRelativePath(projectRoot, filePath)} -> ${target}`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return missing;
|
|
328
|
+
}
|
|
329
|
+
|
|
213
330
|
function collectLayoutReport(projectRoot) {
|
|
214
331
|
const hasStateMetadata = hasInitializedStateMetadata(readState(projectRoot));
|
|
215
332
|
const realSlices = readAllSlices(projectRoot);
|
|
@@ -276,6 +393,116 @@ function collectLayoutReport(projectRoot) {
|
|
|
276
393
|
};
|
|
277
394
|
}
|
|
278
395
|
|
|
396
|
+
function buildDoctorFixPlan(projectRoot) {
|
|
397
|
+
const fixes = [];
|
|
398
|
+
const rootGitignorePath = path.join(projectRoot, '.gitignore');
|
|
399
|
+
const rootGitignoreText = readTextIfExists(rootGitignorePath) || '';
|
|
400
|
+
const missingRootGitignoreLines = missingLineDefaults(rootGitignoreText, ROOT_GITIGNORE_DEFAULTS);
|
|
401
|
+
if (!fs.existsSync(rootGitignorePath)) {
|
|
402
|
+
fixes.push({
|
|
403
|
+
type: 'append-lines',
|
|
404
|
+
path: '.gitignore',
|
|
405
|
+
description: 'Create root .gitignore with safe Quiver defaults.',
|
|
406
|
+
lines: ROOT_GITIGNORE_DEFAULTS,
|
|
407
|
+
});
|
|
408
|
+
} else if (missingRootGitignoreLines.length > 0) {
|
|
409
|
+
fixes.push({
|
|
410
|
+
type: 'append-lines',
|
|
411
|
+
path: '.gitignore',
|
|
412
|
+
description: `Merge missing root .gitignore defaults: ${missingRootGitignoreLines.join(', ')}.`,
|
|
413
|
+
lines: missingRootGitignoreLines,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const quiverGitignorePath = path.join(projectRoot, '.quiver', '.gitignore');
|
|
418
|
+
const quiverGitignoreText = readTextIfExists(quiverGitignorePath) || '';
|
|
419
|
+
const quiverDefaults = buildQuiverInternalGitignore().split(/\r?\n/).filter(Boolean);
|
|
420
|
+
const missingQuiverLines = missingLineDefaults(quiverGitignoreText, quiverDefaults);
|
|
421
|
+
if (!fs.existsSync(quiverGitignorePath)) {
|
|
422
|
+
fixes.push({
|
|
423
|
+
type: 'write-json-or-text',
|
|
424
|
+
path: '.quiver/.gitignore',
|
|
425
|
+
description: 'Create internal .quiver/.gitignore for local AI state.',
|
|
426
|
+
content: buildQuiverInternalGitignore(),
|
|
427
|
+
});
|
|
428
|
+
} else if (missingQuiverLines.length > 0) {
|
|
429
|
+
fixes.push({
|
|
430
|
+
type: 'append-lines',
|
|
431
|
+
path: '.quiver/.gitignore',
|
|
432
|
+
description: `Merge missing .quiver/.gitignore defaults: ${missingQuiverLines.join(', ')}.`,
|
|
433
|
+
lines: missingQuiverLines,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const configPath = path.join(projectRoot, '.quiver', 'config.json');
|
|
438
|
+
if (!fs.existsSync(configPath)) {
|
|
439
|
+
fixes.push({
|
|
440
|
+
type: 'write-json-or-text',
|
|
441
|
+
path: '.quiver/config.json',
|
|
442
|
+
description: 'Create missing Quiver config metadata.',
|
|
443
|
+
content: `${JSON.stringify(buildQuiverConfig(), null, 2)}\n`,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
448
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
449
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
450
|
+
const scripts = packageJson.scripts && typeof packageJson.scripts === 'object' ? packageJson.scripts : {};
|
|
451
|
+
const expectedScripts = resolveInitPackageScripts('default');
|
|
452
|
+
const missingScripts = Object.entries(expectedScripts)
|
|
453
|
+
.filter(([name]) => (name.startsWith('quiver:') || name === 'check-handoff') && typeof scripts[name] !== 'string');
|
|
454
|
+
|
|
455
|
+
if (missingScripts.length > 0) {
|
|
456
|
+
fixes.push({
|
|
457
|
+
type: 'merge-package-scripts',
|
|
458
|
+
path: 'package.json',
|
|
459
|
+
description: `Add missing package scripts: ${missingScripts.map(([name]) => name).join(', ')}.`,
|
|
460
|
+
scripts: Object.fromEntries(missingScripts),
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return fixes;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function applyDoctorFixPlan(projectRoot, fixes) {
|
|
469
|
+
for (const fix of fixes) {
|
|
470
|
+
const targetPath = path.join(projectRoot, fix.path);
|
|
471
|
+
if (fix.type === 'append-lines') {
|
|
472
|
+
appendMissingLines(targetPath, fix.lines);
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (fix.type === 'write-json-or-text') {
|
|
477
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
478
|
+
fs.writeFileSync(targetPath, fix.content);
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (fix.type === 'merge-package-scripts') {
|
|
483
|
+
const packageJson = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
484
|
+
packageJson.scripts = {
|
|
485
|
+
...(packageJson.scripts || {}),
|
|
486
|
+
...fix.scripts,
|
|
487
|
+
};
|
|
488
|
+
fs.writeFileSync(targetPath, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function formatDoctorFixPlan(fixes, { dryRun = false } = {}) {
|
|
494
|
+
const lines = [dryRun ? 'Quiver doctor fix dry-run' : 'Quiver doctor fix'];
|
|
495
|
+
if (fixes.length === 0) {
|
|
496
|
+
lines.push('- No safe fixes to apply.');
|
|
497
|
+
} else {
|
|
498
|
+
for (const fix of fixes) {
|
|
499
|
+
lines.push(`- ${dryRun ? 'Would update' : 'Updated'} ${fix.path}: ${fix.description}`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
lines.push('');
|
|
503
|
+
return lines.join('\n');
|
|
504
|
+
}
|
|
505
|
+
|
|
279
506
|
function collectDoctorReport(projectRoot) {
|
|
280
507
|
const layout = collectLayoutReport(projectRoot);
|
|
281
508
|
const warnings = collectDoctorWarnings(projectRoot);
|
|
@@ -286,6 +513,75 @@ function collectDoctorReport(projectRoot) {
|
|
|
286
513
|
};
|
|
287
514
|
}
|
|
288
515
|
|
|
516
|
+
function runEnvironmentProbe(command, args = [], options = {}) {
|
|
517
|
+
const runner = options.runner || spawnSync;
|
|
518
|
+
return runner(command, args, {
|
|
519
|
+
cwd: options.cwd,
|
|
520
|
+
encoding: 'utf8',
|
|
521
|
+
shell: false,
|
|
522
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
523
|
+
timeout: options.timeout || 3000,
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function probeOk(command, args, options = {}) {
|
|
528
|
+
const result = runEnvironmentProbe(command, args, options);
|
|
529
|
+
if (result && result.error && result.error.code === 'ENOENT') {
|
|
530
|
+
return {
|
|
531
|
+
ok: false,
|
|
532
|
+
reason: 'missing',
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
ok: Boolean(result && result.status === 0),
|
|
537
|
+
reason: result && result.error ? result.error.message : result && result.stderr ? String(result.stderr).trim() : '',
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function collectEnvironmentWarnings(projectRoot, options = {}) {
|
|
542
|
+
const warnings = [];
|
|
543
|
+
const cwd = projectRoot;
|
|
544
|
+
|
|
545
|
+
const checks = [
|
|
546
|
+
['node', ['--version'], 'Node.js is required to run create-quiver. Install Node 20+ and retry.'],
|
|
547
|
+
['npm', ['--version'], 'npm is required for generated npm scripts and package smokes. Install npm or use a Node distribution that includes it.'],
|
|
548
|
+
['git', ['--version'], 'git is required for specs, slices, worktrees, commits, and PR flow. Install git and retry.'],
|
|
549
|
+
];
|
|
550
|
+
|
|
551
|
+
for (const [command, args, message] of checks) {
|
|
552
|
+
const check = probeOk(command, args, { ...options, cwd });
|
|
553
|
+
if (!check.ok) {
|
|
554
|
+
warnings.push(`${command} check failed: ${message}`);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
const ghCheck = probeOk('gh', ['--version'], { ...options, cwd });
|
|
559
|
+
if (!ghCheck.ok) {
|
|
560
|
+
warnings.push('gh check failed: GitHub CLI is required for `ai pr` and `ai doctor`. macOS: brew install gh. Linux: use your distro package manager. Windows: winget install GitHub.cli.');
|
|
561
|
+
} else {
|
|
562
|
+
const authCheck = probeOk('gh', ['auth', 'status'], { ...options, cwd });
|
|
563
|
+
if (!authCheck.ok) {
|
|
564
|
+
warnings.push('gh auth check failed: run `gh auth login` before using `ai pr --create`.');
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (!process.env.SHELL && !process.env.ComSpec) {
|
|
569
|
+
warnings.push('shell check failed: no SHELL or ComSpec environment variable was detected.');
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (projectRoot.includes(' ')) {
|
|
573
|
+
warnings.push('path contains spaces: use quoted paths when copying manual commands.');
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
try {
|
|
577
|
+
fs.accessSync(projectRoot, fs.constants.W_OK);
|
|
578
|
+
} catch {
|
|
579
|
+
warnings.push('permission check failed: current user cannot write to the project root.');
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
return warnings;
|
|
583
|
+
}
|
|
584
|
+
|
|
289
585
|
function collectDoctorWarnings(projectRoot) {
|
|
290
586
|
const warnings = [];
|
|
291
587
|
|
|
@@ -316,11 +612,24 @@ function collectDoctorWarnings(projectRoot) {
|
|
|
316
612
|
warnings.push(`stack information appears outside docs/PROJECT_MAP.md: ${leakIssues.join(', ')}`);
|
|
317
613
|
}
|
|
318
614
|
|
|
615
|
+
const missingLinks = collectMissingMarkdownLinks(projectRoot);
|
|
616
|
+
for (const issue of missingLinks) {
|
|
617
|
+
warnings.push(`missing local docs link: ${issue}`);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
for (const issue of collectEnvironmentWarnings(projectRoot)) {
|
|
621
|
+
warnings.push(issue);
|
|
622
|
+
}
|
|
623
|
+
|
|
319
624
|
return warnings;
|
|
320
625
|
}
|
|
321
626
|
|
|
322
627
|
module.exports = {
|
|
628
|
+
applyDoctorFixPlan,
|
|
629
|
+
buildDoctorFixPlan,
|
|
323
630
|
collectDoctorReport,
|
|
631
|
+
collectEnvironmentWarnings,
|
|
324
632
|
collectDoctorWarnings,
|
|
325
633
|
collectLayoutReport,
|
|
634
|
+
formatDoctorFixPlan,
|
|
326
635
|
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { spawnSync } = require('node:child_process');
|
|
4
|
+
|
|
5
|
+
const DEFAULT_OUTPUT_LIMIT = 4000;
|
|
6
|
+
|
|
7
|
+
function redactSecrets(text) {
|
|
8
|
+
return String(text || '')
|
|
9
|
+
.replace(/(authorization:\s*bearer\s+)[^\s`'"]+/gi, '$1[REDACTED]')
|
|
10
|
+
.replace(/\b((?:api[_-]?key|token|secret|password|passwd|pwd)[A-Z0-9_-]*\s*[:=]\s*)[^\s`'"]+/gi, '$1[REDACTED]')
|
|
11
|
+
.replace(/\b(npm_[A-Za-z0-9]{20,})\b/g, '[REDACTED_NPM_TOKEN]');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function truncateText(text, maxLength = DEFAULT_OUTPUT_LIMIT) {
|
|
15
|
+
const value = String(text || '');
|
|
16
|
+
if (value.length <= maxLength) {
|
|
17
|
+
return {
|
|
18
|
+
text: value,
|
|
19
|
+
truncated: false,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
text: `${value.slice(0, maxLength)}\n[... truncated ${value.length - maxLength} chars ...]`,
|
|
25
|
+
truncated: true,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function quoteCommandPart(value) {
|
|
30
|
+
const part = String(value || '');
|
|
31
|
+
return /\s/.test(part) ? JSON.stringify(part) : part;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function formatCommand(commandArgs) {
|
|
35
|
+
return commandArgs.map(quoteCommandPart).join(' ');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function defaultEvidencePath(repoRoot, startedAt = new Date()) {
|
|
39
|
+
const stamp = startedAt.toISOString().replace(/[-:]/g, '').replace(/\.\d{3}Z$/, 'Z');
|
|
40
|
+
return path.join(repoRoot, '.quiver', 'evidence', `evidence-${stamp}.md`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function renderEvidenceMarkdown(record) {
|
|
44
|
+
return `# Quiver Evidence
|
|
45
|
+
|
|
46
|
+
- Command: \`${record.command}\`
|
|
47
|
+
- Exit code: ${record.exit_code}
|
|
48
|
+
- Duration ms: ${record.duration_ms}
|
|
49
|
+
- Started at: ${record.started_at}
|
|
50
|
+
- Finished at: ${record.finished_at}
|
|
51
|
+
- Output truncated: ${record.output_truncated ? 'yes' : 'no'}
|
|
52
|
+
|
|
53
|
+
## Stdout
|
|
54
|
+
|
|
55
|
+
\`\`\`\`text
|
|
56
|
+
${record.stdout || ''}
|
|
57
|
+
\`\`\`\`
|
|
58
|
+
|
|
59
|
+
## Stderr
|
|
60
|
+
|
|
61
|
+
\`\`\`\`text
|
|
62
|
+
${record.stderr || ''}
|
|
63
|
+
\`\`\`\`
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function runEvidenceCommand(repoRoot, commandArgs, options = {}) {
|
|
68
|
+
if (!Array.isArray(commandArgs) || commandArgs.length === 0) {
|
|
69
|
+
throw new Error('create-quiver: evidence run requires a command after --');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const startedAtDate = new Date();
|
|
73
|
+
const started = Date.now();
|
|
74
|
+
const result = (options.spawnSync || spawnSync)(commandArgs[0], commandArgs.slice(1), {
|
|
75
|
+
cwd: repoRoot,
|
|
76
|
+
encoding: 'utf8',
|
|
77
|
+
shell: false,
|
|
78
|
+
});
|
|
79
|
+
const finishedAtDate = new Date();
|
|
80
|
+
const duration = Date.now() - started;
|
|
81
|
+
const exitCode = typeof result.status === 'number' ? result.status : 1;
|
|
82
|
+
const stdout = truncateText(redactSecrets(result.stdout || ''), options.maxOutput || DEFAULT_OUTPUT_LIMIT);
|
|
83
|
+
const stderr = truncateText(redactSecrets(result.stderr || result.error?.message || ''), options.maxOutput || DEFAULT_OUTPUT_LIMIT);
|
|
84
|
+
const record = {
|
|
85
|
+
command: redactSecrets(formatCommand(commandArgs)),
|
|
86
|
+
duration_ms: duration,
|
|
87
|
+
exit_code: exitCode,
|
|
88
|
+
finished_at: finishedAtDate.toISOString(),
|
|
89
|
+
output_truncated: stdout.truncated || stderr.truncated,
|
|
90
|
+
stderr: stderr.text,
|
|
91
|
+
stdout: stdout.text,
|
|
92
|
+
started_at: startedAtDate.toISOString(),
|
|
93
|
+
};
|
|
94
|
+
const outputPath = options.outputPath
|
|
95
|
+
? path.resolve(repoRoot, options.outputPath)
|
|
96
|
+
: defaultEvidencePath(repoRoot, startedAtDate);
|
|
97
|
+
|
|
98
|
+
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
|
99
|
+
fs.writeFileSync(outputPath, renderEvidenceMarkdown(record));
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
exitCode,
|
|
103
|
+
outputPath,
|
|
104
|
+
record,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
module.exports = {
|
|
109
|
+
DEFAULT_OUTPUT_LIMIT,
|
|
110
|
+
defaultEvidencePath,
|
|
111
|
+
redactSecrets,
|
|
112
|
+
renderEvidenceMarkdown,
|
|
113
|
+
runEvidenceCommand,
|
|
114
|
+
truncateText,
|
|
115
|
+
};
|
|
@@ -10,6 +10,36 @@ const REQUIRED_HEADINGS = [
|
|
|
10
10
|
'## Constraints',
|
|
11
11
|
];
|
|
12
12
|
|
|
13
|
+
const EXECUTION_BRIEF_REQUIRED_HEADINGS = [
|
|
14
|
+
{
|
|
15
|
+
label: 'context',
|
|
16
|
+
alternatives: ['## Context', '## Contexto'],
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
label: 'objective',
|
|
20
|
+
alternatives: ['## Objective', '## Objetivo'],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
label: 'acceptance criteria',
|
|
24
|
+
alternatives: ['## Acceptance Criteria', '## Criterios de aceptacion', '## Criterios de aceptación'],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: 'completion checklist',
|
|
28
|
+
alternatives: ['## Completion Checklist', '## Checklist de finalizacion', '## Checklist de finalización'],
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const CLOSURE_BRIEF_REQUIRED_HEADINGS = [
|
|
33
|
+
{
|
|
34
|
+
label: 'summary',
|
|
35
|
+
alternatives: ['## Summary', '## Summary of Work', '## Resumen de lo realizado'],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
label: 'validation',
|
|
39
|
+
alternatives: ['## Validation', '## Validation Against Acceptance Criteria', '## Validacion contra criterios de aceptacion', '## Validación contra criterios de aceptación'],
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
|
|
13
43
|
const HANDOFF_TEMPLATE_PATH = path.resolve(__dirname, '..', '..', '..', 'specs', '[project-name]', 'HANDOFF.md.template');
|
|
14
44
|
|
|
15
45
|
function normalizePosixPath(filePath, pathLib = path) {
|
|
@@ -21,19 +51,36 @@ function resolveHandoffPath(repoRoot, handoffInput, pathLib = path) {
|
|
|
21
51
|
const relativePath = normalizePosixPath(pathLib.relative(repoRoot, absolutePath), pathLib);
|
|
22
52
|
|
|
23
53
|
if (relativePath.startsWith('..') || pathLib.isAbsolute(relativePath)) {
|
|
24
|
-
throw new Error(`create-quiver: handoff must live
|
|
54
|
+
throw new Error(`create-quiver: handoff or brief must live under specs/<spec-slug>/ (got ${normalizePosixPath(handoffInput, pathLib)})`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const handoffMatch = relativePath.match(/^(specs|specs-fix)\/([^/]+)\/HANDOFF\.md$/);
|
|
58
|
+
if (handoffMatch) {
|
|
59
|
+
return {
|
|
60
|
+
absolutePath,
|
|
61
|
+
relativePath,
|
|
62
|
+
specFamily: handoffMatch[1],
|
|
63
|
+
specSlug: handoffMatch[2],
|
|
64
|
+
kind: 'handoff',
|
|
65
|
+
label: 'Handoff',
|
|
66
|
+
};
|
|
25
67
|
}
|
|
26
68
|
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
|
|
69
|
+
const briefMatch = relativePath.match(/^(specs|specs-fix)\/([^/]+)\/slices\/([^/]+)\/(EXECUTION_BRIEF|CLOSURE_BRIEF)\.md$/);
|
|
70
|
+
if (briefMatch) {
|
|
71
|
+
const briefName = briefMatch[4];
|
|
72
|
+
return {
|
|
73
|
+
absolutePath,
|
|
74
|
+
relativePath,
|
|
75
|
+
specFamily: briefMatch[1],
|
|
76
|
+
specSlug: briefMatch[2],
|
|
77
|
+
sliceId: briefMatch[3],
|
|
78
|
+
kind: briefName === 'EXECUTION_BRIEF' ? 'execution-brief' : 'closure-brief',
|
|
79
|
+
label: briefName === 'EXECUTION_BRIEF' ? 'Execution brief' : 'Closure brief',
|
|
80
|
+
};
|
|
30
81
|
}
|
|
31
82
|
|
|
32
|
-
|
|
33
|
-
absolutePath,
|
|
34
|
-
relativePath,
|
|
35
|
-
specSlug: match[1],
|
|
36
|
-
};
|
|
83
|
+
throw new Error(`create-quiver: handoff or brief must live at specs/<spec-slug>/HANDOFF.md or specs/<spec-slug>/slices/<slice-id>/EXECUTION_BRIEF.md|CLOSURE_BRIEF.md (got ${relativePath})`);
|
|
37
84
|
}
|
|
38
85
|
|
|
39
86
|
function readHandoffSections(text) {
|
|
@@ -49,17 +96,36 @@ function validateHandoffSections(text) {
|
|
|
49
96
|
return REQUIRED_HEADINGS.filter((heading) => !sections.has(heading));
|
|
50
97
|
}
|
|
51
98
|
|
|
99
|
+
function normalizeHeading(heading) {
|
|
100
|
+
return String(heading || '')
|
|
101
|
+
.normalize('NFD')
|
|
102
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
103
|
+
.trim()
|
|
104
|
+
.toLowerCase();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function validateBriefSections(text, kind) {
|
|
108
|
+
const sections = new Set(readHandoffSections(text).map(normalizeHeading));
|
|
109
|
+
const requiredGroups = kind === 'closure-brief' ? CLOSURE_BRIEF_REQUIRED_HEADINGS : EXECUTION_BRIEF_REQUIRED_HEADINGS;
|
|
110
|
+
|
|
111
|
+
return requiredGroups
|
|
112
|
+
.filter((group) => !group.alternatives.some((heading) => sections.has(normalizeHeading(heading))))
|
|
113
|
+
.map((group) => group.label);
|
|
114
|
+
}
|
|
115
|
+
|
|
52
116
|
function checkHandoff(handoffInput, repoRoot = process.cwd()) {
|
|
53
117
|
const resolved = resolveHandoffPath(repoRoot, handoffInput);
|
|
54
118
|
|
|
55
119
|
if (!fs.existsSync(resolved.absolutePath)) {
|
|
56
|
-
throw new Error(`create-quiver: missing
|
|
120
|
+
throw new Error(`create-quiver: missing ${resolved.label.toLowerCase()} file: ${resolved.relativePath}`);
|
|
57
121
|
}
|
|
58
122
|
|
|
59
123
|
const text = fs.readFileSync(resolved.absolutePath, 'utf8');
|
|
60
|
-
const missingSections =
|
|
124
|
+
const missingSections = resolved.kind === 'handoff'
|
|
125
|
+
? validateHandoffSections(text)
|
|
126
|
+
: validateBriefSections(text, resolved.kind);
|
|
61
127
|
if (missingSections.length > 0) {
|
|
62
|
-
throw new Error(`create-quiver:
|
|
128
|
+
throw new Error(`create-quiver: ${resolved.label.toLowerCase()} is missing required sections: ${missingSections.join(', ')}`);
|
|
63
129
|
}
|
|
64
130
|
|
|
65
131
|
return resolved;
|
|
@@ -95,10 +161,13 @@ function scaffoldHandoff(specSlug, repoRoot = process.cwd()) {
|
|
|
95
161
|
}
|
|
96
162
|
|
|
97
163
|
module.exports = {
|
|
164
|
+
CLOSURE_BRIEF_REQUIRED_HEADINGS,
|
|
165
|
+
EXECUTION_BRIEF_REQUIRED_HEADINGS,
|
|
98
166
|
REQUIRED_HEADINGS,
|
|
99
167
|
checkHandoff,
|
|
100
168
|
readHandoffSections,
|
|
101
169
|
scaffoldHandoff,
|
|
102
170
|
resolveHandoffPath,
|
|
171
|
+
validateBriefSections,
|
|
103
172
|
validateHandoffSections,
|
|
104
173
|
};
|