Skip to content

Commit b4ebd77

Browse files
thymikeeclaude
andauthored
refactor(daemon): move four pure leaves to their kits (#2347)
* refactor(selectors): own the parameterized recorded fill leaf `parameterized-recorded-fill.ts` has no value dependency on the daemon: it reads a `TargetAnnotationV1` type from contracts and calls `selectorContainsValue`, so its whole value graph already sits inside `@agent-device/selectors`. Move it there behind its own subpath and let the two daemon consumers reach it by specifier. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BPFjVXwbDrXPqp5W6K2iDK * refactor(host-kit): own the daemon code signature leaves `code-signature.ts` fingerprints a checkout from `node:crypto`/`fs`/`path` and `findProjectRoot`; `code-signature-cache.ts` adds a stat-validated cache over it through `publishFileSync`. Neither reaches the daemon, and both questions — what does this source tree hash to, and can that hash be replayed from stat alone — are host mechanics. Move both into host-kit behind their own subpaths, carrying `code-signature-cache.test.ts` unchanged apart from its specifiers, and let the launch spec and server lifecycle reach them by specifier. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BPFjVXwbDrXPqp5W6K2iDK * refactor(capture-kit): own the screenshot overlay cluster `screenshot-overlay.ts` decides which snapshot nodes earn a ref and where the ref lands on a screenshot; `screenshot-overlay-draw.ts` paints them. Both read kernel snapshot vocabulary, contracts snapshot predicates, and capture-kit's own PNG and rect-projection mechanics — nothing from the daemon. The two `src/snapshot/screenshot-overlay/` helpers had no other importer, and `react-native-overlay.ts` sits on kernel plus its contracts vocabulary alone. Move the cluster into capture-kit as flat siblings of the PNG and projection modules it already used, exposing `./screenshot-overlay` and `./react-native-overlay`; the draw, rects, and android halves stay package internals with no subpath of their own. The moved tests carry over unchanged apart from their specifiers, over a package-local snapshot-state fixture. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BPFjVXwbDrXPqp5W6K2iDK * refactor(capture-kit): own the post-gesture stability loop `post-gesture-stability.ts` polls a caller-supplied snapshot function until a surface settles. It is generic over its snapshot and signature types and reads only host-kit diagnostics and `sleep`, so the loop is capture mechanics with no daemon knowledge; the daemon keeps the pending record, the comparator, and the verdict wiring it hands in. The verdict test stays in `src/daemon` because it composes the loop with the daemon's own `interaction-outcome-policy.ts`; only its specifier changes. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BPFjVXwbDrXPqp5W6K2iDK * chore(gates): pin the four leaf subpaths in the R11 export lists R11 pins every workspace package's exact subpath set, so the four moves need their new specifiers named: `@agent-device/selectors/parameterized-recorded-fill`, `@agent-device/host-kit/code-signature{,-cache}`, and `@agent-device/capture-kit/{screenshot-overlay,react-native-overlay,post-gesture-stability}`. The selectors comment counted its subpaths in prose; it now counts four and says what the fourth is. No eager-closure row is needed: every new entry is a rename the merge-base reader follows, and each closure is unchanged (56/5/19/32/4/8), so all six fall under no-growth rather than the new-entry ceiling. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BPFjVXwbDrXPqp5W6K2iDK * refactor(capture-kit): drop the needless duplication suppression The `fallow-ignore-next-line code-duplication` on the package-local snapshot-state fixture suppressed nothing: `fallow dupes` reports three clone groups on this tree and the fixture is in none of them, with or without the comment. A suppression that matches no finding is dead weight at best and a stale-suppression failure at worst. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BPFjVXwbDrXPqp5W6K2iDK * fix(host-kit): follow workspace subpaths when fingerprinting daemon source `walkDaemonCodeGraph` followed relative specifiers only, so a source checkout's signature covered whatever the daemon still imported by relative path. That was already lossy and the leaf moves made it wrong: the walker itself, the overlay, the recorded-fill and the stability loop all left the graph, so editing them no longer changed the signature a client compares a running daemon against, and the cache's format guard lost the "the walk invalidates every document" property its comment rests on. Measured from `src/daemon.ts`: 619 modules on main with the walker stamped, 611 after the moves with it gone. Resolve a scoped specifier through the owning workspace package's `exports` map and walk into the file it names. The manifest is stamped, not merely probed, so an `exports` retarget invalidates without either endpoint changing; an uninstalled package is recorded as an absent path. Installed dependencies are still not followed — they change on install, not on edit — and the test is structural rather than a name pattern. The graph is now 1459 modules and ~112ms cold, which is what the stat-validated cache exists to absorb. Regression: five of the six new walker tests fail against the previous walker, including one that stamps the real daemon graph and asserts the walker is in it. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01BPFjVXwbDrXPqp5W6K2iDK --------- Co-authored-by: Claude <[email protected]>
1 parent 835af32 commit b4ebd77

33 files changed

Lines changed: 604 additions & 219 deletions

‎packages/capture-kit/package.json‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@
2626
"types": "./src/ios-snapshot-acquisition.ts",
2727
"default": "./src/ios-snapshot-acquisition.ts"
2828
},
29-
"./ios-snapshot-planning": {
30-
"types": "./src/ios-snapshot-planning.ts",
31-
"default": "./src/ios-snapshot-planning.ts"
32-
},
3329
"./ios-snapshot-engine": {
3430
"types": "./src/ios-snapshot-engine/index.ts",
3531
"default": "./src/ios-snapshot-engine/index.ts"
3632
},
33+
"./ios-snapshot-planning": {
34+
"types": "./src/ios-snapshot-planning.ts",
35+
"default": "./src/ios-snapshot-planning.ts"
36+
},
3737
"./mobile-snapshot-semantics": {
3838
"types": "./src/mobile-snapshot-semantics.ts",
3939
"default": "./src/mobile-snapshot-semantics.ts"
@@ -62,6 +62,14 @@
6262
"types": "./src/png-worker-client.ts",
6363
"default": "./src/png-worker-client.ts"
6464
},
65+
"./post-gesture-stability": {
66+
"types": "./src/post-gesture-stability.ts",
67+
"default": "./src/post-gesture-stability.ts"
68+
},
69+
"./react-native-overlay": {
70+
"types": "./src/react-native-overlay.ts",
71+
"default": "./src/react-native-overlay.ts"
72+
},
6573
"./screenshot-density": {
6674
"types": "./src/screenshot-density.ts",
6775
"default": "./src/screenshot-density.ts"
@@ -70,6 +78,10 @@
7078
"types": "./src/screenshot-diff-pixels.ts",
7179
"default": "./src/screenshot-diff-pixels.ts"
7280
},
81+
"./screenshot-overlay": {
82+
"types": "./src/screenshot-overlay.ts",
83+
"default": "./src/screenshot-overlay.ts"
84+
},
7385
"./snapshot-desktop-projection": {
7486
"types": "./src/snapshot-desktop-projection.ts",
7587
"default": "./src/snapshot-desktop-projection.ts"
File renamed without changes.
File renamed without changes.

src/snapshot/__tests__/screenshot-overlay-android.test.ts renamed to packages/capture-kit/src/screenshot-overlay-android.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import assert from 'node:assert/strict';
22
import { test } from 'vitest';
33
import type { SnapshotNode } from '@agent-device/kernel/snapshot';
4-
import { makeSnapshotState } from '../../__tests__/test-utils/snapshot-builders.ts';
4+
import { makeSnapshotState } from './snapshot-state.fixtures.ts';
55
import {
66
isAndroidUnlabeledClickableSource,
77
resolveAndroidOverlaySourceRect,
8-
} from '../screenshot-overlay/android.ts';
8+
} from './screenshot-overlay-android.ts';
99

