@popoverai/dotrequirements 0.23.0 → 0.24.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 (229) hide show
  1. package/README.md +167 -20
  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-apply.d.ts +12 -0
  36. package/dist/codebase-to-spec/prompts/planner-apply.js +32 -0
  37. package/dist/codebase-to-spec/prompts/planner-initial.d.ts +11 -0
  38. package/dist/codebase-to-spec/prompts/planner-initial.js +125 -0
  39. package/dist/codebase-to-spec/prompts/planner-revise.d.ts +14 -0
  40. package/dist/codebase-to-spec/prompts/planner-revise.js +60 -0
  41. package/dist/codebase-to-spec/prompts/spec-reviewer.d.ts +16 -0
  42. package/dist/codebase-to-spec/prompts/spec-reviewer.js +96 -0
  43. package/dist/codebase-to-spec/prompts/specifier.d.ts +12 -0
  44. package/dist/codebase-to-spec/prompts/specifier.js +100 -0
  45. package/dist/codebase-to-spec/prompts/style-check.d.ts +12 -0
  46. package/dist/codebase-to-spec/prompts/style-check.js +78 -0
  47. package/dist/codebase-to-spec/schemas.d.ts +257 -0
  48. package/dist/codebase-to-spec/schemas.js +183 -0
  49. package/dist/codebase-to-spec/skill-install.d.ts +57 -0
  50. package/dist/codebase-to-spec/skill-install.js +79 -0
  51. package/dist/codebase-to-spec/slice.d.ts +49 -0
  52. package/dist/codebase-to-spec/slice.js +111 -0
  53. package/dist/codebase-to-spec/specifier.d.ts +60 -0
  54. package/dist/codebase-to-spec/specifier.js +79 -0
  55. package/dist/codebase-to-spec/style-check.d.ts +29 -0
  56. package/dist/codebase-to-spec/style-check.js +33 -0
  57. package/dist/codebase-to-spec/summary.d.ts +51 -0
  58. package/dist/codebase-to-spec/summary.js +183 -0
  59. package/dist/codebase-to-spec/validate.d.ts +46 -0
  60. package/dist/codebase-to-spec/validate.js +130 -0
  61. package/dist/commands/acceptance-test.d.ts +6 -0
  62. package/dist/commands/acceptance-test.js +212 -0
  63. package/dist/commands/ai-setup.d.ts +5 -0
  64. package/dist/commands/ai-setup.js +441 -0
  65. package/dist/commands/browsertest.js +34 -27
  66. package/dist/commands/codebase-to-spec/compose.d.ts +14 -0
  67. package/dist/commands/codebase-to-spec/compose.js +57 -0
  68. package/dist/commands/codebase-to-spec/edit-loop.d.ts +16 -0
  69. package/dist/commands/codebase-to-spec/edit-loop.js +83 -0
  70. package/dist/commands/codebase-to-spec/fan-out.d.ts +19 -0
  71. package/dist/commands/codebase-to-spec/fan-out.js +77 -0
  72. package/dist/commands/codebase-to-spec/index.d.ts +9 -0
  73. package/dist/commands/codebase-to-spec/index.js +135 -0
  74. package/dist/commands/codebase-to-spec/pack.d.ts +22 -0
  75. package/dist/commands/codebase-to-spec/pack.js +76 -0
  76. package/dist/commands/codebase-to-spec/plan-loop.d.ts +26 -0
  77. package/dist/commands/codebase-to-spec/plan-loop.js +105 -0
  78. package/dist/commands/codebase-to-spec/present.d.ts +21 -0
  79. package/dist/commands/codebase-to-spec/present.js +92 -0
  80. package/dist/commands/codebase-to-spec/run.d.ts +20 -0
  81. package/dist/commands/codebase-to-spec/run.js +85 -0
  82. package/dist/commands/codebase-to-spec/skill-install.d.ts +20 -0
  83. package/dist/commands/codebase-to-spec/skill-install.js +51 -0
  84. package/dist/commands/codebase-to-spec/specify-area.d.ts +18 -0
  85. package/dist/commands/codebase-to-spec/specify-area.js +82 -0
  86. package/dist/commands/codebase-to-spec/style-check.d.ts +15 -0
  87. package/dist/commands/codebase-to-spec/style-check.js +42 -0
  88. package/dist/commands/codebase-to-spec/validate.d.ts +18 -0
  89. package/dist/commands/codebase-to-spec/validate.js +38 -0
  90. package/dist/commands/create-requirement-document.d.ts +2 -0
  91. package/dist/commands/create-requirement-document.js +41 -0
  92. package/dist/commands/finalize.js +7 -7
  93. package/dist/commands/get.d.ts +2 -0
  94. package/dist/commands/get.js +55 -0
  95. package/dist/commands/init.js +132 -117
  96. package/dist/commands/link.js +27 -27
  97. package/dist/commands/list.d.ts +6 -0
  98. package/dist/commands/list.js +43 -0
  99. package/dist/commands/mcp-setup.js +159 -149
  100. package/dist/commands/mcp.js +1 -1
  101. package/dist/commands/prepare.js +4 -4
  102. package/dist/commands/pull.js +116 -121
  103. package/dist/commands/push.js +106 -112
  104. package/dist/commands/report.d.ts +6 -2
  105. package/dist/commands/report.js +177 -122
  106. package/dist/commands/requirements-for.d.ts +2 -0
  107. package/dist/commands/requirements-for.js +29 -0
  108. package/dist/commands/review-test.d.ts +2 -0
  109. package/dist/commands/review-test.js +75 -0
  110. package/dist/commands/search.d.ts +6 -0
  111. package/dist/commands/search.js +39 -0
  112. package/dist/commands/style-check.d.ts +7 -0
  113. package/dist/commands/style-check.js +75 -0
  114. package/dist/commands/test.js +53 -59
  115. package/dist/commands/tests-for.d.ts +2 -0
  116. package/dist/commands/tests-for.js +80 -0
  117. package/dist/commands/validate.d.ts +6 -0
  118. package/dist/commands/validate.js +72 -0
  119. package/dist/config.js +1 -1
  120. package/dist/convex.d.ts +34 -22
  121. package/dist/convex.js +38 -22
  122. package/dist/harness/cache.d.ts +1 -5
  123. package/dist/harness/cache.js +49 -59
  124. package/dist/harness/convexReporting.d.ts +1 -1
  125. package/dist/harness/convexReporting.js +9 -7
  126. package/dist/harness/coverageCache.js +3 -3
  127. package/dist/harness/finalize.js +59 -46
  128. package/dist/harness/index.d.ts +6 -7
  129. package/dist/harness/index.js +9 -10
  130. package/dist/harness/prepare.js +6 -5
  131. package/dist/harness/requirementsLoader.d.ts +2 -2
  132. package/dist/harness/requirementsLoader.js +13 -35
  133. package/dist/harness/tracking.js +18 -18
  134. package/dist/harness/types.d.ts +1 -1
  135. package/dist/mcp/convexClient.d.ts +0 -39
  136. package/dist/mcp/convexClient.js +2 -107
  137. package/dist/mcp/grep.d.ts +1 -1
  138. package/dist/mcp/grep.js +87 -42
  139. package/dist/mcp/handlers/authoring.d.ts +1 -1
  140. package/dist/mcp/handlers/authoring.js +30 -234
  141. package/dist/mcp/handlers/coverage.d.ts +1 -1
  142. package/dist/mcp/handlers/coverage.js +13 -15
  143. package/dist/mcp/handlers/debug.d.ts +2 -3
  144. package/dist/mcp/handlers/debug.js +10 -10
  145. package/dist/mcp/handlers/get.d.ts +1 -1
  146. package/dist/mcp/handlers/get.js +11 -10
  147. package/dist/mcp/handlers/index.d.ts +20 -20
  148. package/dist/mcp/handlers/index.js +10 -10
  149. package/dist/mcp/handlers/list.d.ts +4 -33
  150. package/dist/mcp/handlers/list.js +16 -38
  151. package/dist/mcp/handlers/push.d.ts +1 -1
  152. package/dist/mcp/handlers/push.js +28 -18
  153. package/dist/mcp/handlers/report.d.ts +16 -0
  154. package/dist/mcp/handlers/report.js +134 -0
  155. package/dist/mcp/handlers/review.d.ts +1 -1
  156. package/dist/mcp/handlers/review.js +40 -59
  157. package/dist/mcp/handlers/search.d.ts +1 -1
  158. package/dist/mcp/handlers/search.js +7 -9
  159. package/dist/mcp/handlers/test-mapping.d.ts +1 -1
  160. package/dist/mcp/handlers/test-mapping.js +14 -14
  161. package/dist/mcp/handlers/types.d.ts +3 -3
  162. package/dist/mcp/handlers/types.js +2 -2
  163. package/dist/mcp/index.d.ts +1 -1
  164. package/dist/mcp/index.js +147 -167
  165. package/dist/mcp/requirements.d.ts +2 -2
  166. package/dist/mcp/requirements.js +30 -30
  167. package/dist/mcp/testCodeExtractor.js +24 -26
  168. package/dist/mcp/types.d.ts +1 -1
  169. package/dist/push/core.d.ts +2 -2
  170. package/dist/push/core.js +20 -20
  171. package/dist/push/index.d.ts +1 -1
  172. package/dist/push/index.js +2 -2
  173. package/dist/requirements/cloud-ai.d.ts +57 -0
  174. package/dist/requirements/cloud-ai.js +104 -0
  175. package/dist/requirements/cloud-coverage.d.ts +41 -0
  176. package/dist/requirements/cloud-coverage.js +60 -0
  177. package/dist/requirements/coverage.d.ts +45 -0
  178. package/dist/requirements/coverage.js +114 -0
  179. package/dist/requirements/grep.d.ts +33 -0
  180. package/dist/requirements/grep.js +306 -0
  181. package/dist/requirements/index.d.ts +73 -0
  182. package/dist/requirements/index.js +174 -0
  183. package/dist/requirements/style-guide.d.ts +67 -0
  184. package/dist/requirements/style-guide.js +299 -0
  185. package/dist/requirements/testCodeExtractor.d.ts +22 -0
  186. package/dist/requirements/testCodeExtractor.js +150 -0
  187. package/dist/schema/browser.d.ts +8 -8
  188. package/dist/schema/browser.js +13 -15
  189. package/dist/schema/builder.d.ts +1 -1
  190. package/dist/schema/builder.js +13 -44
  191. package/dist/schema/conversions.d.ts +2 -2
  192. package/dist/schema/conversions.js +11 -11
  193. package/dist/schema/index.d.ts +9 -9
  194. package/dist/schema/index.js +15 -15
  195. package/dist/schema/parser-core.d.ts +1 -1
  196. package/dist/schema/parser-core.js +23 -22
  197. package/dist/schema/parser.d.ts +3 -3
  198. package/dist/schema/parser.js +27 -31
  199. package/dist/schema/resolver.d.ts +1 -1
  200. package/dist/schema/resolver.js +9 -9
  201. package/dist/schema/scenario.d.ts +1 -1
  202. package/dist/schema/scenario.js +1 -1
  203. package/dist/schema/schemas.d.ts +3 -3
  204. package/dist/schema/schemas.js +41 -28
  205. package/dist/schema/test-schema.js +27 -27
  206. package/dist/templates/context-file-section.md +3 -2
  207. package/dist/templates/example-requirements.js +1 -1
  208. package/dist/templates/example-requirements.ts +3 -1
  209. package/dist/templates/requirements-readme.js +1 -1
  210. package/dist/templates/requirements-readme.ts +1 -1
  211. package/dist/templates/skills/codebase-to-spec/SKILL.md +118 -0
  212. package/dist/utils/brand.js +3 -3
  213. package/dist/utils/browser-launch.js +4 -4
  214. package/dist/utils/context-file.d.ts +1 -1
  215. package/dist/utils/context-file.js +26 -26
  216. package/dist/utils/env.js +7 -7
  217. package/dist/utils/gitignore.js +7 -7
  218. package/dist/utils/oauth-callback-server.d.ts +1 -1
  219. package/dist/utils/oauth-callback-server.js +27 -25
  220. package/dist/utils/oauth-flow.js +32 -29
  221. package/dist/utils/project-discovery.d.ts +3 -3
  222. package/dist/utils/project-discovery.js +18 -17
  223. package/dist/utils/project-name.js +8 -8
  224. package/dist/utils/project-selector.d.ts +1 -1
  225. package/dist/utils/project-selector.js +24 -21
  226. package/dist/utils/project-settings.d.ts +1 -1
  227. package/dist/utils/project-settings.js +24 -22
  228. package/dist/utils/templates.js +6 -6
  229. package/package.json +2 -1
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Slice extraction: given a Repomix pack and a list of file paths (or
3
+ * directory-prefix paths), produce a smaller pack containing only the matching
4
+ * files.
5
+ *
6
+ * Pack format (from Repomix --style plain):
7
+ *
8
+ * ================
9
+ * File: path/to/file
10
+ * ================
11
+ * <file contents>
12
+ *
13
+ * ================
14
+ * File: next/file
15
+ * ================
16
+ * ...
17
+ *
18
+ * We preserve the pack header (everything before the first File: section) and
19
+ * the matching sections.
20
+ *
21
+ * Requirements covered:
22
+ * - CTS-SPEC-1: CLI fans out one specifier worker per area; each worker
23
+ * receives a slice extracted from the uncompressed pack
24
+ */
25
+ import { readFileSync, writeFileSync } from "node:fs";
26
+ const SEPARATOR = "================";
27
+ const FILE_PREFIX = "File: ";
28
+ /**
29
+ * Return true when `path` matches one of the entries in `wanted`.
30
+ *
31
+ * Each entry can be:
32
+ * - An exact file path (e.g., `src/foo.ts`) — matches that exact path.
33
+ * - A directory prefix ending in `/` (e.g., `src/services/browser/`) — matches
34
+ * any file under that directory tree.
35
+ */
36
+ export function pathMatchesWanted(path, wanted) {
37
+ for (const w of wanted) {
38
+ if (w === path)
39
+ return true;
40
+ if (w.endsWith("/") && path.startsWith(w))
41
+ return true;
42
+ }
43
+ return false;
44
+ }
45
+ /**
46
+ * Extract sections matching `wanted` from the pack at `inputPath` and write
47
+ * them to `outputPath`. Preserves the pack header (Repomix metadata).
48
+ */
49
+ export function extractSlice(inputPath, outputPath, wanted) {
50
+ const wantedSet = new Set(wanted);
51
+ const text = readFileSync(inputPath, "utf-8");
52
+ return extractSliceFromText(text, outputPath, wantedSet);
53
+ }
54
+ /**
55
+ * Pure variant operating on already-loaded text. Useful for tests.
56
+ */
57
+ export function extractSliceFromText(text, outputPath, wanted) {
58
+ const wantedSet = wanted instanceof Set ? wanted : new Set(wanted);
59
+ const lines = text.split("\n");
60
+ const out = [];
61
+ // Find the start of the first File: section.
62
+ let firstFileIdx = -1;
63
+ for (let i = 0; i + 1 < lines.length; i++) {
64
+ if (lines[i].trim() === SEPARATOR && lines[i + 1].startsWith(FILE_PREFIX)) {
65
+ firstFileIdx = i;
66
+ break;
67
+ }
68
+ }
69
+ if (firstFileIdx === -1) {
70
+ throw new Error("Input pack has no File: sections");
71
+ }
72
+ // Preserve the pack header (lines 0..firstFileIdx-1).
73
+ for (let i = 0; i < firstFileIdx; i++) {
74
+ out.push(lines[i]);
75
+ }
76
+ let matched = 0;
77
+ let total = 0;
78
+ let i = firstFileIdx;
79
+ while (i < lines.length) {
80
+ if (lines[i].trim() === SEPARATOR &&
81
+ i + 1 < lines.length &&
82
+ lines[i + 1].startsWith(FILE_PREFIX)) {
83
+ const path = lines[i + 1].slice(FILE_PREFIX.length).trim();
84
+ total++;
85
+ // Find the end of this section (next ====/File: pair or EOF).
86
+ let j = i + 3; // past the closing separator
87
+ while (j < lines.length) {
88
+ if (lines[j].trim() === SEPARATOR &&
89
+ j + 1 < lines.length &&
90
+ lines[j + 1].startsWith(FILE_PREFIX)) {
91
+ break;
92
+ }
93
+ j++;
94
+ }
95
+ const contentEnd = j; // exclusive
96
+ if (pathMatchesWanted(path, wantedSet)) {
97
+ matched++;
98
+ for (let k = i; k < contentEnd; k++) {
99
+ out.push(lines[k]);
100
+ }
101
+ }
102
+ i = j;
103
+ }
104
+ else {
105
+ i++;
106
+ }
107
+ }
108
+ writeFileSync(outputPath, out.join("\n"), "utf-8");
109
+ return { matched, total };
110
+ }
111
+ //# sourceMappingURL=slice.js.map
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Specifier worker: run a single specifier for one area.
3
+ *
4
+ * The specifier is given its slice + the outline + a target partial path, and
5
+ * it orchestrates its own work via tools (Read, Write, Edit, Grep, Glob, Bash).
6
+ * Self-style-check happens via `Bash dotrequirements cts style-check <path>`.
7
+ *
8
+ * Requirements covered:
9
+ * - CTS-SPEC-1: per-area worker invocation
10
+ * - CTS-SPEC-2: write partial to known path via Write tool
11
+ * - CTS-SPEC-3: self-style-check via Bash
12
+ * - CTS-SPEC-4: access to the full pack for cross-area context
13
+ * - CTS-SPEC-5: failure detection and retry orchestrated by fan-out (this file
14
+ * produces a single attempt; fan-out wraps it with retry policy)
15
+ */
16
+ import { type ClaudeRunner } from "./claude.js";
17
+ import type { Area, Outline } from "./schemas.js";
18
+ export interface SpecifierContext {
19
+ outline: Outline;
20
+ area: Area;
21
+ /** Path to the area's slice (extracted from the uncompressed pack). */
22
+ slicePath: string;
23
+ /** Path to the full uncompressed pack (for cross-area discovery). */
24
+ fullPackPath: string;
25
+ /** Where the specifier should write its partial. */
26
+ partialPath: string;
27
+ /**
28
+ * The command the specifier should run to invoke schema validation on its
29
+ * own partial — typically `dotrequirements cts validate`. Run BEFORE
30
+ * style-check.
31
+ */
32
+ validateCommand: string;
33
+ /**
34
+ * The command the specifier should run to invoke style-check on its own
35
+ * partial — typically `dotrequirements cts style-check`. Run AFTER
36
+ * validate.
37
+ */
38
+ styleCheckCommand: string;
39
+ /** Directories the agent should have read+write access to. */
40
+ addDirs: string[];
41
+ runner?: ClaudeRunner;
42
+ model?: string;
43
+ }
44
+ export interface SpecifierResult {
45
+ /** True if the agent wrote a non-empty partial file at the expected path. */
46
+ wrotePartial: boolean;
47
+ /** Size of the partial in bytes, or 0 if missing. */
48
+ partialBytes: number;
49
+ /** Process exit code. */
50
+ exitCode: number;
51
+ /** Captured stdout. */
52
+ stdout: string;
53
+ /** Captured stderr. */
54
+ stderr: string;
55
+ }
56
+ /**
57
+ * Run a single specifier. Returns details about whether it succeeded.
58
+ */
59
+ export declare function runSpecifier(ctx: SpecifierContext): Promise<SpecifierResult>;
60
+ //# sourceMappingURL=specifier.d.ts.map
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Specifier worker: run a single specifier for one area.
3
+ *
4
+ * The specifier is given its slice + the outline + a target partial path, and
5
+ * it orchestrates its own work via tools (Read, Write, Edit, Grep, Glob, Bash).
6
+ * Self-style-check happens via `Bash dotrequirements cts style-check <path>`.
7
+ *
8
+ * Requirements covered:
9
+ * - CTS-SPEC-1: per-area worker invocation
10
+ * - CTS-SPEC-2: write partial to known path via Write tool
11
+ * - CTS-SPEC-3: self-style-check via Bash
12
+ * - CTS-SPEC-4: access to the full pack for cross-area context
13
+ * - CTS-SPEC-5: failure detection and retry orchestrated by fan-out (this file
14
+ * produces a single attempt; fan-out wraps it with retry policy)
15
+ */
16
+ import { existsSync, statSync } from "node:fs";
17
+ import { runClaude } from "./claude.js";
18
+ import { SPECIFIER_PROMPT } from "./prompts/specifier.js";
19
+ function buildUserMessage(ctx) {
20
+ return [
21
+ `You are specifying ONE area of the system.`,
22
+ ``,
23
+ `Area name: ${ctx.area.name}`,
24
+ `Area description: ${ctx.area.description}`,
25
+ `Document defaultPrefix: ${ctx.outline.defaultPrefix}`,
26
+ `Area prefix: ${ctx.area.prefix}`,
27
+ `Use full requirement IDs of the form: ${ctx.outline.defaultPrefix}-${ctx.area.prefix}-1, ${ctx.outline.defaultPrefix}-${ctx.area.prefix}-2, etc. (sequential, 1-indexed, no zero-padding).`,
28
+ ``,
29
+ `## Paths`,
30
+ `- Slice (your area's files): ${ctx.slicePath}`,
31
+ `- Full uncompressed pack (for discovering behaviors in tests/recipes/docs): ${ctx.fullPackPath}`,
32
+ `- Where to write your partial: ${ctx.partialPath}`,
33
+ `- Validate command (run FIRST after writing your draft — deterministic syntax check):`,
34
+ ` Bash: ${ctx.validateCommand} ${ctx.partialPath}`,
35
+ `- Style-check command (run SECOND, only after validate passes — AI clarity feedback):`,
36
+ ` Bash: ${ctx.styleCheckCommand} ${ctx.partialPath}`,
37
+ ``,
38
+ `## Full system outline (so you know what is in scope vs. not)`,
39
+ `\`\`\`json`,
40
+ JSON.stringify(ctx.outline, null, 2),
41
+ `\`\`\``,
42
+ ``,
43
+ `Follow the three-phase workflow in your system prompt: draft (Phase A) → validate (Phase B) → style-check (Phase C) → confirm.`,
44
+ ].join("\n");
45
+ }
46
+ /**
47
+ * Run a single specifier. Returns details about whether it succeeded.
48
+ */
49
+ export async function runSpecifier(ctx) {
50
+ const runner = ctx.runner ?? runClaude;
51
+ const result = await runner({
52
+ systemPrompt: SPECIFIER_PROMPT,
53
+ userMessage: buildUserMessage(ctx),
54
+ model: ctx.model,
55
+ tools: ["Read", "Write", "Edit", "Grep", "Glob", "Bash"],
56
+ addDirs: ctx.addDirs,
57
+ });
58
+ // Inspect the partial file to determine whether the specifier wrote
59
+ // something usable.
60
+ let wrotePartial = false;
61
+ let partialBytes = 0;
62
+ if (existsSync(ctx.partialPath)) {
63
+ try {
64
+ partialBytes = statSync(ctx.partialPath).size;
65
+ wrotePartial = partialBytes > 0;
66
+ }
67
+ catch {
68
+ // ignore; treat as not written
69
+ }
70
+ }
71
+ return {
72
+ wrotePartial,
73
+ partialBytes,
74
+ exitCode: result.exitCode,
75
+ stdout: result.stdout,
76
+ stderr: result.stderr,
77
+ };
78
+ }
79
+ //# sourceMappingURL=specifier.js.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Local style-check function — produces severity-categorized feedback on a
3
+ * partial-spec file using a fresh, stateless claude -p call.
4
+ *
5
+ * Mirrors the existing cloud `mcp__dotrequirements__style_check` pattern but
6
+ * runs entirely offline (no cloud credentials, no account required), since
7
+ * the codebase-to-spec target audience does not yet have a dotrequirements
8
+ * account.
9
+ *
10
+ * Requirements covered:
11
+ * - CTS-SPEC-3: Specifier worker runs a local style-check on its own draft
12
+ */
13
+ import { type ClaudeRunner } from "./claude.js";
14
+ export interface StyleCheckOptions {
15
+ partialPath: string;
16
+ runner?: ClaudeRunner;
17
+ model?: string;
18
+ }
19
+ export interface StyleCheckResult {
20
+ /** The categorized feedback (Markdown). */
21
+ feedback: string;
22
+ /** Process exit code from the claude -p subprocess. */
23
+ exitCode: number;
24
+ }
25
+ /**
26
+ * Run a style check on a partial-spec file and return the feedback as Markdown.
27
+ */
28
+ export declare function runStyleCheck(options: StyleCheckOptions): Promise<StyleCheckResult>;
29
+ //# sourceMappingURL=style-check.d.ts.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Local style-check function — produces severity-categorized feedback on a
3
+ * partial-spec file using a fresh, stateless claude -p call.
4
+ *
5
+ * Mirrors the existing cloud `mcp__dotrequirements__style_check` pattern but
6
+ * runs entirely offline (no cloud credentials, no account required), since
7
+ * the codebase-to-spec target audience does not yet have a dotrequirements
8
+ * account.
9
+ *
10
+ * Requirements covered:
11
+ * - CTS-SPEC-3: Specifier worker runs a local style-check on its own draft
12
+ */
13
+ import { dirname } from "node:path";
14
+ import { runClaude } from "./claude.js";
15
+ import { STYLE_CHECK_PROMPT } from "./prompts/style-check.js";
16
+ /**
17
+ * Run a style check on a partial-spec file and return the feedback as Markdown.
18
+ */
19
+ export async function runStyleCheck(options) {
20
+ const runner = options.runner ?? runClaude;
21
+ const result = await runner({
22
+ systemPrompt: STYLE_CHECK_PROMPT,
23
+ userMessage: `Run a style check on the partial spec at ${options.partialPath}. Read the file via the Read tool and produce categorized Markdown feedback per your system prompt.`,
24
+ model: options.model,
25
+ tools: ["Read"],
26
+ addDirs: [dirname(options.partialPath)],
27
+ });
28
+ return {
29
+ feedback: result.stdout,
30
+ exitCode: result.exitCode,
31
+ };
32
+ }
33
+ //# sourceMappingURL=style-check.js.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Pipeline summary generation.
3
+ *
4
+ * Reads cached artifacts to assemble a structured summary of what the
5
+ * pipeline produced. Surfaced both as JSON (parseable by wrappers like the
6
+ * skill) and as a short human-readable block.
7
+ *
8
+ * Requirements covered:
9
+ * - CTS-PRESENT-4: Final pipeline summary is surfaced
10
+ * - CTS-OBSERVE-2 (partial): structured failure information available
11
+ */
12
+ import type { CachePaths } from "./cache.js";
13
+ import { type Outline } from "./schemas.js";
14
+ export interface PipelineSummary {
15
+ totalAreas: number;
16
+ totalRequirements: number;
17
+ outline: {
18
+ turnsUsed: number;
19
+ finalVerdict: string | null;
20
+ residualNotes: string[];
21
+ };
22
+ specifiers: {
23
+ completed: number;
24
+ missing: number;
25
+ /** Area names that have no usable partial. */
26
+ missingAreas: string[];
27
+ };
28
+ specReview: {
29
+ turnsUsed: number;
30
+ finalVerdict: string | null;
31
+ residualNotes: string[];
32
+ };
33
+ outputs: {
34
+ /** Paths under .requirements/ that were written. */
35
+ paths: string[];
36
+ };
37
+ }
38
+ export interface BuildSummaryInput {
39
+ outline: Outline;
40
+ paths: CachePaths;
41
+ /** Paths the present stage wrote (under .requirements/). */
42
+ outputPaths: string[];
43
+ }
44
+ export declare function buildPipelineSummary(input: BuildSummaryInput): PipelineSummary;
45
+ /**
46
+ * Render a short human-readable block for the summary. Designed to fit on a
47
+ * small number of lines (CTS-PRESENT-4.2). Wrappers that want richer
48
+ * presentation can read the JSON form instead.
49
+ */
50
+ export declare function renderSummaryText(summary: PipelineSummary): string;
51
+ //# sourceMappingURL=summary.d.ts.map
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Pipeline summary generation.
3
+ *
4
+ * Reads cached artifacts to assemble a structured summary of what the
5
+ * pipeline produced. Surfaced both as JSON (parseable by wrappers like the
6
+ * skill) and as a short human-readable block.
7
+ *
8
+ * Requirements covered:
9
+ * - CTS-PRESENT-4: Final pipeline summary is surfaced
10
+ * - CTS-OBSERVE-2 (partial): structured failure information available
11
+ */
12
+ import { existsSync, readFileSync, statSync } from "node:fs";
13
+ import { sanitizeAreaName } from "./fan-out.js";
14
+ import { parseOutlineReview, parseSpecReview, } from "./schemas.js";
15
+ /**
16
+ * Count top-level requirements in a file by counting fenced
17
+ * \`\`\`dotrequirements blocks. Each block represents one root requirement
18
+ * (CTS-OBSERVE-2 counts each requirement ID once, excluding child criteria).
19
+ */
20
+ function countRequirementsInFile(path) {
21
+ if (!existsSync(path))
22
+ return 0;
23
+ const content = readFileSync(path, "utf-8");
24
+ const matches = content.match(/```dotrequirements\b/g);
25
+ return matches ? matches.length : 0;
26
+ }
27
+ /**
28
+ * Look at outline-review-N.json files in the cache and return how many turns
29
+ * ran and what the final verdict was. Returns {turnsUsed: 0, finalVerdict: null}
30
+ * if no review artifacts exist.
31
+ */
32
+ function summarizeOutlineReview(paths) {
33
+ let n = 0;
34
+ let lastReviewPath = null;
35
+ while (true) {
36
+ const path = paths.outlineReviewTurn(n + 1);
37
+ if (!existsSync(path))
38
+ break;
39
+ n++;
40
+ lastReviewPath = path;
41
+ }
42
+ if (!lastReviewPath)
43
+ return { turnsUsed: 0, finalVerdict: null, residualNotes: [] };
44
+ try {
45
+ const review = parseOutlineReview(readFileSync(lastReviewPath, "utf-8"));
46
+ const notes = [];
47
+ // Surface unresolved findings as residual notes if verdict isn't 'approved'.
48
+ if (review.verdict !== "approved") {
49
+ for (const cat of [
50
+ ["coverage_gap", review.coverage_gaps],
51
+ ["framing_error", review.framing_errors],
52
+ ["granularity", review.granularity_issues],
53
+ ["file_assignment", review.file_assignment_issues],
54
+ ]) {
55
+ for (const note of cat[1]) {
56
+ notes.push(`outline.${cat[0]}: ${note}`);
57
+ }
58
+ }
59
+ }
60
+ return { turnsUsed: n, finalVerdict: review.verdict, residualNotes: notes };
61
+ }
62
+ catch {
63
+ return { turnsUsed: n, finalVerdict: null, residualNotes: [] };
64
+ }
65
+ }
66
+ function summarizeSpecReview(paths) {
67
+ let n = 0;
68
+ let lastReviewPath = null;
69
+ while (true) {
70
+ const path = paths.specReviewTurn(n + 1);
71
+ if (!existsSync(path))
72
+ break;
73
+ n++;
74
+ lastReviewPath = path;
75
+ }
76
+ if (!lastReviewPath)
77
+ return { turnsUsed: 0, finalVerdict: null, residualNotes: [] };
78
+ try {
79
+ const review = parseSpecReview(readFileSync(lastReviewPath, "utf-8"));
80
+ const notes = [];
81
+ if (review.verdict !== "approved") {
82
+ for (const cat of [
83
+ ["coverage_gap", review.coverage_gaps],
84
+ ["framing_error", review.framing_errors],
85
+ ["cross_area", review.cross_area_issues],
86
+ ["internal_mechanics", review.internal_mechanics_drift],
87
+ ]) {
88
+ for (const note of cat[1]) {
89
+ notes.push(`spec.${cat[0]}: ${note}`);
90
+ }
91
+ }
92
+ }
93
+ return { turnsUsed: n, finalVerdict: review.verdict, residualNotes: notes };
94
+ }
95
+ catch {
96
+ return { turnsUsed: n, finalVerdict: null, residualNotes: [] };
97
+ }
98
+ }
99
+ function summarizeSpecifiers(outline, paths) {
100
+ let completed = 0;
101
+ const missingAreas = [];
102
+ for (const area of outline.areas) {
103
+ const partialPath = paths.partial(sanitizeAreaName(area.name));
104
+ if (!existsSync(partialPath)) {
105
+ missingAreas.push(area.name);
106
+ continue;
107
+ }
108
+ const content = readFileSync(partialPath, "utf-8").trim();
109
+ if (!content ||
110
+ content.startsWith("_(missing partial") ||
111
+ content.startsWith("_(no files")) {
112
+ missingAreas.push(area.name);
113
+ continue;
114
+ }
115
+ completed++;
116
+ }
117
+ return { completed, missing: missingAreas.length, missingAreas };
118
+ }
119
+ export function buildPipelineSummary(input) {
120
+ const { outline, paths, outputPaths } = input;
121
+ const outlineReview = summarizeOutlineReview(paths);
122
+ const specReview = summarizeSpecReview(paths);
123
+ const specifiers = summarizeSpecifiers(outline, paths);
124
+ // Count top-level requirements across all written .requirements/ files.
125
+ let totalRequirements = 0;
126
+ for (const path of outputPaths) {
127
+ totalRequirements += countRequirementsInFile(path);
128
+ }
129
+ // Fall back to counting the final cached spec if nothing was written (e.g.
130
+ // dry-run / interrupted) — that way the summary still reflects what the
131
+ // pipeline produced.
132
+ if (totalRequirements === 0 && existsSync(paths.specFinal)) {
133
+ totalRequirements = countRequirementsInFile(paths.specFinal);
134
+ }
135
+ return {
136
+ totalAreas: outline.areas.length,
137
+ totalRequirements,
138
+ outline: outlineReview,
139
+ specifiers,
140
+ specReview,
141
+ outputs: { paths: outputPaths },
142
+ };
143
+ }
144
+ /**
145
+ * Render a short human-readable block for the summary. Designed to fit on a
146
+ * small number of lines (CTS-PRESENT-4.2). Wrappers that want richer
147
+ * presentation can read the JSON form instead.
148
+ */
149
+ export function renderSummaryText(summary) {
150
+ const lines = [];
151
+ lines.push(`Pipeline summary:`);
152
+ lines.push(` Areas: ${summary.totalAreas}`);
153
+ lines.push(` Top-level reqs: ${summary.totalRequirements}`);
154
+ lines.push(` Outline review: ${summary.outline.turnsUsed} turn(s), verdict: ${summary.outline.finalVerdict ?? "n/a"}`);
155
+ lines.push(` Specifiers: ${summary.specifiers.completed} completed, ${summary.specifiers.missing} missing`);
156
+ lines.push(` Spec review: ${summary.specReview.turnsUsed} turn(s), verdict: ${summary.specReview.finalVerdict ?? "n/a"}`);
157
+ lines.push(` Output files:`);
158
+ for (const path of summary.outputs.paths) {
159
+ lines.push(` - ${path}`);
160
+ }
161
+ if (summary.outline.residualNotes.length ||
162
+ summary.specReview.residualNotes.length) {
163
+ lines.push(``);
164
+ lines.push(` Residual notes (worth reviewing manually):`);
165
+ for (const note of [
166
+ ...summary.outline.residualNotes,
167
+ ...summary.specReview.residualNotes,
168
+ ]) {
169
+ lines.push(` - ${note}`);
170
+ }
171
+ }
172
+ if (summary.specifiers.missingAreas.length) {
173
+ lines.push(``);
174
+ lines.push(` Missing specifier output for:`);
175
+ for (const area of summary.specifiers.missingAreas) {
176
+ lines.push(` - ${area}`);
177
+ }
178
+ }
179
+ return lines.join("\n");
180
+ }
181
+ /** Suppress unused-var warning. */
182
+ void statSync;
183
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Local schema validation for a partial-spec file.
3
+ *
4
+ * Mirrors the existing `dotrequirements validate` path (and the
5
+ * `mcp__dotrequirements__validate_requirements` MCP tool), but works on
6
+ * partial files — which lack YAML frontmatter — by synthesizing a minimal
7
+ * wrapper before running the canonical parser.
8
+ *
9
+ * This is a deterministic syntax check: it catches things like missing
10
+ * `→`/`->` arrows, malformed position paths, indentation/position mismatches,
11
+ * and duplicate IDs — things the AI-driven style-check is not guaranteed
12
+ * to notice.
13
+ *
14
+ * Convention from CLAUDE.md: validate before style-check. Validate is the
15
+ * cheap, deterministic gate; style-check is the AI clarity pass.
16
+ *
17
+ * Requirements covered:
18
+ * - CTS-SPEC-3: Specifier worker runs a local schema validator on its draft,
19
+ * then a local style-check, applying feedback from each.
20
+ */
21
+ export interface ValidateOptions {
22
+ /** Path to the partial-spec file to validate. */
23
+ partialPath: string;
24
+ }
25
+ export interface ValidateResult {
26
+ /** True if the partial parsed cleanly. */
27
+ ok: boolean;
28
+ /** Human-readable error message when `ok === false`. */
29
+ error?: string;
30
+ /** Number of requirement blocks found (when `ok === true`). */
31
+ requirementCount?: number;
32
+ }
33
+ /**
34
+ * Validate a partial-spec file. Reads the file, synthesizes a frontmatter
35
+ * envelope, and delegates to the canonical parser. Errors are surfaced as
36
+ * a single human-readable string so the calling agent can act on them as
37
+ * MUST FIX items.
38
+ */
39
+ export declare function runValidate(options: ValidateOptions): ValidateResult;
40
+ /**
41
+ * Format a ValidateResult as the Markdown feedback block the specifier
42
+ * agent reads on stdout. Mirrors the severity-categorized shape produced
43
+ * by `runStyleCheck`, so the prompt can describe them uniformly.
44
+ */
45
+ export declare function formatValidateFeedback(result: ValidateResult): string;
46
+ //# sourceMappingURL=validate.d.ts.map