@popoverai/dotrequirements 0.26.2 → 0.27.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 (56) hide show
  1. package/README.md +13 -69
  2. package/dist/cli.js +19 -7
  3. package/dist/commands/ai-setup.d.ts +8 -2
  4. package/dist/commands/ai-setup.js +153 -347
  5. package/dist/commands/create-requirement-document.js +2 -1
  6. package/dist/commands/init.js +1 -1
  7. package/dist/commands/mcp.d.ts +8 -2
  8. package/dist/commands/mcp.js +17 -6
  9. package/dist/commands/review-test.d.ts +5 -1
  10. package/dist/commands/review-test.js +101 -7
  11. package/dist/commands/style-check.d.ts +1 -0
  12. package/dist/commands/style-check.js +138 -13
  13. package/dist/convex.d.ts +1 -3
  14. package/dist/convex.js +3 -3
  15. package/dist/requirements/cloud-ai.d.ts +21 -8
  16. package/dist/requirements/cloud-ai.js +10 -8
  17. package/dist/requirements/style-guide-file.d.ts +21 -0
  18. package/dist/requirements/style-guide-file.js +30 -0
  19. package/dist/requirements/style-guide.d.ts +20 -22
  20. package/dist/requirements/style-guide.js +57 -35
  21. package/dist/schema/browser.d.ts +1 -1
  22. package/dist/schema/browser.js +4 -1
  23. package/dist/schema/parser-core.d.ts +28 -0
  24. package/dist/schema/parser-core.js +51 -12
  25. package/dist/templates/context-file-section.md +25 -22
  26. package/dist/utils/context-file.d.ts +7 -3
  27. package/dist/utils/context-file.js +10 -7
  28. package/dist/utils/project-settings.d.ts +1 -0
  29. package/dist/utils/project-settings.js +22 -0
  30. package/package.json +3 -4
  31. package/dist/mcp/convexClient.d.ts +0 -19
  32. package/dist/mcp/convexClient.js +0 -24
  33. package/dist/mcp/handlers/authoring.d.ts +0 -41
  34. package/dist/mcp/handlers/authoring.js +0 -113
  35. package/dist/mcp/handlers/debug.d.ts +0 -16
  36. package/dist/mcp/handlers/debug.js +0 -37
  37. package/dist/mcp/handlers/get.d.ts +0 -24
  38. package/dist/mcp/handlers/get.js +0 -69
  39. package/dist/mcp/handlers/index.d.ts +0 -28
  40. package/dist/mcp/handlers/index.js +0 -19
  41. package/dist/mcp/handlers/list.d.ts +0 -7
  42. package/dist/mcp/handlers/list.js +0 -43
  43. package/dist/mcp/handlers/push.d.ts +0 -26
  44. package/dist/mcp/handlers/push.js +0 -232
  45. package/dist/mcp/handlers/report.d.ts +0 -16
  46. package/dist/mcp/handlers/report.js +0 -134
  47. package/dist/mcp/handlers/review.d.ts +0 -52
  48. package/dist/mcp/handlers/review.js +0 -243
  49. package/dist/mcp/handlers/search.d.ts +0 -30
  50. package/dist/mcp/handlers/search.js +0 -58
  51. package/dist/mcp/handlers/test-mapping.d.ts +0 -39
  52. package/dist/mcp/handlers/test-mapping.js +0 -168
  53. package/dist/mcp/handlers/types.d.ts +0 -89
  54. package/dist/mcp/handlers/types.js +0 -52
  55. package/dist/mcp/index.d.ts +0 -45
  56. package/dist/mcp/index.js +0 -638
@@ -1,11 +1,10 @@
1
- import { execFileSync, execSync } from "node:child_process";
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import prompts from "prompts";
6
6
  import { brand } from "../utils/brand.js";
7
7
  import { appendOrUpdateSection, buildNoGitRepoMessage, findDotrequirementsSection, findGitRoot, getContextFileName, } from "../utils/context-file.js";
8
- import { findProjectRoot, readProjectSettings, } from "../utils/project-settings.js";
9
8
  import { loadTemplate } from "../utils/templates.js";
