@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/harness/cache.js
CHANGED
|
@@ -6,25 +6,26 @@
|
|
|
6
6
|
* - tracking.jsonl: Append-only tracking of requirement() calls (cross-process safe)
|
|
7
7
|
* - coverage.json: Deduplication cache for cloud reporting
|
|
8
8
|
*/
|
|
9
|
-
import * as fs from
|
|
10
|
-
import * as path from
|
|
11
|
-
import {
|
|
9
|
+
import * as fs from "node:fs";
|
|
10
|
+
import * as path from "node:path";
|
|
11
|
+
import { findRequirementsFilesSync } from "../requirements/index.js";
|
|
12
12
|
// Cache directory structure
|
|
13
|
-
const CACHE_DIR =
|
|
14
|
-
const LOOKUP_FILE =
|
|
15
|
-
const TRACKING_FILE =
|
|
16
|
-
const COVERAGE_FILE =
|
|
17
|
-
const PROJECT_ROOT_FILE =
|
|
13
|
+
const CACHE_DIR = ".cache";
|
|
14
|
+
const LOOKUP_FILE = "lookup.json";
|
|
15
|
+
const TRACKING_FILE = "tracking.jsonl";
|
|
16
|
+
const COVERAGE_FILE = "coverage.json";
|
|
17
|
+
const PROJECT_ROOT_FILE = "project-root";
|
|
18
18
|
// Test run ID file (outside cache, in .requirements/)
|
|
19
|
-
const TEST_RUN_ID_FILE =
|
|
19
|
+
const TEST_RUN_ID_FILE = ".test-run-id";
|
|
20
20
|
/**
|
|
21
21
|
* Find the nearest .requirements directory by walking up from startDir
|
|
22
22
|
*/
|
|
23
23
|
export function findRequirementsDir(startDir = process.cwd()) {
|
|
24
24
|
let currentDir = path.resolve(startDir);
|
|
25
25
|
while (true) {
|
|
26
|
-
const requirementsDir = path.join(currentDir,
|
|
27
|
-
if (fs.existsSync(requirementsDir) &&
|
|
26
|
+
const requirementsDir = path.join(currentDir, ".requirements");
|
|
27
|
+
if (fs.existsSync(requirementsDir) &&
|
|
28
|
+
fs.statSync(requirementsDir).isDirectory()) {
|
|
28
29
|
return requirementsDir;
|
|
29
30
|
}
|
|
30
31
|
const parentDir = path.dirname(currentDir);
|
|
@@ -52,28 +53,6 @@ export function getCacheDir(requirementsDir, create = false) {
|
|
|
52
53
|
}
|
|
53
54
|
return cacheDir;
|
|
54
55
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Find all *.requirements.md files under project root
|
|
57
|
-
*/
|
|
58
|
-
export function findRequirementsFiles(projectRoot) {
|
|
59
|
-
const pattern = '**/*.requirements.md';
|
|
60
|
-
const matches = globSync(pattern, {
|
|
61
|
-
cwd: projectRoot,
|
|
62
|
-
ignore: [
|
|
63
|
-
'**/node_modules/**',
|
|
64
|
-
'**/dist/**',
|
|
65
|
-
'**/.git/**',
|
|
66
|
-
'**/build/**',
|
|
67
|
-
'**/example/**',
|
|
68
|
-
'**/examples/**',
|
|
69
|
-
'**/__tests__/**',
|
|
70
|
-
'**/fixtures/**',
|
|
71
|
-
'**/.fixtures/**',
|
|
72
|
-
],
|
|
73
|
-
dot: true, // Include dotfiles/dotdirs like .requirements/
|
|
74
|
-
});
|
|
75
|
-
return matches.map(m => path.join(projectRoot, m));
|
|
76
|
-
}
|
|
77
56
|
/**
|
|
78
57
|
* Write the lookup cache with all pre-parsed requirements
|
|
79
58
|
*/
|
|
@@ -101,14 +80,15 @@ export function writeLookupCache(requirementsDir, requirements) {
|
|
|
101
80
|
const labelCounts = new Map();
|
|
102
81
|
for (const child of node.children) {
|
|
103
82
|
let childLabelPath = null;
|
|
104
|
-
if (child.label && child.label !==
|
|
105
|
-
const normalizedLabel = child.label.toLowerCase().replace(/\s+/g,
|
|
83
|
+
if (child.label && child.label !== "requirementHeader") {
|
|
84
|
+
const normalizedLabel = child.label.toLowerCase().replace(/\s+/g, "-");
|
|
106
85
|
const count = labelCounts.get(normalizedLabel) || 0;
|
|
107
86
|
labelCounts.set(normalizedLabel, count + 1);
|
|
108
87
|
const parentPath = labelPath || node.id;
|
|
109
|
-
childLabelPath =
|
|
110
|
-
|
|
111
|
-
|
|
88
|
+
childLabelPath =
|
|
89
|
+
count === 0
|
|
90
|
+
? `${parentPath}.${normalizedLabel}`
|
|
91
|
+
: `${parentPath}.${normalizedLabel}#${count}`;
|
|
112
92
|
}
|
|
113
93
|
flatten(child, childLabelPath);
|
|
114
94
|
}
|
|
@@ -124,7 +104,7 @@ export function writeLookupCache(requirementsDir, requirements) {
|
|
|
124
104
|
*/
|
|
125
105
|
export function isCacheStale(requirementsDir, cacheMtime) {
|
|
126
106
|
const projectRoot = path.dirname(requirementsDir);
|
|
127
|
-
const sourceFiles =
|
|
107
|
+
const sourceFiles = findRequirementsFilesSync(projectRoot);
|
|
128
108
|
for (const file of sourceFiles) {
|
|
129
109
|
try {
|
|
130
110
|
const stat = fs.statSync(file);
|
|
@@ -159,7 +139,7 @@ export function readLookupCache(requirementsDir) {
|
|
|
159
139
|
return null;
|
|
160
140
|
}
|
|
161
141
|
try {
|
|
162
|
-
const content = fs.readFileSync(lookupPath,
|
|
142
|
+
const content = fs.readFileSync(lookupPath, "utf-8");
|
|
163
143
|
return JSON.parse(content);
|
|
164
144
|
}
|
|
165
145
|
catch {
|
|
@@ -183,7 +163,7 @@ export function getTestRunId(requirementsDir) {
|
|
|
183
163
|
if (!fs.existsSync(testRunIdPath)) {
|
|
184
164
|
return null;
|
|
185
165
|
}
|
|
186
|
-
return fs.readFileSync(testRunIdPath,
|
|
166
|
+
return fs.readFileSync(testRunIdPath, "utf-8").trim();
|
|
187
167
|
}
|
|
188
168
|
/**
|
|
189
169
|
* Clean up the test run ID file
|
|
@@ -212,7 +192,7 @@ export function readProjectRoot(requirementsDir) {
|
|
|
212
192
|
if (!fs.existsSync(projectRootPath)) {
|
|
213
193
|
return null;
|
|
214
194
|
}
|
|
215
|
-
return fs.readFileSync(projectRootPath,
|
|
195
|
+
return fs.readFileSync(projectRootPath, "utf-8").trim();
|
|
216
196
|
}
|
|
217
197
|
/**
|
|
218
198
|
* Try to find the project root from any known .requirements cache directory.
|
|
@@ -221,10 +201,10 @@ export function readProjectRoot(requirementsDir) {
|
|
|
221
201
|
export function findCachedProjectRoot(startDir = process.cwd()) {
|
|
222
202
|
let currentDir = path.resolve(startDir);
|
|
223
203
|
while (true) {
|
|
224
|
-
const requirementsDir = path.join(currentDir,
|
|
204
|
+
const requirementsDir = path.join(currentDir, ".requirements");
|
|
225
205
|
const projectRootPath = path.join(requirementsDir, CACHE_DIR, PROJECT_ROOT_FILE);
|
|
226
206
|
if (fs.existsSync(projectRootPath)) {
|
|
227
|
-
return fs.readFileSync(projectRootPath,
|
|
207
|
+
return fs.readFileSync(projectRootPath, "utf-8").trim();
|
|
228
208
|
}
|
|
229
209
|
const parentDir = path.dirname(currentDir);
|
|
230
210
|
if (parentDir === currentDir) {
|
|
@@ -249,7 +229,7 @@ export function clearTrackingFile(requirementsDir) {
|
|
|
249
229
|
export function appendTrackingEntry(requirementsDir, entry) {
|
|
250
230
|
const cacheDir = getCacheDir(requirementsDir, true);
|
|
251
231
|
const trackingPath = path.join(cacheDir, TRACKING_FILE);
|
|
252
|
-
const line = JSON.stringify(entry)
|
|
232
|
+
const line = `${JSON.stringify(entry)}\n`;
|
|
253
233
|
fs.appendFileSync(trackingPath, line);
|
|
254
234
|
}
|
|
255
235
|
/**
|
|
@@ -261,9 +241,9 @@ export function readTrackingEntries(requirementsDir) {
|
|
|
261
241
|
if (!fs.existsSync(trackingPath)) {
|
|
262
242
|
return [];
|
|
263
243
|
}
|
|
264
|
-
const content = fs.readFileSync(trackingPath,
|
|
244
|
+
const content = fs.readFileSync(trackingPath, "utf-8");
|
|
265
245
|
const entries = [];
|
|
266
|
-
for (const line of content.split(
|
|
246
|
+
for (const line of content.split("\n")) {
|
|
267
247
|
if (line.trim()) {
|
|
268
248
|
try {
|
|
269
249
|
entries.push(JSON.parse(line));
|
|
@@ -294,20 +274,28 @@ export function deleteTrackingFile(requirementsDir) {
|
|
|
294
274
|
* can treat both shapes uniformly.
|
|
295
275
|
*/
|
|
296
276
|
function normalizeEntry(raw) {
|
|
297
|
-
if (!raw || typeof raw !==
|
|
277
|
+
if (!raw || typeof raw !== "object")
|
|
278
|
+
return null;
|
|
279
|
+
// Cache entry shape from disk; the guards below check each field at runtime.
|
|
280
|
+
const entry = raw;
|
|
281
|
+
if (typeof entry.testRunId !== "string")
|
|
282
|
+
return null;
|
|
283
|
+
if (typeof entry.timestamp !== "number")
|
|
298
284
|
return null;
|
|
299
|
-
if (Array.isArray(
|
|
285
|
+
if (Array.isArray(entry.tuples)) {
|
|
300
286
|
return {
|
|
301
|
-
testRunId:
|
|
302
|
-
timestamp:
|
|
303
|
-
tuples:
|
|
287
|
+
testRunId: entry.testRunId,
|
|
288
|
+
timestamp: entry.timestamp,
|
|
289
|
+
tuples: entry.tuples,
|
|
304
290
|
};
|
|
305
291
|
}
|
|
306
|
-
if (Array.isArray(
|
|
292
|
+
if (Array.isArray(entry.requirementKeys)) {
|
|
307
293
|
return {
|
|
308
|
-
testRunId:
|
|
309
|
-
timestamp:
|
|
310
|
-
tuples:
|
|
294
|
+
testRunId: entry.testRunId,
|
|
295
|
+
timestamp: entry.timestamp,
|
|
296
|
+
tuples: entry.requirementKeys.map((requirementKey) => ({
|
|
297
|
+
requirementKey,
|
|
298
|
+
})),
|
|
311
299
|
};
|
|
312
300
|
}
|
|
313
301
|
return null;
|
|
@@ -319,7 +307,7 @@ export function readCoverageCache(requirementsDir) {
|
|
|
319
307
|
return { current: null, previous: null };
|
|
320
308
|
}
|
|
321
309
|
try {
|
|
322
|
-
const content = fs.readFileSync(coveragePath,
|
|
310
|
+
const content = fs.readFileSync(coveragePath, "utf-8");
|
|
323
311
|
const raw = JSON.parse(content);
|
|
324
312
|
return {
|
|
325
313
|
current: normalizeEntry(raw?.current),
|
|
@@ -337,7 +325,7 @@ export function readCoverageCache(requirementsDir) {
|
|
|
337
325
|
export function updateCoverageCache(requirementsDir, testRunId, tuples) {
|
|
338
326
|
const cacheDir = getCacheDir(requirementsDir, true);
|
|
339
327
|
const coveragePath = path.join(cacheDir, COVERAGE_FILE);
|
|
340
|
-
const normalized = tuples.map((t) => typeof t ===
|
|
328
|
+
const normalized = tuples.map((t) => typeof t === "string" ? { requirementKey: t } : t);
|
|
341
329
|
const existing = readCoverageCache(requirementsDir);
|
|
342
330
|
const newCache = {
|
|
343
331
|
current: {
|
|
@@ -360,7 +348,9 @@ function tuplesMatch(a, b) {
|
|
|
360
348
|
* Returns true if no matching tuple was reported within the debounce window.
|
|
361
349
|
*/
|
|
362
350
|
export function needsReporting(tupleOrKey, cache) {
|
|
363
|
-
const tuple = typeof tupleOrKey ===
|
|
351
|
+
const tuple = typeof tupleOrKey === "string"
|
|
352
|
+
? { requirementKey: tupleOrKey }
|
|
353
|
+
: tupleOrKey;
|
|
364
354
|
// If no current run, everything needs reporting
|
|
365
355
|
if (!cache.current) {
|
|
366
356
|
return true;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { execSync } from "child_process";
|
|
2
|
-
import { getTrackedRequirements } from "./tracking.js";
|
|
3
|
-
import { saveCache, getRequirementsToReport } from "./coverageCache.js";
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
4
2
|
import { getProjectInfo } from "../utils/project-settings.js";
|
|
3
|
+
import { getRequirementsToReport, saveCache } from "./coverageCache.js";
|
|
4
|
+
import { getTrackedRequirements } from "./tracking.js";
|
|
5
5
|
/**
|
|
6
6
|
* Get the current git branch, or null if not in a git repo
|
|
7
7
|
*/
|
|
@@ -14,7 +14,7 @@ export function getCurrentBranch(cwd = process.cwd()) {
|
|
|
14
14
|
}).trim();
|
|
15
15
|
return branch;
|
|
16
16
|
}
|
|
17
|
-
catch
|
|
17
|
+
catch {
|
|
18
18
|
// Not in a git repo or git not available
|
|
19
19
|
return "unknown";
|
|
20
20
|
}
|
|
@@ -22,7 +22,7 @@ export function getCurrentBranch(cwd = process.cwd()) {
|
|
|
22
22
|
/**
|
|
23
23
|
* Production Convex deployment URL
|
|
24
24
|
*/
|
|
25
|
-
const CONVEX_URL =
|
|
25
|
+
const CONVEX_URL = "https://data.dotrequirements.io";
|
|
26
26
|
/**
|
|
27
27
|
* Extract file path and line number from caller location string
|
|
28
28
|
*/
|
|
@@ -53,7 +53,9 @@ export async function reportCoverageToConvex(cwd = process.cwd(), trackedReqs) {
|
|
|
53
53
|
// Get project info from .requirements/project-settings.json
|
|
54
54
|
const projectInfo = getProjectInfo(cwd);
|
|
55
55
|
// Skip if no project found or not connected to cloud
|
|
56
|
-
if (!projectInfo ||
|
|
56
|
+
if (!projectInfo ||
|
|
57
|
+
projectInfo.status !== "cloud-connected" ||
|
|
58
|
+
!projectInfo.credentials) {
|
|
57
59
|
console.log("\nℹ️ Skipping cloud coverage reporting (project not connected to cloud)");
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
@@ -113,7 +115,7 @@ export async function reportCoverageToConvex(cwd = process.cwd(), trackedReqs) {
|
|
|
113
115
|
console.warn(`\n⚠️ Failed to report coverage to cloud: ${response.status} ${error}`);
|
|
114
116
|
return;
|
|
115
117
|
}
|
|
116
|
-
|
|
118
|
+
await response.json();
|
|
117
119
|
console.log(`\n✓ Reported ${keysToReport.length} requirement(s) to cloud (branch: ${branch})`);
|
|
118
120
|
// Update cache with current test run
|
|
119
121
|
saveCache({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync
|
|
2
|
-
import { join } from "path";
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
3
|
import { v4 as uuidv4 } from "uuid";
|
|
4
4
|
const CACHE_FILE = ".requirements/.coverage-cache.json";
|
|
5
5
|
const STALENESS_THRESHOLD_MS = 4 * 60 * 60 * 1000; // 4 hours
|
|
@@ -15,7 +15,7 @@ export function loadCache(cwd = process.cwd()) {
|
|
|
15
15
|
const content = readFileSync(cachePath, "utf-8");
|
|
16
16
|
return JSON.parse(content);
|
|
17
17
|
}
|
|
18
|
-
catch
|
|
18
|
+
catch {
|
|
19
19
|
// If cache is corrupt, start fresh
|
|
20
20
|
console.warn("Warning: Coverage cache is corrupt, starting fresh");
|
|
21
21
|
return { current: null, previous: null };
|
package/dist/harness/finalize.js
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Implements: HARNESS-FINALIZE-1, HARNESS-FINALIZE-2, HARNESS-FINALIZE-3, HARNESS-FINALIZE-4
|
|
11
11
|
*/
|
|
12
|
-
import { execSync } from
|
|
13
|
-
import { randomUUID } from
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import { execSync } from "node:child_process";
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
import { getProjectInfo } from "../utils/project-settings.js";
|
|
15
|
+
import { cleanupTestRunId, deleteTrackingFile, findProjectRoot, findRequirementsDir, getTestRunId, needsReporting, readCoverageCache, readLookupCache, readTrackingEntries, updateCoverageCache, } from "./cache.js";
|
|
16
16
|
/**
|
|
17
17
|
* Aggregate tracking entries by requirement key
|
|
18
18
|
*/
|
|
@@ -30,15 +30,15 @@ function aggregateEntries(entries) {
|
|
|
30
30
|
*/
|
|
31
31
|
function getCurrentBranch(cwd) {
|
|
32
32
|
try {
|
|
33
|
-
const branch = execSync(
|
|
33
|
+
const branch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
34
34
|
cwd,
|
|
35
|
-
encoding:
|
|
36
|
-
stdio: [
|
|
35
|
+
encoding: "utf-8",
|
|
36
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
37
37
|
}).trim();
|
|
38
38
|
return branch;
|
|
39
39
|
}
|
|
40
40
|
catch {
|
|
41
|
-
return
|
|
41
|
+
return "unknown";
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
@@ -51,8 +51,8 @@ function getLineAuthor(cwd, file, line) {
|
|
|
51
51
|
try {
|
|
52
52
|
const output = execSync(`git blame -L ${line},${line} --porcelain -- "${file}"`, {
|
|
53
53
|
cwd,
|
|
54
|
-
encoding:
|
|
55
|
-
stdio: [
|
|
54
|
+
encoding: "utf-8",
|
|
55
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
56
56
|
});
|
|
57
57
|
const match = output.match(/^author-mail\s+<([^>]+)>/m);
|
|
58
58
|
return match?.[1];
|
|
@@ -68,15 +68,17 @@ function getLineAuthor(cwd, file, line) {
|
|
|
68
68
|
*/
|
|
69
69
|
function printLocalReport(testedKeys, lookup, options) {
|
|
70
70
|
const { showSummary, showTestedList, showUntestedList } = options;
|
|
71
|
-
const allKeys = lookup
|
|
72
|
-
|
|
71
|
+
const allKeys = lookup
|
|
72
|
+
? Object.keys(lookup.requirements).filter((k) => !lookup.requirements[k].isAlias)
|
|
73
|
+
: [];
|
|
74
|
+
const untestedKeys = allKeys.filter((key) => !testedKeys.includes(key));
|
|
73
75
|
const total = allKeys.length;
|
|
74
76
|
const tested = testedKeys.length;
|
|
75
|
-
const coverage = total > 0 ? ((tested / total) * 100).toFixed(1) :
|
|
76
|
-
let report =
|
|
77
|
+
const coverage = total > 0 ? ((tested / total) * 100).toFixed(1) : "0.0";
|
|
78
|
+
let report = "";
|
|
77
79
|
// Show summary stats
|
|
78
80
|
if (showSummary) {
|
|
79
|
-
report +=
|
|
81
|
+
report += "\n=== Requirements Coverage Report ===\n";
|
|
80
82
|
report += `\nTotal Requirements: ${total}\n`;
|
|
81
83
|
report += `Tested Requirements: ${tested}\n`;
|
|
82
84
|
report += `Untested Requirements: ${untestedKeys.length}\n`;
|
|
@@ -84,14 +86,14 @@ function printLocalReport(testedKeys, lookup, options) {
|
|
|
84
86
|
}
|
|
85
87
|
// Show tested requirements
|
|
86
88
|
if (showTestedList && testedKeys.length > 0) {
|
|
87
|
-
report +=
|
|
89
|
+
report += "\n✓ Tested Requirements:\n";
|
|
88
90
|
for (const key of testedKeys) {
|
|
89
91
|
const req = lookup?.requirements[key];
|
|
90
92
|
if (req) {
|
|
91
|
-
const label = req.label ||
|
|
92
|
-
const content = req.content ||
|
|
93
|
-
const preview = content.length > 60 ? content.substring(0, 60)
|
|
94
|
-
const labelPart = label ? ` (${label})` :
|
|
93
|
+
const label = req.label || "";
|
|
94
|
+
const content = req.content || "";
|
|
95
|
+
const preview = content.length > 60 ? `${content.substring(0, 60)}...` : content;
|
|
96
|
+
const labelPart = label ? ` (${label})` : "";
|
|
95
97
|
report += ` - ${key}${labelPart}: ${preview}\n`;
|
|
96
98
|
}
|
|
97
99
|
else {
|
|
@@ -101,14 +103,14 @@ function printLocalReport(testedKeys, lookup, options) {
|
|
|
101
103
|
}
|
|
102
104
|
// Show untested requirements
|
|
103
105
|
if (showUntestedList && untestedKeys.length > 0) {
|
|
104
|
-
report +=
|
|
106
|
+
report += "\n✗ Untested Requirements:\n";
|
|
105
107
|
for (const key of untestedKeys) {
|
|
106
108
|
const req = lookup?.requirements[key];
|
|
107
109
|
if (req) {
|
|
108
|
-
const label = req.label ||
|
|
109
|
-
const content = req.content ||
|
|
110
|
-
const preview = content.length > 60 ? content.substring(0, 60)
|
|
111
|
-
const labelPart = label ? ` (${label})` :
|
|
110
|
+
const label = req.label || "";
|
|
111
|
+
const content = req.content || "";
|
|
112
|
+
const preview = content.length > 60 ? `${content.substring(0, 60)}...` : content;
|
|
113
|
+
const labelPart = label ? ` (${label})` : "";
|
|
112
114
|
report += ` - ${key}${labelPart}: ${preview}\n`;
|
|
113
115
|
}
|
|
114
116
|
else {
|
|
@@ -117,7 +119,7 @@ function printLocalReport(testedKeys, lookup, options) {
|
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
121
|
if (showSummary) {
|
|
120
|
-
report +=
|
|
122
|
+
report += "\n====================================\n";
|
|
121
123
|
}
|
|
122
124
|
if (report) {
|
|
123
125
|
console.log(report);
|
|
@@ -126,7 +128,7 @@ function printLocalReport(testedKeys, lookup, options) {
|
|
|
126
128
|
/**
|
|
127
129
|
* Production Convex deployment URL
|
|
128
130
|
*/
|
|
129
|
-
const CONVEX_URL =
|
|
131
|
+
const CONVEX_URL = "https://data.dotrequirements.io";
|
|
130
132
|
/**
|
|
131
133
|
* Report coverage to Convex cloud
|
|
132
134
|
*
|
|
@@ -138,9 +140,11 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
|
|
|
138
140
|
// Get project info from .requirements/project-settings.json
|
|
139
141
|
const projectInfo = getProjectInfo(projectRoot);
|
|
140
142
|
// Skip if no project found or not connected to cloud
|
|
141
|
-
if (!projectInfo ||
|
|
143
|
+
if (!projectInfo ||
|
|
144
|
+
projectInfo.status !== "cloud-connected" ||
|
|
145
|
+
!projectInfo.credentials) {
|
|
142
146
|
if (showCloudStatus) {
|
|
143
|
-
console.log(
|
|
147
|
+
console.log("\nℹ️ Skipping cloud coverage reporting (project not connected to cloud)");
|
|
144
148
|
}
|
|
145
149
|
return { sent: false, count: 0 };
|
|
146
150
|
}
|
|
@@ -161,7 +165,7 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
|
|
|
161
165
|
const tuplesToReport = allTuples.filter((tuple) => needsReporting(tuple, coverageCache));
|
|
162
166
|
if (tuplesToReport.length === 0) {
|
|
163
167
|
if (showCloudStatus) {
|
|
164
|
-
console.log(
|
|
168
|
+
console.log("\n✓ Coverage unchanged since last run (skipping cloud report)");
|
|
165
169
|
}
|
|
166
170
|
// Still update the cache so the window continues tracking
|
|
167
171
|
updateCoverageCache(requirementsDir, testRunId, allTuples);
|
|
@@ -180,7 +184,7 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
|
|
|
180
184
|
// Parse "filename.ts:42" format
|
|
181
185
|
let testFile;
|
|
182
186
|
let testLine;
|
|
183
|
-
if (location !==
|
|
187
|
+
if (location !== "unknown") {
|
|
184
188
|
const match = location.match(/^(.+):(\d+)$/);
|
|
185
189
|
if (match) {
|
|
186
190
|
testFile = match[1];
|
|
@@ -213,19 +217,19 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
|
|
|
213
217
|
// Note: projectId from env is always a slug (e.g., "reduced-cephalopod-288"),
|
|
214
218
|
// not a Convex ID. Use projectSlug field for authentication and slug for target.
|
|
215
219
|
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
216
|
-
method:
|
|
220
|
+
method: "POST",
|
|
217
221
|
headers: {
|
|
218
|
-
|
|
222
|
+
"Content-Type": "application/json",
|
|
219
223
|
},
|
|
220
224
|
body: JSON.stringify({
|
|
221
|
-
path:
|
|
225
|
+
path: "testCoverage/mutations:recordCoverage",
|
|
222
226
|
args: {
|
|
223
227
|
projectAuth: {
|
|
224
228
|
projectSlug: projectId,
|
|
225
229
|
projectSecret,
|
|
226
230
|
},
|
|
227
231
|
target: {
|
|
228
|
-
type:
|
|
232
|
+
type: "project",
|
|
229
233
|
slug: projectId,
|
|
230
234
|
},
|
|
231
235
|
branch,
|
|
@@ -233,7 +237,7 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
|
|
|
233
237
|
runId,
|
|
234
238
|
coverage,
|
|
235
239
|
},
|
|
236
|
-
format:
|
|
240
|
+
format: "json",
|
|
237
241
|
}),
|
|
238
242
|
});
|
|
239
243
|
if (!response.ok) {
|
|
@@ -253,10 +257,12 @@ async function reportToConvex(projectRoot, testRunId, aggregated, showCloudStatu
|
|
|
253
257
|
catch {
|
|
254
258
|
// Not JSON, treat as success
|
|
255
259
|
}
|
|
256
|
-
if (responseData &&
|
|
260
|
+
if (responseData &&
|
|
261
|
+
typeof responseData === "object" &&
|
|
262
|
+
"status" in responseData) {
|
|
257
263
|
const convexResponse = responseData;
|
|
258
|
-
if (convexResponse.status ===
|
|
259
|
-
const errorMsg = convexResponse.errorMessage ||
|
|
264
|
+
if (convexResponse.status === "error") {
|
|
265
|
+
const errorMsg = convexResponse.errorMessage || "Unknown Convex error";
|
|
260
266
|
if (showCloudStatus) {
|
|
261
267
|
console.warn(`\n⚠️ Failed to report coverage to cloud: ${errorMsg}`);
|
|
262
268
|
}
|
|
@@ -298,7 +304,7 @@ export async function finalize(options = {}) {
|
|
|
298
304
|
projectRoot = findProjectRoot(cwd);
|
|
299
305
|
}
|
|
300
306
|
if (!projectRoot) {
|
|
301
|
-
console.log(
|
|
307
|
+
console.log("Could not find .requirements directory");
|
|
302
308
|
return {
|
|
303
309
|
requirementsTested: 0,
|
|
304
310
|
totalRequirements: 0,
|
|
@@ -311,7 +317,7 @@ export async function finalize(options = {}) {
|
|
|
311
317
|
// Get test run ID
|
|
312
318
|
const testRunId = getTestRunId(requirementsDir);
|
|
313
319
|
if (!testRunId) {
|
|
314
|
-
console.log(
|
|
320
|
+
console.log("No test run ID found - was prepare() called?");
|
|
315
321
|
return {
|
|
316
322
|
requirementsTested: 0,
|
|
317
323
|
totalRequirements: 0,
|
|
@@ -343,17 +349,24 @@ export async function finalize(options = {}) {
|
|
|
343
349
|
}
|
|
344
350
|
}
|
|
345
351
|
const testedKeys = Array.from(aggregated.keys());
|
|
346
|
-
const totalRequirements = lookup
|
|
347
|
-
|
|
348
|
-
? (testedKeys.length / totalRequirements) * 100
|
|
352
|
+
const totalRequirements = lookup
|
|
353
|
+
? Object.keys(lookup.requirements).filter((k) => !lookup.requirements[k].isAlias).length
|
|
349
354
|
: 0;
|
|
355
|
+
const coveragePercent = totalRequirements > 0 ? (testedKeys.length / totalRequirements) * 100 : 0;
|
|
350
356
|
// HARNESS-FINALIZE-1: Print local report
|
|
351
357
|
const shouldPrintLocal = showSummary || showTestedList || showUntestedList;
|
|
352
358
|
if (shouldPrintLocal) {
|
|
353
|
-
printLocalReport(testedKeys, lookup, {
|
|
359
|
+
printLocalReport(testedKeys, lookup, {
|
|
360
|
+
showSummary,
|
|
361
|
+
showTestedList,
|
|
362
|
+
showUntestedList,
|
|
363
|
+
});
|
|
354
364
|
}
|
|
355
365
|
// HARNESS-FINALIZE-2, HARNESS-FINALIZE-3: Report to cloud
|
|
356
|
-
let cloudResult = {
|
|
366
|
+
let cloudResult = {
|
|
367
|
+
sent: false,
|
|
368
|
+
count: 0,
|
|
369
|
+
};
|
|
357
370
|
if (shouldReportToCloud) {
|
|
358
371
|
cloudResult = await reportToConvex(projectRoot, testRunId, aggregated, showCloudStatus, context);
|
|
359
372
|
}
|
package/dist/harness/index.d.ts
CHANGED
|
@@ -60,11 +60,10 @@ export interface RequirementOptions {
|
|
|
60
60
|
* @returns A formatted string with the first requirement's label and content
|
|
61
61
|
*/
|
|
62
62
|
export declare function requirement(...args: (string | RequirementOptions)[]): string;
|
|
63
|
-
export {
|
|
64
|
-
export
|
|
65
|
-
export {
|
|
66
|
-
export
|
|
67
|
-
export { clearTracking } from
|
|
68
|
-
export {
|
|
69
|
-
export type { Requirement } from './types.js';
|
|
63
|
+
export type { FinalizeOptions, FinalizeResult } from "./finalize.js";
|
|
64
|
+
export { finalize } from "./finalize.js";
|
|
65
|
+
export type { PrepareOptions, PrepareResult } from "./prepare.js";
|
|
66
|
+
export { prepare } from "./prepare.js";
|
|
67
|
+
export { clearTracking, finalizeTestRun, initTestRun } from "./tracking.js";
|
|
68
|
+
export type { Requirement } from "./types.js";
|
|
70
69
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/harness/index.js
CHANGED
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
* }
|
|
28
28
|
* ```
|
|
29
29
|
*/
|
|
30
|
-
import { getRequirement, loadRequirements } from
|
|
31
|
-
import { ensureTestRun, trackRequirement,
|
|
30
|
+
import { getRequirement, loadRequirements } from "./requirementsLoader.js";
|
|
31
|
+
import { ensureTestRun, saveTrackingData, trackRequirement, } from "./tracking.js";
|
|
32
32
|
/**
|
|
33
33
|
* Main requirements function for test harness.
|
|
34
34
|
*
|
|
@@ -56,15 +56,15 @@ import { ensureTestRun, trackRequirement, saveTrackingData } from './tracking.js
|
|
|
56
56
|
*/
|
|
57
57
|
export function requirement(...args) {
|
|
58
58
|
if (args.length === 0) {
|
|
59
|
-
throw new Error(
|
|
59
|
+
throw new Error("requirement() requires at least one argument");
|
|
60
60
|
}
|
|
61
61
|
// Check if last argument is options object
|
|
62
62
|
const lastArg = args[args.length - 1];
|
|
63
|
-
const hasOptions = typeof lastArg ===
|
|
63
|
+
const hasOptions = typeof lastArg === "object" && lastArg !== null;
|
|
64
64
|
const options = hasOptions ? lastArg : {};
|
|
65
65
|
const requirementRefs = (hasOptions ? args.slice(0, -1) : args);
|
|
66
66
|
if (requirementRefs.length === 0) {
|
|
67
|
-
throw new Error(
|
|
67
|
+
throw new Error("requirement() requires at least one requirement reference");
|
|
68
68
|
}
|
|
69
69
|
// If projectRoot provided, reload requirements from that path
|
|
70
70
|
if (options.projectRoot) {
|
|
@@ -87,17 +87,16 @@ export function requirement(...args) {
|
|
|
87
87
|
}
|
|
88
88
|
// HARNESS-REQUIREMENT-1: Format output as human-readable string
|
|
89
89
|
// Root requirements use 'requirementHeader' label which should not be shown in output
|
|
90
|
-
if (!req.label || req.label ===
|
|
90
|
+
if (!req.label || req.label === "requirementHeader") {
|
|
91
91
|
return req.content;
|
|
92
92
|
}
|
|
93
93
|
const label = req.label.charAt(0).toUpperCase() + req.label.slice(1);
|
|
94
94
|
return `${label}: ${req.content}`;
|
|
95
95
|
}
|
|
96
|
+
export { finalize } from "./finalize.js";
|
|
96
97
|
// Export new lifecycle functions
|
|
97
|
-
export { prepare } from
|
|
98
|
-
export { finalize } from './finalize.js';
|
|
98
|
+
export { prepare } from "./prepare.js";
|
|
99
99
|
// Export tracking utilities
|
|
100
|
-
export { clearTracking } from './tracking.js';
|
|
101
100
|
// Deprecated exports - use prepare() and finalize() instead
|
|
102
|
-
export {
|
|
101
|
+
export { clearTracking, finalizeTestRun, initTestRun } from "./tracking.js";
|
|
103
102
|
//# sourceMappingURL=index.js.map
|
package/dist/harness/prepare.js
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Implements: HARNESS-PREPARE-1, HARNESS-PREPARE-2, HARNESS-PREPARE-3
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
12
|
-
import { parseRequirementsFromFile, } from
|
|
13
|
-
import { findProjectRoot } from
|
|
11
|
+
import { findRequirementsFilesSync } from "../requirements/index.js";
|
|
12
|
+
import { parseRequirementsFromFile, } from "../schema/index.js";
|
|
13
|
+
import { findProjectRoot } from "../utils/project-settings.js";
|
|
14
|
+
import { clearTrackingFile, findRequirementsDir, initTestRunId, writeLookupCache, writeProjectRoot, } from "./cache.js";
|
|
14
15
|
/**
|
|
15
16
|
* Prepare the test harness for a test run.
|
|
16
17
|
*
|
|
@@ -26,14 +27,14 @@ export function prepare(options = {}) {
|
|
|
26
27
|
// Find the project root by looking for .requirements directory
|
|
27
28
|
const projectRoot = findProjectRoot(cwd);
|
|
28
29
|
if (!projectRoot) {
|
|
29
|
-
throw new Error(
|
|
30
|
+
throw new Error("Could not find .requirements directory. " +
|
|
30
31
|
'Please run "dotrequirements init" to initialize your project.');
|
|
31
32
|
}
|
|
32
33
|
// Set environment variable for cross-process persistence (globalSetup → test workers)
|
|
33
34
|
process.env.DOTREQUIREMENTS_PROJECT_ROOT = projectRoot;
|
|
34
35
|
const requirementsDir = findRequirementsDir(projectRoot);
|
|
35
36
|
// Find all requirements files
|
|
36
|
-
const files =
|
|
37
|
+
const files = findRequirementsFilesSync(projectRoot);
|
|
37
38
|
// Parse all files, collecting requirements and errors
|
|
38
39
|
const allRequirements = [];
|
|
39
40
|
const parseErrors = [];
|