@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
@@ -1,30 +1,30 @@
1
- import * as path from 'path';
2
- import { glob } from 'glob';
3
- import { parseRequirementsFromFile, parseRequirementsFile, buildRequirementMarkdown, getAllRequirements, } from '../schema/index.js';
1
+ import * as path from "node:path";
2
+ import { glob } from "glob";
3
+ import { buildRequirementMarkdown, getAllRequirements, parseRequirementsFile, parseRequirementsFromFile, } from "../schema/index.js";
4
4
  /**
5
5
  * Find all *.requirements.md files in the workspace.
6
6
  * Supports both .requirements/ directories and colocated files.
7
7
  * Excludes example files, test fixtures, and build artifacts.
8
8
  */
9
9
  export async function findRequirementsFiles(workspaceRoot) {
10
- const pattern = '**/*.requirements.md';
10
+ const pattern = "**/*.requirements.md";
11
11
  const matches = await glob(pattern, {
12
12
  cwd: workspaceRoot,
13
13
  ignore: [
14
- '**/node_modules/**',
15
- '**/dist/**',
16
- '**/.git/**',
17
- '**/build/**',
14
+ "**/node_modules/**",
15
+ "**/dist/**",
16
+ "**/.git/**",
17
+ "**/build/**",
18
18
  // Exclude example and test fixture directories
19
- '**/example/**',
20
- '**/examples/**',
21
- '**/__tests__/**',
22
- '**/fixtures/**',
23
- '**/.fixtures/**',
19
+ "**/example/**",
20
+ "**/examples/**",
21
+ "**/__tests__/**",
22
+ "**/fixtures/**",
23
+ "**/.fixtures/**",
24
24
  ],
25
25
  dot: true, // Include dotfiles/dotdirs like .requirements/
26
26
  });
27
- return matches.map(m => path.join(workspaceRoot, m));
27
+ return matches.map((m) => path.join(workspaceRoot, m));
28
28
  }
29
29
  /**
30
30
  * Load all requirements from the workspace
@@ -56,9 +56,9 @@ export function flattenRequirementsFile(file, sourceFile) {
56
56
  const allReqs = getAllRequirements(file.requirements);
57
57
  for (const req of allReqs) {
58
58
  // Extract position from ID (e.g., "REQ123.0.1" -> "0.1")
59
- const idParts = req.id.split('.');
59
+ const idParts = req.id.split(".");
60
60
  const rootId = idParts[0];
61
- const position = idParts.slice(1).join('.');
61
+ const position = idParts.slice(1).join(".");
62
62
  results.push({
63
63
  id: req.id,
64
64
  rootId: rootId,
@@ -76,7 +76,7 @@ export function flattenRequirementsFile(file, sourceFile) {
76
76
  */
