@neonwatty/limner 0.1.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.
Files changed (82) hide show
  1. package/README.md +161 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +26 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/capture.d.ts +12 -0
  6. package/dist/commands/capture.js +66 -0
  7. package/dist/commands/capture.js.map +1 -0
  8. package/dist/commands/compare-image-app.d.ts +12 -0
  9. package/dist/commands/compare-image-app.js +45 -0
  10. package/dist/commands/compare-image-app.js.map +1 -0
  11. package/dist/commands/compare-image-reference.d.ts +28 -0
  12. package/dist/commands/compare-image-reference.js +82 -0
  13. package/dist/commands/compare-image-reference.js.map +1 -0
  14. package/dist/commands/compare.d.ts +15 -0
  15. package/dist/commands/compare.js +168 -0
  16. package/dist/commands/compare.js.map +1 -0
  17. package/dist/commands/init.d.ts +12 -0
  18. package/dist/commands/init.js +65 -0
  19. package/dist/commands/init.js.map +1 -0
  20. package/dist/commands/preview.d.ts +2 -0
  21. package/dist/commands/preview.js +27 -0
  22. package/dist/commands/preview.js.map +1 -0
  23. package/dist/commands/report.d.ts +2 -0
  24. package/dist/commands/report.js +14 -0
  25. package/dist/commands/report.js.map +1 -0
  26. package/dist/commands/runs.d.ts +2 -0
  27. package/dist/commands/runs.js +63 -0
  28. package/dist/commands/runs.js.map +1 -0
  29. package/dist/core/dom-metrics.d.ts +18 -0
  30. package/dist/core/dom-metrics.js +54 -0
  31. package/dist/core/dom-metrics.js.map +1 -0
  32. package/dist/core/playwright-capture.d.ts +27 -0
  33. package/dist/core/playwright-capture.js +46 -0
  34. package/dist/core/playwright-capture.js.map +1 -0
  35. package/dist/core/playwright-dom.d.ts +16 -0
  36. package/dist/core/playwright-dom.js +64 -0
  37. package/dist/core/playwright-dom.js.map +1 -0
  38. package/dist/core/reference-dom-facts.d.ts +65 -0
  39. package/dist/core/reference-dom-facts.js +71 -0
  40. package/dist/core/reference-dom-facts.js.map +1 -0
  41. package/dist/core/report-writer.d.ts +43 -0
  42. package/dist/core/report-writer.js +181 -0
  43. package/dist/core/report-writer.js.map +1 -0
  44. package/dist/core/run-logger.d.ts +22 -0
  45. package/dist/core/run-logger.js +67 -0
  46. package/dist/core/run-logger.js.map +1 -0
  47. package/dist/core/side-by-side.d.ts +8 -0
  48. package/dist/core/side-by-side.js +33 -0
  49. package/dist/core/side-by-side.js.map +1 -0
  50. package/dist/core/static-server.d.ts +6 -0
  51. package/dist/core/static-server.js +73 -0
  52. package/dist/core/static-server.js.map +1 -0
  53. package/dist/core/visual-spec-agent-pack.d.ts +27 -0
  54. package/dist/core/visual-spec-agent-pack.js +143 -0
  55. package/dist/core/visual-spec-agent-pack.js.map +1 -0
  56. package/dist/core/visual-spec-prompts.d.ts +32 -0
  57. package/dist/core/visual-spec-prompts.js +129 -0
  58. package/dist/core/visual-spec-prompts.js.map +1 -0
  59. package/dist/core/workspace.d.ts +31 -0
  60. package/dist/core/workspace.js +97 -0
  61. package/dist/core/workspace.js.map +1 -0
  62. package/dist/index.d.ts +14 -0
  63. package/dist/index.js +12 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/schemas/contract.d.ts +43 -0
  66. package/dist/schemas/contract.js +19 -0
  67. package/dist/schemas/contract.js.map +1 -0
  68. package/dist/schemas/events.d.ts +34 -0
  69. package/dist/schemas/events.js +29 -0
  70. package/dist/schemas/events.js.map +1 -0
  71. package/dist/schemas/visual-spec.d.ts +410 -0
  72. package/dist/schemas/visual-spec.js +201 -0
  73. package/dist/schemas/visual-spec.js.map +1 -0
  74. package/docs/agent-workflow.md +45 -0
  75. package/package.json +64 -0
  76. package/skills/limner/SKILL.md +51 -0
  77. package/templates/target/AGENT_GUIDE.md +24 -0
  78. package/templates/target/contract/acceptance.md +23 -0
  79. package/templates/target/contract/regions.json +11 -0
  80. package/templates/target/contract/tokens.json +21 -0
  81. package/templates/target/reference/index.html +22 -0
  82. package/templates/target/reference/styles.css +53 -0