10
9
  /**
11
10
  * Load the context file section template
@@ -13,60 +12,10 @@ import { loadTemplate } from "../utils/templates.js";
13
12
  function loadContextFileSection() {
14
13
  return loadTemplate("context-file-section.md");
15
14
  }
16
- /**
17
- * Read an assistant's existing MCP config file (AISETUP-2).
18
- * Returns {} when the file is absent or empty. Returns null when the file
19
- * exists but is unusable — unreadable (AISETUP-2.2), invalid JSON
20
- * (AISETUP-2.1), or a non-object root (AISETUP-2.3). In every null case the
21
- * path has already been shown to the user and the caller must stop without
22
- * writing; rewriting would destroy every other configured server.
23
- */
24
- function readExistingMcpConfig(configPath) {
25
- const stopWithoutWriting = (reason) => {
26
- console.error(`❌ ${reason}`);
27
- console.log(" Nothing was changed. Fix (or remove) the file, then re-run ai-setup:");
28
- console.log(` ${configPath}\n`);
29
- return null;
30
- };
31
- if (!existsSync(configPath)) {
32
- return {};
33
- }
34
- let existingContent;
35
- try {
36
- existingContent = readFileSync(configPath, "utf-8");
37
- }
38
- catch {
39
- return stopWithoutWriting("Existing config file could not be read.");
40
- }
41
- if (!existingContent.trim()) {
42
- return {};
43
- }
44
- let parsed;
45
- try {
46
- parsed = JSON.parse(existingContent);
47
- }
48
- catch {
49
- return stopWithoutWriting("Existing config file contains invalid JSON.");
50
- }
51
- // AISETUP-2.3: a non-object root (e.g. a top-level array) would swallow the
52
- // mcpServers assignment and serialize back without it — success would be
53
- // reported while nothing was configured
54
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
55
- return stopWithoutWriting("Existing config file is not a JSON object.");
56
- }
57
- // AISETUP-2.3: same trap one level down — an array-valued mcpServers takes
58
- // the server entry as an expando property that JSON.stringify drops
59
- const mcpServers = parsed.mcpServers;
60
- if (mcpServers != null &&
61
- (typeof mcpServers !== "object" || Array.isArray(mcpServers))) {
62
- return stopWithoutWriting('Existing config file has an "mcpServers" field that is not a JSON object.');
63
- }
64
- return parsed;
65
- }
66
15
  /**
67
16
  * Install workflow guidance to the appropriate context file for a platform.
68
- * With `yes` (the non-interactive --assistant path, AISETUP-1.0), both
69
- * confirmations are auto-accepted — matching their interactive defaults.
17
+ * With `yes` (the non-interactive --assistant path, AISETUP-1.0), the
18
+ * confirmation is auto-accepted — matching its interactive default.
70
19
  */
