@popoverai/dotrequirements 0.23.0 → 0.24.1

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 (235) hide show
  1. package/README.md +169 -22
  2. package/dist/cli.js +121 -60
  3. package/dist/codebase-to-spec/budget.d.ts +53 -0
  4. package/dist/codebase-to-spec/budget.js +80 -0
  5. package/dist/codebase-to-spec/cache.d.ts +49 -0
  6. package/dist/codebase-to-spec/cache.js +54 -0
  7. package/dist/codebase-to-spec/claude.d.ts +69 -0
  8. package/dist/codebase-to-spec/claude.js +126 -0
  9. package/dist/codebase-to-spec/compose.d.ts +49 -0
  10. package/dist/codebase-to-spec/compose.js +124 -0
  11. package/dist/codebase-to-spec/edit-loop.d.ts +54 -0
  12. package/dist/codebase-to-spec/edit-loop.js +195 -0
  13. package/dist/codebase-to-spec/editor.d.ts +54 -0
  14. package/dist/codebase-to-spec/editor.js +74 -0
  15. package/dist/codebase-to-spec/exit-codes.d.ts +40 -0
  16. package/dist/codebase-to-spec/exit-codes.js +58 -0
  17. package/dist/codebase-to-spec/fan-out.d.ts +63 -0
  18. package/dist/codebase-to-spec/fan-out.js +215 -0
  19. package/dist/codebase-to-spec/interactive.d.ts +30 -0
  20. package/dist/codebase-to-spec/interactive.js +48 -0
  21. package/dist/codebase-to-spec/outline-review-loop.d.ts +51 -0
  22. package/dist/codebase-to-spec/outline-review-loop.js +187 -0
  23. package/dist/codebase-to-spec/pack.d.ts +51 -0
  24. package/dist/codebase-to-spec/pack.js +127 -0
  25. package/dist/codebase-to-spec/planner.d.ts +41 -0
  26. package/dist/codebase-to-spec/planner.js +76 -0
  27. package/dist/codebase-to-spec/present.d.ts +94 -0
  28. package/dist/codebase-to-spec/present.js +288 -0
  29. package/dist/codebase-to-spec/progress.d.ts +33 -0
  30. package/dist/codebase-to-spec/progress.js +28 -0
  31. package/dist/codebase-to-spec/prompts/editor.d.ts +13 -0
  32. package/dist/codebase-to-spec/prompts/editor.js +57 -0
  33. package/dist/codebase-to-spec/prompts/outline-reviewer.d.ts +12 -0
  34. package/dist/codebase-to-spec/prompts/outline-reviewer.js +87 -0
  35. package/dist/codebase-to-spec/prompts/planner-initial.d.ts +11 -0
  36. package/dist/codebase-to-spec/prompts/planner-initial.js +125 -0
  37. package/dist/codebase-to-spec/prompts/planner-revise.d.ts +14 -0
  38. package/dist/codebase-to-spec/prompts/planner-revise.js +60 -0
  39. package/dist/codebase-to-spec/prompts/spec-reviewer.d.ts +16 -0
  40. package/dist/codebase-to-spec/prompts/spec-reviewer.js +96 -0
  41. package/dist/codebase-to-spec/prompts/specifier.d.ts +12 -0
  42. package/dist/codebase-to-spec/prompts/specifier.js +100 -0
  43. package/dist/codebase-to-spec/prompts/style-check.d.ts +12 -0
  44. package/dist/codebase-to-spec/prompts/style-check.js +78 -0
  45. package/dist/codebase-to-spec/schemas.d.ts +257 -0
  46. package/dist/codebase-to-spec/schemas.js +183 -0
  47. package/dist/codebase-to-spec/skill-install.d.ts +57 -0
  48. package/dist/codebase-to-spec/skill-install.js +79 -0
  49. package/dist/codebase-to-spec/slice.d.ts +49 -0
  50. package/dist/codebase-to-spec/slice.js +111 -0
  51. package/dist/codebase-to-spec/specifier.d.ts +60 -0
  52. package/dist/codebase-to-spec/specifier.js +79 -0
  53. package/dist/codebase-to-spec/style-check.d.ts +29 -0
  54. package/dist/codebase-to-spec/style-check.js +33 -0
  55. package/dist/codebase-to-spec/summary.d.ts +51 -0
  56. package/dist/codebase-to-spec/summary.js +183 -0
  57. package/dist/codebase-to-spec/validate.d.ts +46 -0
  58. package/dist/codebase-to-spec/validate.js +130 -0
  59. package/dist/commands/acceptance-test.d.ts +6 -0
  60. package/dist/commands/{browsertest.js → acceptance-test.js} +36 -29
  61. package/dist/commands/ai-setup.d.ts +5 -0
  62. package/dist/commands/ai-setup.js +441 -0
  63. package/dist/commands/codebase-to-spec/compose.d.ts +14 -0
  64. package/dist/commands/codebase-to-spec/compose.js +57 -0
  65. package/dist/commands/codebase-to-spec/edit-loop.d.ts +16 -0
  66. package/dist/commands/codebase-to-spec/edit-loop.js +83 -0
  67. package/dist/commands/codebase-to-spec/fan-out.d.ts +19 -0
  68. package/dist/commands/codebase-to-spec/fan-out.js +77 -0
  69. package/dist/commands/codebase-to-spec/index.d.ts +9 -0
  70. package/dist/commands/codebase-to-spec/index.js +135 -0
  71. package/dist/commands/codebase-to-spec/pack.d.ts +22 -0
  72. package/dist/commands/codebase-to-spec/pack.js +76 -0
  73. package/dist/commands/codebase-to-spec/plan-loop.d.ts +26 -0
  74. package/dist/commands/codebase-to-spec/plan-loop.js +105 -0
  75. package/dist/commands/codebase-to-spec/present.d.ts +21 -0
  76. package/dist/commands/codebase-to-spec/present.js +92 -0
  77. package/dist/commands/codebase-to-spec/run.d.ts +20 -0
  78. package/dist/commands/codebase-to-spec/run.js +85 -0
  79. package/dist/commands/codebase-to-spec/skill-install.d.ts +20 -0
  80. package/dist/commands/codebase-to-spec/skill-install.js +51 -0
  81. package/dist/commands/codebase-to-spec/specify-area.d.ts +18 -0
  82. package/dist/commands/codebase-to-spec/specify-area.js +82 -0
  83. package/dist/commands/codebase-to-spec/style-check.d.ts +15 -0
  84. package/dist/commands/codebase-to-spec/style-check.js +42 -0
  85. package/dist/commands/codebase-to-spec/validate.d.ts +18 -0
  86. package/dist/commands/codebase-to-spec/validate.js +38 -0
  87. package/dist/commands/create-requirement-document.d.ts +2 -0
  88. package/dist/commands/create-requirement-document.js +41 -0
  89. package/dist/commands/finalize.js +7 -7
  90. package/dist/commands/get.d.ts +2 -0
  91. package/dist/commands/get.js +55 -0
  92. package/dist/commands/init.js +132 -117
  93. package/dist/commands/link.js +27 -27
  94. package/dist/commands/list.d.ts +6 -0
  95. package/dist/commands/list.js +43 -0
  96. package/dist/commands/mcp.js +1 -1
  97. package/dist/commands/prepare.js +4 -4
  98. package/dist/commands/pull.js +116 -121
  99. package/dist/commands/push.js +106 -112
  100. package/dist/commands/report.d.ts +6 -2
  101. package/dist/commands/report.js +177 -122
  102. package/dist/commands/requirements-for.d.ts +2 -0
  103. package/dist/commands/requirements-for.js +29 -0
  104. package/dist/commands/review-test.d.ts +2 -0
  105. package/dist/commands/review-test.js +75 -0
  106. package/dist/commands/search.d.ts +6 -0
  107. package/dist/commands/search.js +39 -0
  108. package/dist/commands/style-check.d.ts +7 -0
  109. package/dist/commands/style-check.js +75 -0
  110. package/dist/commands/tests-for.d.ts +2 -0
  111. package/dist/commands/tests-for.js +80 -0
  112. package/dist/commands/validate.d.ts +6 -0
  113. package/dist/commands/validate.js +72 -0
  114. package/dist/config.js +1 -1
  115. package/dist/convex.d.ts +34 -22
  116. package/dist/convex.js +38 -22
  117. package/dist/harness/cache.d.ts +1 -5
  118. package/dist/harness/cache.js +49 -59
  119. package/dist/harness/convexReporting.d.ts +1 -1
  120. package/dist/harness/convexReporting.js +9 -7
  121. package/dist/harness/coverageCache.js +3 -3
  122. package/dist/harness/finalize.js +59 -46
  123. package/dist/harness/index.d.ts +6 -7
  124. package/dist/harness/index.js +9 -10
  125. package/dist/harness/prepare.js +6 -5
  126. package/dist/harness/requirementsLoader.d.ts +2 -2
  127. package/dist/harness/requirementsLoader.js +13 -35
  128. package/dist/harness/tracking.js +18 -18
  129. package/dist/harness/types.d.ts +1 -1
  130. package/dist/mcp/convexClient.d.ts +0 -39
  131. package/dist/mcp/convexClient.js +2 -107
  132. package/dist/mcp/handlers/authoring.d.ts +1 -1
  133. package/dist/mcp/handlers/authoring.js +30 -234
  134. package/dist/mcp/handlers/debug.d.ts +2 -3
  135. package/dist/mcp/handlers/debug.js +10 -10
  136. package/dist/mcp/handlers/get.d.ts +1 -1
  137. package/dist/mcp/handlers/get.js +11 -10
  138. package/dist/mcp/handlers/index.d.ts +20 -20
  139. package/dist/mcp/handlers/index.js +10 -10
  140. package/dist/mcp/handlers/list.d.ts +4 -33
  141. package/dist/mcp/handlers/list.js +16 -38
  142. package/dist/mcp/handlers/push.d.ts +1 -1
  143. package/dist/mcp/handlers/push.js +28 -18
  144. package/dist/mcp/handlers/report.d.ts +16 -0
  145. package/dist/mcp/handlers/report.js +134 -0
  146. package/dist/mcp/handlers/review.d.ts +1 -1
  147. package/dist/mcp/handlers/review.js +40 -59
  148. package/dist/mcp/handlers/search.d.ts +1 -1
  149. package/dist/mcp/handlers/search.js +7 -9
  150. package/dist/mcp/handlers/test-mapping.d.ts +1 -1
  151. package/dist/mcp/handlers/test-mapping.js +14 -14
  152. package/dist/mcp/handlers/types.d.ts +3 -3
  153. package/dist/mcp/handlers/types.js +2 -2
  154. package/dist/mcp/index.d.ts +1 -1
  155. package/dist/mcp/index.js +147 -167
  156. package/dist/push/core.d.ts +2 -2
  157. package/dist/push/core.js +20 -20
  158. package/dist/push/index.d.ts +1 -1
  159. package/dist/push/index.js +2 -2
  160. package/dist/requirements/cloud-ai.d.ts +57 -0
  161. package/dist/requirements/cloud-ai.js +104 -0
  162. package/dist/requirements/cloud-coverage.d.ts +41 -0
  163. package/dist/requirements/cloud-coverage.js +60 -0
  164. package/dist/requirements/coverage.d.ts +45 -0
  165. package/dist/requirements/coverage.js +114 -0
  166. package/dist/{mcp → requirements}/grep.d.ts +10 -1
  167. package/dist/{mcp → requirements}/grep.js +89 -44
  168. package/dist/{mcp/requirements.d.ts → requirements/index.d.ts} +19 -3
  169. package/dist/{mcp/requirements.js → requirements/index.js} +54 -35
  170. package/dist/requirements/style-guide.d.ts +67 -0
  171. package/dist/requirements/style-guide.js +299 -0
  172. package/dist/{mcp → requirements}/testCodeExtractor.js +24 -26
  173. package/dist/schema/browser.d.ts +8 -8
  174. package/dist/schema/browser.js +13 -15
  175. package/dist/schema/builder.d.ts +1 -1
  176. package/dist/schema/builder.js +13 -44
  177. package/dist/schema/conversions.d.ts +2 -2
  178. package/dist/schema/conversions.js +11 -11
  179. package/dist/schema/index.d.ts +9 -9
  180. package/dist/schema/index.js +15 -15
  181. package/dist/schema/parser-core.d.ts +1 -1
  182. package/dist/schema/parser-core.js +23 -22
  183. package/dist/schema/parser.d.ts +3 -3
  184. package/dist/schema/parser.js +27 -31
  185. package/dist/schema/resolver.d.ts +1 -1
  186. package/dist/schema/resolver.js +9 -9
  187. package/dist/schema/scenario.d.ts +1 -1
  188. package/dist/schema/scenario.js +1 -1
  189. package/dist/schema/schemas.d.ts +3 -3
  190. package/dist/schema/schemas.js +41 -28
  191. package/dist/schema/test-schema.js +27 -27
  192. package/dist/templates/context-file-section.md +3 -2
  193. package/dist/templates/example-requirements.js +1 -1
  194. package/dist/templates/example-requirements.ts +3 -1
  195. package/dist/templates/requirements-readme.js +1 -1
  196. package/dist/templates/requirements-readme.ts +1 -1
  197. package/dist/templates/skills/codebase-to-spec/SKILL.md +118 -0
  198. package/dist/utils/brand.js +3 -3
  199. package/dist/utils/browser-launch.js +4 -4
  200. package/dist/utils/context-file.d.ts +1 -1
  201. package/dist/utils/context-file.js +26 -26
  202. package/dist/utils/env.js +7 -7
  203. package/dist/utils/gitignore.js +7 -7
  204. package/dist/utils/oauth-callback-server.d.ts +1 -1
  205. package/dist/utils/oauth-callback-server.js +27 -25
  206. package/dist/utils/oauth-flow.js +32 -29
  207. package/dist/utils/project-discovery.d.ts +3 -3
  208. package/dist/utils/project-discovery.js +18 -17
  209. package/dist/utils/project-name.js +8 -8
  210. package/dist/utils/project-selector.d.ts +1 -1
  211. package/dist/utils/project-selector.js +24 -21
  212. package/dist/utils/project-settings.d.ts +1 -1
  213. package/dist/utils/project-settings.js +24 -22
  214. package/dist/utils/templates.js +6 -6
  215. package/package.json +3 -2
  216. package/dist/commands/browsertest.d.ts +0 -6
  217. package/dist/commands/login.d.ts +0 -12
  218. package/dist/commands/login.js +0 -117
  219. package/dist/commands/logout.d.ts +0 -5
  220. package/dist/commands/logout.js +0 -17
  221. package/dist/commands/mcp-setup.d.ts +0 -5
  222. package/dist/commands/mcp-setup.js +0 -431
  223. package/dist/commands/test.d.ts +0 -6
  224. package/dist/commands/test.js +0 -78
  225. package/dist/mcp/handlers/coverage.d.ts +0 -44
  226. package/dist/mcp/handlers/coverage.js +0 -105
  227. package/dist/mcp/types.d.ts +0 -27
  228. package/dist/mcp/types.js +0 -2
  229. package/dist/utils/local-project.d.ts +0 -31
  230. package/dist/utils/local-project.js +0 -33
  231. package/dist/utils/token-refresh.d.ts +0 -24
  232. package/dist/utils/token-refresh.js +0 -69
  233. package/dist/utils/token-storage.d.ts +0 -31
  234. package/dist/utils/token-storage.js +0 -57
  235. /package/dist/{mcp → requirements}/testCodeExtractor.d.ts +0 -0
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Spec review + editor loop.
3
+ *
4
+ * Same structure as the outline review loop, scaled up for document-level
5
+ * revision: stateful spec reviewer + stateless editor. The reviewer
6
+ * persists across turns so it can compare prior spec versions to the latest.
7
+ *
8
+ * Requirements covered:
9
+ * - CTS-EDIT-1: stateful spec reviewer
10
+ * - CTS-EDIT-2: approved → proceed
11
+ * - CTS-EDIT-3: approved-with-revisions → one mechanical edit pass
12
+ * - CTS-EDIT-4: requires-another-review → revise & resubmit
13
+ * - CTS-EDIT-5: editor operates on cohesive document
14
+ * - CTS-EDIT-6: max-turns + convergence nudge
15
+ */
16
+ import { randomUUID } from "node:crypto";
17
+ import { copyFileSync } from "node:fs";
18
+ import { runClaude } from "./claude.js";
19
+ import { runEditor } from "./editor.js";
20
+ import { SPEC_REVIEWER_PROMPT } from "./prompts/spec-reviewer.js";
21
+ import { parseSpecReview, SPEC_REVIEW_JSON_SCHEMA, } from "./schemas.js";
22
+ export const DEFAULT_EDIT_LOOP_MAX_TURNS = 6;
23
+ function reviewerUserMessageInitial(specPath, packPath) {
24
+ return [
25
+ `Initial spec review.`,
26
+ ``,
27
+ `Composed spec: ${specPath}`,
28
+ `Codebase pack: ${packPath}`,
29
+ ``,
30
+ `Read both via the Read tool, then produce your critique JSON.`,
31
+ ].join("\n");
32
+ }
33
+ function reviewerUserMessageRevised(turn, specPath, packPath, nudge) {
34
+ const lines = [
35
+ `Review turn ${turn}. The editor has revised the spec based on your prior feedback.`,
36
+ ``,
37
+ ];
38
+ if (nudge) {
39
+ lines.push(nudge, ``);
40
+ }
41
+ lines.push(`Revised spec: ${specPath}`, `Codebase pack at ${packPath} is unchanged.`, ``, `Read the revised spec, compare to the prior version, and produce your critique JSON.`);
42
+ return lines.join("\n");
43
+ }
44
+ function convergenceNudge(turn, maxTurns) {
45
+ return `CONVERGENCE NUDGE: This is review turn ${turn} of ${maxTurns} maximum. Please prioritize convergence. Your job is still to only approve a genuinely-ready spec, but if it is close, lean toward \`approved-with-revisions\` over \`requires-another-review\`. Reserve \`requires-another-review\` for genuine issues that the editor has not addressed despite prior feedback.`;
46
+ }
47
+ async function callReviewer(args) {
48
+ const result = await args.runner({
49
+ systemPrompt: SPEC_REVIEWER_PROMPT,
50
+ userMessage: args.userMessage,
51
+ model: args.model,
52
+ tools: ["Read", "Grep", "Glob"],
53
+ addDirs: args.addDirs,
54
+ jsonSchema: SPEC_REVIEW_JSON_SCHEMA,
55
+ session: {
56
+ kind: args.isFirstTurn ? "fresh" : "resume",
57
+ sessionId: args.sessionId,
58
+ },
59
+ });
60
+ if (result.exitCode !== 0) {
61
+ throw new Error(`Spec reviewer failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);
62
+ }
63
+ // Retry-once on parse failure (CTS-EDIT-1 convention, same as outline loop).
64
+ try {
65
+ return parseSpecReview(result.stdout);
66
+ }
67
+ catch (err) {
68
+ const retry = await args.runner({
69
+ systemPrompt: SPEC_REVIEWER_PROMPT,
70
+ userMessage: `${args.userMessage}\n\n(Your prior output failed schema validation: ${err instanceof Error ? err.message : String(err)}. Please try again, emitting JSON only.)`,
71
+ model: args.model,
72
+ tools: ["Read", "Grep", "Glob"],
73
+ addDirs: args.addDirs,
74
+ jsonSchema: SPEC_REVIEW_JSON_SCHEMA,
75
+ session: { kind: "resume", sessionId: args.sessionId },
76
+ });
77
+ if (retry.exitCode !== 0) {
78
+ throw new Error(`Spec reviewer retry failed (exit ${retry.exitCode}): ${retry.stderr || retry.stdout}`);
79
+ }
80
+ return parseSpecReview(retry.stdout);
81
+ }
82
+ }
83
+ export async function runEditLoop(options) {
84
+ const { composedSpecPath, specVersionFor, fullPackPath, addDirs, maxTurns = DEFAULT_EDIT_LOOP_MAX_TURNS, runner = runClaude, model, progress, sessionId = randomUUID(), } = options;
85
+ // Turn 1: copy the composed spec to spec-v1 and review it.
86
+ const specV1 = specVersionFor(1);
87
+ copyFileSync(composedSpecPath, specV1);
88
+ progress?.emit({
89
+ stage: "spec-review",
90
+ step: "turn-1",
91
+ message: `Reviewing composed spec (${specV1})`,
92
+ });
93
+ let review = await callReviewer({
94
+ runner,
95
+ sessionId,
96
+ isFirstTurn: true,
97
+ userMessage: reviewerUserMessageInitial(specV1, fullPackPath),
98
+ addDirs,
99
+ model,
100
+ });
101
+ const specPathsByTurn = [specV1];
102
+ const reviewsByTurn = [review];
103
+ let currentSpecPath = specV1;
104
+ progress?.emit({
105
+ stage: "spec-review",
106
+ step: "turn-1",
107
+ message: `Verdict: ${review.verdict}`,
108
+ data: { verdict: review.verdict },
109
+ });
110
+ let turn = 1;
111
+ while (review.verdict === "requires-another-review" && turn < maxTurns) {
112
+ turn++;
113
+ const nextSpec = specVersionFor(turn);
114
+ progress?.emit({
115
+ stage: "spec-review",
116
+ step: `edit-turn-${turn}`,
117
+ message: `Editor revising spec (turn ${turn}/${maxTurns})`,
118
+ });
119
+ const editResult = await runEditor({
120
+ inputSpecPath: currentSpecPath,
121
+ outputSpecPath: nextSpec,
122
+ fullPackPath,
123
+ addDirs,
124
+ critique: review,
125
+ mode: "revise",
126
+ runner,
127
+ model,
128
+ });
129
+ if (!editResult.wroteSpec) {
130
+ throw new Error(`Editor produced no output spec at ${nextSpec} (exit ${editResult.exitCode}): ${editResult.stderr}`);
131
+ }
132
+ currentSpecPath = nextSpec;
133
+ specPathsByTurn.push(currentSpecPath);
134
+ const nudge = turn >= maxTurns - 1 && turn !== maxTurns
135
+ ? convergenceNudge(turn, maxTurns)
136
+ : undefined;
137
+ progress?.emit({
138
+ stage: "spec-review",
139
+ step: `turn-${turn}`,
140
+ message: `Reviewing revised spec (turn ${turn}/${maxTurns})`,
141
+ data: { turn, maxTurns, nudge: !!nudge },
142
+ });
143
+ review = await callReviewer({
144
+ runner,
145
+ sessionId,
146
+ isFirstTurn: false,
147
+ userMessage: reviewerUserMessageRevised(turn, currentSpecPath, fullPackPath, nudge),
148
+ addDirs,
149
+ model,
150
+ });
151
+ reviewsByTurn.push(review);
152
+ progress?.emit({
153
+ stage: "spec-review",
154
+ step: `turn-${turn}`,
155
+ message: `Verdict: ${review.verdict}`,
156
+ data: { verdict: review.verdict },
157
+ });
158
+ }
159
+ const hitMaxTurns = review.verdict === "requires-another-review" && turn >= maxTurns;
160
+ // approved-with-revisions → apply mechanical revisions to a final version.
161
+ if (review.verdict === "approved-with-revisions" &&
162
+ review.revisions.length > 0) {
163
+ const finalTurn = turn + 1;
164
+ const finalPath = specVersionFor(finalTurn);
165
+ progress?.emit({
166
+ stage: "spec-review",
167
+ step: "apply-revisions",
168
+ message: `Applying ${review.revisions.length} mechanical revision(s)`,
169
+ });
170
+ const applyResult = await runEditor({
171
+ inputSpecPath: currentSpecPath,
172
+ outputSpecPath: finalPath,
173
+ fullPackPath,
174
+ addDirs,
175
+ critique: review,
176
+ mode: "apply",
177
+ runner,
178
+ model,
179
+ });
180
+ if (!applyResult.wroteSpec) {
181
+ throw new Error(`Apply-mode editor produced no output spec at ${finalPath} (exit ${applyResult.exitCode}): ${applyResult.stderr}`);
182
+ }
183
+ currentSpecPath = finalPath;
184
+ specPathsByTurn.push(currentSpecPath);
185
+ }
186
+ return {
187
+ finalSpecPath: currentSpecPath,
188
+ specPathsByTurn,
189
+ reviewsByTurn,
190
+ finalVerdict: review.verdict,
191
+ turnsUsed: turn,
192
+ hitMaxTurns,
193
+ };
194
+ }
195
+ //# sourceMappingURL=edit-loop.js.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Editor worker: revise the composed spec in place based on a reviewer's
3
+ * critique.
4
+ *
5
+ * Two modes:
6
+ * - apply: apply mechanical revisions verbatim (when verdict is `approved-with-revisions`)
7
+ * - revise: address the critique using the editor's own judgment (when verdict is `requires-another-review`)
8
+ *
9
+ * Requirements covered:
10
+ * - CTS-EDIT-3: approved-with-revisions triggers apply mode
11
+ * - CTS-EDIT-4: requires-another-review triggers revise mode
12
+ * - CTS-EDIT-5: editor operates on the cohesive document, reads codebase only on demand
13
+ */
14
+ import { type ClaudeRunner } from "./claude.js";
15
+ import type { SpecReview } from "./schemas.js";
16
+ export type EditorMode = "apply" | "revise";
17
+ export interface EditorContext {
18
+ /**
19
+ * Input spec path. The editor reads from here.
20
+ * If `outputSpecPath` differs, the input is copied to the output path first
21
+ * (so the editor's in-place edits land on the output).
22
+ */
23
+ inputSpecPath: string;
24
+ /** Output spec path (may equal inputSpecPath for true in-place editing). */
25
+ outputSpecPath: string;
26
+ /** Path to the codebase pack the editor may consult on demand. */
27
+ fullPackPath: string;
28
+ /** Directories to grant filesystem access to. */
29
+ addDirs: string[];
30
+ /** Reviewer's critique. */
31
+ critique: SpecReview;
32
+ /** Apply or revise. */
33
+ mode: EditorMode;
34
+ runner?: ClaudeRunner;
35
+ model?: string;
36
+ }
37
+ export interface EditorResult {
38
+ /** True if the output file exists and is non-empty after the editor ran. */
39
+ wroteSpec: boolean;
40
+ /** Size of the output in bytes (0 if missing). */
41
+ outputBytes: number;
42
+ /** Process exit code. */
43
+ exitCode: number;
44
+ /** Captured stdout (one-line confirmation). */
45
+ stdout: string;
46
+ /** Captured stderr. */
47
+ stderr: string;
48
+ }
49
+ /**
50
+ * Run the editor. If outputSpecPath differs from inputSpecPath, copy first
51
+ * so the in-place edits land on the output.
52
+ */
53
+ export declare function runEditor(ctx: EditorContext): Promise<EditorResult>;
54
+ //# sourceMappingURL=editor.d.ts.map
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Editor worker: revise the composed spec in place based on a reviewer's
3
+ * critique.
4
+ *
5
+ * Two modes:
6
+ * - apply: apply mechanical revisions verbatim (when verdict is `approved-with-revisions`)
7
+ * - revise: address the critique using the editor's own judgment (when verdict is `requires-another-review`)
8
+ *
9
+ * Requirements covered:
10
+ * - CTS-EDIT-3: approved-with-revisions triggers apply mode
11
+ * - CTS-EDIT-4: requires-another-review triggers revise mode
12
+ * - CTS-EDIT-5: editor operates on the cohesive document, reads codebase only on demand
13
+ */
14
+ import { copyFileSync, existsSync, statSync } from "node:fs";
15
+ import { runClaude } from "./claude.js";
16
+ import { EDITOR_PROMPT } from "./prompts/editor.js";
17
+ function userMessage(ctx) {
18
+ const mode = ctx.mode === "apply" ? "APPLY" : "REVISE";
19
+ const lines = [
20
+ `Mode: ${mode}`,
21
+ ``,
22
+ `Spec to edit (in place via Edit tool): ${ctx.outputSpecPath}`,
23
+ `Codebase pack (consult only on demand): ${ctx.fullPackPath}`,
24
+ ``,
25
+ `## Reviewer critique`,
26
+ `\`\`\`json`,
27
+ JSON.stringify(ctx.critique, null, 2),
28
+ `\`\`\``,
29
+ ``,
30
+ ];
31
+ if (ctx.mode === "apply") {
32
+ lines.push(`You are in APPLY mode. The reviewer's verdict is \`approved-with-revisions\`. Apply each revision in the \`revisions\` array verbatim. Do not restructure. When done, output a one-line confirmation.`);
33
+ }
34
+ else {
35
+ lines.push(`You are in REVISE mode. The reviewer's verdict is \`requires-another-review\`. Address each finding using your judgment. Use the Edit tool for targeted changes. Consult the codebase only to verify specific findings before adding requirements.`);
36
+ }
37
+ return lines.join("\n");
38
+ }
39
+ /**
40
+ * Run the editor. If outputSpecPath differs from inputSpecPath, copy first
41
+ * so the in-place edits land on the output.
42
+ */
43
+ export async function runEditor(ctx) {
44
+ if (ctx.inputSpecPath !== ctx.outputSpecPath) {
45
+ copyFileSync(ctx.inputSpecPath, ctx.outputSpecPath);
46
+ }
47
+ const runner = ctx.runner ?? runClaude;
48
+ const result = await runner({
49
+ systemPrompt: EDITOR_PROMPT,
50
+ userMessage: userMessage(ctx),
51
+ model: ctx.model,
52
+ tools: ["Read", "Edit", "Grep", "Glob"],
53
+ addDirs: ctx.addDirs,
54
+ });
55
+ let wroteSpec = false;
56
+ let outputBytes = 0;
57
+ if (existsSync(ctx.outputSpecPath)) {
58
+ try {
59
+ outputBytes = statSync(ctx.outputSpecPath).size;
60
+ wroteSpec = outputBytes > 0;
61
+ }
62
+ catch {
63
+ // Treat as not written.
64
+ }
65
+ }
66
+ return {
67
+ wroteSpec,
68
+ outputBytes,
69
+ exitCode: result.exitCode,
70
+ stdout: result.stdout,
71
+ stderr: result.stderr,
72
+ };
73
+ }
74
+ //# sourceMappingURL=editor.js.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Stable exit codes for the codebase-to-spec CLI.
3
+ *
4
+ * Wrappers (the skill, CI tooling, scripts) rely on these to branch on outcome.
5
+ * Breaking changes are part of the CLI's public contract — see CTS-CLI-5.
6
+ *
7
+ * Requirements covered:
8
+ * - CTS-CLI-5: CLI exit codes and progress format are part of the public contract
9
+ */
10
+ export declare const ExitCode: {
11
+ /** Success — pipeline completed normally. */
12
+ readonly Success: 0;
13
+ /** Generic failure — unspecified error. */
14
+ readonly GenericFailure: 1;
15
+ /** A required input was missing (e.g., a stage was invoked without its prerequisite cache artifacts). */
16
+ readonly MissingInput: 2;
17
+ /** A pipeline stage failed (specifier, reviewer, editor, etc.). */
18
+ readonly StageFailed: 3;
19
+ /**
20
+ * The codebase exceeds the working-context budget after compression.
21
+ * The CLI exits with this code when CTS-CLI-3 fires.
22
+ */
23
+ readonly BudgetExceeded: 10;
24
+ /**
25
+ * A review loop hit its max-turns cap without converging on `approved` or
26
+ * `approved-with-revisions`. The latest artifact is still usable; this code
27
+ * signals to callers that the residual review should be surfaced.
28
+ */
29
+ readonly MaxTurnsHit: 11;
30
+ /** Output would overwrite an existing `.requirements/` file in non-interactive mode without an explicit flag. */
31
+ readonly OverwriteRefused: 12;
32
+ /** Invalid combination of CLI flags (e.g., --overwrite and --skip-existing both supplied). */
33
+ readonly InvalidFlags: 13;
34
+ };
35
+ export type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];
36
+ /**
37
+ * Human-readable name for an exit code, suitable for logging and error messages.
38
+ */
39
+ export declare function exitCodeName(code: ExitCodeValue): string;
40
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Stable exit codes for the codebase-to-spec CLI.
3
+ *
4
+ * Wrappers (the skill, CI tooling, scripts) rely on these to branch on outcome.
5
+ * Breaking changes are part of the CLI's public contract — see CTS-CLI-5.
6
+ *
7
+ * Requirements covered:
8
+ * - CTS-CLI-5: CLI exit codes and progress format are part of the public contract
9
+ */
10
+ export const ExitCode = {
11
+ /** Success — pipeline completed normally. */
12
+ Success: 0,
13
+ /** Generic failure — unspecified error. */
14
+ GenericFailure: 1,
15
+ /** A required input was missing (e.g., a stage was invoked without its prerequisite cache artifacts). */
16
+ MissingInput: 2,
17
+ /** A pipeline stage failed (specifier, reviewer, editor, etc.). */
18
+ StageFailed: 3,
19
+ /**
20
+ * The codebase exceeds the working-context budget after compression.
21
+ * The CLI exits with this code when CTS-CLI-3 fires.
22
+ */
23
+ BudgetExceeded: 10,
24
+ /**
25
+ * A review loop hit its max-turns cap without converging on `approved` or
26
+ * `approved-with-revisions`. The latest artifact is still usable; this code
27
+ * signals to callers that the residual review should be surfaced.
28
+ */
29
+ MaxTurnsHit: 11,
30
+ /** Output would overwrite an existing `.requirements/` file in non-interactive mode without an explicit flag. */
31
+ OverwriteRefused: 12,
32
+ /** Invalid combination of CLI flags (e.g., --overwrite and --skip-existing both supplied). */
33
+ InvalidFlags: 13,
34
+ };
35
+ /**
36
+ * Human-readable name for an exit code, suitable for logging and error messages.
37
+ */
38
+ export function exitCodeName(code) {
39
+ switch (code) {
40
+ case ExitCode.Success:
41
+ return "Success";
42
+ case ExitCode.GenericFailure:
43
+ return "GenericFailure";
44
+ case ExitCode.MissingInput:
45
+ return "MissingInput";
46
+ case ExitCode.StageFailed:
47
+ return "StageFailed";
48
+ case ExitCode.BudgetExceeded:
49
+ return "BudgetExceeded";
50
+ case ExitCode.MaxTurnsHit:
51
+ return "MaxTurnsHit";
52
+ case ExitCode.OverwriteRefused:
53
+ return "OverwriteRefused";
54
+ case ExitCode.InvalidFlags:
55
+ return "InvalidFlags";
56
+ }
57
+ }
58
+ //# sourceMappingURL=exit-codes.js.map
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Specifier fan-out orchestrator.
3
+ *
4
+ * For each area in the outline, extract a slice, spawn a specifier worker,
5
+ * and write the resulting partial to the cache. Workers run in parallel up
6
+ * to a bounded concurrency limit. On per-area failure (no partial written,
7
+ * empty partial), the worker is retried once; on second failure, the area
8
+ * is recorded as failed for surfacing to the user.
9
+ *
10
+ * Requirements covered:
11
+ * - CTS-SPEC-1.2: bounded concurrent execution
12
+ * - CTS-SPEC-5: failed/empty specifier output is detected and retried
13
+ * - CTS-OBSERVE-2.0: failure details are logged with area name + cause
14
+ * - CTS-RESUME-1.2: existing non-empty partial means the specifier is skipped
15
+ */
16
+ import type { ClaudeRunner } from "./claude.js";
17
+ import type { ProgressEmitter } from "./progress.js";
18
+ import type { Area, Outline } from "./schemas.js";
19
+ export declare const DEFAULT_FAN_OUT_CONCURRENCY = 8;
20
+ export interface FanOutOptions {
21
+ outline: Outline;
22
+ /** Path to the uncompressed pack (slices come from here). */
23
+ fullPackPath: string;
24
+ /** Path resolver: given a sanitized area name, return the partial path. */
25
+ partialPathFor: (sanitizedAreaName: string) => string;
26
+ /** Path resolver: given a sanitized area name, return the slice path. */
27
+ slicePathFor: (sanitizedAreaName: string) => string;
28
+ /** Command (path + args) the specifier should run to invoke schema validation. Run before style-check. */
29
+ validateCommand: string;
30
+ /** Command (path + args) the specifier should run to invoke style-check. */
31
+ styleCheckCommand: string;
32
+ /** Directories the specifier needs filesystem access to. */
33
+ addDirs: string[];
34
+ concurrency?: number;
35
+ runner?: ClaudeRunner;
36
+ model?: string;
37
+ progress?: ProgressEmitter;
38
+ }
39
+ export interface AreaOutcome {
40
+ area: Area;
41
+ status: "completed" | "skipped-resume" | "failed";
42
+ /** Number of attempts made (1 = first attempt succeeded; 2 = retry succeeded; 2 with failed = retried and still failed). */
43
+ attempts: number;
44
+ /** Reason the area failed, if applicable. */
45
+ failureCause?: string;
46
+ /** Path to the partial (whether or not it was written successfully). */
47
+ partialPath: string;
48
+ }
49
+ export interface FanOutResult {
50
+ outcomes: AreaOutcome[];
51
+ /** True if every area produced a non-empty partial (either now or from cache). */
52
+ allSucceeded: boolean;
53
+ }
54
+ /**
55
+ * Convert an area name to a stable filesystem-safe identifier.
56
+ * E.g., "Reading & Editing Files" → "reading-editing-files"
57
+ */
58
+ export declare function sanitizeAreaName(name: string): string;
59
+ /**
60
+ * Run the fan-out: extract slices, invoke specifiers, retry on failure.
61
+ */
62
+ export declare function runFanOut(options: FanOutOptions): Promise<FanOutResult>;
63
+ //# sourceMappingURL=fan-out.d.ts.map