create-quiver 0.12.0 → 0.13.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 (158) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +65 -25
  3. package/README_FOR_AI.md +36 -29
  4. package/ROADMAP.md +22 -3
  5. package/docs/AI_ONBOARDING_PROMPT.md.template +7 -1
  6. package/docs/COMMANDS.md.template +53 -20
  7. package/docs/STATUS.md.template +5 -1
  8. package/docs/WORKFLOW.md.template +13 -11
  9. package/package.json +10 -3
  10. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/EVIDENCE_REPORT.md +293 -0
  11. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/EXECUTION_PLAN.md +58 -0
  12. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/SPEC.md +242 -0
  13. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/STATUS.md +35 -0
  14. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/pr.md +77 -0
  15. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/CLOSURE_BRIEF.md +34 -0
  16. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/EXECUTION_BRIEF.md +52 -0
  17. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-00-spec-foundation/slice.json +52 -0
  18. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/CLOSURE_BRIEF.md +36 -0
  19. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/EXECUTION_BRIEF.md +52 -0
  20. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-01-cli-contract-compatibility/slice.json +56 -0
  21. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/CLOSURE_BRIEF.md +43 -0
  22. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/EXECUTION_BRIEF.md +54 -0
  23. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-02-run-state-phase-locks/slice.json +52 -0
  24. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/CLOSURE_BRIEF.md +35 -0
  25. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/EXECUTION_BRIEF.md +53 -0
  26. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-03-safe-ai-onboarding-docs/slice.json +54 -0
  27. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/CLOSURE_BRIEF.md +34 -0
  28. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/EXECUTION_BRIEF.md +54 -0
  29. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-04-agent-profiles-adapters/slice.json +52 -0
  30. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/CLOSURE_BRIEF.md +34 -0
  31. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/EXECUTION_BRIEF.md +54 -0
  32. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-05-approval-gates/slice.json +53 -0
  33. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/CLOSURE_BRIEF.md +33 -0
  34. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/EXECUTION_BRIEF.md +56 -0
  35. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-06-spec-slice-generator/slice.json +55 -0
  36. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/CLOSURE_BRIEF.md +33 -0
  37. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/EXECUTION_BRIEF.md +54 -0
  38. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-07-slice-execution-planner/slice.json +52 -0
  39. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/CLOSURE_BRIEF.md +39 -0
  40. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/EXECUTION_BRIEF.md +56 -0
  41. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-08-controlled-slice-execution/slice.json +53 -0
  42. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/CLOSURE_BRIEF.md +38 -0
  43. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/EXECUTION_BRIEF.md +57 -0
  44. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-09-git-worktree-pr-lifecycle/slice.json +52 -0
  45. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/CLOSURE_BRIEF.md +39 -0
  46. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/EXECUTION_BRIEF.md +55 -0
  47. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-10-validation-errors-fixtures/slice.json +56 -0
  48. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/CLOSURE_BRIEF.md +36 -0
  49. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/EXECUTION_BRIEF.md +54 -0
  50. package/specs/quiver-v25-ai-first-lifecycle-orchestrator/slices/slice-11-export-dashboard-migration/slice.json +53 -0
  51. package/specs/quiver-v26-0121-smoke-hardening/EVIDENCE_REPORT.md +208 -0
  52. package/specs/quiver-v26-0121-smoke-hardening/EXECUTION_PLAN.md +57 -0
  53. package/specs/quiver-v26-0121-smoke-hardening/SPEC.md +137 -0
  54. package/specs/quiver-v26-0121-smoke-hardening/STATUS.md +32 -0
  55. package/specs/quiver-v26-0121-smoke-hardening/pr.md +96 -0
  56. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/CLOSURE_BRIEF.md +35 -0
  57. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/EXECUTION_BRIEF.md +55 -0
  58. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-00-docs-foundation/slice.json +73 -0
  59. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/CLOSURE_BRIEF.md +38 -0
  60. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/EXECUTION_BRIEF.md +51 -0
  61. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-01-cli-help-version-contract/slice.json +76 -0
  62. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/CLOSURE_BRIEF.md +37 -0
  63. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/EXECUTION_BRIEF.md +52 -0
  64. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-02-init-doc-links-and-flow-guidance/slice.json +75 -0
  65. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/CLOSURE_BRIEF.md +37 -0
  66. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/EXECUTION_BRIEF.md +53 -0
  67. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-03-ai-approval-review-consistency/slice.json +77 -0
  68. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/CLOSURE_BRIEF.md +35 -0
  69. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/EXECUTION_BRIEF.md +52 -0
  70. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-04-local-validation-brief-contracts/slice.json +77 -0
  71. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/CLOSURE_BRIEF.md +34 -0
  72. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/EXECUTION_BRIEF.md +54 -0
  73. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-05-demo-scaffold-readiness/slice.json +84 -0
  74. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/CLOSURE_BRIEF.md +35 -0
  75. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/EXECUTION_BRIEF.md +53 -0
  76. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-06-plan-graph-scope-performance/slice.json +82 -0
  77. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/CLOSURE_BRIEF.md +35 -0
  78. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/EXECUTION_BRIEF.md +55 -0
  79. package/specs/quiver-v26-0121-smoke-hardening/slices/slice-07-smoke-release-readiness/slice.json +92 -0
  80. package/specs/quiver-v27-reliability-ai-workflow-hardening/AUDIT_V24_V25_V26.md +67 -0
  81. package/specs/quiver-v27-reliability-ai-workflow-hardening/COMMAND_CONTRACTS.md +125 -0
  82. package/specs/quiver-v27-reliability-ai-workflow-hardening/COVERAGE_MATRIX.md +74 -0
  83. package/specs/quiver-v27-reliability-ai-workflow-hardening/EVIDENCE_REPORT.md +179 -0
  84. package/specs/quiver-v27-reliability-ai-workflow-hardening/EXECUTION_PLAN.md +71 -0
  85. package/specs/quiver-v27-reliability-ai-workflow-hardening/SPEC.md +176 -0
  86. package/specs/quiver-v27-reliability-ai-workflow-hardening/STATUS.md +37 -0
  87. package/specs/quiver-v27-reliability-ai-workflow-hardening/pr.md +132 -0
  88. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-00-docs-audit-coverage-and-contracts/CLOSURE_BRIEF.md +36 -0
  89. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-00-docs-audit-coverage-and-contracts/EXECUTION_BRIEF.md +56 -0
  90. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-00-docs-audit-coverage-and-contracts/slice.json +75 -0
  91. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-01-core-state-resolver-and-canonical-statuses/CLOSURE_BRIEF.md +37 -0
  92. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-01-core-state-resolver-and-canonical-statuses/EXECUTION_BRIEF.md +54 -0
  93. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-01-core-state-resolver-and-canonical-statuses/slice.json +79 -0
  94. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-02-json-export-contract-and-machine-output/CLOSURE_BRIEF.md +34 -0
  95. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-02-json-export-contract-and-machine-output/EXECUTION_BRIEF.md +54 -0
  96. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-02-json-export-contract-and-machine-output/slice.json +75 -0
  97. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-03-approved-plan-to-spec-create/CLOSURE_BRIEF.md +36 -0
  98. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-03-approved-plan-to-spec-create/EXECUTION_BRIEF.md +55 -0
  99. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-03-approved-plan-to-spec-create/slice.json +78 -0
  100. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-04-ai-artifact-storage-redaction-and-token-compaction/CLOSURE_BRIEF.md +31 -0
  101. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-04-ai-artifact-storage-redaction-and-token-compaction/EXECUTION_BRIEF.md +55 -0
  102. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-04-ai-artifact-storage-redaction-and-token-compaction/slice.json +77 -0
  103. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-05-worktree-lifecycle-locks-and-recovery/CLOSURE_BRIEF.md +31 -0
  104. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-05-worktree-lifecycle-locks-and-recovery/EXECUTION_BRIEF.md +55 -0
  105. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-05-worktree-lifecycle-locks-and-recovery/slice.json +84 -0
  106. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-06-validation-gates-and-scope-safety/CLOSURE_BRIEF.md +32 -0
  107. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-06-validation-gates-and-scope-safety/EXECUTION_BRIEF.md +57 -0
  108. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-06-validation-gates-and-scope-safety/slice.json +99 -0
  109. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-07-context-analysis-and-doctor-flow/CLOSURE_BRIEF.md +31 -0
  110. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-07-context-analysis-and-doctor-flow/EXECUTION_BRIEF.md +57 -0
  111. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-07-context-analysis-and-doctor-flow/slice.json +88 -0
  112. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-08-cross-platform-help-auth-and-dx/CLOSURE_BRIEF.md +31 -0
  113. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-08-cross-platform-help-auth-and-dx/EXECUTION_BRIEF.md +56 -0
  114. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-08-cross-platform-help-auth-and-dx/slice.json +85 -0
  115. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-09-fixtures-smoke-docs-and-release-readiness/CLOSURE_BRIEF.md +32 -0
  116. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-09-fixtures-smoke-docs-and-release-readiness/EXECUTION_BRIEF.md +56 -0
  117. package/specs/quiver-v27-reliability-ai-workflow-hardening/slices/slice-09-fixtures-smoke-docs-and-release-readiness/slice.json +91 -0
  118. package/src/create-quiver/commands/ai.js +652 -27
  119. package/src/create-quiver/commands/flow.js +58 -9
  120. package/src/create-quiver/commands/graph.js +11 -9
  121. package/src/create-quiver/commands/plan.js +7 -16
  122. package/src/create-quiver/commands/spec.js +282 -0
  123. package/src/create-quiver/index.js +409 -31
  124. package/src/create-quiver/lib/actionable-error.js +27 -0
  125. package/src/create-quiver/lib/agent-profiles.js +16 -4
  126. package/src/create-quiver/lib/ai/artifacts.js +318 -0
  127. package/src/create-quiver/lib/ai/context-packs.js +4 -0
  128. package/src/create-quiver/lib/ai/execution-plan.js +16 -1
  129. package/src/create-quiver/lib/ai/executor.js +272 -21
  130. package/src/create-quiver/lib/ai/export-state.js +679 -0
  131. package/src/create-quiver/lib/ai/github.js +162 -2
  132. package/src/create-quiver/lib/ai/onboarding-template.js +215 -2
  133. package/src/create-quiver/lib/ai/plan-review.js +7 -2
  134. package/src/create-quiver/lib/ai/providers.js +4 -3
  135. package/src/create-quiver/lib/ai/run-state.js +414 -0
  136. package/src/create-quiver/lib/ai/spec-generator.js +84 -13
  137. package/src/create-quiver/lib/ai/spec-templates.js +150 -21
  138. package/src/create-quiver/lib/analyze.js +2 -2
  139. package/src/create-quiver/lib/approvals.js +36 -5
  140. package/src/create-quiver/lib/demo.js +189 -14
  141. package/src/create-quiver/lib/doctor.js +154 -0
  142. package/src/create-quiver/lib/git.js +40 -1
  143. package/src/create-quiver/lib/handoff.js +123 -12
  144. package/src/create-quiver/lib/init-docs.js +35 -13
  145. package/src/create-quiver/lib/init-layout.js +9 -0
  146. package/src/create-quiver/lib/json.js +53 -3
  147. package/src/create-quiver/lib/lifecycle.js +52 -3
  148. package/src/create-quiver/lib/locks.js +134 -0
  149. package/src/create-quiver/lib/package-safety.js +7 -0
  150. package/src/create-quiver/lib/paths.js +74 -0
  151. package/src/create-quiver/lib/project-scan.js +74 -0
  152. package/src/create-quiver/lib/project-state-resolver.js +236 -0
  153. package/src/create-quiver/lib/readiness.js +66 -10
  154. package/src/create-quiver/lib/scope.js +52 -8
  155. package/src/create-quiver/lib/slice-graph.js +138 -38
  156. package/src/create-quiver/lib/slice.js +14 -5
  157. package/src/create-quiver/lib/spec-worktrees.js +129 -32
  158. package/src/create-quiver/lib/statuses.js +115 -0
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { spawnSync } = require('child_process');
3
4
  const { readAllSlices } = require('./slice-graph');
