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
@@ -0,0 +1,27 @@
1
+ function formatActionableError({ failure, impact, fix, nextCommand } = {}) {
2
+ const lines = [`create-quiver: ${String(failure || 'operation failed').trim()}`];
3
+
4
+ if (impact) {
5
+ lines.push(`Impact: ${String(impact).trim()}`);
6
+ }
7
+ if (fix) {
8
+ lines.push(`Fix: ${String(fix).trim()}`);
9
+ }
10
+ if (nextCommand) {
11
+ lines.push(`Next command: ${String(nextCommand).trim()}`);
12
+ }
13
+
14
+ return lines.join('\n');
15
+ }
16
+
17
+ function createActionableError(code, fields = {}, details = {}) {
18
+ const error = new Error(formatActionableError(fields));
19
+ error.code = code;
20
+ error.details = details;
21
+ return error;
22
+ }
23
+
24
+ module.exports = {
25
+ createActionableError,
26
+ formatActionableError,
27
+ };
@@ -4,7 +4,7 @@ const path = require('node:path');
4
4
  const { assertSupportedProvider, formatProviderList } = require('./ai/providers');
5
5
  const { quiverInternalPaths } = require('./init-layout');
6
6
 
7
- const AGENT_PROFILE_ROLES = Object.freeze(['planner', 'executor', 'reviewer', 'researcher']);
7
+ const AGENT_PROFILE_ROLES = Object.freeze(['planner', 'executor', 'reviewer', 'doctor']);
8
8
  const PROFILE_STATE_VERSION = 1;
9
9
 