77
77
  export function searchRequirements(requirements, query) {
78
78
  const lowerQuery = query.toLowerCase();
79
- return requirements.filter(req => {
79
+ return requirements.filter((req) => {
80
80
  // Search in ID
81
81
  if (req.id.toLowerCase().includes(lowerQuery))
82
82
  return true;
@@ -94,24 +94,24 @@ export function searchRequirements(requirements, query) {
94
94
  */
95
95
  export function getRequirementById(requirements, id) {
96
96
  // Exact match first
97
- const exact = requirements.find(r => r.id === id);
97
+ const exact = requirements.find((r) => r.id === id);
98
98
  if (exact)
99
99
  return exact;
100
100
  // Try partial match (just the root ID)
101
- return requirements.find(r => r.rootId === id || r.id.startsWith(id + '.'));
101
+ return requirements.find((r) => r.rootId === id || r.id.startsWith(`${id}.`));
102
102
  }
103
103
  /**
104
104
  * Get a requirement and all its children
105
105
  */
106
106
  export function getRequirementTree(requirements, rootId) {
107
- return requirements.filter(r => r.rootId === rootId || r.id === rootId);
107
+ return requirements.filter((r) => r.rootId === rootId || r.id === rootId);
108
108
  }
109
109
  /**
110
110
  * Format a requirement for display
111
111
  */
112
112
  export function formatRequirement(req) {
113
- const indent = ' '.repeat(req.path.length);
114
- const label = req.label ? ` (${req.label})` : '';
113
+ const indent = " ".repeat(req.path.length);
114
+ const label = req.label ? ` (${req.label})` : "";
115
115
  return `${indent}${req.id}${label}: ${req.content}`;
116
116
  }
117
117
  /**
@@ -121,11 +121,11 @@ export function formatRequirement(req) {
121
121
  */
122
122
  export function filterRequirementsByKeys(fileContents, keys) {
123
123
  const { requirements } = parseRequirementsFile(fileContents);
124
- const upperKeys = keys.map(k => k.toUpperCase());
125
- const filtered = requirements.filter(r => upperKeys.includes(r.id.toUpperCase()));
126
- const foundKeys = filtered.map(r => r.id);
127
- const missingKeys = upperKeys.filter(k => !foundKeys.map(f => f.toUpperCase()).includes(k));
128
- const filteredContent = filtered.map(buildRequirementMarkdown).join('\n');
124
+ const upperKeys = keys.map((k) => k.toUpperCase());
125
+ const filtered = requirements.filter((r) => upperKeys.includes(r.id.toUpperCase()));
126
+ const foundKeys = filtered.map((r) => r.id);
127
+ const missingKeys = upperKeys.filter((k) => !foundKeys.map((f) => f.toUpperCase()).includes(k));
128
+ const filteredContent = filtered.map(buildRequirementMarkdown).join("\n");
129
129
  return { filteredContent, foundKeys, missingKeys };
130
130
  }
131
131
  /**
@@ -137,8 +137,8 @@ export function formatRequirementTree(requirements) {
137
137
  // Compare paths element by element for proper tree order
138
138
  const maxLen = Math.max(a.path.length, b.path.length);
139
139
  for (let i = 0; i < maxLen; i++) {
140
- const aVal = i < a.path.length ? parseInt(a.path[i]) : -1;
141
- const bVal = i < b.path.length ? parseInt(b.path[i]) : -1;
140
+ const aVal = i < a.path.length ? parseInt(a.path[i], 10) : -1;
141
+ const bVal = i < b.path.length ? parseInt(b.path[i], 10) : -1;
142
142
  // If one path is a prefix of the other, the shorter one comes first
143
143
  if (aVal === -1)
144
144
  return -1;
@@ -150,6 +150,6 @@ export function formatRequirementTree(requirements) {
150
150
  }
151
151
  return 0;
152
152
  });
153
- return sorted.map(formatRequirement).join('\n');
153
+ return sorted.map(formatRequirement).join("\n");
154
154
  }
155
155
  //# sourceMappingURL=requirements.js.map
@@ -4,30 +4,32 @@
4
4
  * Finds requirement() call references and extracts the enclosing
5
5
  * meaningful code block (function, describe, test, etc.)
6
6
  */
7
- import { parse } from '@babel/parser';
8
- import traverse from '@babel/traverse';
9
- import * as t from '@babel/types';
10
- import * as fs from 'fs';
7
+ import * as fs from "node:fs";
8
+ import { parse } from "@babel/parser";
9
+ import traverse from "@babel/traverse";
10
+ import * as t from "@babel/types";
11
11
  /**
12
12
  * Find all test code blocks that reference a specific requirement
13
13
  */
14
14
  export function findTestCodeForRequirement(filePath, requirementId) {
15
15
  try {
16
- const code = fs.readFileSync(filePath, 'utf-8');
16
+ const code = fs.readFileSync(filePath, "utf-8");
17
17
  const results = [];
18
18
  // Parse with TypeScript and JSX support
19
19
  const ast = parse(code, {
20
- sourceType: 'module',
21
- plugins: ['typescript', 'jsx'],
20
+ sourceType: "module",
21
+ plugins: ["typescript", "jsx"],
22
22
  errorRecovery: true,
23
23
  });
24
24
  // Handle both ES module and CommonJS exports
25
- const traverseFunc = typeof traverse === 'function' ? traverse : traverse.default;
25
+ const traverseFunc =
26
+ // biome-ignore lint/suspicious/noExplicitAny: @babel/traverse CJS default-export interop (callable function vs namespace import)
27
+ typeof traverse === "function" ? traverse : traverse.default;
26
28
  traverseFunc(ast, {
27
29
  CallExpression(path) {
28
30
  // Check if this is a requirement('ID', ...) call
29
31
  const callee = path.node.callee;
30
- if (t.isIdentifier(callee) && callee.name === 'requirement') {
32
+ if (t.isIdentifier(callee) && callee.name === "requirement") {
31
33
  const args = path.node.arguments;
32
34
  // Extract all string literal arguments (supports multi-requirement calls)
33
35
  const refIds = [];
@@ -39,12 +41,11 @@ export function findTestCodeForRequirement(filePath, requirementId) {
39
41
  // Check if any argument matches the requirement we're looking for
40
42
  // Match exact ID or if it's a child (e.g., searching for REQ-123 matches REQ-123.0)
41
43
  for (const refId of refIds) {
42
- const isMatch = refId === requirementId ||
43
- refId.startsWith(`${requirementId}.`);
44
+ const isMatch = refId === requirementId || refId.startsWith(`${requirementId}.`);
44
45
  if (isMatch) {
45
46
  // Find the meaningful enclosing block
46
47
  const contextNode = findMeaningfulParent(path);
47
- if (contextNode && contextNode.node.loc) {
48
+ if (contextNode?.node.loc) {
48
49
  const { start, end } = contextNode.node.loc;
49
50
  const nodeStart = contextNode.node.start ?? 0;
50
51
  const nodeEnd = contextNode.node.end ?? code.length;
@@ -91,15 +92,15 @@ function findMeaningfulParent(path) {
91
92
  const callee = node.callee;
92
93
  // Common test framework function names
93
94
  const testFunctionNames = [
94
- 'describe',
95
- 'it',
96
- 'test',
97
- 'suite',
98
- 'context',
99
- 'beforeEach',
100
- 'afterEach',
101
- 'beforeAll',
102
- 'afterAll',
95
+ "describe",
96
+ "it",
97
+ "test",
98
+ "suite",
99
+ "context",
100
+ "beforeEach",
101
+ "afterEach",
102
+ "beforeAll",
103
+ "afterAll",
103
104
  ];
104
105
  if (t.isIdentifier(callee) && testFunctionNames.includes(callee.name)) {
105
106
  return current;
@@ -125,7 +126,7 @@ export function findFilesWithRequirement(files, requirementId) {
125
126
  const matchingFiles = [];
126
127
  for (const file of files) {
127
128
  try {
128
- const code = fs.readFileSync(file, 'utf-8');
129
+ const code = fs.readFileSync(file, "utf-8");
129
130
  // Check for exact match or child references (e.g., AUTH-VALID-LOGIN or AUTH-VALID-LOGIN.0)
130
131
  // Simple string search first for performance
131
132
  // Patterns match both single and multi-arg calls:
@@ -142,10 +143,7 @@ export function findFilesWithRequirement(files, requirementId) {
142
143
  matchingFiles.push(file);
143
144
  }
144
145
  }
145
- catch (error) {
146
- // Skip files that can't be read
147
- continue;
148
- }
146
+ catch (error) { }
149
147
  }
150
148
  return matchingFiles;
151
149
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Re-export shared types from CLI schema module
3
3
  */
4
- export type { Metadata, RequirementNode, RequirementsFile, } from '../schema/index.js';
4
+ export type { Metadata, RequirementNode, RequirementsFile, } from "../schema/index.js";
5
5
  /**
6
6
  * Flattened requirement for search results
7
7
  */
@@ -9,7 +9,7 @@
9
9
  * - Executing the push
10
10
  * - Updating local files with document IDs and timestamps
11
11
  */
12
- import type { Metadata } from '../schema/index.js';
12
+ import type { Metadata } from "../schema/index.js";
13
13
  export interface PushCredentials {
14
14
  projectId: string;
15
15
  projectSecret: string;
@@ -41,7 +41,7 @@ export interface CloudDocumentMetadata {
41
41
  */
42
42
  export interface DryRunResultItem {
43
43
  dryRun: true;
44
- action: 'create' | 'update' | 'not_found' | 'invalid';
44
+ action: "create" | "update" | "not_found" | "invalid";
45
45
  documentId?: string;
46
46
  title?: string;
47
47
  warning?: string;
package/dist/push/core.js CHANGED
@@ -9,11 +9,11 @@
9
9
  * - Executing the push
10
10
  * - Updating local files with document IDs and timestamps
11
11
  */
12
- import * as fs from 'fs';
13
- import * as path from 'path';
14
- import { ConvexHttpClient } from 'convex/browser';
15
- import { parseRequirementsFromFile, getAllRequirements, parseRequirementKey, buildRequirementsFile, } from '../schema/index.js';
16
- import { api } from '../convex.js';
12
+ import * as fs from "node:fs";
13
+ import * as path from "node:path";
14
+ import { ConvexHttpClient } from "convex/browser";
15
+ import { api } from "../convex.js";
16
+ import { buildRequirementsFile, getAllRequirements, parseRequirementKey, parseRequirementsFromFile, } from "../schema/index.js";
17
17
  // ============================================================================
18
18
  // Parsing
19
19
  // ============================================================================
@@ -36,7 +36,7 @@ export function parseFilesForPush(filePaths) {
36
36
  let totalRequirements = 0;
37
37
  for (const filePath of filePaths) {
38
38
  // Read raw file content
39
- const rawContent = fs.readFileSync(filePath, 'utf-8');
39
+ const rawContent = fs.readFileSync(filePath, "utf-8");
40
40
  // Parse to get metadata and requirements
41
41
  const parsed = parseRequirementsFromFile(filePath);
42
42
  const flatRequirements = getAllRequirements(parsed.requirements);
@@ -82,9 +82,9 @@ export async function dryRunPush(parsedFiles, credentials) {
82
82
  file,
83
83
  result: {
84
84
  dryRun: true,
85
- action: 'invalid',
85
+ action: "invalid",
86
86
  title: fileName,
87
- error: 'Missing document section in frontmatter',
87
+ error: "Missing document section in frontmatter",
88
88
  },
89
89
  });
90
90
  continue;
@@ -95,7 +95,7 @@ export async function dryRunPush(parsedFiles, credentials) {
95
95
  projectSlug: credentials.projectId,
96
96
  projectSecret: credentials.projectSecret,
97
97
  },
98
- target: { type: 'project', slug: credentials.projectId },
98
+ target: { type: "project", slug: credentials.projectId },
99
99
  documentId: doc.id,
100
100
  title: doc.title,
101
101
  markdownContent: file.markdownContent,
@@ -109,7 +109,7 @@ export async function dryRunPush(parsedFiles, credentials) {
109
109
  file,
110
110
  result: {
111
111
  dryRun: true,
112
- action: 'invalid',
112
+ action: "invalid",
113
113
  title: doc.title,
114
114
  error: err.message,
115
115
  },
@@ -117,10 +117,10 @@ export async function dryRunPush(parsedFiles, credentials) {
117
117
  }
118
118
  }
119
119
  // Categorize results
120
- const updates = dryRunResults.filter((r) => r.result.action === 'update');
121
- const creates = dryRunResults.filter((r) => r.result.action === 'create');
122
- const notFound = dryRunResults.filter((r) => r.result.action === 'not_found');
123
- const invalid = dryRunResults.filter((r) => r.result.action === 'invalid');
120
+ const updates = dryRunResults.filter((r) => r.result.action === "update");
121
+ const creates = dryRunResults.filter((r) => r.result.action === "create");
122
+ const notFound = dryRunResults.filter((r) => r.result.action === "not_found");
123
+ const invalid = dryRunResults.filter((r) => r.result.action === "invalid");
124
124
  // Check for conflicts on updates (cloud changed since last pull)
125
125
  const conflicts = [];
126
126
  if (updates.length > 0) {
@@ -130,7 +130,7 @@ export async function dryRunPush(parsedFiles, credentials) {
130
130
  projectSlug: credentials.projectId,
131
131
  projectSecret: credentials.projectSecret,
132
132
  },
133
- target: { type: 'project', slug: credentials.projectId },
133
+ target: { type: "project", slug: credentials.projectId },
134
134
  documentIds: docIds,
135
135
  });
136
136
  const cloudMetaByDocId = new Map(cloudMetadata.map((m) => [m.documentId, m]));
@@ -174,28 +174,28 @@ export async function executePush(dryRunResult, credentials) {
174
174
  const doc = file.metadata.document;
175
175
  const fileName = path.basename(file.filePath);
176
176
  // For not_found, clear the ID so we create a new document
177
- const effectiveDocId = result.action === 'not_found' ? undefined : doc.id;
177
+ const effectiveDocId = result.action === "not_found" ? undefined : doc.id;
178
178
  try {
179
179
  const pushResult = (await client.mutation(api.documents.saveWithRequirements.saveWithRequirements, {
180
180
  projectAuth: {
181
181
  projectSlug: credentials.projectId,
182
182
  projectSecret: credentials.projectSecret,
183
183
  },
184
- target: { type: 'project', slug: credentials.projectId },
184
+ target: { type: "project", slug: credentials.projectId },
185
185
  documentId: effectiveDocId,
186
186
  title: doc.title,
187
187
  markdownContent: file.markdownContent,
188
188
  defaultPrefix: doc.defaultPrefix,
189
189
  dryRun: false,
190
190
  }));
191
- const isCreate = result.action === 'create' || result.action === 'not_found';
191
+ const isCreate = result.action === "create" || result.action === "not_found";
192
192
  if (isCreate) {
193
193
  // New document - write ID back to file
194
194
  doc.id = pushResult;
195
195
  file.metadata.pulledAt = new Date().toISOString();
196
196
  file.metadata.version = 1;
197
197
  const updatedContent = buildRequirementsFile(file.metadata, file.markdownContent);
198
- fs.writeFileSync(file.filePath, updatedContent, 'utf-8');
198
+ fs.writeFileSync(file.filePath, updatedContent, "utf-8");
199
199
  created++;
200
200
  }
201
201
  else {
@@ -203,7 +203,7 @@ export async function executePush(dryRunResult, credentials) {
203
203
  file.metadata.pulledAt = new Date().toISOString();
204
204
  file.metadata.version = (file.metadata.version || 0) + 1;
205
205
  const updatedContent = buildRequirementsFile(file.metadata, file.markdownContent);
206
- fs.writeFileSync(file.filePath, updatedContent, 'utf-8');
206
+ fs.writeFileSync(file.filePath, updatedContent, "utf-8");
207
207
  updated++;
208
208
  }
209
209
  }
@@ -4,5 +4,5 @@
4
4
  * Shared push logic for syncing local requirements files to the cloud.
5
5
  * Used by both CLI push command and MCP push_requirements tool.
6
6
  */
7
- export { type PushCredentials, type ParsedFile, type CloudDocumentMetadata, type DryRunResultItem, type FileWithDryRun, type ConflictInfo, type DryRunResult, type PushResult, extractMarkdownContent, parseFilesForPush, dryRunPush, executePush, } from './core.js';
7
+ export { type CloudDocumentMetadata, type ConflictInfo, type DryRunResult, type DryRunResultItem, dryRunPush, executePush, extractMarkdownContent, type FileWithDryRun, type ParsedFile, type PushCredentials, type PushResult, parseFilesForPush, } from "./core.js";
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -4,7 +4,7 @@
4
4
  * Shared push logic for syncing local requirements files to the cloud.
5
5
  * Used by both CLI push command and MCP push_requirements tool.
6
6
  */
7
- export {
7
+ export { dryRunPush, executePush,
8
8
  // Functions
9
- extractMarkdownContent, parseFilesForPush, dryRunPush, executePush, } from './core.js';
9
+ extractMarkdownContent, parseFilesForPush, } from "./core.js";
10
10
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Cloud-AI library — hosted endpoints for style review, test review, and
3
+ * project context retrieval. Shared between the MCP handlers and the CLI
4
+ * verbs that wrap them.
5
+ *
6
+ * Each function does one cloud call and returns the unwrapped result (or
7
+ * throws on failure). Surface-specific concerns (error formatting, exit
8
+ * codes, MCP tool responses) live in the callers.
9
+ */
10
+ /**
11
+ * Default base URL for the hosted AI endpoints (`/api/style-check`,
12
+ * `/api/review-test`). Overridable via the `apiBaseUrl` argument or
13
+ * the `DOTREQUIREMENTS_API_URL` environment variable in callers.
14
+ */
15
+ export declare const DEFAULT_API_BASE_URL = "https://app.dotrequirements.io";
16
+ export interface StyleCheckParams {
17
+ apiBaseUrl: string;
18
+ projectId: string;
19
+ projectSecret: string;
20
+ fileContents: string;
21
+ fileType: "requirements" | "test";
22
+ model?: string;
23
+ }
24
+ /**
25
+ * POST to `/api/style-check`. Returns the feedback text on success;
26
+ * throws an Error with the underlying failure reason on a non-OK
27
+ * response or a network error.
28
+ */
29
+ export declare function fetchStyleCheckFeedback(params: StyleCheckParams): Promise<string>;
30
+ export interface ReviewTestParams {
31
+ apiBaseUrl: string;
32
+ projectId: string;
33
+ projectSecret: string;
34
+ testFileContents: string;
35
+ requirements: Array<{
36
+ id: string;
37
+ content: string;
38
+ testedIds: string[];
39
+ }>;
40
+ }
41
+ /**
42
+ * POST to `/api/review-test`. Returns the feedback text on success;
43
+ * throws an Error with the underlying failure reason on a non-OK
44
+ * response or a network error.
45
+ */
46
+ export declare function fetchReviewTestFeedback(params: ReviewTestParams): Promise<string>;
47
+ export interface ProjectContext {
48
+ projectContext: string | null;
49
+ requirementsStyleContext: string | null;
50
+ }
51
+ /**
52
+ * Query Convex for project-level AI context (project description and
53
+ * requirements style guidance). Returns null on any failure — the caller
54
+ * is expected to degrade gracefully if context is unavailable.
55
+ */
56
+ export declare function getProjectContext(projectId: string, projectSecret: string, convexUrl: string): Promise<ProjectContext | null>;
57
+ //# sourceMappingURL=cloud-ai.d.ts.map
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Cloud-AI library — hosted endpoints for style review, test review, and
3
+ * project context retrieval. Shared between the MCP handlers and the CLI
4
+ * verbs that wrap them.
5
+ *
6
+ * Each function does one cloud call and returns the unwrapped result (or
7
+ * throws on failure). Surface-specific concerns (error formatting, exit
8
+ * codes, MCP tool responses) live in the callers.
9
+ */
10
+ /**
11
+ * Default base URL for the hosted AI endpoints (`/api/style-check`,
12
+ * `/api/review-test`). Overridable via the `apiBaseUrl` argument or
13
+ * the `DOTREQUIREMENTS_API_URL` environment variable in callers.
14
+ */
15
+ export const DEFAULT_API_BASE_URL = "https://app.dotrequirements.io";
16
+ /**
17
+ * POST to `/api/style-check`. Returns the feedback text on success;
18
+ * throws an Error with the underlying failure reason on a non-OK
19
+ * response or a network error.
20
+ */
21
+ export async function fetchStyleCheckFeedback(params) {
22
+ const response = await fetch(`${params.apiBaseUrl}/api/style-check`, {
23
+ method: "POST",
24
+ headers: { "Content-Type": "application/json" },
25
+ body: JSON.stringify({
26
+ projectId: params.projectId,
27
+ projectSecret: params.projectSecret,
28
+ fileContents: params.fileContents,
29
+ fileType: params.fileType,
30
+ model: params.model,
31
+ }),
32
+ });
33
+ if (!response.ok) {
34
+ const errorData = (await response.json().catch(() => ({})));
35
+ throw new Error(errorData.error || response.statusText);
36
+ }
37
+ const data = (await response.json());
38
+ return data.feedback;
39
+ }
40
+ /**
41
+ * POST to `/api/review-test`. Returns the feedback text on success;
42
+ * throws an Error with the underlying failure reason on a non-OK
43
+ * response or a network error.
44
+ */
45
+ export async function fetchReviewTestFeedback(params) {
46
+ const response = await fetch(`${params.apiBaseUrl}/api/review-test`, {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({
50
+ projectId: params.projectId,
51
+ projectSecret: params.projectSecret,
52
+ testFileContents: params.testFileContents,
53
+ requirements: params.requirements,
54
+ }),
55
+ });
56
+ if (!response.ok) {
57
+ const errorData = (await response.json().catch(() => ({})));
58
+ throw new Error(errorData.error || response.statusText);
59
+ }
60
+ const data = (await response.json());
61
+ return data.feedback;
62
+ }
63
+ /**
64
+ * Query Convex for project-level AI context (project description and
65
+ * requirements style guidance). Returns null on any failure — the caller
66
+ * is expected to degrade gracefully if context is unavailable.
67
+ */
68
+ export async function getProjectContext(projectId, projectSecret, convexUrl) {
69
+ try {
70
+ const response = await fetch(`${convexUrl}/api/query`, {
71
+ method: "POST",
72
+ headers: { "Content-Type": "application/json" },
73
+ body: JSON.stringify({
74
+ path: "projects/queries:get",
75
+ args: {
76
+ projectAuth: {
77
+ projectSlug: projectId,
78
+ projectSecret,
79
+ },
80
+ target: {
81
+ type: "project",
82
+ slug: projectId,
83
+ },
84
+ },
85
+ format: "json",
86
+ }),
87
+ });
88
+ if (!response.ok) {
89
+ return null;
90
+ }
91
+ const json = (await response.json());
92
+ if (json.status === "error" || !json.value) {
93
+ return null;
94
+ }
95
+ return {
96
+ projectContext: json.value.projectContext ?? null,
97
+ requirementsStyleContext: json.value.requirementsStyleContext ?? null,
98
+ };
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ //# sourceMappingURL=cloud-ai.js.map
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Cloud-coverage library — hosted endpoints for querying persisted test
3
+ * coverage from dot•requirements cloud. Shared between the MCP `report`
4
+ * tool and the CLI `report` verb's `--source cloud` mode.
5
+ */
6
+ export interface RequirementCoverageRecord {
7
+ requirementKey: string;
8
+ lastTestedAt: number | null;
9
+ branch: string | null;
10
+ testFile: string | null;
11
+ testLine: number | null;
12
+ allBranches: Array<{
13
+ branch: string;
14
+ lastTestedAt: number;
15
+ testFile?: string;
16
+ testLine?: number;
17
+ }>;
18
+ }
19
+ export interface ProjectCoverageRecord {
20
+ tested: Array<{
21
+ requirementKey: string;
22
+ lastTestedAt: number;
23
+ branch: string;
24
+ testFile?: string;
25
+ testLine?: number;
26
+ }>;
27
+ untested: string[];
28
+ }
29
+ /**
30
+ * Query cloud for coverage on a single requirement.
31
+ */
32
+ export declare function getRequirementCoverage(requirementKey: string, projectId: string, projectSecret: string, convexUrl: string): Promise<RequirementCoverageRecord>;
33
+ /**
34
+ * Query cloud for project-wide coverage summary, optionally filtered by
35
+ * branch or recorded-since timestamp.
36
+ */
37
+ export declare function getProjectCoverage(projectId: string, projectSecret: string, convexUrl: string, options?: {
38
+ branch?: string;
39
+ sinceTimestamp?: number;
40
+ }): Promise<ProjectCoverageRecord>;
41
+ //# sourceMappingURL=cloud-coverage.d.ts.map