@popoverai/dotrequirements 0.23.0 → 0.24.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.
- package/README.md +167 -20
- package/dist/cli.js +121 -60
- package/dist/codebase-to-spec/budget.d.ts +53 -0
- package/dist/codebase-to-spec/budget.js +80 -0
- package/dist/codebase-to-spec/cache.d.ts +49 -0
- package/dist/codebase-to-spec/cache.js +54 -0
- package/dist/codebase-to-spec/claude.d.ts +69 -0
- package/dist/codebase-to-spec/claude.js +126 -0
- package/dist/codebase-to-spec/compose.d.ts +49 -0
- package/dist/codebase-to-spec/compose.js +124 -0
- package/dist/codebase-to-spec/edit-loop.d.ts +54 -0
- package/dist/codebase-to-spec/edit-loop.js +195 -0
- package/dist/codebase-to-spec/editor.d.ts +54 -0
- package/dist/codebase-to-spec/editor.js +74 -0
- package/dist/codebase-to-spec/exit-codes.d.ts +40 -0
- package/dist/codebase-to-spec/exit-codes.js +58 -0
- package/dist/codebase-to-spec/fan-out.d.ts +63 -0
- package/dist/codebase-to-spec/fan-out.js +215 -0
- package/dist/codebase-to-spec/interactive.d.ts +30 -0
- package/dist/codebase-to-spec/interactive.js +48 -0
- package/dist/codebase-to-spec/outline-review-loop.d.ts +51 -0
- package/dist/codebase-to-spec/outline-review-loop.js +187 -0
- package/dist/codebase-to-spec/pack.d.ts +51 -0
- package/dist/codebase-to-spec/pack.js +127 -0
- package/dist/codebase-to-spec/planner.d.ts +41 -0
- package/dist/codebase-to-spec/planner.js +76 -0
- package/dist/codebase-to-spec/present.d.ts +94 -0
- package/dist/codebase-to-spec/present.js +288 -0
- package/dist/codebase-to-spec/progress.d.ts +33 -0
- package/dist/codebase-to-spec/progress.js +28 -0
- package/dist/codebase-to-spec/prompts/editor.d.ts +13 -0
- package/dist/codebase-to-spec/prompts/editor.js +57 -0
- package/dist/codebase-to-spec/prompts/outline-reviewer.d.ts +12 -0
- package/dist/codebase-to-spec/prompts/outline-reviewer.js +87 -0
- package/dist/codebase-to-spec/prompts/planner-apply.d.ts +12 -0
- package/dist/codebase-to-spec/prompts/planner-apply.js +32 -0
- package/dist/codebase-to-spec/prompts/planner-initial.d.ts +11 -0
- package/dist/codebase-to-spec/prompts/planner-initial.js +125 -0
- package/dist/codebase-to-spec/prompts/planner-revise.d.ts +14 -0
- package/dist/codebase-to-spec/prompts/planner-revise.js +60 -0
- package/dist/codebase-to-spec/prompts/spec-reviewer.d.ts +16 -0
- package/dist/codebase-to-spec/prompts/spec-reviewer.js +96 -0
- package/dist/codebase-to-spec/prompts/specifier.d.ts +12 -0
- package/dist/codebase-to-spec/prompts/specifier.js +100 -0
- package/dist/codebase-to-spec/prompts/style-check.d.ts +12 -0
- package/dist/codebase-to-spec/prompts/style-check.js +78 -0
- package/dist/codebase-to-spec/schemas.d.ts +257 -0
- package/dist/codebase-to-spec/schemas.js +183 -0
- package/dist/codebase-to-spec/skill-install.d.ts +57 -0
- package/dist/codebase-to-spec/skill-install.js +79 -0
- package/dist/codebase-to-spec/slice.d.ts +49 -0
- package/dist/codebase-to-spec/slice.js +111 -0
- package/dist/codebase-to-spec/specifier.d.ts +60 -0
- package/dist/codebase-to-spec/specifier.js +79 -0
- package/dist/codebase-to-spec/style-check.d.ts +29 -0
- package/dist/codebase-to-spec/style-check.js +33 -0
- package/dist/codebase-to-spec/summary.d.ts +51 -0
- package/dist/codebase-to-spec/summary.js +183 -0
- package/dist/codebase-to-spec/validate.d.ts +46 -0
- package/dist/codebase-to-spec/validate.js +130 -0
- package/dist/commands/acceptance-test.d.ts +6 -0
- package/dist/commands/acceptance-test.js +212 -0
- package/dist/commands/ai-setup.d.ts +5 -0
- package/dist/commands/ai-setup.js +441 -0
- package/dist/commands/browsertest.js +34 -27
- package/dist/commands/codebase-to-spec/compose.d.ts +14 -0
- package/dist/commands/codebase-to-spec/compose.js +57 -0
- package/dist/commands/codebase-to-spec/edit-loop.d.ts +16 -0
- package/dist/commands/codebase-to-spec/edit-loop.js +83 -0
- package/dist/commands/codebase-to-spec/fan-out.d.ts +19 -0
- package/dist/commands/codebase-to-spec/fan-out.js +77 -0
- package/dist/commands/codebase-to-spec/index.d.ts +9 -0
- package/dist/commands/codebase-to-spec/index.js +135 -0
- package/dist/commands/codebase-to-spec/pack.d.ts +22 -0
- package/dist/commands/codebase-to-spec/pack.js +76 -0
- package/dist/commands/codebase-to-spec/plan-loop.d.ts +26 -0
- package/dist/commands/codebase-to-spec/plan-loop.js +105 -0
- package/dist/commands/codebase-to-spec/present.d.ts +21 -0
- package/dist/commands/codebase-to-spec/present.js +92 -0
- package/dist/commands/codebase-to-spec/run.d.ts +20 -0
- package/dist/commands/codebase-to-spec/run.js +85 -0
- package/dist/commands/codebase-to-spec/skill-install.d.ts +20 -0
- package/dist/commands/codebase-to-spec/skill-install.js +51 -0
- package/dist/commands/codebase-to-spec/specify-area.d.ts +18 -0
- package/dist/commands/codebase-to-spec/specify-area.js +82 -0
- package/dist/commands/codebase-to-spec/style-check.d.ts +15 -0
- package/dist/commands/codebase-to-spec/style-check.js +42 -0
- package/dist/commands/codebase-to-spec/validate.d.ts +18 -0
- package/dist/commands/codebase-to-spec/validate.js +38 -0
- package/dist/commands/create-requirement-document.d.ts +2 -0
- package/dist/commands/create-requirement-document.js +41 -0
- package/dist/commands/finalize.js +7 -7
- package/dist/commands/get.d.ts +2 -0
- package/dist/commands/get.js +55 -0
- package/dist/commands/init.js +132 -117
- package/dist/commands/link.js +27 -27
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.js +43 -0
- package/dist/commands/mcp-setup.js +159 -149
- package/dist/commands/mcp.js +1 -1
- package/dist/commands/prepare.js +4 -4
- package/dist/commands/pull.js +116 -121
- package/dist/commands/push.js +106 -112
- package/dist/commands/report.d.ts +6 -2
- package/dist/commands/report.js +177 -122
- package/dist/commands/requirements-for.d.ts +2 -0
- package/dist/commands/requirements-for.js +29 -0
- package/dist/commands/review-test.d.ts +2 -0
- package/dist/commands/review-test.js +75 -0
- package/dist/commands/search.d.ts +6 -0
- package/dist/commands/search.js +39 -0
- package/dist/commands/style-check.d.ts +7 -0
- package/dist/commands/style-check.js +75 -0
- package/dist/commands/test.js +53 -59
- package/dist/commands/tests-for.d.ts +2 -0
- package/dist/commands/tests-for.js +80 -0
- package/dist/commands/validate.d.ts +6 -0
- package/dist/commands/validate.js +72 -0
- package/dist/config.js +1 -1
- package/dist/convex.d.ts +34 -22
- package/dist/convex.js +38 -22
- package/dist/harness/cache.d.ts +1 -5
- package/dist/harness/cache.js +49 -59
- package/dist/harness/convexReporting.d.ts +1 -1
- package/dist/harness/convexReporting.js +9 -7
- package/dist/harness/coverageCache.js +3 -3
- package/dist/harness/finalize.js +59 -46
- package/dist/harness/index.d.ts +6 -7
- package/dist/harness/index.js +9 -10
- package/dist/harness/prepare.js +6 -5
- package/dist/harness/requirementsLoader.d.ts +2 -2
- package/dist/harness/requirementsLoader.js +13 -35
- package/dist/harness/tracking.js +18 -18
- package/dist/harness/types.d.ts +1 -1
- package/dist/mcp/convexClient.d.ts +0 -39
- package/dist/mcp/convexClient.js +2 -107
- package/dist/mcp/grep.d.ts +1 -1
- package/dist/mcp/grep.js +87 -42
- package/dist/mcp/handlers/authoring.d.ts +1 -1
- package/dist/mcp/handlers/authoring.js +30 -234
- package/dist/mcp/handlers/coverage.d.ts +1 -1
- package/dist/mcp/handlers/coverage.js +13 -15
- package/dist/mcp/handlers/debug.d.ts +2 -3
- package/dist/mcp/handlers/debug.js +10 -10
- package/dist/mcp/handlers/get.d.ts +1 -1
- package/dist/mcp/handlers/get.js +11 -10
- package/dist/mcp/handlers/index.d.ts +20 -20
- package/dist/mcp/handlers/index.js +10 -10
- package/dist/mcp/handlers/list.d.ts +4 -33
- package/dist/mcp/handlers/list.js +16 -38
- package/dist/mcp/handlers/push.d.ts +1 -1
- package/dist/mcp/handlers/push.js +28 -18
- package/dist/mcp/handlers/report.d.ts +16 -0
- package/dist/mcp/handlers/report.js +134 -0
- package/dist/mcp/handlers/review.d.ts +1 -1
- package/dist/mcp/handlers/review.js +40 -59
- package/dist/mcp/handlers/search.d.ts +1 -1
- package/dist/mcp/handlers/search.js +7 -9
- package/dist/mcp/handlers/test-mapping.d.ts +1 -1
- package/dist/mcp/handlers/test-mapping.js +14 -14
- package/dist/mcp/handlers/types.d.ts +3 -3
- package/dist/mcp/handlers/types.js +2 -2
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +147 -167
- package/dist/mcp/requirements.d.ts +2 -2
- package/dist/mcp/requirements.js +30 -30
- package/dist/mcp/testCodeExtractor.js +24 -26
- package/dist/mcp/types.d.ts +1 -1
- package/dist/push/core.d.ts +2 -2
- package/dist/push/core.js +20 -20
- package/dist/push/index.d.ts +1 -1
- package/dist/push/index.js +2 -2
- package/dist/requirements/cloud-ai.d.ts +57 -0
- package/dist/requirements/cloud-ai.js +104 -0
- package/dist/requirements/cloud-coverage.d.ts +41 -0
- package/dist/requirements/cloud-coverage.js +60 -0
- package/dist/requirements/coverage.d.ts +45 -0
- package/dist/requirements/coverage.js +114 -0
- package/dist/requirements/grep.d.ts +33 -0
- package/dist/requirements/grep.js +306 -0
- package/dist/requirements/index.d.ts +73 -0
- package/dist/requirements/index.js +174 -0
- package/dist/requirements/style-guide.d.ts +67 -0
- package/dist/requirements/style-guide.js +299 -0
- package/dist/requirements/testCodeExtractor.d.ts +22 -0
- package/dist/requirements/testCodeExtractor.js +150 -0
- package/dist/schema/browser.d.ts +8 -8
- package/dist/schema/browser.js +13 -15
- package/dist/schema/builder.d.ts +1 -1
- package/dist/schema/builder.js +13 -44
- package/dist/schema/conversions.d.ts +2 -2
- package/dist/schema/conversions.js +11 -11
- package/dist/schema/index.d.ts +9 -9
- package/dist/schema/index.js +15 -15
- package/dist/schema/parser-core.d.ts +1 -1
- package/dist/schema/parser-core.js +23 -22
- package/dist/schema/parser.d.ts +3 -3
- package/dist/schema/parser.js +27 -31
- package/dist/schema/resolver.d.ts +1 -1
- package/dist/schema/resolver.js +9 -9
- package/dist/schema/scenario.d.ts +1 -1
- package/dist/schema/scenario.js +1 -1
- package/dist/schema/schemas.d.ts +3 -3
- package/dist/schema/schemas.js +41 -28
- package/dist/schema/test-schema.js +27 -27
- package/dist/templates/context-file-section.md +3 -2
- package/dist/templates/example-requirements.js +1 -1
- package/dist/templates/example-requirements.ts +3 -1
- package/dist/templates/requirements-readme.js +1 -1
- package/dist/templates/requirements-readme.ts +1 -1
- package/dist/templates/skills/codebase-to-spec/SKILL.md +118 -0
- package/dist/utils/brand.js +3 -3
- package/dist/utils/browser-launch.js +4 -4
- package/dist/utils/context-file.d.ts +1 -1
- package/dist/utils/context-file.js +26 -26
- package/dist/utils/env.js +7 -7
- package/dist/utils/gitignore.js +7 -7
- package/dist/utils/oauth-callback-server.d.ts +1 -1
- package/dist/utils/oauth-callback-server.js +27 -25
- package/dist/utils/oauth-flow.js +32 -29
- package/dist/utils/project-discovery.d.ts +3 -3
- package/dist/utils/project-discovery.js +18 -17
- package/dist/utils/project-name.js +8 -8
- package/dist/utils/project-selector.d.ts +1 -1
- package/dist/utils/project-selector.js +24 -21
- package/dist/utils/project-settings.d.ts +1 -1
- package/dist/utils/project-settings.js +24 -22
- package/dist/utils/templates.js +6 -6
- package/package.json +2 -1
package/dist/mcp/requirements.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import * as path from
|
|
2
|
-
import { glob } from
|
|
3
|
-
import {
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { glob } from "glob";
|
|
3
|
+
import { buildRequirementMarkdown, getAllRequirements, parseRequirementsFile, parseRequirementsFromFile, } from "../schema/index.js";
|
|
4
4
|
/**
|
|
5
5
|
* Find all *.requirements.md files in the workspace.
|
|
6
6
|
* Supports both .requirements/ directories and colocated files.
|
|
7
7
|
* Excludes example files, test fixtures, and build artifacts.
|
|
8
8
|
*/
|
|
9
9
|
export async function findRequirementsFiles(workspaceRoot) {
|
|
10
|
-
const pattern =
|
|
10
|
+
const pattern = "**/*.requirements.md";
|
|
11
11
|
const matches = await glob(pattern, {
|
|
12
12
|
cwd: workspaceRoot,
|
|
13
13
|
ignore: [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
"**/node_modules/**",
|
|
15
|
+
"**/dist/**",
|
|
16
|
+
"**/.git/**",
|
|
17
|
+
"**/build/**",
|
|
18
18
|
// Exclude example and test fixture directories
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
"**/example/**",
|
|
20
|
+
"**/examples/**",
|
|
21
|
+
"**/__tests__/**",
|
|
22
|
+
"**/fixtures/**",
|
|
23
|
+
"**/.fixtures/**",
|
|
24
24
|
],
|
|
25
25
|
dot: true, // Include dotfiles/dotdirs like .requirements/
|
|
26
26
|
});
|
|
27
|
-
return matches.map(m => path.join(workspaceRoot, m));
|
|
27
|
+
return matches.map((m) => path.join(workspaceRoot, m));
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Load all requirements from the workspace
|
|
@@ -56,9 +56,9 @@ export function flattenRequirementsFile(file, sourceFile) {
|
|
|
56
56
|
const allReqs = getAllRequirements(file.requirements);
|
|
57
57
|
for (const req of allReqs) {
|
|
58
58
|
// Extract position from ID (e.g., "REQ123.0.1" -> "0.1")
|
|
59
|
-
const idParts = req.id.split(
|
|
59
|
+
const idParts = req.id.split(".");
|
|
60
60
|
const rootId = idParts[0];
|
|
61
|
-
const position = idParts.slice(1).join(
|
|
61
|
+
const position = idParts.slice(1).join(".");
|
|
62
62
|
results.push({
|
|
63
63
|
id: req.id,
|
|
64
64
|
rootId: rootId,
|
|
@@ -76,7 +76,7 @@ export function flattenRequirementsFile(file, sourceFile) {
|
|
|
76
76
|
*/
|
|
77
77
|
export function searchRequirements(requirements, query) {
|
|
78
78
|
const lowerQuery = query.toLowerCase();
|
|
79
|
-
return requirements.filter(req => {
|
|
79
|
+
return requirements.filter((req) => {
|
|
80
80
|
// Search in ID
|
|
81
81
|
if (req.id.toLowerCase().includes(lowerQuery))
|
|
82
82
|
return true;
|
|
@@ -94,24 +94,24 @@ export function searchRequirements(requirements, query) {
|
|
|
94
94
|
*/
|
|
95
95
|
export function getRequirementById(requirements, id) {
|
|
96
96
|
// Exact match first
|
|
97
|
-
const exact = requirements.find(r => r.id === id);
|
|
97
|
+
const exact = requirements.find((r) => r.id === id);
|
|
98
98
|
if (exact)
|
|
99
99
|
return exact;
|
|
100
100
|
// Try partial match (just the root ID)
|
|
101
|
-
return requirements.find(r => r.rootId === id || r.id.startsWith(id
|
|
101
|
+
return requirements.find((r) => r.rootId === id || r.id.startsWith(`${id}.`));
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
104
|
* Get a requirement and all its children
|
|
105
105
|
*/
|
|
106
106
|
export function getRequirementTree(requirements, rootId) {
|
|
107
|
-
return requirements.filter(r => r.rootId === rootId || r.id === rootId);
|
|
107
|
+
return requirements.filter((r) => r.rootId === rootId || r.id === rootId);
|
|
108
108
|
}
|
|
109
109
|
/**
|
|
110
110
|
* Format a requirement for display
|
|
111
111
|
*/
|
|
112
112
|
export function formatRequirement(req) {
|
|
113
|
-
const indent =
|
|
114
|
-
const label = req.label ? ` (${req.label})` :
|
|
113
|
+
const indent = " ".repeat(req.path.length);
|
|
114
|
+
const label = req.label ? ` (${req.label})` : "";
|
|
115
115
|
return `${indent}${req.id}${label}: ${req.content}`;
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
@@ -121,11 +121,11 @@ export function formatRequirement(req) {
|
|
|
121
121
|
*/
|
|
122
122
|
export function filterRequirementsByKeys(fileContents, keys) {
|
|
123
123
|
const { requirements } = parseRequirementsFile(fileContents);
|
|
124
|
-
const upperKeys = keys.map(k => k.toUpperCase());
|
|
125
|
-
const filtered = requirements.filter(r => upperKeys.includes(r.id.toUpperCase()));
|
|
126
|
-
const foundKeys = filtered.map(r => r.id);
|
|
127
|
-
const missingKeys = upperKeys.filter(k => !foundKeys.map(f => f.toUpperCase()).includes(k));
|
|
128
|
-
const filteredContent = filtered.map(buildRequirementMarkdown).join(
|
|
124
|
+
const upperKeys = keys.map((k) => k.toUpperCase());
|
|
125
|
+
const filtered = requirements.filter((r) => upperKeys.includes(r.id.toUpperCase()));
|
|
126
|
+
const foundKeys = filtered.map((r) => r.id);
|
|
127
|
+
const missingKeys = upperKeys.filter((k) => !foundKeys.map((f) => f.toUpperCase()).includes(k));
|
|
128
|
+
const filteredContent = filtered.map(buildRequirementMarkdown).join("\n");
|
|
129
129
|
return { filteredContent, foundKeys, missingKeys };
|
|
130
130
|
}
|
|
131
131
|
/**
|
|
@@ -137,8 +137,8 @@ export function formatRequirementTree(requirements) {
|
|
|
137
137
|
// Compare paths element by element for proper tree order
|
|
138
138
|
const maxLen = Math.max(a.path.length, b.path.length);
|
|
139
139
|
for (let i = 0; i < maxLen; i++) {
|
|
140
|
-
const aVal = i < a.path.length ? parseInt(a.path[i]) : -1;
|
|
141
|
-
const bVal = i < b.path.length ? parseInt(b.path[i]) : -1;
|
|
140
|
+
const aVal = i < a.path.length ? parseInt(a.path[i], 10) : -1;
|
|
141
|
+
const bVal = i < b.path.length ? parseInt(b.path[i], 10) : -1;
|
|
142
142
|
// If one path is a prefix of the other, the shorter one comes first
|
|
143
143
|
if (aVal === -1)
|
|
144
144
|
return -1;
|
|
@@ -150,6 +150,6 @@ export function formatRequirementTree(requirements) {
|
|
|
150
150
|
}
|
|
151
151
|
return 0;
|
|
152
152
|
});
|
|
153
|
-
return sorted.map(formatRequirement).join(
|
|
153
|
+
return sorted.map(formatRequirement).join("\n");
|
|
154
154
|
}
|
|
155
155
|
//# sourceMappingURL=requirements.js.map
|
|
@@ -4,30 +4,32 @@
|
|
|
4
4
|
* Finds requirement() call references and extracts the enclosing
|
|
5
5
|
* meaningful code block (function, describe, test, etc.)
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import * as
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import { parse } from "@babel/parser";
|
|
9
|
+
import traverse from "@babel/traverse";
|
|
10
|
+
import * as t from "@babel/types";
|
|
11
11
|
/**
|
|
12
12
|
* Find all test code blocks that reference a specific requirement
|
|
13
13
|
*/
|
|
14
14
|
export function findTestCodeForRequirement(filePath, requirementId) {
|
|
15
15
|
try {
|
|
16
|
-
const code = fs.readFileSync(filePath,
|
|
16
|
+
const code = fs.readFileSync(filePath, "utf-8");
|
|
17
17
|
const results = [];
|
|
18
18
|
// Parse with TypeScript and JSX support
|
|
19
19
|
const ast = parse(code, {
|
|
20
|
-
sourceType:
|
|
21
|
-
plugins: [
|
|
20
|
+
sourceType: "module",
|
|
21
|
+
plugins: ["typescript", "jsx"],
|
|
22
22
|
errorRecovery: true,
|
|
23
23
|
});
|
|
24
24
|
// Handle both ES module and CommonJS exports
|
|
25
|
-
const traverseFunc =
|
|
25
|
+
const traverseFunc =
|
|
26
|
+
// biome-ignore lint/suspicious/noExplicitAny: @babel/traverse CJS default-export interop (callable function vs namespace import)
|
|
27
|
+
typeof traverse === "function" ? traverse : traverse.default;
|
|
26
28
|
traverseFunc(ast, {
|
|
27
29
|
CallExpression(path) {
|
|
28
30
|
// Check if this is a requirement('ID', ...) call
|
|
29
31
|
const callee = path.node.callee;
|
|
30
|
-
if (t.isIdentifier(callee) && callee.name ===
|
|
32
|
+
if (t.isIdentifier(callee) && callee.name === "requirement") {
|
|
31
33
|
const args = path.node.arguments;
|
|
32
34
|
// Extract all string literal arguments (supports multi-requirement calls)
|
|
33
35
|
const refIds = [];
|
|
@@ -39,12 +41,11 @@ export function findTestCodeForRequirement(filePath, requirementId) {
|
|
|
39
41
|
// Check if any argument matches the requirement we're looking for
|
|
40
42
|
// Match exact ID or if it's a child (e.g., searching for REQ-123 matches REQ-123.0)
|
|
41
43
|
for (const refId of refIds) {
|
|
42
|
-
const isMatch = refId === requirementId ||
|
|
43
|
-
refId.startsWith(`${requirementId}.`);
|
|
44
|
+
const isMatch = refId === requirementId || refId.startsWith(`${requirementId}.`);
|
|
44
45
|
if (isMatch) {
|
|
45
46
|
// Find the meaningful enclosing block
|
|
46
47
|
const contextNode = findMeaningfulParent(path);
|
|
47
|
-
if (contextNode
|
|
48
|
+
if (contextNode?.node.loc) {
|
|
48
49
|
const { start, end } = contextNode.node.loc;
|
|
49
50
|
const nodeStart = contextNode.node.start ?? 0;
|
|
50
51
|
const nodeEnd = contextNode.node.end ?? code.length;
|
|
@@ -91,15 +92,15 @@ function findMeaningfulParent(path) {
|
|
|
91
92
|
const callee = node.callee;
|
|
92
93
|
// Common test framework function names
|
|
93
94
|
const testFunctionNames = [
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
95
|
+
"describe",
|
|
96
|
+
"it",
|
|
97
|
+
"test",
|
|
98
|
+
"suite",
|
|
99
|
+
"context",
|
|
100
|
+
"beforeEach",
|
|
101
|
+
"afterEach",
|
|
102
|
+
"beforeAll",
|
|
103
|
+
"afterAll",
|
|
103
104
|
];
|
|
104
105
|
if (t.isIdentifier(callee) && testFunctionNames.includes(callee.name)) {
|
|
105
106
|
return current;
|
|
@@ -125,7 +126,7 @@ export function findFilesWithRequirement(files, requirementId) {
|
|
|
125
126
|
const matchingFiles = [];
|
|
126
127
|
for (const file of files) {
|
|
127
128
|
try {
|
|
128
|
-
const code = fs.readFileSync(file,
|
|
129
|
+
const code = fs.readFileSync(file, "utf-8");
|
|
129
130
|
// Check for exact match or child references (e.g., AUTH-VALID-LOGIN or AUTH-VALID-LOGIN.0)
|
|
130
131
|
// Simple string search first for performance
|
|
131
132
|
// Patterns match both single and multi-arg calls:
|
|
@@ -142,10 +143,7 @@ export function findFilesWithRequirement(files, requirementId) {
|
|
|
142
143
|
matchingFiles.push(file);
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
// Skip files that can't be read
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
146
|
+
catch (error) { }
|
|
149
147
|
}
|
|
150
148
|
return matchingFiles;
|
|
151
149
|
}
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Re-export shared types from CLI schema module
|
|
3
3
|
*/
|
|
4
|
-
export type { Metadata, RequirementNode, RequirementsFile, } from
|
|
4
|
+
export type { Metadata, RequirementNode, RequirementsFile, } from "../schema/index.js";
|
|
5
5
|
/**
|
|
6
6
|
* Flattened requirement for search results
|
|
7
7
|
*/
|
package/dist/push/core.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - Executing the push
|
|
10
10
|
* - Updating local files with document IDs and timestamps
|
|
11
11
|
*/
|
|
12
|
-
import type { Metadata } from
|
|
12
|
+
import type { Metadata } from "../schema/index.js";
|
|
13
13
|
export interface PushCredentials {
|
|
14
14
|
projectId: string;
|
|
15
15
|
projectSecret: string;
|
|
@@ -41,7 +41,7 @@ export interface CloudDocumentMetadata {
|
|
|
41
41
|
*/
|
|
42
42
|
export interface DryRunResultItem {
|
|
43
43
|
dryRun: true;
|
|
44
|
-
action:
|
|
44
|
+
action: "create" | "update" | "not_found" | "invalid";
|
|
45
45
|
documentId?: string;
|
|
46
46
|
title?: string;
|
|
47
47
|
warning?: string;
|
package/dist/push/core.js
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
* - Executing the push
|
|
10
10
|
* - Updating local files with document IDs and timestamps
|
|
11
11
|
*/
|
|
12
|
-
import * as fs from
|
|
13
|
-
import * as path from
|
|
14
|
-
import { ConvexHttpClient } from
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
import * as path from "node:path";
|
|
14
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
15
|
+
import { api } from "../convex.js";
|
|
16
|
+
import { buildRequirementsFile, getAllRequirements, parseRequirementKey, parseRequirementsFromFile, } from "../schema/index.js";
|
|
17
17
|
// ============================================================================
|
|
18
18
|
// Parsing
|
|
19
19
|
// ============================================================================
|
|
@@ -36,7 +36,7 @@ export function parseFilesForPush(filePaths) {
|
|
|
36
36
|
let totalRequirements = 0;
|
|
37
37
|
for (const filePath of filePaths) {
|
|
38
38
|
// Read raw file content
|
|
39
|
-
const rawContent = fs.readFileSync(filePath,
|
|
39
|
+
const rawContent = fs.readFileSync(filePath, "utf-8");
|
|
40
40
|
// Parse to get metadata and requirements
|
|
41
41
|
const parsed = parseRequirementsFromFile(filePath);
|
|
42
42
|
const flatRequirements = getAllRequirements(parsed.requirements);
|
|
@@ -82,9 +82,9 @@ export async function dryRunPush(parsedFiles, credentials) {
|
|
|
82
82
|
file,
|
|
83
83
|
result: {
|
|
84
84
|
dryRun: true,
|
|
85
|
-
action:
|
|
85
|
+
action: "invalid",
|
|
86
86
|
title: fileName,
|
|
87
|
-
error:
|
|
87
|
+
error: "Missing document section in frontmatter",
|
|
88
88
|
},
|
|
89
89
|
});
|
|
90
90
|
continue;
|
|
@@ -95,7 +95,7 @@ export async function dryRunPush(parsedFiles, credentials) {
|
|
|
95
95
|
projectSlug: credentials.projectId,
|
|
96
96
|
projectSecret: credentials.projectSecret,
|
|
97
97
|
},
|
|
98
|
-
target: { type:
|
|
98
|
+
target: { type: "project", slug: credentials.projectId },
|
|
99
99
|
documentId: doc.id,
|
|
100
100
|
title: doc.title,
|
|
101
101
|
markdownContent: file.markdownContent,
|
|
@@ -109,7 +109,7 @@ export async function dryRunPush(parsedFiles, credentials) {
|
|
|
109
109
|
file,
|
|
110
110
|
result: {
|
|
111
111
|
dryRun: true,
|
|
112
|
-
action:
|
|
112
|
+
action: "invalid",
|
|
113
113
|
title: doc.title,
|
|
114
114
|
error: err.message,
|
|
115
115
|
},
|
|
@@ -117,10 +117,10 @@ export async function dryRunPush(parsedFiles, credentials) {
|
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
119
|
// Categorize results
|
|
120
|
-
const updates = dryRunResults.filter((r) => r.result.action ===
|
|
121
|
-
const creates = dryRunResults.filter((r) => r.result.action ===
|
|
122
|
-
const notFound = dryRunResults.filter((r) => r.result.action ===
|
|
123
|
-
const invalid = dryRunResults.filter((r) => r.result.action ===
|
|
120
|
+
const updates = dryRunResults.filter((r) => r.result.action === "update");
|
|
121
|
+
const creates = dryRunResults.filter((r) => r.result.action === "create");
|
|
122
|
+
const notFound = dryRunResults.filter((r) => r.result.action === "not_found");
|
|
123
|
+
const invalid = dryRunResults.filter((r) => r.result.action === "invalid");
|
|
124
124
|
// Check for conflicts on updates (cloud changed since last pull)
|
|
125
125
|
const conflicts = [];
|
|
126
126
|
if (updates.length > 0) {
|
|
@@ -130,7 +130,7 @@ export async function dryRunPush(parsedFiles, credentials) {
|
|
|
130
130
|
projectSlug: credentials.projectId,
|
|
131
131
|
projectSecret: credentials.projectSecret,
|
|
132
132
|
},
|
|
133
|
-
target: { type:
|
|
133
|
+
target: { type: "project", slug: credentials.projectId },
|
|
134
134
|
documentIds: docIds,
|
|
135
135
|
});
|
|
136
136
|
const cloudMetaByDocId = new Map(cloudMetadata.map((m) => [m.documentId, m]));
|
|
@@ -174,28 +174,28 @@ export async function executePush(dryRunResult, credentials) {
|
|
|
174
174
|
const doc = file.metadata.document;
|
|
175
175
|
const fileName = path.basename(file.filePath);
|
|
176
176
|
// For not_found, clear the ID so we create a new document
|
|
177
|
-
const effectiveDocId = result.action ===
|
|
177
|
+
const effectiveDocId = result.action === "not_found" ? undefined : doc.id;
|
|
178
178
|
try {
|
|
179
179
|
const pushResult = (await client.mutation(api.documents.saveWithRequirements.saveWithRequirements, {
|
|
180
180
|
projectAuth: {
|
|
181
181
|
projectSlug: credentials.projectId,
|
|
182
182
|
projectSecret: credentials.projectSecret,
|
|
183
183
|
},
|
|
184
|
-
target: { type:
|
|
184
|
+
target: { type: "project", slug: credentials.projectId },
|
|
185
185
|
documentId: effectiveDocId,
|
|
186
186
|
title: doc.title,
|
|
187
187
|
markdownContent: file.markdownContent,
|
|
188
188
|
defaultPrefix: doc.defaultPrefix,
|
|
189
189
|
dryRun: false,
|
|
190
190
|
}));
|
|
191
|
-
const isCreate = result.action ===
|
|
191
|
+
const isCreate = result.action === "create" || result.action === "not_found";
|
|
192
192
|
if (isCreate) {
|
|
193
193
|
// New document - write ID back to file
|
|
194
194
|
doc.id = pushResult;
|
|
195
195
|
file.metadata.pulledAt = new Date().toISOString();
|
|
196
196
|
file.metadata.version = 1;
|
|
197
197
|
const updatedContent = buildRequirementsFile(file.metadata, file.markdownContent);
|
|
198
|
-
fs.writeFileSync(file.filePath, updatedContent,
|
|
198
|
+
fs.writeFileSync(file.filePath, updatedContent, "utf-8");
|
|
199
199
|
created++;
|
|
200
200
|
}
|
|
201
201
|
else {
|
|
@@ -203,7 +203,7 @@ export async function executePush(dryRunResult, credentials) {
|
|
|
203
203
|
file.metadata.pulledAt = new Date().toISOString();
|
|
204
204
|
file.metadata.version = (file.metadata.version || 0) + 1;
|
|
205
205
|
const updatedContent = buildRequirementsFile(file.metadata, file.markdownContent);
|
|
206
|
-
fs.writeFileSync(file.filePath, updatedContent,
|
|
206
|
+
fs.writeFileSync(file.filePath, updatedContent, "utf-8");
|
|
207
207
|
updated++;
|
|
208
208
|
}
|
|
209
209
|
}
|
package/dist/push/index.d.ts
CHANGED
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* Shared push logic for syncing local requirements files to the cloud.
|
|
5
5
|
* Used by both CLI push command and MCP push_requirements tool.
|
|
6
6
|
*/
|
|
7
|
-
export { type
|
|
7
|
+
export { type CloudDocumentMetadata, type ConflictInfo, type DryRunResult, type DryRunResultItem, dryRunPush, executePush, extractMarkdownContent, type FileWithDryRun, type ParsedFile, type PushCredentials, type PushResult, parseFilesForPush, } from "./core.js";
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/push/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Shared push logic for syncing local requirements files to the cloud.
|
|
5
5
|
* Used by both CLI push command and MCP push_requirements tool.
|
|
6
6
|
*/
|
|
7
|
-
export {
|
|
7
|
+
export { dryRunPush, executePush,
|
|
8
8
|
// Functions
|
|
9
|
-
extractMarkdownContent, parseFilesForPush,
|
|
9
|
+
extractMarkdownContent, parseFilesForPush, } from "./core.js";
|
|
10
10
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud-AI library — hosted endpoints for style review, test review, and
|
|
3
|
+
* project context retrieval. Shared between the MCP handlers and the CLI
|
|
4
|
+
* verbs that wrap them.
|
|
5
|
+
*
|
|
6
|
+
* Each function does one cloud call and returns the unwrapped result (or
|
|
7
|
+
* throws on failure). Surface-specific concerns (error formatting, exit
|
|
8
|
+
* codes, MCP tool responses) live in the callers.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Default base URL for the hosted AI endpoints (`/api/style-check`,
|
|
12
|
+
* `/api/review-test`). Overridable via the `apiBaseUrl` argument or
|
|
13
|
+
* the `DOTREQUIREMENTS_API_URL` environment variable in callers.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_API_BASE_URL = "https://app.dotrequirements.io";
|
|
16
|
+
export interface StyleCheckParams {
|
|
17
|
+
apiBaseUrl: string;
|
|
18
|
+
projectId: string;
|
|
19
|
+
projectSecret: string;
|
|
20
|
+
fileContents: string;
|
|
21
|
+
fileType: "requirements" | "test";
|
|
22
|
+
model?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* POST to `/api/style-check`. Returns the feedback text on success;
|
|
26
|
+
* throws an Error with the underlying failure reason on a non-OK
|
|
27
|
+
* response or a network error.
|
|
28
|
+
*/
|
|
29
|
+
export declare function fetchStyleCheckFeedback(params: StyleCheckParams): Promise<string>;
|
|
30
|
+
export interface ReviewTestParams {
|
|
31
|
+
apiBaseUrl: string;
|
|
32
|
+
projectId: string;
|
|
33
|
+
projectSecret: string;
|
|
34
|
+
testFileContents: string;
|
|
35
|
+
requirements: Array<{
|
|
36
|
+
id: string;
|
|
37
|
+
content: string;
|
|
38
|
+
testedIds: string[];
|
|
39
|
+
}>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* POST to `/api/review-test`. Returns the feedback text on success;
|
|
43
|
+
* throws an Error with the underlying failure reason on a non-OK
|
|
44
|
+
* response or a network error.
|
|
45
|
+
*/
|
|
46
|
+
export declare function fetchReviewTestFeedback(params: ReviewTestParams): Promise<string>;
|
|
47
|
+
export interface ProjectContext {
|
|
48
|
+
projectContext: string | null;
|
|
49
|
+
requirementsStyleContext: string | null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Query Convex for project-level AI context (project description and
|
|
53
|
+
* requirements style guidance). Returns null on any failure — the caller
|
|
54
|
+
* is expected to degrade gracefully if context is unavailable.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getProjectContext(projectId: string, projectSecret: string, convexUrl: string): Promise<ProjectContext | null>;
|
|
57
|
+
//# sourceMappingURL=cloud-ai.d.ts.map
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud-AI library — hosted endpoints for style review, test review, and
|
|
3
|
+
* project context retrieval. Shared between the MCP handlers and the CLI
|
|
4
|
+
* verbs that wrap them.
|
|
5
|
+
*
|
|
6
|
+
* Each function does one cloud call and returns the unwrapped result (or
|
|
7
|
+
* throws on failure). Surface-specific concerns (error formatting, exit
|
|
8
|
+
* codes, MCP tool responses) live in the callers.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Default base URL for the hosted AI endpoints (`/api/style-check`,
|
|
12
|
+
* `/api/review-test`). Overridable via the `apiBaseUrl` argument or
|
|
13
|
+
* the `DOTREQUIREMENTS_API_URL` environment variable in callers.
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_API_BASE_URL = "https://app.dotrequirements.io";
|
|
16
|
+
/**
|
|
17
|
+
* POST to `/api/style-check`. Returns the feedback text on success;
|
|
18
|
+
* throws an Error with the underlying failure reason on a non-OK
|
|
19
|
+
* response or a network error.
|
|
20
|
+
*/
|
|
21
|
+
export async function fetchStyleCheckFeedback(params) {
|
|
22
|
+
const response = await fetch(`${params.apiBaseUrl}/api/style-check`, {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "Content-Type": "application/json" },
|
|
25
|
+
body: JSON.stringify({
|
|
26
|
+
projectId: params.projectId,
|
|
27
|
+
projectSecret: params.projectSecret,
|
|
28
|
+
fileContents: params.fileContents,
|
|
29
|
+
fileType: params.fileType,
|
|
30
|
+
model: params.model,
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
35
|
+
throw new Error(errorData.error || response.statusText);
|
|
36
|
+
}
|
|
37
|
+
const data = (await response.json());
|
|
38
|
+
return data.feedback;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* POST to `/api/review-test`. Returns the feedback text on success;
|
|
42
|
+
* throws an Error with the underlying failure reason on a non-OK
|
|
43
|
+
* response or a network error.
|
|
44
|
+
*/
|
|
45
|
+
export async function fetchReviewTestFeedback(params) {
|
|
46
|
+
const response = await fetch(`${params.apiBaseUrl}/api/review-test`, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: { "Content-Type": "application/json" },
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
projectId: params.projectId,
|
|
51
|
+
projectSecret: params.projectSecret,
|
|
52
|
+
testFileContents: params.testFileContents,
|
|
53
|
+
requirements: params.requirements,
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const errorData = (await response.json().catch(() => ({})));
|
|
58
|
+
throw new Error(errorData.error || response.statusText);
|
|
59
|
+
}
|
|
60
|
+
const data = (await response.json());
|
|
61
|
+
return data.feedback;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Query Convex for project-level AI context (project description and
|
|
65
|
+
* requirements style guidance). Returns null on any failure — the caller
|
|
66
|
+
* is expected to degrade gracefully if context is unavailable.
|
|
67
|
+
*/
|
|
68
|
+
export async function getProjectContext(projectId, projectSecret, convexUrl) {
|
|
69
|
+
try {
|
|
70
|
+
const response = await fetch(`${convexUrl}/api/query`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: { "Content-Type": "application/json" },
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
path: "projects/queries:get",
|
|
75
|
+
args: {
|
|
76
|
+
projectAuth: {
|
|
77
|
+
projectSlug: projectId,
|
|
78
|
+
projectSecret,
|
|
79
|
+
},
|
|
80
|
+
target: {
|
|
81
|
+
type: "project",
|
|
82
|
+
slug: projectId,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
format: "json",
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const json = (await response.json());
|
|
92
|
+
if (json.status === "error" || !json.value) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
projectContext: json.value.projectContext ?? null,
|
|
97
|
+
requirementsStyleContext: json.value.requirementsStyleContext ?? null,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=cloud-ai.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud-coverage library — hosted endpoints for querying persisted test
|
|
3
|
+
* coverage from dot•requirements cloud. Shared between the MCP `report`
|
|
4
|
+
* tool and the CLI `report` verb's `--source cloud` mode.
|
|
5
|
+
*/
|
|
6
|
+
export interface RequirementCoverageRecord {
|
|
7
|
+
requirementKey: string;
|
|
8
|
+
lastTestedAt: number | null;
|
|
9
|
+
branch: string | null;
|
|
10
|
+
testFile: string | null;
|
|
11
|
+
testLine: number | null;
|
|
12
|
+
allBranches: Array<{
|
|
13
|
+
branch: string;
|
|
14
|
+
lastTestedAt: number;
|
|
15
|
+
testFile?: string;
|
|
16
|
+
testLine?: number;
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
export interface ProjectCoverageRecord {
|
|
20
|
+
tested: Array<{
|
|
21
|
+
requirementKey: string;
|
|
22
|
+
lastTestedAt: number;
|
|
23
|
+
branch: string;
|
|
24
|
+
testFile?: string;
|
|
25
|
+
testLine?: number;
|
|
26
|
+
}>;
|
|
27
|
+
untested: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Query cloud for coverage on a single requirement.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getRequirementCoverage(requirementKey: string, projectId: string, projectSecret: string, convexUrl: string): Promise<RequirementCoverageRecord>;
|
|
33
|
+
/**
|
|
34
|
+
* Query cloud for project-wide coverage summary, optionally filtered by
|
|
35
|
+
* branch or recorded-since timestamp.
|
|
36
|
+
*/
|
|
37
|
+
export declare function getProjectCoverage(projectId: string, projectSecret: string, convexUrl: string, options?: {
|
|
38
|
+
branch?: string;
|
|
39
|
+
sinceTimestamp?: number;
|
|
40
|
+
}): Promise<ProjectCoverageRecord>;
|
|
41
|
+
//# sourceMappingURL=cloud-coverage.d.ts.map
|