4
5
  const { hasGeneratedProjectSpec, hasInitializedStateMetadata, readState } = require('./state');
5
6
  const { worktreeList } = require('./git');
@@ -330,6 +331,7 @@ function collectLayoutReport(projectRoot) {
330
331
  const hasStateMetadata = hasInitializedStateMetadata(readState(projectRoot));
331
332
  const realSlices = readAllSlices(projectRoot);
332
333
  const specSlugs = Array.from(new Set(realSlices.map((slice) => slice.specSlug))).sort((left, right) => left.localeCompare(right));
334
+ const exampleTarget = selectDoctorExampleTarget(realSlices, specSlugs);
333
335
  const newLayoutFiles = collectPresentPaths(projectRoot, NEW_LAYOUT_REQUIRED_PATHS);
334
336
  const missingNewLayoutFiles = collectMissingPaths(projectRoot, NEW_LAYOUT_REQUIRED_PATHS);
335
337
  const legacySignals = collectPresentPaths(projectRoot, LEGACY_LAYOUT_PROBES);
@@ -378,7 +380,14 @@ function collectLayoutReport(projectRoot) {
378
380
  }
379
381
  }
380
382
 
383
+ if (exampleTarget.source === 'generic-multiple-specs') {
384
+ recommendations.push('Multiple specs were found and no active slice is obvious. Doctor examples use placeholders so they do not point to the wrong spec.');
385
+ } else if (exampleTarget.source === 'active-slice') {
386
+ recommendations.push(`Doctor examples target the active slice candidate ${exampleTarget.specSlug}/${exampleTarget.sliceId} (${exampleTarget.status}).`);
387
+ }
388
+
381
389
  return {
390
+ exampleTarget,
382
391
  hasLegacyLayout,
383
392
  hasNewLayout,
384
393
  hasStateMetadata,
@@ -392,6 +401,76 @@ function collectLayoutReport(projectRoot) {
392
401
  };
393
402
  }