10
10
  function formatError(message) {
@@ -95,6 +95,16 @@ function listAgentProfiles(projectRoot) {
95
95
  }
96
96
 
97
97
  function setAgentProfile(projectRoot, role, options = {}) {
98
+ const next = buildAgentProfileState(projectRoot, role, options);
99
+
100
+ const filePath = writeAgentProfiles(projectRoot, next.state);
101
+ return {
102
+ filePath,
103
+ profile: next.profile,
104
+ };
105
+ }
106
+
107
+ function buildAgentProfileState(projectRoot, role, options = {}) {
98
108
  const normalizedRole = normalizeAgentProfileRole(role);
99
109
  const provider = assertSupportedProvider(options.provider);
100
110
  const model = normalizeOptionalText(options.model, 'model');
@@ -102,7 +112,7 @@ function setAgentProfile(projectRoot, role, options = {}) {
102
112
  const context = normalizeOptionalText(options.context, 'context');
103
113
  const state = readAgentProfiles(projectRoot);
104
114
  const current = state.profiles[normalizedRole] || {};
105
- const now = new Date().toISOString();
115
+ const now = options.now instanceof Date ? options.now.toISOString() : new Date().toISOString();
106
116
  const profile = {
107
117
  role: normalizedRole,
108
118
  provider,
@@ -119,10 +129,11 @@ function setAgentProfile(projectRoot, role, options = {}) {
119
129
  };
120
130
  state.updated_at = now;
121
131
 
122
- const filePath = writeAgentProfiles(projectRoot, state);
123
132
  return {
124
- filePath,
133
+ action: current.provider ? 'update' : 'create',
134
+ filePath: agentProfilesPath(projectRoot),
125
135
  profile,
136
+ state,
126
137
  };
127
138
  }
128
139
 
@@ -139,6 +150,7 @@ module.exports = {
139
150
  PROFILE_STATE_VERSION,
140
151
  agentProfilesPath,
141
152
  formatProviderList,
153
+ buildAgentProfileState,
142
154
  getAgentProfile,
143
155
  listAgentProfiles,
144
156
  normalizeAgentProfileRole,
@@ -0,0 +1,318 @@
1
+ const fs = require('node:fs');
2
+ const os = require('node:os');
3
+ const path = require('node:path');
4
+
5
+ const { redactSecrets } = require('../evidence');
6
+ const { quiverInternalPaths } = require('../init-layout');
7
+
8
+ const RAW_ARTIFACT_SCHEMA_VERSION = 1;
9
+ const DEFAULT_MAX_PROVIDER_PROMPT_BYTES = 1024 * 1024;
10
+ const DEFAULT_MAX_REVISION_INPUT_BYTES = 400 * 1024;
11
+ const DEFAULT_COMPACTED_REVISION_INPUT_BYTES = 120 * 1024;
12
+
13
+ const IMPORTANT_REVISION_LINE = /\b(acceptance|criteri[ao]s?|decision|decisi[o\u00f3]n|risk|riesgo|file|archivo|changed|cambio|scope|alcance|validation|validaci[o\u00f3]n|test|blocker|bloque|dependency|dependencia|assumption|supuesto|pending|pendiente|error|rollback|evidence|evidencia)\b/i;
14
+ const PROVIDER_LOG_LINE = /^\s*(?:\[?(?:debug|info|notice|trace|warn|warning)\]?[:\s-]|(?:codex|claude|gemini)\b.*(?:provider|model|prompt|token|running|loading|thinking)|(?:using|loading)\s+(?:model|provider)\b|prompt\s+(?:length|transport)\s*:)/i;
15
+
16
+ function formatError(message) {
17
+ return `create-quiver: ${message}`;
18
+ }
19
+
20
+ function byteLength(value) {
21
+ return Buffer.byteLength(String(value || ''), 'utf8');
22
+ }
23
+
24
+ function normalizeText(value) {
25
+ return String(value || '')
26
+ .replace(/\r\n/g, '\n')
27
+ .replace(/\r/g, '\n')
28
+ .replace(/\u001b\[[0-9;]*m/g, '');
29
+ }
30
+
31
+ function escapeRegExp(value) {
32
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
33
+ }
34
+
35
+ function redactSensitiveLocalValues(text, options = {}) {
36
+ let result = redactSecrets(text);
37
+ const replacements = [];
38
+
39
+ if (options.projectRoot) {
40
+ replacements.push({
41
+ value: path.resolve(options.projectRoot),
42
+ label: '[PROJECT_ROOT]',
43
+ });
44
+ }
45
+
46
+ if (os.homedir()) {
47
+ replacements.push({
48
+ value: os.homedir(),
49
+ label: '[HOME]',
50
+ });
51
+ }
52
+
53
+ for (const replacement of replacements) {
54
+ if (!replacement.value) {
55
+ continue;
56
+ }
57
+ result = result.replace(new RegExp(escapeRegExp(replacement.value), 'g'), replacement.label);
58
+ }
59
+
60
+ return result;
61
+ }
62
+
63
+ function normalizePositiveInteger(value, fallback) {
64
+ if (value === undefined || value === null || value === '') {
65
+ return fallback;
66
+ }
67
+ const parsed = Number(value);
68
+ if (!Number.isFinite(parsed) || parsed <= 0) {
69
+ return fallback;
70
+ }
71
+ return Math.floor(parsed);
72
+ }
73
+
74
+ function resolveAiArtifactLimits(options = {}) {
75
+ return {
76
+ maxProviderPromptBytes: normalizePositiveInteger(
77
+ options.maxProviderPromptBytes ?? process.env.QUIVER_AI_MAX_PROMPT_BYTES,
78
+ DEFAULT_MAX_PROVIDER_PROMPT_BYTES,
79
+ ),
80
+ maxRevisionInputBytes: normalizePositiveInteger(
81
+ options.maxRevisionInputBytes ?? process.env.QUIVER_AI_MAX_REVISION_INPUT_BYTES,
82
+ DEFAULT_MAX_REVISION_INPUT_BYTES,
83
+ ),
84
+ compactedRevisionInputBytes: normalizePositiveInteger(
85
+ options.compactedRevisionInputBytes ?? process.env.QUIVER_AI_COMPACTED_REVISION_INPUT_BYTES,
86
+ DEFAULT_COMPACTED_REVISION_INPUT_BYTES,
87
+ ),
88
+ };
89
+ }
90
+
91
+ function stripPromptEcho(text, prompt) {
92
+ const normalizedText = normalizeText(text);
93
+ const normalizedPrompt = normalizeText(prompt).trim();
94
+
95
+ if (!normalizedPrompt || normalizedPrompt.length < 80) {
96
+ return normalizedText;
97
+ }
98
+
99
+ const directIndex = normalizedText.indexOf(normalizedPrompt);
100
+ if (directIndex >= 0) {
101
+ return `${normalizedText.slice(0, directIndex)}${normalizedText.slice(directIndex + normalizedPrompt.length)}`;
102
+ }
103
+
104
+ return normalizedText;
105
+ }
106
+
107
+ function stripProviderLogEdges(text) {
108
+ const lines = normalizeText(text).split('\n');
109
+
110
+ while (lines.length > 0 && (PROVIDER_LOG_LINE.test(lines[0]) || lines[0].trim() === '')) {
111
+ lines.shift();
112
+ }
113
+
114
+ while (lines.length > 0 && (PROVIDER_LOG_LINE.test(lines[lines.length - 1]) || lines[lines.length - 1].trim() === '')) {
115
+ lines.pop();
116
+ }
117
+
118
+ return lines.join('\n').trim();
119
+ }
120
+
121
+ function normalizeDraftOutput(text, sourceText = text) {
122
+ const value = normalizeText(text).trim();
123
+ if (!value) {
124
+ return '';
125
+ }
126
+ return /\n\s*$/.test(String(sourceText || '')) ? `${value}\n` : value;
127
+ }
128
+
129
+ function extractCleanProviderOutput(result, options = {}) {
130
+ const stdout = redactSensitiveLocalValues(result?.stdout || '', options);
131
+ const stderr = redactSensitiveLocalValues(result?.stderr || '', options);
132
+ const primary = stdout.trim() ? stdout : stderr;
133
+ const cleaned = stripProviderLogEdges(stripPromptEcho(primary, options.prompt || ''));
134
+ const cleanOutput = normalizeDraftOutput(cleaned, primary);
135
+
136
+ if (cleanOutput) {
137
+ return {
138
+ cleanOutput,
139
+ source: stdout.trim() ? 'stdout' : 'stderr',
140
+ strippedPromptEcho: primary !== stripPromptEcho(primary, options.prompt || ''),
141
+ };
142
+ }
143
+
144
+ return {
145
+ cleanOutput: normalizeDraftOutput(primary || [stdout, stderr].filter(Boolean).join('\n'), primary),
146
+ source: stdout.trim() ? 'stdout' : stderr.trim() ? 'stderr' : 'empty',
147
+ strippedPromptEcho: false,
148
+ };
149
+ }
150
+
151
+ function safeArtifactName(scope, now = new Date()) {
152
+ const slug = String(scope || 'provider-output')
153
+ .trim()
154
+ .toLowerCase()
155
+ .replace(/[^a-z0-9._-]+/g, '-')
156
+ .replace(/^-+|-+$/g, '') || 'provider-output';
157
+ const stamp = now.toISOString()
158
+ .replace(/\.\d{3}Z$/, 'z')
159
+ .replace(/[^0-9a-z]+/gi, '-')
160
+ .toLowerCase()
161
+ .replace(/^-+|-+$/g, '');
162
+ return `${stamp}-${slug}.json`;
163
+ }
164
+
165
+ function toRelativePosix(root, filePath) {
166
+ return path.relative(root, filePath).split(path.sep).join('/');
167
+ }
168
+
169
+ function writeRawProviderArtifact(projectRoot, runId, scope, result, options = {}) {
170
+ if (!runId) {
171
+ throw new Error(formatError('missing AI run id for raw provider artifact'));
172
+ }
173
+
174
+ const now = options.now || new Date();
175
+ const rawDir = path.join(quiverInternalPaths(projectRoot).runsDir, String(runId), 'raw');
176
+ const rawPath = path.join(rawDir, safeArtifactName(scope, now));
177
+ const serializedError = result?.error
178
+ ? {
179
+ code: result.error.code || null,
180
+ message: result.error.message || String(result.error),
181
+ provider: result.error.provider || null,
182
+ command: result.error.command || null,
183
+ }
184
+ : null;
185
+ const artifact = {
186
+ schema_version: RAW_ARTIFACT_SCHEMA_VERSION,
187
+ kind: 'provider-output',
188
+ scope: String(scope || 'provider-output'),
189
+ created_at: now.toISOString(),
190
+ provider: result?.provider || null,
191
+ command: result?.command || null,
192
+ args: Array.isArray(result?.args) ? result.args.slice() : [],
193
+ cwd: result?.cwd ? redactSensitiveLocalValues(result.cwd, { projectRoot }) : null,
194
+ ok: Boolean(result?.ok),
195
+ dry_run: Boolean(result?.dryRun),
196
+ exit_code: typeof result?.exitCode === 'number' ? result.exitCode : null,
197
+ signal: result?.signal || null,
198
+ timeout_ms: typeof result?.timeoutMs === 'number' ? result.timeoutMs : null,
199
+ prompt_transport: result?.promptTransport || null,
200
+ stdout: redactSensitiveLocalValues(result?.stdout || '', { projectRoot }),
201
+ stderr: redactSensitiveLocalValues(result?.stderr || '', { projectRoot }),
202
+ error: serializedError ? JSON.parse(redactSensitiveLocalValues(JSON.stringify(serializedError), { projectRoot })) : null,
203
+ metadata: options.metadata || {},
204
+ };
205
+
206
+ fs.mkdirSync(rawDir, { recursive: true });
207
+ fs.writeFileSync(rawPath, `${JSON.stringify(artifact, null, 2)}\n`);
208
+
209
+ return {
210
+ filePath: rawPath,
211
+ path: toRelativePosix(projectRoot, rawPath),
212
+ artifact,
213
+ };
214
+ }
215
+
216
+ function compactTextToByteLimit(text, maxBytes) {
217
+ let value = normalizeText(text).trim();
218
+ if (byteLength(value) <= maxBytes) {
219
+ return value;
220
+ }
221
+
222
+ while (byteLength(value) > maxBytes && value.length > 0) {
223
+ value = value.slice(0, Math.max(0, value.length - Math.ceil((byteLength(value) - maxBytes) / 2) - 32)).trimEnd();
224
+ }
225
+
226
+ return value;
227
+ }
228
+
229
+ function compactRevisionInput(inputText, options = {}) {
230
+ const limits = resolveAiArtifactLimits(options);
231
+ const originalText = normalizeText(inputText);
232
+ const originalBytes = byteLength(originalText);
233
+
234
+ if (originalBytes <= limits.maxRevisionInputBytes) {
235
+ return {
236
+ text: originalText,
237
+ compaction: null,
238
+ };
239
+ }
240
+
241
+ const lines = originalText.split('\n');
242
+ const selected = [];
243
+ const seen = new Set();
244
+ const addLine = (line) => {
245
+ const key = line;
246
+ if (seen.has(key)) {
247
+ return;
248
+ }
249
+ seen.add(key);
250
+ selected.push(line);
251
+ };
252
+
253
+ lines.slice(0, 24).forEach(addLine);
254
+ for (const line of lines) {
255
+ if (/^\s*#{1,6}\s+/.test(line) || IMPORTANT_REVISION_LINE.test(line)) {
256
+ addLine(line);
257
+ }
258
+ }
259
+ lines.slice(-24).forEach(addLine);
260
+
261
+ const preface = [
262
+ `[Quiver compacted oversized revise input from ${originalBytes} bytes before provider execution.]`,
263
+ '[Preserved headings and lines mentioning decisions, risks, files, acceptance criteria, validation, blockers, dependencies, assumptions, pending work, rollback, and evidence.]',
264
+ '',
265
+ ].join('\n');
266
+ const compacted = `${preface}${selected.join('\n')}`;
267
+ const targetBytes = Math.min(limits.compactedRevisionInputBytes, limits.maxRevisionInputBytes);
268
+ const finalText = compactTextToByteLimit(compacted, targetBytes);
269
+ const compactedBytes = byteLength(finalText);
270
+
271
+ if (compactedBytes > limits.maxRevisionInputBytes) {
272
+ const error = new Error(formatError(`ai revise input is too large after compaction (${compactedBytes} bytes; limit ${limits.maxRevisionInputBytes}). Reduce feedback size and retry.`));
273
+ error.code = 'AI_INPUT_TOO_LARGE';
274
+ throw error;
275
+ }
276
+
277
+ return {
278
+ text: `${finalText.trimEnd()}\n`,
279
+ compaction: {
280
+ compacted: true,
281
+ original_bytes: originalBytes,
282
+ compacted_bytes: compactedBytes,
283
+ max_revision_input_bytes: limits.maxRevisionInputBytes,
284
+ preserved: ['headings', 'decisions', 'risks', 'files', 'acceptance criteria', 'validation', 'blockers', 'dependencies', 'assumptions', 'rollback', 'evidence'],
285
+ },
286
+ };
287
+ }
288
+
289
+ function assertProviderPromptWithinLimit(prompt, options = {}) {
290
+ const limits = resolveAiArtifactLimits(options);
291
+ const promptBytes = byteLength(prompt);
292
+
293
+ if (promptBytes <= limits.maxProviderPromptBytes) {
294
+ return {
295
+ prompt,
296
+ bytes: promptBytes,
297
+ maxProviderPromptBytes: limits.maxProviderPromptBytes,
298
+ };
299
+ }
300
+
301
+ const error = new Error(formatError(`provider prompt is too large (${promptBytes} bytes; limit ${limits.maxProviderPromptBytes}). Reduce the input, split the work, or run ai revise with focused feedback before invoking the provider.`));
302
+ error.code = 'AI_PROMPT_TOO_LARGE';
303
+ throw error;
304
+ }
305
+
306
+ module.exports = {
307
+ DEFAULT_COMPACTED_REVISION_INPUT_BYTES,
308
+ DEFAULT_MAX_PROVIDER_PROMPT_BYTES,
309
+ DEFAULT_MAX_REVISION_INPUT_BYTES,
310
+ RAW_ARTIFACT_SCHEMA_VERSION,
311
+ assertProviderPromptWithinLimit,
312
+ byteLength,
313
+ compactRevisionInput,
314
+ extractCleanProviderOutput,
315
+ redactSensitiveLocalValues,
316
+ resolveAiArtifactLimits,
317
+ writeRawProviderArtifact,
318
+ };
@@ -45,9 +45,13 @@ const DEFAULT_CONTEXT_PACK_BY_ROLE = Object.freeze({
45
45
 
46
46
  const PACK_ORDER = ['full', 'planning', 'slice', 'minimal'];
47
47
  const CONTEXT_PREPARED_DOC_PATHS = Object.freeze([
48
+ 'docs/INDEX.md',
49
+ 'docs/PROJECT_MAP.md',
48
50
  'docs/AI_CONTEXT.md',
49
51
  'docs/AI_ONBOARDING_PROMPT.md',
50
52
  'docs/CONTEXTO.md',
53
+ 'docs/WORKFLOW.md',
54
+ 'docs/ARCHITECTURE.md',
51
55
  'docs/STATUS.md',
52
56
  'docs/DECISIONS.md',
53
57
  ]);
@@ -3,6 +3,7 @@ const path = require('node:path');
3
3
 
4
4
  const { resolveProfileProvider } = require('../agent-profiles');
5
5
  const { branchDelete, runGit, statusPorcelain, worktreeAdd, worktreePrune, worktreeRemove } = require('../git');
6
+ const { withLock } = require('../locks');
6
7
  const { safeBranchName, worktreesRootForRepo } = require('../slice');
7
8
  const { buildGraph, computeLevels, detectFileConflicts, isFoundationSliceId, readAllSlices, topoSort, SliceGraphError } = require('../slice-graph');
8
9
  const { runExecuteSlice } = require('./executor');
@@ -35,6 +36,9 @@ function summarizeSlice(node, repoRoot) {
35
36
  title: node.title || node.sliceId,
36
37
  status: node.status || 'draft',
37
38
  files: Array.isArray(node.files) ? node.files : [],
39
+ expected_read_paths: Array.isArray(node.expected_read_paths) ? node.expected_read_paths : [],
40
+ allowed_write_paths: Array.isArray(node.allowed_write_paths) ? node.allowed_write_paths : [],
41
+ validation_hints: Array.isArray(node.validation_hints) ? node.validation_hints : [],
38
42
  depends_on: Array.isArray(node.depends_on) ? node.depends_on : [],
39
43
  parallel_safe: node.parallel_safe || null,
40
44
  parallel_safe_reason: node.parallel_safe_reason || null,
@@ -274,7 +278,7 @@ function formatHumanExecutionPlan(report) {
274
278
 
275
279
  for (const level of report.ready_levels) {
276
280
  const modeLabel = level.parallel_ready ? 'parallel-ready' : 'sequential';
277
- lines.push(`Level ${level.index} (${modeLabel})`);
281
+ lines.push(`Wave ${level.index} (${modeLabel})`);
278
282
  lines.push(`Worktree strategy: ${level.worktree_strategy.mode}`);
279
283
  if (level.fallback_reason) {
280
284
  lines.push(`Fallback: ${level.fallback_reason}`);
@@ -282,6 +286,7 @@ function formatHumanExecutionPlan(report) {
282
286
 
283
287
  for (const slice of level.slices) {
284
288
  lines.push(`- ${slice.ref} [${slice.status}]`);
289
+ lines.push(` parallel_safe: ${slice.parallel_safe || 'unspecified'}${slice.parallel_safe_reason ? ` (${slice.parallel_safe_reason})` : ''}`);
285
290
  }
286
291
 
287
292
  if (level.conflicts.length > 0) {
@@ -454,6 +459,7 @@ async function runSequentialGroup(repoRoot, level, group, options = {}) {
454
459
  providerExplicit: options.providerExplicit,
455
460
  role: options.role,
456
461
  slice: slice.slice_path,
462
+ skipWorktreeBranchCheck: true,
457
463
  timeout: options.timeout,
458
464
  });
459
465
  results.push({
@@ -481,6 +487,13 @@ async function runParallelGroupInWorktrees(repoRoot, level, group, options = {})
481
487
  const slices = group.slice_refs.map((ref) => level.slices.find((item) => item.ref === ref));
482
488
  const workspaces = slices.map((slice, index) => buildDelegatedWorkspace(repoRoot, slice, runId, index, options));
483
489
 
490
+ return withLock(repoRoot, `execute-plan-${runId}`, {
491
+ command: 'ai execute-plan',
492
+ metadata: {
493
+ mode: 'delegated',
494
+ slices: group.slice_refs,
495
+ },
496
+ }, async () => {
484
497
  let runResults;
485
498
  try {
486
499
  worktreePrune(repoRoot);
@@ -498,6 +511,7 @@ async function runParallelGroupInWorktrees(repoRoot, level, group, options = {})
498
511
  providerExplicit: options.providerExplicit,
499
512
  role: options.role,
500
513
  slice: workspace.slice.slice_path,
514
+ skipWorktreeBranchCheck: true,
501
515
  timeout: options.timeout,
502
516
  });
503
517
  const commit = runGit(['rev-parse', 'HEAD'], workspace.worktreePath);
@@ -536,6 +550,7 @@ async function runParallelGroupInWorktrees(repoRoot, level, group, options = {})
536
550
  workspace: item.workspace.worktreePath,
537
551
  integratedCommit: item.commit,
538
552
  }));
553
+ });
539
554
  }
540
555
 
541
556
  async function runExecutePlan(repoRoot, options = {}) {