@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
package/dist/mcp/index.js DELETED
@@ -1,638 +0,0 @@
1
- #!/usr/bin/env node
2
- import { readFileSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
6
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
- import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
8
- import { loadAllRequirements, } from "../requirements/index.js";
9
- import { discoverProjects, resolveProject, } from "../utils/project-discovery.js";
10
- import { getCredentialsFromEnv } from "../utils/project-settings.js";
11
- import { handleCreateRequirementDocument, handleDebugMcpEnvironment, handleGetRequirement, handleGetRequirementsByTest, handleGetTestsByRequirement, handleList, handlePushRequirements, handleReport, handleReviewTest, handleSearchRequirements, handleStyleCheck, handleValidateRequirements, } from "./handlers/index.js";
12
- // Read version from package.json
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = dirname(__filename);
15
- const packageJson = JSON.parse(readFileSync(join(__dirname, "../../package.json"), "utf-8"));
16
- const VERSION = packageJson.version;
17
- // Get project paths from environment variables
18
- // Supports both PROJ_* pattern (Antigravity) and REQUIREMENTS_DIR fallback
19
- function getProjectPathsFromEnv() {
20
- const projects = new Map();
21
- // Check for PROJ_* env vars (project ID -> path mapping)
22
- for (const [key, value] of Object.entries(process.env)) {
23
- if (key.startsWith("PROJ_") && value) {
24
- const projectId = key.substring(5); // Remove 'PROJ_' prefix
25
- projects.set(projectId, value);
26
- }
27
- }
28
- return projects;
29
- }
30
- // Get workspace root from environment or default to cwd
31
- const WORKSPACE_ROOT = process.env.REQUIREMENTS_DIR || process.cwd();
32
- const PROJECT_PATHS = getProjectPathsFromEnv();
33
- // Parse --auth-from-env flag for CI/CD environments
34
- // When set, credentials are read from DOTREQ_PROJECT_ID and DOTREQ_PROJECT_SECRET env vars
35
- const USE_ENV_AUTH = process.argv.includes("--auth-from-env");
36
- let cachedDiscoveryResult = null;
37
- // Requirements are loaded fresh on every call. A long-lived in-memory cache
38
- // silently served stale data when .requirements/*.md files were created or
39
- // edited mid-session, which is the primary authoring workflow the MCP server
40
- // is meant to support. If this ever becomes a measured performance concern,
41
- // invalidate via directory mtime rather than reintroducing a lifetime cache.
42
- async function getRequirements(projectId) {
43
- const project = await getProjectFromDiscovery(projectId);
44
- const { flattened } = await loadAllRequirements(project.path);
45
- return flattened;
46
- }
47
- async function getProjectFromDiscovery(projectId) {
48
- const { isConfiguredProject } = await import("../utils/project-discovery.js");
49
- // If --auth-from-env flag is set, use credentials from environment variables
50
- // This is the explicit opt-in for CI/CD environments
51
- if (USE_ENV_AUTH) {
52
- const envCredentials = getCredentialsFromEnv();
53
- if (!envCredentials) {
54
- throw new Error("--auth-from-env flag requires DOTREQ_PROJECT_ID and DOTREQ_PROJECT_SECRET environment variables to be set");
55
- }
56
- // Return a synthetic project using env credentials and workspace root
57
- return {
58
- path: WORKSPACE_ROOT,
59
- projectId: envCredentials.projectId,
60
- projectSecret: envCredentials.projectSecret,
61
- };
62
- }
63
- // If we have PROJ_* env vars, use those instead of filesystem discovery
64
- if (PROJECT_PATHS.size > 0) {
65
- const projects = [];
66
- // Validate all env var projects
67
- for (const [, path] of PROJECT_PATHS.entries()) {
68
- const project = isConfiguredProject(path);
69
- if (project) {
70
- projects.push(project);
71
- }
72
- }
73
- // Build discovery result from env var projects
74
- if (projects.length === 0) {
75
- cachedDiscoveryResult = {
76
- type: "none",
77
- message: "No valid dotrequirements projects found in PROJ_* environment variables",
78
- };
79
- }
80
- else if (projects.length === 1) {
81
- cachedDiscoveryResult = { type: "single", project: projects[0] };
82
- }
83
- else {
84
- cachedDiscoveryResult = { type: "multiple", projects };
85
- }
86
- return resolveProject(cachedDiscoveryResult, projectId);
87
- }
88
- // Fall back to filesystem discovery if no PROJ_* env vars
89
- if (!cachedDiscoveryResult) {
90
- cachedDiscoveryResult = await discoverProjects(WORKSPACE_ROOT);
91
- }
92
- return resolveProject(cachedDiscoveryResult, projectId);
93
- }
94
- // Invalidate the project-discovery cache. Requirements are no longer cached,
95
- // so this only resets discovery state. Exported for testing.
96
- export function invalidateCache() {
97
- cachedDiscoveryResult = null;
98
- }
99
- // Tool definitions
100
- const tools = [
101
- {
102
- name: "debug_mcp_environment",
103
- description: "DEBUG TOOL: Returns diagnostic information about the MCP server environment (working directory, env vars, etc.)",
104
- inputSchema: {
105
- type: "object",
106
- properties: {},
107
- required: [],
108
- },
109
- },
110
- {
111
- name: "search_requirements",
112
- description: "Search requirements by text or regex query. Searches requirement IDs, content, and labels. Returns matching requirements with their full context.",
113
- inputSchema: {
114
- type: "object",
115
- properties: {
116
- query: {
117
- type: "string",
118
- description: "Text or regex pattern to search for in requirement IDs, content, or labels",
119
- },
120
- useRegex: {
121
- type: "boolean",
122
- description: "If true, treat query as a regular expression (default: false)",
123
- },
124
- projectId: {
125
- type: "string",
126
- description: "Optional: Specify which project to search (required when multiple projects exist)",
127
- },
128
- },
129
- required: ["query"],
130
- },
131
- },
132
- {
133
- name: "get_requirement",
134
- description: 'Get a requirement and all its children, including test coverage information. Accepts any requirement path (e.g., "REQ-123" returns the root and all children, "REQ-123.0" returns that node and its children). Shows which tests reference this requirement and includes the test code.',
135
- inputSchema: {
136
- type: "object",
137
- properties: {
138
- id: {
139
- type: "string",
140
- description: 'The requirement ID or path (e.g., "REQ-123" for root, "REQ-123.0" for child)',
141
- },
142
- projectId: {
143
- type: "string",
144
- description: "Optional: Specify which project to search (required when multiple projects exist)",
145
- },
146
- },
147
- required: ["id"],
148
- },
149
- },
150
- {
151
- name: "list_requirements",
152
- description: "List requirements in the workspace. Defaults to every root requirement (summary of IDs and content with child counts). Set untested to true to filter to only the root requirements that have no requirement() references in the codebase.",
153
- inputSchema: {
154
- type: "object",
155
- properties: {
156
- untested: {
157
- type: "boolean",
158
- description: "When true, return only root requirements that have no test references (default: false)",
159
- },
160
- projectId: {
161
- type: "string",
162
- description: "Optional: Specify which project to search (required when multiple projects exist)",
163
- },
164
- },
165
- required: [],
166
- },
167
- },
168
- {
169
- name: "get_requirements_by_test",
170
- description: "Get the semantic meaning of requirement() references in a test file. Returns requirement content with line numbers where they are referenced.",
171
- inputSchema: {
172
- type: "object",
173
- properties: {
174
- testFile: {
175
- type: "string",
176
- description: "Path to the test file to analyze",
177
- },
178
- projectId: {
179
- type: "string",
180
- description: "Optional: Specify which project to search (required when multiple projects exist)",
181
- },
182
- },
183
- required: ["testFile"],
184
- },
185
- },
186
- {
187
- name: "get_tests_by_requirement",
188
- description: "Show which requirements from a requirements file have test coverage. Returns a coverage report showing which requirements are tested and where the tests are located. This is the inverse of get_requirements_by_test.",
189
- inputSchema: {
190
- type: "object",
191
- properties: {
192
- requirementsFile: {
193
- type: "string",
194
- description: 'Path to the requirements file (e.g., ".requirements/auth.requirements.md")',
195
- },
196
- projectId: {
197
- type: "string",
198
- description: "Optional: Specify which project to search (required when multiple projects exist)",
199
- },
200
- },
201
- required: ["requirementsFile"],
202
- },
203
- },
204
- {
205
- name: "report_coverage",
206
- description: "Display test coverage for the project's requirements. Defaults to local source (most recent test run on this machine, requires `dotrequirements harness prepare` to have run); set source to cloud to query the dot•requirements cloud-persisted record (requires project to be linked via `dotrequirements link`). Optional requirementKey scopes to a single requirement; branch / sinceTimestamp filter cloud-source results.",
207
- inputSchema: {
208
- type: "object",
209
- properties: {
210
- source: {
211
- type: "string",
212
- enum: ["local", "cloud"],
213
- description: "Where to read coverage from (default: local)",
214
- },
215
- requirementKey: {
216
- type: "string",
217
- description: 'Optional: scope to a single requirement (e.g., "REQ-123"). For local source, also includes that requirement\'s children.',
218
- },
219
- branch: {
220
- type: "string",
221
- description: 'Cloud-only: filter coverage to a specific git branch (e.g., "main")',
222
- },
223
- sinceTimestamp: {
224
- type: "number",
225
- description: "Cloud-only: only include coverage recorded after this timestamp (milliseconds since epoch)",
226
- },
227
- projectId: {
228
- type: "string",
229
- description: "Optional: specify which project to use (required when multiple projects exist)",
230
- },
231
- },
232
- required: [],
233
- },
234
- },
235
- {
236
- name: "create_requirement_document",
237
- description: "Returns a well-formatted Markdown template that demonstrates the requirements file format. Use this to understand the format before creating requirements files. AI should use this template as a reference, then use filesystem tools (Read/Write) to create actual files.",
238
- inputSchema: {
239
- type: "object",
240
- properties: {
241
- filePath: {
242
- type: "string",
243
- description: 'Optional: Suggested file path for documentation purposes (e.g., ".requirements/auth.requirements.md")',
244
- },
245
- },
246
- required: [],
247
- },
248
- },
249
- {
250
- name: "validate_requirements",
251
- description: "Validate a requirements Markdown file's schema. Returns detailed error messages on syntax problems. Works offline (no network/auth required). Use this to verify files before pushing.",
252
- inputSchema: {
253
- type: "object",
254
- properties: {
255
- filePath: {
256
- type: "string",
257
- description: 'Path to the Markdown file to validate (e.g., ".requirements/auth.requirements.md")',
258
- },
259
- },
260
- required: ["filePath"],
261
- },
262
- },
263
- {
264
- name: "push_requirements",
265
- description: "Push local requirements from .requirements/ directory to dot•requirements cloud. First call returns diff summary for user review. Second call with confirmed=true executes the push. Requires project to be linked to cloud (run `dotrequirements link`).",
266
- inputSchema: {
267
- type: "object",
268
- properties: {
269
- filePath: {
270
- type: "string",
271
- description: 'Optional: Push specific file only (e.g., ".requirements/auth.requirements.md"). If omitted, pushes all files.',
272
- },
273
- confirmed: {
274
- type: "boolean",
275
- description: "Set to true to execute the push after reviewing the diff. First call should omit this.",
276
- },
277
- projectId: {
278
- type: "string",
279
- description: "Optional: Specify which project to use (required when multiple projects exist)",
280
- },
281
- },
282
- required: [],
283
- },
284
- },
285
- {
286
- name: "style_check",
287
- description: "Check requirements files or test files for style issues and best practices. Uses AI to provide actionable feedback on writing style, clarity, and conventions. Supports requirements files (*.requirements.md) and test files (*.test.*, *.spec.*). For requirements files, you can optionally specify requirement keys to check only those requirements instead of the entire file. Requires project to be linked to cloud (run `dotrequirements link`).",
288
- inputSchema: {
289
- type: "object",
290
- properties: {
291
- filePath: {
292
- type: "string",
293
- description: 'Path to the file to check (e.g., ".requirements/auth.requirements.md" or "src/auth.test.ts")',
294
- },
295
- requirementKeys: {
296
- type: "array",
297
- items: { type: "string" },
298
- description: 'Optional: Array of requirement keys to check (e.g., ["AUTH-1", "AUTH-2"]). Only valid for requirements files (*.requirements.md). When provided, only these requirements are checked instead of the entire file.',
299
- },
300
- model: {
301
- type: "string",
302
- description: 'Optional: AI model to use for style checking (default: "anthropic/claude-haiku-4.5"). Supported models: "anthropic/claude-haiku-4.5", "google/gemini-3-flash"',
303
- },
304
- projectId: {
305
- type: "string",
306
- description: "Optional: Specify which project to use (required when multiple projects exist)",
307
- },
308
- },
309
- required: ["filePath"],
310
- },
311
- },
312
- {
313
- name: "review_test",
314
- description: "Comprehensively review a test file for both style and semantic correctness. Checks if tests actually validate what the requirements specify (not just style). Loads referenced requirements and validates that test setup, actions, and assertions match requirement preconditions, triggers, and outcomes. Requires project to be linked to cloud (run `dotrequirements link`).",
315
- inputSchema: {
316
- type: "object",
317
- properties: {
318
- testFilePath: {
319
- type: "string",
320
- description: 'Path to the test file to review (e.g., "src/auth.test.ts")',
321
- },
322
- projectId: {
323
- type: "string",
324
- description: "Optional: Specify which project to use (required when multiple projects exist)",
325
- },
326
- },
327
- required: ["testFilePath"],
328
- },
329
- },
330
- ];
331
- // Prompt definitions
332
- const prompts = [
333
- {
334
- name: "capture-requirements",
335
- description: "Guide the user through capturing requirements for a new feature before implementation",
336
- },
337
- {
338
- name: "write-tests",
339
- description: "Guide writing tests that reference and validate requirements",
340
- },
341
- ];
342
- // Create server (exported for testing with InMemoryTransport)
343
- export const server = new Server({
344
- name: "dotrequirements",
345
- version: VERSION,
346
- }, {
347
- capabilities: {
348
- tools: {},
349
- prompts: {},
350
- },
351
- });
352
- // Handle list tools
353
- server.setRequestHandler(ListToolsRequestSchema, async () => {
354
- return { tools };
355
- });
356
- // Handle list prompts
357
- server.setRequestHandler(ListPromptsRequestSchema, async () => {
358
- return { prompts };
359
- });
360
- // Handle get prompt
361
- server.setRequestHandler(GetPromptRequestSchema, async (request) => {
362
- const { name } = request.params;
363
- if (name === "capture-requirements") {
364
- return {
365
- messages: [
366
- {
367
- role: "user",
368
- content: {
369
- type: "text",
370
- text: `# Capture Requirements for New Feature
371
-
372
- Let's document what this feature should do before building it.
373
-
374
- ## Questions to Ask
375
-
376
- 1. What problem does this solve for users?
377
- 2. What are the key behaviors we need to support?
378
- 3. Are there edge cases or error conditions to handle?
379
- 4. How will we know it works correctly?
380
-
381
- ## Workflow
382
-
383
- ### Step 1: Create Requirements Document
384
-
385
- Use \`create_requirement_document\` to get a template with:
386
- - Format guidance (discovers existing patterns in your codebase)
387
- - Style principles for writing clear, testable requirements
388
- - Examples of well-written requirements
389
-
390
- Fill in:
391
- - Project ID (from .env.local)
392
- - Document title
393
- - Requirement IDs, descriptions, and expected behaviors
394
-
395
- ### Step 2: Validate & Refine (Optional)
396
-
397
- - \`validate_requirements\` - Check syntax is correct (works offline)
398
- - \`style_check\` - Get AI-powered feedback on writing quality and clarity
399
-
400
- ### Step 3: Push to Cloud
401
-
402
- - \`push_requirements\` - Sync to dot•requirements cloud
403
- - First call shows a diff preview
404
- - Second call with \`confirmed: true\` executes the push
405
-
406
- ### Step 4: Implement & Test
407
-
408
- After capturing requirements:
409
- 1. Implement the feature
410
- 2. Write tests that reference requirements using \`requirement('REQ-ID')\`
411
- 3. See your project's context file (CLAUDE.md/AGENTS.md) for test structure guidance`,
412
- },
413
- },
414
- ],
415
- };
416
- }
417
- if (name === "write-tests") {
418
- return {
419
- messages: [
420
- {
421
- role: "user",
422
- content: {
423
- type: "text",
424
- text: `# Write Tests for Requirements
425
-
426
- Let's write tests that validate the requirements.
427
-
428
- ## Core Principles
429
-
430
- ### 1. Use requirement() AS the test description
431
-
432
- \`\`\`typescript
433
- // ✅ Good - requirement() is the description
434
- test(requirement('AUTH-1'), () => { /* test code */ });
435
- describe(requirement('LOGIN-1.given'), () => { /* setup */ });
436
- it(requirement('LOGIN-1.then'), () => { /* assert */ });
437
-
438
- // ❌ Bad - requirement() in body or comments
439
- test("user can log in", () => { requirement('AUTH-1'); /* test code */ });
440
- // LOGIN-1: User can log in
441
- \`\`\`
442
-
443
- ### 2. Structure tests to match requirement hierarchy
444
-
445
- For structured requirements, nest describe/it blocks:
446
-
447
- \`\`\`typescript
448
- describe(requirement('LOGIN-1'), () => {
449
- describe(requirement('LOGIN-1.given'), () => {
450
- // Arrange: Set up preconditions
451
- });
452
-
453
- describe(requirement('LOGIN-1.when'), () => {
454
- // Act: Trigger the behavior
455
-
456
- it(requirement('LOGIN-1.then'), () => {
457
- // Assert: Verify outcome
458
- });
459
- });
460
- });
461
- \`\`\`
462
-
463
- For simple requirements, one test block is fine:
464
-
465
- \`\`\`typescript
466
- test(requirement('AUTH-1'), () => {
467
- // arrange, act, assert all in one
468
- });
469
- \`\`\`
470
-
471
- ### 3. Comments describe the TEST, not the requirement
472
-
473
- \`\`\`typescript
474
- // ✅ Good - comment explains test implementation
475
- describe(requirement('REQ-1.0'), () => {
476
- // Mock user with valid credentials
477
- });
478
-
479
- // ❌ Bad - verbatim copy of requirement text
480
- describe(requirement('REQ-1.0'), () => {
481
- // 0. When a registered user provides valid credentials, they are authenticated
482
- });
483
- \`\`\`
484
-
485
- ### 4. NEVER document coverage in comments
486
-
487
- Our MCP tools track coverage automatically. Don't create a second source of truth.
488
-
489
- \`\`\`typescript
490
- // ❌ Bad - creates second source of truth
491
- /**
492
- * Requirements coverage:
493
- * - AUTH-9.0: Backend creates project ✓
494
- * - AUTH-9.1: CLI writes to .env.local ✓
495
- */
496
-
497
- // ✅ Good - use MCP tools to check coverage
498
- // Use get_requirement, get_requirements_by_test
499
- \`\`\`
500
-
501
- ## Requirement Path Formats
502
-
503
- - \`requirement('AUTH-1')\` - root requirement
504
- - \`requirement('AUTH-1.0')\` - by numeric position
505
- - \`requirement('AUTH-1.given')\` - by label (case-insensitive)
506
- - \`requirement('AUTH-1.given#1')\` - disambiguate duplicate labels
507
- - \`requirement('AUTH-1.then.and')\` - nested label path
508
-
509
- ## Workflow
510
-
511
- After writing tests:
512
-
513
- 1. Run tests to ensure they don't throw errors
514
- 2. **ALWAYS run \`review_test\`** on the test file to validate tests actually check what requirements specify
515
- 3. Fix any issues identified by the review
516
-
517
- ## MCP Tools for Test Writing
518
-
519
- - \`get_requirement\` - Get requirement tree with existing coverage
520
- - \`get_requirements_by_test\` - See requirements referenced in a test file
521
- - \`list_requirements\` (with \`untested: true\`) - Find requirements without tests
522
- - \`review_test\` - Validate test actually checks what requirement specifies (run after writing tests)`,
523
- },
524
- },
525
- ],
526
- };
527
- }
528
- throw new Error(`Unknown prompt: ${name}`);
529
- });
530
- /**
531
- * MCP-ARGS-1: find required arguments (per the tool's inputSchema) that are
532
- * missing from a call, so we can fail with a self-explaining error before the
533
- * handler runs — a missing argument must never surface as an internal crash.
534
- */
535
- function findMissingRequiredArgs(toolName, args) {
536
- const tool = tools.find((t) => t.name === toolName);
537
- if (!tool)
538
- return undefined; // unknown tools get their own error downstream
539
- const schema = tool.inputSchema;
540
- const required = schema.required ?? [];
541
- const missing = required.filter((key) => args?.[key] === undefined || args?.[key] === null);
542
- if (missing.length === 0)
543
- return undefined;
544
- return { missing, accepted: Object.keys(schema.properties ?? {}) };
545
- }
546
- // Handle tool calls
547
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
548
- const { name, arguments: args } = request.params;
549
- // Refresh cache for each request to pick up changes
550
- invalidateCache();
551
- // MCP-ARGS-1.2: reject calls missing required arguments before dispatch
552
- const argCheck = findMissingRequiredArgs(name, args);
553
- if (argCheck) {
554
- return {
555
- content: [
556
- {
557
- type: "text",
558
- text: `Missing required argument(s) for ${name}: ${argCheck.missing.join(", ")}. Accepted arguments: ${argCheck.accepted.join(", ")}.`,
559
- },
560
- ],
561
- isError: true,
562
- };
563
- }
564
- // Create handler context for extracted handlers
565
- const handlerContext = {
566
- getRequirements,
567
- getProjectFromDiscovery,
568
- workspaceRoot: WORKSPACE_ROOT,
569
- projectPaths: PROJECT_PATHS,
570
- env: process.env,
571
- };
572
- try {
573
- switch (name) {
574
- case "debug_mcp_environment":
575
- return handleDebugMcpEnvironment({}, handlerContext);
576
- case "search_requirements":
577
- return handleSearchRequirements(args, handlerContext);
578
- case "get_requirement":
579
- return handleGetRequirement(args, handlerContext);
580
- case "list_requirements":
581
- return handleList(args, handlerContext);
582
- case "get_requirements_by_test":
583
- return handleGetRequirementsByTest(args, handlerContext);
584
- case "get_tests_by_requirement":
585
- return handleGetTestsByRequirement(args, handlerContext);
586
- case "report_coverage":
587
- return handleReport(args, handlerContext);
588
- case "create_requirement_document":
589
- return handleCreateRequirementDocument(args, handlerContext);
590
- case "validate_requirements":
591
- return handleValidateRequirements(args, handlerContext);
592
- case "push_requirements":
593
- return handlePushRequirements(args, handlerContext);
594
- case "style_check":
595
- return handleStyleCheck(args, handlerContext, {
596
- useEnvAuth: USE_ENV_AUTH,
597
- apiBaseUrl: process.env.DOTREQUIREMENTS_API_URL,
598
- });
599
- case "review_test":
600
- return handleReviewTest(args, handlerContext, { apiBaseUrl: process.env.DOTREQUIREMENTS_API_URL });
601
- default:
602
- return {
603
- content: [
604
- {
605
- type: "text",
606
- text: `Unknown tool: ${name}`,
607
- },
608
- ],
609
- isError: true,
610
- };
611
- }
612
- }
613
- catch (error) {
614
- return {
615
- content: [
616
- {
617
- type: "text",
618
- text: `Error: ${error instanceof Error ? error.message : String(error)}`,
619
- },
620
- ],
621
- isError: true,
622
- };
623
- }
624
- });
625
- // Start server (exported for CLI command to call directly)
626
- export async function main() {
627
- const transport = new StdioServerTransport();
628
- await server.connect(transport);
629
- console.error("dot•requirements MCP server running");
630
- console.error("WORKSPACE_ROOT:", WORKSPACE_ROOT);
631
- console.error("process.cwd():", process.cwd());
632
- console.error("REQUIREMENTS_DIR env:", process.env.REQUIREMENTS_DIR);
633
- }
634
- // Only run when executed directly, not when imported (enables InMemoryTransport testing)
635
- if (import.meta.url === `file://${process.argv[1]}`) {
636
- main().catch(console.error);
637
- }
638
- //# sourceMappingURL=index.js.map