71
20
  async function installContextFileSection(platform, yes = false) {
72
21
  const fileName = getContextFileName(platform);
@@ -133,28 +82,164 @@ async function installContextFileSection(platform, yes = false) {
133
82
  catch (error) {
134
83
  console.error(`❌ Failed to update ${fileName}`);
135
84
  console.log(` Error: ${error instanceof Error ? error.message : String(error)}\n`);
85
+ // AISETUP-3: writing the guidance is the whole of setup — a CI/agent
86
+ // caller must not see a failed write as success.
87
+ process.exitCode = 1;
88
+ }
89
+ }
90
+ /**
91
+ * Remove the dotrequirements entry from a JSON MCP config file an earlier
92
+ * ai-setup version wrote (Cursor's `.cursor/mcp.json`, Antigravity's
93
+ * `mcp_config.json`). Only our entry is deleted; every other configured
94
+ * server is preserved (AISETUP-2.2). Unusable files are skipped with their
95
+ * path shown (AISETUP-2.4); an absent file or a config with no dotrequirements
96
+ * entry is a silent no-op (AISETUP-2.3).
97
+ */
98
+ async function cleanupJsonMcpConfig(configPath, yes) {
99
+ if (!existsSync(configPath)) {
100
+ return; // AISETUP-2.3: nothing an earlier version left here
101
+ }
102
+ let raw;
103
+ try {
104
+ raw = readFileSync(configPath, "utf-8");
105
+ }
106
+ catch {
107
+ // AISETUP-2.4: unreadable (e.g. a directory) — skip, but keep going
108
+ console.log(`ℹ️ Skipped MCP cleanup: could not read ${configPath}`);
109
+ return;
110
+ }
111
+ if (!raw.trim()) {
112
+ return;
113
+ }
114
+ let parsed;
115
+ try {
116
+ parsed = JSON.parse(raw);
117
+ }
118
+ catch {
119
+ // AISETUP-2.4: invalid JSON — we won't guess at its structure
120
+ console.log(`ℹ️ Skipped MCP cleanup: invalid JSON in ${configPath}`);
121
+ return;
122
+ }
123
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
124
+ // AISETUP-2.4: a non-object root
125
+ console.log(`ℹ️ Skipped MCP cleanup: ${configPath} is not a JSON object`);
126
+ return;
127
+ }
128
+ const mcpServers = parsed.mcpServers;
129
+ if (mcpServers == null ||
130
+ typeof mcpServers !== "object" ||
131
+ Array.isArray(mcpServers)) {
132
+ return; // no usable server map → nothing of ours to remove
133
+ }
134
+ const servers = mcpServers;
135
+ if (!("dotrequirements" in servers)) {
136
+ return; // AISETUP-2.3: our entry isn't here
137
+ }
138
+ if (!yes) {
139
+ const { remove } = await prompts({
140
+ type: "confirm",
141
+ name: "remove",
142
+ message: `Remove the retired dotrequirements MCP server from ${configPath}?`,
143
+ initial: true,
144
+ });
145
+ if (!remove) {
146
+ return;
147
+ }
148
+ }
149
+ delete servers.dotrequirements;
150
+ writeFileSync(configPath, JSON.stringify(parsed, null, 2), "utf-8");
151
+ console.log(`✅ Removed the retired dotrequirements MCP server from ${configPath}`);
152
+ }
153
+ /**
154
+ * Remove the dotrequirements MCP server from a host that manages its own MCP
155
+ * config through a CLI (Claude Code, Codex). Detection via `<bin> mcp get`;
156
+ * removal via `<bin> mcp remove`. A missing entry — or a host CLI that isn't
157
+ * installed — is a silent no-op; the host CLI guarantees only our entry is
158
+ * touched (AISETUP-2.2).
159
+ */
160
+ async function cleanupHostCliMcp(bin, yes) {
161
+ let present = false;
162
+ try {
163
+ execFileSync(bin, ["mcp", "get", "dotrequirements"], { stdio: "pipe" });
164
+ present = true;
165
+ }
166
+ catch {
167
+ // Exit non-zero → not configured, or the host CLI isn't on PATH. Either
168
+ // way there is nothing for us to clean up (AISETUP-2.3).
169
+ return;
170
+ }
171
+ if (!present) {
172
+ return;
173
+ }
174
+ if (!yes) {
175
+ const { remove } = await prompts({
176
+ type: "confirm",
177
+ name: "remove",
178
+ message: `Remove the retired dotrequirements MCP server from ${bin}?`,
179
+ initial: true,
180
+ });
181
+ if (!remove) {
182
+ return;
183
+ }
184
+ }
185
+ try {
186
+ execFileSync(bin, ["mcp", "remove", "dotrequirements"], { stdio: "pipe" });
187
+ console.log(`✅ Removed the retired dotrequirements MCP server from ${bin}`);
188
+ }
189
+ catch {
190
+ console.log(`⚠️ Could not remove the dotrequirements MCP server automatically.\n` +
191
+ ` Remove it manually: ${bin} mcp remove dotrequirements`);
192
+ }
193
+ }
194
+ /**
195
+ * Clean up any MCP configuration an earlier ai-setup version wrote for this
196
+ * assistant. The local MCP server is retired (AISETUP-2.0: setup writes no MCP
197
+ * config); this leaves the entries prior versions created ready to remove.
198
+ */
199
+ async function cleanupStaleMcpConfig(platform, yes) {
200
+ switch (platform) {
201
+ case "claude-code":
202
+ await cleanupHostCliMcp("claude", yes);
203
+ return;
204
+ case "codex":
205
+ await cleanupHostCliMcp("codex", yes);
206
+ return;
207
+ case "cursor": {
208
+ const root = (await findGitRoot()) ?? process.cwd();
209
+ await cleanupJsonMcpConfig(join(root, ".cursor", "mcp.json"), yes);
210
+ return;
211
+ }
212
+ case "antigravity":
213
+ await cleanupJsonMcpConfig(join(homedir(), ".gemini", "antigravity", "mcp_config.json"), yes);
214
+ return;
215
+ // github-copilot never had ai-setup write MCP config — nothing to clean.
136
216
  }
137
217
  }
