forge-cc 0.1.40 → 1.0.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 +454 -338
- package/dist/cli.js +194 -906
- package/dist/cli.js.map +1 -1
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/loader.js +49 -56
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +37 -125
- package/dist/config/schema.js +13 -28
- package/dist/config/schema.js.map +1 -1
- package/dist/doctor.d.ts +10 -0
- package/dist/doctor.js +148 -0
- package/dist/doctor.js.map +1 -0
- package/dist/gates/index.d.ts +14 -12
- package/dist/gates/index.js +53 -105
- package/dist/gates/index.js.map +1 -1
- package/dist/gates/lint-gate.d.ts +2 -2
- package/dist/gates/lint-gate.js +60 -66
- package/dist/gates/lint-gate.js.map +1 -1
- package/dist/gates/tests-gate.d.ts +2 -4
- package/dist/gates/tests-gate.js +75 -203
- package/dist/gates/tests-gate.js.map +1 -1
- package/dist/gates/types-gate.d.ts +2 -2
- package/dist/gates/types-gate.js +53 -59
- package/dist/gates/types-gate.js.map +1 -1
- package/dist/go/linear-sync-cli.js +13 -4
- package/dist/go/linear-sync-cli.js.map +1 -1
- package/dist/go/linear-sync.d.ts +1 -0
- package/dist/go/linear-sync.js +67 -4
- package/dist/go/linear-sync.js.map +1 -1
- package/dist/linear/client.d.ts +34 -105
- package/dist/linear/client.js +85 -365
- package/dist/linear/client.js.map +1 -1
- package/dist/linear/issues.d.ts +3 -1
- package/dist/linear/issues.js +14 -2
- package/dist/linear/issues.js.map +1 -1
- package/dist/linear/projects.js +3 -2
- package/dist/linear/projects.js.map +1 -1
- package/dist/linear/sync.d.ts +15 -0
- package/dist/linear/sync.js +102 -0
- package/dist/linear/sync.js.map +1 -0
- package/dist/runner/loop.d.ts +4 -0
- package/dist/runner/loop.js +168 -0
- package/dist/runner/loop.js.map +1 -0
- package/dist/runner/prompt.d.ts +14 -0
- package/dist/runner/prompt.js +59 -0
- package/dist/runner/prompt.js.map +1 -0
- package/dist/runner/update.d.ts +1 -0
- package/dist/runner/update.js +72 -0
- package/dist/runner/update.js.map +1 -0
- package/dist/server.d.ts +6 -2
- package/dist/server.js +43 -101
- package/dist/server.js.map +1 -1
- package/dist/setup.d.ts +5 -0
- package/dist/setup.js +208 -0
- package/dist/setup.js.map +1 -0
- package/dist/state/cache.d.ts +3 -0
- package/dist/state/cache.js +23 -0
- package/dist/state/cache.js.map +1 -0
- package/dist/state/status.d.ts +66 -0
- package/dist/state/status.js +96 -0
- package/dist/state/status.js.map +1 -0
- package/dist/types.d.ts +46 -114
- package/dist/worktree/manager.d.ts +6 -103
- package/dist/worktree/manager.js +25 -296
- package/dist/worktree/manager.js.map +1 -1
- package/hooks/pre-commit-verify.js +109 -109
- package/package.json +3 -2
- package/skills/forge-go.md +583 -575
- package/skills/forge-setup.md +149 -388
- package/skills/forge-spec.md +367 -342
- package/skills/forge-triage.md +179 -133
- package/skills/forge-update.md +87 -93
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EACL,YAAY,EACZ,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,EACnC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,0FAA0F;IAC1F,YAAY,CAAC,SAAS,CAAC,CAAC;IACxB,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvB,YAAY,CAAC,SAAS,CAAC,CAAC;IAExB,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,0DAA0D,EAC1D;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;QACjF,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;KAC3E,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;QAC9B,MAAM,GAAG,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;QAErC,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;QACvB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAE9C,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,+CAA+C;AAC/C,KAAK,UAAU,WAAW;IACxB,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,6BAA6B;AAC7B,MAAM,MAAM,GACV,OAAO,OAAO,KAAK,WAAW;IAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACf,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;AAEtF,IAAI,MAAM,EAAE,CAAC;IACX,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/setup.d.ts
ADDED
package/dist/setup.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir, readdir, copyFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { dirname } from "node:path";
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
const packageRoot = join(__dirname, "..");
|
|
9
|
+
const FORGE_CLAUDE_SECTION = `
|
|
10
|
+
## Forge Quick Reference
|
|
11
|
+
|
|
12
|
+
| Action | Command |
|
|
13
|
+
|--------|---------|
|
|
14
|
+
| Run verification | \`npx forge verify\` |
|
|
15
|
+
| Run specific gates | \`npx forge verify --gate types,lint\` |
|
|
16
|
+
| Check status | \`npx forge status\` |
|
|
17
|
+
| Check environment | \`npx forge doctor\` |
|
|
18
|
+
|
|
19
|
+
## Session Protocol
|
|
20
|
+
- **On start:** Read CLAUDE.md, .planning/status/*.json, tasks/lessons.md
|
|
21
|
+
- **When lost:** Re-read planning docs
|
|
22
|
+
|
|
23
|
+
## Session Protocol END (Mandatory)
|
|
24
|
+
1. Update .planning/status/<slug>.json
|
|
25
|
+
2. Update tasks/lessons.md (max 10 active)
|
|
26
|
+
3. Commit doc updates to the feature branch
|
|
27
|
+
`;
|
|
28
|
+
/** Copy skill .md files from the forge-cc package to ~/.claude/commands/forge/. */
|
|
29
|
+
async function installSkills() {
|
|
30
|
+
const skillsSource = join(packageRoot, "skills");
|
|
31
|
+
const targetDir = join(homedir(), ".claude", "commands", "forge");
|
|
32
|
+
await mkdir(targetDir, { recursive: true });
|
|
33
|
+
let files;
|
|
34
|
+
try {
|
|
35
|
+
files = await readdir(skillsSource);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const installed = [];
|
|
41
|
+
for (const file of files) {
|
|
42
|
+
if (!file.endsWith(".md") || file === "README.md")
|
|
43
|
+
continue;
|
|
44
|
+
await copyFile(join(skillsSource, file), join(targetDir, file));
|
|
45
|
+
installed.push(file);
|
|
46
|
+
}
|
|
47
|
+
return installed;
|
|
48
|
+
}
|
|
49
|
+
/** Generate .forge.json with auto-detected gates if it doesn't already exist. */
|
|
50
|
+
async function generateForgeConfig(projectDir) {
|
|
51
|
+
const configPath = join(projectDir, ".forge.json");
|
|
52
|
+
// Don't overwrite existing config
|
|
53
|
+
try {
|
|
54
|
+
await readFile(configPath, "utf-8");
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// File doesn't exist, proceed to create
|
|
59
|
+
}
|
|
60
|
+
// Auto-detect gates from package.json
|
|
61
|
+
const gateMap = {
|
|
62
|
+
typescript: "types",
|
|
63
|
+
"@biomejs/biome": "lint",
|
|
64
|
+
biome: "lint",
|
|
65
|
+
vitest: "tests",
|
|
66
|
+
jest: "tests",
|
|
67
|
+
};
|
|
68
|
+
const gates = new Set(["types", "lint", "tests"]);
|
|
69
|
+
try {
|
|
70
|
+
const pkgContent = await readFile(join(projectDir, "package.json"), "utf-8");
|
|
71
|
+
const pkg = JSON.parse(pkgContent);
|
|
72
|
+
const deps = {
|
|
73
|
+
...pkg.dependencies,
|
|
74
|
+
...pkg.devDependencies,
|
|
75
|
+
};
|
|
76
|
+
const detected = new Set();
|
|
77
|
+
for (const [dep, gate] of Object.entries(gateMap)) {
|
|
78
|
+
if (dep in deps)
|
|
79
|
+
detected.add(gate);
|
|
80
|
+
}
|
|
81
|
+
if (detected.size > 0) {
|
|
82
|
+
gates.clear();
|
|
83
|
+
for (const g of detected)
|
|
84
|
+
gates.add(g);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// No package.json, use defaults
|
|
89
|
+
}
|
|
90
|
+
// Detect Linear team if key is set
|
|
91
|
+
let linearTeam = "";
|
|
92
|
+
const apiKey = process.env.LINEAR_API_KEY;
|
|
93
|
+
if (apiKey) {
|
|
94
|
+
try {
|
|
95
|
+
const { ForgeLinearClient } = await import("./linear/client.js");
|
|
96
|
+
const client = new ForgeLinearClient({ apiKey });
|
|
97
|
+
const teams = await client.listTeams();
|
|
98
|
+
if (teams.length === 1) {
|
|
99
|
+
linearTeam = teams[0].key;
|
|
100
|
+
}
|
|
101
|
+
else if (teams.length > 1) {
|
|
102
|
+
console.log("Linear teams found:");
|
|
103
|
+
for (const team of teams) {
|
|
104
|
+
console.log(` ${team.key} — ${team.name}`);
|
|
105
|
+
}
|
|
106
|
+
console.log('Set "linearTeam" in .forge.json to your team key.');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Linear not reachable, skip
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const config = {
|
|
114
|
+
gates: [...gates],
|
|
115
|
+
maxIterations: 5,
|
|
116
|
+
verifyFreshness: 600000,
|
|
117
|
+
linearTeam,
|
|
118
|
+
};
|
|
119
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
/** Copy pre-commit hook to .forge/hooks/ in the project. */
|
|
123
|
+
async function installPreCommitHook(projectDir) {
|
|
124
|
+
const hookSource = join(packageRoot, "hooks", "pre-commit-verify.js");
|
|
125
|
+
const hookTarget = join(projectDir, ".forge", "hooks", "pre-commit-verify.js");
|
|
126
|
+
try {
|
|
127
|
+
await readFile(hookSource);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
await mkdir(join(projectDir, ".forge", "hooks"), { recursive: true });
|
|
133
|
+
await copyFile(hookSource, hookTarget);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
/** Append forge section to CLAUDE.md if not already present. */
|
|
137
|
+
async function updateClaudeMd(projectDir) {
|
|
138
|
+
const claudeMdPath = join(projectDir, "CLAUDE.md");
|
|
139
|
+
let content = "";
|
|
140
|
+
try {
|
|
141
|
+
content = await readFile(claudeMdPath, "utf-8");
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// File doesn't exist, create with forge content
|
|
145
|
+
await writeFile(claudeMdPath, `# Project Instructions\n${FORGE_CLAUDE_SECTION}`, "utf-8");
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
// Check if forge content is already present
|
|
149
|
+
if (content.includes("## Forge Quick Reference") || content.includes("npx forge verify")) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
await writeFile(claudeMdPath, content.trimEnd() + "\n" + FORGE_CLAUDE_SECTION, "utf-8");
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
/** Validate Linear connection if API key is set. */
|
|
156
|
+
async function validateLinear() {
|
|
157
|
+
const apiKey = process.env.LINEAR_API_KEY;
|
|
158
|
+
if (!apiKey)
|
|
159
|
+
return false;
|
|
160
|
+
try {
|
|
161
|
+
const { ForgeLinearClient } = await import("./linear/client.js");
|
|
162
|
+
const client = new ForgeLinearClient({ apiKey });
|
|
163
|
+
const teams = await client.listTeams();
|
|
164
|
+
if (teams.length > 0) {
|
|
165
|
+
console.log(`Linear: authenticated (${teams.length} team${teams.length > 1 ? "s" : ""} found)`);
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
console.log("Linear: authenticated but no teams found");
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
console.log("Linear: connection failed");
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
export async function runSetup(opts) {
|
|
177
|
+
const { projectDir, skillsOnly } = opts;
|
|
178
|
+
// Step 2: Install skill files (always runs)
|
|
179
|
+
const installed = await installSkills();
|
|
180
|
+
if (installed.length > 0) {
|
|
181
|
+
console.log(`Skills synced: ${installed.join(", ")}`);
|
|
182
|
+
}
|
|
183
|
+
if (skillsOnly)
|
|
184
|
+
return;
|
|
185
|
+
// Step 1: Generate .forge.json
|
|
186
|
+
const configCreated = await generateForgeConfig(projectDir);
|
|
187
|
+
if (configCreated) {
|
|
188
|
+
console.log("Created .forge.json");
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.log(".forge.json already exists, skipping");
|
|
192
|
+
}
|
|
193
|
+
// Step 3: Install pre-commit hook
|
|
194
|
+
const hookInstalled = await installPreCommitHook(projectDir);
|
|
195
|
+
if (hookInstalled) {
|
|
196
|
+
console.log("Pre-commit hook installed at .forge/hooks/pre-commit-verify.js");
|
|
197
|
+
console.log("Add to .claude/settings.json hooks to activate");
|
|
198
|
+
}
|
|
199
|
+
// Step 4: Update CLAUDE.md
|
|
200
|
+
const claudeUpdated = await updateClaudeMd(projectDir);
|
|
201
|
+
if (claudeUpdated) {
|
|
202
|
+
console.log("Forge section added to CLAUDE.md");
|
|
203
|
+
}
|
|
204
|
+
// Step 5: Validate Linear
|
|
205
|
+
await validateLinear();
|
|
206
|
+
console.log("\nSetup complete. Run 'npx forge doctor' to verify your environment.");
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** Write verification results to .forge/last-verify.json. */
|
|
4
|
+
export async function writeVerifyCache(projectDir, pipeline) {
|
|
5
|
+
const forgeDir = join(projectDir, ".forge");
|
|
6
|
+
await mkdir(forgeDir, { recursive: true });
|
|
7
|
+
const cache = {
|
|
8
|
+
timestamp: new Date().toISOString(),
|
|
9
|
+
result: pipeline.result,
|
|
10
|
+
gates: {},
|
|
11
|
+
};
|
|
12
|
+
for (const gate of pipeline.gates) {
|
|
13
|
+
cache.gates[gate.gate] = {
|
|
14
|
+
passed: gate.passed,
|
|
15
|
+
errors: gate.errors.length > 0 ? gate.errors : undefined,
|
|
16
|
+
summary: gate.passed
|
|
17
|
+
? "passed"
|
|
18
|
+
: `${gate.errors.length} error(s)`,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
await writeFile(join(forgeDir, "last-verify.json"), JSON.stringify(cache, null, 2), "utf-8");
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/state/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,6DAA6D;AAC7D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAAkB,EAClB,QAAwB;IAExB,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,KAAK,GAAgB;QACzB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,KAAK,EAAE,EAAE;KACV,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;YACxD,OAAO,EAAE,IAAI,CAAC,MAAM;gBAClB,CAAC,CAAC,QAAQ;gBACV,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,WAAW;SACrC,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,CACb,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,EAClC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAC9B,OAAO,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { PRDStatus } from "../types.js";
|
|
3
|
+
export declare const prdStatusSchema: z.ZodObject<{
|
|
4
|
+
project: z.ZodString;
|
|
5
|
+
slug: z.ZodString;
|
|
6
|
+
branch: z.ZodString;
|
|
7
|
+
createdAt: z.ZodString;
|
|
8
|
+
linearProjectId: z.ZodOptional<z.ZodString>;
|
|
9
|
+
linearTeamId: z.ZodOptional<z.ZodString>;
|
|
10
|
+
milestones: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
11
|
+
status: z.ZodEnum<["pending", "in_progress", "complete"]>;
|
|
12
|
+
linearMilestoneId: z.ZodOptional<z.ZodString>;
|
|
13
|
+
linearIssueIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
14
|
+
completedAt: z.ZodOptional<z.ZodString>;
|
|
15
|
+
}, "strip", z.ZodTypeAny, {
|
|
16
|
+
status: "pending" | "in_progress" | "complete";
|
|
17
|
+
linearMilestoneId?: string | undefined;
|
|
18
|
+
linearIssueIds?: string[] | undefined;
|
|
19
|
+
completedAt?: string | undefined;
|
|
20
|
+
}, {
|
|
21
|
+
status: "pending" | "in_progress" | "complete";
|
|
22
|
+
linearMilestoneId?: string | undefined;
|
|
23
|
+
linearIssueIds?: string[] | undefined;
|
|
24
|
+
completedAt?: string | undefined;
|
|
25
|
+
}>>;
|
|
26
|
+
}, "strip", z.ZodTypeAny, {
|
|
27
|
+
project: string;
|
|
28
|
+
slug: string;
|
|
29
|
+
branch: string;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
milestones: Record<string, {
|
|
32
|
+
status: "pending" | "in_progress" | "complete";
|
|
33
|
+
linearMilestoneId?: string | undefined;
|
|
34
|
+
linearIssueIds?: string[] | undefined;
|
|
35
|
+
completedAt?: string | undefined;
|
|
36
|
+
}>;
|
|
37
|
+
linearProjectId?: string | undefined;
|
|
38
|
+
linearTeamId?: string | undefined;
|
|
39
|
+
}, {
|
|
40
|
+
project: string;
|
|
41
|
+
slug: string;
|
|
42
|
+
branch: string;
|
|
43
|
+
createdAt: string;
|
|
44
|
+
milestones: Record<string, {
|
|
45
|
+
status: "pending" | "in_progress" | "complete";
|
|
46
|
+
linearMilestoneId?: string | undefined;
|
|
47
|
+
linearIssueIds?: string[] | undefined;
|
|
48
|
+
completedAt?: string | undefined;
|
|
49
|
+
}>;
|
|
50
|
+
linearProjectId?: string | undefined;
|
|
51
|
+
linearTeamId?: string | undefined;
|
|
52
|
+
}>;
|
|
53
|
+
/** Read and validate a PRD status file. */
|
|
54
|
+
export declare function readStatus(projectDir: string, slug: string): Promise<PRDStatus>;
|
|
55
|
+
/** Write a PRD status file atomically (temp file + rename). */
|
|
56
|
+
export declare function writeStatus(projectDir: string, slug: string, status: PRDStatus): Promise<void>;
|
|
57
|
+
/** Update a single milestone's status within a PRD status file. */
|
|
58
|
+
export declare function updateMilestoneStatus(projectDir: string, slug: string, milestone: string, newStatus: "pending" | "in_progress" | "complete"): Promise<PRDStatus>;
|
|
59
|
+
/** Discover all valid PRD status files in .planning/status/. */
|
|
60
|
+
export declare function discoverStatuses(projectDir: string): Promise<PRDStatus[]>;
|
|
61
|
+
/** Find the first pending milestone in each PRD. */
|
|
62
|
+
export declare function findNextPending(statuses: PRDStatus[]): Array<{
|
|
63
|
+
slug: string;
|
|
64
|
+
milestone: string;
|
|
65
|
+
status: PRDStatus;
|
|
66
|
+
}>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { readFile, readdir, rename, writeFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const milestoneStatusSchema = z.object({
|
|
6
|
+
status: z.enum(["pending", "in_progress", "complete"]),
|
|
7
|
+
linearMilestoneId: z.string().optional(),
|
|
8
|
+
linearIssueIds: z.array(z.string()).optional(),
|
|
9
|
+
completedAt: z.string().optional(),
|
|
10
|
+
});
|
|
11
|
+
export const prdStatusSchema = z.object({
|
|
12
|
+
project: z.string(),
|
|
13
|
+
slug: z.string(),
|
|
14
|
+
branch: z.string(),
|
|
15
|
+
createdAt: z.string(),
|
|
16
|
+
linearProjectId: z.string().optional(),
|
|
17
|
+
linearTeamId: z.string().optional(),
|
|
18
|
+
milestones: z.record(z.string(), milestoneStatusSchema),
|
|
19
|
+
});
|
|
20
|
+
function statusDir(projectDir) {
|
|
21
|
+
return join(projectDir, ".planning", "status");
|
|
22
|
+
}
|
|
23
|
+
function statusPath(projectDir, slug) {
|
|
24
|
+
return join(statusDir(projectDir), `${slug}.json`);
|
|
25
|
+
}
|
|
26
|
+
/** Read and validate a PRD status file. */
|
|
27
|
+
export async function readStatus(projectDir, slug) {
|
|
28
|
+
const raw = await readFile(statusPath(projectDir, slug), "utf-8");
|
|
29
|
+
const json = JSON.parse(raw);
|
|
30
|
+
return prdStatusSchema.parse(json);
|
|
31
|
+
}
|
|
32
|
+
/** Write a PRD status file atomically (temp file + rename). */
|
|
33
|
+
export async function writeStatus(projectDir, slug, status) {
|
|
34
|
+
const dir = statusDir(projectDir);
|
|
35
|
+
await mkdir(dir, { recursive: true });
|
|
36
|
+
const target = statusPath(projectDir, slug);
|
|
37
|
+
const temp = `${target}.${randomUUID()}.tmp`;
|
|
38
|
+
await writeFile(temp, JSON.stringify(status, null, 2), "utf-8");
|
|
39
|
+
await rename(temp, target);
|
|
40
|
+
}
|
|
41
|
+
/** Update a single milestone's status within a PRD status file. */
|
|
42
|
+
export async function updateMilestoneStatus(projectDir, slug, milestone, newStatus) {
|
|
43
|
+
const status = await readStatus(projectDir, slug);
|
|
44
|
+
if (!status.milestones[milestone]) {
|
|
45
|
+
status.milestones[milestone] = { status: newStatus };
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
status.milestones[milestone].status = newStatus;
|
|
49
|
+
}
|
|
50
|
+
if (newStatus === "complete") {
|
|
51
|
+
status.milestones[milestone].completedAt = new Date().toISOString();
|
|
52
|
+
}
|
|
53
|
+
await writeStatus(projectDir, slug, status);
|
|
54
|
+
return status;
|
|
55
|
+
}
|
|
56
|
+
/** Discover all valid PRD status files in .planning/status/. */
|
|
57
|
+
export async function discoverStatuses(projectDir) {
|
|
58
|
+
const dir = statusDir(projectDir);
|
|
59
|
+
let entries;
|
|
60
|
+
try {
|
|
61
|
+
entries = await readdir(dir);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
const statuses = [];
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
if (!entry.endsWith(".json"))
|
|
69
|
+
continue;
|
|
70
|
+
try {
|
|
71
|
+
const raw = await readFile(join(dir, entry), "utf-8");
|
|
72
|
+
const json = JSON.parse(raw);
|
|
73
|
+
const parsed = prdStatusSchema.parse(json);
|
|
74
|
+
statuses.push(parsed);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// skip invalid files
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return statuses;
|
|
81
|
+
}
|
|
82
|
+
/** Find the first pending milestone in each PRD. */
|
|
83
|
+
export function findNextPending(statuses) {
|
|
84
|
+
const results = [];
|
|
85
|
+
for (const status of statuses) {
|
|
86
|
+
const milestoneKeys = Object.keys(status.milestones);
|
|
87
|
+
for (const key of milestoneKeys) {
|
|
88
|
+
if (status.milestones[key].status === "pending") {
|
|
89
|
+
results.push({ slug: status.slug, milestone: key, status });
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/state/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;IACtD,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACxC,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC9C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACtC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACnC,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,qBAAqB,CAAC;CACxD,CAAC,CAAC;AAEH,SAAS,SAAS,CAAC,UAAkB;IACnC,OAAO,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,UAAU,CAAC,UAAkB,EAAE,IAAY;IAClD,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,2CAA2C;AAC3C,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,UAAkB,EAClB,IAAY;IAEZ,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;IAClE,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,OAAO,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAAkB,EAClB,IAAY,EACZ,MAAiB;IAEjB,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAClC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,GAAG,MAAM,IAAI,UAAU,EAAE,MAAM,CAAC;IAC7C,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAChE,MAAM,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,UAAkB,EAClB,IAAY,EACZ,SAAiB,EACjB,SAAiD;IAEjD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC;IAClD,CAAC;IACD,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;QAC7B,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtE,CAAC;IACD,MAAM,WAAW,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gEAAgE;AAChE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAAkB;IAElB,MAAM,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC;IAClC,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,QAAQ,GAAgB,EAAE,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACvC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;YACtD,MAAM,IAAI,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACtC,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,eAAe,CAC7B,QAAqB;IAErB,MAAM,OAAO,GAAkE,EAAE,CAAC;IAClF,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC9B,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QACrD,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAChC,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAChD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC5D,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,131 +1,63 @@
|
|
|
1
|
-
/** Structured error from a verification gate */
|
|
1
|
+
/** Structured error from a verification gate. */
|
|
2
2
|
export interface GateError {
|
|
3
|
-
file
|
|
4
|
-
line
|
|
3
|
+
file: string;
|
|
4
|
+
line: number;
|
|
5
|
+
column?: number;
|
|
5
6
|
message: string;
|
|
6
|
-
|
|
7
|
+
rule?: string;
|
|
7
8
|
}
|
|
8
|
-
/** Result
|
|
9
|
+
/** Result of running a single verification gate. */
|
|
9
10
|
export interface GateResult {
|
|
10
11
|
gate: string;
|
|
11
12
|
passed: boolean;
|
|
12
13
|
errors: GateError[];
|
|
13
|
-
|
|
14
|
-
duration_ms: number;
|
|
14
|
+
durationMs: number;
|
|
15
15
|
}
|
|
16
|
-
/**
|
|
17
|
-
export interface VisualResult extends GateResult {
|
|
18
|
-
screenshots: Array<{
|
|
19
|
-
page: string;
|
|
20
|
-
path: string;
|
|
21
|
-
}>;
|
|
22
|
-
consoleErrors: string[];
|
|
23
|
-
}
|
|
24
|
-
/** Extended result for code review with review-specific metadata */
|
|
25
|
-
export interface ReviewResult extends GateResult {
|
|
26
|
-
reviewFindings: Array<{
|
|
27
|
-
type: "prd_compliance" | "rule_violation" | "style";
|
|
28
|
-
severity: "error" | "warning";
|
|
29
|
-
file?: string;
|
|
30
|
-
line?: number;
|
|
31
|
-
message: string;
|
|
32
|
-
remediation: string;
|
|
33
|
-
source: string;
|
|
34
|
-
}>;
|
|
35
|
-
}
|
|
36
|
-
/** Input for the full verification pipeline */
|
|
37
|
-
export interface PipelineInput {
|
|
38
|
-
projectDir: string;
|
|
39
|
-
appDir?: string;
|
|
40
|
-
gates?: string[];
|
|
41
|
-
prdPath?: string;
|
|
42
|
-
milestoneType?: "ui" | "data" | "mixed";
|
|
43
|
-
pages?: string[];
|
|
44
|
-
apiEndpoints?: string[];
|
|
45
|
-
maxIterations?: number;
|
|
46
|
-
devServerCommand?: string;
|
|
47
|
-
devServerPort?: number;
|
|
48
|
-
baseBranch?: string;
|
|
49
|
-
reviewBlocking?: boolean;
|
|
50
|
-
}
|
|
51
|
-
/** Result from the full verification pipeline */
|
|
52
|
-
export interface PipelineResult {
|
|
53
|
-
passed: boolean;
|
|
54
|
-
iteration: number;
|
|
55
|
-
maxIterations: number;
|
|
56
|
-
gates: GateResult[];
|
|
57
|
-
report: string;
|
|
58
|
-
}
|
|
59
|
-
/** Testing configuration from .forge.json */
|
|
60
|
-
export interface TestingConfig {
|
|
61
|
-
enforce: boolean;
|
|
62
|
-
runner: "vitest" | "jest" | "none";
|
|
63
|
-
testDir: string;
|
|
64
|
-
sourceDir: string;
|
|
65
|
-
structural: boolean;
|
|
66
|
-
categories: string[];
|
|
67
|
-
}
|
|
68
|
-
/** Configuration from .forge.json */
|
|
16
|
+
/** Full configuration shape matching .forge.json. */
|
|
69
17
|
export interface ForgeConfig {
|
|
70
|
-
appDir?: string;
|
|
71
18
|
gates: string[];
|
|
19
|
+
gateTimeouts: Record<string, number>;
|
|
72
20
|
maxIterations: number;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
pages?: string[];
|
|
80
|
-
prdPath?: string;
|
|
81
|
-
linearProject?: string;
|
|
82
|
-
review?: {
|
|
83
|
-
blocking: boolean;
|
|
21
|
+
linearTeam: string;
|
|
22
|
+
linearStates: {
|
|
23
|
+
planned: string;
|
|
24
|
+
inProgress: string;
|
|
25
|
+
inReview: string;
|
|
26
|
+
done: string;
|
|
84
27
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
28
|
+
verifyFreshness: number;
|
|
29
|
+
forgeVersion: string;
|
|
30
|
+
}
|
|
31
|
+
/** Per-milestone status tracking. */
|
|
32
|
+
export interface MilestoneStatus {
|
|
33
|
+
status: 'pending' | 'in_progress' | 'complete';
|
|
34
|
+
linearMilestoneId?: string;
|
|
35
|
+
linearIssueIds?: string[];
|
|
36
|
+
completedAt?: string;
|
|
37
|
+
}
|
|
38
|
+
/** PRD status file shape stored in .planning/status/. */
|
|
39
|
+
export interface PRDStatus {
|
|
40
|
+
project: string;
|
|
41
|
+
slug: string;
|
|
42
|
+
branch: string;
|
|
43
|
+
createdAt: string;
|
|
44
|
+
linearProjectId?: string;
|
|
45
|
+
linearTeamId?: string;
|
|
46
|
+
milestones: Record<string, MilestoneStatus>;
|
|
88
47
|
}
|
|
89
|
-
/**
|
|
48
|
+
/** Cached verification result. */
|
|
90
49
|
export interface VerifyCache {
|
|
91
|
-
passed: boolean;
|
|
92
50
|
timestamp: string;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
name: string;
|
|
99
|
-
width: number;
|
|
100
|
-
height: number;
|
|
101
|
-
}
|
|
102
|
-
/** Serialized DOM node snapshot from page.evaluate() extraction */
|
|
103
|
-
export interface DOMSnapshot {
|
|
104
|
-
tag: string;
|
|
105
|
-
id?: string;
|
|
106
|
-
className?: string;
|
|
107
|
-
visible: boolean;
|
|
108
|
-
rect?: {
|
|
109
|
-
x: number;
|
|
110
|
-
y: number;
|
|
111
|
-
width: number;
|
|
112
|
-
height: number;
|
|
113
|
-
};
|
|
114
|
-
children: DOMSnapshot[];
|
|
115
|
-
}
|
|
116
|
-
/** Result from multi-viewport visual capture with DOM extraction */
|
|
117
|
-
export interface VisualCaptureResult {
|
|
118
|
-
screenshots: Array<{
|
|
119
|
-
page: string;
|
|
120
|
-
viewport: string;
|
|
121
|
-
path: string;
|
|
51
|
+
result: 'PASSED' | 'FAILED';
|
|
52
|
+
gates: Record<string, {
|
|
53
|
+
passed: boolean;
|
|
54
|
+
errors?: GateError[];
|
|
55
|
+
summary?: string;
|
|
122
56
|
}>;
|
|
123
|
-
domSnapshots: Record<string, DOMSnapshot>;
|
|
124
|
-
metadata: {
|
|
125
|
-
viewports: ViewportConfig[];
|
|
126
|
-
pagePath: string;
|
|
127
|
-
capturedAt: string;
|
|
128
|
-
durationMs: number;
|
|
129
|
-
};
|
|
130
57
|
}
|
|
131
|
-
|
|
58
|
+
/** Overall result of a full verification pipeline run. */
|
|
59
|
+
export interface PipelineResult {
|
|
60
|
+
result: 'PASSED' | 'FAILED';
|
|
61
|
+
gates: GateResult[];
|
|
62
|
+
durationMs: number;
|
|
63
|
+
}
|