@popoverai/dotrequirements 0.26.1 → 0.27.0

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 (84) hide show
  1. package/README.md +13 -69
  2. package/dist/cli.js +19 -7
  3. package/dist/codebase-to-spec/present.js +4 -5
  4. package/dist/codebase-to-spec/validate.js +3 -2
  5. package/dist/commands/acceptance-test.js +4 -2
  6. package/dist/commands/ai-setup.d.ts +8 -2
  7. package/dist/commands/ai-setup.js +154 -310
  8. package/dist/commands/get.js +6 -2
  9. package/dist/commands/init.js +8 -6
  10. package/dist/commands/link-resolution.d.ts +3 -1
  11. package/dist/commands/link-resolution.js +4 -2
  12. package/dist/commands/mcp.d.ts +8 -2
  13. package/dist/commands/mcp.js +17 -6
  14. package/dist/commands/pull.js +36 -3
  15. package/dist/commands/push.js +54 -16
  16. package/dist/commands/report.js +18 -3
  17. package/dist/commands/review-test.d.ts +5 -1
  18. package/dist/commands/review-test.js +117 -15
  19. package/dist/commands/style-check.d.ts +1 -0
  20. package/dist/commands/style-check.js +137 -13
  21. package/dist/commands/tests-for.js +13 -13
  22. package/dist/commands/validate.js +14 -14
  23. package/dist/convex.d.ts +1 -3
  24. package/dist/convex.js +3 -3
  25. package/dist/harness/cache.d.ts +19 -3
  26. package/dist/harness/cache.js +38 -12
  27. package/dist/harness/finalize.js +33 -1
  28. package/dist/harness/index.js +16 -9
  29. package/dist/harness/requirementsLoader.js +12 -0
  30. package/dist/harness/tracking.d.ts +17 -2
  31. package/dist/harness/tracking.js +83 -9
  32. package/dist/push/core.d.ts +50 -0
  33. package/dist/push/core.js +149 -11
  34. package/dist/push/index.d.ts +1 -1
  35. package/dist/push/index.js +1 -1
  36. package/dist/requirements/cloud-ai.d.ts +21 -8
  37. package/dist/requirements/cloud-ai.js +10 -8
  38. package/dist/requirements/cloud-coverage.d.ts +12 -2
  39. package/dist/requirements/cloud-coverage.js +30 -3
  40. package/dist/requirements/grep.d.ts +7 -2
  41. package/dist/requirements/grep.js +75 -47
  42. package/dist/schema/builder.d.ts +1 -1
  43. package/dist/schema/builder.js +13 -0
  44. package/dist/schema/conversions.d.ts +7 -2
  45. package/dist/schema/conversions.js +13 -4
  46. package/dist/schema/parser-core.d.ts +41 -0
  47. package/dist/schema/parser-core.js +113 -18
  48. package/dist/schema/parser.d.ts +8 -26
  49. package/dist/schema/parser.js +23 -251
  50. package/dist/schema/resolver.js +18 -8
  51. package/dist/templates/context-file-section.md +25 -22
  52. package/dist/utils/context-file.d.ts +7 -3
  53. package/dist/utils/context-file.js +10 -7
  54. package/dist/utils/env.js +17 -1
  55. package/dist/utils/oauth-flow.js +8 -0
  56. package/dist/utils/project-settings.d.ts +5 -0
  57. package/dist/utils/project-settings.js +36 -1
  58. package/package.json +3 -5
  59. package/dist/mcp/convexClient.d.ts +0 -19
  60. package/dist/mcp/convexClient.js +0 -24
  61. package/dist/mcp/handlers/authoring.d.ts +0 -41
  62. package/dist/mcp/handlers/authoring.js +0 -104
  63. package/dist/mcp/handlers/debug.d.ts +0 -16
  64. package/dist/mcp/handlers/debug.js +0 -37
  65. package/dist/mcp/handlers/get.d.ts +0 -24
  66. package/dist/mcp/handlers/get.js +0 -65
  67. package/dist/mcp/handlers/index.d.ts +0 -28
  68. package/dist/mcp/handlers/index.js +0 -19
  69. package/dist/mcp/handlers/list.d.ts +0 -7
  70. package/dist/mcp/handlers/list.js +0 -43
  71. package/dist/mcp/handlers/push.d.ts +0 -26
  72. package/dist/mcp/handlers/push.js +0 -186
  73. package/dist/mcp/handlers/report.d.ts +0 -16
  74. package/dist/mcp/handlers/report.js +0 -134
  75. package/dist/mcp/handlers/review.d.ts +0 -51
  76. package/dist/mcp/handlers/review.js +0 -200
  77. package/dist/mcp/handlers/search.d.ts +0 -30
  78. package/dist/mcp/handlers/search.js +0 -58
  79. package/dist/mcp/handlers/test-mapping.d.ts +0 -39
  80. package/dist/mcp/handlers/test-mapping.js +0 -133
  81. package/dist/mcp/handlers/types.d.ts +0 -75
  82. package/dist/mcp/handlers/types.js +0 -25
  83. package/dist/mcp/index.d.ts +0 -45
  84. package/dist/mcp/index.js +0 -634
