@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,43 @@
1
+ import { getReferencedRequirementIds } from "../requirements/grep.js";
2
+ import { loadAllRequirements, } from "../requirements/index.js";
3
+ export async function listCommand(options) {
4
+ const workspaceRoot = process.cwd();
5
+ const { flattened } = await loadAllRequirements(workspaceRoot);
6
+ if (flattened.length === 0) {
7
+ console.log("No requirements found. Make sure .requirements/ directory exists with *.requirements.md files.");
8
+ return;
9
+ }
10
+ const rootRequirements = flattened.filter((r) => r.path.length === 0);
11
+ if (options.untested) {
12
+ // CLI-FIND-LIST-2: filter to roots with no requirement() references
13
+ const referencedIds = await getReferencedRequirementIds(workspaceRoot);
14
+ const untested = rootRequirements.filter((r) => !referencedIds.has(r.id));
15
+ // CLI-FIND-LIST-2.2: full coverage → say so explicitly
16
+ if (untested.length === 0) {
17
+ console.log(`All ${rootRequirements.length} requirement(s) have test references.`);
18
+ return;
19
+ }
20
+ // CLI-FIND-LIST-2.1: count of untested + total
21
+ console.log(`Found ${untested.length} untested requirement(s) out of ${rootRequirements.length} total:\n`);
22
+ for (const r of untested) {
23
+ console.log(` ${r.id}: ${r.content}`);
24
+ }
25
+ return;
26
+ }
27
+ // CLI-FIND-LIST-1: list all roots
28
+ const grouped = new Map();
29
+ for (const req of flattened) {
30
+ const existing = grouped.get(req.rootId) || [];
31
+ existing.push(req);
32
+ grouped.set(req.rootId, existing);
33
+ }
34
+ // CLI-FIND-LIST-1.1: totals
35
+ console.log(`Found ${grouped.size} requirement(s) with ${flattened.length} total nodes:\n`);
36
+ // CLI-FIND-LIST-1.0: each root with ID, content, child count
37
+ for (const [rootId, reqs] of grouped) {
38
+ const root = reqs.find((r) => r.path.length === 0);
39
+ const childCount = reqs.length - 1;
40
+ console.log(` ${rootId}: ${root?.content || "(no content)"} (${childCount} children)`);
41
+ }
42
+ }
43
+ //# sourceMappingURL=list.js.map
@@ -1,16 +1,16 @@
1
- import { execSync } from 'child_process';
2
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
3
- import { homedir } from 'os';
4
- import { join } from 'path';
5
- import prompts from 'prompts';
6
- import { loadTemplate } from '../utils/templates.js';
7
- import { brand } from '../utils/brand.js';
8
- import { getContextFileName, findGitRoot, findDotrequirementsSection, appendOrUpdateSection, buildNoGitRepoMessage, } from '../utils/context-file.js';
1
+ import { execSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ import prompts from "prompts";
6
+ import { brand } from "../utils/brand.js";
7
+ import { appendOrUpdateSection, buildNoGitRepoMessage, findDotrequirementsSection, findGitRoot, getContextFileName, } from "../utils/context-file.js";
8
+ import { loadTemplate } from "../utils/templates.js";
9
9
  /**
10
10
  * Load the context file section template
11
11
  */
12
12
  function loadContextFileSection() {
13
- return loadTemplate('context-file-section.md');
13
+ return loadTemplate("context-file-section.md");
14
14
  }
15
15
  /**
16
16
  * Install workflow guidance to the appropriate context file for a platform
@@ -23,7 +23,7 @@ async function installContextFileSection(platform) {
23
23
  }
24
24
  const gitRoot = await findGitRoot();
25
25
  if (!gitRoot) {
26
- console.log('\n' + buildNoGitRepoMessage(fileName) + '\n');
26
+ console.log(`\n${buildNoGitRepoMessage(fileName)}\n`);
27
27
  return;
28
28
  }
29
29
  const contextFilePath = join(gitRoot, fileName);
@@ -31,40 +31,48 @@ async function installContextFileSection(platform) {
31
31
  // Check if file exists and has existing section
32
32
  let existingSection = null;
33
33
  if (existsSync(contextFilePath)) {
34
- const content = readFileSync(contextFilePath, 'utf-8');
34
+ const content = readFileSync(contextFilePath, "utf-8");
35
35
  const section = findDotrequirementsSection(content);
36
36
  if (section) {
37
37
  existingSection = section.content;
38
38
  }
39
39
  }
40
40
  // Prompt user
41
- const action = existingSection ? 'Update' : existsSync(contextFilePath) ? 'Add to' : 'Create';
41
+ const action = existingSection
42
+ ? "Update"
43
+ : existsSync(contextFilePath)
44
+ ? "Add to"
45
+ : "Create";
42
46
  const response = await prompts({
43
- type: 'confirm',
44
- name: 'install',
47
+ type: "confirm",
48
+ name: "install",
45
49
  message: `${action} ${fileName} with dotrequirements workflow guidance?`,
46
50
  initial: true,
47
51
  });
48
52
  if (!response.install) {
49
- console.log('');
53
+ console.log("");
50
54
  return;
51
55
  }
52
56
  // If updating, show what will change
53
57
  if (existingSection) {
54
58
  const confirmUpdate = await prompts({
55
- type: 'confirm',
56
- name: 'confirm',
57
- message: 'Existing dotrequirements section found. Replace it?',
59
+ type: "confirm",
60
+ name: "confirm",
61
+ message: "Existing dotrequirements section found. Replace it?",
58
62
  initial: true,
59
63
  });
60
64
  if (!confirmUpdate.confirm) {
61
- console.log(' Skipped.\n');
65
+ console.log(" Skipped.\n");
62
66
  return;
63
67
  }
64
68
  }
65
69
  try {
66
70
  const result = appendOrUpdateSection(contextFilePath, sectionContent);
67
- const actionVerb = result.action === 'created' ? 'Created' : result.action === 'appended' ? 'Added to' : 'Updated';
71
+ const actionVerb = result.action === "created"
72
+ ? "Created"
73
+ : result.action === "appended"
74
+ ? "Added to"
75
+ : "Updated";
68
76
  console.log(`✅ ${actionVerb} ${contextFilePath}\n`);
69
77
  }
70
78
  catch (error) {
@@ -79,71 +87,72 @@ export async function mcpSetupCommand() {
79
87
  console.log(`🔧 Setting up ${brand} MCP server\n`);
80
88
  // Interactive client selector
81
89
  const response = await prompts({
82
- type: 'select',
83
- name: 'client',
84
- message: 'Which AI assistant are you using?',
90
+ type: "select",
91
+ name: "client",
92
+ message: "Which AI assistant are you using?",
85
93
  choices: [
86
- { title: 'Claude Code', value: 'claude-code' },
87
- { title: 'Claude Desktop', value: 'claude-desktop' },
88
- { title: 'Cursor', value: 'cursor' },
89
- { title: 'Google Antigravity', value: 'antigravity' },
90
- { title: 'OpenAI Codex', value: 'codex' },
91
- { title: 'GitHub Copilot', value: 'github-copilot' },
92
- { title: 'Other (custom path)', value: 'other' },
94
+ { title: "Claude Code", value: "claude-code" },
95
+ { title: "Claude Desktop", value: "claude-desktop" },
96
+ { title: "Cursor", value: "cursor" },
97
+ { title: "Google Antigravity", value: "antigravity" },
98
+ { title: "OpenAI Codex", value: "codex" },
99
+ { title: "GitHub Copilot", value: "github-copilot" },
100
+ { title: "Other (custom path)", value: "other" },
93
101
  ],
94
102
  initial: 0,
95
103
  });
96
104
  if (!response.client) {
97
- console.log('\nSetup cancelled.');
105
+ console.log("\nSetup cancelled.");
98
106
  return;
99
107
  }
100
108
  switch (response.client) {
101
- case 'claude-code':
109
+ case "claude-code":
102
110
  await setupClaudeCode();
103
111
  break;
104
- case 'claude-desktop':
112
+ case "claude-desktop":
105
113
  await setupClaudeDesktop();
106
114
  break;
107
- case 'cursor':
115
+ case "cursor":
108
116
  await setupCursor();
109
117
  break;
110
- case 'antigravity':
118
+ case "antigravity":
111
119
  await setupAntigravity();
112
120
  break;
113
- case 'codex':
121
+ case "codex":
114
122
  await setupCodex();
115
123
  break;
116
- case 'github-copilot':
124
+ case "github-copilot":
117
125
  await setupGitHubCopilot();
118
126
  break;
119
- case 'other':
127
+ case "other":
120
128
  await setupOther();
121
129
  break;
122
130
  default:
123
131
  console.log(`\n❌ ${response.client} is not yet supported.`);
124
- console.log('Please refer to the documentation for manual setup.');
132
+ console.log("Please refer to the documentation for manual setup.");
125
133
  }
126
134
  }
127
135
  async function setupClaudeCode() {
128
- console.log('\n📦 Configuring MCP for Claude Code...\n');
136
+ console.log("\n📦 Configuring MCP for Claude Code...\n");
129
137
  const command = `claude mcp add-json dotrequirements '{"type":"stdio","command":"npx","args":["-y","@popoverai/dotrequirements","mcp"]}'`;
130
138
  let mcpConfigured = false;
131
139
  try {
132
- execSync(command, { stdio: 'pipe' });
133
- console.log('✅ MCP configured successfully for Claude Code!');
140
+ execSync(command, { stdio: "pipe" });
141
+ console.log("✅ MCP configured successfully for Claude Code!");
134
142
  mcpConfigured = true;
135
143
  }
136
144
  catch (error) {
137
- const stderr = error.stderr?.toString() || '';
138
- const errorMessage = error.message || '';
145
+ const execError = error;
146
+ const stderr = execError.stderr?.toString() || "";
147
+ const errorMessage = execError.message || "";
139
148
  const combinedError = stderr + errorMessage;
140
- if (combinedError.includes('already exists')) {
141
- console.log('✅ MCP server already configured for Claude Code');
149
+ if (combinedError.includes("already exists")) {
150
+ console.log("✅ MCP server already configured for Claude Code");
142
151
  mcpConfigured = true;
143
152
  }
144
153
  else {
145
- console.error('❌ Failed to configure MCP automatically.');
146
- console.log('\nYou can manually run:');
154
+ console.error("❌ Failed to configure MCP automatically.");
155
+ console.log("\nYou can manually run:");
147
156
  console.log(` ${command}`);
148
157
  if (stderr) {
149
158
  console.log(`\nError: ${stderr}`);
@@ -151,75 +160,75 @@ async function setupClaudeCode() {
151
160
  }
152
161
  }
153
162
  if (mcpConfigured) {
154
- console.log('\n⚠️ Important: Restart Claude Code for changes to take effect.');
155
- console.log('\nYou can now ask your AI assistant to help write requirements!\n');
156
- await installContextFileSection('claude-code');
163
+ console.log("\n⚠️ Important: Restart Claude Code for changes to take effect.");
164
+ console.log("\nYou can now ask your AI assistant to help write requirements!\n");
165
+ await installContextFileSection("claude-code");
157
166
  }
158
167
  }
159
168
  async function setupClaudeDesktop() {
160
- console.log('\n📦 Configuring MCP for Claude Desktop...\n');
169
+ console.log("\n📦 Configuring MCP for Claude Desktop...\n");
161
170
  // Determine config path based on OS
162
171
  const platform = process.platform;
163
172
  let configPath;
164
173
  let configDir;
165
- if (platform === 'darwin') {
166
- configDir = join(homedir(), 'Library', 'Application Support', 'Claude');
167
- configPath = join(configDir, 'claude_desktop_config.json');
174
+ if (platform === "darwin") {
175
+ configDir = join(homedir(), "Library", "Application Support", "Claude");
176
+ configPath = join(configDir, "claude_desktop_config.json");
168
177
  }
169
- else if (platform === 'win32') {
170
- const appData = process.env.APPDATA || join(homedir(), 'AppData', 'Roaming');
171
- configDir = join(appData, 'Claude');
172
- configPath = join(configDir, 'claude_desktop_config.json');
178
+ else if (platform === "win32") {
179
+ const appData = process.env.APPDATA || join(homedir(), "AppData", "Roaming");
180
+ configDir = join(appData, "Claude");
181
+ configPath = join(configDir, "claude_desktop_config.json");
173
182
  }
174
183
  else {
175
- console.error('❌ Claude Desktop is only supported on macOS and Windows.');
176
- console.log('\nFor Linux, please manually configure the MCP server.');
184
+ console.error("❌ Claude Desktop is only supported on macOS and Windows.");
185
+ console.log("\nFor Linux, please manually configure the MCP server.");
177
186
  return;
178
187
  }
179
188
  const mcpServerConfig = {
180
- command: 'npx',
181
- args: ['-y', '@popoverai/dotrequirements', 'mcp'],
189
+ command: "npx",
190
+ args: ["-y", "@popoverai/dotrequirements", "mcp"],
182
191
  env: {
183
192
  REQUIREMENTS_DIR: process.cwd(),
184
193
  },
185
194
  };
186
195
  try {
187
196
  if (!existsSync(configDir)) {
188
- console.log('Creating Claude Desktop config directory...');
197
+ console.log("Creating Claude Desktop config directory...");
189
198
  mkdirSync(configDir, { recursive: true });
190
199
  }
191
200
  let config = {};
192
201
  if (existsSync(configPath)) {
193
202
  try {
194
- const existingContent = readFileSync(configPath, 'utf-8');
203
+ const existingContent = readFileSync(configPath, "utf-8");
195
204
  if (existingContent.trim()) {
196
205
  config = JSON.parse(existingContent);
197
206
  }
198
207
  }
199
208
  catch (parseError) {
200
- console.log('⚠️ Existing config file is invalid, creating fresh config...');
209
+ console.log("⚠️ Existing config file is invalid, creating fresh config...");
201
210
  config = {};
202
211
  }
203
212
  }
204
213
  if (!config.mcpServers) {
205
214
  config.mcpServers = {};
206
215
  }
207
- config.mcpServers['dotrequirements'] = mcpServerConfig;
208
- writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
216
+ config.mcpServers.dotrequirements = mcpServerConfig;
217
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
209
218
  console.log(`✅ MCP configured successfully!`);
210
219
  console.log(` Config file: ${configPath}`);
211
220
  console.log(` REQUIREMENTS_DIR: ${process.cwd()}\n`);
212
- console.log('⚠️ Important: Quit and restart Claude Desktop for changes to take effect.');
213
- console.log(' (Cmd+Q on macOS, not just close the window)\n');
214
- console.log('You can now ask Claude Desktop to help write requirements!\n');
221
+ console.log("⚠️ Important: Quit and restart Claude Desktop for changes to take effect.");
222
+ console.log(" (Cmd+Q on macOS, not just close the window)\n");
223
+ console.log("You can now ask Claude Desktop to help write requirements!\n");
215
224
  // Claude Desktop doesn't use skills like Claude Code, so we skip that step
216
225
  }
217
226
  catch (error) {
218
- console.error('❌ Failed to configure MCP automatically.');
227
+ console.error("❌ Failed to configure MCP automatically.");
219
228
  console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
220
- console.log('\nYou can manually edit the config file at:');
229
+ console.log("\nYou can manually edit the config file at:");
221
230
  console.log(` ${configPath}\n`);
222
- console.log('Add the following configuration:');
231
+ console.log("Add the following configuration:");
223
232
  const manualConfig = {
224
233
  mcpServers: {
225
234
  dotrequirements: mcpServerConfig,
@@ -229,48 +238,48 @@ async function setupClaudeDesktop() {
229
238
  }
230
239
  }
231
240
  async function setupCursor() {
232
- console.log('\n📦 Configuring MCP for Cursor (project-specific)...\n');
233
- const configPath = join(process.cwd(), '.cursor', 'mcp.json');
234
- const configDir = join(process.cwd(), '.cursor');
241
+ console.log("\n📦 Configuring MCP for Cursor (project-specific)...\n");
242
+ const configPath = join(process.cwd(), ".cursor", "mcp.json");
243
+ const configDir = join(process.cwd(), ".cursor");
235
244
  const mcpServerConfig = {
236
- command: 'npx',
237
- args: ['-y', '@popoverai/dotrequirements', 'mcp'],
245
+ command: "npx",
246
+ args: ["-y", "@popoverai/dotrequirements", "mcp"],
238
247
  };
239
248
  try {
240
249
  if (!existsSync(configDir)) {
241
- console.log('Creating Cursor config directory...');
250
+ console.log("Creating Cursor config directory...");
242
251
  mkdirSync(configDir, { recursive: true });
243
252
  }
244
253
  let config = {};
245
254
  if (existsSync(configPath)) {
246
255
  try {
247
- const existingContent = readFileSync(configPath, 'utf-8');
256
+ const existingContent = readFileSync(configPath, "utf-8");
248
257
  if (existingContent.trim()) {
249
258
  config = JSON.parse(existingContent);
250
259
  }
251
260
  }
252
261
  catch (parseError) {
253
- console.log('⚠️ Existing config file is invalid, creating fresh config...');
262
+ console.log("⚠️ Existing config file is invalid, creating fresh config...");
254
263
  config = {};
255
264
  }
256
265
  }
257
266
  if (!config.mcpServers) {
258
267
  config.mcpServers = {};
259
268
  }
260
- config.mcpServers['dotrequirements'] = mcpServerConfig;
261
- writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
269
+ config.mcpServers.dotrequirements = mcpServerConfig;
270
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
262
271
  console.log(`✅ MCP configured successfully!`);
263
272
  console.log(` Config file: ${configPath}\n`);
264
- console.log('⚠️ Important: Reload or restart Cursor for changes to take effect.');
265
- console.log('\nYou can now ask your AI assistant to help write requirements!\n');
266
- await installContextFileSection('cursor');
273
+ console.log("⚠️ Important: Reload or restart Cursor for changes to take effect.");
274
+ console.log("\nYou can now ask your AI assistant to help write requirements!\n");
275
+ await installContextFileSection("cursor");
267
276
  }
268
277
  catch (error) {
269
- console.error('❌ Failed to configure MCP automatically.');
278
+ console.error("❌ Failed to configure MCP automatically.");
270
279
  console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
271
- console.log('\nYou can manually edit the config file at:');
280
+ console.log("\nYou can manually edit the config file at:");
272
281
  console.log(` ${configPath}\n`);
273
- console.log('Add the following configuration:');
282
+ console.log("Add the following configuration:");
274
283
  const manualConfig = {
275
284
  mcpServers: {
276
285
  dotrequirements: mcpServerConfig,
@@ -280,21 +289,21 @@ async function setupCursor() {
280
289
  }
281
290
  }
282
291
  async function setupAntigravity() {
283
- console.log('\n📦 Configuring MCP for Google Antigravity...\n');
284
- const configPath = join(homedir(), '.gemini', 'antigravity', 'mcp_config.json');
285
- const configDir = join(homedir(), '.gemini', 'antigravity');
292
+ console.log("\n📦 Configuring MCP for Google Antigravity...\n");
293
+ const configPath = join(homedir(), ".gemini", "antigravity", "mcp_config.json");
294
+ const configDir = join(homedir(), ".gemini", "antigravity");
286
295
  // Check if we're in a dotrequirements project directory
287
- const envLocalPath = join(process.cwd(), '.env.local');
296
+ const envLocalPath = join(process.cwd(), ".env.local");
288
297
  let projectId = null;
289
298
  let projectPath = null;
290
299
  if (existsSync(envLocalPath)) {
291
300
  try {
292
- const envContent = readFileSync(envLocalPath, 'utf-8');
293
- const lines = envContent.split('\n');
301
+ const envContent = readFileSync(envLocalPath, "utf-8");
302
+ const lines = envContent.split("\n");
294
303
  for (const line of lines) {
295
304
  const trimmed = line.trim();
296
- if (trimmed.startsWith('DOTREQUIREMENTS_PROJECT_ID=')) {
297
- projectId = trimmed.split('=')[1]?.trim().replace(/['"]/g, '');
305
+ if (trimmed.startsWith("DOTREQUIREMENTS_PROJECT_ID=")) {
306
+ projectId = trimmed.split("=")[1]?.trim().replace(/['"]/g, "");
298
307
  projectPath = process.cwd();
299
308
  break;
300
309
  }
@@ -306,33 +315,34 @@ async function setupAntigravity() {
306
315
  }
307
316
  try {
308
317
  if (!existsSync(configDir)) {
309
- console.log('Creating Antigravity config directory...');
318
+ console.log("Creating Antigravity config directory...");
310
319
  mkdirSync(configDir, { recursive: true });
311
320
  }
312
321
  let config = {};
313
322
  if (existsSync(configPath)) {
314
323
  try {
315
- const existingContent = readFileSync(configPath, 'utf-8');
324
+ const existingContent = readFileSync(configPath, "utf-8");
316
325
  if (existingContent.trim()) {
317
326
  config = JSON.parse(existingContent);
318
327
  }
319
328
  }
320
329
  catch (parseError) {
321
- console.log('⚠️ Existing config file is invalid, creating fresh config...');
330
+ console.log("⚠️ Existing config file is invalid, creating fresh config...");
322
331
  config = {};
323
332
  }
324
333
  }
325
334
  if (!config.mcpServers) {
326
335
  config.mcpServers = {};
327
336
  }
328
- if (!config.mcpServers['dotrequirements']) {
329
- config.mcpServers['dotrequirements'] = {
330
- command: 'npx',
331
- args: ['-y', '@popoverai/dotrequirements', 'mcp'],
337
+ if (!config.mcpServers.dotrequirements) {
338
+ config.mcpServers.dotrequirements = {
339
+ command: "npx",
340
+ args: ["-y", "@popoverai/dotrequirements", "mcp"],
332
341
  env: {},
333
342
  };
334
343
  }
335
- const dotreqServer = config.mcpServers['dotrequirements'];
344
+ // biome-ignore lint/suspicious/noExplicitAny: `config` is parsed JSON from a user-owned MCP config file; its shape isn't ours to type fully. We only need the `env` bag, which we narrow ad-hoc here.
345
+ const dotreqServer = config.mcpServers.dotrequirements;
336
346
  if (!dotreqServer.env) {
337
347
  dotreqServer.env = {};
338
348
  }
@@ -344,86 +354,86 @@ async function setupAntigravity() {
344
354
  }
345
355
  else {
346
356
  console.log(`ℹ️ Not in a ${brand} project directory (no .env.local with DOTREQUIREMENTS_PROJECT_ID found)`);
347
- console.log(' Setting up global MCP server only.\n');
357
+ console.log(" Setting up global MCP server only.\n");
348
358
  }
349
- writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
359
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
350
360
  console.log(`✅ MCP configured successfully!`);
351
361
  console.log(` Config file: ${configPath}\n`);
352
- console.log('⚠️ Important: Reload or restart Google Antigravity for changes to take effect.');
353
- console.log('\nYou can now ask your AI assistant to help write requirements!');
362
+ console.log("⚠️ Important: Reload or restart Google Antigravity for changes to take effect.");
363
+ console.log("\nYou can now ask your AI assistant to help write requirements!");
354
364
  if (projectId) {
355
365
  console.log(`\n💡 To add more projects, run \`dotreq mcp-setup\` from each project directory.\n`);
356
366
  }
357
367
  else {
358
- console.log('');
368
+ console.log("");
359
369
  }
360
- await installContextFileSection('antigravity');
370
+ await installContextFileSection("antigravity");
361
371
  }
362
372
  catch (error) {
363
- console.error('❌ Failed to configure MCP automatically.');
373
+ console.error("❌ Failed to configure MCP automatically.");
364
374
  console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
365
- console.log('\nYou can manually edit the config file at:');
375
+ console.log("\nYou can manually edit the config file at:");
366
376
  console.log(` ${configPath}`);
367
377
  }
368
378
  }
369
379
  async function setupCodex() {
370
- console.log('\n📦 Configuring MCP for OpenAI Codex...\n');
380
+ console.log("\n📦 Configuring MCP for OpenAI Codex...\n");
371
381
  const command = `codex mcp add dotrequirements -- npx -y @popoverai/dotrequirements mcp`;
372
382
  try {
373
- execSync(command, { stdio: 'inherit' });
374
- console.log('\n✅ MCP configured successfully for Codex!');
375
- console.log('\n⚠️ Important: Restart Codex for changes to take effect.');
376
- console.log('\nYou can now ask your AI assistant to help write requirements!\n');
377
- await installContextFileSection('codex');
383
+ execSync(command, { stdio: "inherit" });
384
+ console.log("\n✅ MCP configured successfully for Codex!");
385
+ console.log("\n⚠️ Important: Restart Codex for changes to take effect.");
386
+ console.log("\nYou can now ask your AI assistant to help write requirements!\n");
387
+ await installContextFileSection("codex");
378
388
  }
379
389
  catch (error) {
380
- console.error('\n❌ Failed to configure MCP automatically.');
381
- console.log('\nYou can manually run:');
390
+ console.error("\n❌ Failed to configure MCP automatically.");
391
+ console.log("\nYou can manually run:");
382
392
  console.log(` ${command}`);
383
- console.log('\nOr manually edit ~/.codex/config.toml and add:');
384
- console.log('[mcp_servers.dotrequirements]');
393
+ console.log("\nOr manually edit ~/.codex/config.toml and add:");
394
+ console.log("[mcp_servers.dotrequirements]");
385
395
  console.log('command = "npx"');
386
396
  console.log('args = ["-y", "@popoverai/dotrequirements", "mcp"]');
387
397
  }
388
398
  }
389
399
  async function setupGitHubCopilot() {
390
- console.log('\n📦 Configuring skills for GitHub Copilot...\n');
391
- console.log('ℹ️ GitHub Copilot discovers MCP servers from your IDE configuration.');
392
- console.log(' Please configure the MCP server in VS Code settings or GitHub settings.\n');
393
- console.log(' MCP server command: npx -y @popoverai/dotrequirements mcp\n');
394
- await installContextFileSection('github-copilot');
400
+ console.log("\n📦 Configuring skills for GitHub Copilot...\n");
401
+ console.log("ℹ️ GitHub Copilot discovers MCP servers from your IDE configuration.");
402
+ console.log(" Please configure the MCP server in VS Code settings or GitHub settings.\n");
403
+ console.log(" MCP server command: npx -y @popoverai/dotrequirements mcp\n");
404
+ await installContextFileSection("github-copilot");
395
405
  }
396
406
  async function setupOther() {
397
- console.log('\n📦 Custom Context File Setup\n');
398
- console.log('ℹ️ Workflow guidance is added to a context file at your project root.');
399
- console.log(' Common file names by platform:');
400
- console.log(' - CLAUDE.md (Claude Code)');
401
- console.log(' - AGENTS.md (Cursor, Codex, GitHub Copilot)');
402
- console.log(' - GEMINI.md (Antigravity)\n');
407
+ console.log("\n📦 Custom Context File Setup\n");
408
+ console.log("ℹ️ Workflow guidance is added to a context file at your project root.");
409
+ console.log(" Common file names by platform:");
410
+ console.log(" - CLAUDE.md (Claude Code)");
411
+ console.log(" - AGENTS.md (Cursor, Codex, GitHub Copilot)");
412
+ console.log(" - GEMINI.md (Antigravity)\n");
403
413
  const response = await prompts({
404
- type: 'select',
405
- name: 'file',
406
- message: 'Which context file should we update?',
414
+ type: "select",
415
+ name: "file",
416
+ message: "Which context file should we update?",
407
417
  choices: [
408
- { title: 'AGENTS.md (most compatible)', value: 'AGENTS.md' },
409
- { title: 'CLAUDE.md', value: 'CLAUDE.md' },
410
- { title: 'GEMINI.md', value: 'GEMINI.md' },
418
+ { title: "AGENTS.md (most compatible)", value: "AGENTS.md" },
419
+ { title: "CLAUDE.md", value: "CLAUDE.md" },
420
+ { title: "GEMINI.md", value: "GEMINI.md" },
411
421
  ],
412
422
  initial: 0,
413
423
  });
414
424
  if (!response.file) {
415
- console.log('\nSetup cancelled.');
425
+ console.log("\nSetup cancelled.");
416
426
  return;
417
427
  }
418
- console.log('\n📝 MCP Server Setup\n');
419
- console.log('Configure your AI assistant to run the MCP server:');
420
- console.log(' Command: npx');
421
- console.log(' Args: -y @popoverai/dotrequirements mcp\n');
428
+ console.log("\n📝 MCP Server Setup\n");
429
+ console.log("Configure your AI assistant to run the MCP server:");
430
+ console.log(" Command: npx");
431
+ console.log(" Args: -y @popoverai/dotrequirements mcp\n");
422
432
  // Determine platform based on file choice for the install function
423
433
  const platformMap = {
424
- 'CLAUDE.md': 'claude-code',
425
- 'AGENTS.md': 'cursor', // Any AGENTS.md platform works
426
- 'GEMINI.md': 'antigravity',
434
+ "CLAUDE.md": "claude-code",
435
+ "AGENTS.md": "cursor", // Any AGENTS.md platform works
436
+ "GEMINI.md": "antigravity",
427
437
  };
428
438
  const platform = platformMap[response.file];
429
439
  await installContextFileSection(platform);
@@ -5,7 +5,7 @@
5
5
  export async function mcpCommand() {
6
6
  // Import and start the MCP server
7
7
  // The server handles stdio transport and runs until process termination
8
- const { main } = await import('../mcp/index.js');
8
+ const { main } = await import("../mcp/index.js");
9
9
  await main();
10
10
  }
11
11
  //# sourceMappingURL=mcp.js.map
@@ -1,4 +1,4 @@
1
- import { prepare } from '../harness/prepare.js';
1
+ import { prepare } from "../harness/prepare.js";
2
2
  export async function prepareCommand(options) {
3
3
  const result = prepare({
4
4
  cwd: process.cwd(),
@@ -12,9 +12,9 @@ export async function prepareCommand(options) {
12
12
  console.log(` - ${err.file}: ${err.error}`);
13
13
  }
14
14
  }
15
- console.log('\nCache written to .requirements/.cache/lookup.json');
16
- console.log('Tracking initialized at .requirements/.cache/tracking.jsonl');
17
- console.log('\nRun your tests, then run "dotrequirements finalize" to generate coverage report.');
15
+ console.log("\nCache written to .requirements/.cache/lookup.json");
16
+ console.log("Tracking initialized at .requirements/.cache/tracking.jsonl");
17
+ console.log('\nRun your tests, then run "dotrequirements harness finalize" to generate coverage report.');
18
18
  }
19
19
  }
20
20
  //# sourceMappingURL=prepare.js.map