394
403
 
404
+ function normalizeStatus(value) {
405
+ return String(value || '').trim().toLowerCase().replace(/_/g, '-');
406
+ }
407
+
408
+ function statusRank(status) {
409
+ const normalized = normalizeStatus(status);
410
+ const ranks = new Map([
411
+ ['in-progress', 0],
412
+ ['review', 1],
413
+ ['ready', 2],
414
+ ['planned', 3],
415
+ ['approved', 4],
416
+ ['blocked', 5],
417
+ ['draft', 6],
418
+ ['completed', 99],
419
+ ['done', 99],
420
+ ]);
421
+
422
+ return ranks.has(normalized) ? ranks.get(normalized) : 20;
423
+ }
424
+
425
+ function selectDoctorExampleTarget(realSlices, specSlugs) {
426
+ if (!Array.isArray(specSlugs) || specSlugs.length === 0) {
427
+ return {
428
+ sliceId: '<slice-id>',
429
+ source: 'no-specs',
430
+ specSlug: '<spec-slug>',
431
+ status: '',
432
+ };
433
+ }
434
+
435
+ const rankedSlices = (Array.isArray(realSlices) ? realSlices : [])
436
+ .filter((slice) => specSlugs.includes(slice.specSlug))
437
+ .slice()
438
+ .sort((left, right) => {
439
+ const rankDelta = statusRank(left.status) - statusRank(right.status);
440
+ if (rankDelta !== 0) {
441
+ return rankDelta;
442
+ }
443
+
444
+ return left.ref.localeCompare(right.ref);
445
+ });
446
+ const activeSlice = rankedSlices.find((slice) => statusRank(slice.status) < 99);
447
+
448
+ if (activeSlice) {
449
+ return {
450
+ sliceId: activeSlice.sliceId,
451
+ source: 'active-slice',
452
+ specSlug: activeSlice.specSlug,
453
+ status: activeSlice.status || '',
454
+ };
455
+ }
456
+
457
+ if (specSlugs.length === 1) {
458
+ return {
459
+ sliceId: '<slice-id>',
460
+ source: 'single-spec',
461
+ specSlug: specSlugs[0],
462
+ status: '',
463
+ };
464
+ }
465
+
466
+ return {
467
+ sliceId: '<slice-id>',
468
+ source: 'generic-multiple-specs',
469
+ specSlug: '<spec-slug>',
470
+ status: '',
471
+ };
472
+ }
473
+
395
474
  function buildDoctorFixPlan(projectRoot) {
396
475
  const fixes = [];
397
476
  const rootGitignorePath = path.join(projectRoot, '.gitignore');
@@ -512,6 +591,75 @@ function collectDoctorReport(projectRoot) {
512
591
  };
513
592
  }
514
593
 
