create-quiver 0.15.4 → 0.16.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.
Files changed (179) hide show
  1. package/.github/pull_request_template.md +17 -0
  2. package/.github/workflows/ci.yml +76 -0
  3. package/.markdown-link-check.json +15 -0
  4. package/.markdownlint.json +11 -0
  5. package/.quiver/runs/run-2026-06-09t19-14-39z/approvals.json +5 -0
  6. package/.quiver/runs/run-2026-06-09t19-14-39z/decisions.md +2 -0
  7. package/.quiver/runs/run-2026-06-09t19-14-39z/requirement.md +0 -0
  8. package/.quiver/runs/run-2026-06-09t19-14-39z/snapshots/20260609T191439Z/docs/INDEX.md +97 -0
  9. package/.quiver/runs/run-2026-06-09t19-14-39z/snapshots/20260609T191439Z/manifest.json +61 -0
  10. package/.quiver/runs/run-2026-06-09t19-14-39z/state.json +28 -0
  11. package/ACTIVE_SLICES.md +43 -0
  12. package/ARCHITECTURE.md +133 -0
  13. package/CHANGELOG.md +12 -0
  14. package/CONTRIBUTING.md +174 -9
  15. package/README.md +10 -1
  16. package/ROADMAP.md +4 -0
  17. package/SECURITY.md +9 -2
  18. package/auditoria-ux-ui-performance-documentacion.md +705 -0
  19. package/copys-landing-page.md +244 -0
  20. package/docs/AI_CONTEXT.md.es.template +3 -1
  21. package/docs/AI_CONTEXT.md.template +3 -1
  22. package/docs/CLI_UX_GUIDE.md +9 -1
  23. package/docs/COMMANDS.md.template +20 -6
  24. package/docs/GITFLOW_PR_GUIDE.md +73 -11
  25. package/docs/GITFLOW_PR_GUIDE.md.es.template +61 -2
  26. package/docs/GITFLOW_PR_GUIDE.md.template +72 -10
  27. package/docs/INDEX.md +1 -0
  28. package/docs/QUICK.md.template +2 -1
  29. package/docs/STANDARD.md.template +2 -1
  30. package/docs/WORKFLOW.md.es.template +3 -1
  31. package/docs/WORKFLOW.md.template +6 -4
  32. package/docs/ai/ACTIVE_SLICE.md +61 -0
  33. package/docs/getting-started/installation.md +7 -0
  34. package/docs/reference/commands.md +104 -6
  35. package/docs/reference/slice-schema.md +37 -0
  36. package/docs/schema/slice.schema.json +221 -0
  37. package/docs/specs/01-spec/01-slice/01-slice.json +36 -0
  38. package/docs/specs/01-spec/01-slice/01-slice.md +106 -0
  39. package/docs/specs/01-spec/01-slice/CLOSURE_BRIEF.md +80 -0
  40. package/docs/specs/01-spec/01-slice/EXECUTION_BRIEF.md +39 -0
  41. package/docs/specs/01-spec/02-slice/02-slice.json +36 -0
  42. package/docs/specs/01-spec/02-slice/02-slice.md +108 -0
  43. package/docs/specs/01-spec/02-slice/CLOSURE_BRIEF.md +88 -0
  44. package/docs/specs/01-spec/02-slice/EXECUTION_BRIEF.md +40 -0
  45. package/docs/specs/01-spec/03-slice/03-slice.json +36 -0
  46. package/docs/specs/01-spec/03-slice/03-slice.md +103 -0
  47. package/docs/specs/01-spec/03-slice/CLOSURE_BRIEF.md +54 -0
  48. package/docs/specs/01-spec/03-slice/EXECUTION_BRIEF.md +39 -0
  49. package/docs/specs/01-spec/04-slice/04-slice.json +36 -0
  50. package/docs/specs/01-spec/04-slice/04-slice.md +107 -0
  51. package/docs/specs/01-spec/04-slice/CLOSURE_BRIEF.md +46 -0
  52. package/docs/specs/01-spec/04-slice/EXECUTION_BRIEF.md +39 -0
  53. package/docs/specs/01-spec/05-slice/05-slice.json +36 -0
  54. package/docs/specs/01-spec/05-slice/05-slice.md +106 -0
  55. package/docs/specs/01-spec/05-slice/CLOSURE_BRIEF.md +84 -0
  56. package/docs/specs/01-spec/05-slice/EXECUTION_BRIEF.md +109 -0
  57. package/docs/specs/01-spec/06-slice/06-slice.json +36 -0
  58. package/docs/specs/01-spec/06-slice/06-slice.md +107 -0
  59. package/docs/specs/01-spec/06-slice/CLOSURE_BRIEF.md +67 -0
  60. package/docs/specs/01-spec/06-slice/EXECUTION_BRIEF.md +39 -0
  61. package/docs/specs/01-spec/07-slice/07-slice.json +36 -0
  62. package/docs/specs/01-spec/07-slice/07-slice.md +105 -0
  63. package/docs/specs/01-spec/07-slice/CLOSURE_BRIEF.md +71 -0
  64. package/docs/specs/01-spec/07-slice/EXECUTION_BRIEF.md +39 -0
  65. package/docs/specs/01-spec/08-slice/08-slice.json +36 -0
  66. package/docs/specs/01-spec/08-slice/08-slice.md +105 -0
  67. package/docs/specs/01-spec/08-slice/CLOSURE_BRIEF.md +114 -0
  68. package/docs/specs/01-spec/08-slice/EXECUTION_BRIEF.md +39 -0
  69. package/docs/specs/01-spec/CLOSURE_BRIEF.md +87 -0
  70. package/docs/specs/01-spec/spec.md +197 -0
  71. package/docs/workflows/full-ai-spec-to-pr.md +46 -3
  72. package/i18n/es/docs/GITFLOW_PR_GUIDE.md.template +38 -1
  73. package/package.json +27 -1
  74. package/pr.md +154 -0
  75. package/scripts/package-quiver.sh +82 -2
  76. package/scripts/release-quiver.sh +14 -3
  77. package/specs/[project-name]/slices/pr.md.template +19 -0
  78. package/specs/quiver-v43-cli-i18n-audit-release-readiness/command-language-mode-matrix.json +91 -0
  79. package/specs/quiver-v50-audit-trust-foundation/EVIDENCE_REPORT.md +151 -0
  80. package/specs/quiver-v50-audit-trust-foundation/EXECUTION_PLAN.md +34 -0
  81. package/specs/quiver-v50-audit-trust-foundation/SPEC.md +113 -0
  82. package/specs/quiver-v50-audit-trust-foundation/STATUS.md +26 -0
  83. package/specs/quiver-v50-audit-trust-foundation/pr.md +120 -0
  84. package/specs/quiver-v50-audit-trust-foundation/slices/slice-00-audit-baseline-and-resolved-findings/CLOSURE_BRIEF.md +20 -0
  85. package/specs/quiver-v50-audit-trust-foundation/slices/slice-00-audit-baseline-and-resolved-findings/EXECUTION_BRIEF.md +58 -0
  86. package/specs/quiver-v50-audit-trust-foundation/slices/slice-00-audit-baseline-and-resolved-findings/slice.json +57 -0
  87. package/specs/quiver-v50-audit-trust-foundation/slices/slice-01-runtime-minimum-and-package-metadata/CLOSURE_BRIEF.md +24 -0
  88. package/specs/quiver-v50-audit-trust-foundation/slices/slice-01-runtime-minimum-and-package-metadata/EXECUTION_BRIEF.md +67 -0
  89. package/specs/quiver-v50-audit-trust-foundation/slices/slice-01-runtime-minimum-and-package-metadata/slice.json +71 -0
  90. package/specs/quiver-v50-audit-trust-foundation/slices/slice-02-migrate-write-safety-contract/CLOSURE_BRIEF.md +24 -0
  91. package/specs/quiver-v50-audit-trust-foundation/slices/slice-02-migrate-write-safety-contract/EXECUTION_BRIEF.md +71 -0
  92. package/specs/quiver-v50-audit-trust-foundation/slices/slice-02-migrate-write-safety-contract/slice.json +81 -0
  93. package/specs/quiver-v50-audit-trust-foundation/slices/slice-03-security-reporting-channel/CLOSURE_BRIEF.md +22 -0
  94. package/specs/quiver-v50-audit-trust-foundation/slices/slice-03-security-reporting-channel/EXECUTION_BRIEF.md +57 -0
  95. package/specs/quiver-v50-audit-trust-foundation/slices/slice-03-security-reporting-channel/slice.json +56 -0
  96. package/specs/quiver-v50-audit-trust-foundation/slices/slice-04-user-facing-i18n-error-coverage/CLOSURE_BRIEF.md +23 -0
  97. package/specs/quiver-v50-audit-trust-foundation/slices/slice-04-user-facing-i18n-error-coverage/EXECUTION_BRIEF.md +68 -0
  98. package/specs/quiver-v50-audit-trust-foundation/slices/slice-04-user-facing-i18n-error-coverage/slice.json +84 -0
  99. package/specs/quiver-v50-audit-trust-foundation/slices/slice-05-init-analyze-progress-and-summaries/CLOSURE_BRIEF.md +25 -0
  100. package/specs/quiver-v50-audit-trust-foundation/slices/slice-05-init-analyze-progress-and-summaries/EXECUTION_BRIEF.md +73 -0
  101. package/specs/quiver-v50-audit-trust-foundation/slices/slice-05-init-analyze-progress-and-summaries/slice.json +72 -0
  102. package/specs/quiver-v50-audit-trust-foundation/slices/slice-06-contributor-and-architecture-docs/CLOSURE_BRIEF.md +22 -0
  103. package/specs/quiver-v50-audit-trust-foundation/slices/slice-06-contributor-and-architecture-docs/EXECUTION_BRIEF.md +66 -0
  104. package/specs/quiver-v50-audit-trust-foundation/slices/slice-06-contributor-and-architecture-docs/slice.json +74 -0
  105. package/specs/quiver-v50-audit-trust-foundation/slices/slice-07-ci-and-documentation-lint-baseline/CLOSURE_BRIEF.md +29 -0
  106. package/specs/quiver-v50-audit-trust-foundation/slices/slice-07-ci-and-documentation-lint-baseline/EXECUTION_BRIEF.md +74 -0
  107. package/specs/quiver-v50-audit-trust-foundation/slices/slice-07-ci-and-documentation-lint-baseline/slice.json +81 -0
  108. package/specs/quiver-v51-cli-ergonomics-automation-contracts/EVIDENCE_REPORT.md +145 -0
  109. package/specs/quiver-v51-cli-ergonomics-automation-contracts/EXECUTION_PLAN.md +32 -0
  110. package/specs/quiver-v51-cli-ergonomics-automation-contracts/SPEC.md +109 -0
  111. package/specs/quiver-v51-cli-ergonomics-automation-contracts/STATUS.md +25 -0
  112. package/specs/quiver-v51-cli-ergonomics-automation-contracts/pr.md +69 -0
  113. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-00-cli-contract-baseline/CLOSURE_BRIEF.md +20 -0
  114. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-00-cli-contract-baseline/EXECUTION_BRIEF.md +58 -0
  115. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-00-cli-contract-baseline/slice.json +56 -0
  116. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-01-flow-json-compatibility/CLOSURE_BRIEF.md +21 -0
  117. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-01-flow-json-compatibility/EXECUTION_BRIEF.md +61 -0
  118. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-01-flow-json-compatibility/slice.json +68 -0
  119. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-02-dashboard-section-validation-i18n/CLOSURE_BRIEF.md +25 -0
  120. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-02-dashboard-section-validation-i18n/EXECUTION_BRIEF.md +65 -0
  121. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-02-dashboard-section-validation-i18n/pr.md +134 -0
  122. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-02-dashboard-section-validation-i18n/slice.json +80 -0
  123. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-03-base-branch-resolution-policy/CLOSURE_BRIEF.md +31 -0
  124. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-03-base-branch-resolution-policy/EXECUTION_BRIEF.md +80 -0
  125. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-03-base-branch-resolution-policy/pr.md +159 -0
  126. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-03-base-branch-resolution-policy/slice.json +102 -0
  127. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-04-next-plan-graph-ux-edge-cases/CLOSURE_BRIEF.md +25 -0
  128. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-04-next-plan-graph-ux-edge-cases/EXECUTION_BRIEF.md +74 -0
  129. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-04-next-plan-graph-ux-edge-cases/pr.md +147 -0
  130. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-04-next-plan-graph-ux-edge-cases/slice.json +91 -0
  131. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-05-evidence-robustness-path-safety/CLOSURE_BRIEF.md +28 -0
  132. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-05-evidence-robustness-path-safety/EXECUTION_BRIEF.md +73 -0
  133. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-05-evidence-robustness-path-safety/pr.md +146 -0
  134. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-05-evidence-robustness-path-safety/slice.json +100 -0
  135. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-06-namespace-compatibility-windows-scripts/CLOSURE_BRIEF.md +36 -0
  136. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-06-namespace-compatibility-windows-scripts/EXECUTION_BRIEF.md +76 -0
  137. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-06-namespace-compatibility-windows-scripts/pr.md +155 -0
  138. package/specs/quiver-v51-cli-ergonomics-automation-contracts/slices/slice-06-namespace-compatibility-windows-scripts/slice.json +111 -0
  139. package/specs/quiver-v52-schema-docs-release-hygiene/EVIDENCE_REPORT.md +95 -0
  140. package/specs/quiver-v52-schema-docs-release-hygiene/EXECUTION_PLAN.md +31 -0
  141. package/specs/quiver-v52-schema-docs-release-hygiene/SPEC.md +107 -0
  142. package/specs/quiver-v52-schema-docs-release-hygiene/STATUS.md +22 -0
  143. package/specs/quiver-v52-schema-docs-release-hygiene/pr.md +69 -0
  144. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-00-schema-docs-release-baseline/CLOSURE_BRIEF.md +21 -0
  145. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-00-schema-docs-release-baseline/EXECUTION_BRIEF.md +60 -0
  146. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-00-schema-docs-release-baseline/slice.json +62 -0
  147. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-01-json-schema-for-slice-json/CLOSURE_BRIEF.md +34 -0
  148. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-01-json-schema-for-slice-json/EXECUTION_BRIEF.md +71 -0
  149. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-01-json-schema-for-slice-json/pr.md +146 -0
  150. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-01-json-schema-for-slice-json/slice.json +106 -0
  151. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-02-generated-cli-reference/CLOSURE_BRIEF.md +33 -0
  152. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-02-generated-cli-reference/EXECUTION_BRIEF.md +67 -0
  153. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-02-generated-cli-reference/pr.md +144 -0
  154. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-02-generated-cli-reference/slice.json +86 -0
  155. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-03-changelog-package-release-smoke-hygiene/CLOSURE_BRIEF.md +38 -0
  156. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-03-changelog-package-release-smoke-hygiene/EXECUTION_BRIEF.md +75 -0
  157. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-03-changelog-package-release-smoke-hygiene/pr.md +159 -0
  158. package/specs/quiver-v52-schema-docs-release-hygiene/slices/slice-03-changelog-package-release-smoke-hygiene/slice.json +105 -0
  159. package/src/create-quiver/commands/changelog.js +93 -0
  160. package/src/create-quiver/commands/config.js +16 -5
  161. package/src/create-quiver/commands/evidence.js +33 -2
  162. package/src/create-quiver/commands/flow.js +1 -0
  163. package/src/create-quiver/commands/graph.js +8 -2
  164. package/src/create-quiver/commands/plan.js +6 -0
  165. package/src/create-quiver/commands/spec.js +28 -13
  166. package/src/create-quiver/index.js +294 -94
  167. package/src/create-quiver/lib/ai/github.js +5 -2
  168. package/src/create-quiver/lib/ai/spec-templates.js +19 -0
  169. package/src/create-quiver/lib/cli/command-registry.js +71 -0
  170. package/src/create-quiver/lib/cli/parser.js +14 -0
  171. package/src/create-quiver/lib/evidence.js +161 -6
  172. package/src/create-quiver/lib/git.js +99 -0
  173. package/src/create-quiver/lib/i18n/messages/en.js +52 -7
  174. package/src/create-quiver/lib/i18n/messages/es.js +54 -9
  175. package/src/create-quiver/lib/init-docs.js +1 -1
  176. package/src/create-quiver/lib/init-layout.js +9 -8
  177. package/src/create-quiver/lib/lifecycle.js +24 -26
  178. package/src/create-quiver/lib/readiness.js +67 -56
  179. package/src/create-quiver/lib/spec-worktrees.js +16 -34
