From 0a14c6b1ba9a4227287e174a896443f4bc9fb0ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 16 Oct 2026 13:28:21 +0200 Subject: [PATCH 1/2] refactor(capture-kit): move screenshot-diff beside its pixel worker and overlays Co-Authored-By: Claude Sonnet 5.5 --- docs/adr/0019-request-bound-platform-runtime.md | 9 +++++---- packages/capture-kit/package.json | 12 ++++++++++++ .../capture-kit/src}/screenshot-diff-components.ts | 0 .../src}/screenshot-diff-overlay-matches.ts | 0 .../src}/screenshot-diff-region-overlay.ts | 2 +- .../capture-kit/src}/screenshot-diff-region-split.ts | 2 +- .../capture-kit/src}/screenshot-diff-region-types.ts | 0 .../capture-kit/src}/screenshot-diff-regions.ts | 2 +- .../capture-kit/src}/screenshot-diff.test.ts | 6 +++--- .../capture-kit/src}/screenshot-diff.ts | 4 ++-- src/cli/commands/screenshot.ts | 2 +- src/commands/capture/runtime/diff-screenshot.ts | 4 ++-- src/commands/output/diff.ts | 4 ++-- 13 files changed, 30 insertions(+), 17 deletions(-) rename {src/screenshot-diff => packages/capture-kit/src}/screenshot-diff-components.ts (100%) rename {src/screenshot-diff => packages/capture-kit/src}/screenshot-diff-overlay-matches.ts (100%) rename {src/screenshot-diff => packages/capture-kit/src}/screenshot-diff-region-overlay.ts (97%) rename {src/screenshot-diff => packages/capture-kit/src}/screenshot-diff-region-split.ts (99%) rename {src/screenshot-diff => packages/capture-kit/src}/screenshot-diff-region-types.ts (100%) rename {src/screenshot-diff => packages/capture-kit/src}/screenshot-diff-regions.ts (99%) rename {src/screenshot-diff/__tests__ => packages/capture-kit/src}/screenshot-diff.test.ts (99%) rename {src/screenshot-diff => packages/capture-kit/src}/screenshot-diff.ts (98%) diff --git a/docs/adr/0019-request-bound-platform-runtime.md b/docs/adr/0019-request-bound-platform-runtime.md index f6074b484c..a18b6134d9 100644 --- a/docs/adr/0019-request-bound-platform-runtime.md +++ b/docs/adr/0019-request-bound-platform-runtime.md @@ -990,10 +990,11 @@ anchor, not as a proposed commitment. `interaction-targeting` and the android UI-hierarchy fixtures) and `src/__tests__/snapshot-desktop-surface.test.ts` (pinned to the root eager-import-closure fixtures). -- `src/screenshot-diff/*.ts` (region split/overlay/summarization/component composition) — - pixel-diff computation and PNG decode/encode already call capture-kit's `png`/ - `png-worker-client`; the root files remain for daemon/CLI diff-report composition. - Equivalent: none (built atop already-migrated capture-kit mechanics). +- `src/screenshot-diff/*.ts` (region split/overlay/summarization/component composition, with its + test) — **migrated to `packages/capture-kit/src/`** beside the pixel worker and screenshot + overlays it was built on. The CLI and command output consume it through + `@agent-device/capture-kit/screenshot-diff`, `/screenshot-diff-regions`, and + `/screenshot-diff-overlay-matches`. - `src/provider-device-runtime.ts`, `src/provider-device-runtimes.ts`, `src/provider-limrun-runtime.ts`, `src/provider-webdriver.ts`. Mostly already thin: the bulk of WebDriver and Limrun provider logic lives in `packages/provider-webdriver/src/` and diff --git a/packages/capture-kit/package.json b/packages/capture-kit/package.json index 722d2c51bc..93b2b54e02 100644 --- a/packages/capture-kit/package.json +++ b/packages/capture-kit/package.json @@ -238,10 +238,22 @@ "types": "./src/screenshot-density.ts", "default": "./src/screenshot-density.ts" }, + "./screenshot-diff": { + "types": "./src/screenshot-diff.ts", + "default": "./src/screenshot-diff.ts" + }, + "./screenshot-diff-overlay-matches": { + "types": "./src/screenshot-diff-overlay-matches.ts", + "default": "./src/screenshot-diff-overlay-matches.ts" + }, "./screenshot-diff-pixels": { "types": "./src/screenshot-diff-pixels.ts", "default": "./src/screenshot-diff-pixels.ts" }, + "./screenshot-diff-regions": { + "types": "./src/screenshot-diff-regions.ts", + "default": "./src/screenshot-diff-regions.ts" + }, "./screenshot-overlay": { "types": "./src/screenshot-overlay.ts", "default": "./src/screenshot-overlay.ts" diff --git a/src/screenshot-diff/screenshot-diff-components.ts b/packages/capture-kit/src/screenshot-diff-components.ts similarity index 100% rename from src/screenshot-diff/screenshot-diff-components.ts rename to packages/capture-kit/src/screenshot-diff-components.ts diff --git a/src/screenshot-diff/screenshot-diff-overlay-matches.ts b/packages/capture-kit/src/screenshot-diff-overlay-matches.ts similarity index 100% rename from src/screenshot-diff/screenshot-diff-overlay-matches.ts rename to packages/capture-kit/src/screenshot-diff-overlay-matches.ts diff --git a/src/screenshot-diff/screenshot-diff-region-overlay.ts b/packages/capture-kit/src/screenshot-diff-region-overlay.ts similarity index 97% rename from src/screenshot-diff/screenshot-diff-region-overlay.ts rename to packages/capture-kit/src/screenshot-diff-region-overlay.ts index 66d7c0cafa..478a76c7cf 100644 --- a/src/screenshot-diff/screenshot-diff-region-overlay.ts +++ b/packages/capture-kit/src/screenshot-diff-region-overlay.ts @@ -1,4 +1,4 @@ -import type { PNG } from '@agent-device/capture-kit/png'; +import type { PNG } from './png.ts'; import type { ScreenshotDiffRegion } from './screenshot-diff-regions.ts'; const REGION_BORDER_COLOR = [0, 187, 255, 255] as const; diff --git a/src/screenshot-diff/screenshot-diff-region-split.ts b/packages/capture-kit/src/screenshot-diff-region-split.ts similarity index 99% rename from src/screenshot-diff/screenshot-diff-region-split.ts rename to packages/capture-kit/src/screenshot-diff-region-split.ts index ace6cbbd97..cbc44323b4 100644 --- a/src/screenshot-diff/screenshot-diff-region-split.ts +++ b/packages/capture-kit/src/screenshot-diff-region-split.ts @@ -1,4 +1,4 @@ -import type { PNG } from '@agent-device/capture-kit/png'; +import type { PNG } from './png.ts'; import type { MutableDiffRegion } from './screenshot-diff-region-types.ts'; // Region splitting is based on screen-relative heights so it works on phone, diff --git a/src/screenshot-diff/screenshot-diff-region-types.ts b/packages/capture-kit/src/screenshot-diff-region-types.ts similarity index 100% rename from src/screenshot-diff/screenshot-diff-region-types.ts rename to packages/capture-kit/src/screenshot-diff-region-types.ts diff --git a/src/screenshot-diff/screenshot-diff-regions.ts b/packages/capture-kit/src/screenshot-diff-regions.ts similarity index 99% rename from src/screenshot-diff/screenshot-diff-regions.ts rename to packages/capture-kit/src/screenshot-diff-regions.ts index 952b2066e5..b699e85c2c 100644 --- a/src/screenshot-diff/screenshot-diff-regions.ts +++ b/packages/capture-kit/src/screenshot-diff-regions.ts @@ -1,5 +1,5 @@ import type { Rect } from '@agent-device/kernel/snapshot'; -import type { PNG } from '@agent-device/capture-kit/png'; +import type { PNG } from './png.ts'; import { normalizedRect, type NormalizedRect } from '@agent-device/kernel/screenshot-geometry'; import { findConnectedMaskComponents } from './screenshot-diff-components.ts'; import { splitLargeDiffRegions } from './screenshot-diff-region-split.ts'; diff --git a/src/screenshot-diff/__tests__/screenshot-diff.test.ts b/packages/capture-kit/src/screenshot-diff.test.ts similarity index 99% rename from src/screenshot-diff/__tests__/screenshot-diff.test.ts rename to packages/capture-kit/src/screenshot-diff.test.ts index cd9a1ec5b7..ba4e4792c0 100644 --- a/src/screenshot-diff/__tests__/screenshot-diff.test.ts +++ b/packages/capture-kit/src/screenshot-diff.test.ts @@ -2,10 +2,10 @@ import { test } from 'vitest'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; -import { mkdtempForTestSync } from '@agent-device/test-kit'; +import { mkdtempForTestSync } from './tmp-dir.fixtures.ts'; -import { hasPngSignature, PNG } from '@agent-device/capture-kit/png'; -import { compareScreenshots } from '../screenshot-diff.ts'; +import { hasPngSignature, PNG } from './png.ts'; +import { compareScreenshots } from './screenshot-diff.ts'; function tmpDir(): string { return mkdtempForTestSync('agent-device-screenshot-diff-'); diff --git a/src/screenshot-diff/screenshot-diff.ts b/packages/capture-kit/src/screenshot-diff.ts similarity index 98% rename from src/screenshot-diff/screenshot-diff.ts rename to packages/capture-kit/src/screenshot-diff.ts index 657d104591..500664f046 100644 --- a/src/screenshot-diff/screenshot-diff.ts +++ b/packages/capture-kit/src/screenshot-diff.ts @@ -2,12 +2,12 @@ import { promises as fs } from 'node:fs'; import path from 'node:path'; import { AppError } from '@agent-device/kernel/errors'; import type { Rect } from '@agent-device/kernel/snapshot'; -import { PNG } from '@agent-device/capture-kit/png'; +import { PNG } from './png.ts'; import { computeScreenshotDiffPixelsAsync, decodeScreenshotImageAsync, encodePngAsync, -} from '@agent-device/capture-kit/png-worker-client'; +} from './png-worker-client.ts'; import { annotateDiffRegions } from './screenshot-diff-region-overlay.ts'; import { summarizeDiffRegions, type ScreenshotDiffRegion } from './screenshot-diff-regions.ts'; import type { ImageDimensions } from '@agent-device/kernel/screenshot-geometry'; diff --git a/src/cli/commands/screenshot.ts b/src/cli/commands/screenshot.ts index 8cff127c59..0e3b291236 100644 --- a/src/cli/commands/screenshot.ts +++ b/src/cli/commands/screenshot.ts @@ -1,6 +1,6 @@ import { localCommandPolicy } from '@agent-device/contracts/command-policy'; import { formatScreenshotDiffText, formatSnapshotDiffText } from '../../commands/output/diff.ts'; -import type { ScreenshotDiffResult } from '../../screenshot-diff/screenshot-diff.ts'; +import type { ScreenshotDiffResult } from '@agent-device/capture-kit/screenshot-diff'; import { AppError } from '@agent-device/kernel/errors'; import { isNonDefaultResponseLevel } from '@agent-device/kernel/contracts'; import { resolveUserPath } from '@agent-device/host-kit/file'; diff --git a/src/commands/capture/runtime/diff-screenshot.ts b/src/commands/capture/runtime/diff-screenshot.ts index ffeef99376..7abe0adbcb 100644 --- a/src/commands/capture/runtime/diff-screenshot.ts +++ b/src/commands/capture/runtime/diff-screenshot.ts @@ -16,8 +16,8 @@ import { AppError } from '@agent-device/kernel/errors'; import { compareScreenshots, type ScreenshotDiffResult, -} from '../../../screenshot-diff/screenshot-diff.ts'; -import { attachCurrentOverlayMatches } from '../../../screenshot-diff/screenshot-diff-overlay-matches.ts'; +} from '@agent-device/capture-kit/screenshot-diff'; +import { attachCurrentOverlayMatches } from '@agent-device/capture-kit/screenshot-diff-overlay-matches'; import type { RuntimeCommand } from '../../runtime-types.ts'; import { createCommandTempFile, diff --git a/src/commands/output/diff.ts b/src/commands/output/diff.ts index dab295824a..c16b73a7ba 100644 --- a/src/commands/output/diff.ts +++ b/src/commands/output/diff.ts @@ -1,8 +1,8 @@ import path from 'node:path'; import { colorize, supportsColor } from './color.ts'; import { readSnapshotWarnings } from './snapshot.ts'; -import type { ScreenshotDiffResult } from '../../screenshot-diff/screenshot-diff.ts'; -import type { ScreenshotDiffRegion } from '../../screenshot-diff/screenshot-diff-regions.ts'; +import type { ScreenshotDiffResult } from '@agent-device/capture-kit/screenshot-diff'; +import type { ScreenshotDiffRegion } from '@agent-device/capture-kit/screenshot-diff-regions'; type SnapshotDiffLine = { kind?: 'added' | 'removed' | 'unchanged'; text?: string; From 05c664543996f00303d7f9807d53c64248217c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Fri, 16 Oct 2026 13:28:21 +0200 Subject: [PATCH 2/2] chore(gates): drop the screenshot-diff zone and pin the new capture-kit exports Co-Authored-By: Claude Sonnet 5.5 --- scripts/layering/model.test.ts | 1 - scripts/layering/model.ts | 1 - scripts/layering/package-boundaries.test.ts | 3 +++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/layering/model.test.ts b/scripts/layering/model.test.ts index 1ccdf44885..818b8dd51b 100644 --- a/scripts/layering/model.test.ts +++ b/scripts/layering/model.test.ts @@ -521,7 +521,6 @@ test('classifyZone separates the ranked spine from intentionally-unranked zones' assert.equal(classifyZone('(root)'), 'ranked'); assert.equal(classifyZone('platform-runtime'), 'ranked'); assert.equal(classifyZone('mcp'), 'ranked'); - assert.equal(classifyZone('screenshot-diff'), 'ranked'); // A zone that is neither ranked nor listed peripheral must be flagged, never // silently treated as back-edge-free. assert.equal(classifyZone('not-a-real-zone'), 'unclassified'); diff --git a/scripts/layering/model.ts b/scripts/layering/model.ts index a1114d3352..08528310eb 100644 --- a/scripts/layering/model.ts +++ b/scripts/layering/model.ts @@ -55,7 +55,6 @@ const TARGET_DAG_RANK = new Map([ ['maestro', 1], ['replay-port', 1], ['replay-test', 1], - ['screenshot-diff', 1], ['selectors', 1], ['session-journal', 1], ['core', 2], diff --git a/scripts/layering/package-boundaries.test.ts b/scripts/layering/package-boundaries.test.ts index 518dd3abf8..6c74a8d526 100644 --- a/scripts/layering/package-boundaries.test.ts +++ b/scripts/layering/package-boundaries.test.ts @@ -529,7 +529,10 @@ test('the real tree parses, declares, and passes R11', () => { '@agent-device/capture-kit/screen-recording-stop-recovery', '@agent-device/capture-kit/screen-recording-transport', '@agent-device/capture-kit/screenshot-density', + '@agent-device/capture-kit/screenshot-diff', + '@agent-device/capture-kit/screenshot-diff-overlay-matches', '@agent-device/capture-kit/screenshot-diff-pixels', + '@agent-device/capture-kit/screenshot-diff-regions', '@agent-device/capture-kit/screenshot-overlay', '@agent-device/capture-kit/scroll-edge-state', '@agent-device/capture-kit/snapshot-baseline',