@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,168 +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 { existsSync } from "node:fs";
|
|
7
|
-
import { relative, resolve } from "node:path";
|
|
8
|
-
import { findAllTestReferences, findRequirementsInFile, } from "../../requirements/grep.js";
|
|
9
|
-
import { getRequirementById } from "../../requirements/index.js";
|
|
10
|
-
import { errorResponse, resolveProjectFilePath, textResponse, } from "./types.js";
|
|
11
|
-
/**
|
|
12
|
-
* Handler for get_requirements_by_test tool
|
|
13
|
-
*
|
|
14
|
-
* Requirements covered:
|
|
15
|
-
* - MCP-MAP-1.0: The response lists each requirement() call found in the test file
|
|
16
|
-
* - MCP-MAP-1.1: For each reference, the requirement content and line number are shown
|
|
17
|
-
* - MCP-MAP-1.2: When the test file does not exist, an error is returned
|
|
18
|
-
*/
|
|
19
|
-
export async function handleGetRequirementsByTest(args, context) {
|
|
20
|
-
const { testFile, projectId } = args;
|
|
21
|
-
// #49: Resolve against the discovered project.path (matching push) with a
|
|
22
|
-
// workspaceRoot fallback, so a relative path works in PROJ_*-based setups.
|
|
23
|
-
let projectPath;
|
|
24
|
-
try {
|
|
25
|
-
projectPath = (await context.getProjectFromDiscovery(projectId)).path;
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
projectPath = undefined;
|
|
29
|
-
}
|
|
30
|
-
// MCP-MAP-1.2: Check if file exists before processing
|
|
31
|
-
const fullPath = resolveProjectFilePath(testFile, projectPath, context.workspaceRoot);
|
|
32
|
-
if (!existsSync(fullPath)) {
|
|
33
|
-
return errorResponse(`Test file not found: ${testFile}`);
|
|
34
|
-
}
|
|
35
|
-
const requirements = await context.getRequirements(projectId);
|
|
36
|
-
// MCP-MAP-1.0: Find all requirement references in the test file.
|
|
37
|
-
// #44: Pass the already-resolved absolute path — findRequirementsInFile
|
|
38
|
-
// resolves relative paths against process.cwd(), which is not the workspace
|
|
39
|
-
// root when the MCP server runs from a different directory.
|
|
40
|
-
const refs = await findRequirementsInFile(fullPath);
|
|
41
|
-
if (refs.length === 0) {
|
|
42
|
-
return textResponse(`No requirement references found in "${testFile}"`);
|
|
43
|
-
}
|
|
44
|
-
// MCP-MAP-1.1: For each reference, get the requirement content and show line number
|
|
45
|
-
const entries = refs.map((ref) => {
|
|
46
|
-
const req = getRequirementById(requirements, ref.requirementId);
|
|
47
|
-
const reqContent = req
|
|
48
|
-
? `**${req.label}:** ${req.content}`
|
|
49
|
-
: `(requirement not found)`;
|
|
50
|
-
return `**Line ${ref.line}:** \`${ref.requirementId}\` - ${reqContent}`;
|
|
51
|
-
});
|
|
52
|
-
return textResponse(`Requirements referenced in "${testFile}":\n\n${entries.join("\n\n")}`);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Handler for get_tests_by_requirement tool
|
|
56
|
-
*
|
|
57
|
-
* Requirements covered:
|
|
58
|
-
* - MCP-MAP-2.0: The response lists which requirements have test references
|
|
59
|
-
* - MCP-MAP-2.1: For each covered requirement, the test file and line number are shown
|
|
60
|
-
* - MCP-MAP-2.2: Requirements without test references are listed separately
|
|
61
|
-
*/
|
|
62
|
-
export async function handleGetTestsByRequirement(args, context) {
|
|
63
|
-
const { requirementsFile, projectId } = args;
|
|
64
|
-
const { workspaceRoot } = context;
|
|
65
|
-
// #49: Resolve against the discovered project.path (matching push) with a
|
|
66
|
-
// workspaceRoot fallback, so a relative path works in PROJ_*-based setups.
|
|
67
|
-
// The same base root anchors sourceFile comparison, test scanning, and the
|
|
68
|
-
// relative paths in the output.
|
|
69
|
-
let projectPath;
|
|
70
|
-
try {
|
|
71
|
-
projectPath = (await context.getProjectFromDiscovery(projectId)).path;
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
projectPath = undefined;
|
|
75
|
-
}
|
|
76
|
-
const fullPath = resolveProjectFilePath(requirementsFile, projectPath, workspaceRoot);
|
|
77
|
-
// Verify file exists
|
|
78
|
-
if (!existsSync(fullPath)) {
|
|
79
|
-
return errorResponse(`Requirements file not found: ${requirementsFile}`);
|
|
80
|
-
}
|
|
81
|
-
// Verify it's a requirements file
|
|
82
|
-
if (!requirementsFile.endsWith(".requirements.md")) {
|
|
83
|
-
return errorResponse(`File must be a requirements file: *.requirements.md`);
|
|
84
|
-
}
|
|
85
|
-
// Anchor all subsequent path work to the root that actually contains the
|
|
86
|
-
// requirements file, so sourceFile comparison and test discovery agree.
|
|
87
|
-
const baseRoot = projectPath ?? workspaceRoot;
|
|
88
|
-
// Load all requirements from this file
|
|
89
|
-
const requirements = await context.getRequirements(projectId);
|
|
90
|
-
const fileRequirements = requirements.filter((req) => resolve(baseRoot, req.sourceFile) === fullPath);
|
|
91
|
-
if (fileRequirements.length === 0) {
|
|
92
|
-
return textResponse(`No requirements found in "${requirementsFile}"`);
|
|
93
|
-
}
|
|
94
|
-
// Get unique root requirement IDs from this file
|
|
95
|
-
const rootIds = new Set(fileRequirements.map((req) => req.rootId));
|
|
96
|
-
// Find all test references in the workspace
|
|
97
|
-
const allTestRefs = await findAllTestReferences(baseRoot);
|
|
98
|
-
// Build coverage map keyed by ROOT id. A reference may be a bare root
|
|
99
|
-
// (`AUTH-1`), an index child (`AUTH-1.0`), or a label path (`AUTH-1.given`).
|
|
100
|
-
// #47: Normalize each reference to its root id (the substring before the
|
|
101
|
-
// first dot) before keying — the same normalization as the tests-for fix —
|
|
102
|
-
// so label-path refs match numeric requirement ids instead of rendering as
|
|
103
|
-
// "(requirement not found)".
|
|
104
|
-
const coverageMap = new Map();
|
|
105
|
-
for (const ref of allTestRefs) {
|
|
106
|
-
const dotIndex = ref.requirementId.indexOf(".");
|
|
107
|
-
const refRootId = dotIndex > 0
|
|
108
|
-
? ref.requirementId.substring(0, dotIndex)
|
|
109
|
-
: ref.requirementId;
|
|
110
|
-
if (!coverageMap.has(refRootId)) {
|
|
111
|
-
coverageMap.set(refRootId, []);
|
|
112
|
-
}
|
|
113
|
-
coverageMap.get(refRootId).push(ref);
|
|
114
|
-
}
|
|
115
|
-
// MCP-MAP-2.0: Categorize requirements as covered or not covered
|
|
116
|
-
const covered = [];
|
|
117
|
-
const notCovered = [];
|
|
118
|
-
for (const rootId of rootIds) {
|
|
119
|
-
// Check if this requirement ID or any of its children are referenced
|
|
120
|
-
const reqAndChildren = fileRequirements.filter((r) => r.rootId === rootId);
|
|
121
|
-
const allIds = reqAndChildren.map((r) => r.id);
|
|
122
|
-
const testsForThisReq = [];
|
|
123
|
-
for (const id of allIds) {
|
|
124
|
-
const refs = coverageMap.get(id);
|
|
125
|
-
if (refs) {
|
|
126
|
-
testsForThisReq.push(...refs);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (testsForThisReq.length > 0) {
|
|
130
|
-
covered.push({ id: rootId, tests: testsForThisReq });
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
notCovered.push(rootId);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Format output
|
|
137
|
-
let output = `# Test Coverage for \`${requirementsFile}\`\n\n`;
|
|
138
|
-
// MCP-MAP-2.1: For each covered requirement, show test file and line number
|
|
139
|
-
if (covered.length > 0) {
|
|
140
|
-
output += `## Covered (${covered.length})\n\n`;
|
|
141
|
-
for (const { id, tests } of covered) {
|
|
142
|
-
// Group tests by file
|
|
143
|
-
const testsByFile = new Map();
|
|
144
|
-
for (const test of tests) {
|
|
145
|
-
if (!testsByFile.has(test.file)) {
|
|
146
|
-
testsByFile.set(test.file, []);
|
|
147
|
-
}
|
|
148
|
-
testsByFile.get(test.file).push(test.line);
|
|
149
|
-
}
|
|
150
|
-
output += `- **${id}**: ${tests.length} test${tests.length === 1 ? "" : "s"}\n`;
|
|
151
|
-
for (const [file, lines] of testsByFile.entries()) {
|
|
152
|
-
const relPath = relative(baseRoot, file);
|
|
153
|
-
const lineList = lines.sort((a, b) => a - b).join(", ");
|
|
154
|
-
output += ` - \`${relPath}\` (lines ${lineList})\n`;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
output += "\n";
|
|
158
|
-
}
|
|
159
|
-
// MCP-MAP-2.2: Requirements without test references are listed separately
|
|
160
|
-
if (notCovered.length > 0) {
|
|
161
|
-
output += `## Not Covered (${notCovered.length})\n\n`;
|
|
162
|
-
for (const id of notCovered) {
|
|
163
|
-
output += `- **${id}**: No tests found\n`;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return textResponse(output);
|
|
167
|
-
}
|
|
168
|
-
//# sourceMappingURL=test-mapping.js.map
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handler types for MCP tool handlers
|
|
3
|
-
*
|
|
4
|
-
* Each handler is a pure function that takes arguments and context,
|
|
5
|
-
* and returns an MCP tool response. This enables unit testing without
|
|
6
|
-
* the full MCP server infrastructure.
|
|
7
|
-
*/
|
|
8
|
-
import type { FlattenedRequirement } from "../../requirements/index.js";
|
|
9
|
-
import type { DotreqProject } from "../../utils/project-discovery.js";
|
|
10
|
-
/**
|
|
11
|
-
* MCP tool response content item
|
|
12
|
-
*/
|
|
13
|
-
export interface ToolContentItem {
|
|
14
|
-
type: "text";
|
|
15
|
-
text: string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* MCP tool response
|
|
19
|
-
*
|
|
20
|
-
* Compatible with MCP SDK's CallToolResult type.
|
|
21
|
-
* The index signature allows for SDK extensibility (e.g., _meta, task).
|
|
22
|
-
*/
|
|
23
|
-
export interface ToolResponse {
|
|
24
|
-
[key: string]: unknown;
|
|
25
|
-
content: ToolContentItem[];
|
|
26
|
-
isError?: boolean;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Context provided to all handlers
|
|
30
|
-
*
|
|
31
|
-
* This abstraction enables:
|
|
32
|
-
* - Unit testing with mock context
|
|
33
|
-
* - Dependency injection
|
|
34
|
-
* - Isolation from global state
|
|
35
|
-
*/
|
|
36
|
-
export interface HandlerContext {
|
|
37
|
-
/**
|
|
38
|
-
* Get flattened requirements for a project
|
|
39
|
-
* @param projectId - Optional project ID for multi-project scenarios
|
|
40
|
-
*/
|
|
41
|
-
getRequirements: (projectId?: string) => Promise<FlattenedRequirement[]>;
|
|
42
|
-
/**
|
|
43
|
-
* Get project from discovery (path, credentials)
|
|
44
|
-
* @param projectId - Optional project ID for multi-project scenarios
|
|
45
|
-
*/
|
|
46
|
-
getProjectFromDiscovery: (projectId?: string) => Promise<DotreqProject>;
|
|
47
|
-
/**
|
|
48
|
-
* Workspace root directory
|
|
49
|
-
*/
|
|
50
|
-
workspaceRoot: string;
|
|
51
|
-
/**
|
|
52
|
-
* Project paths from environment variables (PROJ_* pattern)
|
|
53
|
-
*/
|
|
54
|
-
projectPaths: Map<string, string>;
|
|
55
|
-
/**
|
|
56
|
-
* Environment variables (for debug_mcp_environment)
|
|
57
|
-
*/
|
|
58
|
-
env: NodeJS.ProcessEnv;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Handler function signature
|
|
62
|
-
*
|
|
63
|
-
* All MCP tool handlers implement this interface.
|
|
64
|
-
* The args parameter contains tool-specific arguments.
|
|
65
|
-
*/
|
|
66
|
-
export type ToolHandler<TArgs = Record<string, unknown>> = (args: TArgs, context: HandlerContext) => Promise<ToolResponse>;
|
|
67
|
-
/**
|
|
68
|
-
* Resolve a user-supplied relative file path to an absolute path.
|
|
69
|
-
*
|
|
70
|
-
* #49: The MCP server's workspaceRoot is its process cwd, but in PROJ_*-based
|
|
71
|
-
* (Antigravity) setups the discovered project.path is the real project root and
|
|
72
|
-
* differs from cwd. push_requirements resolves against project.path; the other
|
|
73
|
-
* file-taking handlers historically resolved against workspaceRoot, so the same
|
|
74
|
-
* relative path worked for push but not for validate/style/review/mapping.
|
|
75
|
-
*
|
|
76
|
-
* This resolves against project.path first (matching push) and falls back to
|
|
77
|
-
* workspaceRoot when the file is not present there, so both layouts work.
|
|
78
|
-
* Absolute paths are returned unchanged.
|
|
79
|
-
*/
|
|
80
|
-
export declare function resolveProjectFilePath(filePath: string, projectPath: string | undefined, workspaceRoot: string): string;
|
|
81
|
-
/**
|
|
82
|
-
* Helper to create a text response
|
|
83
|
-
*/
|
|
84
|
-
export declare function textResponse(text: string): ToolResponse;
|
|
85
|
-
/**
|
|
86
|
-
* Helper to create an error response
|
|
87
|
-
*/
|
|
88
|
-
export declare function errorResponse(message: string): ToolResponse;
|
|
89
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Handler types for MCP tool handlers
|
|
3
|
-
*
|
|
4
|
-
* Each handler is a pure function that takes arguments and context,
|
|
5
|
-
* and returns an MCP tool response. This enables unit testing without
|
|
6
|
-
* the full MCP server infrastructure.
|
|
7
|
-
*/
|
|
8
|
-
import { existsSync } from "node:fs";
|
|
9
|
-
import { isAbsolute, resolve } from "node:path";
|
|
10
|
-
/**
|
|
11
|
-
* Resolve a user-supplied relative file path to an absolute path.
|
|
12
|
-
*
|
|
13
|
-
* #49: The MCP server's workspaceRoot is its process cwd, but in PROJ_*-based
|
|
14
|
-
* (Antigravity) setups the discovered project.path is the real project root and
|
|
15
|
-
* differs from cwd. push_requirements resolves against project.path; the other
|
|
16
|
-
* file-taking handlers historically resolved against workspaceRoot, so the same
|
|
17
|
-
* relative path worked for push but not for validate/style/review/mapping.
|
|
18
|
-
*
|
|
19
|
-
* This resolves against project.path first (matching push) and falls back to
|
|
20
|
-
* workspaceRoot when the file is not present there, so both layouts work.
|
|
21
|
-
* Absolute paths are returned unchanged.
|
|
22
|
-
*/
|
|
23
|
-
export function resolveProjectFilePath(filePath, projectPath, workspaceRoot) {
|
|
24
|
-
if (isAbsolute(filePath)) {
|
|
25
|
-
return filePath;
|
|
26
|
-
}
|
|
27
|
-
if (projectPath) {
|
|
28
|
-
const fromProject = resolve(projectPath, filePath);
|
|
29
|
-
if (existsSync(fromProject)) {
|
|
30
|
-
return fromProject;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return resolve(workspaceRoot, filePath);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Helper to create a text response
|
|
37
|
-
*/
|
|
38
|
-
export function textResponse(text) {
|
|
39
|
-
return {
|
|
40
|
-
content: [{ type: "text", text }],
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Helper to create an error response
|
|
45
|
-
*/
|
|
46
|
-
export function errorResponse(message) {
|
|
47
|
-
return {
|
|
48
|
-
content: [{ type: "text", text: message }],
|
|
49
|
-
isError: true,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
//# sourceMappingURL=types.js.map
|
package/dist/mcp/index.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
-
export declare function invalidateCache(): void;
|
|
4
|
-
export declare const server: Server<{
|
|
5
|
-
method: string;
|
|
6
|
-
params?: {
|
|
7
|
-
[x: string]: unknown;
|
|
8
|
-
task?: {
|
|
9
|
-
[x: string]: unknown;
|
|
10
|
-
ttl?: number | null | undefined;
|
|
11
|
-
pollInterval?: number | undefined;
|
|
12
|
-
} | undefined;
|
|
13
|
-
_meta?: {
|
|
14
|
-
[x: string]: unknown;
|
|
15
|
-
progressToken?: string | number | undefined;
|
|
16
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
17
|
-
[x: string]: unknown;
|
|
18
|
-
taskId: string;
|
|
19
|
-
} | undefined;
|
|
20
|
-
} | undefined;
|
|
21
|
-
} | undefined;
|
|
22
|
-
}, {
|
|
23
|
-
method: string;
|
|
24
|
-
params?: {
|
|
25
|
-
[x: string]: unknown;
|
|
26
|
-
_meta?: {
|
|
27
|
-
[x: string]: unknown;
|
|
28
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
29
|
-
[x: string]: unknown;
|
|
30
|
-
taskId: string;
|
|
31
|
-
} | undefined;
|
|
32
|
-
} | undefined;
|
|
33
|
-
} | undefined;
|
|
34
|
-
}, {
|
|
35
|
-
[x: string]: unknown;
|
|
36
|
-
_meta?: {
|
|
37
|
-
[x: string]: unknown;
|
|
38
|
-
"io.modelcontextprotocol/related-task"?: {
|
|
39
|
-
[x: string]: unknown;
|
|
40
|
-
taskId: string;
|
|
41
|
-
} | undefined;
|
|
42
|
-
} | undefined;
|
|
43
|
-
}>;
|
|
44
|
-
export declare function main(): Promise<void>;
|
|
45
|
-
//# sourceMappingURL=index.d.ts.map
|