@@ -3,7 +3,7 @@ const os = require('node:os');
3
3
  const path = require('node:path');
4
4
  const { spawnSync } = require('node:child_process');
5
5
 
6
- const { currentBranch, hasRemote, isCleanWorktree } = require('../git');
6
+ const { currentBranch, hasRemote, isCleanWorktree, resolveBaseBranchName } = require('../git');
7
7
  const { createTranslator } = require('../i18n/catalog');
8
8
  const { parseJsonWithComments } = require('../json');
9
9
  const { formatActionableError } = require('../actionable-error');
@@ -510,7 +510,10 @@ function buildPrCreateArgs(plan) {
510
510
  function buildPrCreatePlan(repoRoot, preflightReport, options = {}) {
511
511
  const prBody = readPrBody(repoRoot, options.prBodyPath || options.input);
512
512
  ensureNoOpenSlicesForPrBody(repoRoot, prBody.path);
513
- const baseBranch = String(options.baseBranch || 'main').trim() || 'main';
513
+ const baseBranch = resolveBaseBranchName(repoRoot, {
514
+ explicitBaseBranch: options.baseBranch,
515
+ remote: preflightReport.remote || DEFAULT_REMOTE,
516
+ });
514
517
  const title = String(options.title || '').trim() || extractPrTitle(prBody.body, preflightReport.branchName);
515
518
  const plan = {
516
519
  baseBranch,
@@ -289,6 +289,25 @@ function buildPrMarkdown(manifest) {
289
289
  '',
290
290
  'Generate the spec foundation, slice-00, implementation slices, execution plan, and PR body from the approved planning input.',
291
291
  '',
292
+ '## PR Policy',
293
+ '',
294
+ '- [ ] One slice only.',
295
+ '- [ ] Grouped PR exception: at most 2-3 slices, all docs-only, research-only, or low-risk mechanical cleanup.',
296
+ '- [ ] No behavior changes in a grouped PR.',
297
+ '- [ ] No mixed docs with UI, backend, refactor, or performance work.',
298
+ '- [ ] Separate evidence for each included slice.',
299
+ '- [ ] Whole PR is revertible without leaving partial state.',
300
+ '',
301
+ 'Individual PR required when the slice includes functional code, UI/UX, Supabase, Edge Functions, auth, storage, preview, performance/code-splitting, refactors, or tests/CI changes that affect gates.',
302
+ '',
303
+ '### Merge Policy',
304
+ '',
305
+ '- [ ] Human merge expected.',
306
+ '- [ ] Assisted auto-merge explicitly authorized for this PR or documented category.',
307
+ '- [ ] Assisted auto-merge conditions met: docs-only or chore-only, low risk, no runtime changes, no production configuration changes, green checks, and no pending comments.',
308
+ '',
309
+ 'Assisted auto-merge is prohibited for UI, Supabase, Edge Functions, auth, storage, preview, performance, refactors, and changes with doubtful rollback.',
310
+ '',
292
311
  '## Scope',
293
312
  '',
294
313
  '- `SPEC.md`',
@@ -0,0 +1,71 @@
1
+ const SUPPORTED_COMMAND_MODES = new Set([
2
+ 'init',
3
+ 'version',
4
+ 'changelog',
5
+ 'flow',
6
+ 'dashboard',
7
+ 'plan',
8
+ 'graph',
9
+ 'next',
10
+ 'doctor',
11
+ 'prepare',
12
+ 'analyze',
13
+ 'migrate',
14
+ 'slice',
15
+ 'handoff',
16
+ 'start-slice',
17
+ 'check-slice',
18
+ 'check-pr',
19
+ 'check-handoff',
20
+ 'new-handoff',
21
+ 'cleanup-slice',
22
+ 'check-scope',
23
+ 'config',
24
+ 'refresh-active-slices',
25
+ 'spec',
26
+ 'evidence',
27
+ 'demo',
28
+ 'ai',
29
+ ]);
30
+
31
+ const SUPPORTED_AI_COMMANDS = new Set([
32
+ 'active-slice',
33
+ 'agent',
34
+ 'approve',
35
+ 'approval-status',
36
+ 'approvals',
37
+ 'doctor',
38
+ 'execute-plan',
39
+ 'execute-slice',
40
+ 'executor-prompt',
41
+ 'export',
42
+ 'inspect',
43
+ 'onboard',
44
+ 'plan',
45
+ 'prepare-context',
46
+ 'pr',
47
+ 'prompt-slice',
48
+ 'repair-plan',
49
+ 'review-plan',
50
+ 'revise',
51
+ 'resume',
52
+ 'run',
53
+ 'slices',
54
+ 'specs',
55
+ 'status',
56
+ 'trace',
57
+ ]);
58
+
59
+ const SUPPORTED_SPEC_COMMANDS = new Set(['close', 'create', 'start', 'status', 'validate']);
60
+ const SUPPORTED_DEMO_COMMANDS = new Set(['create']);
61
+ const SUPPORTED_CONFIG_SECTIONS = new Set(['language']);
62
+ const SUPPORTED_CONFIG_LANGUAGE_COMMANDS = new Set(['show', 'set']);
63
+
64
+ module.exports = {
65
+ SUPPORTED_AI_COMMANDS,
66
+ SUPPORTED_COMMAND_MODES,
67
+ SUPPORTED_CONFIG_LANGUAGE_COMMANDS,
68
+ SUPPORTED_CONFIG_SECTIONS,
69
+ SUPPORTED_DEMO_COMMANDS,
70
+ SUPPORTED_SPEC_COMMANDS,
71
+ };
@@ -0,0 +1,14 @@
1
+ function parseCliArgs(argv, options = {}) {
2
+ const legacyParseArgs = options.legacyParseArgs;
3
+ if (typeof legacyParseArgs !== 'function') {
4
+ throw new TypeError('parseCliArgs requires a legacyParseArgs adapter');
5
+ }
6
+
7
+ return legacyParseArgs(argv, {
8
+ language: options.language,
9
+ });
10
+ }
11
+
12
+ module.exports = {
13
+ parseCliArgs,
14
+ };
@@ -3,6 +3,23 @@ const path = require('path');
3
3
  const { spawnSync } = require('node:child_process');
4
4
 
5
5
  const DEFAULT_OUTPUT_LIMIT = 4000;
6
+ const SIGNAL_NUMBERS = {
7
+ SIGHUP: 1,
8
+ SIGINT: 2,
9
+ SIGQUIT: 3,
10
+ SIGILL: 4,
11
+ SIGTRAP: 5,
12
+ SIGABRT: 6,
13
+ SIGBUS: 7,
14
+ SIGFPE: 8,
15
+ SIGKILL: 9,
16
+ SIGUSR1: 10,
17
+ SIGSEGV: 11,
18
+ SIGUSR2: 12,
19
+ SIGPIPE: 13,
20
+ SIGALRM: 14,
21
+ SIGTERM: 15,
22
+ };
6
23
 
7
24
  function redactSecrets(text) {
8
25
  return String(text || '')
@@ -40,6 +57,83 @@ function defaultEvidencePath(repoRoot, startedAt = new Date()) {
40
57
  return path.join(repoRoot, '.quiver', 'evidence', `evidence-${stamp}.md`);
41
58
  }
42
59
 
60
+ function isPathInside(parentPath, childPath) {
61
+ const relative = path.relative(parentPath, childPath);
62
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
63
+ }
64
+
65
+ function realpathExistingAncestor(targetPath) {
66
+ let current = targetPath;
67
+ while (!fs.existsSync(current)) {
68
+ const next = path.dirname(current);
69
+ if (next === current) {
70
+ return fs.realpathSync(current);
71
+ }
72
+ current = next;
73
+ }
74
+ return fs.realpathSync(current);
75
+ }
76
+
77
+ function assertSafeProjectPath(repoRoot, targetPath, label = 'evidence path') {
78
+ const rootPath = path.resolve(repoRoot);
79
+ const rootReal = fs.realpathSync(rootPath);
80
+ const resolved = path.resolve(rootPath, targetPath);
81
+ const ancestorReal = realpathExistingAncestor(resolved);
82
+ const pathLooksInsideRoot = isPathInside(rootPath, resolved) || isPathInside(rootReal, resolved);
83
+
84
+ if (!pathLooksInsideRoot || !isPathInside(rootReal, ancestorReal)) {
85
+ throw new Error(`create-quiver: ${label} must stay inside the project root.`);
86
+ }
87
+
88
+ return resolved;
89
+ }
90
+
91
+ function resolveEvidenceOutputPath(repoRoot, outputPath, startedAtDate = new Date()) {
92
+ const resolved = outputPath
93
+ ? assertSafeProjectPath(repoRoot, outputPath, 'evidence output path')
94
+ : defaultEvidencePath(repoRoot, startedAtDate);
95
+ const directory = path.dirname(resolved);
96
+
97
+ if (fs.existsSync(resolved) && fs.lstatSync(resolved).isSymbolicLink()) {
98
+ throw new Error('create-quiver: evidence output path cannot be a symlink.');
99
+ }
100
+
101
+ fs.mkdirSync(directory, { recursive: true });
102
+ const rootReal = fs.realpathSync(repoRoot);
103
+ const directoryReal = fs.realpathSync(directory);
104
+ if (!isPathInside(rootReal, directoryReal)) {
105
+ throw new Error('create-quiver: evidence output path must stay inside the project root.');
106
+ }
107
+
108
+ return resolved;
109
+ }
110
+
111
+ function resolveEvidenceReadPath(repoRoot, evidencePath) {
112
+ if (!evidencePath) {
113
+ throw new Error('create-quiver: evidence show requires an evidence file path.');
114
+ }
115
+
116
+ const resolved = assertSafeProjectPath(repoRoot, evidencePath, 'evidence read path');
117
+ if (!fs.existsSync(resolved)) {
118
+ throw new Error(`create-quiver: evidence file not found: ${evidencePath}`);
119
+ }
120
+
121
+ const rootReal = fs.realpathSync(repoRoot);
122
+ const fileReal = fs.realpathSync(resolved);
123
+ if (!isPathInside(rootReal, fileReal)) {
124
+ throw new Error('create-quiver: evidence read path must stay inside the project root.');
125
+ }
126
+
127
+ return resolved;
128
+ }
129
+
130
+ function signalExitCode(signal) {
131
+ if (!signal) {
132
+ return null;
133
+ }
134
+ return 128 + (SIGNAL_NUMBERS[signal] || 0) || 1;
135
+ }
136
+
43
137
  function renderEvidenceMarkdown(record) {
44
138
  return `# Quiver Evidence
45
139
 
@@ -48,6 +142,7 @@ function renderEvidenceMarkdown(record) {
48
142
  - Duration ms: ${record.duration_ms}
49
143
  - Started at: ${record.started_at}
50
144
  - Finished at: ${record.finished_at}
145
+ - Signal: ${record.signal || '-'}
51
146
  - Output truncated: ${record.output_truncated ? 'yes' : 'no'}
52
147
 
53
148
  ## Stdout
@@ -66,10 +161,11 @@ ${record.stderr || ''}
66
161
 
67
162
  function runEvidenceCommand(repoRoot, commandArgs, options = {}) {
68
163
  if (!Array.isArray(commandArgs) || commandArgs.length === 0) {
69
- throw new Error('create-quiver: evidence run requires a command after --');
164
+ throw new Error(options.missingCommandMessage || 'create-quiver: evidence run requires a command after --');
70
165
  }
71
166
 
72
167
  const startedAtDate = new Date();
168
+ const outputPath = resolveEvidenceOutputPath(repoRoot, options.outputPath, startedAtDate);
73
169
  const started = Date.now();
74
170
  const result = (options.spawnSync || spawnSync)(commandArgs[0], commandArgs.slice(1), {
75
171
  cwd: repoRoot,
@@ -78,7 +174,8 @@ function runEvidenceCommand(repoRoot, commandArgs, options = {}) {
78
174
  });
79
175
  const finishedAtDate = new Date();
80
176
  const duration = Date.now() - started;
81
- const exitCode = typeof result.status === 'number' ? result.status : 1;
177
+ const signal = result.signal || '';
178
+ const exitCode = typeof result.status === 'number' ? result.status : (signalExitCode(signal) || 1);
82
179
  const stdout = truncateText(redactSecrets(result.stdout || ''), options.maxOutput || DEFAULT_OUTPUT_LIMIT);
83
180
  const stderr = truncateText(redactSecrets(result.stderr || result.error?.message || ''), options.maxOutput || DEFAULT_OUTPUT_LIMIT);
84
181
  const record = {
@@ -87,15 +184,12 @@ function runEvidenceCommand(repoRoot, commandArgs, options = {}) {
87
184
  exit_code: exitCode,
88
185
  finished_at: finishedAtDate.toISOString(),
89
186
  output_truncated: stdout.truncated || stderr.truncated,
187
+ signal,
90
188
  stderr: stderr.text,
91
189
  stdout: stdout.text,
92
190
  started_at: startedAtDate.toISOString(),
93
191
  };
94
- const outputPath = options.outputPath
95
- ? path.resolve(repoRoot, options.outputPath)
96
- : defaultEvidencePath(repoRoot, startedAtDate);
97
192
 
98
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
99
193
  fs.writeFileSync(outputPath, renderEvidenceMarkdown(record));
100
194
 
101
195
  return {
@@ -105,11 +199,72 @@ function runEvidenceCommand(repoRoot, commandArgs, options = {}) {
105
199
  };
106
200
  }
107
201
 
202
+ function parseEvidenceMarkdown(content) {
203
+ const text = String(content || '');
204
+ const field = (label) => {
205
+ const match = text.match(new RegExp(`^- ${label}: (.*)$`, 'm'));
206
+ return match ? match[1].trim() : '';
207
+ };
208
+ const rawExitCode = field('Exit code');
209
+ const rawDuration = field('Duration ms');
210
+
211
+ return {
212
+ command: field('Command').replace(/^`|`$/g, ''),
213
+ duration_ms: Number.isFinite(Number(rawDuration)) ? Number(rawDuration) : null,
214
+ exit_code: Number.isFinite(Number(rawExitCode)) ? Number(rawExitCode) : null,
215
+ finished_at: field('Finished at'),
216
+ output_truncated: field('Output truncated') === 'yes',
217
+ signal: field('Signal') === '-' ? '' : field('Signal'),
218
+ started_at: field('Started at'),
219
+ };
220
+ }
221
+
222
+ function listEvidenceFiles(repoRoot) {
223
+ const evidenceDir = path.join(repoRoot, '.quiver', 'evidence');
224
+ if (!fs.existsSync(evidenceDir)) {
225
+ return [];
226
+ }
227
+
228
+ const rootReal = fs.realpathSync(repoRoot);
229
+ const dirReal = fs.realpathSync(evidenceDir);
230
+ if (!isPathInside(rootReal, dirReal)) {
231
+ throw new Error('create-quiver: evidence directory must stay inside the project root.');
232
+ }
233
+
234
+ return fs.readdirSync(evidenceDir)
235
+ .filter((entry) => entry.endsWith('.md'))
236
+ .sort()
237
+ .map((entry) => {
238
+ const filePath = path.join(evidenceDir, entry);
239
+ const content = fs.readFileSync(resolveEvidenceReadPath(repoRoot, filePath), 'utf8');
240
+ return {
241
+ path: path.relative(repoRoot, filePath).split(path.sep).join('/'),
242
+ ...parseEvidenceMarkdown(content),
243
+ };
244
+ });
245
+ }
246
+
247
+ function showEvidenceFile(repoRoot, evidencePath) {
248
+ const resolved = resolveEvidenceReadPath(repoRoot, evidencePath);
249
+ const content = fs.readFileSync(resolved, 'utf8');
250
+ return {
251
+ content,
252
+ path: path.relative(repoRoot, resolved).split(path.sep).join('/'),
253
+ record: parseEvidenceMarkdown(content),
254
+ };
255
+ }
256
+
108
257
  module.exports = {
109
258
  DEFAULT_OUTPUT_LIMIT,
110
259
  defaultEvidencePath,
260
+ listEvidenceFiles,
261
+ parseEvidenceMarkdown,
111
262
  redactSecrets,
112
263
  renderEvidenceMarkdown,
264
+ resolveEvidenceOutputPath,
265
+ resolveEvidenceReadPath,
113
266
  runEvidenceCommand,
267
+ showEvidenceFile,
268
+ signalExitCode,
114
269
  truncateText,
115
270
  };
@@ -2,6 +2,8 @@ const cp = require('child_process');
2
2
  const fs = require('fs');
3
3
  const path = require('path');
4
4
 
5
+ const DEFAULT_BASE_BRANCH_CANDIDATES = ['main', 'master', 'develop'];
6
+
5
7
  function runGit(args, cwd, options = {}) {
6
8
  return cp.execFileSync('git', args, {
7
9
  cwd,
@@ -123,6 +125,98 @@ function hasRemote(repoRoot, remoteName = 'origin') {
123
125
  return remoteList(repoRoot).includes(remoteName);
124
126
  }
125
127
 
128
+ function normalizeBranchName(value) {
129
+ return String(value || '').trim();
130
+ }
131
+
132
+ function remoteHeadBranch(repoRoot, remote = 'origin') {
133
+ const value = tryGit(['symbolic-ref', '--quiet', '--short', `refs/remotes/${remote}/HEAD`], repoRoot);
134
+ const prefix = `${remote}/`;
135
+ return value.startsWith(prefix) ? value.slice(prefix.length) : '';
136
+ }
137
+
138
+ function uniqueBaseCandidates(candidates) {
139
+ const seen = new Set();
140
+ return candidates.filter((candidate) => {
141
+ const branch = normalizeBranchName(candidate.branch);
142
+ if (!branch || seen.has(branch)) {
143
+ return false;
144
+ }
145
+ seen.add(branch);
146
+ candidate.branch = branch;
147
+ return true;
148
+ });
149
+ }
150
+
151
+ function buildBaseBranchCandidates(repoRoot, options = {}) {
152
+ const remote = options.remote || 'origin';
153
+ const explicitBaseBranch = normalizeBranchName(options.explicitBaseBranch);
154
+ const preferredBaseBranch = normalizeBranchName(options.preferredBaseBranch);
155
+ const defaults = Array.isArray(options.defaultBranches) && options.defaultBranches.length > 0
156
+ ? options.defaultBranches
157
+ : DEFAULT_BASE_BRANCH_CANDIDATES;
158
+
159
+ if (explicitBaseBranch) {
160
+ return [{ branch: explicitBaseBranch, source: '--base', explicit: true }];
161
+ }
162
+
163
+ return uniqueBaseCandidates([
164
+ preferredBaseBranch ? { branch: preferredBaseBranch, source: options.preferredSource || 'slice.git.base_branch', explicit: false } : null,
165
+ { branch: remoteHeadBranch(repoRoot, remote), source: 'remote HEAD', explicit: false },
166
+ ...defaults.map((branch) => ({ branch, source: 'fallback', explicit: false })),
167
+ ].filter(Boolean));
168
+ }
169
+
170
+ function resolveBaseRef(repoRoot, options = {}) {
171
+ const remote = options.remote || 'origin';
172
+ const candidates = buildBaseBranchCandidates(repoRoot, options);
173
+
174
+ for (const candidate of candidates) {
175
+ if (remote && hasRemoteBranch(repoRoot, candidate.branch, remote)) {
176
+ return {
177
+ baseBranch: candidate.branch,
178
+ baseRef: `${remote}/${candidate.branch}`,
179
+ candidates,
180
+ explicit: candidate.explicit,
181
+ remote,
182
+ source: candidate.source,
183
+ };
184
+ }
185
+ if (hasLocalBranch(repoRoot, candidate.branch)) {
186
+ return {
187
+ baseBranch: candidate.branch,
188
+ baseRef: candidate.branch,
189
+ candidates,
190
+ explicit: candidate.explicit,
191
+ remote: '',
192
+ source: candidate.source,
193
+ };
194
+ }
195
+ }
196
+
197
+ if (options.missingOk === true) {
198
+ const first = candidates[0] || { branch: '', source: 'fallback', explicit: false };
199
+ return {
200
+ baseBranch: first.branch,
201
+ baseRef: '',
202
+ candidates,
203
+ explicit: first.explicit,
204
+ remote: '',
205
+ source: first.source,
206
+ };
207
+ }
208
+
209
+ throw new Error(`create-quiver: missing base branch. Tried: ${candidates.map((candidate) => candidate.branch).join(', ') || '(none)'}.`);
210
+ }
211
+
212
+ function resolveBaseBranchName(repoRoot, options = {}) {
213
+ const resolution = resolveBaseRef(repoRoot, {
214
+ ...options,
215
+ missingOk: true,
216
+ });
217
+ return resolution.baseBranch || DEFAULT_BASE_BRANCH_CANDIDATES[0];
218
+ }
219
+
126
220
  function isCleanWorktree(repoRoot) {
127
221
  return Boolean(repoRoot && fs.existsSync(repoRoot) && isGitWorktree(repoRoot) && statusPorcelain(repoRoot) === '');
128
222
  }
@@ -195,8 +289,10 @@ function catFileExists(repoRoot, specRef) {
195
289
 
196
290
  module.exports = {
197
291
  branchDelete,
292
+ buildBaseBranchCandidates,
198
293
  catFileExists,
199
294
  currentBranch,
295
+ DEFAULT_BASE_BRANCH_CANDIDATES,
200
296
  fetchBranch,
201
297
  fetchRemote,
202
298
  hasLocalBranch,
@@ -211,7 +307,10 @@ module.exports = {
211
307
  isGitWorktree,
212
308
  isLinkedWorktree,
213
309
  revListCount,
310
+ remoteHeadBranch,
214
311
  remoteList,
312
+ resolveBaseBranchName,
313
+ resolveBaseRef,
215
314
  runGit,
216
315
  statusPorcelain,
217
316
  tryGit,
@@ -13,7 +13,9 @@ module.exports = {
13
13
  },
14
14
  groupTitles: {},
15
15
  commandDescriptions: {},
16
- optionDescriptions: {},
16
+ optionDescriptions: {
17
+ 'Show one human dashboard section': 'Show one human dashboard section (overview, specs, slices, blockers, warnings, agents, approvals, runs, active-slice, next-steps)',
18
+ },
17
19
  },
18
20
  'common.command.help': 'Run: npx create-quiver --help',
19
21
  'common.language.current': 'Language: {language}',
@@ -28,6 +30,9 @@ module.exports = {
28
30
  'common.unknown': 'unknown',
29
31
  'common.warning': 'Warning: {message}',
30
32
  'common.yes': 'yes',
33
+ 'config.error.unsupported_language': 'unsupported language: {language}. Supported languages: {supported}. Run: npx create-quiver config language set {fallback}',
34
+ 'config.error.unsupported_language_command': 'unsupported config language command: {command}. Supported commands: show, set',
35
+ 'config.error.unsupported_section': 'unsupported config section: {section}. Supported sections: language',
31
36
  'ai_task.command': 'Command: {command}',
32
37
  'ai_task.context_pack': 'Context pack: {context}',
33
38
  'ai_task.documentation_debt': 'Documentation debt: {count}',
@@ -320,6 +325,14 @@ module.exports = {
320
325
  'analyze.detected_package_manager': 'Detected package manager: {manager}',
321
326
  'analyze.detected_primary_stack': 'Detected primary stack: {stack}',
322
327
  'analyze.dry_run_for': 'Project analysis dry-run for {path}',
328
+ 'analyze.progress.artifacts_written': 'Analysis artifacts written',
329
+ 'analyze.progress.context_refreshed': 'AI context refreshed',
330
+ 'analyze.progress.refreshing_context': 'Refreshing AI context...',
331
+ 'analyze.progress.scanned': 'Project scan completed',
332
+ 'analyze.progress.scanning': 'Scanning project...',
333
+ 'analyze.progress.state_updated': 'Analysis state updated',
334
+ 'analyze.progress.updating_state': 'Updating Quiver state...',
335
+ 'analyze.progress.writing_artifacts': 'Writing analysis artifacts...',
323
336
  'analyze.would_refresh': 'Would refresh {path}',
324
337
  'analyze.would_write': 'Would write {path}',
325
338
  'analyze.writes_none': 'Writes: none',
@@ -352,7 +365,11 @@ module.exports = {
352
365
  'demo.title.created': 'Quiver demo created',
353
366
  'demo.title.dry_run': 'Quiver demo dry-run',
354
367
  'evidence.command': 'Command: {command}',
368
+ 'evidence.error.missing_command': 'evidence run requires a command after --',
369
+ 'evidence.error.missing_subcommand': 'missing evidence subcommand. Use: npx create-quiver evidence <run|list|show>',
355
370
  'evidence.exit_code': 'Exit code: {code}',
371
+ 'evidence.list.empty': 'No evidence files found.',
372
+ 'evidence.list.title': 'Quiver evidence files',
356
373
  'evidence.output': 'Output: {path}',
357
374
  'evidence.recorded': 'Quiver evidence recorded',
358
375
  'init.agent_guidance.show.hint': 'Does not store credentials or execute providers',
@@ -379,6 +396,14 @@ module.exports = {
379
396
  'init.next_steps.review_agents': 'Review AGENTS.md, then {path}',
380
397
  'init.next_steps.review_workflow': 'Review {path}',
381
398
  'init.next_steps.title': 'Next steps:',
399
+ 'init.progress.docs_written': 'Init docs written',
400
+ 'init.progress.exporting_templates': 'Exporting compatibility templates...',
401
+ 'init.progress.install_checked': 'Package install checked',
402
+ 'init.progress.installing_package': 'Checking create-quiver package install...',
403
+ 'init.progress.preparing_templates': 'Preparing packaged templates...',
404
+ 'init.progress.templates_exported': 'Compatibility templates exported',
405
+ 'init.progress.templates_ready': 'Packaged templates ready',
406
+ 'init.progress.writing_docs': 'Writing init docs...',
382
407
  'init.profile.default.hint': 'Recommended AI-first contract',
383
408
  'init.profile.full.hint': 'Includes historical compatibility and visible templates',
384
409
  'init.profile.minimal.hint': 'Only essential documents',
@@ -396,6 +421,9 @@ module.exports = {
396
421
  'init.summary.project': 'Project',
397
422
  'init.summary.title': 'Selected configuration',
398
423
  'migrate.completed_for': 'Quiver migration completed for {path}',
424
+ 'migrate.confirm.declined': 'migrate canceled. No files were written.',
425
+ 'migrate.confirm.prompt': 'This command will modify project files under {path}. Run `npx create-quiver migrate --dry-run` to preview. Continue?',
426
+ 'migrate.confirm.required': 'migrate writes require confirmation before modifying project files. Run `npx create-quiver migrate --dry-run` to preview, or pass `--yes` to continue in automation.',
399
427
  'migrate.dry_run_title': 'Quiver migration dry-run',
400
428
  'migrate.legacy_preserved': 'Legacy layout detected and preserved: {paths}',
401
429
  'migrate.next_command': 'Next command: {command}',
@@ -462,7 +490,9 @@ module.exports = {
462
490
  'flow.stage.technical-plan-stale': 'technical plan needs revision',
463
491
  'flow.suggested_sequence': 'Suggested sequence',
464
492
  'flow.title': 'Quiver guided flow',
493
+ 'graph.empty.level': 'No slices found for graph level {level}.',
465
494
  'graph.empty.pending': 'No pending slices found.',
495
+ 'graph.error.unsupported_format': 'unsupported graph format: {format}',
466
496
  'graph.level': 'Level {level}',
467
497
  'graph.lots_count': {
468
498
  one: '{count} lot',
@@ -494,6 +524,10 @@ module.exports = {
494
524
  'plan.header.status': 'STATUS',
495
525
  'plan.header.ticket': 'TICKET',
496
526
  'plan.header.title': 'TITLE',
527
+ 'plan.missing_estimates_note': {
528
+ one: 'Note: {count} slice has no positive estimated_hours and is counted as 0h.',
529
+ other: 'Note: {count} slices have no positive estimated_hours and are counted as 0h.',
530
+ },
497
531
  'plan.title': 'Quiver plan',
498
532
  'plan.title.including_completed': 'Quiver plan (including completed)',
499
533
  'plan.title.ready': 'Ready slices',
@@ -665,11 +699,11 @@ module.exports = {
665
699
  'lifecycle.cleanup.dry_run.branch': 'DRY RUN: git branch {flag} {branch}',
666
700
  'lifecycle.cleanup.dry_run.slice': 'DRY RUN: slice={slice} branch={branch}',
667
701
  'lifecycle.cleanup.dry_run.worktree': 'DRY RUN: git worktree remove {force}{path}',
668
- 'lifecycle.cleanup.error.branch': 'normal cleanup must run from develop. Current branch: {branch}',
669
- 'lifecycle.cleanup.error.develop_stale': 'local develop is not up to date. Run git pull --ff-only before cleanup.',
702
+ 'lifecycle.cleanup.error.branch': 'normal cleanup must run from {base}. Current branch: {branch}',
703
+ 'lifecycle.cleanup.error.base_stale': 'local {base} is not up to date with {ref}. Run git pull --ff-only before cleanup.',
670
704
  'lifecycle.cleanup.error.dirty': 'the current checkout is not clean. Clean it before cleanup.',
671
705
  'lifecycle.cleanup.error.missing': "no worktree or local branch exists for '{slice}'.",
672
- 'lifecycle.cleanup.error.unmerged': "branch '{branch}' is not merged into origin/develop. Use --discard if the slice is intentionally discarded.",
706
+ 'lifecycle.cleanup.error.unmerged': "branch '{branch}' is not merged into {ref}. Use --discard if the slice is intentionally discarded.",
673
707
  'lifecycle.cleanup.finished': "PASS: Cleanup completed for '{slice}'.",
674
708
  'lifecycle.cleanup.removed_active_slice': 'PASS: ACTIVE_SLICE.md removed',
675
709
  'lifecycle.cleanup.removed_branch': 'PASS: Local branch removed: {branch}',
@@ -724,15 +758,15 @@ module.exports = {
724
758
  'readiness.pr.branch.pass': 'PASS: Current branch matches the slice branch declaration.',
725
759
  'readiness.pr.case.pass': 'PASS: At least one documented use case.',
726
760
  'readiness.pr.clean.pass': 'PASS: Worktree is clean.',
727
- 'readiness.pr.commits.pass': 'PASS: Branch has own commits against origin/develop.',
728
- 'readiness.pr.error.absorbed': 'The branch was already absorbed by origin/develop. This gate applies before merge.',
761
+ 'readiness.pr.commits.pass': 'PASS: Branch has own commits against {ref}.',
762
+ 'readiness.pr.error.absorbed': 'The branch was already absorbed by {ref}. This gate applies before merge.',
729
763
  'readiness.pr.error.dirty': 'The worktree is not clean. Close the implementation before opening the PR.',
730
764
  'readiness.pr.error.missing_branch': 'Missing git.branch_name in the slice.',
731
765
  'readiness.pr.error.missing_pr': 'Missing pr.md next to the slice.',
732
766
  'readiness.pr.error.missing_section': "Missing required section '{heading}' in pr.md.",
733
767
  'readiness.pr.error.missing_subsection': "Missing subsection '{subheading}' inside How to Test.",
734
768
  'readiness.pr.error.no_case': 'How to Test must include at least one documented use case (#### Case 1: ...).',
735
- 'readiness.pr.error.no_commits': 'The branch has no own commits against origin/develop.',
769
+ 'readiness.pr.error.no_commits': 'The branch has no own commits against {ref}.',
736
770
  'readiness.pr.error.rollback': 'Rollback must include at least one git revert command.',
737
771
  'readiness.pr.error.wrong_branch': 'Run this check from the slice branch. Current: {actual} Expected: {expected}',
738
772
  'readiness.pr.how_to_test.pass': 'PASS: How to Test includes environment, worktree access, startup, use cases, and technical verification.',
@@ -750,6 +784,11 @@ module.exports = {
750
784
  'readiness.spec_docs.pass': 'PASS: Local spec has SPEC.md, STATUS.md, and EVIDENCE_REPORT.md.',
751
785
  'readiness.warn': 'WARN: {message}',
752
786
  'spec_create.confirm_create': 'Create spec "{slug}"?',
787
+ 'spec_create.error.approval_declined': 'spec create interactive approval declined. No files were written.',
788
+ 'spec_create.error.interactive_tty_required': 'spec create --interactive requires an interactive TTY. Use --input, --spec, --review, and --dry-run for non-interactive automation.',
789
+ 'spec_create.error.review_canceled': '{reason}\nReview artifact: {path}',
790
+ 'spec_create.error.review_canceled.default_reason': 'spec create review was canceled.',
791
+ 'spec_create.error.review_tty_required': 'spec create --review requires an interactive terminal or an injected editor runner.\nReview artifact: {path}',
753
792
  'spec_create.input.approved_plan_hint': 'Reviewed and approved technical plan',
754
793
  'spec_create.label.files_written': 'Files written: {count}',
755
794
  'spec_create.label.input_file': 'Input file: {path}',
@@ -817,6 +856,12 @@ module.exports = {
817
856
  'spec_validate.strict': 'Strict: {value}',
818
857
  'spec_validate.title': 'Quiver spec validation',
819
858
  'spec_validate.warnings': 'Warnings:',
859
+ 'spec.error.directory_not_found': 'spec directory not found: {path}',
860
+ 'spec.error.directory_already_exists': 'spec directory already exists: {path}',
861
+ 'spec.error.missing_approved_plan_input': 'missing reviewed and approved plan input: {path}',
862
+ 'spec.error.missing_directory_command': 'missing spec directory. Use: npx create-quiver spec <start|status|validate|close> <spec-dir>',
863
+ 'spec.error.missing_directory_validate': 'missing spec directory. Use: npx create-quiver spec validate specs/<spec-slug>',
864
+ 'spec.error.validate_failed': 'spec validate failed for {path}',
820
865
  'status.blocked': 'blocked',
821
866
  'status.cancelled': 'cancelled',
822
867
  'status.active': 'active',