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
|
@@ -3,16 +3,39 @@ const os = require('os');
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { execFileSync } = require('child_process');
|
|
5
5
|
const { checkHandoff, scaffoldHandoff } = require('./lib/handoff');
|
|
6
|
-
const {
|
|
6
|
+
const {
|
|
7
|
+
applyDoctorFixPlan,
|
|
8
|
+
buildDoctorFixPlan,
|
|
9
|
+
collectDoctorReport,
|
|
10
|
+
formatDoctorFixPlan,
|
|
11
|
+
} = require('./lib/doctor');
|
|
12
|
+
const { runAgent: runAiAgent, runApprovalStatus: runAiApprovalStatus, runApprove: runAiApprove, runDoctor: runAiDoctor, runExecutePlan: runAiExecutePlan, runExecuteSlice: runAiExecuteSlice, runOnboard, runPlan: runAiPlan, runPrepareContext: runAiPrepareContext, runPr: runAiPr, runPromptSlice: runAiPromptSlice, runReviewPlan: runAiReviewPlan } = require('./commands/ai');
|
|
13
|
+
const { runDemo } = require('./commands/demo');
|
|
14
|
+
const { runPrepare } = require('./commands/prepare');
|
|
15
|
+
const { runEvidence } = require('./commands/evidence');
|
|
16
|
+
const { runFlow } = require('./commands/flow');
|
|
7
17
|
const { runGraph } = require('./commands/graph');
|
|
8
18
|
const { runNext } = require('./commands/next');
|
|
9
19
|
const { runPlan } = require('./commands/plan');
|
|
10
|
-
const {
|
|
20
|
+
const { runCreateSpec } = require('./commands/spec');
|
|
21
|
+
const { buildInitLayout, formatInitLayoutPlan } = require('./lib/init-layout');
|
|
22
|
+
const { initializeProjectDocs, installSelfAsDevDep, refreshAiContextDoc } = require('./lib/init-docs');
|
|
11
23
|
const { checkPrReadiness, checkScope, checkSliceReadiness } = require('./lib/readiness');
|
|
12
24
|
const { cleanupSlice, refreshActiveSlicesBoard, startSlice } = require('./lib/lifecycle');
|
|
25
|
+
const { buildSpecStatus, closeSpecWorktree, formatSpecCloseResult, formatSpecStartResult, formatSpecStatus, startSpecWorktree } = require('./lib/spec-worktrees');
|
|
26
|
+
const { getContextPathExclusionReason } = require('./lib/ai/safety');
|
|
13
27
|
const { relativePosixPath, resolveTargetRoot } = require('./lib/paths');
|
|
28
|
+
const {
|
|
29
|
+
CURRENT_SCAN_RELATIVE_PATH,
|
|
30
|
+
PROJECT_MAP_RELATIVE_PATH,
|
|
31
|
+
hasProjectScanArtifact,
|
|
32
|
+
projectScanPaths,
|
|
33
|
+
writeProjectScanJson,
|
|
34
|
+
} = require('./lib/project-scan');
|
|
35
|
+
const { resolveTemplateRoot } = require('./lib/template-resolver');
|
|
14
36
|
const {
|
|
15
37
|
hasQuiverInitializationEvidence,
|
|
38
|
+
inspectLegacyMigrationLayout,
|
|
16
39
|
readState,
|
|
17
40
|
updateStateForAnalyze,
|
|
18
41
|
updateStateForMigrate,
|
|
@@ -24,15 +47,74 @@ function formatError(message) {
|
|
|
24
47
|
return `create-quiver: ${message}`;
|
|
25
48
|
}
|
|
26
49
|
|
|
50
|
+
const SUPPORTED_COMMAND_MODES = new Set([
|
|
51
|
+
'init',
|
|
52
|
+
'flow',
|
|
53
|
+
'plan',
|
|
54
|
+
'graph',
|
|
55
|
+
'next',
|
|
56
|
+
'doctor',
|
|
57
|
+
'prepare',
|
|
58
|
+
'analyze',
|
|
59
|
+
'migrate',
|
|
60
|
+
'start-slice',
|
|
61
|
+
'check-slice',
|
|
62
|
+
'check-pr',
|
|
63
|
+
'check-handoff',
|
|
64
|
+
'new-handoff',
|
|
65
|
+
'cleanup-slice',
|
|
66
|
+
'check-scope',
|
|
67
|
+
'refresh-active-slices',
|
|
68
|
+
'spec',
|
|
69
|
+
'evidence',
|
|
70
|
+
'demo',
|
|
71
|
+
'ai',
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
const SUPPORTED_AI_COMMANDS = new Set([
|
|
75
|
+
'agent',
|
|
76
|
+
'approve',
|
|
77
|
+
'approval-status',
|
|
78
|
+
'approvals',
|
|
79
|
+
'doctor',
|
|
80
|
+
'execute-plan',
|
|
81
|
+
'execute-slice',
|
|
82
|
+
'executor-prompt',
|
|
83
|
+
'onboard',
|
|
84
|
+
'plan',
|
|
85
|
+
'prepare-context',
|
|
86
|
+
'pr',
|
|
87
|
+
'prompt-slice',
|
|
88
|
+
'review-plan',
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
const SUPPORTED_SPEC_COMMANDS = new Set(['close', 'create', 'start', 'status']);
|
|
92
|
+
const SUPPORTED_DEMO_COMMANDS = new Set(['create']);
|
|
93
|
+
|
|
94
|
+
function unsupportedCommandMessage(commandName) {
|
|
95
|
+
return [
|
|
96
|
+
`unsupported command: ${commandName}`,
|
|
97
|
+
'Run: npx create-quiver --help',
|
|
98
|
+
`If you meant to initialize a project, use: npx create-quiver init --name "${commandName}"`,
|
|
99
|
+
'If this command exists in newer docs, update create-quiver and rerun the command.',
|
|
100
|
+
].join('\n');
|
|
101
|
+
}
|
|
102
|
+
|
|
27
103
|
function printUsage() {
|
|
28
104
|
console.log(`Usage:
|
|
29
105
|
npx create-quiver [options]
|
|
106
|
+
npx create-quiver init [options]
|
|
30
107
|
npx create-quiver analyze [options]
|
|
108
|
+
npx create-quiver flow [options]
|
|
31
109
|
npx create-quiver plan [options]
|
|
110
|
+
npx create-quiver ai <task> [options]
|
|
111
|
+
npx create-quiver ai agent <set|list|show> [role] [options]
|
|
112
|
+
npx create-quiver ai prepare-context [options]
|
|
32
113
|
npx create-quiver graph [options]
|
|
33
114
|
npx create-quiver next [options]
|
|
34
115
|
npx create-quiver migrate [options]
|
|
35
116
|
npx create-quiver doctor [options]
|
|
117
|
+
npx create-quiver prepare [options]
|
|
36
118
|
npx create-quiver start-slice [options] <slice.json>
|
|
37
119
|
npx create-quiver check-slice [options] <slice.json>
|
|
38
120
|
npx create-quiver check-pr <slice.json>
|
|
@@ -41,6 +123,12 @@ function printUsage() {
|
|
|
41
123
|
npx create-quiver cleanup-slice [options] <slice.json>
|
|
42
124
|
npx create-quiver check-scope [options] <slice.json>
|
|
43
125
|
npx create-quiver refresh-active-slices
|
|
126
|
+
npx create-quiver spec create [options]
|
|
127
|
+
npx create-quiver spec start <spec-dir>
|
|
128
|
+
npx create-quiver spec status <spec-dir>
|
|
129
|
+
npx create-quiver spec close <spec-dir>
|
|
130
|
+
npx create-quiver evidence run [options] -- <command>
|
|
131
|
+
npx create-quiver demo create spec-viewer [options]
|
|
44
132
|
|
|
45
133
|
Options:
|
|
46
134
|
-n, --name <project-name> Project name to generate
|
|
@@ -50,18 +138,63 @@ Options:
|
|
|
50
138
|
--show-conflicts Show shared file paths in graph output
|
|
51
139
|
--level <n> Restrict graph output to one level
|
|
52
140
|
--json Emit machine-readable JSON
|
|
141
|
+
--include-completed Include completed slices in plan, graph, or next history output
|
|
53
142
|
--only-ready Show only slices with no pending dependencies
|
|
54
143
|
--all-ready List every ready slice returned by next
|
|
55
144
|
--auto-start Prompt for confirmation and run start-slice on next
|
|
145
|
+
--local For check-slice, run structural validation without remote/base checks
|
|
56
146
|
--unicode Prefer Unicode output when supported
|
|
147
|
+
--minimal Plan or run the minimal init profile
|
|
148
|
+
--full Plan or run the full compatibility init profile
|
|
149
|
+
--legacy-scripts Include legacy Bash wrappers in init profile
|
|
150
|
+
--include-templates Export packaged templates in init profile
|
|
151
|
+
--dry-run Preview init, prepare, spec create, demo, or AI work without executing writes/providers
|
|
152
|
+
--fix For doctor, apply safe non-destructive repairs
|
|
153
|
+
--execute For ai execute-plan, run the planned slices instead of printing commands
|
|
154
|
+
--create For ai pr, create the PR after preflight instead of printing the plan only
|
|
155
|
+
--commit For ai execute-slice, commit validated slice changes after provider, scope, and tests pass
|
|
156
|
+
--allow-dirty For ai execute-slice, allow pre-existing dirty files and ignore them for scope diff
|
|
157
|
+
--mode <name> Execution mode for ai execute-plan (auto, manual, delegated)
|
|
158
|
+
--provider <name> Provider CLI to preflight for prepare or AI commands
|
|
159
|
+
--model <label> Free-form model label for AI agent profiles
|
|
160
|
+
--version <n> Draft version to approve for AI planner phases
|
|
161
|
+
--ssh-host-alias <name> SSH host alias to validate for prepare or AI commands
|
|
162
|
+
--identity-file <path> SSH identity file to validate for prepare or AI commands
|
|
163
|
+
--remote <name> Git remote name for check-slice or AI PR checks
|
|
164
|
+
--base <branch> Base branch for check-slice, ai pr, or spec close (default: main)
|
|
165
|
+
--output <file> Output file for evidence run
|
|
166
|
+
--max-output <n> Maximum stdout/stderr chars per evidence section
|
|
167
|
+
--title <text> Override PR title for ai pr create
|
|
57
168
|
-y, --yes Skip prompts and use the provided inputs
|
|
58
169
|
-h, --help Show this help message
|
|
59
170
|
|
|
60
171
|
Examples:
|
|
172
|
+
npx create-quiver init --name "My Project"
|
|
173
|
+
npx create-quiver init --name "My Project" --dry-run
|
|
61
174
|
npx create-quiver --name "My Project"
|
|
62
175
|
npx create-quiver --name "My Project" --dir ./my-project
|
|
176
|
+
cd ./my-project && npx create-quiver flow
|
|
63
177
|
cd ./my-project && npx create-quiver analyze
|
|
64
178
|
cd ./my-project && npx create-quiver plan --json
|
|
179
|
+
cd ./my-project && npx create-quiver ai onboard --dry-run
|
|
180
|
+
cd ./my-project && npx create-quiver ai prepare-context --dry-run
|
|
181
|
+
cd ./my-project && npx create-quiver ai agent set planner --provider codex --model gpt-5.5
|
|
182
|
+
cd ./my-project && npx create-quiver ai agent list
|
|
183
|
+
cd ./my-project && npx create-quiver ai plan --phase acceptance --input requirements.md --dry-run
|
|
184
|
+
cd ./my-project && npx create-quiver ai approve --phase acceptance --input acceptance.md
|
|
185
|
+
cd ./my-project && npx create-quiver ai plan --phase technical-plan --dry-run
|
|
186
|
+
cd ./my-project && npx create-quiver ai review-plan --dry-run
|
|
187
|
+
cd ./my-project && npx create-quiver ai approve --phase technical-plan --version 1
|
|
188
|
+
cd ./my-project && npx create-quiver spec create --dry-run
|
|
189
|
+
cd ./my-project && npx create-quiver ai approvals
|
|
190
|
+
cd ./my-project && npx create-quiver ai prompt-slice --slice specs/my-project/slices/slice-01/slice.json --dry-run
|
|
191
|
+
cd ./my-project && npx create-quiver ai execute-slice --slice specs/my-project/slices/slice-01/slice.json --dry-run
|
|
192
|
+
cd ./my-project && npx create-quiver ai execute-slice --slice specs/my-project/slices/slice-01/slice.json --commit
|
|
193
|
+
cd ./my-project && npx create-quiver ai execute-plan --dry-run --commit
|
|
194
|
+
cd ./my-project && npx create-quiver ai doctor --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
|
|
195
|
+
cd ./my-project && npx create-quiver ai pr --dry-run --ssh-host-alias github-work --identity-file ~/.ssh/github-work
|
|
196
|
+
cd ./my-project && npx create-quiver ai pr --create --input specs/my-project/pr.md --ssh-host-alias github-work --identity-file ~/.ssh/github-work
|
|
197
|
+
cd ./my-project && npx create-quiver prepare --dry-run --provider codex --ssh-host-alias github-work --identity-file ~/.ssh/github-work
|
|
65
198
|
cd ./my-project && npx create-quiver graph --show-conflicts
|
|
66
199
|
cd ./my-project && npx create-quiver graph --format mermaid
|
|
67
200
|
cd ./my-project && npx create-quiver graph --format dot
|
|
@@ -78,6 +211,11 @@ Examples:
|
|
|
78
211
|
cd ./my-project && npx create-quiver cleanup-slice specs/my-project/slices/slice-01/slice.json
|
|
79
212
|
cd ./my-project && npx create-quiver check-scope specs/my-project/slices/slice-01/slice.json
|
|
80
213
|
cd ./my-project && npx create-quiver refresh-active-slices
|
|
214
|
+
cd ./my-project && npx create-quiver spec start specs/my-project
|
|
215
|
+
cd ./my-project && npx create-quiver spec status specs/my-project
|
|
216
|
+
cd ./my-project && npx create-quiver spec close specs/my-project --dry-run
|
|
217
|
+
cd ./my-project && npx create-quiver evidence run -- npm test
|
|
218
|
+
cd ./my-project && npx create-quiver demo create spec-viewer --dry-run
|
|
81
219
|
node bin/create-quiver.js doctor --dir ./my-project
|
|
82
220
|
`);
|
|
83
221
|
}
|
|
@@ -86,17 +224,22 @@ function parseArgs(argv) {
|
|
|
86
224
|
const result = {
|
|
87
225
|
help: false,
|
|
88
226
|
force: false,
|
|
227
|
+
explicitInit: false,
|
|
89
228
|
mode: 'init',
|
|
90
229
|
allowDraft: false,
|
|
230
|
+
checkSliceLocal: false,
|
|
91
231
|
closeBaseline: false,
|
|
92
232
|
discard: false,
|
|
233
|
+
doctorFix: false,
|
|
93
234
|
dryRun: false,
|
|
94
235
|
gate: 'execution',
|
|
95
236
|
projectName: '',
|
|
96
237
|
targetDir: '.',
|
|
238
|
+
targetDirExplicit: false,
|
|
97
239
|
strict: false,
|
|
98
240
|
strictOverlap: false,
|
|
99
241
|
json: false,
|
|
242
|
+
includeCompleted: false,
|
|
100
243
|
onlyReady: false,
|
|
101
244
|
allReady: false,
|
|
102
245
|
autoStart: false,
|
|
@@ -105,13 +248,60 @@ function parseArgs(argv) {
|
|
|
105
248
|
showConflicts: false,
|
|
106
249
|
level: null,
|
|
107
250
|
unicode: false,
|
|
251
|
+
aiCommand: '',
|
|
252
|
+
aiAgentCommand: '',
|
|
253
|
+
aiAgentRole: '',
|
|
254
|
+
aiPhase: 'acceptance',
|
|
255
|
+
aiProvider: 'codex',
|
|
256
|
+
aiProviderExplicit: false,
|
|
257
|
+
aiModel: '',
|
|
258
|
+
aiLabel: '',
|
|
259
|
+
aiVersion: '',
|
|
260
|
+
prepareProvider: '',
|
|
261
|
+
aiRole: '',
|
|
262
|
+
aiContext: '',
|
|
263
|
+
aiInput: '',
|
|
264
|
+
aiSlice: '',
|
|
265
|
+
aiTimeout: null,
|
|
266
|
+
aiCommit: false,
|
|
267
|
+
aiAllowDirty: false,
|
|
268
|
+
aiExecute: false,
|
|
269
|
+
aiExecutionMode: 'auto',
|
|
270
|
+
aiCreate: false,
|
|
271
|
+
aiBaseBranch: 'main',
|
|
272
|
+
baseBranchExplicit: false,
|
|
273
|
+
aiTitle: '',
|
|
274
|
+
aiSshHostAlias: '',
|
|
275
|
+
aiIdentityFile: '',
|
|
276
|
+
aiRemote: 'origin',
|
|
277
|
+
initFull: false,
|
|
278
|
+
initIncludeTemplates: false,
|
|
279
|
+
initLegacyScripts: false,
|
|
280
|
+
initMinimal: false,
|
|
281
|
+
specCommand: '',
|
|
282
|
+
demoCommand: '',
|
|
283
|
+
demoName: '',
|
|
284
|
+
evidenceCommand: '',
|
|
285
|
+
evidenceArgs: [],
|
|
286
|
+
evidenceOutput: '',
|
|
287
|
+
evidenceMaxOutput: null,
|
|
108
288
|
};
|
|
109
289
|
|
|
110
290
|
const args = [...argv];
|
|
111
|
-
|
|
112
|
-
if (commandModes.has(args[0])) {
|
|
291
|
+
if (SUPPORTED_COMMAND_MODES.has(args[0])) {
|
|
113
292
|
result.mode = args[0];
|
|
293
|
+
result.explicitInit = args[0] === 'init';
|
|
114
294
|
args.shift();
|
|
295
|
+
if (result.mode === 'spec') {
|
|
296
|
+
result.specCommand = args.shift() || '';
|
|
297
|
+
}
|
|
298
|
+
if (result.mode === 'evidence') {
|
|
299
|
+
result.evidenceCommand = args.shift() || '';
|
|
300
|
+
}
|
|
301
|
+
if (result.mode === 'demo') {
|
|
302
|
+
result.demoCommand = args.shift() || '';
|
|
303
|
+
result.demoName = args.shift() || '';
|
|
304
|
+
}
|
|
115
305
|
} else if (args[0] === '--analyze') {
|
|
116
306
|
result.mode = 'analyze';
|
|
117
307
|
args.shift();
|
|
@@ -127,6 +317,8 @@ function parseArgs(argv) {
|
|
|
127
317
|
} else if (args[0] === '--new-handoff') {
|
|
128
318
|
result.mode = 'new-handoff';
|
|
129
319
|
args.shift();
|
|
320
|
+
} else if (args[0] && !args[0].startsWith('-')) {
|
|
321
|
+
throw new Error(formatError(unsupportedCommandMessage(args[0])));
|
|
130
322
|
}
|
|
131
323
|
|
|
132
324
|
const positional = [];
|
|
@@ -134,6 +326,11 @@ function parseArgs(argv) {
|
|
|
134
326
|
for (let index = 0; index < args.length; index += 1) {
|
|
135
327
|
const arg = args[index];
|
|
136
328
|
|
|
329
|
+
if (arg === '--') {
|
|
330
|
+
result.evidenceArgs = args.slice(index + 1);
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
|
|
137
334
|
if (arg === '-h' || arg === '--help') {
|
|
138
335
|
result.help = true;
|
|
139
336
|
continue;
|
|
@@ -174,6 +371,11 @@ function parseArgs(argv) {
|
|
|
174
371
|
continue;
|
|
175
372
|
}
|
|
176
373
|
|
|
374
|
+
if (arg === '--local') {
|
|
375
|
+
result.checkSliceLocal = true;
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
|
|
177
379
|
if (arg === '--close-baseline') {
|
|
178
380
|
result.closeBaseline = true;
|
|
179
381
|
continue;
|
|
@@ -184,11 +386,65 @@ function parseArgs(argv) {
|
|
|
184
386
|
continue;
|
|
185
387
|
}
|
|
186
388
|
|
|
389
|
+
if (arg === '--fix') {
|
|
390
|
+
result.doctorFix = true;
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
|
|
187
394
|
if (arg === '--dry-run') {
|
|
188
395
|
result.dryRun = true;
|
|
189
396
|
continue;
|
|
190
397
|
}
|
|
191
398
|
|
|
399
|
+
if (arg === '--commit') {
|
|
400
|
+
result.aiCommit = true;
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (arg === '--execute') {
|
|
405
|
+
result.aiExecute = true;
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (arg === '--create') {
|
|
410
|
+
result.aiCreate = true;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (arg === '--mode') {
|
|
415
|
+
const value = args[++index];
|
|
416
|
+
if (!value) {
|
|
417
|
+
throw new Error(formatError('missing value for --mode'));
|
|
418
|
+
}
|
|
419
|
+
result.aiExecutionMode = value;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (arg === '--allow-dirty') {
|
|
424
|
+
result.aiAllowDirty = true;
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (arg === '--minimal') {
|
|
429
|
+
result.initMinimal = true;
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (arg === '--full') {
|
|
434
|
+
result.initFull = true;
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (arg === '--legacy-scripts') {
|
|
439
|
+
result.initLegacyScripts = true;
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (arg === '--include-templates') {
|
|
444
|
+
result.initIncludeTemplates = true;
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
|
|
192
448
|
if (arg === '--strict') {
|
|
193
449
|
result.strict = true;
|
|
194
450
|
continue;
|
|
@@ -204,6 +460,11 @@ function parseArgs(argv) {
|
|
|
204
460
|
continue;
|
|
205
461
|
}
|
|
206
462
|
|
|
463
|
+
if (arg === '--include-completed') {
|
|
464
|
+
result.includeCompleted = true;
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
|
|
207
468
|
if (arg === '--show-conflicts') {
|
|
208
469
|
result.showConflicts = true;
|
|
209
470
|
continue;
|
|
@@ -251,6 +512,170 @@ function parseArgs(argv) {
|
|
|
251
512
|
continue;
|
|
252
513
|
}
|
|
253
514
|
|
|
515
|
+
if (arg === '--provider') {
|
|
516
|
+
const value = args[++index];
|
|
517
|
+
if (!value) {
|
|
518
|
+
throw new Error(formatError('missing value for --provider'));
|
|
519
|
+
}
|
|
520
|
+
result.aiProvider = value;
|
|
521
|
+
result.prepareProvider = value;
|
|
522
|
+
result.aiProviderExplicit = true;
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (arg === '--model') {
|
|
527
|
+
const value = args[++index];
|
|
528
|
+
if (!value) {
|
|
529
|
+
throw new Error(formatError('missing value for --model'));
|
|
530
|
+
}
|
|
531
|
+
result.aiModel = value;
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (arg === '--label') {
|
|
536
|
+
const value = args[++index];
|
|
537
|
+
if (!value) {
|
|
538
|
+
throw new Error(formatError('missing value for --label'));
|
|
539
|
+
}
|
|
540
|
+
result.aiLabel = value;
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (arg === '--version') {
|
|
545
|
+
const value = args[++index];
|
|
546
|
+
if (!value) {
|
|
547
|
+
throw new Error(formatError('missing value for --version'));
|
|
548
|
+
}
|
|
549
|
+
result.aiVersion = value;
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (arg === '--role') {
|
|
554
|
+
const value = args[++index];
|
|
555
|
+
if (!value) {
|
|
556
|
+
throw new Error(formatError('missing value for --role'));
|
|
557
|
+
}
|
|
558
|
+
result.aiRole = value;
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
if (arg === '--context') {
|
|
563
|
+
const value = args[++index];
|
|
564
|
+
if (!value) {
|
|
565
|
+
throw new Error(formatError('missing value for --context'));
|
|
566
|
+
}
|
|
567
|
+
result.aiContext = value;
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (arg === '--input') {
|
|
572
|
+
const value = args[++index];
|
|
573
|
+
if (!value) {
|
|
574
|
+
throw new Error(formatError('missing value for --input'));
|
|
575
|
+
}
|
|
576
|
+
result.aiInput = value;
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (arg === '--slice') {
|
|
581
|
+
const value = args[++index];
|
|
582
|
+
if (!value) {
|
|
583
|
+
throw new Error(formatError('missing value for --slice'));
|
|
584
|
+
}
|
|
585
|
+
result.aiSlice = value;
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if (arg === '--timeout') {
|
|
590
|
+
const value = args[++index];
|
|
591
|
+
if (typeof value === 'undefined') {
|
|
592
|
+
throw new Error(formatError('missing value for --timeout'));
|
|
593
|
+
}
|
|
594
|
+
const parsed = Number.parseInt(value, 10);
|
|
595
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
596
|
+
throw new Error(formatError('invalid value for --timeout'));
|
|
597
|
+
}
|
|
598
|
+
result.aiTimeout = parsed;
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (arg === '--ssh-host-alias') {
|
|
603
|
+
const value = args[++index];
|
|
604
|
+
if (!value) {
|
|
605
|
+
throw new Error(formatError('missing value for --ssh-host-alias'));
|
|
606
|
+
}
|
|
607
|
+
result.aiSshHostAlias = value;
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
if (arg === '--identity-file') {
|
|
612
|
+
const value = args[++index];
|
|
613
|
+
if (!value) {
|
|
614
|
+
throw new Error(formatError('missing value for --identity-file'));
|
|
615
|
+
}
|
|
616
|
+
result.aiIdentityFile = value;
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (arg === '--remote') {
|
|
621
|
+
const value = args[++index];
|
|
622
|
+
if (!value) {
|
|
623
|
+
throw new Error(formatError('missing value for --remote'));
|
|
624
|
+
}
|
|
625
|
+
result.aiRemote = value;
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (arg === '--base') {
|
|
630
|
+
const value = args[++index];
|
|
631
|
+
if (!value) {
|
|
632
|
+
throw new Error(formatError('missing value for --base'));
|
|
633
|
+
}
|
|
634
|
+
result.aiBaseBranch = value;
|
|
635
|
+
result.baseBranchExplicit = true;
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (arg === '--output') {
|
|
640
|
+
const value = args[++index];
|
|
641
|
+
if (!value) {
|
|
642
|
+
throw new Error(formatError('missing value for --output'));
|
|
643
|
+
}
|
|
644
|
+
result.evidenceOutput = value;
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
if (arg === '--max-output') {
|
|
649
|
+
const value = args[++index];
|
|
650
|
+
if (typeof value === 'undefined') {
|
|
651
|
+
throw new Error(formatError('missing value for --max-output'));
|
|
652
|
+
}
|
|
653
|
+
const parsed = Number.parseInt(value, 10);
|
|
654
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
655
|
+
throw new Error(formatError('invalid value for --max-output'));
|
|
656
|
+
}
|
|
657
|
+
result.evidenceMaxOutput = parsed;
|
|
658
|
+
continue;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (arg === '--title') {
|
|
662
|
+
const value = args[++index];
|
|
663
|
+
if (!value) {
|
|
664
|
+
throw new Error(formatError('missing value for --title'));
|
|
665
|
+
}
|
|
666
|
+
result.aiTitle = value;
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
if (arg === '--phase') {
|
|
671
|
+
const value = args[++index];
|
|
672
|
+
if (!value) {
|
|
673
|
+
throw new Error(formatError('missing value for --phase'));
|
|
674
|
+
}
|
|
675
|
+
result.aiPhase = value;
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
|
|
254
679
|
if (arg === '--spec') {
|
|
255
680
|
const value = args[++index];
|
|
256
681
|
if (!value) {
|
|
@@ -284,6 +709,7 @@ function parseArgs(argv) {
|
|
|
284
709
|
throw new Error(formatError('missing value for --dir'));
|
|
285
710
|
}
|
|
286
711
|
result.targetDir = value;
|
|
712
|
+
result.targetDirExplicit = true;
|
|
287
713
|
continue;
|
|
288
714
|
}
|
|
289
715
|
|
|
@@ -306,10 +732,78 @@ function parseArgs(argv) {
|
|
|
306
732
|
if (positional.length > 0) {
|
|
307
733
|
throw new Error(formatError('plan does not accept positional arguments; use --spec <slug>'));
|
|
308
734
|
}
|
|
735
|
+
} else if (result.mode === 'flow') {
|
|
736
|
+
if (positional.length > 0) {
|
|
737
|
+
throw new Error(formatError('flow does not accept positional arguments'));
|
|
738
|
+
}
|
|
739
|
+
} else if (result.mode === 'ai') {
|
|
740
|
+
if (!result.aiCommand && positional.length > 0) {
|
|
741
|
+
result.aiCommand = positional.shift();
|
|
742
|
+
}
|
|
743
|
+
if (result.aiCommand === 'agent') {
|
|
744
|
+
if (!result.aiAgentCommand && positional.length > 0) {
|
|
745
|
+
result.aiAgentCommand = positional.shift();
|
|
746
|
+
}
|
|
747
|
+
if (!result.aiAgentRole && positional.length > 0) {
|
|
748
|
+
result.aiAgentRole = positional.shift();
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (positional.length > 0) {
|
|
752
|
+
throw new Error(formatError('ai does not accept extra positional arguments'));
|
|
753
|
+
}
|
|
754
|
+
} else if (result.mode === 'prepare') {
|
|
755
|
+
if (positional.length > 0) {
|
|
756
|
+
throw new Error(formatError('prepare does not accept positional arguments'));
|
|
757
|
+
}
|
|
309
758
|
} else if (result.mode === 'refresh-active-slices') {
|
|
310
759
|
if (positional.length > 0) {
|
|
311
760
|
throw new Error(formatError('refresh-active-slices does not accept positional arguments'));
|
|
312
761
|
}
|
|
762
|
+
} else if (result.mode === 'spec') {
|
|
763
|
+
if (!result.specCommand && positional.length > 0) {
|
|
764
|
+
result.specCommand = positional.shift();
|
|
765
|
+
}
|
|
766
|
+
if (!result.specCommand) {
|
|
767
|
+
throw new Error(formatError('missing spec subcommand. Use: npx create-quiver spec <create|start|status|close>'));
|
|
768
|
+
}
|
|
769
|
+
if (result.specCommand !== 'create' && positional.length > 0) {
|
|
770
|
+
result.targetDir = positional.shift();
|
|
771
|
+
}
|
|
772
|
+
if (result.specCommand === 'create' && positional.length > 0) {
|
|
773
|
+
throw new Error(formatError('spec create does not accept positional arguments; use --input <file> or --spec <slug>'));
|
|
774
|
+
}
|
|
775
|
+
} else if (result.mode === 'evidence') {
|
|
776
|
+
if (!result.evidenceCommand && positional.length > 0) {
|
|
777
|
+
result.evidenceCommand = positional.shift();
|
|
778
|
+
}
|
|
779
|
+
if (!result.evidenceCommand) {
|
|
780
|
+
throw new Error(formatError('missing evidence subcommand. Use: npx create-quiver evidence run -- <command>'));
|
|
781
|
+
}
|
|
782
|
+
if (result.evidenceCommand !== 'run') {
|
|
783
|
+
throw new Error(formatError(`unsupported evidence subcommand: ${result.evidenceCommand}. Supported tasks: run`));
|
|
784
|
+
}
|
|
785
|
+
if (positional.length > 0) {
|
|
786
|
+
throw new Error(formatError('evidence run does not accept positional arguments before --'));
|
|
787
|
+
}
|
|
788
|
+
} else if (result.mode === 'demo') {
|
|
789
|
+
if (!result.demoCommand && positional.length > 0) {
|
|
790
|
+
result.demoCommand = positional.shift();
|
|
791
|
+
}
|
|
792
|
+
if (!result.demoName && positional.length > 0) {
|
|
793
|
+
result.demoName = positional.shift();
|
|
794
|
+
}
|
|
795
|
+
if (!result.demoCommand) {
|
|
796
|
+
throw new Error(formatError('missing demo subcommand. Use: npx create-quiver demo create spec-viewer'));
|
|
797
|
+
}
|
|
798
|
+
if (!SUPPORTED_DEMO_COMMANDS.has(result.demoCommand)) {
|
|
799
|
+
throw new Error(formatError(`unsupported demo subcommand: ${result.demoCommand}. Supported tasks: create`));
|
|
800
|
+
}
|
|
801
|
+
if (result.demoName !== 'spec-viewer') {
|
|
802
|
+
throw new Error(formatError(`unsupported demo: ${result.demoName || '(missing)'}. Supported demos: spec-viewer`));
|
|
803
|
+
}
|
|
804
|
+
if (positional.length > 0) {
|
|
805
|
+
throw new Error(formatError('demo create spec-viewer does not accept positional target paths; use --dir <target-dir>'));
|
|
806
|
+
}
|
|
313
807
|
} else {
|
|
314
808
|
if (positional.length > 0) {
|
|
315
809
|
result.targetDir = positional.shift();
|
|
@@ -340,6 +834,43 @@ function runCommand(command, args, options = {}) {
|
|
|
340
834
|
});
|
|
341
835
|
}
|
|
342
836
|
|
|
837
|
+
function copyPackageFallback(packageRoot, tempRoot) {
|
|
838
|
+
const fallbackDir = path.join(tempRoot, 'package-fallback');
|
|
839
|
+
const ignoredRoots = new Set([
|
|
840
|
+
'.git',
|
|
841
|
+
'.worktrees',
|
|
842
|
+
'examples',
|
|
843
|
+
'package-lock.json',
|
|
844
|
+
'tests',
|
|
845
|
+
]);
|
|
846
|
+
const ignoredPrefixes = [
|
|
847
|
+
'scripts/ci',
|
|
848
|
+
'specs/quiver-v01',
|
|
849
|
+
'specs/quiver-v02-bootstrap-hardening',
|
|
850
|
+
'specs/quiver-v03-adoption-verification',
|
|
851
|
+
'specs/quiver-v04-zero-friction-installation',
|
|
852
|
+
];
|
|
853
|
+
|
|
854
|
+
fs.cpSync(packageRoot, fallbackDir, {
|
|
855
|
+
recursive: true,
|
|
856
|
+
filter: (sourcePath) => {
|
|
857
|
+
const relativePath = relativePosixPath(packageRoot, sourcePath);
|
|
858
|
+
if (!relativePath || relativePath === '.') {
|
|
859
|
+
return true;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
const firstSegment = relativePath.split('/')[0];
|
|
863
|
+
if (ignoredRoots.has(firstSegment) || ignoredRoots.has(relativePath)) {
|
|
864
|
+
return false;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
return !ignoredPrefixes.some((prefix) => relativePath === prefix || relativePath.startsWith(`${prefix}/`));
|
|
868
|
+
},
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
return fallbackDir;
|
|
872
|
+
}
|
|
873
|
+
|
|
343
874
|
function packTemplate(packageRoot, tempRoot) {
|
|
344
875
|
const packDir = path.join(tempRoot, 'pack');
|
|
345
876
|
const extractDir = path.join(tempRoot, 'extract');
|
|
@@ -349,24 +880,32 @@ function packTemplate(packageRoot, tempRoot) {
|
|
|
349
880
|
fs.mkdirSync(extractDir, { recursive: true });
|
|
350
881
|
fs.mkdirSync(npmCache, { recursive: true });
|
|
351
882
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
883
|
+
try {
|
|
884
|
+
const packOutput = runCommand('npm', ['pack', '--json', '--pack-destination', packDir], {
|
|
885
|
+
cwd: packageRoot,
|
|
886
|
+
env: {
|
|
887
|
+
...process.env,
|
|
888
|
+
npm_config_cache: npmCache,
|
|
889
|
+
},
|
|
890
|
+
});
|
|
359
891
|
|
|
360
|
-
|
|
361
|
-
|
|
892
|
+
const packInfo = JSON.parse(packOutput.trim());
|
|
893
|
+
const tarballPath = path.join(packDir, packInfo[0].filename);
|
|
362
894
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
895
|
+
if (!fs.existsSync(tarballPath)) {
|
|
896
|
+
throw new Error(formatError(`pack output not found at ${tarballPath}`));
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
runCommand('tar', ['-xzf', tarballPath, '-C', extractDir]);
|
|
366
900
|
|
|
367
|
-
|
|
901
|
+
return path.join(extractDir, 'package');
|
|
902
|
+
} catch (error) {
|
|
903
|
+
if (error && error.code === 'ENOENT') {
|
|
904
|
+
return copyPackageFallback(packageRoot, tempRoot);
|
|
905
|
+
}
|
|
368
906
|
|
|
369
|
-
|
|
907
|
+
throw error;
|
|
908
|
+
}
|
|
370
909
|
}
|
|
371
910
|
|
|
372
911
|
function ensureDir(dirPath) {
|
|
@@ -385,6 +924,10 @@ function copyTemplate(templateRoot, targetDir) {
|
|
|
385
924
|
return docsTemplateDir;
|
|
386
925
|
}
|
|
387
926
|
|
|
927
|
+
function exportTemplatesToLegacyRoot(templateRoot, targetDir) {
|
|
928
|
+
return copyTemplate(templateRoot, targetDir);
|
|
929
|
+
}
|
|
930
|
+
|
|
388
931
|
function mergeDirectoryTree(sourceDir, targetDir) {
|
|
389
932
|
if (!fs.existsSync(sourceDir)) {
|
|
390
933
|
return;
|
|
@@ -399,12 +942,22 @@ function mergeDirectoryTree(sourceDir, targetDir) {
|
|
|
399
942
|
});
|
|
400
943
|
}
|
|
401
944
|
|
|
402
|
-
function runInitDocs(repoRoot, projectName) {
|
|
945
|
+
function runInitDocs(repoRoot, projectName, options = {}) {
|
|
946
|
+
const templateRoot = options.templateRoot
|
|
947
|
+
? { path: options.templateRoot }
|
|
948
|
+
: resolveTemplateRoot(repoRoot, {
|
|
949
|
+
packageRoot: path.resolve(__dirname, '../..'),
|
|
950
|
+
});
|
|
951
|
+
|
|
403
952
|
initializeProjectDocs({
|
|
404
953
|
projectRoot: repoRoot,
|
|
405
954
|
projectName,
|
|
406
955
|
cliVersion: CLI_VERSION,
|
|
956
|
+
includeTemplates: options.includeTemplates === true,
|
|
957
|
+
legacyScripts: options.legacyScripts === true,
|
|
407
958
|
migrateMode: false,
|
|
959
|
+
profile: options.profile || 'default',
|
|
960
|
+
templateRoot: templateRoot.path,
|
|
408
961
|
});
|
|
409
962
|
}
|
|
410
963
|
|
|
@@ -426,6 +979,10 @@ function assertFilesExist(root, relativePaths) {
|
|
|
426
979
|
}
|
|
427
980
|
|
|
428
981
|
function assertExecutablesExist(root, relativePaths) {
|
|
982
|
+
if (process.platform === 'win32') {
|
|
983
|
+
return [];
|
|
984
|
+
}
|
|
985
|
+
|
|
429
986
|
return relativePaths.filter((relativePath) => {
|
|
430
987
|
const absolutePath = path.join(root, relativePath);
|
|
431
988
|
|
|
@@ -472,6 +1029,43 @@ function escapeMarkdownCell(value) {
|
|
|
472
1029
|
return String(value).replace(/\|/g, '\\|');
|
|
473
1030
|
}
|
|
474
1031
|
|
|
1032
|
+
function summarizeSkippedPaths(scan) {
|
|
1033
|
+
const details = Array.isArray(scan.skipped_path_details) && scan.skipped_path_details.length > 0
|
|
1034
|
+
? scan.skipped_path_details
|
|
1035
|
+
: (Array.isArray(scan.skipped_paths) ? scan.skipped_paths.map((item) => ({ reason: 'excluded path', path: item })) : []);
|
|
1036
|
+
const counts = new Map();
|
|
1037
|
+
const dependencySegments = new Set(['node_modules', '.pnpm-store', '.npm', '.yarn']);
|
|
1038
|
+
const outputSegments = new Set(['dist', 'build', 'coverage', 'out', 'tmp', 'temp', 'cache', '.cache', '.turbo', '.next', '.nuxt', '.parcel-cache', 'generated', 'gen', 'artifacts', 'reports', 'vendor', 'target']);
|
|
1039
|
+
|
|
1040
|
+
for (const item of details) {
|
|
1041
|
+
const reason = item.reason || 'excluded path';
|
|
1042
|
+
let label = reason;
|
|
1043
|
+
if (reason === 'env-file') {
|
|
1044
|
+
label = 'env files';
|
|
1045
|
+
} else if (reason === 'git-metadata') {
|
|
1046
|
+
label = 'git metadata';
|
|
1047
|
+
} else if (reason === 'hidden-directory') {
|
|
1048
|
+
label = 'hidden directories';
|
|
1049
|
+
} else if (reason.startsWith('secret-file:')) {
|
|
1050
|
+
label = 'secret files';
|
|
1051
|
+
} else if (reason.startsWith('unsafe-segment:')) {
|
|
1052
|
+
const segment = reason.slice('unsafe-segment:'.length);
|
|
1053
|
+
if (segment === '.quiver') {
|
|
1054
|
+
label = 'local AI state';
|
|
1055
|
+
} else if (dependencySegments.has(segment)) {
|
|
1056
|
+
label = 'dependency folders';
|
|
1057
|
+
} else if (outputSegments.has(segment)) {
|
|
1058
|
+
label = 'generated/output/cache folders';
|
|
1059
|
+
} else {
|
|
1060
|
+
label = segment;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
counts.set(label, (counts.get(label) || 0) + 1);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
return Array.from(counts.entries()).map(([reason, count]) => ({ reason, count }));
|
|
1067
|
+
}
|
|
1068
|
+
|
|
475
1069
|
function collectPackageManagers(projectRoot) {
|
|
476
1070
|
const packageManagerField = readJsonIfExists(path.join(projectRoot, 'package.json'))?.packageManager;
|
|
477
1071
|
|
|
@@ -499,6 +1093,7 @@ function collectPackageManagers(projectRoot) {
|
|
|
499
1093
|
function collectProjectFiles(projectRoot, maxDepth = 2) {
|
|
500
1094
|
const files = [];
|
|
501
1095
|
const skippedPaths = [];
|
|
1096
|
+
const skippedPathDetails = [];
|
|
502
1097
|
const ignoredDirs = new Set([
|
|
503
1098
|
'.git',
|
|
504
1099
|
'node_modules',
|
|
@@ -515,6 +1110,12 @@ function collectProjectFiles(projectRoot, maxDepth = 2) {
|
|
|
515
1110
|
]);
|
|
516
1111
|
const allowedHiddenDirs = new Set(['.github', '.vscode', '.devcontainer']);
|
|
517
1112
|
|
|
1113
|
+
function skipPath(relativePath, reason) {
|
|
1114
|
+
const normalized = relativePath.split(path.sep).join('/');
|
|
1115
|
+
skippedPaths.push(normalized);
|
|
1116
|
+
skippedPathDetails.push({ path: normalized, reason });
|
|
1117
|
+
}
|
|
1118
|
+
|
|
518
1119
|
function walk(currentDir, depth, relativeDir = '') {
|
|
519
1120
|
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
520
1121
|
|
|
@@ -524,12 +1125,18 @@ function collectProjectFiles(projectRoot, maxDepth = 2) {
|
|
|
524
1125
|
|
|
525
1126
|
if (entry.isDirectory()) {
|
|
526
1127
|
if (ignoredDirs.has(entry.name)) {
|
|
527
|
-
|
|
1128
|
+
skipPath(entryRelativePath, `unsafe-segment:${entry.name}`);
|
|
1129
|
+
continue;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
const directoryReason = getContextPathExclusionReason(entryRelativePath);
|
|
1133
|
+
if (directoryReason) {
|
|
1134
|
+
skipPath(entryRelativePath, directoryReason);
|
|
528
1135
|
continue;
|
|
529
1136
|
}
|
|
530
1137
|
|
|
531
1138
|
if (entry.name.startsWith('.') && !allowedHiddenDirs.has(entry.name)) {
|
|
532
|
-
|
|
1139
|
+
skipPath(entryRelativePath, 'hidden-directory');
|
|
533
1140
|
continue;
|
|
534
1141
|
}
|
|
535
1142
|
|
|
@@ -540,13 +1147,19 @@ function collectProjectFiles(projectRoot, maxDepth = 2) {
|
|
|
540
1147
|
continue;
|
|
541
1148
|
}
|
|
542
1149
|
|
|
1150
|
+
const fileReason = getContextPathExclusionReason(entryRelativePath);
|
|
1151
|
+
if (fileReason) {
|
|
1152
|
+
skipPath(entryRelativePath, fileReason);
|
|
1153
|
+
continue;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
543
1156
|
files.push(entryRelativePath);
|
|
544
1157
|
}
|
|
545
1158
|
}
|
|
546
1159
|
|
|
547
1160
|
walk(projectRoot, 0);
|
|
548
1161
|
|
|
549
|
-
return { files, skippedPaths };
|
|
1162
|
+
return { files, skipped_path_details: skippedPathDetails, skippedPaths };
|
|
550
1163
|
}
|
|
551
1164
|
|
|
552
1165
|
function collectRootEntries(projectRoot) {
|
|
@@ -594,6 +1207,7 @@ function collectLanguageSignals(files) {
|
|
|
594
1207
|
}
|
|
595
1208
|
|
|
596
1209
|
const languages = [];
|
|
1210
|
+
const seenLanguages = new Set();
|
|
597
1211
|
const extToLanguage = new Map([
|
|
598
1212
|
['.ts', 'typescript'],
|
|
599
1213
|
['.tsx', 'typescript'],
|
|
@@ -619,14 +1233,90 @@ function collectLanguageSignals(files) {
|
|
|
619
1233
|
]);
|
|
620
1234
|
|
|
621
1235
|
for (const [ext, language] of extToLanguage.entries()) {
|
|
622
|
-
if (extensions.has(ext)) {
|
|
1236
|
+
if (extensions.has(ext) && !seenLanguages.has(language)) {
|
|
623
1237
|
languages.push(language);
|
|
1238
|
+
seenLanguages.add(language);
|
|
624
1239
|
}
|
|
625
1240
|
}
|
|
626
1241
|
|
|
627
1242
|
return languages;
|
|
628
1243
|
}
|
|
629
1244
|
|
|
1245
|
+
function parseCreateQuiverScriptCommand(command) {
|
|
1246
|
+
const normalized = String(command || '').trim();
|
|
1247
|
+
const match = normalized.match(/^npx\s+create-quiver(?:@[^\s]+)?\s+(.+)$/);
|
|
1248
|
+
if (!match) {
|
|
1249
|
+
return null;
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
const tokens = match[1].split(/\s+/).filter(Boolean);
|
|
1253
|
+
if (tokens.length === 0) {
|
|
1254
|
+
return null;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
return {
|
|
1258
|
+
commandName: tokens[0],
|
|
1259
|
+
subcommand: tokens[1] || '',
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function findUnsupportedCreateQuiverScripts(scripts = {}) {
|
|
1264
|
+
const unsupported = [];
|
|
1265
|
+
|
|
1266
|
+
for (const [scriptName, command] of Object.entries(scripts)) {
|
|
1267
|
+
const parsed = parseCreateQuiverScriptCommand(command);
|
|
1268
|
+
if (!parsed) {
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
if (!SUPPORTED_COMMAND_MODES.has(parsed.commandName)) {
|
|
1273
|
+
unsupported.push({
|
|
1274
|
+
command,
|
|
1275
|
+
reason: `unsupported command "${parsed.commandName}"`,
|
|
1276
|
+
scriptName,
|
|
1277
|
+
});
|
|
1278
|
+
continue;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
if (parsed.commandName === 'ai' && !SUPPORTED_AI_COMMANDS.has(parsed.subcommand)) {
|
|
1282
|
+
unsupported.push({
|
|
1283
|
+
command,
|
|
1284
|
+
reason: `unsupported ai subcommand "${parsed.subcommand || '(missing)'}"`,
|
|
1285
|
+
scriptName,
|
|
1286
|
+
});
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
if (parsed.commandName === 'spec' && !SUPPORTED_SPEC_COMMANDS.has(parsed.subcommand)) {
|
|
1291
|
+
unsupported.push({
|
|
1292
|
+
command,
|
|
1293
|
+
reason: `unsupported spec subcommand "${parsed.subcommand || '(missing)'}"`,
|
|
1294
|
+
scriptName,
|
|
1295
|
+
});
|
|
1296
|
+
continue;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
if (parsed.commandName === 'demo' && !SUPPORTED_DEMO_COMMANDS.has(parsed.subcommand)) {
|
|
1300
|
+
unsupported.push({
|
|
1301
|
+
command,
|
|
1302
|
+
reason: `unsupported demo subcommand "${parsed.subcommand || '(missing)'}"`,
|
|
1303
|
+
scriptName,
|
|
1304
|
+
});
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
return unsupported;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
function detectNodeProject(files, rootEntries, packageJson, languages) {
|
|
1312
|
+
const hasPackageJson = Boolean(packageJson);
|
|
1313
|
+
const hasJavaScriptSignals = languages.some((language) => language === 'javascript' || language === 'typescript');
|
|
1314
|
+
const hasSourceDirectories = detectSourceDirectories(rootEntries).length > 0;
|
|
1315
|
+
const hasSourceFiles = files.some((file) => /\.(?:c|m)?jsx?$/i.test(file) || /\.(?:c|m)?tsx?$/i.test(file));
|
|
1316
|
+
|
|
1317
|
+
return hasJavaScriptSignals && (hasPackageJson || hasSourceDirectories || hasSourceFiles);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
630
1320
|
function collectWorkspaces(packageJson) {
|
|
631
1321
|
if (!packageJson) {
|
|
632
1322
|
return [];
|
|
@@ -756,6 +1446,11 @@ function detectFrameworks(projectRoot, files, rootEntries, packageJson) {
|
|
|
756
1446
|
evidence.push({ framework: 'react', signals: ['react', 'typescript files'] });
|
|
757
1447
|
}
|
|
758
1448
|
|
|
1449
|
+
if (frameworks.length === 0 && detectNodeProject(files, rootEntries, packageJson, languages)) {
|
|
1450
|
+
frameworks.push('node');
|
|
1451
|
+
evidence.push({ framework: 'node', signals: ['package.json', 'javascript or typescript source files'] });
|
|
1452
|
+
}
|
|
1453
|
+
|
|
759
1454
|
const primary = frameworks[0] || 'unknown';
|
|
760
1455
|
|
|
761
1456
|
return {
|
|
@@ -850,7 +1545,7 @@ function detectRisks(projectRoot, scan) {
|
|
|
850
1545
|
function buildProjectScan(projectRoot) {
|
|
851
1546
|
const packageJson = readJsonIfExists(path.join(projectRoot, 'package.json'));
|
|
852
1547
|
const rootEntries = collectRootEntries(projectRoot);
|
|
853
|
-
const { files, skippedPaths } = collectProjectFiles(projectRoot);
|
|
1548
|
+
const { files, skippedPaths, skipped_path_details } = collectProjectFiles(projectRoot);
|
|
854
1549
|
const topLevelDirectories = rootEntries.filter((entry) => entry.type === 'directory' && !entry.name.startsWith('.')).map((entry) => entry.name);
|
|
855
1550
|
const sourceDirectories = detectSourceDirectories(rootEntries);
|
|
856
1551
|
const configFiles = detectConfigFiles(rootEntries);
|
|
@@ -908,6 +1603,7 @@ function buildProjectScan(projectRoot) {
|
|
|
908
1603
|
},
|
|
909
1604
|
risks: [],
|
|
910
1605
|
skipped_paths: skippedPaths,
|
|
1606
|
+
skipped_path_details,
|
|
911
1607
|
};
|
|
912
1608
|
|
|
913
1609
|
scan.risks = detectRisks(projectRoot, scan);
|
|
@@ -931,8 +1627,8 @@ function renderProjectMap(scan) {
|
|
|
931
1627
|
'docs/INDEX.md',
|
|
932
1628
|
'docs/AI_CONTEXT.md',
|
|
933
1629
|
'docs/DECISIONS.md',
|
|
934
|
-
|
|
935
|
-
|
|
1630
|
+
CURRENT_SCAN_RELATIVE_PATH,
|
|
1631
|
+
PROJECT_MAP_RELATIVE_PATH,
|
|
936
1632
|
'docs/AI_ONBOARDING_PROMPT.md',
|
|
937
1633
|
'docs/CONTEXTO.md',
|
|
938
1634
|
'docs/WORKFLOW.md',
|
|
@@ -952,8 +1648,7 @@ function renderProjectMap(scan) {
|
|
|
952
1648
|
'README.md',
|
|
953
1649
|
'docs/INDEX.md',
|
|
954
1650
|
'docs/AI_CONTEXT.md',
|
|
955
|
-
|
|
956
|
-
'docs/PROJECT_MAP.md',
|
|
1651
|
+
PROJECT_MAP_RELATIVE_PATH,
|
|
957
1652
|
hasDecisionLog ? 'docs/DECISIONS.md' : 'docs/DECISIONS.md (create with migrate if missing)',
|
|
958
1653
|
'docs/CONTEXTO.md',
|
|
959
1654
|
'docs/WORKFLOW.md',
|
|
@@ -993,7 +1688,7 @@ function renderProjectMap(scan) {
|
|
|
993
1688
|
lines.push('## Entry Points');
|
|
994
1689
|
lines.push(`- Project overview: ${scan.docs.has_readme ? 'README.md' : 'docs/CONTEXTO.md'}`);
|
|
995
1690
|
lines.push(`- AI context: ${hasDecisionLog ? 'docs/AI_CONTEXT.md + docs/DECISIONS.md' : 'docs/AI_CONTEXT.md'}`);
|
|
996
|
-
lines.push(
|
|
1691
|
+
lines.push(`- Analysis outputs: ${CURRENT_SCAN_RELATIVE_PATH}, ${PROJECT_MAP_RELATIVE_PATH}`);
|
|
997
1692
|
lines.push(`- Workflow contract: docs/WORKFLOW.md`);
|
|
998
1693
|
lines.push(`- Spec contract: specs/${projectSlug}/SPEC.md`);
|
|
999
1694
|
if (sourceDirs.length > 0) {
|
|
@@ -1025,7 +1720,7 @@ function renderProjectMap(scan) {
|
|
|
1025
1720
|
}
|
|
1026
1721
|
|
|
1027
1722
|
const relevantScripts = Object.entries(scan.commands.scripts)
|
|
1028
|
-
.filter(([name]) => /(^|:)(analyze|doctor|migrate|test|build|lint|dev|start|check)(:|$)|analyze|doctor|migrate|test|build|lint|dev|start|check/i.test(name))
|
|
1723
|
+
.filter(([name]) => /(^|:)(analyze|doctor|migrate|validate|test|build|lint|dev|start|check)(:|$)|analyze|doctor|migrate|validate|test|build|lint|dev|start|check/i.test(name))
|
|
1029
1724
|
.slice(0, 12);
|
|
1030
1725
|
|
|
1031
1726
|
if (relevantScripts.length > 0) {
|
|
@@ -1085,9 +1780,10 @@ function renderProjectMap(scan) {
|
|
|
1085
1780
|
|
|
1086
1781
|
lines.push('');
|
|
1087
1782
|
lines.push('## Skipped Paths');
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1783
|
+
const skippedSummaries = summarizeSkippedPaths(scan);
|
|
1784
|
+
if (skippedSummaries.length > 0) {
|
|
1785
|
+
for (const skippedPath of skippedSummaries) {
|
|
1786
|
+
lines.push(`- ${skippedPath.reason}: ${skippedPath.count}`);
|
|
1091
1787
|
}
|
|
1092
1788
|
} else {
|
|
1093
1789
|
lines.push('- None');
|
|
@@ -1095,10 +1791,8 @@ function renderProjectMap(scan) {
|
|
|
1095
1791
|
|
|
1096
1792
|
lines.push('');
|
|
1097
1793
|
lines.push('## Do Not Read First');
|
|
1098
|
-
if (
|
|
1099
|
-
|
|
1100
|
-
lines.push(`- ${skippedPath}`);
|
|
1101
|
-
}
|
|
1794
|
+
if (skippedSummaries.length > 0) {
|
|
1795
|
+
lines.push('- Hidden, generated, secret, and cache paths are excluded from the analysis scan.');
|
|
1102
1796
|
} else {
|
|
1103
1797
|
lines.push('- None detected, but still prioritize docs and config files before source trees.');
|
|
1104
1798
|
}
|
|
@@ -1108,16 +1802,13 @@ function renderProjectMap(scan) {
|
|
|
1108
1802
|
}
|
|
1109
1803
|
|
|
1110
1804
|
function writeProjectScanArtifacts(projectRoot, scan) {
|
|
1111
|
-
const
|
|
1112
|
-
ensureDir(
|
|
1805
|
+
const scanPaths = projectScanPaths(projectRoot);
|
|
1806
|
+
ensureDir(path.dirname(scanPaths.projectMapPath));
|
|
1113
1807
|
|
|
1114
|
-
const jsonPath =
|
|
1115
|
-
|
|
1808
|
+
const jsonPath = writeProjectScanJson(projectRoot, scan);
|
|
1809
|
+
fs.writeFileSync(scanPaths.projectMapPath, `${renderProjectMap(scan)}\n`);
|
|
1116
1810
|
|
|
1117
|
-
|
|
1118
|
-
fs.writeFileSync(mdPath, `${renderProjectMap(scan)}\n`);
|
|
1119
|
-
|
|
1120
|
-
return { jsonPath, mdPath };
|
|
1811
|
+
return { jsonPath, mdPath: scanPaths.projectMapPath };
|
|
1121
1812
|
}
|
|
1122
1813
|
|
|
1123
1814
|
function runAnalyze(targetDir) {
|
|
@@ -1129,11 +1820,13 @@ function runAnalyze(targetDir) {
|
|
|
1129
1820
|
|
|
1130
1821
|
const scan = buildProjectScan(projectRoot);
|
|
1131
1822
|
const artifacts = writeProjectScanArtifacts(projectRoot, scan);
|
|
1823
|
+
const aiContextPath = refreshAiContextDoc(projectRoot, scan);
|
|
1132
1824
|
updateStateForAnalyze(projectRoot, CLI_VERSION);
|
|
1133
1825
|
|
|
1134
1826
|
console.log(`Project analysis completed for ${projectRoot}`);
|
|
1135
1827
|
console.log(`Wrote ${relativePosixPath(projectRoot, artifacts.jsonPath)}`);
|
|
1136
1828
|
console.log(`Wrote ${relativePosixPath(projectRoot, artifacts.mdPath)}`);
|
|
1829
|
+
console.log(`Wrote ${relativePosixPath(projectRoot, aiContextPath)}`);
|
|
1137
1830
|
console.log(`Detected primary stack: ${scan.stack.primary}`);
|
|
1138
1831
|
console.log(`Detected package manager: ${scan.project.package_manager}`);
|
|
1139
1832
|
}
|
|
@@ -1153,6 +1846,7 @@ function runMigrate(targetDir, options = {}) {
|
|
|
1153
1846
|
const projectName = packageJson.name || path.basename(projectRoot) || 'Quiver Project';
|
|
1154
1847
|
const packageRoot = path.resolve(__dirname, '../..');
|
|
1155
1848
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'quiver-migrate-'));
|
|
1849
|
+
const legacyLayout = inspectLegacyMigrationLayout(projectRoot);
|
|
1156
1850
|
|
|
1157
1851
|
try {
|
|
1158
1852
|
const templateRoot = packTemplate(packageRoot, tempRoot);
|
|
@@ -1161,7 +1855,10 @@ function runMigrate(targetDir, options = {}) {
|
|
|
1161
1855
|
projectRoot,
|
|
1162
1856
|
projectName,
|
|
1163
1857
|
cliVersion: CLI_VERSION,
|
|
1858
|
+
legacyScripts: true,
|
|
1164
1859
|
migrateMode: true,
|
|
1860
|
+
profile: 'full',
|
|
1861
|
+
templateRoot,
|
|
1165
1862
|
});
|
|
1166
1863
|
updateStateForMigrate(projectRoot, projectName, CLI_VERSION);
|
|
1167
1864
|
|
|
@@ -1176,12 +1873,15 @@ function runMigrate(targetDir, options = {}) {
|
|
|
1176
1873
|
|
|
1177
1874
|
console.log(`Quiver migration completed for ${projectRoot}`);
|
|
1178
1875
|
console.log('Missing workflow files were restored without overwriting existing project files.');
|
|
1876
|
+
if (legacyLayout.hasLegacyLayout) {
|
|
1877
|
+
console.log(`Legacy layout detected and preserved: ${legacyLayout.legacyPaths.join(', ')}`);
|
|
1878
|
+
}
|
|
1179
1879
|
} finally {
|
|
1180
1880
|
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
1181
1881
|
}
|
|
1182
1882
|
}
|
|
1183
1883
|
|
|
1184
|
-
function runDoctor(targetDir) {
|
|
1884
|
+
function runDoctor(targetDir, options = {}) {
|
|
1185
1885
|
const projectRoot = resolveTargetRoot(process.cwd(), targetDir);
|
|
1186
1886
|
|
|
1187
1887
|
if (!fs.existsSync(projectRoot)) {
|
|
@@ -1192,47 +1892,53 @@ function runDoctor(targetDir) {
|
|
|
1192
1892
|
throw new Error(formatError('doctor requires a project previously initialized by Quiver.\nRun init first: npx create-quiver --name "Project Name"'));
|
|
1193
1893
|
}
|
|
1194
1894
|
|
|
1195
|
-
const
|
|
1196
|
-
if (
|
|
1197
|
-
|
|
1895
|
+
const fixPlan = buildDoctorFixPlan(projectRoot);
|
|
1896
|
+
if (options.fix) {
|
|
1897
|
+
if (options.dryRun) {
|
|
1898
|
+
console.log(formatDoctorFixPlan(fixPlan, { dryRun: true }));
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
applyDoctorFixPlan(projectRoot, fixPlan);
|
|
1903
|
+
console.log(formatDoctorFixPlan(fixPlan));
|
|
1198
1904
|
}
|
|
1199
1905
|
|
|
1200
|
-
const
|
|
1201
|
-
const
|
|
1906
|
+
const doctorReport = collectDoctorReport(projectRoot);
|
|
1907
|
+
const specSlugs = doctorReport.specSlugs;
|
|
1908
|
+
const specRequiredFiles = specSlugs.flatMap((projectSlug) => [
|
|
1909
|
+
`specs/${projectSlug}/SPEC.md`,
|
|
1910
|
+
`specs/${projectSlug}/STATUS.md`,
|
|
1911
|
+
`specs/${projectSlug}/EVIDENCE_REPORT.md`,
|
|
1912
|
+
]);
|
|
1913
|
+
const newLayoutRequiredFiles = [
|
|
1202
1914
|
'AGENTS.md',
|
|
1203
1915
|
'README.md',
|
|
1204
|
-
'docs/INDEX.md',
|
|
1205
1916
|
'docs/AI_CONTEXT.md',
|
|
1206
1917
|
'docs/AI_ONBOARDING_PROMPT.md',
|
|
1207
|
-
'docs/
|
|
1918
|
+
'docs/COMMANDS.md',
|
|
1208
1919
|
'docs/WORKFLOW.md',
|
|
1209
|
-
'docs/SUPPORT_MATRIX.md',
|
|
1210
|
-
'docs/TROUBLESHOOTING.md',
|
|
1211
|
-
'docs/TESTING_GUIDE_FOR_AI.md',
|
|
1212
|
-
'docs/ai/PRINCIPLES.md',
|
|
1213
|
-
'docs/ai/RULES.yaml',
|
|
1214
|
-
'docs/ai/LESSONS.md',
|
|
1215
|
-
`specs/${projectSlug}/SPEC.md`,
|
|
1216
|
-
`specs/${projectSlug}/STATUS.md`,
|
|
1217
|
-
`specs/${projectSlug}/EVIDENCE_REPORT.md`,
|
|
1218
1920
|
'package.json',
|
|
1219
|
-
'.
|
|
1220
|
-
'.
|
|
1221
|
-
'.
|
|
1222
|
-
|
|
1223
|
-
];
|
|
1224
|
-
|
|
1225
|
-
const requiredExecutables = [
|
|
1226
|
-
'tools/scripts/start-slice.sh',
|
|
1227
|
-
'tools/scripts/check-slice-readiness.sh',
|
|
1228
|
-
'tools/scripts/check-pr-readiness.sh',
|
|
1229
|
-
'tools/scripts/cleanup-slice.sh',
|
|
1230
|
-
'tools/scripts/check-scope.sh',
|
|
1921
|
+
'.quiver/state.json',
|
|
1922
|
+
'.quiver/config.json',
|
|
1923
|
+
'.quiver/.gitignore',
|
|
1924
|
+
...specRequiredFiles,
|
|
1231
1925
|
];
|
|
1232
|
-
|
|
1926
|
+
const requiredFiles = doctorReport.layout === 'legacy'
|
|
1927
|
+
? ['package.json', ...specRequiredFiles]
|
|
1928
|
+
: newLayoutRequiredFiles;
|
|
1929
|
+
const legacyScriptsDir = path.join(projectRoot, 'tools', 'scripts');
|
|
1930
|
+
const requiredExecutables = fs.existsSync(legacyScriptsDir)
|
|
1931
|
+
? [
|
|
1932
|
+
'tools/scripts/start-slice.sh',
|
|
1933
|
+
'tools/scripts/check-slice-readiness.sh',
|
|
1934
|
+
'tools/scripts/check-pr-readiness.sh',
|
|
1935
|
+
'tools/scripts/cleanup-slice.sh',
|
|
1936
|
+
'tools/scripts/check-scope.sh',
|
|
1937
|
+
]
|
|
1938
|
+
: [];
|
|
1233
1939
|
const missingFiles = assertFilesExist(projectRoot, requiredFiles);
|
|
1234
1940
|
const nonExecutableScripts = assertExecutablesExist(projectRoot, requiredExecutables);
|
|
1235
|
-
const pkg = loadPackageJson(projectRoot);
|
|
1941
|
+
const pkg = fs.existsSync(path.join(projectRoot, 'package.json')) ? loadPackageJson(projectRoot) : {};
|
|
1236
1942
|
const workflowScriptGroups = [
|
|
1237
1943
|
{ label: 'migrate', node: 'quiver:migrate', legacy: 'migrate' },
|
|
1238
1944
|
{ label: 'start-slice', node: 'quiver:start-slice', legacy: 'start:slice' },
|
|
@@ -1250,8 +1956,21 @@ function runDoctor(targetDir) {
|
|
|
1250
1956
|
.map((group) => group.label);
|
|
1251
1957
|
const missingNodeNativeScripts = ['quiver:migrate', 'quiver:analyze', 'quiver:doctor']
|
|
1252
1958
|
.filter((name) => typeof pkg.scripts?.[name] !== 'string');
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1959
|
+
const missingAiScripts = [
|
|
1960
|
+
'quiver:ai:agent',
|
|
1961
|
+
'quiver:ai:onboard',
|
|
1962
|
+
'quiver:ai:plan',
|
|
1963
|
+
'quiver:ai:review-plan',
|
|
1964
|
+
'quiver:ai:approve',
|
|
1965
|
+
'quiver:ai:prompt-slice',
|
|
1966
|
+
'quiver:ai:execute-slice',
|
|
1967
|
+
'quiver:ai:execute-plan',
|
|
1968
|
+
'quiver:ai:pr',
|
|
1969
|
+
'quiver:ai:doctor',
|
|
1970
|
+
].filter((name) => typeof pkg.scripts?.[name] !== 'string');
|
|
1971
|
+
const unsupportedCreateQuiverScripts = findUnsupportedCreateQuiverScripts(pkg.scripts || {});
|
|
1972
|
+
const hasScanArtifacts = hasProjectScanArtifact(projectRoot)
|
|
1973
|
+
&& fs.existsSync(path.join(projectRoot, PROJECT_MAP_RELATIVE_PATH));
|
|
1255
1974
|
const quiverState = readState(projectRoot);
|
|
1256
1975
|
const hasQuiverState = Boolean(quiverState);
|
|
1257
1976
|
const stateWarnings = hasQuiverState ? [] : ['missing Quiver state metadata: .quiver/state.json'];
|
|
@@ -1260,24 +1979,41 @@ function runDoctor(targetDir) {
|
|
|
1260
1979
|
...nonExecutableScripts.map((file) => `missing executable bit: ${file}`),
|
|
1261
1980
|
...missingScripts.map((name) => `missing package.json script: ${name}`),
|
|
1262
1981
|
];
|
|
1263
|
-
const softWarnings =
|
|
1982
|
+
const softWarnings = doctorReport.warnings;
|
|
1264
1983
|
|
|
1265
1984
|
if (migrationProblems.length > 0) {
|
|
1266
1985
|
throw new Error(formatError(`doctor failed:\n- ${migrationProblems.join('\n- ')}\n- Run migration first: npx create-quiver migrate`));
|
|
1267
1986
|
}
|
|
1268
1987
|
|
|
1269
1988
|
console.log(`Quiver doctor passed for ${projectRoot}`);
|
|
1270
|
-
console.log(`
|
|
1989
|
+
console.log(`Layout: ${doctorReport.layout}`);
|
|
1990
|
+
if (specSlugs.length > 0) {
|
|
1991
|
+
console.log(`Specs: ${specSlugs.join(', ')}`);
|
|
1992
|
+
} else {
|
|
1993
|
+
console.log('Specs: none yet');
|
|
1994
|
+
}
|
|
1995
|
+
if (doctorReport.legacySignals.length > 0) {
|
|
1996
|
+
console.log(`Legacy signals: ${doctorReport.legacySignals.join(', ')}`);
|
|
1997
|
+
}
|
|
1271
1998
|
console.log('Next steps:');
|
|
1999
|
+
for (const recommendation of doctorReport.recommendations) {
|
|
2000
|
+
console.log(`- ${recommendation}`);
|
|
2001
|
+
}
|
|
1272
2002
|
for (const warning of stateWarnings) {
|
|
1273
2003
|
console.log(`- Warning: ${warning}`);
|
|
1274
2004
|
}
|
|
1275
2005
|
for (const scriptName of missingNodeNativeScripts) {
|
|
1276
2006
|
console.log(`- Warning: missing Node-native script: ${scriptName}`);
|
|
1277
2007
|
}
|
|
2008
|
+
for (const scriptName of missingAiScripts) {
|
|
2009
|
+
console.log(`- Warning: missing AI orchestration script: ${scriptName}`);
|
|
2010
|
+
}
|
|
1278
2011
|
if (legacyOnlyScripts.length > 0) {
|
|
1279
2012
|
console.log(`- Warning: legacy Bash workflow scripts detected for ${legacyOnlyScripts.join(', ')}. Run npx create-quiver migrate to add quiver:* npm scripts.`);
|
|
1280
2013
|
}
|
|
2014
|
+
for (const script of unsupportedCreateQuiverScripts) {
|
|
2015
|
+
console.log(`- Warning: package.json script ${script.scriptName} targets ${script.reason}: \`${script.command}\`. Update create-quiver or regenerate scripts with npx create-quiver migrate.`);
|
|
2016
|
+
}
|
|
1281
2017
|
for (const warning of softWarnings) {
|
|
1282
2018
|
console.log(`- Warning: ${warning}`);
|
|
1283
2019
|
}
|
|
@@ -1289,20 +2025,23 @@ function runDoctor(targetDir) {
|
|
|
1289
2025
|
console.log('- Ask your AI agent: Read AGENTS.md, then docs/AI_ONBOARDING_PROMPT.md and execute it.');
|
|
1290
2026
|
}
|
|
1291
2027
|
console.log('- Check the next ready slice: npx create-quiver next');
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
2028
|
+
if (specSlugs.length > 0) {
|
|
2029
|
+
const projectSlug = specSlugs[0];
|
|
2030
|
+
console.log(`- Start a slice: npx create-quiver start-slice specs/${projectSlug}/slices/<slice-id>/slice.json`);
|
|
2031
|
+
console.log(`- Validate a slice: npx create-quiver check-slice specs/${projectSlug}/slices/<slice-id>/slice.json`);
|
|
2032
|
+
console.log(`- Validate the PR gate: npx create-quiver check-pr specs/${projectSlug}/slices/<slice-id>/slice.json`);
|
|
2033
|
+
} else {
|
|
2034
|
+
console.log('- Create real specs and slices only after acceptance criteria are approved and the technical plan is reviewed and approved.');
|
|
2035
|
+
}
|
|
1295
2036
|
}
|
|
1296
2037
|
|
|
1297
2038
|
function printInitNextSteps(targetDir, projectName) {
|
|
1298
|
-
const projectSlug = toProjectSlug(projectName);
|
|
1299
|
-
|
|
1300
2039
|
console.log('');
|
|
1301
2040
|
console.log('Next steps:');
|
|
1302
|
-
console.log(`- Review AGENTS.md, then ${path.join(targetDir, 'docs', '
|
|
2041
|
+
console.log(`- Review AGENTS.md, then ${path.join(targetDir, 'docs', 'AI_ONBOARDING_PROMPT.md')}`);
|
|
1303
2042
|
console.log(`- Review ${path.join(targetDir, 'docs', 'WORKFLOW.md')}`);
|
|
1304
|
-
console.log(
|
|
1305
|
-
console.log(
|
|
2043
|
+
console.log('- Analyze the project with npx create-quiver analyze');
|
|
2044
|
+
console.log('- Create real specs and slices after acceptance criteria are approved and the technical plan is reviewed and approved.');
|
|
1306
2045
|
}
|
|
1307
2046
|
|
|
1308
2047
|
async function run(argv) {
|
|
@@ -1318,8 +2057,16 @@ async function run(argv) {
|
|
|
1318
2057
|
return;
|
|
1319
2058
|
}
|
|
1320
2059
|
|
|
2060
|
+
if (args.mode === 'flow') {
|
|
2061
|
+
await runFlow(process.cwd(), {
|
|
2062
|
+
json: args.json,
|
|
2063
|
+
});
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
|
|
1321
2067
|
if (args.mode === 'plan') {
|
|
1322
2068
|
runPlan(process.cwd(), {
|
|
2069
|
+
includeCompleted: args.includeCompleted,
|
|
1323
2070
|
json: args.json,
|
|
1324
2071
|
onlyReady: args.onlyReady,
|
|
1325
2072
|
specSlug: args.specSlug,
|
|
@@ -1328,12 +2075,170 @@ async function run(argv) {
|
|
|
1328
2075
|
return;
|
|
1329
2076
|
}
|
|
1330
2077
|
|
|
2078
|
+
if (args.mode === 'prepare') {
|
|
2079
|
+
await runPrepare(process.cwd(), {
|
|
2080
|
+
dryRun: args.dryRun,
|
|
2081
|
+
identityFile: args.aiIdentityFile || undefined,
|
|
2082
|
+
provider: args.prepareProvider || undefined,
|
|
2083
|
+
sshHostAlias: args.aiSshHostAlias || undefined,
|
|
2084
|
+
});
|
|
2085
|
+
return;
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
if (args.mode === 'ai') {
|
|
2089
|
+
if (!args.aiCommand) {
|
|
2090
|
+
throw new Error(formatError('missing ai subcommand. Use: npx create-quiver ai onboard | prepare-context | plan | review-plan | approve | approvals | agent | prompt-slice | execute-slice | execute-plan | doctor | pr'));
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
if (args.aiCommand === 'agent') {
|
|
2094
|
+
runAiAgent(process.cwd(), {
|
|
2095
|
+
command: args.aiAgentCommand,
|
|
2096
|
+
context: args.aiContext || undefined,
|
|
2097
|
+
label: args.aiLabel || undefined,
|
|
2098
|
+
model: args.aiModel || undefined,
|
|
2099
|
+
provider: args.aiProviderExplicit ? args.aiProvider : undefined,
|
|
2100
|
+
role: args.aiAgentRole || undefined,
|
|
2101
|
+
});
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
if (args.aiCommand === 'onboard') {
|
|
2106
|
+
await runOnboard(process.cwd(), {
|
|
2107
|
+
context: args.aiContext || undefined,
|
|
2108
|
+
dryRun: args.dryRun,
|
|
2109
|
+
input: args.aiInput || undefined,
|
|
2110
|
+
provider: args.aiProvider,
|
|
2111
|
+
providerExplicit: args.aiProviderExplicit,
|
|
2112
|
+
role: args.aiRole,
|
|
2113
|
+
timeout: args.aiTimeout,
|
|
2114
|
+
});
|
|
2115
|
+
return;
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
if (args.aiCommand === 'prepare-context') {
|
|
2119
|
+
await runAiPrepareContext(process.cwd(), {
|
|
2120
|
+
dryRun: args.dryRun,
|
|
2121
|
+
});
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
if (args.aiCommand === 'plan') {
|
|
2126
|
+
await runAiPlan(process.cwd(), {
|
|
2127
|
+
context: args.aiContext || undefined,
|
|
2128
|
+
dryRun: args.dryRun,
|
|
2129
|
+
input: args.aiInput || undefined,
|
|
2130
|
+
phase: args.aiPhase,
|
|
2131
|
+
provider: args.aiProvider,
|
|
2132
|
+
providerExplicit: args.aiProviderExplicit,
|
|
2133
|
+
role: args.aiRole,
|
|
2134
|
+
specSlug: args.specSlug || undefined,
|
|
2135
|
+
timeout: args.aiTimeout,
|
|
2136
|
+
});
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
if (args.aiCommand === 'review-plan') {
|
|
2141
|
+
await runAiReviewPlan(process.cwd(), {
|
|
2142
|
+
context: args.aiContext || undefined,
|
|
2143
|
+
dryRun: args.dryRun,
|
|
2144
|
+
input: args.aiInput || undefined,
|
|
2145
|
+
provider: args.aiProvider,
|
|
2146
|
+
providerExplicit: args.aiProviderExplicit,
|
|
2147
|
+
timeout: args.aiTimeout,
|
|
2148
|
+
});
|
|
2149
|
+
return;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
if (args.aiCommand === 'approve') {
|
|
2153
|
+
await runAiApprove(process.cwd(), {
|
|
2154
|
+
dryRun: args.dryRun,
|
|
2155
|
+
input: args.aiInput || undefined,
|
|
2156
|
+
phase: args.aiPhase,
|
|
2157
|
+
version: args.aiVersion || undefined,
|
|
2158
|
+
});
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
if (args.aiCommand === 'approvals' || args.aiCommand === 'approval-status') {
|
|
2163
|
+
await runAiApprovalStatus(process.cwd());
|
|
2164
|
+
return;
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
if (args.aiCommand === 'execute-slice') {
|
|
2168
|
+
await runAiExecuteSlice(process.cwd(), {
|
|
2169
|
+
allowDirty: args.aiAllowDirty,
|
|
2170
|
+
commit: args.aiCommit,
|
|
2171
|
+
context: args.aiContext || undefined,
|
|
2172
|
+
dryRun: args.dryRun,
|
|
2173
|
+
provider: args.aiProvider,
|
|
2174
|
+
providerExplicit: args.aiProviderExplicit,
|
|
2175
|
+
role: args.aiRole,
|
|
2176
|
+
slice: args.aiSlice || undefined,
|
|
2177
|
+
timeout: args.aiTimeout,
|
|
2178
|
+
});
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
if (args.aiCommand === 'prompt-slice' || args.aiCommand === 'executor-prompt') {
|
|
2183
|
+
runAiPromptSlice(process.cwd(), {
|
|
2184
|
+
slice: args.aiSlice || undefined,
|
|
2185
|
+
});
|
|
2186
|
+
return;
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
if (args.aiCommand === 'execute-plan') {
|
|
2190
|
+
await runAiExecutePlan(process.cwd(), {
|
|
2191
|
+
allowDirty: args.aiAllowDirty,
|
|
2192
|
+
commit: args.aiCommit,
|
|
2193
|
+
context: args.aiContext || undefined,
|
|
2194
|
+
dryRun: args.dryRun,
|
|
2195
|
+
execute: args.aiExecute,
|
|
2196
|
+
json: args.json,
|
|
2197
|
+
mode: args.aiExecutionMode,
|
|
2198
|
+
provider: args.aiProvider,
|
|
2199
|
+
providerExplicit: args.aiProviderExplicit,
|
|
2200
|
+
role: args.aiRole,
|
|
2201
|
+
specSlug: args.specSlug || undefined,
|
|
2202
|
+
timeout: args.aiTimeout,
|
|
2203
|
+
});
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
if (args.aiCommand === 'doctor') {
|
|
2208
|
+
await runAiDoctor(process.cwd(), {
|
|
2209
|
+
dryRun: args.dryRun,
|
|
2210
|
+
remote: args.aiRemote || undefined,
|
|
2211
|
+
sshHostAlias: args.aiSshHostAlias || undefined,
|
|
2212
|
+
identityFile: args.aiIdentityFile || undefined,
|
|
2213
|
+
});
|
|
2214
|
+
return;
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
if (args.aiCommand === 'pr') {
|
|
2218
|
+
await runAiPr(process.cwd(), {
|
|
2219
|
+
baseBranch: args.aiBaseBranch,
|
|
2220
|
+
create: args.aiCreate,
|
|
2221
|
+
dryRun: args.dryRun,
|
|
2222
|
+
input: args.aiInput || undefined,
|
|
2223
|
+
remote: args.aiRemote || undefined,
|
|
2224
|
+
sshHostAlias: args.aiSshHostAlias || undefined,
|
|
2225
|
+
identityFile: args.aiIdentityFile || undefined,
|
|
2226
|
+
title: args.aiTitle || undefined,
|
|
2227
|
+
});
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
throw new Error(formatError(`unsupported ai subcommand: ${args.aiCommand}. Supported tasks: onboard, plan, review-plan, approve, approvals, agent, prompt-slice, execute-slice, execute-plan, doctor, pr`));
|
|
2232
|
+
}
|
|
2233
|
+
|
|
1331
2234
|
if (args.mode === 'graph') {
|
|
1332
2235
|
runGraph(process.cwd(), {
|
|
1333
2236
|
format: args.format,
|
|
2237
|
+
includeCompleted: args.includeCompleted,
|
|
1334
2238
|
json: args.json,
|
|
1335
2239
|
level: args.level,
|
|
1336
2240
|
showConflicts: args.showConflicts,
|
|
2241
|
+
specSlug: args.specSlug,
|
|
1337
2242
|
unicode: args.unicode,
|
|
1338
2243
|
});
|
|
1339
2244
|
return;
|
|
@@ -1343,37 +2248,66 @@ async function run(argv) {
|
|
|
1343
2248
|
await runNext(process.cwd(), {
|
|
1344
2249
|
allReady: args.allReady,
|
|
1345
2250
|
autoStart: args.autoStart,
|
|
2251
|
+
includeCompleted: args.includeCompleted,
|
|
1346
2252
|
json: args.json,
|
|
1347
2253
|
specSlug: args.specSlug,
|
|
1348
2254
|
});
|
|
1349
2255
|
return;
|
|
1350
2256
|
}
|
|
1351
2257
|
|
|
2258
|
+
if (args.mode === 'evidence') {
|
|
2259
|
+
const result = runEvidence(process.cwd(), {
|
|
2260
|
+
command: args.evidenceArgs,
|
|
2261
|
+
maxOutput: args.evidenceMaxOutput || undefined,
|
|
2262
|
+
output: args.evidenceOutput || undefined,
|
|
2263
|
+
subcommand: args.evidenceCommand,
|
|
2264
|
+
});
|
|
2265
|
+
process.exitCode = result.exitCode;
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
if (args.mode === 'demo') {
|
|
2270
|
+
const demoTarget = resolveTargetRoot(process.cwd(), args.targetDirExplicit ? args.targetDir : 'quiver-spec-viewer');
|
|
2271
|
+
runDemo({
|
|
2272
|
+
command: args.demoCommand,
|
|
2273
|
+
demo: args.demoName,
|
|
2274
|
+
dryRun: args.dryRun,
|
|
2275
|
+
targetRoot: demoTarget,
|
|
2276
|
+
});
|
|
2277
|
+
return;
|
|
2278
|
+
}
|
|
2279
|
+
|
|
1352
2280
|
if (args.mode === 'migrate') {
|
|
1353
2281
|
runMigrate(args.targetDir, { skipInstall: args.skipInstall });
|
|
1354
2282
|
return;
|
|
1355
2283
|
}
|
|
1356
2284
|
|
|
1357
2285
|
if (args.mode === 'doctor') {
|
|
1358
|
-
runDoctor(args.targetDir
|
|
2286
|
+
runDoctor(args.targetDir, {
|
|
2287
|
+
dryRun: args.dryRun,
|
|
2288
|
+
fix: args.doctorFix,
|
|
2289
|
+
});
|
|
1359
2290
|
return;
|
|
1360
2291
|
}
|
|
1361
2292
|
|
|
1362
2293
|
if (args.mode === 'start-slice') {
|
|
1363
|
-
startSlice(
|
|
2294
|
+
startSlice(args.targetDir, { allowDraft: args.allowDraft });
|
|
1364
2295
|
return;
|
|
1365
2296
|
}
|
|
1366
2297
|
|
|
1367
2298
|
if (args.mode === 'check-slice') {
|
|
1368
|
-
checkSliceReadiness(
|
|
2299
|
+
checkSliceReadiness(args.targetDir, {
|
|
2300
|
+
baseBranch: args.baseBranchExplicit ? args.aiBaseBranch : '',
|
|
1369
2301
|
gate: args.gate,
|
|
2302
|
+
local: args.checkSliceLocal,
|
|
2303
|
+
remote: args.aiRemote,
|
|
1370
2304
|
strictOverlap: args.strictOverlap,
|
|
1371
2305
|
});
|
|
1372
2306
|
return;
|
|
1373
2307
|
}
|
|
1374
2308
|
|
|
1375
2309
|
if (args.mode === 'check-pr') {
|
|
1376
|
-
checkPrReadiness(
|
|
2310
|
+
checkPrReadiness(args.targetDir);
|
|
1377
2311
|
return;
|
|
1378
2312
|
}
|
|
1379
2313
|
|
|
@@ -1397,7 +2331,7 @@ async function run(argv) {
|
|
|
1397
2331
|
}
|
|
1398
2332
|
|
|
1399
2333
|
if (args.mode === 'cleanup-slice') {
|
|
1400
|
-
cleanupSlice(
|
|
2334
|
+
cleanupSlice(args.targetDir, {
|
|
1401
2335
|
closeBaseline: args.closeBaseline,
|
|
1402
2336
|
discard: args.discard,
|
|
1403
2337
|
dryRun: args.dryRun,
|
|
@@ -1407,7 +2341,7 @@ async function run(argv) {
|
|
|
1407
2341
|
}
|
|
1408
2342
|
|
|
1409
2343
|
if (args.mode === 'check-scope') {
|
|
1410
|
-
checkScope(
|
|
2344
|
+
checkScope(args.targetDir, { strict: args.strict });
|
|
1411
2345
|
return;
|
|
1412
2346
|
}
|
|
1413
2347
|
|
|
@@ -1417,17 +2351,81 @@ async function run(argv) {
|
|
|
1417
2351
|
return;
|
|
1418
2352
|
}
|
|
1419
2353
|
|
|
2354
|
+
if (args.mode === 'spec') {
|
|
2355
|
+
if (args.specCommand === 'create') {
|
|
2356
|
+
runCreateSpec(process.cwd(), {
|
|
2357
|
+
dryRun: args.dryRun,
|
|
2358
|
+
input: args.aiInput || undefined,
|
|
2359
|
+
specSlug: args.specSlug || undefined,
|
|
2360
|
+
});
|
|
2361
|
+
return;
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
if (!args.targetDir || args.targetDir === '.') {
|
|
2365
|
+
throw new Error(formatError('missing spec directory. Use: npx create-quiver spec <start|status|close> <spec-dir>'));
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
if (args.specCommand === 'start') {
|
|
2369
|
+
const report = startSpecWorktree(process.cwd(), args.targetDir);
|
|
2370
|
+
process.stdout.write(formatSpecStartResult(report));
|
|
2371
|
+
return;
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
if (args.specCommand === 'status') {
|
|
2375
|
+
const report = buildSpecStatus(process.cwd(), args.targetDir);
|
|
2376
|
+
process.stdout.write(formatSpecStatus(report));
|
|
2377
|
+
return;
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
if (args.specCommand === 'close') {
|
|
2381
|
+
const report = closeSpecWorktree(process.cwd(), args.targetDir, {
|
|
2382
|
+
baseBranch: args.aiBaseBranch,
|
|
2383
|
+
discard: args.discard,
|
|
2384
|
+
dryRun: args.dryRun,
|
|
2385
|
+
force: args.force,
|
|
2386
|
+
remote: args.aiRemote,
|
|
2387
|
+
});
|
|
2388
|
+
process.stdout.write(formatSpecCloseResult(report));
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
throw new Error(formatError(`unsupported spec subcommand: ${args.specCommand}. Supported tasks: create, start, status, close`));
|
|
2393
|
+
}
|
|
2394
|
+
|
|
1420
2395
|
const packageRoot = path.resolve(__dirname, '../..');
|
|
1421
2396
|
const targetDir = resolveTargetRoot(process.cwd(), args.targetDir);
|
|
1422
2397
|
const projectName = args.projectName || path.basename(targetDir) || 'Quiver Project';
|
|
2398
|
+
const initLayout = buildInitLayout(targetDir, {
|
|
2399
|
+
compatibilityAlias: !args.explicitInit,
|
|
2400
|
+
dryRun: args.dryRun,
|
|
2401
|
+
full: args.initFull,
|
|
2402
|
+
includeTemplates: args.initIncludeTemplates,
|
|
2403
|
+
legacyScripts: args.initLegacyScripts,
|
|
2404
|
+
minimal: args.initMinimal,
|
|
2405
|
+
projectName,
|
|
2406
|
+
skipInstall: args.skipInstall,
|
|
2407
|
+
});
|
|
2408
|
+
|
|
2409
|
+
if (args.dryRun) {
|
|
2410
|
+
console.log(formatInitLayoutPlan(initLayout));
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
|
|
1423
2414
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'quiver-create-'));
|
|
1424
2415
|
|
|
1425
2416
|
try {
|
|
1426
2417
|
ensureDir(targetDir);
|
|
1427
2418
|
|
|
1428
2419
|
const templateRoot = packTemplate(packageRoot, tempRoot);
|
|
1429
|
-
|
|
1430
|
-
|
|
2420
|
+
if (initLayout.profile === 'full') {
|
|
2421
|
+
exportTemplatesToLegacyRoot(templateRoot, targetDir);
|
|
2422
|
+
}
|
|
2423
|
+
runInitDocs(targetDir, projectName, {
|
|
2424
|
+
includeTemplates: args.initIncludeTemplates,
|
|
2425
|
+
legacyScripts: args.initLegacyScripts,
|
|
2426
|
+
profile: initLayout.profile,
|
|
2427
|
+
templateRoot,
|
|
2428
|
+
});
|
|
1431
2429
|
|
|
1432
2430
|
if (!args.skipInstall) {
|
|
1433
2431
|
const installResult = installSelfAsDevDep(targetDir, CLI_VERSION);
|
|
@@ -1448,6 +2446,8 @@ async function run(argv) {
|
|
|
1448
2446
|
module.exports = {
|
|
1449
2447
|
runAnalyze,
|
|
1450
2448
|
runDoctor,
|
|
2449
|
+
runFlow,
|
|
1451
2450
|
runMigrate,
|
|
2451
|
+
runPrepare,
|
|
1452
2452
|
run,
|
|
1453
2453
|
};
|