@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.
- package/README.md +13 -69
- package/dist/cli.js +19 -7
- package/dist/commands/ai-setup.d.ts +8 -2
- package/dist/commands/ai-setup.js +153 -347
- package/dist/commands/create-requirement-document.js +2 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/mcp.d.ts +8 -2
- package/dist/commands/mcp.js +17 -6
- package/dist/commands/review-test.d.ts +5 -1
- package/dist/commands/review-test.js +101 -7
- package/dist/commands/style-check.d.ts +1 -0
- package/dist/commands/style-check.js +138 -13
- package/dist/convex.d.ts +1 -3
- package/dist/convex.js +3 -3
- package/dist/requirements/cloud-ai.d.ts +21 -8
- package/dist/requirements/cloud-ai.js +10 -8
- package/dist/requirements/style-guide-file.d.ts +21 -0
- package/dist/requirements/style-guide-file.js +30 -0
- package/dist/requirements/style-guide.d.ts +20 -22
- package/dist/requirements/style-guide.js +57 -35
- package/dist/schema/browser.d.ts +1 -1
- package/dist/schema/browser.js +4 -1
- package/dist/schema/parser-core.d.ts +28 -0
- package/dist/schema/parser-core.js +51 -12
- package/dist/templates/context-file-section.md +25 -22
- package/dist/utils/context-file.d.ts +7 -3
- package/dist/utils/context-file.js +10 -7
- package/dist/utils/project-settings.d.ts +1 -0
- package/dist/utils/project-settings.js +22 -0
- package/package.json +3 -4
- package/dist/mcp/convexClient.d.ts +0 -19
- package/dist/mcp/convexClient.js +0 -24
- package/dist/mcp/handlers/authoring.d.ts +0 -41
- package/dist/mcp/handlers/authoring.js +0 -113
- package/dist/mcp/handlers/debug.d.ts +0 -16
- package/dist/mcp/handlers/debug.js +0 -37
- package/dist/mcp/handlers/get.d.ts +0 -24
- package/dist/mcp/handlers/get.js +0 -69
- package/dist/mcp/handlers/index.d.ts +0 -28
- package/dist/mcp/handlers/index.js +0 -19
- package/dist/mcp/handlers/list.d.ts +0 -7
- package/dist/mcp/handlers/list.js +0 -43
- package/dist/mcp/handlers/push.d.ts +0 -26
- package/dist/mcp/handlers/push.js +0 -232
- package/dist/mcp/handlers/report.d.ts +0 -16
- package/dist/mcp/handlers/report.js +0 -134
- package/dist/mcp/handlers/review.d.ts +0 -52
- package/dist/mcp/handlers/review.js +0 -243
- package/dist/mcp/handlers/search.d.ts +0 -30
- package/dist/mcp/handlers/search.js +0 -58
- package/dist/mcp/handlers/test-mapping.d.ts +0 -39
- package/dist/mcp/handlers/test-mapping.js +0 -168
- package/dist/mcp/handlers/types.d.ts +0 -89
- package/dist/mcp/handlers/types.js +0 -52
- package/dist/mcp/index.d.ts +0 -45
- package/dist/mcp/index.js +0 -638
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { execFileSync
|
|
2
|
-
import { existsSync,
|
|
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),
|
|
69
|
-
*
|
|
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
|
|
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}
|
|
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
|
-
|
|
192
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
|
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) {
|
package/dist/commands/init.js
CHANGED
|
@@ -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.
|
|
354
|
+
await client.mutation(api.teamInvites.mutations.acceptInvite, { token });
|
|
355
355
|
console.log(`✓ Joined team "${inviteInfo.teamName}"`);
|
|
356
356
|
}
|
|
357
357
|
catch (err) {
|
package/dist/commands/mcp.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP command
|
|
3
|
-
*
|
|
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
|
package/dist/commands/mcp.js
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP command
|
|
3
|
-
*
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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
|