@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,134 +0,0 @@
1
- /**
2
- * Unified coverage handler for the MCP `report_coverage` tool. Replaces
3
- * `get_requirement_coverage` and `get_project_coverage_summary` with a
4
- * single tool that takes a `source: "local" | "cloud"` argument and
5
- * mirrors the CLI `dotreq report` semantics.
6
- */
7
- import { getProjectCoverage as queryProjectCoverage, getRequirementCoverage as queryRequirementCoverage, } from "../../requirements/cloud-coverage.js";
8
- import { buildLocalReport, LocalReportCacheMissingError, } from "../../requirements/coverage.js";
9
- import { CONVEX_URL } from "../convexClient.js";
10
- import { errorResponse, textResponse } from "./types.js";
11
- export async function handleReport(args, context) {
12
- const source = args.source ?? "local";
13
- if (source === "local") {
14
- if (args.branch || args.sinceTimestamp !== undefined) {
15
- return errorResponse("branch and sinceTimestamp require source=cloud. Local reports cover only the most recent test run on this machine.");
16
- }
17
- try {
18
- const report = buildLocalReport({
19
- projectRoot: context.workspaceRoot,
20
- requirementFilter: args.requirementKey,
21
- });
22
- return textResponse(formatLocalReport(report));
23
- }
24
- catch (error) {
25
- if (error instanceof LocalReportCacheMissingError) {
26
- return errorResponse(error.message);
27
- }
28
- throw error;
29
- }
30
- }
31
- // source === "cloud"
32
- let project;
33
- try {
34
- project = await context.getProjectFromDiscovery(args.projectId);
35
- }
36
- catch (error) {
37
- return errorResponse(`Cloud report requires cloud credentials. Run \`dotrequirements link\` to connect to cloud.\n\nError: ${error instanceof Error ? error.message : String(error)}`);
38
- }
39
- if (args.requirementKey) {
40
- const record = await queryRequirementCoverage(args.requirementKey, project.projectId, project.projectSecret, CONVEX_URL);
41
- return textResponse(formatCloudRequirement(record));
42
- }
43
- const record = await queryProjectCoverage(project.projectId, project.projectSecret, CONVEX_URL, {
44
- branch: args.branch,
45
- sinceTimestamp: args.sinceTimestamp,
46
- });
47
- return textResponse(formatCloudProject(record, {
48
- branch: args.branch,
49
- sinceTimestamp: args.sinceTimestamp,
50
- }));
51
- }
52
- function formatLocalReport(report) {
53
- const { total, tested, untested, coveragePercent } = report.summary;
54
- let out = `# Coverage Report (local)\n\n`;
55
- if (report.warnings.length > 0) {
56
- for (const w of report.warnings) {
57
- out += `> ⚠️ ${w}\n`;
58
- }
59
- out += "\n";
60
- }
61
- out += `**Total:** ${total} | **Tested:** ${tested} | **Untested:** ${untested} | **Coverage:** ${coveragePercent}%\n\n`;
62
- const testedEntries = report.entries.filter((c) => c.tested);
63
- if (testedEntries.length > 0) {
64
- out += `## Tested (${testedEntries.length})\n\n`;
65
- for (const c of testedEntries) {
66
- out += `- **${c.key}**: ${c.content}\n`;
67
- for (const loc of c.locations) {
68
- out += ` - \`${loc}\`\n`;
69
- }
70
- }
71
- out += "\n";
72
- }
73
- const untestedEntries = report.entries.filter((c) => !c.tested);
74
- if (untestedEntries.length > 0) {
75
- out += `## Untested (${untestedEntries.length})\n\n`;
76
- for (const c of untestedEntries) {
77
- out += `- **${c.key}**: ${c.content}\n`;
78
- }
79
- }
80
- return out;
81
- }
82
- function formatCloudRequirement(record) {
83
- if (!record.lastTestedAt) {
84
- return `**${record.requirementKey}** has no cloud coverage records.`;
85
- }
86
- const lastTested = new Date(record.lastTestedAt).toISOString();
87
- let out = `# Coverage for ${record.requirementKey} (cloud)\n\n`;
88
- out += `**Last tested:** ${lastTested}\n`;
89
- if (record.branch)
90
- out += `**Branch:** ${record.branch}\n`;
91
- if (record.testFile) {
92
- out += `**Test location:** \`${record.testFile}${record.testLine ? `:${record.testLine}` : ""}\`\n`;
93
- }
94
- const otherBranches = record.allBranches.filter((b) => b.branch !== record.branch);
95
- if (otherBranches.length > 0) {
96
- out += `\n**Also tested on:**\n`;
97
- for (const b of otherBranches) {
98
- out += `- ${b.branch}: ${new Date(b.lastTestedAt).toISOString()}\n`;
99
- }
100
- }
101
- return out;
102
- }
103
- function formatCloudProject(record, filters) {
104
- const tested = record.tested.length;
105
- const untested = record.untested.length;
106
- const total = tested + untested;
107
- const coveragePercent = total > 0 ? ((tested / total) * 100).toFixed(1) : "0.0";
108
- let filterNote = "";
109
- if (filters.branch)
110
- filterNote += `\n**Branch:** ${filters.branch}`;
111
- if (filters.sinceTimestamp) {
112
- filterNote += `\n**Since:** ${new Date(filters.sinceTimestamp).toISOString()}`;
113
- }
114
- let out = `# Project Coverage Report (cloud)\n\n`;
115
- out += `**Total Requirements:** ${total}\n**Coverage:** ${coveragePercent}%${filterNote}\n`;
116
- if (record.tested.length > 0) {
117
- out += `\n## Tested Requirements (${record.tested.length})\n\n`;
118
- for (const t of record.tested) {
119
- const date = new Date(t.lastTestedAt).toISOString();
120
- const location = t.testFile
121
- ? ` (\`${t.testFile}${t.testLine ? `:${t.testLine}` : ""}\`)`
122
- : "";
123
- out += `- **${t.requirementKey}** [${t.branch}]: ${date}${location}\n`;
124
- }
125
- }
126
- if (record.untested.length > 0) {
127
- out += `\n## Untested Requirements (${record.untested.length})\n\n`;
128
- for (const key of record.untested) {
129
- out += `- ${key}\n`;
130
- }
131
- }
132
- return out;
133
- }
134
- //# sourceMappingURL=report.js.map
@@ -1,52 +0,0 @@
1
- /**
2
- * Review handlers for MCP tools
3
- *
4
- * Provides AI-powered review functionality:
5
- * - style_check: Check requirements or test files for style issues
6
- * - review_test: Comprehensively review tests for semantic correctness
7
- */
8
- import type { HandlerContext, ToolResponse } from "./types.js";
9
- /**
10
- * Arguments for style_check tool
11
- */
12
- export interface StyleCheckArgs {
13
- filePath: string;
14
- requirementKeys?: string[];
15
- model?: string;
16
- projectId?: string;
17
- }
18
- /**
19
- * Arguments for review_test tool
20
- */
21
- export interface ReviewTestArgs {
22
- testFilePath: string;
23
- projectId?: string;
24
- }
25
- /**
26
- * Handler for style_check tool
27
- *
28
- * Requirements covered:
29
- * - MCP-REVIEW-1.0: For requirements files, feedback identifies clarity issues such as vague language and missing preconditions
30
- * - MCP-REVIEW-1.1: For test files, feedback identifies incorrect requirement() usage and missing test coverage
31
- * - MCP-REVIEW-1.2: Feedback is categorized by severity: must fix, should fix, could improve
32
- * - MCP-REVIEW-1.3: When cloud credentials are unavailable, an error explains how to authenticate
33
- */
34
- export declare function handleStyleCheck(args: StyleCheckArgs, context: HandlerContext, options?: {
35
- useEnvAuth?: boolean;
36
- apiBaseUrl?: string;
37
- }): Promise<ToolResponse>;
38
- /**
39
- * Handler for review_test tool
40
- *
41
- * Requirements covered:
42
- * - MCP-REVIEW-2.0: Feedback identifies test setup that does not match requirement preconditions
43
- * - MCP-REVIEW-2.1: Feedback identifies test actions that do not match requirement triggers
44
- * - MCP-REVIEW-2.2: Feedback identifies test assertions that do not match requirement outcomes
45
- * - MCP-REVIEW-2.3: Feedback identifies requirements without test coverage
46
- * - MCP-REVIEW-2.4: Feedback identifies tests that reference non-existent requirements
47
- * - MCP-REVIEW-2.5: When cloud credentials are unavailable, an error explains how to authenticate
48
- */
49
- export declare function handleReviewTest(args: ReviewTestArgs, context: HandlerContext, options?: {
50
- apiBaseUrl?: string;
51
- }): Promise<ToolResponse>;
52
- //# sourceMappingURL=review.d.ts.map
@@ -1,243 +0,0 @@
1
- /**
2
- * Review handlers for MCP tools
3
- *
4
- * Provides AI-powered review functionality:
5
- * - style_check: Check requirements or test files for style issues
6
- * - review_test: Comprehensively review tests for semantic correctness
7
- */
8
- import { existsSync, readFileSync } from "node:fs";
9
- import { dirname } from "node:path";
10
- import { fetchReviewTestFeedback, fetchStyleCheckFeedback, } from "../../requirements/cloud-ai.js";
11
- import { findRequirementsInFile } from "../../requirements/grep.js";
12
- import { filterRequirementsByKeys, formatRequirementTree, getRequirementTree, } from "../../requirements/index.js";
13
- import { discoverProjects, } from "../../utils/project-discovery.js";
14
- import { errorResponse, resolveProjectFilePath, textResponse, } from "./types.js";
15
- const STYLE_CHECK_GUIDANCE = `
16
-
17
- ---
18
-
19
- ## How to use this feedback
20
-
21
- 1. **This check is stateless.** It is a "new set of eyes" from any previous feedback rounds — it has no memory of prior suggestions or changes you've already made.
22
-
23
- 2. **Act on feedback from the posture of "what will make the requirements better."** The severity categories (MUST FIX / SHOULD FIX / COULD IMPROVE) are prioritized for convenience, but unless the user has explicitly told you to ignore lower-priority feedback, go ahead and make any improvements — minor or otherwise. If you believe acting on a specific piece of feedback would make the requirements *worse*, surface that feedback to the user rather than silently ignoring it. Otherwise, just act.
24
-
25
- 3. **Next steps:** Always run \`validate_requirements\` again after making updates. If you make significant changes based on this feedback, you can run \`style_check\` again — but be aware that will be a fresh set of eyes, not a continued conversation.`;
26
- /**
27
- * Handler for style_check tool
28
- *
29
- * Requirements covered:
30
- * - MCP-REVIEW-1.0: For requirements files, feedback identifies clarity issues such as vague language and missing preconditions
31
- * - MCP-REVIEW-1.1: For test files, feedback identifies incorrect requirement() usage and missing test coverage
32
- * - MCP-REVIEW-1.2: Feedback is categorized by severity: must fix, should fix, could improve
33
- * - MCP-REVIEW-1.3: When cloud credentials are unavailable, an error explains how to authenticate
34
- */
35
- export async function handleStyleCheck(args, context, options) {
36
- const { filePath, requirementKeys, model, projectId } = args;
37
- const { useEnvAuth = false, apiBaseUrl = "https://app.dotrequirements.io" } = options ?? {};
38
- // #49: Resolve against the discovered project.path (matching push) with a
39
- // workspaceRoot fallback, so a relative path that push accepts also works
40
- // here in PROJ_*-based setups. Discovery may throw without credentials — that
41
- // is fine, we then fall back to workspaceRoot.
42
- let styleProjectPath;
43
- try {
44
- styleProjectPath = (await context.getProjectFromDiscovery(projectId)).path;
45
- }
46
- catch {
47
- styleProjectPath = undefined;
48
- }
49
- const fullPath = resolveProjectFilePath(filePath, styleProjectPath, context.workspaceRoot);
50
- if (!existsSync(fullPath)) {
51
- return errorResponse(`File not found: ${filePath}`);
52
- }
53
- // Read file contents
54
- const fileContents = readFileSync(fullPath, "utf-8");
55
- // Detect file type
56
- // MCP-REVIEW-1.0 & MCP-REVIEW-1.1: Different feedback for different file types
57
- const isRequirementsFile = filePath.endsWith(".requirements.md");
58
- const isTestFile = /\.(test|spec)\.(js|jsx|ts|tsx)$/.test(filePath);
59
- if (!isRequirementsFile && !isTestFile) {
60
- return errorResponse(`Unsupported file type. File must be:\n- Requirements file: *.requirements.md\n- Test file: *.test.{js,jsx,ts,tsx} or *.spec.{js,jsx,ts,tsx}`);
61
- }
62
- const fileType = isRequirementsFile ? "requirements" : "test";
63
- // If requirementKeys provided, filter the file to only those requirements
64
- let fileContentsToCheck = fileContents;
65
- let scopeNote = "";
66
- if (requirementKeys && requirementKeys.length > 0) {
67
- if (!isRequirementsFile) {
68
- return errorResponse(`requirementKeys can only be used with requirements files (*.requirements.md), not test files.`);
69
- }
70
- try {
71
- const { filteredContent, foundKeys, missingKeys } = filterRequirementsByKeys(fileContents, requirementKeys);
72
- if (foundKeys.length === 0) {
73
- return errorResponse(`None of the specified requirement keys were found in ${filePath}: ${requirementKeys.join(", ")}`);
74
- }
75
- fileContentsToCheck = filteredContent;
76
- if (missingKeys.length > 0) {
77
- scopeNote = `\n\n> **Note:** Some specified keys were not found in the file: ${missingKeys.join(", ")}`;
78
- }
79
- }
80
- catch (error) {
81
- return errorResponse(`Failed to filter requirements: ${error instanceof Error ? error.message : String(error)}`);
82
- }
83
- }
84
- // MCP-REVIEW-1.3: Get credentials - walk up from file's directory to find project
85
- const fileDir = dirname(fullPath);
86
- let project;
87
- try {
88
- if (projectId) {
89
- // #48: PROJ-CONTEXT-6 — an explicit projectId disambiguates a
90
- // multi-project workspace. Thread it straight through to discovery
91
- // (matching review_test/push/report) instead of the file-directory
92
- // auto-detect path, which cannot choose among multiple projects.
93
- project = await context.getProjectFromDiscovery(projectId);
94
- }
95
- else if (useEnvAuth) {
96
- // Using env auth - go straight to context
97
- project = await context.getProjectFromDiscovery();
98
- }
99
- else {
100
- // Try to find a project starting from the file's directory
101
- const result = await discoverProjects(fileDir);
102
- if (result.type === "none") {
103
- // If no project found from file dir, try from context
104
- project = await context.getProjectFromDiscovery();
105
- }
106
- else if (result.type === "single") {
107
- project = result.project;
108
- }
109
- else {
110
- // #48: Multiple projects — can't auto-detect. The remedy is to pass
111
- // projectId (not `dotrequirements link`, which is already satisfied);
112
- // list the available projects so the caller can choose.
113
- const available = result.projects
114
- .map((p) => p.projectId)
115
- .filter(Boolean)
116
- .join(", ");
117
- return errorResponse(`Multiple projects found. Specify the \`projectId\` parameter to choose one${available ? ` (available: ${available})` : ""}.`);
118
- }
119
- }
120
- }
121
- catch (error) {
122
- return errorResponse(`Style check requires project credentials. Run \`dotrequirements link\` to connect to cloud.\n\nError: ${error instanceof Error ? error.message : String(error)}`);
123
- }
124
- // Call hosted endpoint via the shared library helper
125
- try {
126
- const feedback = await fetchStyleCheckFeedback({
127
- apiBaseUrl,
128
- projectId: project.projectId,
129
- projectSecret: project.projectSecret,
130
- fileContents: fileContentsToCheck,
131
- fileType,
132
- model,
133
- });
134
- const scopeLabel = requirementKeys && requirementKeys.length > 0
135
- ? ` (${requirementKeys.join(", ")})`
136
- : "";
137
- // MCP-REVIEW-1.2: Feedback includes severity categories (in the API response)
138
- return textResponse(`# Style Check Results for \`${filePath}\`${scopeLabel}\n\n${feedback}${scopeNote}${STYLE_CHECK_GUIDANCE}`);
139
- }
140
- catch (error) {
141
- return errorResponse(`Style check failed: ${error instanceof Error ? error.message : String(error)}`);
142
- }
143
- }
144
- /**
145
- * Handler for review_test tool
146
- *
147
- * Requirements covered:
148
- * - MCP-REVIEW-2.0: Feedback identifies test setup that does not match requirement preconditions
149
- * - MCP-REVIEW-2.1: Feedback identifies test actions that do not match requirement triggers
150
- * - MCP-REVIEW-2.2: Feedback identifies test assertions that do not match requirement outcomes
151
- * - MCP-REVIEW-2.3: Feedback identifies requirements without test coverage
152
- * - MCP-REVIEW-2.4: Feedback identifies tests that reference non-existent requirements
153
- * - MCP-REVIEW-2.5: When cloud credentials are unavailable, an error explains how to authenticate
154
- */
155
- export async function handleReviewTest(args, context, options) {
156
- const { testFilePath, projectId } = args;
157
- const { apiBaseUrl = "https://app.dotrequirements.io" } = options ?? {};
158
- // #49: Resolve against the discovered project.path (matching push) with a
159
- // workspaceRoot fallback. Discovery may throw without credentials — fall back
160
- // to workspaceRoot; the credential error is reported later.
161
- let reviewProjectPath;
162
- try {
163
- reviewProjectPath = (await context.getProjectFromDiscovery(projectId)).path;
164
- }
165
- catch {
166
- reviewProjectPath = undefined;
167
- }
168
- const fullPath = resolveProjectFilePath(testFilePath, reviewProjectPath, context.workspaceRoot);
169
- if (!existsSync(fullPath)) {
170
- return errorResponse(`File not found: ${testFilePath}`);
171
- }
172
- // Verify it's a test file
173
- const isTestFile = /\.(test|spec)\.(js|jsx|ts|tsx)$/.test(testFilePath);
174
- if (!isTestFile) {
175
- return errorResponse(`File must be a test file: *.test.{js,jsx,ts,tsx} or *.spec.{js,jsx,ts,tsx}`);
176
- }
177
- // Read test file contents
178
- const testFileContents = readFileSync(fullPath, "utf-8");
179
- // #43: Extract requirement IDs via the shared AST-based extractor so that
180
- // multi-arg calls (`requirement("A", "B")`) and options-bearing calls
181
- // (`requirement("A", { ... })`) are captured — the old single-string regex
182
- // matched neither.
183
- const references = await findRequirementsInFile(fullPath);
184
- const requirementIds = new Set(references.map((ref) => ref.requirementId));
185
- // MCP-REVIEW-2.5: Get project credentials
186
- let project;
187
- try {
188
- project = await context.getProjectFromDiscovery(projectId);
189
- }
190
- catch (error) {
191
- return errorResponse(`Test review requires a configured dotrequirements project.\n\nError: ${error instanceof Error ? error.message : String(error)}`);
192
- }
193
- // Load all requirements for this project
194
- const allRequirements = await context.getRequirements(projectId);
195
- // Group requirement IDs by their root to avoid sending duplicate trees
196
- // e.g., NAV-3.0, NAV-3.1, NAV-3.2 all belong to root NAV-3
197
- //
198
- // #42: A reference may be a bare root (`AUTH-1`), an index child (`AUTH-1.0`),
199
- // or a label path (`AUTH-1.given`). Normalize each reference to its root id
200
- // (the substring before the first dot) before matching — the same approach
201
- // getReferencedRequirementIds uses — so label-path refs resolve instead of
202
- // being reported as non-existent.
203
- const rootToTestedIds = new Map();
204
- for (const reqId of requirementIds) {
205
- const dotIndex = reqId.indexOf(".");
206
- const refRootId = dotIndex > 0 ? reqId.substring(0, dotIndex) : reqId;
207
- const req = allRequirements.find((r) => r.rootId === refRootId);
208
- if (req) {
209
- if (!rootToTestedIds.has(req.rootId)) {
210
- rootToTestedIds.set(req.rootId, new Set());
211
- }
212
- rootToTestedIds.get(req.rootId).add(reqId);
213
- }
214
- }
215
- // Build requirements array with one entry per unique root tree
216
- // MCP-REVIEW-2.0, 2.1, 2.2: These validations happen in the API based on the tree structure
217
- const requirements = [];
218
- for (const [rootId, testedIds] of rootToTestedIds) {
219
- const tree = getRequirementTree(allRequirements, rootId);
220
- const formattedTree = formatRequirementTree(tree);
221
- requirements.push({
222
- id: rootId,
223
- content: formattedTree,
224
- testedIds: Array.from(testedIds).sort(),
225
- });
226
- }
227
- // Call hosted endpoint via the shared library helper
228
- // MCP-REVIEW-2.3 & 2.4: API identifies coverage gaps and non-existent references
229
- try {
230
- const feedback = await fetchReviewTestFeedback({
231
- apiBaseUrl,
232
- projectId: project.projectId,
233
- projectSecret: project.projectSecret,
234
- testFileContents,
235
- requirements,
236
- });
237
- return textResponse(`# Test Review Results for \`${testFilePath}\`\n\n${feedback}`);
238
- }
239
- catch (error) {
240
- return errorResponse(`Test review failed: ${error instanceof Error ? error.message : String(error)}`);
241
- }
242
- }
243
- //# sourceMappingURL=review.js.map
@@ -1,30 +0,0 @@
1
- /**
2
- * search_requirements handler
3
- *
4
- * Searches requirements by text or regex query across IDs, content, and labels.
5
- * Returns matching requirements with their full tree context.
6
- */
7
- import type { HandlerContext, ToolResponse } from "./types.js";
8
- /**
9
- * Arguments for search_requirements tool
10
- */
11
- export interface SearchRequirementsArgs {
12
- query: string;
13
- useRegex?: boolean;
14
- projectId?: string;
15
- }
16
- /**
17
- * Handler for search_requirements tool
18
- *
19
- * Requirements covered:
20
- * - MCP-SEARCH-1.0: Query matches requirement ID
21
- * - MCP-SEARCH-1.1: Query matches requirement content
22
- * - MCP-SEARCH-1.2: Query matches requirement label
23
- * - MCP-SEARCH-1.3: useRegex interprets query as case-insensitive regex
24
- * - MCP-SEARCH-1.4: Invalid regex returns error
25
- * - MCP-SEARCH-1.5: No matches returns informative message
26
- * - MCP-SEARCH-1.6: Nested match returns the full root requirement tree
27
- * - MCP-SEARCH-1.7: Results include full tree as code block
28
- */
29
- export declare function handleSearchRequirements(args: SearchRequirementsArgs, context: HandlerContext): Promise<ToolResponse>;
30
- //# sourceMappingURL=search.d.ts.map
@@ -1,58 +0,0 @@
1
- /**
2
- * search_requirements handler
3
- *
4
- * Searches requirements by text or regex query across IDs, content, and labels.
5
- * Returns matching requirements with their full tree context.
6
- */
7
- import { formatRequirementTree, getRequirementTree, searchRequirements, } from "../../requirements/index.js";
8
- import { errorResponse, textResponse } from "./types.js";
9
- /**
10
- * Handler for search_requirements tool
11
- *
12
- * Requirements covered:
13
- * - MCP-SEARCH-1.0: Query matches requirement ID
14
- * - MCP-SEARCH-1.1: Query matches requirement content
15
- * - MCP-SEARCH-1.2: Query matches requirement label
16
- * - MCP-SEARCH-1.3: useRegex interprets query as case-insensitive regex
17
- * - MCP-SEARCH-1.4: Invalid regex returns error
18
- * - MCP-SEARCH-1.5: No matches returns informative message
19
- * - MCP-SEARCH-1.6: Nested match returns the full root requirement tree
20
- * - MCP-SEARCH-1.7: Results include full tree as code block
21
- */
22
- export async function handleSearchRequirements(args, context) {
23
- const { query, useRegex = false, projectId } = args;
24
- const requirements = await context.getRequirements(projectId);
25
- let results;
26
- if (useRegex) {
27
- // MCP-SEARCH-1.3: Interpret query as case-insensitive regex
28
- // MCP-SEARCH-1.4: Return error for invalid regex
29
- try {
30
- const regex = new RegExp(query, "i");
31
- results = requirements.filter((r) => regex.test(r.id) || regex.test(r.content) || regex.test(r.label));
32
- }
33
- catch (error) {
34
- return errorResponse(`Invalid regular expression: ${error instanceof Error ? error.message : String(error)}`);
35
- }
36
- }
37
- else {
38
- // MCP-SEARCH-1.0, MCP-SEARCH-1.1, MCP-SEARCH-1.2: Text search across ID, content, label
39
- results = searchRequirements(requirements, query);
40
- }
41
- // MCP-SEARCH-1.6: Collect unique root IDs from all matches (nested matches bubble up to their root)
42
- const matchedRootIds = new Set(results.map((r) => r.rootId));
43
- const rootResults = requirements.filter((r) => r.path.length === 0 && matchedRootIds.has(r.rootId));
44
- // MCP-SEARCH-1.5: No matches returns informative message
45
- if (rootResults.length === 0) {
46
- return textResponse(`No requirements found matching "${query}"${useRegex ? " (regex)" : ""}`);
47
- }
48
- // MCP-SEARCH-1.7: Each result includes full tree as code block
49
- const formatted = rootResults
50
- .map((r) => {
51
- const tree = getRequirementTree(requirements, r.id);
52
- const treeFormatted = formatRequirementTree(tree);
53
- return `**${r.id}** (${r.label})\n${r.content}\n_Source: ${r.documentTitle}_\n\n\`\`\`\n${treeFormatted}\n\`\`\``;
54
- })
55
- .join("\n\n---\n\n");
56
- return textResponse(`Found ${rootResults.length} requirement(s) matching "${query}"${useRegex ? " (regex)" : ""}:\n\n${formatted}`);
57
- }
58
- //# sourceMappingURL=search.js.map
@@ -1,39 +0,0 @@
1
- /**
2
- * get_requirements_by_test and get_tests_by_requirement handlers
3
- *
4
- * Maps between test files and requirements in both directions.
5
- */
6
- import type { HandlerContext, ToolResponse } from "./types.js";
7
- /**
8
- * Arguments for get_requirements_by_test tool
9
- */
10
- export interface GetRequirementsByTestArgs {
11
- testFile: string;
12
- projectId?: string;
13
- }
14
- /**
15
- * Handler for get_requirements_by_test tool
16
- *
17
- * Requirements covered:
18
- * - MCP-MAP-1.0: The response lists each requirement() call found in the test file
19
- * - MCP-MAP-1.1: For each reference, the requirement content and line number are shown
20
- * - MCP-MAP-1.2: When the test file does not exist, an error is returned
21
- */
22
- export declare function handleGetRequirementsByTest(args: GetRequirementsByTestArgs, context: HandlerContext): Promise<ToolResponse>;
23
- /**
24
- * Arguments for get_tests_by_requirement tool
25
- */
26
- export interface GetTestsByRequirementArgs {
27
- requirementsFile: string;
28
- projectId?: string;
29
- }
30
- /**
31
- * Handler for get_tests_by_requirement tool
32
- *
33
- * Requirements covered:
34
- * - MCP-MAP-2.0: The response lists which requirements have test references
35
- * - MCP-MAP-2.1: For each covered requirement, the test file and line number are shown
36
- * - MCP-MAP-2.2: Requirements without test references are listed separately
37
- */
38
- export declare function handleGetTestsByRequirement(args: GetTestsByRequirementArgs, context: HandlerContext): Promise<ToolResponse>;
39
- //# sourceMappingURL=test-mapping.d.ts.map