138
218
  /**
139
219
  * Assistant identifiers accepted by the non-interactive --assistant flag
140
220
  * (AISETUP-1). "other" is interactive-only: it prompts for a custom path.
221
+ *
222
+ * Claude Desktop was dropped: it consumed only the retired local MCP server
223
+ * (no terminal, no context file), so setup has nothing to install for it. Its
224
+ * path forward is the remote MCP connector.
141
225
  */
142
226
  export const SUPPORTED_ASSISTANTS = [
143
227
  "claude-code",
144
- "claude-desktop",
145
228
  "cursor",
146
229
  "antigravity",
147
230
  "codex",
148
231
  "github-copilot",
149
232
  ];
150
233
  /**
151
- * AI setup command - configures the MCP server for AI assistants
234
+ * AI setup command — installs the requirements-driven workflow guidance into
235
+ * the assistant's context file, and removes any MCP configuration an earlier
236
+ * version wrote (the local MCP server is retired).
152
237
  *
153
238
  * AISETUP-1: with --assistant <id>, setup runs without any interactive prompt
154
239
  * (an AI assistant configuring itself knows which assistant it is).
155
240
  */
156
241
  export async function aiSetupCommand(options = {}) {
157
- console.log(`🔧 Setting up ${brand} MCP server\n`);
242
+ console.log(`🔧 Setting up ${brand} workflow guidance\n`);
158
243
  if (options.assistant) {
159
244
  const id = options.assistant.toLowerCase();
160
245
  if (!SUPPORTED_ASSISTANTS.includes(id)) {
@@ -172,7 +257,6 @@ export async function aiSetupCommand(options = {}) {
172
257
  message: "Which AI assistant are you using?",
173
258
  choices: [
174
259
  { title: "Claude Code", value: "claude-code" },
175
- { title: "Claude Desktop", value: "claude-desktop" },
176
260
  { title: "Cursor", value: "cursor" },
177
261
  { title: "Google Antigravity", value: "antigravity" },
178
262
  { title: "OpenAI Codex", value: "codex" },
@@ -188,298 +272,26 @@ export async function aiSetupCommand(options = {}) {
188
272
  await dispatchSetup(response.client);
189
273
  }
190
274
  async function dispatchSetup(client, yes = false) {
191
- switch (client) {
192
- case "claude-code":
193
- await setupClaudeCode(yes);
194
- break;
195
- case "claude-desktop":
196
- await setupClaudeDesktop();
197
- break;
198
- case "cursor":
199
- await setupCursor(yes);
200
- break;
201
- case "antigravity":
202
- await setupAntigravity(yes);
203
- break;
204
- case "codex":
205
- await setupCodex(yes);
206
- break;
207
- case "github-copilot":
208
- await setupGitHubCopilot(yes);
209
- break;
210
- case "other":
211
- await setupOther();
212
- break;
213
- default:
214
- console.log(`\n❌ ${client} is not yet supported.`);
215
- console.log("Please refer to the documentation for manual setup.");
216
- }
217
- }
218
- async function setupClaudeCode(yes = false) {
219
- console.log("\n📦 Configuring MCP for Claude Code...\n");
220
- // Register via an args array so no shell quoting is involved: cmd.exe does
221
- // not honor single quotes, so a shell-quoted JSON string breaks on Windows.
222
- const mcpServerJson = JSON.stringify({
223
- type: "stdio",
224
- command: "npx",
225
- args: ["-y", "@popoverai/dotrequirements", "mcp"],
226
- });
227
- // Shell-safe on every platform (no quoting needed anywhere)
228
- const manualCommand = "claude mcp add dotrequirements -- npx -y @popoverai/dotrequirements mcp";
229
- let mcpConfigured = false;
230
- try {
231
- execFileSync("claude", ["mcp", "add-json", "dotrequirements", mcpServerJson], { stdio: "pipe" });
232
- console.log("✅ MCP configured successfully for Claude Code!");
233
- mcpConfigured = true;
234
- }
235
- catch (error) {
236
- const execError = error;
237
- const stderr = execError.stderr?.toString() || "";
238
- const errorMessage = execError.message || "";
239
- const combinedError = stderr + errorMessage;
240
- if (combinedError.includes("already exists")) {
241
- console.log("✅ MCP server already configured for Claude Code");
242
- mcpConfigured = true;
243
- }
244
- else {
245
- console.error("❌ Failed to configure MCP automatically.");
246
- console.log("\nYou can manually run:");
247
- console.log(` ${manualCommand}`);
248
- if (stderr) {
249
- console.log(`\nError: ${stderr}`);
250
- }
251
- }
252
- }
253
- if (mcpConfigured) {
254
- console.log("\n⚠️ Important: Restart Claude Code for changes to take effect.");
255
- console.log("\nYou can now ask your AI assistant to help write requirements!\n");
256
- await installContextFileSection("claude-code", yes);
257
- }
258
- }
259
- async function setupClaudeDesktop() {
260
- console.log("\n📦 Configuring MCP for Claude Desktop...\n");
261
- // Determine config path based on OS
262
- const platform = process.platform;
263
- let configPath;
264
- let configDir;
265
- if (platform === "darwin") {
266
- configDir = join(homedir(), "Library", "Application Support", "Claude");
267
- configPath = join(configDir, "claude_desktop_config.json");
268
- }
269
- else if (platform === "win32") {
270
- const appData = process.env.APPDATA || join(homedir(), "AppData", "Roaming");
271
- configDir = join(appData, "Claude");
272
- configPath = join(configDir, "claude_desktop_config.json");
273
- }
274
- else {
275
- console.error("❌ Claude Desktop is only supported on macOS and Windows.");
276
- console.log("\nFor Linux, please manually configure the MCP server.");
275
+ if (client === "other") {
276
+ await setupOther();
277
277
  return;
278
278
  }
279
- const mcpServerConfig = {
280
- command: "npx",
281
- args: ["-y", "@popoverai/dotrequirements", "mcp"],
282
- env: {
283
- REQUIREMENTS_DIR: process.cwd(),
284
- },
285
- };
286
- // AISETUP-2.1–2.3: bail out before touching anything if the config is unusable
287
- const config = readExistingMcpConfig(configPath);
288
- if (config === null) {
279
+ if (!SUPPORTED_ASSISTANTS.includes(client)) {
280
+ console.log(`\n❌ ${client} is not yet supported.`);
281
+ console.log("Please refer to the documentation for manual setup.");
289
282
  return;
290
283
  }
291
- try {
292
- if (!existsSync(configDir)) {
293
- console.log("Creating Claude Desktop config directory...");
294
- mkdirSync(configDir, { recursive: true });
295
- }
296
- // AISETUP-2.0: other configured servers survive; only ours is (re)set
297
- if (!config.mcpServers) {
298
- config.mcpServers = {};
299
- }
300
- config.mcpServers.dotrequirements = mcpServerConfig;
301
- writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
302
- console.log(`✅ MCP configured successfully!`);
303
- console.log(` Config file: ${configPath}`);
304
- console.log(` REQUIREMENTS_DIR: ${process.cwd()}\n`);
305
- console.log("⚠️ Important: Quit and restart Claude Desktop for changes to take effect.");
306
- console.log(" (Cmd+Q on macOS, not just close the window)\n");
307
- console.log("You can now ask Claude Desktop to help write requirements!\n");
308
- // Claude Desktop doesn't use skills like Claude Code, so we skip that step
309
- }
310
- catch (error) {
311
- console.error("❌ Failed to configure MCP automatically.");
312
- console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
313
- console.log("\nYou can manually edit the config file at:");
314
- console.log(` ${configPath}\n`);
315
- console.log("Add the following configuration:");
316
- const manualConfig = {
317
- mcpServers: {
318
- dotrequirements: mcpServerConfig,
319
- },
320
- };
321
- console.log(JSON.stringify(manualConfig, null, 2));
322
- }
323
- }
324
- async function setupCursor(yes = false) {
325
- console.log("\n📦 Configuring MCP for Cursor (project-specific)...\n");
326
- // Cursor loads .cursor/mcp.json from the project (git) root — match the
327
- // context-file placement, falling back to cwd outside a repository
328
- const projectDir = (await findGitRoot()) ?? process.cwd();
329
- const configDir = join(projectDir, ".cursor");
330
- const configPath = join(configDir, "mcp.json");
331
- const mcpServerConfig = {
332
- command: "npx",
333
- args: ["-y", "@popoverai/dotrequirements", "mcp"],
334
- };
335
- // AISETUP-2.1–2.3: bail out before touching anything if the config is unusable
336
- const config = readExistingMcpConfig(configPath);
337
- if (config === null) {
338
- return;
339
- }
340
- try {
341
- if (!existsSync(configDir)) {
342
- console.log("Creating Cursor config directory...");
343
- mkdirSync(configDir, { recursive: true });
344
- }
345
- // AISETUP-2.0: other configured servers survive; only ours is (re)set
346
- if (!config.mcpServers) {
347
- config.mcpServers = {};
348
- }
349
- config.mcpServers.dotrequirements = mcpServerConfig;
350
- writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
351
- console.log(`✅ MCP configured successfully!`);
352
- console.log(` Config file: ${configPath}\n`);
353
- console.log("⚠️ Important: Reload or restart Cursor for changes to take effect.");
354
- console.log("\nYou can now ask your AI assistant to help write requirements!\n");
355
- await installContextFileSection("cursor", yes);
356
- }
357
- catch (error) {
358
- console.error("❌ Failed to configure MCP automatically.");
359
- console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
360
- console.log("\nYou can manually edit the config file at:");
361
- console.log(` ${configPath}\n`);
362
- console.log("Add the following configuration:");
363
- const manualConfig = {
364
- mcpServers: {
365
- dotrequirements: mcpServerConfig,
366
- },
367
- };
368
- console.log(JSON.stringify(manualConfig, null, 2));
369
- }
370
- }
371
- async function setupAntigravity(yes = false) {
372
- console.log("\n📦 Configuring MCP for Google Antigravity...\n");
373
- const configPath = join(homedir(), ".gemini", "antigravity", "mcp_config.json");
374
- const configDir = join(homedir(), ".gemini", "antigravity");
375
- // AISETUP-3.0: detect the project the way the CLI defines projects —
376
- // .requirements/project-settings.json at the project root
377
- let projectId = null;
378
- let projectPath = null;
379
- const projectRoot = findProjectRoot();
380
- if (projectRoot) {
381
- try {
382
- const settings = readProjectSettings(projectRoot);
383
- if (settings) {
384
- projectId = settings.projectId;
385
- projectPath = projectRoot;
386
- }
387
- }
388
- catch {
389
- // Settings file unreadable/invalid — continue with global setup
390
- }
391
- }
392
- // AISETUP-2.1–2.3: bail out before touching anything if the config is unusable
393
- const config = readExistingMcpConfig(configPath);
394
- if (config === null) {
395
- return;
396
- }
397
- try {
398
- if (!existsSync(configDir)) {
399
- console.log("Creating Antigravity config directory...");
400
- mkdirSync(configDir, { recursive: true });
401
- }
402
- if (!config.mcpServers) {
403
- config.mcpServers = {};
404
- }
405
- if (!config.mcpServers.dotrequirements) {
406
- config.mcpServers.dotrequirements = {
407
- command: "npx",
408
- args: ["-y", "@popoverai/dotrequirements", "mcp"],
409
- env: {},
410
- };
411
- }
412
- // 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.
413
- const dotreqServer = config.mcpServers.dotrequirements;
414
- if (!dotreqServer.env) {
415
- dotreqServer.env = {};
416
- }
417
- if (projectId && projectPath) {
418
- const envKey = `PROJ_${projectId}`;
419
- dotreqServer.env[envKey] = projectPath;
420
- console.log(`✅ Added project to MCP config: ${envKey}`);
421
- console.log(` Path: ${projectPath}\n`);
422
- }
423
- else {
424
- // AISETUP-3.1: outside any initialized project — skip the per-project
425
- // step and say so
426
- console.log("ℹ️ No project found (no .requirements/project-settings.json in this directory or its parents)");
427
- console.log(" Setting up global MCP server only.\n");
428
- }
429
- writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
430
- console.log(`✅ MCP configured successfully!`);
431
- console.log(` Config file: ${configPath}\n`);
432
- console.log("⚠️ Important: Reload or restart Google Antigravity for changes to take effect.");
433
- console.log("\nYou can now ask your AI assistant to help write requirements!");
434
- if (projectId) {
435
- console.log(`\n💡 To add more projects, run \`dotreq ai-setup\` from each project directory.\n`);
436
- }
437
- else {
438
- console.log("");
439
- }
440
- await installContextFileSection("antigravity", yes);
441
- }
442
- catch (error) {
443
- console.error("❌ Failed to configure MCP automatically.");
444
- console.log(`\nError: ${error instanceof Error ? error.message : String(error)}`);
445
- console.log("\nYou can manually edit the config file at:");
446
- console.log(` ${configPath}`);
447
- }
448
- }
449
- async function setupCodex(yes = false) {
450
- console.log("\n📦 Configuring MCP for OpenAI Codex...\n");
451
- const command = `codex mcp add dotrequirements -- npx -y @popoverai/dotrequirements mcp`;
452
- try {
453
- execSync(command, { stdio: "inherit" });
454
- console.log("\n✅ MCP configured successfully for Codex!");
455
- console.log("\n⚠️ Important: Restart Codex for changes to take effect.");
456
- console.log("\nYou can now ask your AI assistant to help write requirements!\n");
457
- await installContextFileSection("codex", yes);
458
- }
459
- catch {
460
- console.error("\n❌ Failed to configure MCP automatically.");
461
- console.log("\nYou can manually run:");
462
- console.log(` ${command}`);
463
- console.log("\nOr manually edit ~/.codex/config.toml and add:");
464
- console.log("[mcp_servers.dotrequirements]");
465
- console.log('command = "npx"');
466
- console.log('args = ["-y", "@popoverai/dotrequirements", "mcp"]');
467
- }
468
- }
469
- async function setupGitHubCopilot(yes = false) {
470
- console.log("\n📦 Configuring skills for GitHub Copilot...\n");
471
- console.log("ℹ️ GitHub Copilot discovers MCP servers from your IDE configuration.");
472
- console.log(" Please configure the MCP server in VS Code settings or GitHub settings.\n");
473
- console.log(" MCP server command: npx -y @popoverai/dotrequirements mcp\n");
474
- await installContextFileSection("github-copilot", yes);
284
+ // AISETUP-2: remove any MCP config an earlier version wrote, then install
285
+ // the workflow guidance (the whole of setup now).
286
+ await cleanupStaleMcpConfig(client, yes);
287
+ await installContextFileSection(client, yes);
475
288
  }
476
289
  async function setupOther() {
477
290
  console.log("\n📦 Custom Context File Setup\n");
478
291
  console.log("ℹ️ Workflow guidance is added to a context file at your project root.");
479
292
  console.log(" Common file names by platform:");
480
293
  console.log(" - CLAUDE.md (Claude Code)");
481
- console.log(" - AGENTS.md (Cursor, Codex, GitHub Copilot)");
482
- console.log(" - GEMINI.md (Antigravity)\n");
294
+ console.log(" - AGENTS.md (Cursor, Codex, Antigravity, GitHub Copilot)\n");
483
295
  const response = await prompts({
484
296
  type: "select",
485
297
  name: "file",
@@ -487,7 +299,6 @@ async function setupOther() {
487
299
  choices: [
488
300
  { title: "AGENTS.md (most compatible)", value: "AGENTS.md" },
489
301
  { title: "CLAUDE.md", value: "CLAUDE.md" },
490
- { title: "GEMINI.md", value: "GEMINI.md" },
491
302
  ],
492
303
  initial: 0,
493
304
  });
@@ -495,15 +306,10 @@ async function setupOther() {
495
306
  console.log("\nSetup cancelled.");
496
307
  return;
497
308
  }
498
- console.log("\n📝 MCP Server Setup\n");
499
- console.log("Configure your AI assistant to run the MCP server:");
500
- console.log(" Command: npx");
501
- console.log(" Args: -y @popoverai/dotrequirements mcp\n");
502
309
  // Determine platform based on file choice for the install function
503
310
  const platformMap = {
504
311
  "CLAUDE.md": "claude-code",
505
312
  "AGENTS.md": "cursor", // Any AGENTS.md platform works
506
- "GEMINI.md": "antigravity",
507
313
  };
508
314
  const platform = platformMap[response.file];
509
315
  await installContextFileSection(platform);
@@ -1,6 +1,7 @@
1
1
  import { getProjectContext } from "../requirements/cloud-ai.js";
2
2
  import { loadAllRequirements } from "../requirements/index.js";
3
- import { generateStyleGuide, readLocalStyleGuide, } from "../requirements/style-guide.js";
3
+ import { generateStyleGuide } from "../requirements/style-guide.js";
4
+ import { readLocalStyleGuide } from "../requirements/style-guide-file.js";
4
5
  import { findProjectRoot, getProjectCredentials, } from "../utils/project-settings.js";
5
6
  const CONVEX_URL = "https://data.dotrequirements.io";
6
7
  export async function createRequirementDocumentCommand(filePath) {
@@ -351,7 +351,7 @@ async function inviteFlow(cwd, token) {
351
351
  // MEMBERSHIP-18.1: Accept invite (joins team, marks token used)
352
352
  // MEMBERSHIP-18.2: If already a member, continue gracefully
353
353
  try {
354
- await client.action(api.polar.acceptTeamInvite, { token });
354
+ await client.mutation(api.teamInvites.mutations.acceptInvite, { token });
355
355
  console.log(`✓ Joined team "${inviteInfo.teamName}"`);
356
356
  }
357
357
  catch (err) {
@@ -1,6 +1,12 @@
1
1
  /**
2
- * MCP command - starts the Model Context Protocol server
3
- * This allows AI assistants to query requirements data
2
+ * MCP command — retired stub.
3
+ *
4
+ * The local stdio MCP server was retired with the MCP surface migration:
5
+ * coding agents use the CLI verbs directly (discovered via the workflow
6
+ * guidance ai-setup installs), and conversational agents use the remote
7
+ * dotrequirements connector. Configured assistants still invoking
8
+ * `npx @popoverai/dotrequirements mcp` land here, so this failure explains
9
+ * itself at the moment someone investigates.
4
10
  */
5
11
  export declare function mcpCommand(): Promise<void>;
6
12
  //# sourceMappingURL=mcp.d.ts.map
@@ -1,11 +1,22 @@
1
1
  /**
2
- * MCP command - starts the Model Context Protocol server
3
- * This allows AI assistants to query requirements data
2
+ * MCP command — retired stub.
3
+ *
4
+ * The local stdio MCP server was retired with the MCP surface migration:
5
+ * coding agents use the CLI verbs directly (discovered via the workflow
6
+ * guidance ai-setup installs), and conversational agents use the remote
7
+ * dotrequirements connector. Configured assistants still invoking
8
+ * `npx @popoverai/dotrequirements mcp` land here, so this failure explains
9
+ * itself at the moment someone investigates.
4
10
  */
5
11
  export async function mcpCommand() {
6
- // Import and start the MCP server
7
- // The server handles stdio transport and runs until process termination
8
- const { main } = await import("../mcp/index.js");
9
- await main();
12
+ throw new Error([
13
+ "The local MCP server was retired — coding agents now use the dotrequirements CLI directly.",
14
+ "",
15
+ "To update this machine's configuration:",
16
+ " dotreq ai-setup",
17
+ "",
18
+ "It removes stale MCP registrations and installs the current workflow guidance.",
19
+ "For chat apps (Claude, ChatGPT), use the dot•requirements remote connector instead.",
20
+ ].join("\n"));
10
21
  }
11
22
  //# sourceMappingURL=mcp.js.map
@@ -1,2 +1,6 @@
1
- export declare function reviewTestCommand(testFilePath: string): Promise<void>;
1
+ interface ReviewTestOptions {
2
+ source?: string;
3
+ }
4
+ export declare function reviewTestCommand(testFilePath: string, options?: ReviewTestOptions): Promise<void>;
5
+ export {};
2
6
  //# sourceMappingURL=review-test.d.ts.map