@@ -1,19 +0,0 @@
1
- /**
2
- * Production Convex deployment URL
3
- */
4
- export declare const CONVEX_URL = "https://data.dotrequirements.io";
5
- /**
6
- * Convex configuration for cloud operations
7
- */
8
- interface ConvexConfig {
9
- convexUrl: string;
10
- projectId: string;
11
- projectSecret: string;
12
- }
13
- /**
14
- * Load Convex configuration from project settings.
15
- * Returns null if credentials are not configured.
16
- */
17
- export declare function loadConvexConfig(cwd?: string): ConvexConfig | null;
18
- export {};
19
- //# sourceMappingURL=convexClient.d.ts.map
@@ -1,24 +0,0 @@
1
- import { getProjectCredentials } from "../utils/project-settings.js";
2
- /**
3
- * Production Convex deployment URL
4
- */
5
- export const CONVEX_URL = "https://data.dotrequirements.io";
6
- /**
7
- * Load Convex configuration from project settings.
8
- * Returns null if credentials are not configured.
9
- */
10
- export function loadConvexConfig(cwd = process.cwd()) {
11
- try {
12
- const credentials = getProjectCredentials(cwd);
13
- return {
14
- convexUrl: CONVEX_URL,
15
- projectId: credentials.projectId,
16
- projectSecret: credentials.projectSecret,
17
- };
18
- }
19
- catch {
20
- // Credentials not found or project not connected to cloud
21
- return null;
22
- }
23
- }
24
- //# sourceMappingURL=convexClient.js.map
@@ -1,41 +0,0 @@
1
- /**
2
- * Authoring handlers for MCP tools
3
- *
4
- * Provides document creation and validation:
5
- * - create_requirement_document: Generate requirements template with format guidance
6
- * - validate_requirements: Validate requirements file syntax offline
7
- */
8
- import type { HandlerContext, ToolResponse } from "./types.js";
9
- /**
10
- * Arguments for create_requirement_document tool
11
- */
12
- export interface CreateRequirementDocumentArgs {
13
- filePath?: string;
14
- }
15
- /**
16
- * Arguments for validate_requirements tool
17
- */
18
- export interface ValidateRequirementsArgs {
19
- filePath: string;
20
- }
21
- /**
22
- * Handler for create_requirement_document tool
23
- *
24
- * Requirements covered:
25
- * - MCP-AUTHOR-1.0: The template includes format guidance with code block examples
26
- * - MCP-AUTHOR-1.1: The template includes style guidance (concrete examples, concise prose, testable conditions)
27
- * - MCP-AUTHOR-1.2: When the project has requirementsStyleContext configured, it is included in the template
28
- * - MCP-AUTHOR-1.3: When cloud credentials are unavailable, the template works without the custom context
29
- */
30
- export declare function handleCreateRequirementDocument(args: CreateRequirementDocumentArgs, context: HandlerContext): Promise<ToolResponse>;
31
- /**
32
- * Handler for validate_requirements tool
33
- *
34
- * Requirements covered:
35
- * - MCP-AUTHOR-2.1: When the file has valid syntax, the response confirms validation passed
36
- * - MCP-AUTHOR-2.2: When the file has syntax errors, the response lists each error with location
37
- * - MCP-AUTHOR-2.3: Validation does not require network access or cloud credentials
38
- * - MCP-AUTHOR-2.4: When the file does not exist, an error is returned
39
- */
40
- export declare function handleValidateRequirements(args: ValidateRequirementsArgs, context: HandlerContext): Promise<ToolResponse>;
41
- //# sourceMappingURL=authoring.d.ts.map
@@ -1,104 +0,0 @@
1
- /**
2
- * Authoring handlers for MCP tools
3
- *
4
- * Provides document creation and validation:
5
- * - create_requirement_document: Generate requirements template with format guidance
6
- * - validate_requirements: Validate requirements file syntax offline
7
- */
8
- import { existsSync } from "node:fs";
9
- import { resolve } from "node:path";
10
- import { getProjectContext } from "../../requirements/cloud-ai.js";
11
- import { generateStyleGuide, readLocalStyleGuide, } from "../../requirements/style-guide.js";
12
- import { parseRequirementsFromFile, validateForPush, } from "../../schema/index.js";
13
- import { CONVEX_URL } from "../convexClient.js";
14
- import { errorResponse, textResponse } from "./types.js";
15
- /**
16
- * Handler for create_requirement_document tool
17
- *
18
- * Requirements covered:
19
- * - MCP-AUTHOR-1.0: The template includes format guidance with code block examples
20
- * - MCP-AUTHOR-1.1: The template includes style guidance (concrete examples, concise prose, testable conditions)
21
- * - MCP-AUTHOR-1.2: When the project has requirementsStyleContext configured, it is included in the template
22
- * - MCP-AUTHOR-1.3: When cloud credentials are unavailable, the template works without the custom context
23
- */
24
- export async function handleCreateRequirementDocument(args, context) {
25
- const { filePath = ".requirements/example.requirements.md" } = args;
26
- // MCP-AUTHOR-1.3: Try to get requirements, but don't fail if no project is configured
27
- let requirements = [];
28
- try {
29
- requirements = await context.getRequirements();
30
- }
31
- catch {
32
- // No project configured — discovered patterns will be empty
33
- }
34
- // MCP-AUTHOR-1.2: Try to fetch user-provided style context from cloud
35
- let customStyleGuidance = null;
36
- try {
37
- const project = await context.getProjectFromDiscovery();
38
- const contextData = await getProjectContext(project.projectId, project.projectSecret, CONVEX_URL);
39
- customStyleGuidance = contextData?.requirementsStyleContext ?? null;
40
- }
41
- catch {
42
- // MCP-AUTHOR-1.3: No credentials or cloud unavailable - continue without user context
43
- }
44
- const localStyleGuide = readLocalStyleGuide(context.workspaceRoot);
45
- return textResponse(generateStyleGuide({
46
- requirements,
47
- customStyleGuidance,
48
- filePath,
49
- localStyleGuide,
50
- }));
51
- }
52
- /**
53
- * Handler for validate_requirements tool
54
- *
55
- * Requirements covered:
56
- * - MCP-AUTHOR-2.1: When the file has valid syntax, the response confirms validation passed
57
- * - MCP-AUTHOR-2.2: When the file has syntax errors, the response lists each error with location
58
- * - MCP-AUTHOR-2.3: Validation does not require network access or cloud credentials
59
- * - MCP-AUTHOR-2.4: When the file does not exist, an error is returned
60
- */
61
- export async function handleValidateRequirements(args, context) {
62
- const { filePath } = args;
63
- // MCP-AUTHOR-2.3: Validation works offline - just use workspaceRoot
64
- const fullPath = resolve(context.workspaceRoot, filePath);
65
- // MCP-AUTHOR-2.4: Check if file exists
66
- if (!existsSync(fullPath)) {
67
- return errorResponse(`File not found: ${filePath}`);
68
- }
69
- try {
70
- // MCP-AUTHOR-2.1 & MCP-AUTHOR-2.2: Parse and validate
71
- const parsed = parseRequirementsFromFile(fullPath);
72
- const reqCount = Object.keys(parsed.requirements).length;
73
- // Check push readiness
74
- const pushValidation = validateForPush(parsed.metadata);
75
- let headline;
76
- let pushDetails = "";
77
- if (!pushValidation.valid) {
78
- headline = `❌ \`${filePath}\` - Not push-ready\n- ${pushValidation.reason}`;
79
- }
80
- else {
81
- const actionLabel = pushValidation.action === "create"
82
- ? "Will create new document"
83
- : "Will update existing document";
84
- headline = `✓ \`${filePath}\` - ${actionLabel}`;
85
- if (pushValidation.warning) {
86
- pushDetails = `\n- ⚠️ ${pushValidation.warning}`;
87
- }
88
- }
89
- return textResponse(`${headline}${pushDetails}\n\n**Metadata:**\n- Version: ${parsed.metadata.version ?? "(none)"}\n- Document: ${parsed.metadata.document?.title || "(none)"}\n- Document ID: ${parsed.metadata.document?.id || "(none)"}\n\n**Requirements:** ${reqCount} root requirement(s) found`);
90
- }
91
- catch (error) {
92
- // MCP-AUTHOR-2.2: Syntax errors are returned with details
93
- return {
94
- content: [
95
- {
96
- type: "text",
97
- text: `✗ Validation failed for \`${filePath}\`:\n\n${error instanceof Error ? error.message : String(error)}`,
98
- },
99
- ],
100
- isError: true,
101
- };
102
- }
103
- }
104
- //# sourceMappingURL=authoring.js.map
@@ -1,16 +0,0 @@
1
- /**
2
- * debug_mcp_environment handler
3
- *
4
- * Returns diagnostic information about the MCP server environment.
5
- * Useful for debugging configuration issues.
6
- */
7
- import type { HandlerContext, ToolResponse } from "./types.js";
8
- /**
9
- * Arguments for debug_mcp_environment tool
10
- */
11
- export type DebugMcpEnvironmentArgs = Record<string, never>;
12
- /**
13
- * Handler for debug_mcp_environment tool
14
- */
15
- export declare function handleDebugMcpEnvironment(_args: DebugMcpEnvironmentArgs, context: HandlerContext): Promise<ToolResponse>;
16
- //# sourceMappingURL=debug.d.ts.map
@@ -1,37 +0,0 @@
1
- /**
2
- * debug_mcp_environment handler
3
- *
4
- * Returns diagnostic information about the MCP server environment.
5
- * Useful for debugging configuration issues.
6
- */
7
- import { textResponse } from "./types.js";
8
- /**
9
- * Handler for debug_mcp_environment tool
10
- */
11
- export async function handleDebugMcpEnvironment(_args, context) {
12
- // Check for Antigravity-specific env vars
13
- const antigravityVars = Object.entries(context.env)
14
- .filter(([key]) => key.startsWith("GEMINI_") || key.startsWith("ANTIGRAVITY_"))
15
- .map(([key, value]) => ` ${key}: ${value}`)
16
- .join("\n");
17
- // Show discovered projects from env vars
18
- const projectList = Array.from(context.projectPaths.entries())
19
- .map(([id, path]) => ` ${id}: ${path}`)
20
- .join("\n");
21
- const text = `# MCP Server Environment Debug Info
22
-
23
- **process.cwd():** ${process.cwd()}
24
- **WORKSPACE_ROOT:** ${context.workspaceRoot}
25
- **REQUIREMENTS_DIR env:** ${context.env.REQUIREMENTS_DIR || "(not set)"}
26
- **HOME:** ${context.env.HOME || "(not set)"}
27
- **PWD:** ${context.env.PWD || "(not set)"}
28
- **OLDPWD:** ${context.env.OLDPWD || "(not set)"}
29
-
30
- **Antigravity/Gemini env vars:**
31
- ${antigravityVars || "(none found)"}
32
-
33
- **Projects from PROJ_* env vars:**
34
- ${projectList || "(none found)"}`;
35
- return textResponse(text);
36
- }
37
- //# sourceMappingURL=debug.js.map
@@ -1,24 +0,0 @@
1
- /**
2
- * get_requirement handler
3
- *
4
- * Retrieves a specific requirement by ID with its full tree and test coverage.
5
- */
6
- import type { HandlerContext, ToolResponse } from "./types.js";
7
- /**
8
- * Arguments for get_requirement tool
9
- */
10
- export interface GetRequirementArgs {
11
- id: string;
12
- projectId?: string;
13
- }
14
- /**
15
- * Handler for get_requirement tool
16
- *
17
- * Requirements covered:
18
- * - MCP-GET-1.0: When the ID matches a root requirement, the full tree is returned
19
- * - MCP-GET-1.1: When the ID matches a child requirement, that subtree is returned
20
- * - MCP-GET-1.2: When the ID does not exist, an error message is returned
21
- * - MCP-GET-1.3: When a requirement is retrieved, test references are shown with file path and line number
22
- */
23
- export declare function handleGetRequirement(args: GetRequirementArgs, context: HandlerContext): Promise<ToolResponse>;
24
- //# sourceMappingURL=get.d.ts.map
@@ -1,65 +0,0 @@
1
- /**
2
- * get_requirement handler
3
- *
4
- * Retrieves a specific requirement by ID with its full tree and test coverage.
5
- */
6
- import { glob } from "glob";
7
- import { formatRequirementTree, getRequirementTree, } from "../../requirements/index.js";
8
- import { findFilesWithRequirement, findTestCodeForRequirement, } from "../../requirements/testCodeExtractor.js";
9
- import { textResponse } from "./types.js";
10
- /**
11
- * Handler for get_requirement tool
12
- *
13
- * Requirements covered:
14
- * - MCP-GET-1.0: When the ID matches a root requirement, the full tree is returned
15
- * - MCP-GET-1.1: When the ID matches a child requirement, that subtree is returned
16
- * - MCP-GET-1.2: When the ID does not exist, an error message is returned
17
- * - MCP-GET-1.3: When a requirement is retrieved, test references are shown with file path and line number
18
- */
19
- export async function handleGetRequirement(args, context) {
20
- const { id, projectId } = args;
21
- const project = await context.getProjectFromDiscovery(projectId);
22
- const requirements = await context.getRequirements(projectId);
23
- // Get the tree starting from this ID
24
- // MCP-GET-1.0: Full tree for root requirement
25
- // MCP-GET-1.1: Subtree for child requirement
26
- const tree = getRequirementTree(requirements, id);
27
- // MCP-GET-1.2: Return error if not found
28
- if (tree.length === 0) {
29
- return textResponse(`Requirement "${id}" not found`);
30
- }
31
- const root = tree[0];
32
- const formatted = formatRequirementTree(tree);
33
- // MCP-GET-1.3: Find test files that reference this requirement
34
- const testFiles = await glob("**/*.{test,spec}.{js,jsx,ts,tsx}", {
35
- cwd: project.path,
36
- absolute: true,
37
- ignore: ["**/node_modules/**", "**/dist/**", "**/build/**"],
38
- });
39
- const matchingFiles = findFilesWithRequirement(testFiles, id);
40
- const testCodeSections = [];
41
- for (const file of matchingFiles) {
42
- const testRefs = findTestCodeForRequirement(file, id);
43
- // Deduplicate by removing nested blocks - keep only outermost blocks
44
- const deduplicated = testRefs.filter((ref, i) => {
45
- // Check if this ref is contained within any other ref
46
- const isNested = testRefs.some((other, j) => {
47
- if (i === j)
48
- return false;
49
- // other contains ref if it starts before or at the same line and ends after or at the same line
50
- return (other.startLine <= ref.startLine &&
51
- other.endLine >= ref.endLine &&
52
- (other.startLine < ref.startLine || other.endLine > ref.endLine));
53
- });
54
- return !isNested;
55
- });
56
- for (const ref of deduplicated) {
57
- testCodeSections.push(`**${ref.requirementId}** tested in \`${ref.file}:${ref.startLine}-${ref.endLine}\`:\n\n\`\`\`typescript\n${ref.code}\n\`\`\``);
58
- }
59
- }
60
- const testSection = testCodeSections.length > 0
61
- ? `\n\n## Test Coverage (${testCodeSections.length} reference(s)):\n\n${testCodeSections.join("\n\n---\n\n")}`
62
- : "\n\n## Test Coverage\n\nNo tests found referencing this requirement.";
63
- return textResponse(`# ${id}\n\n**Document:** ${root.documentTitle}\n**Source:** ${root.sourceFile}\n\n## Requirement Tree (${tree.length} node(s)):\n\n\`\`\`\n${formatted}\n\`\`\`${testSection}`);
64
- }
65
- //# sourceMappingURL=get.js.map
@@ -1,28 +0,0 @@
1
- /**
2
- * MCP Tool Handlers
3
- *
4
- * Each handler is a pure function that processes tool arguments
5
- * and returns an MCP response. Handlers receive a context object
6
- * that provides access to shared dependencies.
7
- */
8
- export type { CreateRequirementDocumentArgs, ValidateRequirementsArgs, } from "./authoring.js";
9
- export { handleCreateRequirementDocument, handleValidateRequirements, } from "./authoring.js";
10
- export type { DebugMcpEnvironmentArgs } from "./debug.js";
11
- export { handleDebugMcpEnvironment } from "./debug.js";
12
- export type { GetRequirementArgs } from "./get.js";
13
- export { handleGetRequirement } from "./get.js";
14
- export type { ListArgs } from "./list.js";
15
- export { handleList } from "./list.js";
16
- export type { PushRequirementsArgs } from "./push.js";
17
- export { handlePushRequirements } from "./push.js";
18
- export type { ReportArgs } from "./report.js";
19
- export { handleReport } from "./report.js";
20
- export type { ReviewTestArgs, StyleCheckArgs } from "./review.js";
21
- export { handleReviewTest, handleStyleCheck } from "./review.js";
22
- export type { SearchRequirementsArgs } from "./search.js";
23
- export { handleSearchRequirements } from "./search.js";
24
- export type { GetRequirementsByTestArgs, GetTestsByRequirementArgs, } from "./test-mapping.js";
25
- export { handleGetRequirementsByTest, handleGetTestsByRequirement, } from "./test-mapping.js";
26
- export type { HandlerContext, ToolContentItem, ToolHandler, ToolResponse, } from "./types.js";
27
- export { errorResponse, textResponse } from "./types.js";
28
- //# sourceMappingURL=index.d.ts.map
@@ -1,19 +0,0 @@
1
- /**
2
- * MCP Tool Handlers
3
- *
4
- * Each handler is a pure function that processes tool arguments
5
- * and returns an MCP response. Handlers receive a context object
6
- * that provides access to shared dependencies.
7
- */
8
- export { handleCreateRequirementDocument, handleValidateRequirements, } from "./authoring.js";
9
- // Handlers
10
- export { handleDebugMcpEnvironment } from "./debug.js";
11
- export { handleGetRequirement } from "./get.js";
12
- export { handleList } from "./list.js";
13
- export { handlePushRequirements } from "./push.js";
14
- export { handleReport } from "./report.js";
15
- export { handleReviewTest, handleStyleCheck } from "./review.js";
16
- export { handleSearchRequirements } from "./search.js";
17
- export { handleGetRequirementsByTest, handleGetTestsByRequirement, } from "./test-mapping.js";
18
- export { errorResponse, textResponse } from "./types.js";
19
- //# sourceMappingURL=index.js.map
@@ -1,7 +0,0 @@
1
- import type { HandlerContext, ToolResponse } from "./types.js";
2
- export interface ListArgs {
3
- untested?: boolean;
4
- projectId?: string;
5
- }
6
- export declare function handleList(args: ListArgs, context: HandlerContext): Promise<ToolResponse>;
7
- //# sourceMappingURL=list.d.ts.map
@@ -1,43 +0,0 @@
1
- import { getReferencedRequirementIds } from "../../requirements/grep.js";
2
- import { textResponse } from "./types.js";
3
- export async function handleList(args, context) {
4
- const { untested = false, projectId } = args;
5
- const project = await context.getProjectFromDiscovery(projectId);
6
- const requirements = await context.getRequirements(projectId);
7
- if (requirements.length === 0) {
8
- return textResponse(`No requirements found in project: ${project.path}\n\nMake sure .requirements/ directory exists with Markdown files (*.requirements.md).`);
9
- }
10
- if (untested) {
11
- return formatUntested(requirements, project.path);
12
- }
13
- return formatAll(requirements);
14
- }
15
- function formatAll(requirements) {
16
- const grouped = new Map();
17
- for (const req of requirements) {
18
- const existing = grouped.get(req.rootId) || [];
19
- existing.push(req);
20
- grouped.set(req.rootId, existing);
21
- }
22
- const formatted = Array.from(grouped.entries())
23
- .map(([rootId, reqs]) => {
24
- const root = reqs.find((r) => r.path.length === 0);
25
- const childCount = reqs.length - 1;
26
- return `- **${rootId}**: ${root?.content || "(no content)"} (${childCount} children)`;
27
- })
28
- .join("\n");
29
- return textResponse(`Found ${grouped.size} requirement(s) with ${requirements.length} total nodes:\n\n${formatted}`);
30
- }
31
- async function formatUntested(requirements, projectPath) {
32
- const referencedIds = await getReferencedRequirementIds(projectPath);
33
- const rootRequirements = requirements.filter((r) => r.path.length === 0);
34
- const untested = rootRequirements.filter((r) => !referencedIds.has(r.id));
35
- if (untested.length === 0) {
36
- return textResponse(`All ${rootRequirements.length} requirement(s) have test references — coverage is complete.`);
37
- }
38
- const formatted = untested
39
- .map((r) => `- **${r.id}**: ${r.content}`)
40
- .join("\n");
41
- return textResponse(`Found ${untested.length} untested requirement(s) out of ${rootRequirements.length} total:\n\n${formatted}`);
42
- }
43
- //# sourceMappingURL=list.js.map
@@ -1,26 +0,0 @@
1
- /**
2
- * Push handler for MCP tools
3
- *
4
- * Provides requirements push functionality:
5
- * - push_requirements: Push local requirements to cloud
6
- */
7
- import type { HandlerContext, ToolResponse } from "./types.js";
8
- /**
9
- * Arguments for push_requirements tool
10
- */
11
- export interface PushRequirementsArgs {
12
- filePath?: string;
13
- confirmed?: boolean;
14
- projectId?: string;
15
- }
16
- /**
17
- * Handler for push_requirements tool
18
- *
19
- * Requirements covered:
20
- * - MCP-PUSH-1.0: When not confirmed, no changes are made and a preview of creates/updates is returned
21
- * - MCP-PUSH-1.1: When confirmed is true, the push executes and returns success message
22
- * - MCP-PUSH-1.2: When credentials are missing or invalid, an error explains how to authenticate
23
- * - MCP-PUSH-1.3: When filePath is provided, only that file is pushed (MCP-PUSH-1.3.0: missing file is an error)
24
- */
25
- export declare function handlePushRequirements(args: PushRequirementsArgs, context: HandlerContext): Promise<ToolResponse>;
26
- //# sourceMappingURL=push.d.ts.map
@@ -1,186 +0,0 @@
1
- /**
2
- * Push handler for MCP tools
3
- *
4
- * Provides requirements push functionality:
5
- * - push_requirements: Push local requirements to cloud
6
- */
7
- import { existsSync } from "node:fs";
8
- import { basename, resolve } from "node:path";
9
- import { dryRunPush, executePush, parseFilesForPush, } from "../../push/index.js";
10
- import { findRequirementsFiles } from "../../requirements/index.js";
11
- import { CONVEX_URL } from "../convexClient.js";
12
- import { errorResponse, textResponse } from "./types.js";
13
- /**
14
- * Handler for push_requirements tool
15
- *
16
- * Requirements covered:
17
- * - MCP-PUSH-1.0: When not confirmed, no changes are made and a preview of creates/updates is returned
18
- * - MCP-PUSH-1.1: When confirmed is true, the push executes and returns success message
19
- * - MCP-PUSH-1.2: When credentials are missing or invalid, an error explains how to authenticate
20
- * - MCP-PUSH-1.3: When filePath is provided, only that file is pushed (MCP-PUSH-1.3.0: missing file is an error)
21
- */
22
- export async function handlePushRequirements(args, context) {
23
- const { filePath, confirmed = false, projectId } = args;
24
- // MCP-PUSH-1.2: Get project credentials (throws if not configured)
25
- let project;
26
- try {
27
- project = await context.getProjectFromDiscovery(projectId);
28
- }
29
- catch (error) {
30
- return errorResponse(`Push requires project credentials. Run \`dotrequirements link\` to connect to cloud.\n\nError: ${error instanceof Error ? error.message : String(error)}`);
31
- }
32
- // Determine files to push
33
- let filesToPush;
34
- // MCP-PUSH-1.3: When filePath is provided, only that file is pushed
35
- if (filePath) {
36
- const fullPath = resolve(project.path, filePath);
37
- if (!existsSync(fullPath)) {
38
- return errorResponse(`File not found: ${filePath}`);
39
- }
40
- filesToPush = [fullPath];
41
- }
42
- else {
43
- // Use same file discovery as CLI - searches entire workspace
44
- filesToPush = await findRequirementsFiles(project.path);
45
- if (filesToPush.length === 0) {
46
- return textResponse("No *.requirements.md files found. Nothing to push.");
47
- }
48
- }
49
- // Parse files
50
- const { parsedFiles, totalRequirements } = parseFilesForPush(filesToPush);
51
- // Build credentials
52
- const credentials = {
53
- projectId: project.projectId,
54
- projectSecret: project.projectSecret,
55
- convexUrl: CONVEX_URL,
56
- };
57
- // Run dry run (always, even when confirmed - ensures fresh state)
58
- const dryRunResult = await dryRunPush(parsedFiles, credentials);
59
- // Check if there's anything to push
60
- const pushableCount = dryRunResult.updates.length +
61
- dryRunResult.creates.length +
62
- dryRunResult.notFound.length;
63
- if (pushableCount === 0 && dryRunResult.invalid.length > 0) {
64
- // Only invalid files
65
- const invalidList = dryRunResult.invalid
66
- .map(({ file, result }) => `- ${basename(file.filePath)}: ${result.error}`)
67
- .join("\n");
68
- return {
69
- content: [
70
- {
71
- type: "text",
72
- text: `✗ No valid documents to push.\n\n**Invalid files:**\n${invalidList}`,
73
- },
74
- ],
75
- isError: true,
76
- };
77
- }
78
- // MCP-PUSH-1.0: When not confirmed, show preview
79
- if (!confirmed) {
80
- let summary = `# Push Preview\n\n**Files:** ${parsedFiles.length}\n**Requirements:** ${totalRequirements}\n\n`;
81
- if (dryRunResult.updates.length > 0) {
82
- summary += `## Updates (${dryRunResult.updates.length})\n`;
83
- for (const { file, result } of dryRunResult.updates) {
84
- const fileName = basename(file.filePath);
85
- const hasConflict = dryRunResult.conflicts.some((c) => c.item.file === file);
86
- const conflictNote = hasConflict ? " ⚠️ [cloud changed since pull]" : "";
87
- const warningNote = result.warning ? ` (${result.warning})` : "";
88
- summary += `- ~ ${fileName}${conflictNote}${warningNote}\n`;
89
- }
90
- summary += "\n";
91
- }
92
- if (dryRunResult.creates.length > 0) {
93
- summary += `## New Documents (${dryRunResult.creates.length})\n`;
94
- for (const { file, result } of dryRunResult.creates) {
95
- const fileName = basename(file.filePath);
96
- const warningNote = result.warning ? ` (${result.warning})` : "";
97
- summary += `- + ${fileName}${warningNote}\n`;
98
- }
99
- summary += "\n";
100
- }
101
- if (dryRunResult.notFound.length > 0) {
102
- summary += `## Not Found in Cloud (${dryRunResult.notFound.length}) - will create new\n`;
103
- for (const { file, result } of dryRunResult.notFound) {
104
- const fileName = basename(file.filePath);
105
- summary += `- ! ${fileName} (ID: ${result.documentId})\n`;
106
- }
107
- summary += "\n";
108
- }
109
- if (dryRunResult.invalid.length > 0) {
110
- summary += `## Skipped - Invalid (${dryRunResult.invalid.length})\n`;
111
- for (const { file, result } of dryRunResult.invalid) {
112
- const fileName = basename(file.filePath);
113
- summary += `- ✗ ${fileName}: ${result.error}\n`;
114
- }
115
- summary += "\n";
116
- }
117
- if (dryRunResult.conflicts.length > 0) {
118
- summary += `⚠️ **Warning:** ${dryRunResult.conflicts.length} file(s) have cloud changes since last pull. Pushing will overwrite those changes.\n\n`;
119
- }
120
- summary += `**To proceed:** Call this tool again with \`confirmed: true\``;
121
- return textResponse(summary);
122
- }
123
- // MCP-PUSH-1.1: When confirmed, execute push
124
- try {
125
- const result = await executePush(dryRunResult, credentials);
126
- // SYNC-FAIL-1: a failed push must not masquerade as success
127
- const failed = result.errors.length;
128
- const syncedCount = result.created + result.updated;
129
- let output;
130
- if (failed > 0 && syncedCount === 0) {
131
- output = `✗ Push failed: ${failed} document(s) could not be saved.\n\n`;
132
- }
133
- else if (failed > 0) {
134
- output = `⚠ Push incomplete: ${syncedCount} document(s) synced, ${failed} failed.\n\n`;
135
- }
136
- else {
137
- output = "✓ Push complete!\n\n";
138
- }
139
- if (result.created > 0) {
140
- output += `**Created:** ${result.created} document(s)\n`;
141
- }
142
- if (result.updated > 0) {
143
- output += `**Updated:** ${result.updated} document(s)\n`;
144
- }
145
- // IMPORT-3: marker failures are loud but never fatal
146
- if (result.importWarnings.length > 0) {
147
- output += `\n**Import marker warnings:**\n`;
148
- for (const { fileName, status } of result.importWarnings) {
149
- output +=
150
- status === "already_used"
151
- ? `- ⚠ ${fileName}: import marker already used — requirements were saved as natively authored (they count toward the plan's requirement limit). Re-running codebase-to-spec produces a fresh marker.\n`
152
- : `- ⚠ ${fileName}: import marker not recognized — the CLI may need updating. Requirements were saved as natively authored (they count toward the plan's requirement limit).\n`;
153
- }
154
- }
155
- if (result.errors.length > 0) {
156
- output += `\n**Errors:**\n`;
157
- for (const { fileName, error } of result.errors) {
158
- output += `- ${fileName}: ${error}\n`;
159
- }
160
- }
161
- // SYNC-LAND-1: where each synced document lives in the web app
162
- if (result.synced.length > 0) {
163
- output += `\n**Review in dot•requirements:**\n`;
164
- for (const doc of result.synced) {
165
- output += `- ${doc.fileName}: ${doc.url}\n`;
166
- }
167
- }
168
- // SYNC-FAIL-1.2: total failure is an error result, not a success story
169
- if (failed > 0 && syncedCount === 0) {
170
- return { content: [{ type: "text", text: output }], isError: true };
171
- }
172
- return textResponse(output);
173
- }
174
- catch (error) {
175
- return {
176
- content: [
177
- {
178
- type: "text",
179
- text: `✗ Push failed:\n\n${error instanceof Error ? error.message : String(error)}`,
180
- },
181
- ],
182
- isError: true,
183
- };
184
- }
185
- }
186
- //# sourceMappingURL=push.js.map
@@ -1,16 +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 type { HandlerContext, ToolResponse } from "./types.js";
8
- export interface ReportArgs {
9
- source?: "local" | "cloud";
10
- requirementKey?: string;
11
- branch?: string;
12
- sinceTimestamp?: number;
13
- projectId?: string;
14
- }
15
- export declare function handleReport(args: ReportArgs, context: HandlerContext): Promise<ToolResponse>;
16
- //# sourceMappingURL=report.d.ts.map