Skip to content

Commit 56039fe

Browse files
committed
refactor: split generic host mechanics into @agent-device/host-kit (#2082 W1)
The shared src/utils closure that blocked the platform-family moves lands on declared owners: generic host mechanics form a new private @agent-device/host-kit package between kernel and capture-kit, and capture-kit keeps capture, snapshot, and recording behavior, depending on host-kit for the mechanics it needs. tar-stream and yauzl move with the archive code. Every seam's exported subpaths are pinned in package-boundaries.test.ts, the layering model ranks the new zone, R13's allow-list names it, and each seam carries an exact eager-closure row. ADR-0019's substrate amendment describes the layout. Tests that mocked two of the moved modules separately became duplicate same-seam vi.mock factories, where the second silently replaced the first; those are merged, and the mocks that production code reaches past are pinned at their injection points instead. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH
1 parent 77b5be8 commit 56039fe

593 files changed

Lines changed: 1711 additions & 1080 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.fallowrc.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@
6565
"file": "src/platforms/android/perf.ts",
6666
"exports": ["sampleAndroidMemoryPerf"]
6767
},
68+
{
69+
"comment": "Apple perf sampling metadata is selected through the same lazy platform host; Fallow cannot follow the dynamic property read in src/platform-runtime-perf-host.ts.",
70+
"file": "src/platforms/apple/core/perf.ts",
71+
"exports": ["buildAppleFrameSamplingMetadata", "buildAppleMemorySamplingMetadata"]
72+
},
6873
{
6974
"comment": "Daemon route handlers are reached only through the dynamic `import()` table in request-handler-chain.ts, which --production analysis cannot follow to a consumer.",
7075
"file": "src/daemon/handlers/{lease,session,snapshot,react-native,record-trace,find,interaction}.ts",
@@ -212,6 +217,13 @@
212217
"rules": {
213218
"unused-types": "off"
214219
}
220+
},
221+
{
222+
"comment": "Host-kit seam façades: same false-positive shape as the contracts façades above — each seam names every type its re-exported functions put in a public signature, and callers use those types structurally without importing the name. unused-exports (the VALUE check) stays on.",
223+
"files": ["packages/host-kit/src/*.ts"],
224+
"rules": {
225+
"unused-types": "off"
226+
}
215227
}
216228
],
217229
"production": {

.oxlintrc.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,28 @@
3737
},
3838
"overrides": [
3939
{
40-
"files": ["src/**/*.ts"],
40+
"files": ["src/**/*.ts", "packages/capture-kit/src/**/*.ts"],
4141
"rules": {
4242
"eslint/no-restricted-imports": [
4343
"error",
4444
{
4545
"paths": [
4646
{
4747
"name": "node:child_process",
48-
"message": "Use process helpers from src/utils/exec.ts instead of importing node:child_process directly."
48+
"message": "Use process helpers from @agent-device/capture-kit/exec instead of importing node:child_process directly."
4949
}
5050
]
5151
}
5252
]
5353
}
5454
},
5555
{
56-
"files": ["src/utils/exec.ts", "src/**/*.test.ts", "src/**/__tests__/**/*.ts"],
56+
"files": [
57+
"packages/capture-kit/src/exec.ts",
58+
"packages/capture-kit/src/*.test.ts",
59+
"src/**/*.test.ts",
60+
"src/**/__tests__/**/*.ts"
61+
],
5762
"rules": {
5863
"eslint/no-restricted-imports": ["error", { "paths": [] }]
5964
}

AGENTS.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ Read the declaration rather than maintaining a prose copy:
6161
- common command input fields, and which surface may write an input key (model, operator, retired):
6262
`src/commands/common-input-fields.ts` and `src/commands/input-audience.ts`
6363

64-
Shared selector parsing and matching belongs in `@agent-device/selectors`; request cancellation and
65-
progress in `src/request`; cross-layer contracts in `src/contracts`; CLI flags in
66-
`src/commands/cli-grammar`; cross-surface schema composition in `src/cli-schema`.
64+
Shared selector parsing and matching belongs in `@agent-device/selectors`; request cancellation
65+
and progress in `@agent-device/capture-kit` (`request-cancel`, `request-progress`); cross-layer
66+
contracts in `src/contracts`; CLI flags in `src/commands/cli-grammar`; cross-surface schema
67+
composition in `src/cli-schema`.
6768

6869
The enforced registries are self-declaring. A failing completeness, parity, coverage, timeout,
6970
layering, or construction gate means the new cell or path is unclassified; do not suppress or
@@ -123,7 +124,7 @@ The OS-neutral Apple runner lives under `packages/platform-apple/src/runner/`. F
123124
retry policy, or command typing, start at `runner-contract.ts`; transport stays below session/client
124125
behavior, and xctestrun build/cache logic stays outside request execution.
125126

126-
Diagnostics use `src/utils/diagnostics.ts`. Request diagnostics belong in the session request log;
127+
Diagnostics use `@agent-device/capture-kit/diagnostics`. Request diagnostics belong in the session request log;
127128
session artifact paths come from `src/daemon/session-store.ts`. App/device logs remain in `app.log`;
128129
Apple runner and xcodebuild output remains in `runner.log`.
129130

apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTapPointPolicy.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import XCTest
1111
// This is pure geometry on purpose — no XCUIElement — so the exact decision
1212
// can be proven against the golden fixture table shared with the TS twin:
1313
// table: contracts/fixtures/tap-point-policy.json
14-
// TS twin: src/snapshot/mobile-snapshot-semantics.ts#isTapPointInsideViewport
14+
// TS twin: packages/contracts/src/mobile-snapshot-semantics.ts#isTapPointInsideViewport
1515
// TS test: src/snapshot/__tests__/tap-point-policy-parity.test.ts
1616
// Drift on either side turns CI red without needing a simulator.
1717
enum TapPointPolicy {

docs/adr/0019-request-bound-platform-runtime.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,34 @@ platform-common package, and it preserves the package façades' implementation-l
132132
Its introduction carries the normal workspace-package compliance surface: `check:affected`
133133
selection, R11/R13 package enumeration, and the composite typecheck project list.
134134

135+
> **Amendment (#2082): the substrate below the platform families.** Retiring the shared
136+
> `src/utils` and `src/platforms` root surfaces (so the family trees can move behind their
137+
> exports maps) forces every shared file onto a declared domain owner, and the paragraph above
138+
> is amended to name that layout rather than let capture-kit absorb it:
139+
>
140+
> - `@agent-device/host-kit` owns generic host mechanics — process execution, supervision, and
141+
> diagnostics; archives, streams, atomic files, locks, and path/device isolation; small host
142+
> value helpers; request-scoped plumbing — behind a small deep surface of exactly four seams:
143+
> `exec`, `fs`, `values`, `request`. Modules under `src/internal/` are reachable only through
144+
> those seams; consumers import a seam, never an internal module.
145+
> - `@agent-device/capture-kit` owns capture, snapshot, and recording behavior — PNG tooling,
146+
> screenshot density and pixel diffing, snapshot occlusion, mobile snapshot semantics,
147+
> quality verdicts and backend capability tables. Snapshot *behavior* is capture domain, not
148+
> contracts vocabulary, and host mechanics are host-kit's, not capture-kit's.
149+
> - `@agent-device/provision-kit` owns provisioning mechanics — install-artifact acquisition
150+
> (local paths, archives, guarded network downloads) and host toolchain probing.
151+
> - The enforced direction is `kernel < contracts < host-kit < capture-kit < provision-kit <
152+
> platform/provider/daemon`.
153+
> - Contracts stays vocabulary, plan models, and pure classification with no process,
154+
> filesystem, or timer mechanics (the existing planted-red gate); platform-specific parsing
155+
> stays with its family package and reaches legacy callers through composition, never by a
156+
> family importing another owner's internals.
157+
>
158+
> Enforcement: each substrate package's exported subpaths are pinned in
159+
> `package-boundaries.test.ts` (widening fails the gate), the contracts mechanics gate stays
160+
> planted red, and the `platforms-root-shape` rule rejects any new shared file or directory
161+
> appearing directly under `src/platforms`.
162+
135163
The Apple XCUITest runner client is a durable platform-owned implementation facet colocated
136164
inside `packages/platform-apple` as the `src/runner/` subtree (#2040) — Apple mechanics belong to
137165
the Apple package. R13 models the facet by enumeration rather than by exception sprawl: the family

docs/agents/testing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ whether tests distinguish changed decision logic. Do not infer redundancy from l
129129
Run `pnpm depgraph affected` before touching a high-fan-in module:
130130

131131
```sh
132-
pnpm depgraph affected src/utils/exec.ts
132+
pnpm depgraph affected packages/capture-kit/src/exec.ts
133133
pnpm depgraph affected src/daemon/ref-frame.ts --json --limit 25
134134
```
135135

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@
161161
"check:unit": "pnpm test:unit && pnpm check:tmpdir-leaks && pnpm test:smoke",
162162
"check": "pnpm check:tooling && pnpm check:fallow && pnpm check:unit",
163163
"prepack": "pnpm check:mcp-metadata && pnpm package:npm",
164-
"typecheck": "tsc -b packages/xml packages/kernel packages/contracts packages/capture-kit packages/platform-apple packages/platform-android packages/platform-harmonyos packages/platform-vega packages/platform-linux packages/platform-web packages/ad-script packages/selectors packages/ad-replay packages/maestro packages/replay-test packages/provider-webdriver packages/provider-limrun && tsc -p tsconfig.json && tsc -p examples/sdk/tsconfig.json",
164+
"typecheck": "tsc -b packages/xml packages/kernel packages/contracts packages/host-kit packages/capture-kit packages/platform-apple packages/platform-android packages/platform-harmonyos packages/platform-vega packages/platform-linux packages/platform-web packages/ad-script packages/selectors packages/ad-replay packages/maestro packages/replay-test packages/provider-webdriver packages/provider-limrun && tsc -p tsconfig.json && tsc -p examples/sdk/tsconfig.json",
165165
"test-app:install": "pnpm install --dir examples/test-app",
166166
"test-app:start": "pnpm --dir examples/test-app start",
167167
"test-app:ios": "pnpm --dir examples/test-app ios",
@@ -278,6 +278,7 @@
278278
"@agent-device/ad-script": "workspace:*",
279279
"@agent-device/capture-kit": "workspace:*",
280280
"@agent-device/contracts": "workspace:*",
281+
"@agent-device/host-kit": "workspace:*",
281282
"@agent-device/kernel": "workspace:*",
282283
"@agent-device/maestro": "workspace:*",
283284
"@agent-device/platform-android": "workspace:*",

packages/ad-replay/src/internal/canonical-json.ts

Lines changed: 0 additions & 14 deletions
This file was deleted.

packages/ad-replay/src/internal/plan-digest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createHash } from 'node:crypto';
22
import type { SessionAction } from '@agent-device/contracts/session';
3-
import { canonicalJson } from './canonical-json.ts';
3+
import { canonicalJson } from '@agent-device/kernel/collections';
44

55
/**
66
* ADR 0012 decision 4 / migration step 5: `planDigest` is SHA-256 over the

packages/capture-kit/package.json

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,64 @@
33
"version": "0.0.0",
44
"private": true,
55
"type": "module",
6-
"description": "Private durable-capture mechanics shared by platform runtimes, providers, and daemon orchestration.",
6+
"description": "Private host and durable-capture mechanics shared by platform runtimes, providers, and daemon orchestration: process execution, diagnostics, archives, PNG tooling, and request-scoped plumbing.",
77
"dependencies": {
88
"@agent-device/contracts": "workspace:*",
9+
"@agent-device/host-kit": "workspace:*",
910
"@agent-device/kernel": "workspace:*"
1011
},
1112
"exports": {
1213
".": {
1314
"types": "./src/index.ts",
1415
"default": "./src/index.ts"
16+
},
17+
"./mobile-snapshot-semantics": {
18+
"types": "./src/mobile-snapshot-semantics.ts",
19+
"default": "./src/mobile-snapshot-semantics.ts"
20+
},
21+
"./png": {
22+
"types": "./src/png.ts",
23+
"default": "./src/png.ts"
24+
},
25+
"./png-resize": {
26+
"types": "./src/png-resize.ts",
27+
"default": "./src/png-resize.ts"
28+
},
29+
"./png-rgb-difference": {
30+
"types": "./src/png-rgb-difference.ts",
31+
"default": "./src/png-rgb-difference.ts"
32+
},
33+
"./png-size": {
34+
"types": "./src/png-size.ts",
35+
"default": "./src/png-size.ts"
36+
},
37+
"./png-worker-client": {
38+
"types": "./src/png-worker-client.ts",
39+
"default": "./src/png-worker-client.ts"
40+
},
41+
"./screenshot-density": {
42+
"types": "./src/screenshot-density.ts",
43+
"default": "./src/screenshot-density.ts"
44+
},
45+
"./screenshot-diff-pixels": {
46+
"types": "./src/screenshot-diff-pixels.ts",
47+
"default": "./src/screenshot-diff-pixels.ts"
48+
},
49+
"./snapshot-occlusion": {
50+
"types": "./src/snapshot-occlusion.ts",
51+
"default": "./src/snapshot-occlusion.ts"
52+
},
53+
"./snapshot-quality-backend-capabilities": {
54+
"types": "./src/snapshot-quality-backend-capabilities.ts",
55+
"default": "./src/snapshot-quality-backend-capabilities.ts"
56+
},
57+
"./snapshot-quality-verdict": {
58+
"types": "./src/snapshot-quality-verdict.ts",
59+
"default": "./src/snapshot-quality-verdict.ts"
1560
}
61+
},
62+
"devDependencies": {
63+
"@types/pngjs": "^6.0.5",
64+
"pngjs": "^7.0.0"
1665
}
1766
}

0 commit comments

Comments
 (0)