@neonwatty/limner 0.1.1 → 0.1.3
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 +25 -26
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/compare-image-reference.d.ts +3 -0
- package/dist/commands/compare-image-reference.js +26 -3
- package/dist/commands/compare-image-reference.js.map +1 -1
- package/dist/commands/compare.d.ts +4 -1
- package/dist/commands/compare.js +72 -45
- package/dist/commands/compare.js.map +1 -1
- package/dist/core/agent-comparison-fingerprint.d.ts +12 -0
- package/dist/core/agent-comparison-fingerprint.js +27 -0
- package/dist/core/agent-comparison-fingerprint.js.map +1 -0
- package/dist/core/agent-comparison-pack.d.ts +30 -0
- package/dist/core/agent-comparison-pack.js +148 -0
- package/dist/core/agent-comparison-pack.js.map +1 -0
- package/dist/core/agent-comparison-profiles.d.ts +9 -0
- package/dist/core/agent-comparison-profiles.js +19 -0
- package/dist/core/agent-comparison-profiles.js.map +1 -0
- package/dist/core/agent-comparison-prompts.d.ts +22 -0
- package/dist/core/agent-comparison-prompts.js +84 -0
- package/dist/core/agent-comparison-prompts.js.map +1 -0
- package/dist/core/agent-comparison-report.d.ts +3 -0
- package/dist/core/agent-comparison-report.js +56 -0
- package/dist/core/agent-comparison-report.js.map +1 -0
- package/dist/core/agent-comparison-validation.d.ts +2 -0
- package/dist/core/agent-comparison-validation.js +8 -0
- package/dist/core/agent-comparison-validation.js.map +1 -0
- package/dist/core/playwright-capture.js +1 -1
- package/dist/core/playwright-capture.js.map +1 -1
- package/dist/core/report-writer.d.ts +7 -11
- package/dist/core/report-writer.js +20 -42
- package/dist/core/report-writer.js.map +1 -1
- package/dist/core/workspace.d.ts +1 -0
- package/dist/core/workspace.js +13 -2
- package/dist/core/workspace.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/schemas/comparison.d.ts +349 -0
- package/dist/schemas/comparison.js +211 -0
- package/dist/schemas/comparison.js.map +1 -0
- package/dist/schemas/visual-spec.d.ts +8 -8
- package/dist/schemas/visual-spec.js +2 -2
- package/dist/schemas/visual-spec.js.map +1 -1
- package/docs/agent-workflow.md +18 -31
- package/docs/superpowers/plans/2026-06-12-agent-comparison-scores.md +209 -0
- package/package.json +1 -1
- package/skills/limner/SKILL.md +15 -18
- package/templates/target/AGENT_GUIDE.md +12 -8
- package/dist/commands/compare-image-app.d.ts +0 -12
- package/dist/commands/compare-image-app.js +0 -45
- package/dist/commands/compare-image-app.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Limner
|
|
2
2
|
|
|
3
|
-
Limner is an agent-guided visual fidelity workbench. It helps a coding agent turn an input image into
|
|
3
|
+
Limner is an agent-guided visual fidelity workbench. It helps a coding agent turn an input image into an approved HTML mockup, then compare that approved mockup against a real implementation.
|
|
4
4
|
|
|
5
|
-
Limner is model-agnostic. It does not call a vision model and it does not
|
|
5
|
+
Limner is model-agnostic. It does not call a vision model and it does not make final pass/fail judgments. It prepares artifacts and schemas for agent-authored UX comparison scores, diffs, and next-iteration guidance.
|
|
6
6
|
|
|
7
7
|
The optional visual spec workflow is agent-required. Limner can prepare the prompt pack and validate structured agent output, but it does not extract that spec on its own.
|
|
8
8
|
|
|
@@ -55,8 +55,7 @@ limner init ./ideal.png --target replay-boundaries
|
|
|
55
55
|
limner preview --target replay-boundaries
|
|
56
56
|
limner capture reference --target replay-boundaries
|
|
57
57
|
limner compare image-reference --target replay-boundaries
|
|
58
|
-
limner compare
|
|
59
|
-
limner compare reference-app --target replay-boundaries --url http://localhost:3152/internal/optimization-lab/wedding-envelope#replay-boundaries --storage-state ./e2e/.auth/user.json
|
|
58
|
+
limner compare reference-implementation --target replay-boundaries --url http://localhost:3152/internal/optimization-lab/wedding-envelope#replay-boundaries --storage-state ./e2e/.auth/user.json
|
|
60
59
|
limner report --target replay-boundaries
|
|
61
60
|
limner runs list
|
|
62
61
|
```
|
|
@@ -84,7 +83,7 @@ limner-workspace/
|
|
|
84
83
|
|
|
85
84
|
### Image To Reference
|
|
86
85
|
|
|
87
|
-
Use this while recreating the
|
|
86
|
+
Use this while recreating the ideal image as a standalone HTML/CSS mockup. This mode uses the `ideal-to-mockup` agent comparison profile.
|
|
88
87
|
|
|
89
88
|
```bash
|
|
90
89
|
limner compare image-reference --target replay-boundaries
|
|
@@ -96,8 +95,15 @@ Outputs:
|
|
|
96
95
|
|
|
97
96
|
- `captures/image-reference/reference.png`
|
|
98
97
|
- `captures/image-reference/side-by-side.png`
|
|
98
|
+
- `captures/image-reference/agent-comparison/agent-prompt.codex.md`
|
|
99
|
+
- `captures/image-reference/agent-comparison/agent-response.schema.json`
|
|
99
100
|
- `reports/image-reference.md`
|
|
100
101
|
|
|
102
|
+
After an agent writes `captures/image-reference/agent-comparison/agent-response.json`, rerun the same command and Limner validates and emits:
|
|
103
|
+
|
|
104
|
+
- `captures/image-reference/image-comparison.json`
|
|
105
|
+
- `captures/image-reference/comparison-summary.json`
|
|
106
|
+
|
|
101
107
|
With `--spec`, Limner also writes an agent handoff pack under `captures/image-reference/spec/`:
|
|
102
108
|
|
|
103
109
|
- `agent-prompt.md`
|
|
@@ -123,36 +129,29 @@ The prompt pack is tuned for two common flows:
|
|
|
123
129
|
|
|
124
130
|
Agents should inspect the ideal image and reference screenshot separately. The side-by-side image is comparison context, not the source image to parse.
|
|
125
131
|
|
|
126
|
-
###
|
|
132
|
+
### Reference To Implementation
|
|
127
133
|
|
|
128
|
-
Use this
|
|
129
|
-
It compares the source image directly to a captured app viewport.
|
|
134
|
+
Use this after the HTML mockup is approved and the real implementation needs to match it. This mode uses the `mockup-to-implementation` agent comparison profile.
|
|
130
135
|
|
|
131
136
|
```bash
|
|
132
|
-
limner compare
|
|
137
|
+
limner compare reference-implementation --target replay-boundaries --url http://localhost:3152/... --storage-state ./e2e/.auth/user.json
|
|
133
138
|
```
|
|
134
139
|
|
|
135
140
|
Outputs:
|
|
136
141
|
|
|
137
|
-
- `captures/
|
|
138
|
-
- `captures/
|
|
139
|
-
- `
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
- `captures/reference-implementation/reference.png`
|
|
143
|
+
- `captures/reference-implementation/implementation.png`
|
|
144
|
+
- `captures/reference-implementation/side-by-side.png`
|
|
145
|
+
- `captures/reference-implementation/dom-metrics.json`
|
|
146
|
+
- `captures/reference-implementation/agent-comparison/agent-prompt.codex.md`
|
|
147
|
+
- `captures/reference-implementation/agent-comparison/agent-response.schema.json`
|
|
148
|
+
- `reports/reference-implementation.md`
|
|
144
149
|
|
|
145
|
-
|
|
146
|
-
limner compare reference-app --target replay-boundaries --url http://localhost:3152/... --storage-state ./e2e/.auth/user.json
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
Outputs:
|
|
150
|
+
After an agent writes `captures/reference-implementation/agent-comparison/agent-response.json`, rerun the same command and Limner validates and emits:
|
|
150
151
|
|
|
151
|
-
- `captures/reference-
|
|
152
|
-
- `captures/reference-
|
|
153
|
-
- `captures/reference-
|
|
154
|
-
- `captures/reference-app/dom-metrics.json`
|
|
155
|
-
- `reports/reference-app.md`
|
|
152
|
+
- `captures/reference-implementation/image-comparison.json`
|
|
153
|
+
- `captures/reference-implementation/structure-comparison.json`
|
|
154
|
+
- `captures/reference-implementation/comparison-summary.json`
|
|
156
155
|
|
|
157
156
|
Capture commands default to viewport-only screenshots. Add `--full-page` when the full scrollable page is the comparison target.
|
|
158
157
|
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
import { registerCaptureCommand } from './commands/capture.js';
|
|
4
5
|
import { registerCompareCommand } from './commands/compare.js';
|
|
@@ -6,11 +7,12 @@ import { registerInitCommand } from './commands/init.js';
|
|
|
6
7
|
import { registerPreviewCommand } from './commands/preview.js';
|
|
7
8
|
import { registerReportCommand } from './commands/report.js';
|
|
8
9
|
import { registerRunsCommand } from './commands/runs.js';
|
|
10
|
+
const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
9
11
|
const program = new Command();
|
|
10
12
|
program
|
|
11
13
|
.name('limner')
|
|
12
14
|
.description('Agent-guided visual fidelity workbench')
|
|
13
|
-
.version(
|
|
15
|
+
.version(packageJson.version)
|
|
14
16
|
.option('-w, --workspace <path>', 'Limner workspace root', process.cwd());
|
|
15
17
|
registerInitCommand(program);
|
|
16
18
|
registerPreviewCommand(program);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,wCAAwC,CAAC;KACrD,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAC3C,CAAC;AAEzB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,wCAAwC,CAAC;KACrD,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC;KAC5B,MAAM,CAAC,wBAAwB,EAAE,uBAAuB,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AAE5E,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAE7B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IACxD,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,KAAK,CAAC,WAAW,OAAO,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AgentComparisonPackResult } from '../core/agent-comparison-pack.js';
|
|
1
2
|
export declare function compareImageReference(options: {
|
|
2
3
|
workspaceRoot: string;
|
|
3
4
|
target: string;
|
|
@@ -5,6 +6,7 @@ export declare function compareImageReference(options: {
|
|
|
5
6
|
fullPage?: boolean;
|
|
6
7
|
spec?: boolean;
|
|
7
8
|
specInstructions?: string;
|
|
9
|
+
agentComparison?: boolean;
|
|
8
10
|
}): Promise<{
|
|
9
11
|
sideBySidePath: string;
|
|
10
12
|
reportPath: string;
|
|
@@ -13,6 +15,7 @@ export declare function compareImageReference(options: {
|
|
|
13
15
|
referenceSpecPath: string;
|
|
14
16
|
diffPath: string;
|
|
15
17
|
};
|
|
18
|
+
agentComparison?: AgentComparisonPackResult;
|
|
16
19
|
agentSpec?: {
|
|
17
20
|
promptPath: string;
|
|
18
21
|
codexPromptPath: string;
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { mkdir } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { writeAgentComparisonPack } from '../core/agent-comparison-pack.js';
|
|
3
4
|
import { writeImageReferenceReport } from '../core/report-writer.js';
|
|
4
5
|
import { createRunLogger } from '../core/run-logger.js';
|
|
5
6
|
import { createSideBySideImage } from '../core/side-by-side.js';
|
|
6
7
|
import { startStaticServer } from '../core/static-server.js';
|
|
7
8
|
import { writeImageReferenceSpecPack } from '../core/visual-spec-agent-pack.js';
|
|
8
|
-
import {
|
|
9
|
+
import { resolveTargetWithSource, resolveWorkspace } from '../core/workspace.js';
|
|
9
10
|
import { capturePage } from '../core/playwright-capture.js';
|
|
10
11
|
export async function compareImageReference(options) {
|
|
11
12
|
const workspace = resolveWorkspace(options.workspaceRoot);
|
|
12
|
-
const target =
|
|
13
|
+
const target = await resolveTargetWithSource(options.workspaceRoot, options.target);
|
|
13
14
|
const logger = await createRunLogger(workspace, { command: 'compare', target: options.target, mode: 'image-reference' });
|
|
14
15
|
const captureDir = path.join(target.capturesDir, 'image-reference');
|
|
15
16
|
const referencePath = path.join(captureDir, 'reference.png');
|
|
16
17
|
const sideBySidePath = path.join(captureDir, 'side-by-side.png');
|
|
17
18
|
let specPaths;
|
|
18
19
|
let agentSpec;
|
|
20
|
+
let agentComparison;
|
|
19
21
|
try {
|
|
20
22
|
await logger.event({ type: 'command.started' });
|
|
21
23
|
await mkdir(captureDir, { recursive: true });
|
|
@@ -28,6 +30,18 @@ export async function compareImageReference(options) {
|
|
|
28
30
|
fullPage: options.fullPage,
|
|
29
31
|
});
|
|
30
32
|
await createSideBySideImage({ leftPath: target.sourceImagePath, rightPath: referencePath, outputPath: sideBySidePath });
|
|
33
|
+
if (options.agentComparison !== false) {
|
|
34
|
+
agentComparison = await writeAgentComparisonPack({
|
|
35
|
+
workspaceRoot: options.workspaceRoot,
|
|
36
|
+
captureDir,
|
|
37
|
+
mode: 'image-reference',
|
|
38
|
+
profile: 'ideal-to-mockup',
|
|
39
|
+
imageInputs: {
|
|
40
|
+
expectedImagePath: target.sourceImagePath,
|
|
41
|
+
actualImagePath: referencePath,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
31
45
|
if (options.spec) {
|
|
32
46
|
const specPack = await writeImageReferenceSpecPack({
|
|
33
47
|
target,
|
|
@@ -53,6 +67,7 @@ export async function compareImageReference(options) {
|
|
|
53
67
|
specPaths,
|
|
54
68
|
specHighlights: agentSpec?.status === 'validated' ? agentSpec.diffHighlights : undefined,
|
|
55
69
|
agentSpec,
|
|
70
|
+
agentComparison,
|
|
56
71
|
});
|
|
57
72
|
await logger.artifact(referencePath, 'screenshot');
|
|
58
73
|
await logger.artifact(sideBySidePath, 'side-by-side');
|
|
@@ -64,6 +79,14 @@ export async function compareImageReference(options) {
|
|
|
64
79
|
await logger.artifact(agentSpec.examplePath, 'spec-example');
|
|
65
80
|
await logger.artifact(agentSpec.schemaPath, 'spec-schema');
|
|
66
81
|
}
|
|
82
|
+
if (agentComparison) {
|
|
83
|
+
await logger.artifact(agentComparison.promptPath, 'agent-comparison-prompt');
|
|
84
|
+
await logger.artifact(agentComparison.schemaPath, 'agent-comparison-schema');
|
|
85
|
+
if (agentComparison.imageComparisonPath)
|
|
86
|
+
await logger.artifact(agentComparison.imageComparisonPath, 'image-comparison');
|
|
87
|
+
if (agentComparison.summaryPath)
|
|
88
|
+
await logger.artifact(agentComparison.summaryPath, 'comparison-summary');
|
|
89
|
+
}
|
|
67
90
|
if (specPaths) {
|
|
68
91
|
await logger.artifact(specPaths.idealSpecPath, 'visual-spec');
|
|
69
92
|
await logger.artifact(specPaths.referenceSpecPath, 'visual-spec');
|
|
@@ -71,7 +94,7 @@ export async function compareImageReference(options) {
|
|
|
71
94
|
}
|
|
72
95
|
await logger.artifact(reportPath, 'report');
|
|
73
96
|
await logger.complete('ok');
|
|
74
|
-
return { sideBySidePath, reportPath, specPaths, agentSpec };
|
|
97
|
+
return { sideBySidePath, reportPath, specPaths, agentSpec, agentComparison };
|
|
75
98
|
}
|
|
76
99
|
catch (error) {
|
|
77
100
|
await logger.event({ type: 'command.failed', status: 'failed', message: error instanceof Error ? error.message : String(error) });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-image-reference.js","sourceRoot":"","sources":["../../src/commands/compare-image-reference.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"compare-image-reference.js","sourceRoot":"","sources":["../../src/commands/compare-image-reference.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
+
import { type AgentComparisonPackResult } from '../core/agent-comparison-pack.js';
|
|
2
3
|
export { compareImageReference } from './compare-image-reference.js';
|
|
3
|
-
export declare function
|
|
4
|
+
export declare function compareReferenceImplementation(options: {
|
|
4
5
|
workspaceRoot: string;
|
|
5
6
|
target: string;
|
|
6
7
|
url: string;
|
|
7
8
|
headed?: boolean;
|
|
8
9
|
storageState?: string;
|
|
9
10
|
fullPage?: boolean;
|
|
11
|
+
agentComparison?: boolean;
|
|
10
12
|
}): Promise<{
|
|
11
13
|
sideBySidePath: string;
|
|
12
14
|
reportPath: string;
|
|
13
15
|
metricsPath: string;
|
|
16
|
+
agentComparison?: AgentComparisonPackResult;
|
|
14
17
|
}>;
|
|
15
18
|
export declare function registerCompareCommand(program: Command): void;
|
package/dist/commands/compare.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { writeAgentComparisonPack } from '../core/agent-comparison-pack.js';
|
|
3
4
|
import { loadRegionContract } from '../core/dom-metrics.js';
|
|
4
5
|
import { capturePage } from '../core/playwright-capture.js';
|
|
5
|
-
import {
|
|
6
|
+
import { writeReferenceImplementationReport } from '../core/report-writer.js';
|
|
6
7
|
import { createRunLogger } from '../core/run-logger.js';
|
|
7
8
|
import { createSideBySideImage } from '../core/side-by-side.js';
|
|
8
9
|
import { startStaticServer } from '../core/static-server.js';
|
|
9
10
|
import { resolveTarget, resolveWorkspace } from '../core/workspace.js';
|
|
10
|
-
import { compareImageApp } from './compare-image-app.js';
|
|
11
11
|
import { compareImageReference } from './compare-image-reference.js';
|
|
12
12
|
export { compareImageReference } from './compare-image-reference.js';
|
|
13
|
-
export async function
|
|
13
|
+
export async function compareReferenceImplementation(options) {
|
|
14
14
|
const workspace = resolveWorkspace(options.workspaceRoot);
|
|
15
15
|
const target = resolveTarget(options.workspaceRoot, options.target);
|
|
16
|
-
const logger = await createRunLogger(workspace, { command: 'compare', target: options.target, mode: 'reference-
|
|
17
|
-
const captureDir = path.join(target.capturesDir, 'reference-
|
|
16
|
+
const logger = await createRunLogger(workspace, { command: 'compare', target: options.target, mode: 'reference-implementation' });
|
|
17
|
+
const captureDir = path.join(target.capturesDir, 'reference-implementation');
|
|
18
18
|
const referencePath = path.join(captureDir, 'reference.png');
|
|
19
|
-
const
|
|
19
|
+
const implementationPath = path.join(captureDir, 'implementation.png');
|
|
20
20
|
const sideBySidePath = path.join(captureDir, 'side-by-side.png');
|
|
21
21
|
const metricsPath = path.join(captureDir, 'dom-metrics.json');
|
|
22
22
|
try {
|
|
@@ -38,9 +38,9 @@ export async function compareReferenceApp(options) {
|
|
|
38
38
|
finally {
|
|
39
39
|
await server.close();
|
|
40
40
|
}
|
|
41
|
-
const
|
|
41
|
+
const implementationResult = await capturePage({
|
|
42
42
|
url: options.url,
|
|
43
|
-
outputPath:
|
|
43
|
+
outputPath: implementationPath,
|
|
44
44
|
contract,
|
|
45
45
|
side: 'app',
|
|
46
46
|
headed: options.headed,
|
|
@@ -49,27 +49,53 @@ export async function compareReferenceApp(options) {
|
|
|
49
49
|
});
|
|
50
50
|
await writeFile(metricsPath, JSON.stringify({
|
|
51
51
|
reference: referenceResult.metrics,
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
implementation: implementationResult.metrics,
|
|
53
|
+
implementationConsole: implementationResult.consoleMessages,
|
|
54
54
|
referenceConsole: referenceResult.consoleMessages,
|
|
55
55
|
}, null, 2) + '\n');
|
|
56
|
-
await createSideBySideImage({ leftPath: referencePath, rightPath:
|
|
57
|
-
const
|
|
56
|
+
await createSideBySideImage({ leftPath: referencePath, rightPath: implementationPath, outputPath: sideBySidePath });
|
|
57
|
+
const agentComparison = options.agentComparison === false ? undefined : await writeAgentComparisonPack({
|
|
58
|
+
workspaceRoot: options.workspaceRoot,
|
|
59
|
+
captureDir,
|
|
60
|
+
mode: 'reference-implementation',
|
|
61
|
+
profile: 'mockup-to-implementation',
|
|
62
|
+
imageInputs: {
|
|
63
|
+
expectedImagePath: referencePath,
|
|
64
|
+
actualImagePath: implementationPath,
|
|
65
|
+
},
|
|
66
|
+
structureInputs: {
|
|
67
|
+
expectedStructurePath: `${referencePath}.metrics.json`,
|
|
68
|
+
actualStructurePath: `${implementationPath}.metrics.json`,
|
|
69
|
+
structureKind: 'dom-metrics',
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
const reportPath = await writeReferenceImplementationReport({
|
|
58
73
|
target,
|
|
59
74
|
referencePath,
|
|
60
|
-
|
|
75
|
+
implementationPath,
|
|
61
76
|
sideBySidePath,
|
|
62
77
|
referenceMetrics: referenceResult.metrics,
|
|
63
|
-
|
|
64
|
-
|
|
78
|
+
implementationMetrics: implementationResult.metrics,
|
|
79
|
+
implementationUrl: options.url,
|
|
80
|
+
agentComparison,
|
|
65
81
|
});
|
|
66
82
|
await logger.artifact(referencePath, 'screenshot');
|
|
67
|
-
await logger.artifact(
|
|
83
|
+
await logger.artifact(implementationPath, 'screenshot');
|
|
68
84
|
await logger.artifact(sideBySidePath, 'side-by-side');
|
|
69
85
|
await logger.artifact(metricsPath, 'dom-metrics');
|
|
86
|
+
if (agentComparison) {
|
|
87
|
+
await logger.artifact(agentComparison.promptPath, 'agent-comparison-prompt');
|
|
88
|
+
await logger.artifact(agentComparison.schemaPath, 'agent-comparison-schema');
|
|
89
|
+
if (agentComparison.imageComparisonPath)
|
|
90
|
+
await logger.artifact(agentComparison.imageComparisonPath, 'image-comparison');
|
|
91
|
+
if (agentComparison.structureComparisonPath)
|
|
92
|
+
await logger.artifact(agentComparison.structureComparisonPath, 'structure-comparison');
|
|
93
|
+
if (agentComparison.summaryPath)
|
|
94
|
+
await logger.artifact(agentComparison.summaryPath, 'comparison-summary');
|
|
95
|
+
}
|
|
70
96
|
await logger.artifact(reportPath, 'report');
|
|
71
97
|
await logger.complete('ok');
|
|
72
|
-
return { sideBySidePath, reportPath, metricsPath };
|
|
98
|
+
return { sideBySidePath, reportPath, metricsPath, agentComparison };
|
|
73
99
|
}
|
|
74
100
|
catch (error) {
|
|
75
101
|
await logger.event({ type: 'command.failed', status: 'failed', message: error instanceof Error ? error.message : String(error) });
|
|
@@ -87,6 +113,7 @@ export function registerCompareCommand(program) {
|
|
|
87
113
|
.option('--full-page', 'capture the full scrollable page')
|
|
88
114
|
.option('--spec', 'prepare or validate an agent-authored visual spec pack')
|
|
89
115
|
.option('--spec-instructions <path>', 'custom visual spec instructions markdown file')
|
|
116
|
+
.option('--no-agent-comparison', 'skip the default agent comparison prompt pack')
|
|
90
117
|
.option('--viewport-only', 'capture only the viewport (default)')
|
|
91
118
|
.action(async (options, command) => {
|
|
92
119
|
const globals = command.optsWithGlobals();
|
|
@@ -97,8 +124,10 @@ export function registerCompareCommand(program) {
|
|
|
97
124
|
fullPage: options.fullPage,
|
|
98
125
|
spec: options.spec,
|
|
99
126
|
specInstructions: options.specInstructions,
|
|
127
|
+
agentComparison: options.agentComparison,
|
|
100
128
|
});
|
|
101
129
|
console.log(`Side-by-side: ${result.sideBySidePath}`);
|
|
130
|
+
printAgentComparison(result.agentComparison);
|
|
102
131
|
if (result.agentSpec) {
|
|
103
132
|
console.log(`Shared agent prompt: ${result.agentSpec.promptPath}`);
|
|
104
133
|
console.log(`Codex prompt: ${result.agentSpec.codexPromptPath}`);
|
|
@@ -119,50 +148,48 @@ export function registerCompareCommand(program) {
|
|
|
119
148
|
console.log(`Report: ${result.reportPath}`);
|
|
120
149
|
});
|
|
121
150
|
compare
|
|
122
|
-
.command('reference-
|
|
123
|
-
.description('Compare reference HTML to an
|
|
151
|
+
.command('reference-implementation')
|
|
152
|
+
.description('Compare reference HTML to an implementation URL')
|
|
124
153
|
.requiredOption('-t, --target <name>', 'target name')
|
|
125
|
-
.requiredOption('-u, --url <url>', '
|
|
154
|
+
.requiredOption('-u, --url <url>', 'implementation URL')
|
|
126
155
|
.option('--headed', 'show browser while capturing')
|
|
127
|
-
.option('--storage-state <path>', 'Playwright storageState JSON for authenticated
|
|
156
|
+
.option('--storage-state <path>', 'Playwright storageState JSON for authenticated implementation captures')
|
|
128
157
|
.option('--full-page', 'capture the full scrollable page')
|
|
158
|
+
.option('--no-agent-comparison', 'skip the default agent comparison prompt pack')
|
|
129
159
|
.option('--viewport-only', 'capture only the viewport (default)')
|
|
130
160
|
.action(async (options, command) => {
|
|
131
161
|
const globals = command.optsWithGlobals();
|
|
132
|
-
const result = await
|
|
162
|
+
const result = await compareReferenceImplementation({
|
|
133
163
|
workspaceRoot: globals.workspace,
|
|
134
164
|
target: options.target,
|
|
135
165
|
url: options.url,
|
|
136
166
|
headed: options.headed,
|
|
137
167
|
storageState: options.storageState,
|
|
138
168
|
fullPage: options.fullPage,
|
|
169
|
+
agentComparison: options.agentComparison,
|
|
139
170
|
});
|
|
140
171
|
console.log(`Side-by-side: ${result.sideBySidePath}`);
|
|
141
172
|
console.log(`Metrics: ${result.metricsPath}`);
|
|
173
|
+
printAgentComparison(result.agentComparison);
|
|
142
174
|
console.log(`Report: ${result.reportPath}`);
|
|
143
175
|
});
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
});
|
|
163
|
-
console.log(`App screenshot: ${result.appPath}`);
|
|
164
|
-
console.log(`Side-by-side: ${result.sideBySidePath}`);
|
|
165
|
-
console.log(`Report: ${result.reportPath}`);
|
|
166
|
-
});
|
|
176
|
+
}
|
|
177
|
+
function printAgentComparison(agentComparison) {
|
|
178
|
+
if (!agentComparison)
|
|
179
|
+
return;
|
|
180
|
+
console.log(`Agent comparison prompt: ${agentComparison.promptPath}`);
|
|
181
|
+
console.log(`Codex comparison prompt: ${agentComparison.codexPromptPath}`);
|
|
182
|
+
console.log(`Claude comparison prompt: ${agentComparison.claudePromptPath}`);
|
|
183
|
+
console.log(`Agent comparison schema: ${agentComparison.schemaPath}`);
|
|
184
|
+
console.log(`Agent comparison response target: ${agentComparison.responsePath}`);
|
|
185
|
+
if (agentComparison.status === 'validated') {
|
|
186
|
+
console.log(`Image comparison: ${agentComparison.imageComparisonPath}`);
|
|
187
|
+
if (agentComparison.structureComparisonPath)
|
|
188
|
+
console.log(`Structure comparison: ${agentComparison.structureComparisonPath}`);
|
|
189
|
+
console.log(`Comparison summary: ${agentComparison.summaryPath}`);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.log(`Agent comparison status: ${agentComparison.status}`);
|
|
193
|
+
}
|
|
167
194
|
}
|
|
168
195
|
//# sourceMappingURL=compare.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentComparisonInputFingerprint } from '../schemas/comparison.js';
|
|
2
|
+
export declare function clearAgentComparisonOutputs(captureDir: string): Promise<void>;
|
|
3
|
+
export declare function createInputFingerprint(input: {
|
|
4
|
+
imageInputs: {
|
|
5
|
+
expectedImagePath: string;
|
|
6
|
+
actualImagePath: string;
|
|
7
|
+
};
|
|
8
|
+
structureInputs?: {
|
|
9
|
+
expectedStructurePath: string;
|
|
10
|
+
actualStructurePath: string;
|
|
11
|
+
};
|
|
12
|
+
}): Promise<AgentComparisonInputFingerprint>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFile, rm } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export async function clearAgentComparisonOutputs(captureDir) {
|
|
5
|
+
await Promise.all([
|
|
6
|
+
rm(path.join(captureDir, 'image-comparison.json'), { force: true }),
|
|
7
|
+
rm(path.join(captureDir, 'structure-comparison.json'), { force: true }),
|
|
8
|
+
rm(path.join(captureDir, 'comparison-summary.json'), { force: true }),
|
|
9
|
+
]);
|
|
10
|
+
}
|
|
11
|
+
export async function createInputFingerprint(input) {
|
|
12
|
+
const [expectedImageSha256, actualImageSha256] = await Promise.all([
|
|
13
|
+
sha256File(input.imageInputs.expectedImagePath),
|
|
14
|
+
sha256File(input.imageInputs.actualImagePath),
|
|
15
|
+
]);
|
|
16
|
+
if (!input.structureInputs)
|
|
17
|
+
return { expectedImageSha256, actualImageSha256 };
|
|
18
|
+
const [expectedStructureSha256, actualStructureSha256] = await Promise.all([
|
|
19
|
+
sha256File(input.structureInputs.expectedStructurePath),
|
|
20
|
+
sha256File(input.structureInputs.actualStructurePath),
|
|
21
|
+
]);
|
|
22
|
+
return { expectedImageSha256, actualImageSha256, expectedStructureSha256, actualStructureSha256 };
|
|
23
|
+
}
|
|
24
|
+
async function sha256File(filePath) {
|
|
25
|
+
return createHash('sha256').update(await readFile(filePath)).digest('hex');
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=agent-comparison-fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-comparison-fingerprint.js","sourceRoot":"","sources":["../../src/core/agent-comparison-fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,UAAkB;IAClE,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,uBAAuB,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACnE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,2BAA2B,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACvE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,yBAAyB,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;KACtE,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,KAM5C;IACC,MAAM,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACjE,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,iBAAiB,CAAC;QAC/C,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,eAAe,CAAC;KAC9C,CAAC,CAAC;IACH,IAAI,CAAC,KAAK,CAAC,eAAe;QAAE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,CAAC;IAC9E,MAAM,CAAC,uBAAuB,EAAE,qBAAqB,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACzE,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,qBAAqB,CAAC;QACvD,UAAU,CAAC,KAAK,CAAC,eAAe,CAAC,mBAAmB,CAAC;KACtD,CAAC,CAAC;IACH,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,CAAC;AACpG,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7E,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { AgentComparisonProfileName } from './agent-comparison-profiles.js';
|
|
2
|
+
export type AgentComparisonPackResult = {
|
|
3
|
+
promptPath: string;
|
|
4
|
+
codexPromptPath: string;
|
|
5
|
+
claudePromptPath: string;
|
|
6
|
+
schemaPath: string;
|
|
7
|
+
examplePath: string;
|
|
8
|
+
responsePath: string;
|
|
9
|
+
status: 'awaiting-agent' | 'validated' | 'invalid';
|
|
10
|
+
validationErrors?: string[];
|
|
11
|
+
imageComparisonPath?: string;
|
|
12
|
+
structureComparisonPath?: string;
|
|
13
|
+
summaryPath?: string;
|
|
14
|
+
scoreHighlights?: string[];
|
|
15
|
+
};
|
|
16
|
+
export declare function writeAgentComparisonPack(input: {
|
|
17
|
+
workspaceRoot: string;
|
|
18
|
+
captureDir: string;
|
|
19
|
+
mode: 'image-reference' | 'reference-implementation';
|
|
20
|
+
profile: AgentComparisonProfileName;
|
|
21
|
+
imageInputs: {
|
|
22
|
+
expectedImagePath: string;
|
|
23
|
+
actualImagePath: string;
|
|
24
|
+
};
|
|
25
|
+
structureInputs?: {
|
|
26
|
+
expectedStructurePath: string;
|
|
27
|
+
actualStructurePath: string;
|
|
28
|
+
structureKind: 'visual-spec' | 'dom-metrics' | 'html' | 'json-description';
|
|
29
|
+
};
|
|
30
|
+
}): Promise<AgentComparisonPackResult>;
|