1010
const SCREEN = { x: 0, y: 0, width: 1080, height: 1920 };
1111

src/snapshot/screenshot-overlay/android.ts renamed to packages/capture-kit/src/screenshot-overlay-android.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Rect, SnapshotNode, SnapshotState } from '@agent-device/kernel/snapshot';
22
import { isViewportRootNode, normalizeType } from '@agent-device/contracts/snapshot';
3-
import { hasPositiveRect, rectArea, rectContains, unionRects } from './rects.ts';
3+
import { hasPositiveRect, rectArea, rectContains, unionRects } from './screenshot-overlay-rects.ts';
44

55
/**
66
* Android overlay policy (#1983): which Android nodes earn an overlay ref, and what rectangle

src/daemon/screenshot-overlay-draw.ts renamed to packages/capture-kit/src/screenshot-overlay-draw.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Rect, ScreenshotOverlayRef } from '@agent-device/kernel/snapshot';
2-
import type { PNG } from '@agent-device/capture-kit/png';
3-
import { clamp } from '../snapshot/screenshot-overlay/rects.ts';
2+
import type { PNG } from './png.ts';
3+
import { clamp } from './screenshot-overlay-rects.ts';
44

55
/**
66
* Rasterizing one overlay ref onto a decoded PNG: border, badge, and the bitmap glyphs the badge
File renamed without changes.

src/daemon/__tests__/screenshot-overlay.test.ts renamed to packages/capture-kit/src/screenshot-overlay.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { test } from 'vitest';
22
import assert from 'node:assert/strict';
33
import fs from 'node:fs';
44
import path from 'node:path';
5-
import { PNG } from '@agent-device/capture-kit/png';
6-
import { annotateScreenshotWithRefs, buildScreenshotOverlayRefs } from '../screenshot-overlay.ts';
7-
import { makeSnapshotState } from '../../__tests__/test-utils/snapshot-builders.ts';
8-
import { mkdtempForTestSync } from '../../__tests__/test-utils/tmp-dir.ts';
5+
import { PNG } from './png.ts';
6+
import { annotateScreenshotWithRefs, buildScreenshotOverlayRefs } from './screenshot-overlay.ts';
7+
import { makeSnapshotState } from './snapshot-state.fixtures.ts';
8+
import { mkdtempForTestSync } from './tmp-dir.fixtures.ts';
99

1010
function writeSolidPng(filePath: string, width: number, height: number): void {
1111
const png = new PNG({ width, height });

src/daemon/screenshot-overlay.ts renamed to packages/capture-kit/src/screenshot-overlay.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import {
66
type SnapshotNode,
77
type SnapshotState,
88
} from '@agent-device/kernel/snapshot';
9-
import { decodePngAsync, encodePngAsync } from '@agent-device/capture-kit/png-worker-client';
9+
import { decodePngAsync, encodePngAsync } from './png-worker-client.ts';
1010
import {
1111
projectSnapshotRectToScreenshot,
1212
resolveSnapshotBounds,
13-
} from '@agent-device/capture-kit/snapshot-rect-projection';
14-
import { analyzeReactNativeOverlay } from '../core/react-native-overlay.ts';
13+
} from './snapshot-rect-projection.ts';
14+
import { analyzeReactNativeOverlay } from './react-native-overlay.ts';
1515
import {
1616
findNearestAncestor,
1717
isMeaningfulSignal,
@@ -21,14 +21,9 @@ import {
2121
import {
2222
isAndroidUnlabeledClickableSource,
2323
resolveAndroidOverlaySourceRect,
24-
} from '../snapshot/screenshot-overlay/android.ts';
24+
} from './screenshot-overlay-android.ts';
2525
import { drawOverlayRef } from './screenshot-overlay-draw.ts';
26-
import {
27-
clamp,
28-
hasPositiveRect,
29-
rectArea,
30-
rectContains,
31-
} from '../snapshot/screenshot-overlay/rects.ts';
26+
import { clamp, hasPositiveRect, rectArea, rectContains } from './screenshot-overlay-rects.ts';
3227

3328
const MAX_OVERLAY_REFS = 24;
3429
const ACTIONABLE_ROLE_TYPES = [
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {
2+
attachRefs,
3+
type RawSnapshotNode,
4+
type SnapshotState,
5+
type SnapshotStateProvenance,
6+
} from '@agent-device/kernel/snapshot';
7+
8+
export function makeSnapshotState(
9+
raw: RawSnapshotNode[],
10+
// The provenance pair stays correlated: overrides carry it as one value, never as two
11+
// independently typed fields.
12+
overrides?: Omit<Partial<SnapshotState>, 'backend' | 'producer'> & SnapshotStateProvenance,
13+
): SnapshotState {
14+
return {
15+
nodes: attachRefs(raw),
16+
createdAt: Date.now(),
17+
...overrides,
18+
};
19+
}

0 commit comments

Comments
 (0)