594
+ function runEnvironmentProbe(command, args = [], options = {}) {
595
+ const runner = options.runner || spawnSync;
596
+ return runner(command, args, {
597
+ cwd: options.cwd,
598
+ encoding: 'utf8',
599
+ shell: false,
600
+ stdio: ['ignore', 'pipe', 'pipe'],
601
+ timeout: options.timeout || 3000,
602
+ });
603
+ }
604
+
605
+ function probeOk(command, args, options = {}) {
606
+ const result = runEnvironmentProbe(command, args, options);
607
+ if (result && result.error && result.error.code === 'ENOENT') {
608
+ return {
609
+ ok: false,
610
+ reason: 'missing',
611
+ };
612
+ }
613
+ return {
614
+ ok: Boolean(result && result.status === 0),
615
+ reason: result && result.error ? result.error.message : result && result.stderr ? String(result.stderr).trim() : '',
616
+ };
617
+ }
618
+
619
+ function collectEnvironmentWarnings(projectRoot, options = {}) {
620
+ const warnings = [];
621
+ const cwd = projectRoot;
622
+
623
+ const checks = [
624
+ ['node', ['--version'], 'Node.js is required to run create-quiver. Install Node 20+ and retry.'],
625
+ ['npm', ['--version'], 'npm is required for generated npm scripts and package smokes. Install npm or use a Node distribution that includes it.'],
626
+ ['git', ['--version'], 'git is required for specs, slices, worktrees, commits, and PR flow. Install git and retry.'],
627
+ ];
628
+
629
+ for (const [command, args, message] of checks) {
630
+ const check = probeOk(command, args, { ...options, cwd });
631
+ if (!check.ok) {
632
+ warnings.push(`${command} check failed: ${message}`);
633
+ }
634
+ }
635
+
636
+ const ghCheck = probeOk('gh', ['--version'], { ...options, cwd });
637
+ if (!ghCheck.ok) {
638
+ warnings.push('gh check failed: GitHub CLI is required for `ai pr` and `ai doctor`. macOS: brew install gh. Linux: use your distro package manager. Windows: winget install GitHub.cli.');
639
+ } else {
640
+ const authCheck = probeOk('gh', ['auth', 'status'], { ...options, cwd });
641
+ if (!authCheck.ok) {
642
+ warnings.push('gh auth check failed: run `gh auth login` before using `ai pr --create`.');
643
+ }
644
+ }
645
+
646
+ if (!process.env.SHELL && !process.env.ComSpec) {
647
+ warnings.push('shell check failed: no SHELL or ComSpec environment variable was detected.');
648
+ }
649
+
650
+ if (projectRoot.includes(' ')) {
651
+ warnings.push('path contains spaces: use quoted paths when copying manual commands.');
652
+ }
653
+
654
+ try {
655
+ fs.accessSync(projectRoot, fs.constants.W_OK);
656
+ } catch {
657
+ warnings.push('permission check failed: current user cannot write to the project root.');
658
+ }
659
+
660
+ return warnings;
661
+ }
662
+
515
663
  function collectDoctorWarnings(projectRoot) {
516
664
  const warnings = [];
517
665
 
@@ -547,6 +695,10 @@ function collectDoctorWarnings(projectRoot) {
547
695
  warnings.push(`missing local docs link: ${issue}`);
548
696
  }
549
697
 
698
+ for (const issue of collectEnvironmentWarnings(projectRoot)) {
699
+ warnings.push(issue);
700
+ }
701
+
550
702
  return warnings;
551
703
  }
552
704
 
@@ -554,7 +706,9 @@ module.exports = {
554
706
  applyDoctorFixPlan,
555
707
  buildDoctorFixPlan,
556
708
  collectDoctorReport,
709
+ collectEnvironmentWarnings,
557
710
  collectDoctorWarnings,
558
711
  collectLayoutReport,
559
712
  formatDoctorFixPlan,
713
+ selectDoctorExampleTarget,
560
714
  };
@@ -1,4 +1,6 @@
1
1
  const cp = require('child_process');
2
+ const fs = require('fs');
3
+ const path = require('path');
2
4
 
