@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
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slice extraction: given a Repomix pack and a list of file paths (or
|
|
3
|
+
* directory-prefix paths), produce a smaller pack containing only the matching
|
|
4
|
+
* files.
|
|
5
|
+
*
|
|
6
|
+
* Pack format (from Repomix --style plain):
|
|
7
|
+
*
|
|
8
|
+
* ================
|
|
9
|
+
* File: path/to/file
|
|
10
|
+
* ================
|
|
11
|
+
* <file contents>
|
|
12
|
+
*
|
|
13
|
+
* ================
|
|
14
|
+
* File: next/file
|
|
15
|
+
* ================
|
|
16
|
+
* ...
|
|
17
|
+
*
|
|
18
|
+
* We preserve the pack header (everything before the first File: section) and
|
|
19
|
+
* the matching sections.
|
|
20
|
+
*
|
|
21
|
+
* Requirements covered:
|
|
22
|
+
* - CTS-SPEC-1: CLI fans out one specifier worker per area; each worker
|
|
23
|
+
* receives a slice extracted from the uncompressed pack
|
|
24
|
+
*/
|
|
25
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
26
|
+
const SEPARATOR = "================";
|
|
27
|
+
const FILE_PREFIX = "File: ";
|
|
28
|
+
/**
|
|
29
|
+
* Return true when `path` matches one of the entries in `wanted`.
|
|
30
|
+
*
|
|
31
|
+
* Each entry can be:
|
|
32
|
+
* - An exact file path (e.g., `src/foo.ts`) — matches that exact path.
|
|
33
|
+
* - A directory prefix ending in `/` (e.g., `src/services/browser/`) — matches
|
|
34
|
+
* any file under that directory tree.
|
|
35
|
+
*/
|
|
36
|
+
export function pathMatchesWanted(path, wanted) {
|
|
37
|
+
for (const w of wanted) {
|
|
38
|
+
if (w === path)
|
|
39
|
+
return true;
|
|
40
|
+
if (w.endsWith("/") && path.startsWith(w))
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Extract sections matching `wanted` from the pack at `inputPath` and write
|
|
47
|
+
* them to `outputPath`. Preserves the pack header (Repomix metadata).
|
|
48
|
+
*/
|
|
49
|
+
export function extractSlice(inputPath, outputPath, wanted) {
|
|
50
|
+
const wantedSet = new Set(wanted);
|
|
51
|
+
const text = readFileSync(inputPath, "utf-8");
|
|
52
|
+
return extractSliceFromText(text, outputPath, wantedSet);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Pure variant operating on already-loaded text. Useful for tests.
|
|
56
|
+
*/
|
|
57
|
+
export function extractSliceFromText(text, outputPath, wanted) {
|
|
58
|
+
const wantedSet = wanted instanceof Set ? wanted : new Set(wanted);
|
|
59
|
+
const lines = text.split("\n");
|
|
60
|
+
const out = [];
|
|
61
|
+
// Find the start of the first File: section.
|
|
62
|
+
let firstFileIdx = -1;
|
|
63
|
+
for (let i = 0; i + 1 < lines.length; i++) {
|
|
64
|
+
if (lines[i].trim() === SEPARATOR && lines[i + 1].startsWith(FILE_PREFIX)) {
|
|
65
|
+
firstFileIdx = i;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (firstFileIdx === -1) {
|
|
70
|
+
throw new Error("Input pack has no File: sections");
|
|
71
|
+
}
|
|
72
|
+
// Preserve the pack header (lines 0..firstFileIdx-1).
|
|
73
|
+
for (let i = 0; i < firstFileIdx; i++) {
|
|
74
|
+
out.push(lines[i]);
|
|
75
|
+
}
|
|
76
|
+
let matched = 0;
|
|
77
|
+
let total = 0;
|
|
78
|
+
let i = firstFileIdx;
|
|
79
|
+
while (i < lines.length) {
|
|
80
|
+
if (lines[i].trim() === SEPARATOR &&
|
|
81
|
+
i + 1 < lines.length &&
|
|
82
|
+
lines[i + 1].startsWith(FILE_PREFIX)) {
|
|
83
|
+
const path = lines[i + 1].slice(FILE_PREFIX.length).trim();
|
|
84
|
+
total++;
|
|
85
|
+
// Find the end of this section (next ====/File: pair or EOF).
|
|
86
|
+
let j = i + 3; // past the closing separator
|
|
87
|
+
while (j < lines.length) {
|
|
88
|
+
if (lines[j].trim() === SEPARATOR &&
|
|
89
|
+
j + 1 < lines.length &&
|
|
90
|
+
lines[j + 1].startsWith(FILE_PREFIX)) {
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
j++;
|
|
94
|
+
}
|
|
95
|
+
const contentEnd = j; // exclusive
|
|
96
|
+
if (pathMatchesWanted(path, wantedSet)) {
|
|
97
|
+
matched++;
|
|
98
|
+
for (let k = i; k < contentEnd; k++) {
|
|
99
|
+
out.push(lines[k]);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
i = j;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
i++;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
writeFileSync(outputPath, out.join("\n"), "utf-8");
|
|
109
|
+
return { matched, total };
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=slice.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specifier worker: run a single specifier for one area.
|
|
3
|
+
*
|
|
4
|
+
* The specifier is given its slice + the outline + a target partial path, and
|
|
5
|
+
* it orchestrates its own work via tools (Read, Write, Edit, Grep, Glob, Bash).
|
|
6
|
+
* Self-style-check happens via `Bash dotrequirements cts style-check <path>`.
|
|
7
|
+
*
|
|
8
|
+
* Requirements covered:
|
|
9
|
+
* - CTS-SPEC-1: per-area worker invocation
|
|
10
|
+
* - CTS-SPEC-2: write partial to known path via Write tool
|
|
11
|
+
* - CTS-SPEC-3: self-style-check via Bash
|
|
12
|
+
* - CTS-SPEC-4: access to the full pack for cross-area context
|
|
13
|
+
* - CTS-SPEC-5: failure detection and retry orchestrated by fan-out (this file
|
|
14
|
+
* produces a single attempt; fan-out wraps it with retry policy)
|
|
15
|
+
*/
|
|
16
|
+
import { type ClaudeRunner } from "./claude.js";
|
|
17
|
+
import type { Area, Outline } from "./schemas.js";
|
|
18
|
+
export interface SpecifierContext {
|
|
19
|
+
outline: Outline;
|
|
20
|
+
area: Area;
|
|
21
|
+
/** Path to the area's slice (extracted from the uncompressed pack). */
|
|
22
|
+
slicePath: string;
|
|
23
|
+
/** Path to the full uncompressed pack (for cross-area discovery). */
|
|
24
|
+
fullPackPath: string;
|
|
25
|
+
/** Where the specifier should write its partial. */
|
|
26
|
+
partialPath: string;
|
|
27
|
+
/**
|
|
28
|
+
* The command the specifier should run to invoke schema validation on its
|
|
29
|
+
* own partial — typically `dotrequirements cts validate`. Run BEFORE
|
|
30
|
+
* style-check.
|
|
31
|
+
*/
|
|
32
|
+
validateCommand: string;
|
|
33
|
+
/**
|
|
34
|
+
* The command the specifier should run to invoke style-check on its own
|
|
35
|
+
* partial — typically `dotrequirements cts style-check`. Run AFTER
|
|
36
|
+
* validate.
|
|
37
|
+
*/
|
|
38
|
+
styleCheckCommand: string;
|
|
39
|
+
/** Directories the agent should have read+write access to. */
|
|
40
|
+
addDirs: string[];
|
|
41
|
+
runner?: ClaudeRunner;
|
|
42
|
+
model?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface SpecifierResult {
|
|
45
|
+
/** True if the agent wrote a non-empty partial file at the expected path. */
|
|
46
|
+
wrotePartial: boolean;
|
|
47
|
+
/** Size of the partial in bytes, or 0 if missing. */
|
|
48
|
+
partialBytes: number;
|
|
49
|
+
/** Process exit code. */
|
|
50
|
+
exitCode: number;
|
|
51
|
+
/** Captured stdout. */
|
|
52
|
+
stdout: string;
|
|
53
|
+
/** Captured stderr. */
|
|
54
|
+
stderr: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Run a single specifier. Returns details about whether it succeeded.
|
|
58
|
+
*/
|
|
59
|
+
export declare function runSpecifier(ctx: SpecifierContext): Promise<SpecifierResult>;
|
|
60
|
+
//# sourceMappingURL=specifier.d.ts.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Specifier worker: run a single specifier for one area.
|
|
3
|
+
*
|
|
4
|
+
* The specifier is given its slice + the outline + a target partial path, and
|
|
5
|
+
* it orchestrates its own work via tools (Read, Write, Edit, Grep, Glob, Bash).
|
|
6
|
+
* Self-style-check happens via `Bash dotrequirements cts style-check <path>`.
|
|
7
|
+
*
|
|
8
|
+
* Requirements covered:
|
|
9
|
+
* - CTS-SPEC-1: per-area worker invocation
|
|
10
|
+
* - CTS-SPEC-2: write partial to known path via Write tool
|
|
11
|
+
* - CTS-SPEC-3: self-style-check via Bash
|
|
12
|
+
* - CTS-SPEC-4: access to the full pack for cross-area context
|
|
13
|
+
* - CTS-SPEC-5: failure detection and retry orchestrated by fan-out (this file
|
|
14
|
+
* produces a single attempt; fan-out wraps it with retry policy)
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, statSync } from "node:fs";
|
|
17
|
+
import { runClaude } from "./claude.js";
|
|
18
|
+
import { SPECIFIER_PROMPT } from "./prompts/specifier.js";
|
|
19
|
+
function buildUserMessage(ctx) {
|
|
20
|
+
return [
|
|
21
|
+
`You are specifying ONE area of the system.`,
|
|
22
|
+
``,
|
|
23
|
+
`Area name: ${ctx.area.name}`,
|
|
24
|
+
`Area description: ${ctx.area.description}`,
|
|
25
|
+
`Document defaultPrefix: ${ctx.outline.defaultPrefix}`,
|
|
26
|
+
`Area prefix: ${ctx.area.prefix}`,
|
|
27
|
+
`Use full requirement IDs of the form: ${ctx.outline.defaultPrefix}-${ctx.area.prefix}-1, ${ctx.outline.defaultPrefix}-${ctx.area.prefix}-2, etc. (sequential, 1-indexed, no zero-padding).`,
|
|
28
|
+
``,
|
|
29
|
+
`## Paths`,
|
|
30
|
+
`- Slice (your area's files): ${ctx.slicePath}`,
|
|
31
|
+
`- Full uncompressed pack (for discovering behaviors in tests/recipes/docs): ${ctx.fullPackPath}`,
|
|
32
|
+
`- Where to write your partial: ${ctx.partialPath}`,
|
|
33
|
+
`- Validate command (run FIRST after writing your draft — deterministic syntax check):`,
|
|
34
|
+
` Bash: ${ctx.validateCommand} ${ctx.partialPath}`,
|
|
35
|
+
`- Style-check command (run SECOND, only after validate passes — AI clarity feedback):`,
|
|
36
|
+
` Bash: ${ctx.styleCheckCommand} ${ctx.partialPath}`,
|
|
37
|
+
``,
|
|
38
|
+
`## Full system outline (so you know what is in scope vs. not)`,
|
|
39
|
+
`\`\`\`json`,
|
|
40
|
+
JSON.stringify(ctx.outline, null, 2),
|
|
41
|
+
`\`\`\``,
|
|
42
|
+
``,
|
|
43
|
+
`Follow the three-phase workflow in your system prompt: draft (Phase A) → validate (Phase B) → style-check (Phase C) → confirm.`,
|
|
44
|
+
].join("\n");
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Run a single specifier. Returns details about whether it succeeded.
|
|
48
|
+
*/
|
|
49
|
+
export async function runSpecifier(ctx) {
|
|
50
|
+
const runner = ctx.runner ?? runClaude;
|
|
51
|
+
const result = await runner({
|
|
52
|
+
systemPrompt: SPECIFIER_PROMPT,
|
|
53
|
+
userMessage: buildUserMessage(ctx),
|
|
54
|
+
model: ctx.model,
|
|
55
|
+
tools: ["Read", "Write", "Edit", "Grep", "Glob", "Bash"],
|
|
56
|
+
addDirs: ctx.addDirs,
|
|
57
|
+
});
|
|
58
|
+
// Inspect the partial file to determine whether the specifier wrote
|
|
59
|
+
// something usable.
|
|
60
|
+
let wrotePartial = false;
|
|
61
|
+
let partialBytes = 0;
|
|
62
|
+
if (existsSync(ctx.partialPath)) {
|
|
63
|
+
try {
|
|
64
|
+
partialBytes = statSync(ctx.partialPath).size;
|
|
65
|
+
wrotePartial = partialBytes > 0;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// ignore; treat as not written
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
wrotePartial,
|
|
73
|
+
partialBytes,
|
|
74
|
+
exitCode: result.exitCode,
|
|
75
|
+
stdout: result.stdout,
|
|
76
|
+
stderr: result.stderr,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=specifier.js.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local style-check function — produces severity-categorized feedback on a
|
|
3
|
+
* partial-spec file using a fresh, stateless claude -p call.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the existing cloud `mcp__dotrequirements__style_check` pattern but
|
|
6
|
+
* runs entirely offline (no cloud credentials, no account required), since
|
|
7
|
+
* the codebase-to-spec target audience does not yet have a dotrequirements
|
|
8
|
+
* account.
|
|
9
|
+
*
|
|
10
|
+
* Requirements covered:
|
|
11
|
+
* - CTS-SPEC-3: Specifier worker runs a local style-check on its own draft
|
|
12
|
+
*/
|
|
13
|
+
import { type ClaudeRunner } from "./claude.js";
|
|
14
|
+
export interface StyleCheckOptions {
|
|
15
|
+
partialPath: string;
|
|
16
|
+
runner?: ClaudeRunner;
|
|
17
|
+
model?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface StyleCheckResult {
|
|
20
|
+
/** The categorized feedback (Markdown). */
|
|
21
|
+
feedback: string;
|
|
22
|
+
/** Process exit code from the claude -p subprocess. */
|
|
23
|
+
exitCode: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Run a style check on a partial-spec file and return the feedback as Markdown.
|
|
27
|
+
*/
|
|
28
|
+
export declare function runStyleCheck(options: StyleCheckOptions): Promise<StyleCheckResult>;
|
|
29
|
+
//# sourceMappingURL=style-check.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local style-check function — produces severity-categorized feedback on a
|
|
3
|
+
* partial-spec file using a fresh, stateless claude -p call.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the existing cloud `mcp__dotrequirements__style_check` pattern but
|
|
6
|
+
* runs entirely offline (no cloud credentials, no account required), since
|
|
7
|
+
* the codebase-to-spec target audience does not yet have a dotrequirements
|
|
8
|
+
* account.
|
|
9
|
+
*
|
|
10
|
+
* Requirements covered:
|
|
11
|
+
* - CTS-SPEC-3: Specifier worker runs a local style-check on its own draft
|
|
12
|
+
*/
|
|
13
|
+
import { dirname } from "node:path";
|
|
14
|
+
import { runClaude } from "./claude.js";
|
|
15
|
+
import { STYLE_CHECK_PROMPT } from "./prompts/style-check.js";
|
|
16
|
+
/**
|
|
17
|
+
* Run a style check on a partial-spec file and return the feedback as Markdown.
|
|
18
|
+
*/
|
|
19
|
+
export async function runStyleCheck(options) {
|
|
20
|
+
const runner = options.runner ?? runClaude;
|
|
21
|
+
const result = await runner({
|
|
22
|
+
systemPrompt: STYLE_CHECK_PROMPT,
|
|
23
|
+
userMessage: `Run a style check on the partial spec at ${options.partialPath}. Read the file via the Read tool and produce categorized Markdown feedback per your system prompt.`,
|
|
24
|
+
model: options.model,
|
|
25
|
+
tools: ["Read"],
|
|
26
|
+
addDirs: [dirname(options.partialPath)],
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
feedback: result.stdout,
|
|
30
|
+
exitCode: result.exitCode,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=style-check.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline summary generation.
|
|
3
|
+
*
|
|
4
|
+
* Reads cached artifacts to assemble a structured summary of what the
|
|
5
|
+
* pipeline produced. Surfaced both as JSON (parseable by wrappers like the
|
|
6
|
+
* skill) and as a short human-readable block.
|
|
7
|
+
*
|
|
8
|
+
* Requirements covered:
|
|
9
|
+
* - CTS-PRESENT-4: Final pipeline summary is surfaced
|
|
10
|
+
* - CTS-OBSERVE-2 (partial): structured failure information available
|
|
11
|
+
*/
|
|
12
|
+
import type { CachePaths } from "./cache.js";
|
|
13
|
+
import { type Outline } from "./schemas.js";
|
|
14
|
+
export interface PipelineSummary {
|
|
15
|
+
totalAreas: number;
|
|
16
|
+
totalRequirements: number;
|
|
17
|
+
outline: {
|
|
18
|
+
turnsUsed: number;
|
|
19
|
+
finalVerdict: string | null;
|
|
20
|
+
residualNotes: string[];
|
|
21
|
+
};
|
|
22
|
+
specifiers: {
|
|
23
|
+
completed: number;
|
|
24
|
+
missing: number;
|
|
25
|
+
/** Area names that have no usable partial. */
|
|
26
|
+
missingAreas: string[];
|
|
27
|
+
};
|
|
28
|
+
specReview: {
|
|
29
|
+
turnsUsed: number;
|
|
30
|
+
finalVerdict: string | null;
|
|
31
|
+
residualNotes: string[];
|
|
32
|
+
};
|
|
33
|
+
outputs: {
|
|
34
|
+
/** Paths under .requirements/ that were written. */
|
|
35
|
+
paths: string[];
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export interface BuildSummaryInput {
|
|
39
|
+
outline: Outline;
|
|
40
|
+
paths: CachePaths;
|
|
41
|
+
/** Paths the present stage wrote (under .requirements/). */
|
|
42
|
+
outputPaths: string[];
|
|
43
|
+
}
|
|
44
|
+
export declare function buildPipelineSummary(input: BuildSummaryInput): PipelineSummary;
|
|
45
|
+
/**
|
|
46
|
+
* Render a short human-readable block for the summary. Designed to fit on a
|
|
47
|
+
* small number of lines (CTS-PRESENT-4.2). Wrappers that want richer
|
|
48
|
+
* presentation can read the JSON form instead.
|
|
49
|
+
*/
|
|
50
|
+
export declare function renderSummaryText(summary: PipelineSummary): string;
|
|
51
|
+
//# sourceMappingURL=summary.d.ts.map
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline summary generation.
|
|
3
|
+
*
|
|
4
|
+
* Reads cached artifacts to assemble a structured summary of what the
|
|
5
|
+
* pipeline produced. Surfaced both as JSON (parseable by wrappers like the
|
|
6
|
+
* skill) and as a short human-readable block.
|
|
7
|
+
*
|
|
8
|
+
* Requirements covered:
|
|
9
|
+
* - CTS-PRESENT-4: Final pipeline summary is surfaced
|
|
10
|
+
* - CTS-OBSERVE-2 (partial): structured failure information available
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
13
|
+
import { sanitizeAreaName } from "./fan-out.js";
|
|
14
|
+
import { parseOutlineReview, parseSpecReview, } from "./schemas.js";
|
|
15
|
+
/**
|
|
16
|
+
* Count top-level requirements in a file by counting fenced
|
|
17
|
+
* \`\`\`dotrequirements blocks. Each block represents one root requirement
|
|
18
|
+
* (CTS-OBSERVE-2 counts each requirement ID once, excluding child criteria).
|
|
19
|
+
*/
|
|
20
|
+
function countRequirementsInFile(path) {
|
|
21
|
+
if (!existsSync(path))
|
|
22
|
+
return 0;
|
|
23
|
+
const content = readFileSync(path, "utf-8");
|
|
24
|
+
const matches = content.match(/```dotrequirements\b/g);
|
|
25
|
+
return matches ? matches.length : 0;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Look at outline-review-N.json files in the cache and return how many turns
|
|
29
|
+
* ran and what the final verdict was. Returns {turnsUsed: 0, finalVerdict: null}
|
|
30
|
+
* if no review artifacts exist.
|
|
31
|
+
*/
|
|
32
|
+
function summarizeOutlineReview(paths) {
|
|
33
|
+
let n = 0;
|
|
34
|
+
let lastReviewPath = null;
|
|
35
|
+
while (true) {
|
|
36
|
+
const path = paths.outlineReviewTurn(n + 1);
|
|
37
|
+
if (!existsSync(path))
|
|
38
|
+
break;
|
|
39
|
+
n++;
|
|
40
|
+
lastReviewPath = path;
|
|
41
|
+
}
|
|
42
|
+
if (!lastReviewPath)
|
|
43
|
+
return { turnsUsed: 0, finalVerdict: null, residualNotes: [] };
|
|
44
|
+
try {
|
|
45
|
+
const review = parseOutlineReview(readFileSync(lastReviewPath, "utf-8"));
|
|
46
|
+
const notes = [];
|
|
47
|
+
// Surface unresolved findings as residual notes if verdict isn't 'approved'.
|
|
48
|
+
if (review.verdict !== "approved") {
|
|
49
|
+
for (const cat of [
|
|
50
|
+
["coverage_gap", review.coverage_gaps],
|
|
51
|
+
["framing_error", review.framing_errors],
|
|
52
|
+
["granularity", review.granularity_issues],
|
|
53
|
+
["file_assignment", review.file_assignment_issues],
|
|
54
|
+
]) {
|
|
55
|
+
for (const note of cat[1]) {
|
|
56
|
+
notes.push(`outline.${cat[0]}: ${note}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return { turnsUsed: n, finalVerdict: review.verdict, residualNotes: notes };
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return { turnsUsed: n, finalVerdict: null, residualNotes: [] };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function summarizeSpecReview(paths) {
|
|
67
|
+
let n = 0;
|
|
68
|
+
let lastReviewPath = null;
|
|
69
|
+
while (true) {
|
|
70
|
+
const path = paths.specReviewTurn(n + 1);
|
|
71
|
+
if (!existsSync(path))
|
|
72
|
+
break;
|
|
73
|
+
n++;
|
|
74
|
+
lastReviewPath = path;
|
|
75
|
+
}
|
|
76
|
+
if (!lastReviewPath)
|
|
77
|
+
return { turnsUsed: 0, finalVerdict: null, residualNotes: [] };
|
|
78
|
+
try {
|
|
79
|
+
const review = parseSpecReview(readFileSync(lastReviewPath, "utf-8"));
|
|
80
|
+
const notes = [];
|
|
81
|
+
if (review.verdict !== "approved") {
|
|
82
|
+
for (const cat of [
|
|
83
|
+
["coverage_gap", review.coverage_gaps],
|
|
84
|
+
["framing_error", review.framing_errors],
|
|
85
|
+
["cross_area", review.cross_area_issues],
|
|
86
|
+
["internal_mechanics", review.internal_mechanics_drift],
|
|
87
|
+
]) {
|
|
88
|
+
for (const note of cat[1]) {
|
|
89
|
+
notes.push(`spec.${cat[0]}: ${note}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return { turnsUsed: n, finalVerdict: review.verdict, residualNotes: notes };
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return { turnsUsed: n, finalVerdict: null, residualNotes: [] };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function summarizeSpecifiers(outline, paths) {
|
|
100
|
+
let completed = 0;
|
|
101
|
+
const missingAreas = [];
|
|
102
|
+
for (const area of outline.areas) {
|
|
103
|
+
const partialPath = paths.partial(sanitizeAreaName(area.name));
|
|
104
|
+
if (!existsSync(partialPath)) {
|
|
105
|
+
missingAreas.push(area.name);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const content = readFileSync(partialPath, "utf-8").trim();
|
|
109
|
+
if (!content ||
|
|
110
|
+
content.startsWith("_(missing partial") ||
|
|
111
|
+
content.startsWith("_(no files")) {
|
|
112
|
+
missingAreas.push(area.name);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
completed++;
|
|
116
|
+
}
|
|
117
|
+
return { completed, missing: missingAreas.length, missingAreas };
|
|
118
|
+
}
|
|
119
|
+
export function buildPipelineSummary(input) {
|
|
120
|
+
const { outline, paths, outputPaths } = input;
|
|
121
|
+
const outlineReview = summarizeOutlineReview(paths);
|
|
122
|
+
const specReview = summarizeSpecReview(paths);
|
|
123
|
+
const specifiers = summarizeSpecifiers(outline, paths);
|
|
124
|
+
// Count top-level requirements across all written .requirements/ files.
|
|
125
|
+
let totalRequirements = 0;
|
|
126
|
+
for (const path of outputPaths) {
|
|
127
|
+
totalRequirements += countRequirementsInFile(path);
|
|
128
|
+
}
|
|
129
|
+
// Fall back to counting the final cached spec if nothing was written (e.g.
|
|
130
|
+
// dry-run / interrupted) — that way the summary still reflects what the
|
|
131
|
+
// pipeline produced.
|
|
132
|
+
if (totalRequirements === 0 && existsSync(paths.specFinal)) {
|
|
133
|
+
totalRequirements = countRequirementsInFile(paths.specFinal);
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
totalAreas: outline.areas.length,
|
|
137
|
+
totalRequirements,
|
|
138
|
+
outline: outlineReview,
|
|
139
|
+
specifiers,
|
|
140
|
+
specReview,
|
|
141
|
+
outputs: { paths: outputPaths },
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Render a short human-readable block for the summary. Designed to fit on a
|
|
146
|
+
* small number of lines (CTS-PRESENT-4.2). Wrappers that want richer
|
|
147
|
+
* presentation can read the JSON form instead.
|
|
148
|
+
*/
|
|
149
|
+
export function renderSummaryText(summary) {
|
|
150
|
+
const lines = [];
|
|
151
|
+
lines.push(`Pipeline summary:`);
|
|
152
|
+
lines.push(` Areas: ${summary.totalAreas}`);
|
|
153
|
+
lines.push(` Top-level reqs: ${summary.totalRequirements}`);
|
|
154
|
+
lines.push(` Outline review: ${summary.outline.turnsUsed} turn(s), verdict: ${summary.outline.finalVerdict ?? "n/a"}`);
|
|
155
|
+
lines.push(` Specifiers: ${summary.specifiers.completed} completed, ${summary.specifiers.missing} missing`);
|
|
156
|
+
lines.push(` Spec review: ${summary.specReview.turnsUsed} turn(s), verdict: ${summary.specReview.finalVerdict ?? "n/a"}`);
|
|
157
|
+
lines.push(` Output files:`);
|
|
158
|
+
for (const path of summary.outputs.paths) {
|
|
159
|
+
lines.push(` - ${path}`);
|
|
160
|
+
}
|
|
161
|
+
if (summary.outline.residualNotes.length ||
|
|
162
|
+
summary.specReview.residualNotes.length) {
|
|
163
|
+
lines.push(``);
|
|
164
|
+
lines.push(` Residual notes (worth reviewing manually):`);
|
|
165
|
+
for (const note of [
|
|
166
|
+
...summary.outline.residualNotes,
|
|
167
|
+
...summary.specReview.residualNotes,
|
|
168
|
+
]) {
|
|
169
|
+
lines.push(` - ${note}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (summary.specifiers.missingAreas.length) {
|
|
173
|
+
lines.push(``);
|
|
174
|
+
lines.push(` Missing specifier output for:`);
|
|
175
|
+
for (const area of summary.specifiers.missingAreas) {
|
|
176
|
+
lines.push(` - ${area}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return lines.join("\n");
|
|
180
|
+
}
|
|
181
|
+
/** Suppress unused-var warning. */
|
|
182
|
+
void statSync;
|
|
183
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local schema validation for a partial-spec file.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the existing `dotrequirements validate` path (and the
|
|
5
|
+
* `mcp__dotrequirements__validate_requirements` MCP tool), but works on
|
|
6
|
+
* partial files — which lack YAML frontmatter — by synthesizing a minimal
|
|
7
|
+
* wrapper before running the canonical parser.
|
|
8
|
+
*
|
|
9
|
+
* This is a deterministic syntax check: it catches things like missing
|
|
10
|
+
* `→`/`->` arrows, malformed position paths, indentation/position mismatches,
|
|
11
|
+
* and duplicate IDs — things the AI-driven style-check is not guaranteed
|
|
12
|
+
* to notice.
|
|
13
|
+
*
|
|
14
|
+
* Convention from CLAUDE.md: validate before style-check. Validate is the
|
|
15
|
+
* cheap, deterministic gate; style-check is the AI clarity pass.
|
|
16
|
+
*
|
|
17
|
+
* Requirements covered:
|
|
18
|
+
* - CTS-SPEC-3: Specifier worker runs a local schema validator on its draft,
|
|
19
|
+
* then a local style-check, applying feedback from each.
|
|
20
|
+
*/
|
|
21
|
+
export interface ValidateOptions {
|
|
22
|
+
/** Path to the partial-spec file to validate. */
|
|
23
|
+
partialPath: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ValidateResult {
|
|
26
|
+
/** True if the partial parsed cleanly. */
|
|
27
|
+
ok: boolean;
|
|
28
|
+
/** Human-readable error message when `ok === false`. */
|
|
29
|
+
error?: string;
|
|
30
|
+
/** Number of requirement blocks found (when `ok === true`). */
|
|
31
|
+
requirementCount?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validate a partial-spec file. Reads the file, synthesizes a frontmatter
|
|
35
|
+
* envelope, and delegates to the canonical parser. Errors are surfaced as
|
|
36
|
+
* a single human-readable string so the calling agent can act on them as
|
|
37
|
+
* MUST FIX items.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runValidate(options: ValidateOptions): ValidateResult;
|
|
40
|
+
/**
|
|
41
|
+
* Format a ValidateResult as the Markdown feedback block the specifier
|
|
42
|
+
* agent reads on stdout. Mirrors the severity-categorized shape produced
|
|
43
|
+
* by `runStyleCheck`, so the prompt can describe them uniformly.
|
|
44
|
+
*/
|
|
45
|
+
export declare function formatValidateFeedback(result: ValidateResult): string;
|
|
46
|
+
//# sourceMappingURL=validate.d.ts.map
|