@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
@@ -1,7 +1,7 @@
1
- import { execSync } from "child_process";
2
- import { getTrackedRequirements } from "./tracking.js";
3
- import { saveCache, getRequirementsToReport } from "./coverageCache.js";
1
+ import { execSync } from "node:child_process";
4
2
  import { getProjectInfo } from "../utils/project-settings.js";
3
+ import { getRequirementsToReport, saveCache } from "./coverageCache.js";
4
+ import { getTrackedRequirements } from "./tracking.js";
5
5
  /**
6
6
  * Get the current git branch, or null if not in a git repo
7
7
  */
@@ -14,7 +14,7 @@ export function getCurrentBranch(cwd = process.cwd()) {
14
14
  }).trim();
15
15
  return branch;
16
16
  }
17
- catch (error) {
17
+ catch {
18
18
  // Not in a git repo or git not available
19
19
  return "unknown";
20
20
  }
@@ -22,7 +22,7 @@ export function getCurrentBranch(cwd = process.cwd()) {
22
22
  /**
23
23
  * Production Convex deployment URL
24
24
  */
25
- const CONVEX_URL = 'https://data.dotrequirements.io';
25
+ const CONVEX_URL = "https://data.dotrequirements.io";
26
26
  /**
27
27
  * Extract file path and line number from caller location string
28
28
  */
@@ -53,7 +53,9 @@ export async function reportCoverageToConvex(cwd = process.cwd(), trackedReqs) {
53
53
  // Get project info from .requirements/project-settings.json
54
54
  const projectInfo = getProjectInfo(cwd);
55
55
  // Skip if no project found or not connected to cloud
56
- if (!projectInfo || projectInfo.status !== 'cloud-connected' || !projectInfo.credentials) {
56
+ if (!projectInfo ||
57
+ projectInfo.status !== "cloud-connected" ||
58
+ !projectInfo.credentials) {
57
59
  console.log("\nℹ️ Skipping cloud coverage reporting (project not connected to cloud)");
58
60
  return;
59
61
  }
@@ -113,7 +115,7 @@ export async function reportCoverageToConvex(cwd = process.cwd(), trackedReqs) {
113
115
  console.warn(`\n⚠️ Failed to report coverage to cloud: ${response.status} ${error}`);
114
116
  return;
115
117
  }
116
- const result = await response.json();
118
+ await response.json();
117
119
  console.log(`\n✓ Reported ${keysToReport.length} requirement(s) to cloud (branch: ${branch})`);
118
120
  // Update cache with current test run
119
121
  saveCache({
@@ -1,5 +1,5 @@
1
- import { readFileSync, writeFileSync, existsSync } from "fs";
2
- import { join } from "path";
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
3
  import { v4 as uuidv4 } from "uuid";
4
4
  const CACHE_FILE = ".requirements/.coverage-cache.json";
5
5
  const STALENESS_THRESHOLD_MS = 4 * 60 * 60 * 1000; // 4 hours
@@ -15,7 +15,7 @@ export function loadCache(cwd = process.cwd()) {
15
15
  const content = readFileSync(cachePath, "utf-8");
16
16
  return JSON.parse(content);
17
17
  }
18
- catch (error) {
18
+ catch {
19
19
  // If cache is corrupt, start fresh
20
20
  console.warn("Warning: Coverage cache is corrupt, starting fresh");
21
21
  return { current: null, previous: null };
@@ -9,10 +9,10 @@
9
9
  *
10
10
  * Implements: HARNESS-FINALIZE-1, HARNESS-FINALIZE-2, HARNESS-FINALIZE-3, HARNESS-FINALIZE-4
11
11
  */
12
- import { execSync } from 'child_process';
13
- import { randomUUID } from 'crypto';
14
- import { findRequirementsDir, findProjectRoot, getTestRunId, cleanupTestRunId, readTrackingEntries, deleteTrackingFile, readLookupCache, readCoverageCache, updateCoverageCache, needsReporting, } from './cache.js';
15
- import { getProjectInfo } from '../utils/project-settings.js';
12
+ import { execSync } from "node:child_process";
13
+ import { randomUUID } from "node:crypto";
14
+ import { getProjectInfo } from "../utils/project-settings.js";
15
+ import { cleanupTestRunId, deleteTrackingFile, findProjectRoot, findRequirementsDir, getTestRunId, needsReporting, readCoverageCache, readLookupCache, readTrackingEntries, updateCoverageCache, } from "./cache.js";
16
16
  /**
17
17
  * Aggregate tracking entries by requirement key
18
18
  */
@@ -30,15 +30,15 @@ function aggregateEntries(entries) {
30
30
  */
31
31
  function getCurrentBranch(cwd) {
32
32
  try {
33
- const branch = execSync('git rev-parse --abbrev-ref HEAD', {
33
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", {
34
34
  cwd,
35
- encoding: 'utf-8',
36
- stdio: ['pipe', 'pipe', 'ignore'],
35
+ encoding: "utf-8",
36
+ stdio: ["pipe", "pipe", "ignore"],
37
37
  }).trim();
38
38
  return branch;
39
39
  }
40
40
  catch {
41
- return 'unknown';
41
+ return "unknown";
42
42
  }
43
43
  }
44
44
  /**
@@ -51,8 +51,8 @@ function getLineAuthor(cwd, file, line) {
51
51
  try {
52
52
  const output = execSync(`git blame -L ${line},${line} --porcelain -- "${file}"`, {
53
53
  cwd,
54
- encoding: 'utf-8',
55
- stdio: ['pipe', 'pipe', 'ignore'],
54
+ encoding: "utf-8",
55
+ stdio: ["pipe", "pipe", "ignore"],
56
56
  });
57
57
  const match = output.match(/^author-mail\s+<([^>]+)>/m);
58
58
  return match?.[1];
@@ -68,15 +68,17 @@ function getLineAuthor(cwd, file, line) {
68
68
  */
69
69
  function printLocalReport(testedKeys, lookup, options) {
70
70
  const { showSummary, showTestedList, showUntestedList } = options;
71
- const allKeys = lookup ? Object.keys(lookup.requirements).filter(k => !lookup.requirements[k].isAlias) : [];
72
- const untestedKeys = allKeys.filter(key => !testedKeys.includes(key));
71
+ const allKeys = lookup
72
+ ? Object.keys(lookup.requirements).filter((k) => !lookup.requirements[k].isAlias)
73
+ : [];
74
+ const untestedKeys = allKeys.filter((key) => !testedKeys.includes(key));
73
75
  const total = allKeys.length;
74
76
  const tested = testedKeys.length;
75
- const coverage = total > 0 ? ((tested / total) * 100).toFixed(1) : '0.0';
76
- let report = '';
77
+ const coverage = total > 0 ? ((tested / total) * 100).toFixed(1) : "0.0";
78
+ let report = "";
77
79
  // Show summary stats
78
80
  if (showSummary) {
79
- report += '\n=== Requirements Coverage Report ===\n';
81
+ report += "\n=== Requirements Coverage Report ===\n";
80
82
  report += `\nTotal Requirements: ${total}\n`;
81
83
  report += `Tested Requirements: ${tested}\n`;
82
84
  report += `Untested Requirements: ${untestedKeys.length}\n`;
@@ -84,14 +86,14 @@ function printLocalReport(testedKeys, lookup, options) {
84
86
  }
85
87
  // Show tested requirements
86
88
  if (showTestedList && testedKeys.length > 0) {
87
- report += '\n✓ Tested Requirements:\n';
89
+ report += "\n✓ Tested Requirements:\n";
88
90
  for (const key of testedKeys) {
89
91
  const req = lookup?.requirements[key];
90
92
  if (req) {
91
- const label = req.label || '';
92
- const content = req.content || '';
93
- const preview = content.length > 60 ? content.substring(0, 60) + '...' : content;
94
- const labelPart = label ? ` (${label})` : '';
93
+ const label = req.label || "";
94
+ const content = req.content || "";
95
+ const preview = content.length > 60 ? `${content.substring(0, 60)}...` : content;
96
+ const labelPart = label ? ` (${label})` : "";
95
97
  report += ` - ${key}${labelPart}: ${preview}\n`;
96
98
  }
97
99
  else {
@@ -101,14 +103,14 @@ function printLocalReport(testedKeys, lookup, options) {
101
103
  }
102
104
  // Show untested requirements
103
105
  if (showUntestedList && untestedKeys.length > 0) {
104
- report += '\n✗ Untested Requirements:\n';
106
+ report += "\n✗ Untested Requirements:\n";
105
107
  for (const key of untestedKeys) {
106
108
  const req = lookup?.requirements[key];
107
109
  if (req) {
108
- const label = req.label || '';
109
- const content = req.content || '';
110
- const preview = content.length > 60 ? content.substring(0, 60) + '...' : content;
111
- const labelPart = label ? ` (${label})` : '';
110
+ const label = req.label || "";
111
+ const content = req.content || "";
112
+ const preview = content.length > 60 ? `${content.substring(0, 60)}...` : content;
113
+ const labelPart = label ? ` (${label})` : "";
112
114
  report += ` - ${key}${labelPart}: ${preview}\n`;
113
115
  }
114
116
  else {
@@ -117,7 +119,7 @@ function printLocalReport(testedKeys, lookup, options) {
117
119
  }
118
120
  }
119
121
  if (showSummary) {
120
- report += '\n====================================\n';
122
+ report += "\n====================================\n";
121
123
  }
122
124
  if (report) {
123
125
  console.log(report);
@@ -126,7 +128,7 @@ function printLocalReport(testedKeys, lookup, options) {
126
128
  /**
127
129
  * Production Convex deployment URL
128
130
  */
129
- const CONVEX_URL = 'https://data.dotrequirements.io';
131
+ const CONVEX_URL = "https://data.dotrequirements.io";
130
132
  /**
131
133
  * Report coverage to Convex cloud
132
134
  *
@@ -138,9 +140,11 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
138
140
  // Get project info from .requirements/project-settings.json
139
141
  const projectInfo = getProjectInfo(projectRoot);
140
142
  // Skip if no project found or not connected to cloud
141
- if (!projectInfo || projectInfo.status !== 'cloud-connected' || !projectInfo.credentials) {
143
+ if (!projectInfo ||
144
+ projectInfo.status !== "cloud-connected" ||
145
+ !projectInfo.credentials) {
142
146
  if (showCloudStatus) {
143
- console.log('\nℹ️ Skipping cloud coverage reporting (project not connected to cloud)');
147
+ console.log("\nℹ️ Skipping cloud coverage reporting (project not connected to cloud)");
144
148
  }
145
149
  return { sent: false, count: 0 };
146
150
  }
@@ -161,7 +165,7 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
161
165
  const tuplesToReport = allTuples.filter((tuple) => needsReporting(tuple, coverageCache));
162
166
  if (tuplesToReport.length === 0) {
163
167
  if (showCloudStatus) {
164
- console.log('\n✓ Coverage unchanged since last run (skipping cloud report)');
168
+ console.log("\n✓ Coverage unchanged since last run (skipping cloud report)");
165
169
  }
166
170
  // Still update the cache so the window continues tracking
167
171
  updateCoverageCache(requirementsDir, testRunId, allTuples);
@@ -180,7 +184,7 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
180
184
  // Parse "filename.ts:42" format
181
185
  let testFile;
182
186
  let testLine;
183
- if (location !== 'unknown') {
187
+ if (location !== "unknown") {
184
188
  const match = location.match(/^(.+):(\d+)$/);
185
189
  if (match) {
186
190
  testFile = match[1];
@@ -213,19 +217,19 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
213
217
  // Note: projectId from env is always a slug (e.g., "reduced-cephalopod-288"),
214
218
  // not a Convex ID. Use projectSlug field for authentication and slug for target.
215
219
  const response = await fetch(`${CONVEX_URL}/api/mutation`, {
216
- method: 'POST',
220
+ method: "POST",
217
221
  headers: {
218
- 'Content-Type': 'application/json',
222
+ "Content-Type": "application/json",
219
223
  },
220
224
  body: JSON.stringify({
221
- path: 'testCoverage/mutations:recordCoverage',
225
+ path: "testCoverage/mutations:recordCoverage",
222
226
  args: {
223
227
  projectAuth: {
224
228
  projectSlug: projectId,
225
229
  projectSecret,
226
230
  },
227
231
  target: {
228
- type: 'project',
232
+ type: "project",
229
233
  slug: projectId,
230
234
  },
231
235
  branch,
@@ -233,7 +237,7 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
233
237
  runId,
234
238
  coverage,
235
239
  },
236
- format: 'json',
240
+ format: "json",
237
241
  }),
238
242
  });
239
243
  if (!response.ok) {
@@ -253,10 +257,12 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
253
257
  catch {
254
258
  // Not JSON, treat as success
255
259
  }
256
- if (responseData && typeof responseData === 'object' && 'status' in responseData) {
260
+ if (responseData &&
261
+ typeof responseData === "object" &&
262
+ "status" in responseData) {
257
263
  const convexResponse = responseData;
258
- if (convexResponse.status === 'error') {
259
- const errorMsg = convexResponse.errorMessage || 'Unknown Convex error';
264
+ if (convexResponse.status === "error") {
265
+ const errorMsg = convexResponse.errorMessage || "Unknown Convex error";
260
266
  if (showCloudStatus) {
261
267
  console.warn(`\n⚠️ Failed to report coverage to cloud: ${errorMsg}`);
262
268
  }
@@ -298,7 +304,7 @@ export async function finalize(options = {}) {
298
304
  projectRoot = findProjectRoot(cwd);
299
305
  }
300
306
  if (!projectRoot) {
301
- console.log('Could not find .requirements directory');
307
+ console.log("Could not find .requirements directory");
302
308
  return {
303
309
  requirementsTested: 0,
304
310
  totalRequirements: 0,
@@ -311,7 +317,7 @@ export async function finalize(options = {}) {
311
317
  // Get test run ID
312
318
  const testRunId = getTestRunId(requirementsDir);
313
319
  if (!testRunId) {
314
- console.log('No test run ID found - was prepare() called?');
320
+ console.log("No test run ID found - was prepare() called?");
315
321
  return {
316
322
  requirementsTested: 0,
317
323
  totalRequirements: 0,
@@ -343,17 +349,24 @@ export async function finalize(options = {}) {
343
349
  }
344
350
  }
345
351
  const testedKeys = Array.from(aggregated.keys());
346
- const totalRequirements = lookup ? Object.keys(lookup.requirements).filter(k => !lookup.requirements[k].isAlias).length : 0;
347
- const coveragePercent = totalRequirements > 0
348
- ? (testedKeys.length / totalRequirements) * 100
352
+ const totalRequirements = lookup
353
+ ? Object.keys(lookup.requirements).filter((k) => !lookup.requirements[k].isAlias).length
349
354
  : 0;
355
+ const coveragePercent = totalRequirements > 0 ? (testedKeys.length / totalRequirements) * 100 : 0;
350
356
  // HARNESS-FINALIZE-1: Print local report
351
357
  const shouldPrintLocal = showSummary || showTestedList || showUntestedList;
352
358
  if (shouldPrintLocal) {
353
- printLocalReport(testedKeys, lookup, { showSummary, showTestedList, showUntestedList });
359
+ printLocalReport(testedKeys, lookup, {
360
+ showSummary,
361
+ showTestedList,
362
+ showUntestedList,
363
+ });
354
364
  }
355
365
  // HARNESS-FINALIZE-2, HARNESS-FINALIZE-3: Report to cloud
356
- let cloudResult = { sent: false, count: 0 };
366
+ let cloudResult = {
367
+ sent: false,
368
+ count: 0,
369
+ };
357
370
  if (shouldReportToCloud) {
358
371
  cloudResult = await reportToConvex(projectRoot, testRunId, aggregated, showCloudStatus, context);
359
372
  }
@@ -60,11 +60,10 @@ export interface RequirementOptions {
60
60
  * @returns A formatted string with the first requirement's label and content
61
61
  */
62
62
  export declare function requirement(...args: (string | RequirementOptions)[]): string;
63
- export { prepare } from './prepare.js';
64
- export type { PrepareOptions, PrepareResult } from './prepare.js';
65
- export { finalize } from './finalize.js';
66
- export type { FinalizeOptions, FinalizeResult } from './finalize.js';
67
- export { clearTracking } from './tracking.js';
68
- export { initTestRun, finalizeTestRun, } from './tracking.js';
69
- export type { Requirement } from './types.js';
63
+ export type { FinalizeOptions, FinalizeResult } from "./finalize.js";
64
+ export { finalize } from "./finalize.js";
65
+ export type { PrepareOptions, PrepareResult } from "./prepare.js";
66
+ export { prepare } from "./prepare.js";
67
+ export { clearTracking, finalizeTestRun, initTestRun } from "./tracking.js";
68
+ export type { Requirement } from "./types.js";
70
69
  //# sourceMappingURL=index.d.ts.map
@@ -27,8 +27,8 @@
27
27
  * }
28
28
  * ```
29
29
  */
30
- import { getRequirement, loadRequirements } from './requirementsLoader.js';
31
- import { ensureTestRun, trackRequirement, saveTrackingData } from './tracking.js';
30
+ import { getRequirement, loadRequirements } from "./requirementsLoader.js";
31
+ import { ensureTestRun, saveTrackingData, trackRequirement, } from "./tracking.js";
32
32
  /**
33
33
  * Main requirements function for test harness.
34
34
  *
@@ -56,15 +56,15 @@ import { ensureTestRun, trackRequirement, saveTrackingData } from './tracking.js
56
56
  */
57
57
  export function requirement(...args) {
58
58
  if (args.length === 0) {
59
- throw new Error('requirement() requires at least one argument');
59
+ throw new Error("requirement() requires at least one argument");
60
60
  }
61
61
  // Check if last argument is options object
62
62
  const lastArg = args[args.length - 1];
63
- const hasOptions = typeof lastArg === 'object' && lastArg !== null;
63
+ const hasOptions = typeof lastArg === "object" && lastArg !== null;
64
64
  const options = hasOptions ? lastArg : {};
65
65
  const requirementRefs = (hasOptions ? args.slice(0, -1) : args);
66
66
  if (requirementRefs.length === 0) {
67
- throw new Error('requirement() requires at least one requirement reference');
67
+ throw new Error("requirement() requires at least one requirement reference");
68
68
  }
69
69
  // If projectRoot provided, reload requirements from that path
70
70
  if (options.projectRoot) {
@@ -87,17 +87,16 @@ export function requirement(...args) {
87
87
  }
88
88
  // HARNESS-REQUIREMENT-1: Format output as human-readable string
89
89
  // Root requirements use 'requirementHeader' label which should not be shown in output
90
- if (!req.label || req.label === 'requirementHeader') {
90
+ if (!req.label || req.label === "requirementHeader") {
91
91
  return req.content;
92
92
  }
93
93
  const label = req.label.charAt(0).toUpperCase() + req.label.slice(1);
94
94
  return `${label}: ${req.content}`;
95
95
  }
96
+ export { finalize } from "./finalize.js";
96
97
  // Export new lifecycle functions
97
- export { prepare } from './prepare.js';
98
- export { finalize } from './finalize.js';
98
+ export { prepare } from "./prepare.js";
99
99
  // Export tracking utilities
100
- export { clearTracking } from './tracking.js';
101
100
  // Deprecated exports - use prepare() and finalize() instead
102
- export { initTestRun, finalizeTestRun, } from './tracking.js';
101
+ export { clearTracking, finalizeTestRun, initTestRun } from "./tracking.js";
103
102
  //# sourceMappingURL=index.js.map
@@ -8,9 +8,10 @@
8
8
  *
9
9
  * Implements: HARNESS-PREPARE-1, HARNESS-PREPARE-2, HARNESS-PREPARE-3
10
10
  */
11
- import { findRequirementsDir, findRequirementsFiles, writeLookupCache, initTestRunId, clearTrackingFile, writeProjectRoot, } from './cache.js';
12
- import { parseRequirementsFromFile, } from '../schema/index.js';
13
- import { findProjectRoot } from '../utils/project-settings.js';
11
+ import { findRequirementsFilesSync } from "../requirements/index.js";
12
+ import { parseRequirementsFromFile, } from "../schema/index.js";
13
+ import { findProjectRoot } from "../utils/project-settings.js";
14
+ import { clearTrackingFile, findRequirementsDir, initTestRunId, writeLookupCache, writeProjectRoot, } from "./cache.js";
14
15
  /**
15
16
  * Prepare the test harness for a test run.
16
17
  *
@@ -26,14 +27,14 @@ export function prepare(options = {}) {
26
27
  // Find the project root by looking for .requirements directory
27
28
  const projectRoot = findProjectRoot(cwd);
28
29
  if (!projectRoot) {
29
- throw new Error('Could not find .requirements directory. ' +
30
+ throw new Error("Could not find .requirements directory. " +
30
31
  'Please run "dotrequirements init" to initialize your project.');
31
32
  }
32
33
  // Set environment variable for cross-process persistence (globalSetup → test workers)
33
34
  process.env.DOTREQUIREMENTS_PROJECT_ROOT = projectRoot;
34
35
  const requirementsDir = findRequirementsDir(projectRoot);
35
36
  // Find all requirements files
36
- const files = findRequirementsFiles(projectRoot);
37
+ const files = findRequirementsFilesSync(projectRoot);
37
38
  // Parse all files, collecting requirements and errors
38
39
  const allRequirements = [];
39
40
  const parseErrors = [];
@@ -7,8 +7,8 @@
7
7
  * 2. DOTREQUIREMENTS_PROJECT_ROOT environment variable
8
8
  * 3. Cached project root file (.requirements/.cache/project-root) written by prepare()
9
9
  */
10
- import { type RequirementNode } from '../schema/index.js';
11
- import { Requirement } from './types.js';
10
+ import { type RequirementNode } from "../schema/index.js";
11
+ import type { Requirement } from "./types.js";
12
12
  export declare const loadedRequirements: Map<string, RequirementNode>;
13
13
  export interface LoadOptions {
14
14
  /** Explicit project root path. Takes precedence over env var and cached file. */
@@ -7,11 +7,11 @@
7
7
  * 2. DOTREQUIREMENTS_PROJECT_ROOT environment variable
8
8
  * 3. Cached project root file (.requirements/.cache/project-root) written by prepare()
9
9
  */
10
- import * as fs from 'fs';
11
- import * as path from 'path';
12
- import { globSync } from 'glob';
13
- import { parseRequirementsFromFile, resolveRequirementPath, } from '../schema/index.js';
14
- import { findCachedProjectRoot, readLookupCache, } from './cache.js';
10
+ import * as fs from "node:fs";
11
+ import * as path from "node:path";
12
+ import { findRequirementsFilesSync } from "../requirements/index.js";
13
+ import { parseRequirementsFromFile, resolveRequirementPath, } from "../schema/index.js";
14
+ import { findCachedProjectRoot, readLookupCache } from "./cache.js";
15
15
  // Cache: Maps full requirement IDs (e.g., "REQ-123.0.1") to RequirementNode
16
16
  export const loadedRequirements = new Map();
17
17
  // Cache: Maps root requirement IDs (e.g., "REQ-123") to their tree
@@ -36,34 +36,12 @@ function findProjectRoot(options = {}) {
36
36
  // Priority 3: Cached file (written by prepare())
37
37
  return findCachedProjectRoot(process.cwd());
38
38
  }
39
- /**
40
- * Find all *.requirements.md files under project root synchronously.
41
- */
42
- function findRequirementsFilesSync(projectRoot) {
43
- const pattern = '**/*.requirements.md';
44
- const matches = globSync(pattern, {
45
- cwd: projectRoot,
46
- ignore: [
47
- '**/node_modules/**',
48
- '**/dist/**',
49
- '**/.git/**',
50
- '**/build/**',
51
- '**/example/**',
52
- '**/examples/**',
53
- '**/__tests__/**',
54
- '**/fixtures/**',
55
- '**/.fixtures/**',
56
- ],
57
- dot: true, // Include dotfiles/dotdirs like .requirements/
58
- });
59
- return matches.map(m => path.join(projectRoot, m));
60
- }
61
39
  /**
62
40
  * Try to load requirements from lookup cache (fast path).
63
41
  * Returns true if cache was loaded, false if not available.
64
42
  */
65
43
  function tryLoadFromCache(projectRoot) {
66
- const requirementsDir = path.join(projectRoot, '.requirements');
44
+ const requirementsDir = path.join(projectRoot, ".requirements");
67
45
  if (!fs.existsSync(requirementsDir)) {
68
46
  return false;
69
47
  }
@@ -82,7 +60,7 @@ function tryLoadFromCache(projectRoot) {
82
60
  };
83
61
  loadedRequirements.set(id, node);
84
62
  // If this is a root node (no dot in ID), add to trees cache
85
- if (!id.includes('.')) {
63
+ if (!id.includes(".")) {
86
64
  requirementTrees.set(id, node);
87
65
  }
88
66
  }
@@ -96,7 +74,7 @@ function flattenRequirementTree(node) {
96
74
  // Add this node to the flat cache
97
75
  loadedRequirements.set(node.id, node);
98
76
  // If this is a root node (no dot in ID), also add to trees cache
99
- if (!node.id.includes('.')) {
77
+ if (!node.id.includes(".")) {
100
78
  requirementTrees.set(node.id, node);
101
79
  }
102
80
  // Recursively add children
@@ -119,8 +97,8 @@ export function loadRequirements(options = {}) {
119
97
  // Find project root
120
98
  const projectRoot = findProjectRoot(options);
121
99
  if (!projectRoot) {
122
- throw new Error('Could not find project root. ' +
123
- 'Set DOTREQUIREMENTS_PROJECT_ROOT environment variable or run prepare() in globalSetup.');
100
+ throw new Error("Could not find project root. " +
101
+ "Set DOTREQUIREMENTS_PROJECT_ROOT environment variable or run prepare() in globalSetup.");
124
102
  }
125
103
  // Try cache first (fast path)
126
104
  if (tryLoadFromCache(projectRoot)) {
@@ -128,8 +106,8 @@ export function loadRequirements(options = {}) {
128
106
  }
129
107
  // Fallback: Parse .requirements.md files on-demand
130
108
  if (!warnedAboutFallback && !options.projectRoot) {
131
- console.warn('⚠️ Performance warning: prepare() was not called. ' +
132
- 'Parsing requirements on-demand. Run prepare() in globalSetup for faster tests.');
109
+ console.warn("⚠️ Performance warning: prepare() was not called. " +
110
+ "Parsing requirements on-demand. Run prepare() in globalSetup for faster tests.");
133
111
  warnedAboutFallback = true;
134
112
  }
135
113
  // Find all .requirements.md files under the project root
@@ -144,7 +122,7 @@ export function loadRequirements(options = {}) {
144
122
  }
145
123
  }
146
124
  catch (error) {
147
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
125
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
148
126
  console.error(`Error loading ${file}:`, errorMessage);
149
127
  }
150
128
  }
@@ -6,8 +6,8 @@
6
6
  *
7
7
  * HARNESS-REQUIREMENT-3: Each requirement() call is recorded for coverage reporting
8
8
  */
9
- import * as path from 'path';
10
- import { findRequirementsDir, findProjectRoot, getTestRunId, appendTrackingEntry, getCacheDir, initTestRunId, clearTrackingFile, } from './cache.js';
9
+ import * as path from "node:path";
10
+ import { appendTrackingEntry, clearTrackingFile, findProjectRoot, findRequirementsDir, getCacheDir, getTestRunId, initTestRunId, } from "./cache.js";
11
11
  const trackedRequirements = new Map();
12
12
  // Test run tracking
13
13
  let testRunId = null;
@@ -17,7 +17,7 @@ export function ensureTestRun() {
17
17
  if (!testRunId) {
18
18
  // Priority 1: Use environment variable (cross-process persistence from globalSetup)
19
19
  if (process.env.DOTREQUIREMENTS_PROJECT_ROOT) {
20
- requirementsDirCached = path.join(process.env.DOTREQUIREMENTS_PROJECT_ROOT, '.requirements');
20
+ requirementsDirCached = path.join(process.env.DOTREQUIREMENTS_PROJECT_ROOT, ".requirements");
21
21
  }
22
22
  // Priority 2: Find from caller directory
23
23
  if (!requirementsDirCached) {
@@ -29,7 +29,7 @@ export function ensureTestRun() {
29
29
  }
30
30
  }
31
31
  if (!requirementsDirCached) {
32
- throw new Error('Could not find .requirements directory. Please create one in your project root.');
32
+ throw new Error("Could not find .requirements directory. Please create one in your project root.");
33
33
  }
34
34
  // Try to read from shared test run ID file (set by prepare())
35
35
  const existingRunId = getTestRunId(requirementsDirCached);
@@ -48,14 +48,14 @@ export function ensureTestRun() {
48
48
  // Get caller location for tracking
49
49
  export function getCallerLocation() {
50
50
  const error = new Error();
51
- const stack = error.stack?.split('\n') || [];
51
+ const stack = error.stack?.split("\n") || [];
52
52
  // Find the first stack frame that's not in our library files
53
53
  for (let i = 2; i < stack.length; i++) {
54
54
  const frame = stack[i];
55
- if (!frame.includes('/harness/index.ts') &&
56
- !frame.includes('/harness/index.js') &&
57
- !frame.includes('/harness/tracking.ts') &&
58
- !frame.includes('/harness/tracking.js')) {
55
+ if (!frame.includes("/harness/index.ts") &&
56
+ !frame.includes("/harness/index.js") &&
57
+ !frame.includes("/harness/tracking.ts") &&
58
+ !frame.includes("/harness/tracking.js")) {
59
59
  // Extract filename and line number
60
60
  const regex1 = /\((.+):(\d+):(\d+)\)/;
61
61
  const regex2 = /at (.+):(\d+):(\d+)/;
@@ -67,19 +67,19 @@ export function getCallerLocation() {
67
67
  }
68
68
  }
69
69
  }
70
- return 'unknown';
70
+ return "unknown";
71
71
  }
72
72
  // Get caller's directory (full path) for finding .requirements
73
73
  function getCallerDirectory() {
74
74
  const error = new Error();
75
- const stack = error.stack?.split('\n') || [];
75
+ const stack = error.stack?.split("\n") || [];
76
76
  // Find the first stack frame that's not in our library files
77
77
  for (let i = 2; i < stack.length; i++) {
78
78
  const frame = stack[i];
79
- if (!frame.includes('/harness/index.ts') &&
80
- !frame.includes('/harness/index.js') &&
81
- !frame.includes('/harness/tracking.ts') &&
82
- !frame.includes('/harness/tracking.js')) {
79
+ if (!frame.includes("/harness/index.ts") &&
80
+ !frame.includes("/harness/index.js") &&
81
+ !frame.includes("/harness/tracking.ts") &&
82
+ !frame.includes("/harness/tracking.js")) {
83
83
  // Extract filename
84
84
  const regex1 = /\((.+):(\d+):(\d+)\)/;
85
85
  const regex2 = /at (.+):(\d+):(\d+)/;
@@ -154,7 +154,7 @@ export function clearTracking() {
154
154
  export function initTestRun() {
155
155
  const projectRoot = findProjectRoot();
156
156
  if (!projectRoot) {
157
- throw new Error('Could not find .requirements directory. Please create one in your project root.');
157
+ throw new Error("Could not find .requirements directory. Please create one in your project root.");
158
158
  }
159
159
  const reqDir = findRequirementsDir();
160
160
  // Initialize test run ID
@@ -171,9 +171,9 @@ export function initTestRun() {
171
171
  export function finalizeTestRun() {
172
172
  // Import and call the new finalize function
173
173
  // Using dynamic import to avoid circular dependencies
174
- const { finalize } = require('./finalize.js');
174
+ const { finalize } = require("./finalize.js");
175
175
  finalize().catch((error) => {
176
- console.error('Error in finalizeTestRun:', error.message);
176
+ console.error("Error in finalizeTestRun:", error.message);
177
177
  });
178
178
  }
179
179
  //# sourceMappingURL=tracking.js.map
@@ -2,7 +2,7 @@
2
2
  * Type definitions for test harness.
3
3
  * Uses shared schema types for consistency with CLI and MCP.
4
4
  */
5
- import type { RequirementNode } from '../schema/index.js';
5
+ import type { RequirementNode } from "../schema/index.js";
6
6
  export type { RequirementNode as Requirement };
7
7
  export interface CriteriaDetail {
8
8
  reqId: string;