3
5
  function runGit(args, cwd, options = {}) {
4
6
  return cp.execFileSync('git', args, {
@@ -98,6 +100,9 @@ function currentBranch(repoRoot) {
98
100
  }
99
101
 
100
102
  function statusPorcelain(repoRoot) {
103
+ if (!repoRoot || !fs.existsSync(repoRoot)) {
104
+ return '__MISSING_WORKTREE__';
105
+ }
101
106
  return tryGit(['status', '--porcelain'], repoRoot);
102
107
  }
103
108
 
@@ -111,7 +116,37 @@ function hasRemote(repoRoot, remoteName = 'origin') {
111
116
  }
112
117
 
113
118
  function isCleanWorktree(repoRoot) {
114
- return statusPorcelain(repoRoot) === '';
119
+ return Boolean(repoRoot && fs.existsSync(repoRoot) && isGitWorktree(repoRoot) && statusPorcelain(repoRoot) === '');
120
+ }
121
+
122
+ function isGitWorktree(repoRoot) {
123
+ return tryGit(['rev-parse', '--is-inside-work-tree'], repoRoot) === 'true';
124
+ }
125
+
126
+ function absoluteGitDir(repoRoot) {
127
+ return tryGit(['rev-parse', '--absolute-git-dir'], repoRoot);
128
+ }
129
+
130
+ function gitCommonDir(repoRoot) {
131
+ const value = tryGit(['rev-parse', '--git-common-dir'], repoRoot);
132
+ if (!value) {
133
+ return '';
134
+ }
135
+ return path.isAbsolute(value) ? path.resolve(value) : path.resolve(repoRoot, value);
136
+ }
137
+
138
+ function realpathOrResolve(value) {
139
+ try {
140
+ return fs.realpathSync(value);
141
+ } catch {
142
+ return path.resolve(value);
143
+ }
144
+ }
145
+
146
+ function isLinkedWorktree(repoRoot) {
147
+ const gitDir = absoluteGitDir(repoRoot);
148
+ const commonDir = gitCommonDir(repoRoot);
149
+ return Boolean(gitDir && commonDir && realpathOrResolve(gitDir) !== realpathOrResolve(commonDir));
115
150
  }
116
151
 
117
152
  function isDetachedHead(repoRoot) {
@@ -161,8 +196,12 @@ module.exports = {
161
196
  lsRemoteHeads,
162
197
  mergeBaseIsAncestor,
163
198
  hasRemote,
199
+ absoluteGitDir,
200
+ gitCommonDir,
164
201
  isCleanWorktree,
165
202
  isDetachedHead,
203
+ isGitWorktree,
204
+ isLinkedWorktree,
166
205
  revListCount,
167
206
  remoteList,
168
207
  runGit,
@@ -10,6 +10,36 @@ const REQUIRED_HEADINGS = [
10
10
  '## Constraints',
11
11
  ];
12
12
 
13
+ const EXECUTION_BRIEF_REQUIRED_HEADINGS = [
14
+ {
15
+ label: 'context',
16
+ alternatives: ['## Context', '## Contexto'],
17
+ },
18
+ {
19
+ label: 'objective',
20
+ alternatives: ['## Objective', '## Objetivo'],
21
+ },
22
+ {
23
+ label: 'acceptance criteria',
24
+ alternatives: ['## Acceptance Criteria', '## Criterios de aceptacion', '## Criterios de aceptación'],
25
+ },
26
+ {
27
+ label: 'completion checklist',
28
+ alternatives: ['## Completion Checklist', '## Checklist de finalizacion', '## Checklist de finalización'],
29
+ },
30
+ ];
31
+
32
+ const CLOSURE_BRIEF_REQUIRED_HEADINGS = [
33
+ {
34
+ label: 'summary',
35
+ alternatives: ['## Summary', '## Summary of Work', '## Resumen de lo realizado'],
36
+ },
37
+ {
38
+ label: 'validation',
39
+ alternatives: ['## Validation', '## Validation Against Acceptance Criteria', '## Validacion contra criterios de aceptacion', '## Validación contra criterios de aceptación'],
40
+ },
41
+ ];
42
+
13
43
  const HANDOFF_TEMPLATE_PATH = path.resolve(__dirname, '..', '..', '..', 'specs', '[project-name]', 'HANDOFF.md.template');
14
44
 
15
45
  function normalizePosixPath(filePath, pathLib = path) {
@@ -21,19 +51,36 @@ function resolveHandoffPath(repoRoot, handoffInput, pathLib = path) {
21
51
  const relativePath = normalizePosixPath(pathLib.relative(repoRoot, absolutePath), pathLib);
22
52
 
23
53
  if (relativePath.startsWith('..') || pathLib.isAbsolute(relativePath)) {
24
- throw new Error(`create-quiver: handoff must live at specs/<spec-slug>/HANDOFF.md (got ${normalizePosixPath(handoffInput, pathLib)})`);
54
+ throw new Error(`create-quiver: handoff or brief must live under specs/<spec-slug>/ (got ${normalizePosixPath(handoffInput, pathLib)})`);
55
+ }
56
+
57
+ const handoffMatch = relativePath.match(/^(specs|specs-fix)\/([^/]+)\/HANDOFF\.md$/);
58
+ if (handoffMatch) {
59
+ return {
60
+ absolutePath,
61
+ relativePath,
62
+ specFamily: handoffMatch[1],
63
+ specSlug: handoffMatch[2],
64
+ kind: 'handoff',
65
+ label: 'Handoff',
66
+ };
25
67
  }
26
68
 
27
- const match = relativePath.match(/^specs\/([^/]+)\/HANDOFF\.md$/);
28
- if (!match) {
29
- throw new Error(`create-quiver: handoff must live at specs/<spec-slug>/HANDOFF.md (got ${relativePath})`);
69
+ const briefMatch = relativePath.match(/^(specs|specs-fix)\/([^/]+)\/slices\/([^/]+)\/(EXECUTION_BRIEF|CLOSURE_BRIEF)\.md$/);
70
+ if (briefMatch) {
71
+ const briefName = briefMatch[4];
72
+ return {
73
+ absolutePath,
74
+ relativePath,
75
+ specFamily: briefMatch[1],
76
+ specSlug: briefMatch[2],
77
+ sliceId: briefMatch[3],
78
+ kind: briefName === 'EXECUTION_BRIEF' ? 'execution-brief' : 'closure-brief',
79
+ label: briefName === 'EXECUTION_BRIEF' ? 'Execution brief' : 'Closure brief',
80
+ };
30
81
  }
31
82
 
32
- return {
33
- absolutePath,
34
- relativePath,
35
- specSlug: match[1],
36
- };
83
+ throw new Error(`create-quiver: handoff or brief must live at specs/<spec-slug>/HANDOFF.md or specs/<spec-slug>/slices/<slice-id>/EXECUTION_BRIEF.md|CLOSURE_BRIEF.md (got ${relativePath})`);
37
84
  }
38
85
 
39
86
  function readHandoffSections(text) {
@@ -49,17 +96,76 @@ function validateHandoffSections(text) {
49
96
  return REQUIRED_HEADINGS.filter((heading) => !sections.has(heading));
50
97
  }
51
98
 
99
+ function normalizeHeading(heading) {
100
+ return String(heading || '')
101
+ .normalize('NFD')
102
+ .replace(/[\u0300-\u036f]/g, '')
103
+ .trim()
104
+ .toLowerCase();
105
+ }
106
+
107
+ function validateBriefSections(text, kind) {
108
+ const sections = new Set(readHandoffSections(text).map(normalizeHeading));
109
+ const requiredGroups = kind === 'closure-brief' ? CLOSURE_BRIEF_REQUIRED_HEADINGS : EXECUTION_BRIEF_REQUIRED_HEADINGS;
110
+
111
+ return requiredGroups
112
+ .filter((group) => !group.alternatives.some((heading) => sections.has(normalizeHeading(heading))))
113
+ .map((group) => group.label);
114
+ }
115
+
116
+ function headingGroupsForKind(kind) {
117
+ if (kind === 'handoff') {
118
+ return REQUIRED_HEADINGS.map((heading) => ({
119
+ label: heading.replace(/^##\s+/, '').toLowerCase(),
120
+ alternatives: [heading],
121
+ }));
122
+ }
123
+ return kind === 'closure-brief' ? CLOSURE_BRIEF_REQUIRED_HEADINGS : EXECUTION_BRIEF_REQUIRED_HEADINGS;
124
+ }
125
+
126
+ function formatAliasGuidance(kind) {
127
+ return headingGroupsForKind(kind)
128
+ .map((group) => `- ${group.label}: ${group.alternatives.join(' | ')}`)
129
+ .join('\n');
130
+ }
131
+
132
+ function canonicalHeadingForGroup(group) {
133
+ return group.alternatives[0] || `## ${group.label}`;
134
+ }
135
+
136
+ function formatMinimalTemplate(kind) {
137
+ const lines = [];
138
+ for (const group of headingGroupsForKind(kind)) {
139
+ lines.push(canonicalHeadingForGroup(group), '', 'TODO', '');
140
+ }
141
+ return lines.join('\n').trimEnd();
142
+ }
143
+
144
+ function formatMissingSectionsError(resolved, missingSections) {
145
+ return [
146
+ `create-quiver: ${resolved.label.toLowerCase()} is missing required sections: ${missingSections.join(', ')}`,
147
+ '',
148
+ 'Accepted headings/aliases:',
149
+ formatAliasGuidance(resolved.kind),
150
+ '',
151
+ 'Minimal template:',
152
+ formatMinimalTemplate(resolved.kind),
153
+ ].join('\n');
154
+ }
155
+
52
156
  function checkHandoff(handoffInput, repoRoot = process.cwd()) {
53
157
  const resolved = resolveHandoffPath(repoRoot, handoffInput);
54
158
 
55
159
  if (!fs.existsSync(resolved.absolutePath)) {
56
- throw new Error(`create-quiver: missing handoff file: ${resolved.relativePath}`);
160
+ throw new Error(`create-quiver: missing ${resolved.label.toLowerCase()} file: ${resolved.relativePath}`);
57
161
  }
58
162
 
59
163
  const text = fs.readFileSync(resolved.absolutePath, 'utf8');
60
- const missingSections = validateHandoffSections(text);
164
+ const missingSections = resolved.kind === 'handoff'
165
+ ? validateHandoffSections(text)
166
+ : validateBriefSections(text, resolved.kind);
61
167
  if (missingSections.length > 0) {
62
- throw new Error(`create-quiver: handoff is missing required sections: ${missingSections.join(', ')}`);
168
+ throw new Error(formatMissingSectionsError(resolved, missingSections));
63
169
  }
64
170
 
65
171
  return resolved;
@@ -95,10 +201,15 @@ function scaffoldHandoff(specSlug, repoRoot = process.cwd()) {
95
201
  }
96
202
 
97
203
  module.exports = {
204
+ CLOSURE_BRIEF_REQUIRED_HEADINGS,
205
+ EXECUTION_BRIEF_REQUIRED_HEADINGS,
98
206
  REQUIRED_HEADINGS,
99
207
  checkHandoff,
208
+ formatAliasGuidance,
209
+ formatMinimalTemplate,
100
210
  readHandoffSections,
101
211
  scaffoldHandoff,
102
212
  resolveHandoffPath,
213
+ validateBriefSections,
103
214
  validateHandoffSections,
104
215
  };
@@ -316,8 +316,14 @@ Use \`AGENTS.md\` first, then \`docs/AI_CONTEXT.md\` and \`docs/AI_ONBOARDING_PR
316
316
  \`\`\`bash
317
317
  npm run quiver:prepare -- --dry-run
318
318
  npm run quiver:ai:onboard -- --dry-run
319
+ npm run quiver:ai:inspect
320
+ npm run quiver:ai:export -- --format json
321
+ npm run quiver:ai:specs
322
+ npm run quiver:ai:slices
323
+ npm run quiver:ai:trace
319
324
  npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
320
- npm run quiver:ai:approve -- --phase acceptance --input acceptance-approved.md
325
+ npm run quiver:ai:revise -- --phase acceptance --input feedback.md --dry-run
326
+ npm run quiver:ai:approve -- --phase acceptance --version <n>
321
327
  npm run quiver:ai:plan -- --phase technical-plan --dry-run
322
328
  npm run quiver:ai:review-plan -- --dry-run
323
329
  npm run quiver:ai:approve -- --phase technical-plan --version <n>
@@ -371,7 +377,8 @@ Use dry-runs before spending model tokens:
371
377
  npm run quiver:prepare -- --dry-run
372
378
  npm run quiver:ai:onboard -- --dry-run
373
379
  npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
374
- npm run quiver:ai:approve -- --phase acceptance --input acceptance-approved.md
380
+ npm run quiver:ai:revise -- --phase acceptance --input feedback.md --dry-run
381
+ npm run quiver:ai:approve -- --phase acceptance --version <n>
375
382
  npm run quiver:ai:plan -- --phase technical-plan --dry-run
376
383
  npm run quiver:ai:review-plan -- --dry-run
377
384
  npm run quiver:ai:approve -- --phase technical-plan --version <n>
@@ -397,9 +404,16 @@ npm run quiver:plan
397
404
  npm run quiver:graph
398
405
  npm run quiver:next
399
406
  npm run quiver:doctor
407
+ npm run quiver:ai:inspect
408
+ npm run quiver:ai:export -- --format json
409
+ npm run quiver:ai:export -- --format markdown
410
+ npm run quiver:ai:specs
411
+ npm run quiver:ai:slices
412
+ npm run quiver:ai:trace
400
413
  npm run quiver:ai:onboard -- --dry-run
401
414
  npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
402
- npm run quiver:ai:approve -- --phase acceptance --input acceptance-approved.md
415
+ npm run quiver:ai:revise -- --phase acceptance --input feedback.md --dry-run
416
+ npm run quiver:ai:approve -- --phase acceptance --version <n>
403
417
  npm run quiver:ai:plan -- --phase technical-plan --dry-run
404
418
  npm run quiver:ai:review-plan -- --dry-run
405
419
  npm run quiver:ai:approve -- --phase technical-plan --version <n>
@@ -470,7 +484,8 @@ Start with dry-runs so you can inspect the provider, role, context pack, and inv
470
484
  npm run quiver:prepare -- --dry-run
471
485
  npm run quiver:ai:onboard -- --dry-run
472
486
  npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
473
- npm run quiver:ai:approve -- --phase acceptance --input acceptance-approved.md
487
+ npm run quiver:ai:revise -- --phase acceptance --input feedback.md --dry-run
488
+ npm run quiver:ai:approve -- --phase acceptance --version <n>
474
489
  npm run quiver:ai:plan -- --phase technical-plan --dry-run
475
490
  npm run quiver:ai:review-plan -- --dry-run
476
491
  npm run quiver:ai:approve -- --phase technical-plan --version <n>
@@ -497,7 +512,8 @@ npm run quiver:next
497
512
  npm run quiver:doctor
498
513
  npm run quiver:ai:onboard -- --dry-run
499
514
  npm run quiver:ai:plan -- --phase acceptance --input requirements.md --dry-run
500
- npm run quiver:ai:approve -- --phase acceptance --input acceptance-approved.md
515
+ npm run quiver:ai:revise -- --phase acceptance --input feedback.md --dry-run
516
+ npm run quiver:ai:approve -- --phase acceptance --version <n>
501
517
  npm run quiver:ai:plan -- --phase technical-plan --dry-run
502
518
  npm run quiver:ai:review-plan -- --dry-run
503
519
  npm run quiver:ai:approve -- --phase technical-plan --version <n>
@@ -515,6 +531,7 @@ npm run quiver:start-slice -- specs/${projectSlug}/slices/slice-01/slice.json
515
531
  npm run quiver:check-slice -- specs/${projectSlug}/slices/slice-01/slice.json
516
532
  npm run quiver:check-pr -- specs/${projectSlug}/slices/slice-01/slice.json
517
533
  npm run quiver:check-handoff -- specs/${projectSlug}/HANDOFF.md
534
+ npm run quiver:check-handoff -- specs/${projectSlug}/slices/slice-01/EXECUTION_BRIEF.md
518
535
  npm run quiver:cleanup-slice -- specs/${projectSlug}/slices/slice-01/slice.json
519
536
  npm run quiver:check-scope -- specs/${projectSlug}/slices/slice-01/slice.json
520
537
  npm run quiver:refresh-active-slices
@@ -522,13 +539,14 @@ npm run quiver:refresh-active-slices
522
539
 
523
540
  The \`quiver:graph\` script prints the tree view by default; use \`npx create-quiver graph --format mermaid\` for PR-ready Markdown and \`--format dot\` when you want Graphviz source.
524
541
  The \`quiver:next\` script points to the next ready slice and can auto-start it behind a confirmation prompt.
525
- The \`quiver:ai:*\` scripts standardize planner/executor AI flows. Use dry-run first: onboarding and planning dry-runs do not require provider auth, \`quiver:ai:execute-plan -- --dry-run --commit --mode manual\` prints manual prompts, \`--mode delegated\` prints safe waves, and \`quiver:ai:pr -- --dry-run\` validates \`gh\`, GitFlow docs, branch/worktree state, SSH inputs, and \`pr.md\` without creating a PR. Add \`--create\` only after reviewing the plan.
542
+ The \`quiver:ai:*\` scripts standardize planner/executor AI flows. Use dry-run first: onboarding and planning dry-runs do not require provider auth, \`quiver:ai:execute-plan -- --dry-run --commit --mode manual\` prints manual prompts, \`--mode delegated\` prints safe waves, \`quiver:ai:inspect\` shows lifecycle state, \`quiver:ai:export -- --format json|markdown\` emits dashboard/agent-friendly state, and \`quiver:ai:pr -- --dry-run\` validates \`gh\`, GitFlow docs, branch/worktree state, SSH inputs, and \`pr.md\` without creating a PR. Add \`--create\` only after reviewing the plan.
526
543
  Use \`quiver:spec:create\`, \`quiver:spec:start\`, \`quiver:spec:status\`, and \`quiver:spec:close\` for one spec generation and worktree per spec.
527
544
  Use \`npx create-quiver next --all-ready\` when you want the full ready level instead of a single suggestion.
528
545
  The legacy Bash wrappers remain in \`tools/scripts/\` for compatibility, but new project-level automation should prefer the \`quiver:*\` scripts and the direct \`npx create-quiver ...\` commands below.
529
546
  \`npm run quiver:migrate\` is only for projects that were already initialized by Quiver.
530
547
  \`npm run check-handoff -- specs/${projectSlug}/HANDOFF.md\` is available as a legacy-friendly alias for the handoff validator.
531
548
  If a new bounded transfer is needed, scaffold \`specs/${projectSlug}/HANDOFF.md\` with \`npx create-quiver new-handoff ${projectSlug}\` and validate it with \`npx create-quiver check-handoff specs/${projectSlug}/HANDOFF.md\`.
549
+ Use \`npx create-quiver check-handoff specs/${projectSlug}/slices/slice-01/EXECUTION_BRIEF.md\` or \`CLOSURE_BRIEF.md\` to validate the current per-slice brief contract.
532
550
  For exceptional context transfers between agents or phases, a dedicated \`HANDOFF.md\` can live alongside the usual spec and docs files.
533
551
 
534
552
  ## Cross-Platform Support
@@ -1074,6 +1092,15 @@ function installSelfAsDevDep(projectRoot, version) {
1074
1092
  return 'skipped-already-present';
1075
1093
  }
1076
1094
 
1095
+ try {
1096
+ execSync(formatInstallSelfCommand(projectRoot, version), { cwd: projectRoot, stdio: 'inherit' });
1097
+ return 'installed';
1098
+ } catch {
1099
+ return 'failed';
1100
+ }
1101
+ }
1102
+
1103
+ function formatInstallSelfCommand(projectRoot, version) {
1077
1104
  const pm = detectPackageManager(projectRoot);
1078
1105
  const commands = {
1079
1106
  npm: `npm install -D create-quiver@${version}`,
@@ -1081,13 +1108,7 @@ function installSelfAsDevDep(projectRoot, version) {
1081
1108
  pnpm: `pnpm add -D create-quiver@${version}`,
1082
1109
  bun: `bun add -d create-quiver@${version}`,
1083
1110
  };
1084
-
1085
- try {
1086
- execSync(commands[pm], { cwd: projectRoot, stdio: 'inherit' });
1087
- return 'installed';
1088
- } catch {
1089
- return 'failed';
1090
- }
1111
+ return commands[pm] || commands.npm;
1091
1112
  }
1092
1113
 
1093
1114
  function normalizeSkippedReason(reason) {
@@ -1235,5 +1256,6 @@ module.exports = {
1235
1256
  writeFrontMatter,
1236
1257
  toProjectSlug,
1237
1258
  detectPackageManager,
1259
+ formatInstallSelfCommand,
1238
1260
  installSelfAsDevDep,
1239
1261
  };
@@ -82,6 +82,7 @@ function quiverInternalPaths(projectRoot) {
82
82
  cacheDir: path.join(root, 'cache'),
83
83
  configPath: path.join(root, 'config.json'),
84
84
  gitignorePath: path.join(root, '.gitignore'),
85
+ locksDir: path.join(root, 'locks'),
85
86
  runsDir: path.join(root, 'runs'),
86
87
  scansDir: path.join(root, 'scans'),
87
88
  statePath: path.join(root, 'state.json'),
@@ -94,6 +95,7 @@ function buildQuiverInternalGitignore() {
94
95
  return [
95
96
  'cache/',
96
97
  'evidence/',
98
+ 'locks/',
97
99
  'runs/',
98
100
  'worktrees/',
99
101
  '',
@@ -188,9 +190,15 @@ function resolveInitPackageScripts(profile, options = {}) {
188
190
  'quiver:doctor': 'npx create-quiver doctor',
189
191
  'quiver:evidence': 'npx create-quiver evidence',
190
192
  'quiver:ai:agent': 'npx create-quiver ai agent',
193
+ 'quiver:ai:inspect': 'npx create-quiver ai inspect',
194
+ 'quiver:ai:export': 'npx create-quiver ai export',
195
+ 'quiver:ai:specs': 'npx create-quiver ai specs list',
196
+ 'quiver:ai:slices': 'npx create-quiver ai slices list',
197
+ 'quiver:ai:trace': 'npx create-quiver ai trace report',
191
198
  'quiver:ai:onboard': 'npx create-quiver ai onboard',
192
199
  'quiver:ai:prepare-context': 'npx create-quiver ai prepare-context',
193
200
  'quiver:ai:plan': 'npx create-quiver ai plan',
201
+ 'quiver:ai:revise': 'npx create-quiver ai revise',
194
202
  'quiver:ai:review-plan': 'npx create-quiver ai review-plan',
195
203
  'quiver:ai:approve': 'npx create-quiver ai approve',
196
204
  'quiver:ai:prompt-slice': 'npx create-quiver ai prompt-slice',
@@ -201,6 +209,7 @@ function resolveInitPackageScripts(profile, options = {}) {
201
209
  'quiver:spec:create': 'npx create-quiver spec create',
202
210
  'quiver:spec:start': 'npx create-quiver spec start',
203
211
  'quiver:spec:status': 'npx create-quiver spec status',
212
+ 'quiver:spec:validate': 'npx create-quiver spec validate',
204
213
  'quiver:spec:close': 'npx create-quiver spec close',
205
214
  'quiver:start-slice': 'npx create-quiver start-slice',
206
215
  'quiver:check-slice': 'npx create-quiver check-slice',
@@ -1,7 +1,57 @@
1
1
  function stripJsonComments(text) {
2
- return String(text || '')
3
- .replace(/^\s*\/\/.*$/gm, '')
4
- .replace(/\/\*[\s\S]*?\*\//g, '');
2
+ const input = String(text || '');
3
+ let output = '';
4
+ let inString = false;
5
+ let escaped = false;
6
+
7
+ for (let index = 0; index < input.length; index += 1) {
8
+ const char = input[index];
9
+ const next = input[index + 1];
10
+
11
+ if (inString) {
12
+ output += char;
13
+ if (escaped) {
14
+ escaped = false;
15
+ } else if (char === '\\') {
16
+ escaped = true;
17
+ } else if (char === '"') {
18
+ inString = false;
19
+ }
20
+ continue;
21
+ }
22
+
23
+ if (char === '"') {
24
+ inString = true;
25
+ output += char;
26
+ continue;
27
+ }
28
+
29
+ if (char === '/' && next === '/') {
30
+ while (index < input.length && input[index] !== '\n') {
31
+ index += 1;
32
+ }
33
+ if (index < input.length) {
34
+ output += '\n';
35
+ }
36
+ continue;
37
+ }
38
+
39
+ if (char === '/' && next === '*') {
40
+ index += 2;
41
+ while (index < input.length && !(input[index] === '*' && input[index + 1] === '/')) {
42
+ if (input[index] === '\n') {
43
+ output += '\n';
44
+ }
45
+ index += 1;
46
+ }
47
+ index += 1;
48
+ continue;
49
+ }
50
+
51
+ output += char;
52
+ }
53
+
54
+ return output;
5
55
  }
6
56
 
7
57
  function parseJsonWithComments(text) {