forge-cc 1.0.0 → 1.0.1
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/package.json +3 -2
- package/dist/gates/codex-gate.d.ts +0 -51
- package/dist/gates/codex-gate.js +0 -121
- package/dist/gates/codex-gate.js.map +0 -1
- package/dist/gates/prd-gate.d.ts +0 -7
- package/dist/gates/prd-gate.js +0 -193
- package/dist/gates/prd-gate.js.map +0 -1
- package/dist/gates/remediation.d.ts +0 -46
- package/dist/gates/remediation.js +0 -423
- package/dist/gates/remediation.js.map +0 -1
- package/dist/gates/review-gate.d.ts +0 -16
- package/dist/gates/review-gate.js +0 -479
- package/dist/gates/review-gate.js.map +0 -1
- package/dist/gates/runtime-gate.d.ts +0 -5
- package/dist/gates/runtime-gate.js +0 -99
- package/dist/gates/runtime-gate.js.map +0 -1
- package/dist/gates/test-analysis.d.ts +0 -21
- package/dist/gates/test-analysis.js +0 -394
- package/dist/gates/test-analysis.js.map +0 -1
- package/dist/gates/visual-capture.d.ts +0 -24
- package/dist/gates/visual-capture.js +0 -144
- package/dist/gates/visual-capture.js.map +0 -1
- package/dist/gates/visual-gate.d.ts +0 -18
- package/dist/gates/visual-gate.js +0 -234
- package/dist/gates/visual-gate.js.map +0 -1
- package/dist/gates/visual-reviewer.d.ts +0 -11
- package/dist/gates/visual-reviewer.js +0 -211
- package/dist/gates/visual-reviewer.js.map +0 -1
- package/dist/go/auto-chain.d.ts +0 -136
- package/dist/go/auto-chain.js +0 -389
- package/dist/go/auto-chain.js.map +0 -1
- package/dist/go/executor.d.ts +0 -137
- package/dist/go/executor.js +0 -447
- package/dist/go/executor.js.map +0 -1
- package/dist/go/finalize.d.ts +0 -108
- package/dist/go/finalize.js +0 -331
- package/dist/go/finalize.js.map +0 -1
- package/dist/go/linear-sync-cli.d.ts +0 -55
- package/dist/go/linear-sync-cli.js +0 -192
- package/dist/go/linear-sync-cli.js.map +0 -1
- package/dist/go/linear-sync.d.ts +0 -112
- package/dist/go/linear-sync.js +0 -375
- package/dist/go/linear-sync.js.map +0 -1
- package/dist/go/prd-queue.d.ts +0 -43
- package/dist/go/prd-queue.js +0 -67
- package/dist/go/prd-queue.js.map +0 -1
- package/dist/go/prd-selector.d.ts +0 -57
- package/dist/go/prd-selector.js +0 -101
- package/dist/go/prd-selector.js.map +0 -1
- package/dist/go/verify-loop.d.ts +0 -64
- package/dist/go/verify-loop.js +0 -327
- package/dist/go/verify-loop.js.map +0 -1
- package/dist/hooks/pre-commit.d.ts +0 -5
- package/dist/hooks/pre-commit.js +0 -75
- package/dist/hooks/pre-commit.js.map +0 -1
- package/dist/linear/issues.d.ts +0 -22
- package/dist/linear/issues.js +0 -51
- package/dist/linear/issues.js.map +0 -1
- package/dist/linear/milestones.d.ts +0 -11
- package/dist/linear/milestones.js +0 -32
- package/dist/linear/milestones.js.map +0 -1
- package/dist/linear/projects.d.ts +0 -16
- package/dist/linear/projects.js +0 -51
- package/dist/linear/projects.js.map +0 -1
- package/dist/reporter/human.d.ts +0 -7
- package/dist/reporter/human.js +0 -93
- package/dist/reporter/human.js.map +0 -1
- package/dist/reporter/json.d.ts +0 -2
- package/dist/reporter/json.js +0 -4
- package/dist/reporter/json.js.map +0 -1
- package/dist/setup/structural-templates.d.ts +0 -12
- package/dist/setup/structural-templates.js +0 -288
- package/dist/setup/structural-templates.js.map +0 -1
- package/dist/setup/templates.d.ts +0 -17
- package/dist/setup/templates.js +0 -109
- package/dist/setup/templates.js.map +0 -1
- package/dist/setup/test-planner.d.ts +0 -38
- package/dist/setup/test-planner.js +0 -91
- package/dist/setup/test-planner.js.map +0 -1
- package/dist/setup/test-scaffold.d.ts +0 -31
- package/dist/setup/test-scaffold.js +0 -209
- package/dist/setup/test-scaffold.js.map +0 -1
- package/dist/setup/test-templates.d.ts +0 -37
- package/dist/setup/test-templates.js +0 -313
- package/dist/setup/test-templates.js.map +0 -1
- package/dist/spec/generator.d.ts +0 -34
- package/dist/spec/generator.js +0 -227
- package/dist/spec/generator.js.map +0 -1
- package/dist/spec/interview.d.ts +0 -142
- package/dist/spec/interview.js +0 -287
- package/dist/spec/interview.js.map +0 -1
- package/dist/spec/linear-sync.d.ts +0 -48
- package/dist/spec/linear-sync.js +0 -125
- package/dist/spec/linear-sync.js.map +0 -1
- package/dist/spec/scanner.d.ts +0 -79
- package/dist/spec/scanner.js +0 -566
- package/dist/spec/scanner.js.map +0 -1
- package/dist/spec/templates.d.ts +0 -375
- package/dist/spec/templates.js +0 -95
- package/dist/spec/templates.js.map +0 -1
- package/dist/state/prd-status.d.ts +0 -62
- package/dist/state/prd-status.js +0 -122
- package/dist/state/prd-status.js.map +0 -1
- package/dist/state/reader.d.ts +0 -7
- package/dist/state/reader.js +0 -43
- package/dist/state/reader.js.map +0 -1
- package/dist/state/writer.d.ts +0 -21
- package/dist/state/writer.js +0 -106
- package/dist/state/writer.js.map +0 -1
- package/dist/team/consensus.d.ts +0 -28
- package/dist/team/consensus.js +0 -130
- package/dist/team/consensus.js.map +0 -1
- package/dist/team/index.d.ts +0 -4
- package/dist/team/index.js +0 -5
- package/dist/team/index.js.map +0 -1
- package/dist/team/lifecycle.d.ts +0 -37
- package/dist/team/lifecycle.js +0 -92
- package/dist/team/lifecycle.js.map +0 -1
- package/dist/team/reviewer.d.ts +0 -10
- package/dist/team/reviewer.js +0 -345
- package/dist/team/reviewer.js.map +0 -1
- package/dist/team/types.d.ts +0 -269
- package/dist/team/types.js +0 -70
- package/dist/team/types.js.map +0 -1
- package/dist/utils/browser.d.ts +0 -10
- package/dist/utils/browser.js +0 -96
- package/dist/utils/browser.js.map +0 -1
- package/dist/utils/platform.d.ts +0 -29
- package/dist/utils/platform.js +0 -90
- package/dist/utils/platform.js.map +0 -1
- package/dist/worktree/identity.d.ts +0 -9
- package/dist/worktree/identity.js +0 -32
- package/dist/worktree/identity.js.map +0 -1
- package/dist/worktree/parallel.d.ts +0 -87
- package/dist/worktree/parallel.js +0 -328
- package/dist/worktree/parallel.js.map +0 -1
- package/dist/worktree/session.d.ts +0 -67
- package/dist/worktree/session.js +0 -194
- package/dist/worktree/session.js.map +0 -1
- package/dist/worktree/state-merge.d.ts +0 -43
- package/dist/worktree/state-merge.js +0 -162
- package/dist/worktree/state-merge.js.map +0 -1
|
@@ -1,234 +0,0 @@
|
|
|
1
|
-
import { getBrowser, startDevServer, stopDevServer, waitForServer, } from "../utils/browser.js";
|
|
2
|
-
import { captureVisual } from "./visual-capture.js";
|
|
3
|
-
import { reviewVisual } from "./visual-reviewer.js";
|
|
4
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { join } from "node:path";
|
|
6
|
-
// ---------------------------------------------------------------------------
|
|
7
|
-
// Before snapshot disk persistence
|
|
8
|
-
// ---------------------------------------------------------------------------
|
|
9
|
-
/** Sanitize a page path to a safe filename key (e.g. "/" -> "index", "/dashboard" -> "dashboard") */
|
|
10
|
-
function snapshotKey(pagePath) {
|
|
11
|
-
const sanitized = pagePath.replace(/\//g, "_").replace(/^_/, "");
|
|
12
|
-
return sanitized || "index";
|
|
13
|
-
}
|
|
14
|
-
/** Save a before snapshot to disk so it survives across CLI invocations. */
|
|
15
|
-
function saveBeforeSnapshot(screenshotDir, pagePath, result) {
|
|
16
|
-
const dir = join(screenshotDir, "before");
|
|
17
|
-
mkdirSync(dir, { recursive: true });
|
|
18
|
-
const filePath = join(dir, `${snapshotKey(pagePath)}.snapshot.json`);
|
|
19
|
-
writeFileSync(filePath, JSON.stringify(result, null, 2));
|
|
20
|
-
}
|
|
21
|
-
/** Load a before snapshot from disk. Returns null if none exists. */
|
|
22
|
-
function loadBeforeSnapshot(screenshotDir, pagePath) {
|
|
23
|
-
const filePath = join(screenshotDir, "before", `${snapshotKey(pagePath)}.snapshot.json`);
|
|
24
|
-
if (!existsSync(filePath))
|
|
25
|
-
return null;
|
|
26
|
-
try {
|
|
27
|
-
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Capture and store "before" snapshots for the given pages.
|
|
35
|
-
* Snapshots are persisted to disk (.forge/screenshots/before/*.snapshot.json)
|
|
36
|
-
* so they survive across separate CLI invocations.
|
|
37
|
-
*/
|
|
38
|
-
export async function captureBeforeSnapshots(projectDir, pages, options) {
|
|
39
|
-
const resolvedPages = pages.length > 0 ? pages : ["/"];
|
|
40
|
-
const port = options?.devServerPort ?? 3000;
|
|
41
|
-
const screenshotDir = options?.screenshotDir ?? join(projectDir, ".forge", "screenshots");
|
|
42
|
-
const beforeDir = join(screenshotDir, "before");
|
|
43
|
-
mkdirSync(beforeDir, { recursive: true });
|
|
44
|
-
try {
|
|
45
|
-
await startDevServer(projectDir, options?.devServerCommand, port);
|
|
46
|
-
const ready = await waitForServer(port);
|
|
47
|
-
if (!ready) {
|
|
48
|
-
return; // Cannot capture baseline — verifyVisual will still work without it
|
|
49
|
-
}
|
|
50
|
-
const browser = await getBrowser();
|
|
51
|
-
const context = await browser.newContext();
|
|
52
|
-
try {
|
|
53
|
-
for (const pagePath of resolvedPages) {
|
|
54
|
-
const page = await context.newPage();
|
|
55
|
-
try {
|
|
56
|
-
await page.goto(`http://localhost:${port}${pagePath}`, {
|
|
57
|
-
waitUntil: "networkidle",
|
|
58
|
-
timeout: 30_000,
|
|
59
|
-
});
|
|
60
|
-
const result = await captureVisual(page, {
|
|
61
|
-
pagePath,
|
|
62
|
-
screenshotDir: beforeDir,
|
|
63
|
-
});
|
|
64
|
-
saveBeforeSnapshot(screenshotDir, pagePath, result);
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
// Failed to capture baseline for this page — skip it
|
|
68
|
-
}
|
|
69
|
-
finally {
|
|
70
|
-
await page.close();
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
finally {
|
|
75
|
-
await context.close();
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
await stopDevServer();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
/** Clear all stored "before" snapshots from disk (e.g. between milestones). */
|
|
83
|
-
export function clearBeforeSnapshots(projectDir) {
|
|
84
|
-
const dir = join(projectDir, ".forge", "screenshots", "before");
|
|
85
|
-
let files;
|
|
86
|
-
try {
|
|
87
|
-
files = readdirSync(dir);
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
return; // Directory doesn't exist — nothing to clear
|
|
91
|
-
}
|
|
92
|
-
for (const file of files) {
|
|
93
|
-
if (file.endsWith(".snapshot.json")) {
|
|
94
|
-
try {
|
|
95
|
-
unlinkSync(join(dir, file));
|
|
96
|
-
}
|
|
97
|
-
catch { /* ignore */ }
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// ---------------------------------------------------------------------------
|
|
102
|
-
// Main visual gate
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
export async function verifyVisual(projectDir, pages, options) {
|
|
105
|
-
const start = Date.now();
|
|
106
|
-
const resolvedPages = pages.length > 0 ? pages : ["/"];
|
|
107
|
-
const port = options?.devServerPort ?? 3000;
|
|
108
|
-
const screenshotDir = options?.screenshotDir ?? join(projectDir, ".forge", "screenshots");
|
|
109
|
-
const afterDir = join(screenshotDir, "after");
|
|
110
|
-
const consoleErrors = [];
|
|
111
|
-
const warnings = [];
|
|
112
|
-
const screenshots = [];
|
|
113
|
-
mkdirSync(afterDir, { recursive: true });
|
|
114
|
-
try {
|
|
115
|
-
// Start dev server
|
|
116
|
-
try {
|
|
117
|
-
await startDevServer(projectDir, options?.devServerCommand, port);
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
const message = err instanceof Error ? err.message : "Unknown dev server error";
|
|
121
|
-
return {
|
|
122
|
-
gate: "visual",
|
|
123
|
-
passed: false,
|
|
124
|
-
errors: [{ message: `Dev server failed to start: ${message}` }],
|
|
125
|
-
warnings,
|
|
126
|
-
duration_ms: Date.now() - start,
|
|
127
|
-
screenshots,
|
|
128
|
-
consoleErrors,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
// Ensure server is reachable
|
|
132
|
-
const ready = await waitForServer(port);
|
|
133
|
-
if (!ready) {
|
|
134
|
-
return {
|
|
135
|
-
gate: "visual",
|
|
136
|
-
passed: false,
|
|
137
|
-
errors: [{ message: `Dev server not reachable on port ${port}` }],
|
|
138
|
-
warnings,
|
|
139
|
-
duration_ms: Date.now() - start,
|
|
140
|
-
screenshots,
|
|
141
|
-
consoleErrors,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
// Launch browser and create context
|
|
145
|
-
const browser = await getBrowser();
|
|
146
|
-
const context = await browser.newContext();
|
|
147
|
-
const reviewerErrors = [];
|
|
148
|
-
try {
|
|
149
|
-
for (const pagePath of resolvedPages) {
|
|
150
|
-
const page = await context.newPage();
|
|
151
|
-
// Collect console errors
|
|
152
|
-
page.on("console", (msg) => {
|
|
153
|
-
if (msg.type() === "error") {
|
|
154
|
-
consoleErrors.push(msg.text());
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
page.on("pageerror", (err) => {
|
|
158
|
-
consoleErrors.push(err.message);
|
|
159
|
-
});
|
|
160
|
-
// Navigate to the page
|
|
161
|
-
try {
|
|
162
|
-
await page.goto(`http://localhost:${port}${pagePath}`, {
|
|
163
|
-
waitUntil: "networkidle",
|
|
164
|
-
timeout: 30_000,
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
catch (err) {
|
|
168
|
-
const message = err instanceof Error ? err.message : "Navigation failed";
|
|
169
|
-
consoleErrors.push(`Navigation error for ${pagePath}: ${message}`);
|
|
170
|
-
await page.close();
|
|
171
|
-
continue;
|
|
172
|
-
}
|
|
173
|
-
// Capture "after" snapshot using the M1 capture module
|
|
174
|
-
try {
|
|
175
|
-
const afterResult = await captureVisual(page, {
|
|
176
|
-
pagePath,
|
|
177
|
-
screenshotDir: afterDir,
|
|
178
|
-
});
|
|
179
|
-
// Map multi-viewport screenshots to the flat { page, path } format
|
|
180
|
-
for (const shot of afterResult.screenshots) {
|
|
181
|
-
screenshots.push({ page: shot.page, path: shot.path });
|
|
182
|
-
}
|
|
183
|
-
// Compare with "before" snapshot if one exists (loaded from disk)
|
|
184
|
-
const beforeResult = loadBeforeSnapshot(screenshotDir, pagePath);
|
|
185
|
-
if (beforeResult) {
|
|
186
|
-
const findings = reviewVisual(beforeResult, afterResult);
|
|
187
|
-
reviewerErrors.push(...findings);
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
warnings.push(`No baseline snapshot for ${pagePath} — before/after comparison skipped. Call captureBeforeSnapshots() before verifyVisual() to enable.`);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
catch (err) {
|
|
194
|
-
const message = err instanceof Error ? err.message : "Visual capture failed";
|
|
195
|
-
warnings.push(`Visual capture failed for ${pagePath}: ${message}`);
|
|
196
|
-
}
|
|
197
|
-
await page.close();
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
finally {
|
|
201
|
-
await context.close();
|
|
202
|
-
}
|
|
203
|
-
// Combine console errors and reviewer errors into a single GateError list
|
|
204
|
-
const errors = [
|
|
205
|
-
...consoleErrors.map((msg) => ({ message: msg })),
|
|
206
|
-
...reviewerErrors,
|
|
207
|
-
];
|
|
208
|
-
return {
|
|
209
|
-
gate: "visual",
|
|
210
|
-
passed: errors.length === 0,
|
|
211
|
-
errors,
|
|
212
|
-
warnings,
|
|
213
|
-
duration_ms: Date.now() - start,
|
|
214
|
-
screenshots,
|
|
215
|
-
consoleErrors,
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
catch (err) {
|
|
219
|
-
const message = err instanceof Error ? err.message : "Unknown error in verifyVisual";
|
|
220
|
-
return {
|
|
221
|
-
gate: "visual",
|
|
222
|
-
passed: false,
|
|
223
|
-
errors: [{ message }],
|
|
224
|
-
warnings,
|
|
225
|
-
duration_ms: Date.now() - start,
|
|
226
|
-
screenshots,
|
|
227
|
-
consoleErrors,
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
finally {
|
|
231
|
-
await stopDevServer();
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
//# sourceMappingURL=visual-gate.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"visual-gate.js","sourceRoot":"","sources":["../../src/gates/visual-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { GateError, VisualCaptureResult } from "../types.js";
|
|
2
|
-
/**
|
|
3
|
-
* Compare before and after visual capture results using DOM structural
|
|
4
|
-
* analysis. Returns a list of `GateError` entries describing detected
|
|
5
|
-
* differences per viewport.
|
|
6
|
-
*
|
|
7
|
-
* This does NOT perform pixel-level comparison — it analyses the serialized
|
|
8
|
-
* DOM trees for element count changes, missing/added elements, visibility
|
|
9
|
-
* changes, and significant layout dimension shifts.
|
|
10
|
-
*/
|
|
11
|
-
export declare function reviewVisual(before: VisualCaptureResult, after: VisualCaptureResult): GateError[];
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
// ---------------------------------------------------------------------------
|
|
2
|
-
// Helpers
|
|
3
|
-
// ---------------------------------------------------------------------------
|
|
4
|
-
/**
|
|
5
|
-
* Build a human-readable DOM path string from root to the given node.
|
|
6
|
-
* Example: "body > div#main > nav.sidebar"
|
|
7
|
-
*/
|
|
8
|
-
function domPath(node, ancestors) {
|
|
9
|
-
const parts = [];
|
|
10
|
-
for (const a of ancestors) {
|
|
11
|
-
parts.push(nodeLabel(a));
|
|
12
|
-
}
|
|
13
|
-
parts.push(nodeLabel(node));
|
|
14
|
-
return parts.join(" > ");
|
|
15
|
-
}
|
|
16
|
-
/** Produce a concise label for a single DOM node: tag#id.className */
|
|
17
|
-
function nodeLabel(node) {
|
|
18
|
-
let label = node.tag;
|
|
19
|
-
if (node.id) {
|
|
20
|
-
label += `#${node.id}`;
|
|
21
|
-
}
|
|
22
|
-
if (node.className) {
|
|
23
|
-
// Collapse whitespace and join with dots
|
|
24
|
-
label += "." + node.className.split(/\s+/).join(".");
|
|
25
|
-
}
|
|
26
|
-
return label;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Build an identity key for a node so we can match elements across
|
|
30
|
-
* before/after snapshots. Nodes with an `id` get that as their key;
|
|
31
|
-
* otherwise we fall back to tag+className which is less unique but still
|
|
32
|
-
* useful.
|
|
33
|
-
*/
|
|
34
|
-
function nodeKey(node) {
|
|
35
|
-
if (node.id) {
|
|
36
|
-
return `id:${node.id}`;
|
|
37
|
-
}
|
|
38
|
-
return `tag:${node.tag}|class:${node.className ?? ""}`;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Recursively flatten a DOM tree into a list of FlatNode entries, each
|
|
42
|
-
* carrying its identity key and human-readable path.
|
|
43
|
-
*/
|
|
44
|
-
function flattenTree(root, ancestors = []) {
|
|
45
|
-
const result = [];
|
|
46
|
-
const currentPath = domPath(root, ancestors);
|
|
47
|
-
result.push({ node: root, path: currentPath, key: nodeKey(root) });
|
|
48
|
-
const nextAncestors = [...ancestors, root];
|
|
49
|
-
for (const child of root.children) {
|
|
50
|
-
result.push(...flattenTree(child, nextAncestors));
|
|
51
|
-
}
|
|
52
|
-
return result;
|
|
53
|
-
}
|
|
54
|
-
/** Count the total number of nodes in a DOM tree (including the root). */
|
|
55
|
-
function countNodes(root) {
|
|
56
|
-
let count = 1;
|
|
57
|
-
for (const child of root.children) {
|
|
58
|
-
count += countNodes(child);
|
|
59
|
-
}
|
|
60
|
-
return count;
|
|
61
|
-
}
|
|
62
|
-
// ---------------------------------------------------------------------------
|
|
63
|
-
// Comparison thresholds
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
/** If total element count changes by more than this ratio, flag it. */
|
|
66
|
-
const ELEMENT_COUNT_CHANGE_THRESHOLD = 0.20; // 20%
|
|
67
|
-
/** Bounding-rect shift (in px) above which we flag a layout change. */
|
|
68
|
-
const LAYOUT_SHIFT_PX = 50;
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
// Per-viewport comparison
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
function compareSnapshots(viewport, before, after) {
|
|
73
|
-
const errors = [];
|
|
74
|
-
// --- Element count change ------------------------------------------------
|
|
75
|
-
const beforeCount = countNodes(before);
|
|
76
|
-
const afterCount = countNodes(after);
|
|
77
|
-
if (beforeCount > 0) {
|
|
78
|
-
const ratio = Math.abs(afterCount - beforeCount) / beforeCount;
|
|
79
|
-
if (ratio > ELEMENT_COUNT_CHANGE_THRESHOLD) {
|
|
80
|
-
const direction = afterCount > beforeCount ? "increase" : "decrease";
|
|
81
|
-
errors.push({
|
|
82
|
-
message: `[${viewport}] Significant element count ${direction}: ${beforeCount} -> ${afterCount} (${Math.round(ratio * 100)}% change)`,
|
|
83
|
-
remediation: `Review the DOM on the "${viewport}" viewport — a large element count ${direction} may indicate unintended additions or removals.`,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
// --- Flatten both trees and index by key ---------------------------------
|
|
88
|
-
const beforeFlat = flattenTree(before);
|
|
89
|
-
const afterFlat = flattenTree(after);
|
|
90
|
-
const beforeByKey = new Map();
|
|
91
|
-
for (const entry of beforeFlat) {
|
|
92
|
-
const existing = beforeByKey.get(entry.key);
|
|
93
|
-
if (existing) {
|
|
94
|
-
existing.push(entry);
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
beforeByKey.set(entry.key, [entry]);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
const afterByKey = new Map();
|
|
101
|
-
for (const entry of afterFlat) {
|
|
102
|
-
const existing = afterByKey.get(entry.key);
|
|
103
|
-
if (existing) {
|
|
104
|
-
existing.push(entry);
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
afterByKey.set(entry.key, [entry]);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
// --- Missing elements (in before, not in after) --------------------------
|
|
111
|
-
for (const [key, beforeEntries] of beforeByKey) {
|
|
112
|
-
if (!afterByKey.has(key)) {
|
|
113
|
-
// All instances of this key are missing in `after`
|
|
114
|
-
for (const entry of beforeEntries) {
|
|
115
|
-
errors.push({
|
|
116
|
-
message: `[${viewport}] Missing element: ${entry.path}`,
|
|
117
|
-
remediation: `Element ${nodeLabel(entry.node)} missing on "${viewport}" viewport — check responsive CSS rules and conditional rendering logic.`,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
// --- Added elements (in after, not in before) — informational ------------
|
|
123
|
-
for (const [key, afterEntries] of afterByKey) {
|
|
124
|
-
if (!beforeByKey.has(key)) {
|
|
125
|
-
for (const entry of afterEntries) {
|
|
126
|
-
errors.push({
|
|
127
|
-
message: `[${viewport}] Added element: ${entry.path}`,
|
|
128
|
-
remediation: `New element ${nodeLabel(entry.node)} detected on "${viewport}" viewport — verify this addition is intentional.`,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// --- Visibility changes and layout shifts --------------------------------
|
|
134
|
-
// For elements present in both snapshots, compare visibility and rect.
|
|
135
|
-
for (const [key, beforeEntries] of beforeByKey) {
|
|
136
|
-
const afterEntries = afterByKey.get(key);
|
|
137
|
-
if (!afterEntries)
|
|
138
|
-
continue;
|
|
139
|
-
// Compare pairwise (first-to-first, etc.) up to the shorter list length
|
|
140
|
-
const pairCount = Math.min(beforeEntries.length, afterEntries.length);
|
|
141
|
-
for (let i = 0; i < pairCount; i++) {
|
|
142
|
-
const bEntry = beforeEntries[i];
|
|
143
|
-
const aEntry = afterEntries[i];
|
|
144
|
-
// Visibility change
|
|
145
|
-
if (bEntry.node.visible && !aEntry.node.visible) {
|
|
146
|
-
errors.push({
|
|
147
|
-
message: `[${viewport}] Element became hidden: ${bEntry.path}`,
|
|
148
|
-
remediation: `Element ${nodeLabel(bEntry.node)} changed from visible to hidden on "${viewport}" viewport — check CSS display/visibility/opacity rules.`,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
else if (!bEntry.node.visible && aEntry.node.visible) {
|
|
152
|
-
errors.push({
|
|
153
|
-
message: `[${viewport}] Element became visible: ${bEntry.path}`,
|
|
154
|
-
remediation: `Element ${nodeLabel(bEntry.node)} changed from hidden to visible on "${viewport}" viewport — verify this visibility change is intentional.`,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
// Layout dimension shift (only when both have rect data)
|
|
158
|
-
if (bEntry.node.rect && aEntry.node.rect) {
|
|
159
|
-
const bRect = bEntry.node.rect;
|
|
160
|
-
const aRect = aEntry.node.rect;
|
|
161
|
-
const dx = Math.abs(aRect.x - bRect.x);
|
|
162
|
-
const dy = Math.abs(aRect.y - bRect.y);
|
|
163
|
-
const dw = Math.abs(aRect.width - bRect.width);
|
|
164
|
-
const dh = Math.abs(aRect.height - bRect.height);
|
|
165
|
-
const shifts = [];
|
|
166
|
-
if (dx > LAYOUT_SHIFT_PX)
|
|
167
|
-
shifts.push(`x shifted by ${dx}px`);
|
|
168
|
-
if (dy > LAYOUT_SHIFT_PX)
|
|
169
|
-
shifts.push(`y shifted by ${dy}px`);
|
|
170
|
-
if (dw > LAYOUT_SHIFT_PX)
|
|
171
|
-
shifts.push(`width changed by ${dw}px`);
|
|
172
|
-
if (dh > LAYOUT_SHIFT_PX)
|
|
173
|
-
shifts.push(`height changed by ${dh}px`);
|
|
174
|
-
if (shifts.length > 0) {
|
|
175
|
-
errors.push({
|
|
176
|
-
message: `[${viewport}] Layout shift on ${bEntry.path}: ${shifts.join(", ")}`,
|
|
177
|
-
remediation: `Element ${nodeLabel(bEntry.node)} dimensions shifted by >${LAYOUT_SHIFT_PX}px on "${viewport}" viewport — review layout changes.`,
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return errors;
|
|
184
|
-
}
|
|
185
|
-
// ---------------------------------------------------------------------------
|
|
186
|
-
// Public API
|
|
187
|
-
// ---------------------------------------------------------------------------
|
|
188
|
-
/**
|
|
189
|
-
* Compare before and after visual capture results using DOM structural
|
|
190
|
-
* analysis. Returns a list of `GateError` entries describing detected
|
|
191
|
-
* differences per viewport.
|
|
192
|
-
*
|
|
193
|
-
* This does NOT perform pixel-level comparison — it analyses the serialized
|
|
194
|
-
* DOM trees for element count changes, missing/added elements, visibility
|
|
195
|
-
* changes, and significant layout dimension shifts.
|
|
196
|
-
*/
|
|
197
|
-
export function reviewVisual(before, after) {
|
|
198
|
-
const errors = [];
|
|
199
|
-
// Only compare viewports present in both snapshots
|
|
200
|
-
const beforeViewports = new Set(Object.keys(before.domSnapshots));
|
|
201
|
-
const afterViewports = new Set(Object.keys(after.domSnapshots));
|
|
202
|
-
for (const viewport of beforeViewports) {
|
|
203
|
-
if (!afterViewports.has(viewport))
|
|
204
|
-
continue;
|
|
205
|
-
const beforeSnap = before.domSnapshots[viewport];
|
|
206
|
-
const afterSnap = after.domSnapshots[viewport];
|
|
207
|
-
errors.push(...compareSnapshots(viewport, beforeSnap, afterSnap));
|
|
208
|
-
}
|
|
209
|
-
return errors;
|
|
210
|
-
}
|
|
211
|
-
//# sourceMappingURL=visual-reviewer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"visual-reviewer.js","sourceRoot":"","sources":["../../src/gates/visual-reviewer.ts"],"names":[],"mappings":"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"}
|
package/dist/go/auto-chain.d.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-Chain — Multi-Milestone Execution Orchestrator
|
|
3
|
-
*
|
|
4
|
-
* After a milestone completes, spawns a fresh agent with clean context for the
|
|
5
|
-
* next milestone. Fresh agent reads CLAUDE.md + next milestone section only.
|
|
6
|
-
* Loops until all milestones done or a failure stops the chain.
|
|
7
|
-
*
|
|
8
|
-
* This module is the data/logic layer. It does NOT spawn agents — that is
|
|
9
|
-
* the skill file's job (via Claude Code's Task tool). Auto-chain prepares
|
|
10
|
-
* the context and tracks results across milestones.
|
|
11
|
-
*/
|
|
12
|
-
import { findNextPendingMilestone, countPendingMilestones } from "../state/prd-status.js";
|
|
13
|
-
import type { CommitResult } from "../state/writer.js";
|
|
14
|
-
import type { ForgeConfig } from "../types.js";
|
|
15
|
-
import type { SchedulerResult } from "../worktree/parallel.js";
|
|
16
|
-
export interface AutoChainOptions {
|
|
17
|
-
projectDir: string;
|
|
18
|
-
prdPath: string;
|
|
19
|
-
config: ForgeConfig;
|
|
20
|
-
branch: string;
|
|
21
|
-
/** Project name (e.g., "forge-cc") */
|
|
22
|
-
project: string;
|
|
23
|
-
/** PRD slug for per-PRD status tracking */
|
|
24
|
-
prdSlug: string;
|
|
25
|
-
/** Relative PRD path for state docs */
|
|
26
|
-
activePrd: string;
|
|
27
|
-
/** Developer name for session memory */
|
|
28
|
-
developer: string;
|
|
29
|
-
/** Repository root (for worktree operations). Defaults to projectDir. */
|
|
30
|
-
repoRoot?: string;
|
|
31
|
-
/** If not provided, detect from per-PRD status */
|
|
32
|
-
startMilestone?: number;
|
|
33
|
-
/** Called when a milestone begins execution */
|
|
34
|
-
onMilestoneStart?: (milestoneNumber: number, name: string) => void;
|
|
35
|
-
/** Called when a milestone finishes (success or failure) */
|
|
36
|
-
onMilestoneComplete?: (milestoneNumber: number, result: MilestoneResult) => void;
|
|
37
|
-
/** Called when the entire chain finishes */
|
|
38
|
-
onChainComplete?: (results: MilestoneResult[]) => void;
|
|
39
|
-
}
|
|
40
|
-
export interface MilestoneResult {
|
|
41
|
-
milestoneNumber: number;
|
|
42
|
-
milestoneName: string;
|
|
43
|
-
success: boolean;
|
|
44
|
-
commitSha?: string;
|
|
45
|
-
isLast: boolean;
|
|
46
|
-
/** Fresh-context prompt for spawning this milestone's agent */
|
|
47
|
-
freshPrompt: string;
|
|
48
|
-
/** Path to the worktree used for execution */
|
|
49
|
-
worktreePath?: string;
|
|
50
|
-
errors: string[];
|
|
51
|
-
}
|
|
52
|
-
export interface AutoChainResult {
|
|
53
|
-
completed: MilestoneResult[];
|
|
54
|
-
/** true if the chain stopped due to a milestone failure */
|
|
55
|
-
stopped: boolean;
|
|
56
|
-
/** Milestone number where the chain stopped (on failure) */
|
|
57
|
-
stoppedAt?: number;
|
|
58
|
-
/** true if every milestone in the roadmap is complete */
|
|
59
|
-
allComplete: boolean;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Build the fresh-context prompt for a milestone agent (Ralph Loop pattern).
|
|
63
|
-
*
|
|
64
|
-
* Reads CLAUDE.md (abbreviated to Quick Context) and the current milestone
|
|
65
|
-
* section from the PRD. The total is kept as small as possible (~200-300
|
|
66
|
-
* lines) while giving the agent enough context to work.
|
|
67
|
-
*/
|
|
68
|
-
export declare function buildFreshSessionPrompt(projectDir: string, prdPath: string, milestoneNumber: number): Promise<string>;
|
|
69
|
-
export { findNextPendingMilestone, countPendingMilestones };
|
|
70
|
-
/**
|
|
71
|
-
* Auto-chain orchestrator: manages multi-milestone execution with context resets.
|
|
72
|
-
*
|
|
73
|
-
* For each pending milestone:
|
|
74
|
-
* 1. Determines the starting milestone (from options or per-PRD status)
|
|
75
|
-
* 2. Creates a git worktree for isolated execution
|
|
76
|
-
* 3. Registers a session in the session registry
|
|
77
|
-
* 4. Builds a fresh-context prompt for the milestone agent
|
|
78
|
-
* 5. Calls the milestone context builder for structured data
|
|
79
|
-
* 6. Returns results so the calling skill can spawn agents and drive execution
|
|
80
|
-
* 7. On completion or failure, deregisters the session and cleans up the worktree
|
|
81
|
-
*
|
|
82
|
-
* The worktree is created ONCE per /forge:go session, not per milestone.
|
|
83
|
-
* All milestones in the chain execute in the same worktree.
|
|
84
|
-
*
|
|
85
|
-
* The chain stops on the first milestone failure, or when all milestones
|
|
86
|
-
* are complete. The caller is responsible for actually executing each
|
|
87
|
-
* milestone (spawning agents, running waves) — this function provides the
|
|
88
|
-
* orchestration loop and context management.
|
|
89
|
-
*/
|
|
90
|
-
export declare function runAutoChain(options: AutoChainOptions): Promise<AutoChainResult>;
|
|
91
|
-
/**
|
|
92
|
-
* Called after a milestone's agent finishes execution.
|
|
93
|
-
*
|
|
94
|
-
* Handles:
|
|
95
|
-
* 1. Updating milestone status in per-PRD status JSON
|
|
96
|
-
* 2. Committing milestone work to git (in the worktree if one was used)
|
|
97
|
-
* 3. Merging worktree branch into the feature branch (if worktree was used)
|
|
98
|
-
* 4. Returning the commit SHA for the milestone result
|
|
99
|
-
*
|
|
100
|
-
* The caller should update the MilestoneResult with the returned commit info.
|
|
101
|
-
*/
|
|
102
|
-
export declare function completeMilestone(options: {
|
|
103
|
-
projectDir: string;
|
|
104
|
-
project: string;
|
|
105
|
-
prdSlug: string;
|
|
106
|
-
milestoneNumber: number;
|
|
107
|
-
milestoneName: string;
|
|
108
|
-
branch: string;
|
|
109
|
-
activePrd: string;
|
|
110
|
-
developer: string;
|
|
111
|
-
filesToStage: string[];
|
|
112
|
-
push?: boolean;
|
|
113
|
-
/** Path to the worktree used for execution. If set, commit happens in the worktree. */
|
|
114
|
-
worktreePath?: string;
|
|
115
|
-
/** Repository root, required when worktreePath is provided (for merge operations). */
|
|
116
|
-
repoRoot?: string;
|
|
117
|
-
}): Promise<{
|
|
118
|
-
commitResult: CommitResult;
|
|
119
|
-
isLast: boolean;
|
|
120
|
-
}>;
|
|
121
|
-
/**
|
|
122
|
-
* Build a parallel execution plan for all milestones in a PRD.
|
|
123
|
-
*
|
|
124
|
-
* Parses the PRD markdown for milestone definitions and `dependsOn` fields,
|
|
125
|
-
* builds a dependency DAG, and computes parallel execution waves showing
|
|
126
|
-
* which milestones can run simultaneously.
|
|
127
|
-
*
|
|
128
|
-
* If no `dependsOn` fields are found in the PRD, all milestones are treated
|
|
129
|
-
* as roots (no dependencies) and placed in a single wave. This is backward
|
|
130
|
-
* compatible — the caller can process them sequentially by milestone number.
|
|
131
|
-
*
|
|
132
|
-
* @param prdPath - Absolute path to the PRD markdown file
|
|
133
|
-
* @returns The wave schedule showing which milestones can run simultaneously
|
|
134
|
-
* @throws If a dependency cycle is detected or a referenced dependency doesn't exist
|
|
135
|
-
*/
|
|
136
|
-
export declare function buildParallelPlan(prdPath: string): Promise<SchedulerResult>;
|