@@ -0,0 +1 @@
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 { Command } from 'commander';
2
+ export type InitTargetOptions = {
3
+ workspaceRoot: string;
4
+ target: string;
5
+ imagePath: string;
6
+ force?: boolean;
7
+ };
8
+ export declare function initTarget(options: InitTargetOptions): Promise<{
9
+ targetRoot: string;
10
+ sourceImagePath: string;
11
+ }>;
12
+ export declare function registerInitCommand(program: Command): void;
@@ -0,0 +1,65 @@
1
+ import { mkdir, readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { createRunLogger } from '../core/run-logger.js';
5
+ import { copyIfMissing, ensureTargetDirs, ensureWorkspace, resolveTarget, resolveWorkspace, writeIfMissing, } from '../core/workspace.js';
6
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..');
7
+ const templateRoot = path.join(packageRoot, 'templates', 'target');
8
+ export async function initTarget(options) {
9
+ const workspace = resolveWorkspace(options.workspaceRoot);
10
+ const imageName = path.basename(options.imagePath);
11
+ const target = resolveTarget(options.workspaceRoot, options.target, imageName);
12
+ const logger = await createRunLogger(workspace, { command: 'init', target: options.target });
13
+ try {
14
+ await logger.event({ type: 'command.started' });
15
+ await ensureWorkspace(workspace);
16
+ await ensureTargetDirs(target);
17
+ await mkdir(target.root, { recursive: true });
18
+ await copyIfMissing(path.resolve(options.imagePath), target.sourceImagePath, options.force);
19
+ await writeTemplates(target, Boolean(options.force));
20
+ await logger.artifact(target.sourceImagePath, 'source-image');
21
+ await logger.artifact(target.referenceHtmlPath, 'reference-html');
22
+ await logger.complete('ok');
23
+ return { targetRoot: target.root, sourceImagePath: target.sourceImagePath };
24
+ }
25
+ catch (error) {
26
+ await logger.event({ type: 'command.failed', status: 'failed', message: error instanceof Error ? error.message : String(error) });
27
+ await logger.complete('failed');
28
+ throw error;
29
+ }
30
+ }
31
+ export function registerInitCommand(program) {
32
+ program
33
+ .command('init')
34
+ .description('Create a Limner target workspace from an input image')
35
+ .argument('<image>', 'input image path')
36
+ .requiredOption('-t, --target <name>', 'target name')
37
+ .option('--force', 'overwrite existing target scaffold files')
38
+ .action(async (image, options, command) => {
39
+ const globals = command.optsWithGlobals();
40
+ const result = await initTarget({
41
+ workspaceRoot: globals.workspace,
42
+ target: options.target,
43
+ imagePath: image,
44
+ force: options.force,
45
+ });
46
+ console.log(`Created target ${options.target}`);
47
+ console.log(`Target: ${result.targetRoot}`);
48
+ console.log(`Source: ${result.sourceImagePath}`);
49
+ });
50
+ }
51
+ async function writeTemplates(target, force) {
52
+ const files = [
53
+ ['contract/regions.json', target.regionsPath],
54
+ ['contract/tokens.json', target.tokensPath],
55
+ ['contract/acceptance.md', target.acceptancePath],
56
+ ['reference/index.html', target.referenceHtmlPath],
57
+ ['reference/styles.css', target.referenceCssPath],
58
+ ['AGENT_GUIDE.md', target.agentGuidePath],
59
+ ];
60
+ for (const [templatePath, destinationPath] of files) {
61
+ const contents = await readFile(path.join(templateRoot, templatePath), 'utf8');
62
+ await writeIfMissing(destinationPath, contents, force);
63
+ }
64
+ }
65
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerPreviewCommand(program: Command): void;
@@ -0,0 +1,27 @@
1
+ import { startStaticServer } from '../core/static-server.js';
2
+ import { resolveTarget } from '../core/workspace.js';
3
+ export function registerPreviewCommand(program) {
4
+ program
5
+ .command('preview')
6
+ .description('Preview a target reference HTML page')
7
+ .requiredOption('-t, --target <name>', 'target name')
8
+ .option('-p, --port <port>', 'port to bind', parseInteger)
9
+ .action(async (options, command) => {
10
+ const globals = command.optsWithGlobals();
11
+ const target = resolveTarget(globals.workspace, options.target);
12
+ const server = await startStaticServer(target.referenceDir, options.port ?? 0);
13
+ console.log(`Preview: ${server.url}`);
14
+ console.log('Press Ctrl+C to stop.');
15
+ process.on('SIGINT', async () => {
16
+ await server.close();
17
+ process.exit(0);
18
+ });
19
+ });
20
+ }
21
+ function parseInteger(value) {
22
+ const parsed = Number.parseInt(value, 10);
23
+ if (!Number.isFinite(parsed))
24
+ throw new Error(`Invalid integer: ${value}`);
25
+ return parsed;
26
+ }
27
+ //# sourceMappingURL=preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preview.js","sourceRoot":"","sources":["../../src/commands/preview.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACrD,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,sCAAsC,CAAC;SACnD,cAAc,CAAC,qBAAqB,EAAE,aAAa,CAAC;SACpD,MAAM,CAAC,mBAAmB,EAAE,cAAc,EAAE,YAAY,CAAC;SACzD,MAAM,CAAC,KAAK,EAAE,OAA0C,EAAE,OAAgB,EAAE,EAAE;QAC7E,MAAM,OAAO,GAAG,OAAO,CAAC,eAAe,EAA2B,CAAC;QACnE,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAC9B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,KAAK,EAAE,CAAC,CAAC;IAC3E,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerReportCommand(program: Command): void;
@@ -0,0 +1,14 @@
1
+ import { writeTargetSummary } from '../core/report-writer.js';
2
+ import { resolveTarget } from '../core/workspace.js';
3
+ export function registerReportCommand(program) {
4
+ program
5
+ .command('report')
6
+ .description('Print a target artifact summary')
7
+ .requiredOption('-t, --target <name>', 'target name')
8
+ .action(async (options, command) => {
9
+ const globals = command.optsWithGlobals();
10
+ const target = resolveTarget(globals.workspace, options.target);
11
+ console.log(await writeTargetSummary(target));
12
+ });
13
+ }
14
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,iCAAiC,CAAC;SAC9C,cAAc,CAAC,qBAAqB,EAAE,aAAa,CAAC;SACpD,MAAM,CAAC,KAAK,EAAE,OAA2B,EAAE,OAAgB,EAAE,EAAE;QAC9D,MAAM,OAAO,GAAG,OAAO,CAAC,eAAe,EAA2B,CAAC;QACnE,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAChE,OAAO,CAAC,GAAG,CAAC,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerRunsCommand(program: Command): void;
@@ -0,0 +1,63 @@
1
+ import { readdir, readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { resolveWorkspace } from '../core/workspace.js';
4
+ export function registerRunsCommand(program) {
5
+ const runs = program.command('runs').description('Inspect local Limner run logs');
6
+ runs
7
+ .command('list')
8
+ .description('List local Limner runs')
9
+ .action(async (_options, command) => {
10
+ const globals = command.optsWithGlobals();
11
+ const manifests = await listRunManifests(globals.workspace);
12
+ for (const manifest of manifests) {
13
+ console.log(`${manifest.runId}\t${manifest.status}\t${manifest.command}\t${manifest.target ?? '-'}\t${manifest.mode ?? '-'}`);
14
+ }
15
+ });
16
+ runs
17
+ .command('show')
18
+ .description('Show a run manifest and event log')
19
+ .argument('<runId>', 'run id')
20
+ .action(async (runId, _options, command) => {
21
+ const globals = command.optsWithGlobals();
22
+ const workspace = resolveWorkspace(globals.workspace);
23
+ const runDir = path.join(workspace.runsDir, runId);
24
+ console.log(await readFile(path.join(runDir, 'manifest.json'), 'utf8'));
25
+ console.log(await readFile(path.join(runDir, 'events.jsonl'), 'utf8'));
26
+ });
27
+ runs
28
+ .command('summarize')
29
+ .description('Summarize local Limner runs')
30
+ .action(async (_options, command) => {
31
+ const globals = command.optsWithGlobals();
32
+ const manifests = await listRunManifests(globals.workspace);
33
+ const byStatus = new Map();
34
+ for (const manifest of manifests) {
35
+ byStatus.set(manifest.status, (byStatus.get(manifest.status) ?? 0) + 1);
36
+ }
37
+ console.log(`Runs: ${manifests.length}`);
38
+ for (const [status, count] of byStatus.entries()) {
39
+ console.log(`${status}: ${count}`);
40
+ }
41
+ });
42
+ }
43
+ async function listRunManifests(workspaceRoot) {
44
+ const workspace = resolveWorkspace(workspaceRoot);
45
+ let runIds;
46
+ try {
47
+ runIds = await readdir(workspace.runsDir);
48
+ }
49
+ catch {
50
+ return [];
51
+ }
52
+ const manifests = [];
53
+ for (const runId of runIds.sort()) {
54
+ try {
55
+ manifests.push(JSON.parse(await readFile(path.join(workspace.runsDir, runId, 'manifest.json'), 'utf8')));
56
+ }
57
+ catch {
58
+ // Ignore malformed run folders while listing.
59
+ }
60
+ }
61
+ return manifests;
62
+ }
63
+ //# sourceMappingURL=runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/commands/runs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Page } from 'playwright';
2
+ import { type LimnerRegionContract } from '../schemas/contract.js';
3
+ export type RegionMetrics = {
4
+ id: string;
5
+ label: string;
6
+ selector: string;
7
+ found: boolean;
8
+ bounds?: {
9
+ x: number;
10
+ y: number;
11
+ width: number;
12
+ height: number;
13
+ };
14
+ computedStyle?: Record<string, string>;
15
+ text?: string;
16
+ };
17
+ export declare function loadRegionContract(filePath: string): Promise<LimnerRegionContract>;
18
+ export declare function collectRegionMetrics(page: Page, contract: LimnerRegionContract, side: 'reference' | 'app'): Promise<RegionMetrics[]>;
@@ -0,0 +1,54 @@
1
+ import { limnerRegionContractSchema } from '../schemas/contract.js';
2
+ import { readJsonFile } from './workspace.js';
3
+ export async function loadRegionContract(filePath) {
4
+ const raw = await readJsonFile(filePath);
5
+ return limnerRegionContractSchema.parse(raw);
6
+ }
7
+ export async function collectRegionMetrics(page, contract, side) {
8
+ const metrics = [];
9
+ for (const region of contract.regions) {
10
+ const selector = side === 'reference' ? region.referenceSelector : region.appSelector ?? region.referenceSelector;
11
+ const locator = page.locator(selector).first();
12
+ const count = await locator.count();
13
+ if (count === 0) {
14
+ metrics.push({ id: region.id, label: region.label, selector, found: false });
15
+ continue;
16
+ }
17
+ const bounds = await locator.boundingBox();
18
+ const computedStyle = await locator.evaluate((element) => {
19
+ const style = window.getComputedStyle(element);
20
+ return {
21
+ display: style.display,
22
+ position: style.position,
23
+ color: style.color,
24
+ backgroundColor: style.backgroundColor,
25
+ fontFamily: style.fontFamily,
26
+ fontSize: style.fontSize,
27
+ fontWeight: style.fontWeight,
28
+ lineHeight: style.lineHeight,
29
+ borderRadius: style.borderRadius,
30
+ borderColor: style.borderColor,
31
+ };
32
+ });
33
+ const text = await locator.innerText().catch(() => '');
34
+ metrics.push({
35
+ id: region.id,
36
+ label: region.label,
37
+ selector,
38
+ found: true,
39
+ bounds: bounds ? roundBounds(bounds) : undefined,
40
+ computedStyle,
41
+ text: text.slice(0, 1000),
42
+ });
43
+ }
44
+ return metrics;
45
+ }
46
+ function roundBounds(bounds) {
47
+ return {
48
+ x: Math.round(bounds.x * 100) / 100,
49
+ y: Math.round(bounds.y * 100) / 100,
50
+ width: Math.round(bounds.width * 100) / 100,
51
+ height: Math.round(bounds.height * 100) / 100,
52
+ };
53
+ }
54
+ //# sourceMappingURL=dom-metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dom-metrics.js","sourceRoot":"","sources":["../../src/core/dom-metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { LimnerRegionContract } from '../schemas/contract.js';
2
+ import { type RegionMetrics } from './dom-metrics.js';
3
+ export type CaptureOptions = {
4
+ url: string;
5
+ outputPath: string;
6
+ viewport?: {
7
+ width: number;
8
+ height: number;
9
+ };
10
+ storageState?: string;
11
+ fullPage?: boolean;
12
+ contract?: LimnerRegionContract;
13
+ side?: 'reference' | 'app';
14
+ headed?: boolean;
15
+ };
16
+ export type CaptureResult = {
17
+ url: string;
18
+ title: string;
19
+ screenshotPath: string;
20
+ consoleMessages: Array<{
21
+ type: string;
22
+ text: string;
23
+ }>;
24
+ metrics: RegionMetrics[];
25
+ bodyText: string;
26
+ };
27
+ export declare function capturePage(options: CaptureOptions): Promise<CaptureResult>;
@@ -0,0 +1,46 @@
1
+ import { mkdir, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { chromium } from 'playwright';
4
+ import { collectRegionMetrics } from './dom-metrics.js';
5
+ export async function capturePage(options) {
6
+ const browser = await chromium.launch({ headless: !options.headed });
7
+ const context = await browser.newContext({
8
+ viewport: options.viewport ?? { width: 1440, height: 900 },
9
+ deviceScaleFactor: 1,
10
+ storageState: options.storageState,
11
+ });
12
+ const page = await context.newPage();
13
+ const consoleMessages = [];
14
+ page.on('console', (message) => {
15
+ if (message.type() === 'warning' || message.type() === 'error') {
16
+ consoleMessages.push({ type: message.type(), text: message.text() });
17
+ }
18
+ });
19
+ try {
20
+ await page.goto(options.url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
21
+ await page.waitForTimeout(500);
22
+ await mkdir(path.dirname(options.outputPath), { recursive: true });
23
+ await page.screenshot({ path: options.outputPath, fullPage: options.fullPage ?? false });
24
+ const metrics = options.contract
25
+ ? await collectRegionMetrics(page, options.contract, options.side ?? 'reference')
26
+ : [];
27
+ const bodyText = await page.locator('body').innerText().catch(() => '');
28
+ const result = {
29
+ url: page.url(),
30
+ title: await page.title(),
31
+ screenshotPath: options.outputPath,
32
+ consoleMessages,
33
+ metrics,
34
+ bodyText,
35
+ };
36
+ await writeFile(`${options.outputPath}.console.json`, JSON.stringify(consoleMessages, null, 2) + '\n');
37
+ if (metrics.length > 0) {
38
+ await writeFile(`${options.outputPath}.metrics.json`, JSON.stringify(metrics, null, 2) + '\n');
39
+ }
40
+ return result;
41
+ }
42
+ finally {
43
+ await browser.close();
44
+ }
45
+ }
46
+ //# sourceMappingURL=playwright-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-capture.js","sourceRoot":"","sources":["../../src/core/playwright-capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Locator, Page } from 'playwright';
2
+ export declare function firstVisible(page: Page, selectors: string[]): Promise<{
3
+ selector: string;
4
+ locator: Locator;
5
+ } | undefined>;
6
+ export declare function elementBounds(locator: Locator): Promise<{
7
+ x: number;
8
+ y: number;
9
+ width: number;
10
+ height: number;
11
+ } | undefined>;
12
+ export declare function elementText(locator: Locator): Promise<string>;
13
+ export declare function visibleTexts(locator: Locator, limit?: number): Promise<string[]>;
14
+ export declare function computedStyle(locator: Locator): Promise<Record<string, string> | undefined>;
15
+ export declare function normalizeColor(value: string | undefined): string;
16
+ export declare function toPx(value: string | undefined): number | undefined;
@@ -0,0 +1,64 @@
1
+ export async function firstVisible(page, selectors) {
2
+ for (const selector of selectors) {
3
+ const locator = page.locator(selector).first();
4
+ if (await locator.count() && await locator.isVisible().catch(() => false)) {
5
+ return { selector, locator };
6
+ }
7
+ }
8
+ return undefined;
9
+ }
10
+ export async function elementBounds(locator) {
11
+ const bounds = await locator.boundingBox();
12
+ return bounds ?? undefined;
13
+ }
14
+ export async function elementText(locator) {
15
+ return locator.innerText().then((text) => text.replace(/\s+/g, ' ').trim()).catch(() => '');
16
+ }
17
+ export async function visibleTexts(locator, limit = Number.POSITIVE_INFINITY) {
18
+ const count = await locator.count();
19
+ const values = [];
20
+ for (let index = 0; index < Math.min(count, limit); index += 1) {
21
+ const candidate = locator.nth(index);
22
+ if (!(await candidate.isVisible().catch(() => false))) {
23
+ continue;
24
+ }
25
+ const text = await elementText(candidate);
26
+ if (text) {
27
+ values.push(text);
28
+ }
29
+ }
30
+ return values;
31
+ }
32
+ export async function computedStyle(locator) {
33
+ if (!(await locator.count()) || !(await locator.isVisible().catch(() => false))) {
34
+ return undefined;
35
+ }
36
+ return locator.evaluate((element) => {
37
+ const style = window.getComputedStyle(element);
38
+ return {
39
+ backgroundColor: style.backgroundColor,
40
+ borderColor: style.borderColor,
41
+ borderRadius: style.borderRadius,
42
+ color: style.color,
43
+ fontFamily: style.fontFamily,
44
+ fontSize: style.fontSize,
45
+ fontWeight: style.fontWeight,
46
+ paddingLeft: style.paddingLeft,
47
+ position: style.position,
48
+ };
49
+ });
50
+ }
51
+ export function normalizeColor(value) {
52
+ if (!value) {
53
+ return '';
54
+ }
55
+ const matches = value.match(/\d+(\.\d+)?/g);
56
+ if (!matches || matches.length < 3) {
57
+ return value;
58
+ }
59
+ return `#${matches.slice(0, 3).map((part) => Number.parseFloat(part).toString(16).padStart(2, '0')).join('')}`;
60
+ }
61
+ export function toPx(value) {
62
+ return value ? Number.parseFloat(value) || undefined : undefined;
63
+ }
64
+ //# sourceMappingURL=playwright-dom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playwright-dom.js","sourceRoot":"","sources":["../../src/core/playwright-dom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ export type ReferenceDomFacts = {
2
+ viewport: {
3
+ width: number;
4
+ height: number;
5
+ };
6
+ selectors: {
7
+ header?: string;
8
+ hero?: string;
9
+ footer?: string;
10
+ frame?: string;
11
+ };
12
+ bounds: {
13
+ header?: {
14
+ x: number;
15
+ y: number;
16
+ width: number;
17
+ height: number;
18
+ };
19
+ hero?: {
20
+ x: number;
21
+ y: number;
22
+ width: number;
23
+ height: number;
24
+ };
25
+ footer?: {
26
+ x: number;
27
+ y: number;
28
+ width: number;
29
+ height: number;
30
+ };
31
+ frame?: {
32
+ x: number;
33
+ y: number;
34
+ width: number;
35
+ height: number;
36
+ };
37
+ };
38
+ typography: {
39
+ bodyFont?: string;
40
+ bodySize?: number;
41
+ headingFont?: string;
42
+ headingSize?: number;
43
+ headingWeight?: number;
44
+ };
45
+ tokens: {
46
+ background?: string;
47
+ text?: string;
48
+ surface?: string;
49
+ border?: string;
50
+ accent?: string;
51
+ panelRadius?: number;
52
+ controlRadius?: number;
53
+ pagePadding?: number;
54
+ };
55
+ content: {
56
+ headingText?: string;
57
+ primaryActions: string[];
58
+ disabledActions: string[];
59
+ warningText: string[];
60
+ progressLabels: string[];
61
+ };
62
+ mobileTraits: string[];
63
+ panelCount: number;
64
+ };
65
+ export declare function collectReferenceDomFacts(url: string, headed?: boolean): Promise<ReferenceDomFacts>;
@@ -0,0 +1,71 @@
1
+ import { chromium } from 'playwright';
2
+ import { computedStyle, elementBounds, elementText, firstVisible, normalizeColor, toPx, visibleTexts } from './playwright-dom.js';
3
+ export async function collectReferenceDomFacts(url, headed = false) {
4
+ const browser = await chromium.launch({ headless: !headed });
5
+ const context = await browser.newContext({ viewport: { width: 1440, height: 900 }, deviceScaleFactor: 1 });
6
+ const page = await context.newPage();
7
+ try {
8
+ await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30_000 });
9
+ await page.waitForTimeout(250);
10
+ const viewport = await page.evaluate(() => ({ width: window.innerWidth, height: window.innerHeight }));
11
+ const header = await firstVisible(page, ['header', '.app-topbar', '.mobile-eventbar', '.mobile-status']);
12
+ const hero = await firstVisible(page, ['h1', '.mobile-h1', '.h1']);
13
+ const footer = await firstVisible(page, ['footer', '.bottom-fixed', '.footer-nav']);
14
+ const frame = await firstVisible(page, ['.mobile-frame', '.content-wide', '.content-narrow', '[data-limner-region="reference-root"]']);
15
+ const panel = await firstVisible(page, ['.panel', '.mobile-card', '.mobile-panel', '.rail-item']);
16
+ const action = await firstVisible(page, ['.cta', 'button', 'a[href]']);
17
+ const bodyStyle = await computedStyle(page.locator('body'));
18
+ const heroStyle = hero ? await computedStyle(hero.locator) : undefined;
19
+ const panelStyle = panel ? await computedStyle(panel.locator) : undefined;
20
+ const actionStyle = action ? await computedStyle(action.locator) : undefined;
21
+ return {
22
+ viewport,
23
+ selectors: {
24
+ header: header?.selector,
25
+ hero: hero?.selector,
26
+ footer: footer?.selector,
27
+ frame: frame?.selector,
28
+ },
29
+ bounds: {
30
+ header: header ? await elementBounds(header.locator) : undefined,
31
+ hero: hero ? await elementBounds(hero.locator) : undefined,
32
+ footer: footer ? await elementBounds(footer.locator) : undefined,
33
+ frame: frame ? await elementBounds(frame.locator) : undefined,
34
+ },
35
+ typography: {
36
+ bodyFont: bodyStyle?.fontFamily,
37
+ bodySize: toPx(bodyStyle?.fontSize),
38
+ headingFont: heroStyle?.fontFamily,
39
+ headingSize: toPx(heroStyle?.fontSize),
40
+ headingWeight: heroStyle?.fontWeight ? Number.parseInt(heroStyle.fontWeight, 10) || undefined : undefined,
41
+ },
42
+ tokens: {
43
+ background: normalizeColor(bodyStyle?.backgroundColor),
44
+ text: normalizeColor(bodyStyle?.color),
45
+ surface: normalizeColor(panelStyle?.backgroundColor),
46
+ border: normalizeColor(panelStyle?.borderColor),
47
+ accent: normalizeColor(actionStyle?.backgroundColor),
48
+ panelRadius: toPx(panelStyle?.borderRadius),
49
+ controlRadius: toPx(actionStyle?.borderRadius),
50
+ pagePadding: toPx(frame ? (await computedStyle(frame.locator))?.paddingLeft : undefined),
51
+ },
52
+ content: {
53
+ headingText: hero ? await elementText(hero.locator) : undefined,
54
+ primaryActions: await visibleTexts(page.locator('.cta, button, a[href]'), 6),
55
+ disabledActions: await visibleTexts(page.locator('.disabled, button[disabled], a[aria-disabled="true"]'), 6),
56
+ warningText: await visibleTexts(page.locator('.warning-panel, .danger-panel, [class*="warning"], [class*="danger"]'), 4),
57
+ progressLabels: await visibleTexts(page.locator('.step-dot, .progress-line, .label, .mobile-stepbar'), 8),
58
+ },
59
+ mobileTraits: [
60
+ (await page.locator('.mobile-frame').count()) > 0 ? 'mobile-frame' : '',
61
+ (await page.locator('.bottom-fixed').count()) > 0 ? 'sticky-bottom-actions' : '',
62
+ viewport.width <= 700 ? 'narrow-viewport' : '',
63
+ ].filter(Boolean),
64
+ panelCount: await page.locator('.panel, .mobile-card, .mobile-panel, .rail-item').count(),
65
+ };
66
+ }
67
+ finally {
68
+ await browser.close();
69
+ }
70
+ }
71
+ //# sourceMappingURL=reference-dom-facts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference-dom-facts.js","sourceRoot":"","sources":["../../src/core/reference-dom-facts.ts"],"names":[],"mappings":"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"}