create-quiver 0.9.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BACKLOG.md +16 -17
- package/CHANGELOG.md +34 -0
- package/README.md +419 -330
- package/README_FOR_AI.md +93 -56
- package/ROADMAP.md +22 -11
- package/docs/AI_CONTEXT.md.template +2 -0
- package/docs/AI_ONBOARDING_PROMPT.md.template +36 -19
- package/docs/COMMANDS.md.template +73 -1
- package/docs/CONTEXTO.md.template +2 -0
- package/docs/DECISIONS.md.template +1 -0
- package/docs/GITFLOW_PR_GUIDE.md.template +11 -0
- package/docs/INDEX.md.template +20 -18
- package/docs/STANDARD.md.template +1 -1
- package/docs/STATUS.md.template +1 -0
- package/docs/SUPPORT_MATRIX.md.template +6 -2
- package/docs/TROUBLESHOOTING.md.template +79 -1
- package/docs/WORKFLOW.md.template +26 -18
- package/package.json +24 -2
- package/package.template.json +24 -7
- package/scripts/check-pr-readiness.sh +1 -1
- package/scripts/check-scope.sh +0 -1
- package/scripts/check-slice-readiness.sh +3 -4
- package/scripts/init-docs.sh +53 -6
- package/scripts/package-quiver.sh +18 -2
- package/specs/quiver-v20-ai-cli-orchestration/EVIDENCE_REPORT.md +23 -0
- package/specs/quiver-v20-ai-cli-orchestration/EXECUTION_PLAN.md +57 -0
- package/specs/quiver-v20-ai-cli-orchestration/SPEC.md +202 -0
- package/specs/quiver-v20-ai-cli-orchestration/STATUS.md +35 -0
- package/specs/quiver-v20-ai-cli-orchestration/pr.md +100 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-00-spec-foundation/slice.json +54 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/CLOSURE_BRIEF.md +39 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-01-ai-provider-runner/slice.json +55 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/CLOSURE_BRIEF.md +40 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-02-context-packs-token-budget/slice.json +54 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/EXECUTION_BRIEF.md +62 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-03-ai-phase-gated-planner/slice.json +62 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-04-spec-slice-handoff-pr-generation/slice.json +59 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-05-execution-plan-parallel-worktrees/slice.json +59 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/EXECUTION_BRIEF.md +64 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-06-ai-execute-slice-scope-enforcement/slice.json +65 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/EXECUTION_BRIEF.md +66 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-07-github-pr-preflight/slice.json +63 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/EXECUTION_BRIEF.md +64 -0
- package/specs/quiver-v20-ai-cli-orchestration/slices/slice-08-docs-smokes-release-readiness/slice.json +77 -0
- package/specs/quiver-v21-ai-first-layout/EVIDENCE_REPORT.md +31 -0
- package/specs/quiver-v21-ai-first-layout/EXECUTION_PLAN.md +185 -0
- package/specs/quiver-v21-ai-first-layout/SPEC.md +212 -0
- package/specs/quiver-v21-ai-first-layout/STATUS.md +37 -0
- package/specs/quiver-v21-ai-first-layout/pr.md +110 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +63 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-00-spec-foundation/slice.json +45 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-01-init-profiles-dry-run/slice.json +57 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-02-internal-layout-template-resolver/slice.json +58 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-03-generation-profiles-visible-contract/slice.json +64 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-04-analyze-scan-relocation/slice.json +64 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/EXECUTION_BRIEF.md +60 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-05-empty-specs-layout-doctor/slice.json +65 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/EXECUTION_BRIEF.md +62 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-06-legacy-migration-optional-assets/slice.json +66 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-07-docs-guidance-alignment/slice.json +67 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/EXECUTION_BRIEF.md +66 -0
- package/specs/quiver-v21-ai-first-layout/slices/slice-08-smokes-release-readiness/slice.json +62 -0
- package/specs/quiver-v22-guided-ai-workflow/EVIDENCE_REPORT.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/EXECUTION_PLAN.md +88 -0
- package/specs/quiver-v22-guided-ai-workflow/SPEC.md +228 -0
- package/specs/quiver-v22-guided-ai-workflow/STATUS.md +42 -0
- package/specs/quiver-v22-guided-ai-workflow/pr.md +104 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +35 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-01-docs-source-of-truth-sync/slice.json +55 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/EXECUTION_BRIEF.md +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-02-prepare-command-diagnostics/slice.json +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-03-context-doc-refresh/slice.json +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-04-planner-approval-state/slice.json +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/EXECUTION_BRIEF.md +56 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-05-spec-worktree-lifecycle/slice.json +54 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-06-executor-commit-recovery/slice.json +57 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-07-execution-waves-delegation/slice.json +55 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-08-pr-create-gh-ssh/slice.json +53 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/EXECUTION_BRIEF.md +59 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-09-post-merge-cleanup-release-safety/slice.json +59 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +58 -0
- package/specs/quiver-v22-guided-ai-workflow/slices/slice-10-docs-smokes-release-readiness/slice.json +60 -0
- package/specs/quiver-v23-guided-flow-productization/EVIDENCE_REPORT.md +80 -0
- package/specs/quiver-v23-guided-flow-productization/EXECUTION_PLAN.md +80 -0
- package/specs/quiver-v23-guided-flow-productization/SPEC.md +203 -0
- package/specs/quiver-v23-guided-flow-productization/STATUS.md +39 -0
- package/specs/quiver-v23-guided-flow-productization/pr.md +119 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +61 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/EXECUTION_BRIEF.md +35 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-01-short-command-and-flow-entrypoint/slice.json +56 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-02-flow-status-wizard/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-03-agent-profiles/slice.json +54 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-04-context-preparation-onboarding/slice.json +59 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/EXECUTION_BRIEF.md +29 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-05-planner-iteration-history/slice.json +53 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-06-production-plan-review/slice.json +54 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-07-spec-create-experience/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/EXECUTION_BRIEF.md +30 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-08-executor-prompt-generation/slice.json +55 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/EXECUTION_BRIEF.md +34 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-09-delegated-slice-execution/slice.json +57 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +32 -0
- package/specs/quiver-v23-guided-flow-productization/slices/slice-10-docs-smokes-release-readiness/slice.json +63 -0
- package/specs/quiver-v24-dx-onboarding-hardening/EVIDENCE_REPORT.md +55 -0
- package/specs/quiver-v24-dx-onboarding-hardening/EXECUTION_PLAN.md +43 -0
- package/specs/quiver-v24-dx-onboarding-hardening/SPEC.md +149 -0
- package/specs/quiver-v24-dx-onboarding-hardening/STATUS.md +31 -0
- package/specs/quiver-v24-dx-onboarding-hardening/pr.md +76 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +31 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-00-spec-foundation/slice.json +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/CLOSURE_BRIEF.md +38 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-01-init-template-hygiene/slice.json +55 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-02-cli-command-routing-version-errors/slice.json +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-03-doctor-fix-doc-link-checks/slice.json +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-04-prepare-output-ai-context-drafts/slice.json +70 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/CLOSURE_BRIEF.md +36 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/EXECUTION_BRIEF.md +49 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-05-local-slice-validation-base-guidance/slice.json +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/CLOSURE_BRIEF.md +43 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/EXECUTION_BRIEF.md +53 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-06-plan-graph-next-history-views/slice.json +60 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/CLOSURE_BRIEF.md +32 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/EXECUTION_BRIEF.md +50 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-07-analyzer-command-map-hardening/slice.json +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/EXECUTION_BRIEF.md +52 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-08-evidence-run-command/slice.json +54 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/CLOSURE_BRIEF.md +34 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/EXECUTION_BRIEF.md +51 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-09-spec-viewer-demo-scaffolding/slice.json +59 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/CLOSURE_BRIEF.md +33 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/EXECUTION_BRIEF.md +54 -0
- package/specs/quiver-v24-dx-onboarding-hardening/slices/slice-10-docs-smokes-release-readiness/slice.json +76 -0
- package/src/create-quiver/commands/ai.js +915 -0
- package/src/create-quiver/commands/demo.js +22 -0
- package/src/create-quiver/commands/evidence.js +37 -0
- package/src/create-quiver/commands/flow.js +561 -0
- package/src/create-quiver/commands/graph.js +14 -1
- package/src/create-quiver/commands/next.js +28 -0
- package/src/create-quiver/commands/plan.js +6 -3
- package/src/create-quiver/commands/prepare.js +236 -0
- package/src/create-quiver/commands/spec.js +133 -0
- package/src/create-quiver/index.js +1096 -96
- package/src/create-quiver/lib/agent-profiles.js +148 -0
- package/src/create-quiver/lib/ai/context-packs.js +170 -0
- package/src/create-quiver/lib/ai/execution-plan.js +614 -0
- package/src/create-quiver/lib/ai/executor.js +682 -0
- package/src/create-quiver/lib/ai/github.js +525 -0
- package/src/create-quiver/lib/ai/onboarding-template.js +365 -0
- package/src/create-quiver/lib/ai/phase-gates.js +72 -0
- package/src/create-quiver/lib/ai/plan-review.js +283 -0
- package/src/create-quiver/lib/ai/preflight.js +58 -0
- package/src/create-quiver/lib/ai/prompt-transport.js +81 -0
- package/src/create-quiver/lib/ai/prompts.js +39 -0
- package/src/create-quiver/lib/ai/providers.js +315 -0
- package/src/create-quiver/lib/ai/safety.js +156 -0
- package/src/create-quiver/lib/ai/spec-generator.js +314 -0
- package/src/create-quiver/lib/ai/spec-templates.js +715 -0
- package/src/create-quiver/lib/approvals.js +350 -0
- package/src/create-quiver/lib/demo.js +657 -0
- package/src/create-quiver/lib/doctor.js +348 -0
- package/src/create-quiver/lib/evidence.js +115 -0
- package/src/create-quiver/lib/git.js +21 -0
- package/src/create-quiver/lib/init-docs.js +545 -23
- package/src/create-quiver/lib/init-layout.js +451 -0
- package/src/create-quiver/lib/lifecycle.js +8 -2
- package/src/create-quiver/lib/package-safety.js +117 -0
- package/src/create-quiver/lib/paths.js +63 -2
- package/src/create-quiver/lib/project-scan.js +66 -0
- package/src/create-quiver/lib/readiness.js +87 -18
- package/src/create-quiver/lib/scope.js +125 -0
- package/src/create-quiver/lib/slice-graph.js +7 -0
- package/src/create-quiver/lib/slice.js +59 -16
- package/src/create-quiver/lib/spec-worktrees.js +349 -0
- package/src/create-quiver/lib/state.js +18 -1
- package/src/create-quiver/lib/template-resolver.js +74 -0
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { readAllSlices } = require('./slice-graph');
|
|
4
|
+
const { hasGeneratedProjectSpec, hasInitializedStateMetadata, readState } = require('./state');
|
|
3
5
|
const { worktreeList } = require('./git');
|
|
6
|
+
const {
|
|
7
|
+
buildQuiverConfig,
|
|
8
|
+
buildQuiverInternalGitignore,
|
|
9
|
+
resolveInitPackageScripts,
|
|
10
|
+
} = require('./init-layout');
|
|
11
|
+
|
|
12
|
+
const NEW_LAYOUT_REQUIRED_PATHS = [
|
|
13
|
+
'README.md',
|
|
14
|
+
'AGENTS.md',
|
|
15
|
+
'package.json',
|
|
16
|
+
'docs/AI_CONTEXT.md',
|
|
17
|
+
'docs/AI_ONBOARDING_PROMPT.md',
|
|
18
|
+
'docs/COMMANDS.md',
|
|
19
|
+
'docs/WORKFLOW.md',
|
|
20
|
+
'.quiver/state.json',
|
|
21
|
+
'.quiver/config.json',
|
|
22
|
+
'.quiver/.gitignore',
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const LEGACY_LAYOUT_PROBES = [
|
|
26
|
+
'docs-template/',
|
|
27
|
+
'tools/scripts/start-slice.sh',
|
|
28
|
+
'tools/scripts/check-slice-readiness.sh',
|
|
29
|
+
'tools/scripts/check-pr-readiness.sh',
|
|
30
|
+
'.github/pull_request_template.md',
|
|
31
|
+
'docs/PROJECT_SCAN.json',
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const ROOT_GITIGNORE_DEFAULTS = [
|
|
35
|
+
'node_modules/',
|
|
36
|
+
'.DS_Store',
|
|
37
|
+
'dist/',
|
|
38
|
+
'coverage/',
|
|
39
|
+
];
|
|
4
40
|
|
|
5
41
|
function readTextIfExists(filePath) {
|
|
6
42
|
if (!fs.existsSync(filePath)) {
|
|
@@ -10,6 +46,34 @@ function readTextIfExists(filePath) {
|
|
|
10
46
|
return fs.readFileSync(filePath, 'utf8');
|
|
11
47
|
}
|
|
12
48
|
|
|
49
|
+
function normalizeIgnorePattern(line) {
|
|
50
|
+
const trimmed = line.trim();
|
|
51
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
52
|
+
return trimmed;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return trimmed.replace(/\/+$/g, '');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function missingLineDefaults(existingText, defaults) {
|
|
59
|
+
const seen = new Set(
|
|
60
|
+
String(existingText || '')
|
|
61
|
+
.split(/\r?\n/)
|
|
62
|
+
.map(normalizeIgnorePattern)
|
|
63
|
+
.filter(Boolean),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
return defaults.filter((line) => !seen.has(normalizeIgnorePattern(line)));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function appendMissingLines(filePath, lines) {
|
|
70
|
+
const existingText = readTextIfExists(filePath) || '';
|
|
71
|
+
const trimmed = existingText.replace(/\s+$/g, '');
|
|
72
|
+
const prefix = trimmed.length > 0 ? `${trimmed}\n` : '';
|
|
73
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
74
|
+
fs.writeFileSync(filePath, `${prefix}${lines.join('\n')}\n`);
|
|
75
|
+
}
|
|
76
|
+
|
|
13
77
|
function countNonEmptyLines(text) {
|
|
14
78
|
return String(text || '')
|
|
15
79
|
.split(/\r?\n/)
|
|
@@ -30,6 +94,18 @@ function normalizeRelativePath(root, absolutePath) {
|
|
|
30
94
|
return path.relative(root, absolutePath).split(path.sep).join('/');
|
|
31
95
|
}
|
|
32
96
|
|
|
97
|
+
function hasPath(projectRoot, relativePath) {
|
|
98
|
+
return fs.existsSync(path.join(projectRoot, relativePath));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function collectPresentPaths(projectRoot, relativePaths) {
|
|
102
|
+
return relativePaths.filter((relativePath) => hasPath(projectRoot, relativePath));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function collectMissingPaths(projectRoot, relativePaths) {
|
|
106
|
+
return relativePaths.filter((relativePath) => !hasPath(projectRoot, relativePath));
|
|
107
|
+
}
|
|
108
|
+
|
|
33
109
|
function collectAiMarkdownFiles(projectRoot) {
|
|
34
110
|
const aiDir = path.join(projectRoot, 'docs', 'ai');
|
|
35
111
|
if (!fs.existsSync(aiDir)) {
|
|
@@ -174,6 +250,268 @@ function countStackInfoLeaks(projectRoot) {
|
|
|
174
250
|
return leaks;
|
|
175
251
|
}
|
|
176
252
|
|
|
253
|
+
function collectGeneratedMarkdownFiles(projectRoot) {
|
|
254
|
+
const files = [];
|
|
255
|
+
const rootFiles = ['README.md', 'AGENTS.md'];
|
|
256
|
+
|
|
257
|
+
for (const file of rootFiles) {
|
|
258
|
+
const absolutePath = path.join(projectRoot, file);
|
|
259
|
+
if (fs.existsSync(absolutePath)) {
|
|
260
|
+
files.push(absolutePath);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const docsDir = path.join(projectRoot, 'docs');
|
|
265
|
+
if (!fs.existsSync(docsDir)) {
|
|
266
|
+
return files;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const walk = (dirPath) => {
|
|
270
|
+
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
271
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
272
|
+
if (entry.isDirectory()) {
|
|
273
|
+
walk(fullPath);
|
|
274
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
275
|
+
files.push(fullPath);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
walk(docsDir);
|
|
281
|
+
|
|
282
|
+
return files;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function isExternalLink(target) {
|
|
286
|
+
return /^(?:[a-z][a-z0-9+.-]*:|#)/i.test(target);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function normalizeMarkdownLinkTarget(target) {
|
|
290
|
+
return target
|
|
291
|
+
.trim()
|
|
292
|
+
.replace(/^<|>$/g, '')
|
|
293
|
+
.split('#')[0]
|
|
294
|
+
.trim();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function collectMissingMarkdownLinks(projectRoot) {
|
|
298
|
+
const missing = [];
|
|
299
|
+
const linkPattern = /!?\[[^\]]*]\(([^)]+)\)/g;
|
|
300
|
+
|
|
301
|
+
for (const filePath of collectGeneratedMarkdownFiles(projectRoot)) {
|
|
302
|
+
const text = readTextIfExists(filePath);
|
|
303
|
+
if (!text) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
let match;
|
|
308
|
+
while ((match = linkPattern.exec(text)) !== null) {
|
|
309
|
+
const target = normalizeMarkdownLinkTarget(match[1]);
|
|
310
|
+
if (!target || isExternalLink(target)) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const resolved = path.resolve(path.dirname(filePath), target);
|
|
315
|
+
const relativeToRoot = path.relative(projectRoot, resolved);
|
|
316
|
+
if (relativeToRoot.startsWith('..') || path.isAbsolute(relativeToRoot)) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (!fs.existsSync(resolved)) {
|
|
321
|
+
missing.push(`${normalizeRelativePath(projectRoot, filePath)} -> ${target}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return missing;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function collectLayoutReport(projectRoot) {
|
|
330
|
+
const hasStateMetadata = hasInitializedStateMetadata(readState(projectRoot));
|
|
331
|
+
const realSlices = readAllSlices(projectRoot);
|
|
332
|
+
const specSlugs = Array.from(new Set(realSlices.map((slice) => slice.specSlug))).sort((left, right) => left.localeCompare(right));
|
|
333
|
+
const newLayoutFiles = collectPresentPaths(projectRoot, NEW_LAYOUT_REQUIRED_PATHS);
|
|
334
|
+
const missingNewLayoutFiles = collectMissingPaths(projectRoot, NEW_LAYOUT_REQUIRED_PATHS);
|
|
335
|
+
const legacySignals = collectPresentPaths(projectRoot, LEGACY_LAYOUT_PROBES);
|
|
336
|
+
const hasLegacyProjectSpec = hasGeneratedProjectSpec(projectRoot);
|
|
337
|
+
|
|
338
|
+
if (hasLegacyProjectSpec) {
|
|
339
|
+
legacySignals.push('specs/<project-slug>/SPEC.md');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const hasNewLayout = missingNewLayoutFiles.length === 0;
|
|
343
|
+
const hasLegacyLayout = legacySignals.length > 0;
|
|
344
|
+
|
|
345
|
+
let layout = 'incomplete';
|
|
346
|
+
if (hasNewLayout && hasLegacyLayout) {
|
|
347
|
+
layout = 'hybrid';
|
|
348
|
+
} else if (hasNewLayout) {
|
|
349
|
+
layout = 'new';
|
|
350
|
+
} else if (hasLegacyLayout) {
|
|
351
|
+
layout = 'legacy';
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const recommendations = [];
|
|
355
|
+
|
|
356
|
+
if (layout === 'new') {
|
|
357
|
+
if (specSlugs.length === 0) {
|
|
358
|
+
recommendations.push('No specs yet. That is valid after the AI-first init flow.');
|
|
359
|
+
} else {
|
|
360
|
+
recommendations.push(`Specs found: ${specSlugs.join(', ')}.`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (!hasPath(projectRoot, 'docs/PROJECT_MAP.md')) {
|
|
364
|
+
recommendations.push('Run `npx create-quiver analyze` to generate docs/PROJECT_MAP.md when you want the visible project map.');
|
|
365
|
+
}
|
|
366
|
+
} else if (layout === 'legacy') {
|
|
367
|
+
recommendations.push('Legacy layout detected. Run `npx create-quiver migrate` to add the modern .quiver/ contract and AI-first docs.');
|
|
368
|
+
} else if (layout === 'hybrid') {
|
|
369
|
+
recommendations.push('Hybrid layout detected. Keep the new .quiver/ contract as the source of truth and plan cleanup of legacy roots.');
|
|
370
|
+
recommendations.push('Review any remaining docs-template/, tools/scripts/, or docs/PROJECT_SCAN.json paths and migrate them only if they are still needed.');
|
|
371
|
+
} else {
|
|
372
|
+
recommendations.push('Incomplete layout detected. Restore the missing AI-first contract files before relying on this project for onboarding.');
|
|
373
|
+
if (missingNewLayoutFiles.length > 0) {
|
|
374
|
+
recommendations.push(`Missing files: ${missingNewLayoutFiles.join(', ')}.`);
|
|
375
|
+
}
|
|
376
|
+
if (!hasStateMetadata && !hasLegacyLayout) {
|
|
377
|
+
recommendations.push('Run `npx create-quiver --name "Project Name"` or `npx create-quiver init` to create the Quiver contract first.');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
hasLegacyLayout,
|
|
383
|
+
hasNewLayout,
|
|
384
|
+
hasStateMetadata,
|
|
385
|
+
layout,
|
|
386
|
+
legacySignals,
|
|
387
|
+
missingNewLayoutFiles,
|
|
388
|
+
newLayoutFiles,
|
|
389
|
+
recommendations,
|
|
390
|
+
realSlices,
|
|
391
|
+
specSlugs,
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function buildDoctorFixPlan(projectRoot) {
|
|
396
|
+
const fixes = [];
|
|
397
|
+
const rootGitignorePath = path.join(projectRoot, '.gitignore');
|
|
398
|
+
const rootGitignoreText = readTextIfExists(rootGitignorePath) || '';
|
|
399
|
+
const missingRootGitignoreLines = missingLineDefaults(rootGitignoreText, ROOT_GITIGNORE_DEFAULTS);
|
|
400
|
+
if (!fs.existsSync(rootGitignorePath)) {
|
|
401
|
+
fixes.push({
|
|
402
|
+
type: 'append-lines',
|
|
403
|
+
path: '.gitignore',
|
|
404
|
+
description: 'Create root .gitignore with safe Quiver defaults.',
|
|
405
|
+
lines: ROOT_GITIGNORE_DEFAULTS,
|
|
406
|
+
});
|
|
407
|
+
} else if (missingRootGitignoreLines.length > 0) {
|
|
408
|
+
fixes.push({
|
|
409
|
+
type: 'append-lines',
|
|
410
|
+
path: '.gitignore',
|
|
411
|
+
description: `Merge missing root .gitignore defaults: ${missingRootGitignoreLines.join(', ')}.`,
|
|
412
|
+
lines: missingRootGitignoreLines,
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const quiverGitignorePath = path.join(projectRoot, '.quiver', '.gitignore');
|
|
417
|
+
const quiverGitignoreText = readTextIfExists(quiverGitignorePath) || '';
|
|
418
|
+
const quiverDefaults = buildQuiverInternalGitignore().split(/\r?\n/).filter(Boolean);
|
|
419
|
+
const missingQuiverLines = missingLineDefaults(quiverGitignoreText, quiverDefaults);
|
|
420
|
+
if (!fs.existsSync(quiverGitignorePath)) {
|
|
421
|
+
fixes.push({
|
|
422
|
+
type: 'write-json-or-text',
|
|
423
|
+
path: '.quiver/.gitignore',
|
|
424
|
+
description: 'Create internal .quiver/.gitignore for local AI state.',
|
|
425
|
+
content: buildQuiverInternalGitignore(),
|
|
426
|
+
});
|
|
427
|
+
} else if (missingQuiverLines.length > 0) {
|
|
428
|
+
fixes.push({
|
|
429
|
+
type: 'append-lines',
|
|
430
|
+
path: '.quiver/.gitignore',
|
|
431
|
+
description: `Merge missing .quiver/.gitignore defaults: ${missingQuiverLines.join(', ')}.`,
|
|
432
|
+
lines: missingQuiverLines,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const configPath = path.join(projectRoot, '.quiver', 'config.json');
|
|
437
|
+
if (!fs.existsSync(configPath)) {
|
|
438
|
+
fixes.push({
|
|
439
|
+
type: 'write-json-or-text',
|
|
440
|
+
path: '.quiver/config.json',
|
|
441
|
+
description: 'Create missing Quiver config metadata.',
|
|
442
|
+
content: `${JSON.stringify(buildQuiverConfig(), null, 2)}\n`,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const packageJsonPath = path.join(projectRoot, 'package.json');
|
|
447
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
448
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
449
|
+
const scripts = packageJson.scripts && typeof packageJson.scripts === 'object' ? packageJson.scripts : {};
|
|
450
|
+
const expectedScripts = resolveInitPackageScripts('default');
|
|
451
|
+
const missingScripts = Object.entries(expectedScripts)
|
|
452
|
+
.filter(([name]) => (name.startsWith('quiver:') || name === 'check-handoff') && typeof scripts[name] !== 'string');
|
|
453
|
+
|
|
454
|
+
if (missingScripts.length > 0) {
|
|
455
|
+
fixes.push({
|
|
456
|
+
type: 'merge-package-scripts',
|
|
457
|
+
path: 'package.json',
|
|
458
|
+
description: `Add missing package scripts: ${missingScripts.map(([name]) => name).join(', ')}.`,
|
|
459
|
+
scripts: Object.fromEntries(missingScripts),
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return fixes;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function applyDoctorFixPlan(projectRoot, fixes) {
|
|
468
|
+
for (const fix of fixes) {
|
|
469
|
+
const targetPath = path.join(projectRoot, fix.path);
|
|
470
|
+
if (fix.type === 'append-lines') {
|
|
471
|
+
appendMissingLines(targetPath, fix.lines);
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (fix.type === 'write-json-or-text') {
|
|
476
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
477
|
+
fs.writeFileSync(targetPath, fix.content);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (fix.type === 'merge-package-scripts') {
|
|
482
|
+
const packageJson = JSON.parse(fs.readFileSync(targetPath, 'utf8'));
|
|
483
|
+
packageJson.scripts = {
|
|
484
|
+
...(packageJson.scripts || {}),
|
|
485
|
+
...fix.scripts,
|
|
486
|
+
};
|
|
487
|
+
fs.writeFileSync(targetPath, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function formatDoctorFixPlan(fixes, { dryRun = false } = {}) {
|
|
493
|
+
const lines = [dryRun ? 'Quiver doctor fix dry-run' : 'Quiver doctor fix'];
|
|
494
|
+
if (fixes.length === 0) {
|
|
495
|
+
lines.push('- No safe fixes to apply.');
|
|
496
|
+
} else {
|
|
497
|
+
for (const fix of fixes) {
|
|
498
|
+
lines.push(`- ${dryRun ? 'Would update' : 'Updated'} ${fix.path}: ${fix.description}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
lines.push('');
|
|
502
|
+
return lines.join('\n');
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function collectDoctorReport(projectRoot) {
|
|
506
|
+
const layout = collectLayoutReport(projectRoot);
|
|
507
|
+
const warnings = collectDoctorWarnings(projectRoot);
|
|
508
|
+
|
|
509
|
+
return {
|
|
510
|
+
...layout,
|
|
511
|
+
warnings,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
177
515
|
function collectDoctorWarnings(projectRoot) {
|
|
178
516
|
const warnings = [];
|
|
179
517
|
|
|
@@ -204,9 +542,19 @@ function collectDoctorWarnings(projectRoot) {
|
|
|
204
542
|
warnings.push(`stack information appears outside docs/PROJECT_MAP.md: ${leakIssues.join(', ')}`);
|
|
205
543
|
}
|
|
206
544
|
|
|
545
|
+
const missingLinks = collectMissingMarkdownLinks(projectRoot);
|
|
546
|
+
for (const issue of missingLinks) {
|
|
547
|
+
warnings.push(`missing local docs link: ${issue}`);
|
|
548
|
+
}
|
|
549
|
+
|
|
207
550
|
return warnings;
|
|
208
551
|
}
|
|
209
552
|
|
|
210
553
|
module.exports = {
|
|
554
|
+
applyDoctorFixPlan,
|
|
555
|
+
buildDoctorFixPlan,
|
|
556
|
+
collectDoctorReport,
|
|
211
557
|
collectDoctorWarnings,
|
|
558
|
+
collectLayoutReport,
|
|
559
|
+
formatDoctorFixPlan,
|
|
212
560
|
};
|
|
@@ -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
|
+
};
|
|
@@ -101,6 +101,23 @@ function statusPorcelain(repoRoot) {
|
|
|
101
101
|
return tryGit(['status', '--porcelain'], repoRoot);
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
function remoteList(repoRoot) {
|
|
105
|
+
const output = tryGit(['remote'], repoRoot);
|
|
106
|
+
return output ? output.split('\n').map((line) => line.trim()).filter(Boolean) : [];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function hasRemote(repoRoot, remoteName = 'origin') {
|
|
110
|
+
return remoteList(repoRoot).includes(remoteName);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isCleanWorktree(repoRoot) {
|
|
114
|
+
return statusPorcelain(repoRoot) === '';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function isDetachedHead(repoRoot) {
|
|
118
|
+
return currentBranch(repoRoot) === '';
|
|
119
|
+
}
|
|
120
|
+
|
|
104
121
|
function revListCount(repoRoot, range) {
|
|
105
122
|
const output = tryGit(['rev-list', '--count', range], repoRoot);
|
|
106
123
|
return Number(output || '0');
|
|
@@ -143,7 +160,11 @@ module.exports = {
|
|
|
143
160
|
hasRemoteBranch,
|
|
144
161
|
lsRemoteHeads,
|
|
145
162
|
mergeBaseIsAncestor,
|
|
163
|
+
hasRemote,
|
|
164
|
+
isCleanWorktree,
|
|
165
|
+
isDetachedHead,
|
|
146
166
|
revListCount,
|
|
167
|
+
remoteList,
|
|
147
168
|
runGit,
|
|
148
169
|
statusPorcelain,
|
|
149
170
|
tryGit,
|