diff --git a/AGENTS.md b/AGENTS.md index 389a4c8ef4..2281354b16 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -56,9 +56,8 @@ Read the declaration rather than maintaining a prose copy: `src/commands/common-input-fields.ts` and `src/commands/input-audience.ts` Shared selector parsing and matching belongs in `@agent-device/selectors`; request cancellation -and progress in `@agent-device/capture-kit` (`request-cancel`, `request-progress`); cross-layer -contracts in `@agent-device/contracts`; CLI flags in `src/commands/cli-grammar`; cross-surface schema -composition in `src/cli-schema`. +and progress in `@agent-device/host-kit/request`; cross-layer contracts in `packages/contracts/src`; +CLI flags in `src/commands/cli-grammar`; cross-surface schema composition in `src/cli-schema`. Resolve registry completeness failures at the missing declaration. Diagnose other gate failures at their reported invariant; do not suppress them or add an allowlist to get a pass. Build interaction @@ -87,8 +86,6 @@ under `contracts/fixtures/`. - Tests mirror source topology one-to-one. Split a source module and its test together; do not add to the legacy `interaction.test.ts` or platform `index.test.ts` aggregations. Pure moves carry their tests unchanged; rename-only hunks owe no new coverage. -- `src/daemon/handlers/session.ts` is already over budget; extract the relevant platform-specific - concept before adding behavior. ## Toolchain and worktree traps @@ -104,7 +101,7 @@ under `contracts/fixtures/`. ## Runtime and diagnostics seams -Diagnostics use `@agent-device/capture-kit/diagnostics`. Request diagnostics belong in the session request log; +Diagnostics use `@agent-device/host-kit/diagnostics`. Request diagnostics belong in the session request log; session artifact paths come from `src/daemon/session-artifact-paths.ts`. App/device logs remain in `app.log`; Apple runner and xcodebuild output remains in `runner.log`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4470cac89b..97388c218f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,8 @@ reviewable change. Detailed testing and device procedures live in the linked foc Requirements: -- Node.js 22 or newer +- Node.js 22.13 or newer — the pinned pnpm requires it. The published package keeps a lower + `engines.node` floor of 22.12, which CI verifies separately on the installed tarball. - pnpm at the version pinned in `package.json` - Android SDK tools (`adb`) for Android work - Xcode (`simctl`/`devicectl`) for Apple-platform work diff --git a/docs/adr/0019-request-bound-platform-runtime.md b/docs/adr/0019-request-bound-platform-runtime.md index b205648a4a..3d7ff8298d 100644 --- a/docs/adr/0019-request-bound-platform-runtime.md +++ b/docs/adr/0019-request-bound-platform-runtime.md @@ -877,7 +877,7 @@ there, not about retiring the directory. **Entry-to-platform hop count.** Corrected 2026-09-03, re-measured for #2278 at `27a97ee619`: the counting definition, ordered chains, hop roles, and commit for this measurement are in -[`0019-end-state-hop-trace.md`](./0019-end-state-hop-trace.md), which supersedes the numbers +[`0023-end-state-hop-trace.md`](./0023-end-state-hop-trace.md), which supersedes the numbers below. A file-by-file re-trace at HEAD measured 41 hops for `press`/Android and 47/49 hops (shared 30 plus 17/19 per arm) for `snapshot`/iOS, which is now a dual-arm route (in-simulator AX bridge primary, XCTest runner fallback). The previously stated 38/29 named no ordered chain, diff --git a/docs/adr/0022-daemon-platform-runtime-coupling.md b/docs/adr/0022-daemon-platform-runtime-coupling.md index 6fff12e779..fad980cd10 100644 --- a/docs/adr/0022-daemon-platform-runtime-coupling.md +++ b/docs/adr/0022-daemon-platform-runtime-coupling.md @@ -79,7 +79,7 @@ or owning issue. #2278 audited all four concerns at `27a97ee619`. 4. **The entry-to-platform hop trace was re-run with hop roles** (policy / orchestration / translation / adapter / pass-through + terminal) and a deletion test per pass-through/translation hop. The updated artifact is - [`0019-end-state-hop-trace.md`](0019-end-state-hop-trace.md): 41 hops for `press`/Android and + [`0023-end-state-hop-trace.md`](0023-end-state-hop-trace.md): 41 hops for `press`/Android and 47/49 per arm for the now dual-arm `snapshot`/iOS route (shared 30 + AX bridge 17 / runner fallback 19). The deletion test proves a single distinct removable hop (`commands/runtime-types.ts`); the request-spine guards (auth comparison, cancellation gate, diff --git a/docs/adr/0019-end-state-hop-trace.md b/docs/adr/0023-end-state-hop-trace.md similarity index 99% rename from docs/adr/0019-end-state-hop-trace.md rename to docs/adr/0023-end-state-hop-trace.md index 98d604b293..4af004ea9a 100644 --- a/docs/adr/0019-end-state-hop-trace.md +++ b/docs/adr/0023-end-state-hop-trace.md @@ -1,4 +1,4 @@ -# ADR-0019 end-state: entry-to-platform hop trace +# ADR-0023: end-state entry-to-platform hop trace Backs the "Entry-to-platform hop count" paragraph in [0019-request-bound-platform-runtime.md](./0019-request-bound-platform-runtime.md#end-state-proposed-2026-09-02-maintainer-decision-pending). diff --git a/docs/adr/README.md b/docs/adr/README.md index 3b078f9af1..c0b33c0347 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -24,6 +24,7 @@ | [0020 Composable Recorded Fragments (Proposed)](0020-composable-recorded-fragments.md) | lifecycle-free recorded fragment capture/composition, entry guards, fragment-local addresses/digests, staleness, and native `.ad`/Maestro composition | | [0021 Host — Simlock-Backed Managed Device Allocation and the Host Supervisor](0021-host-simlock-managed-device-allocation.md) | local-first Simlock-managed execution, Host identity/admin boundaries, shape allocation, durable managed-device lease mapping, lifecycle ownership, and supervised maintenance | | [0022 Daemon — Platform Runtime Coupling Audit and Ownership Ratchets](0022-daemon-platform-runtime-coupling.md) | daemon imports of root `platform-runtime-*` modules, the R76 edge classification inventory, R75 session-authority ratchet, entry-to-platform hop routes and roles | +| [0023 End-State Entry-to-Platform Hop Trace](0023-end-state-hop-trace.md) | the hop counting definition, the ordered `press`/Android and dual-arm `snapshot`/iOS chains, per-hop roles, and the deletion test behind the numbers ADR 0019 and ADR 0022 quote | ADRs record *why*; the registries and gates they describe are the living source of truth — when prose and a registry disagree, the registry wins and the ADR needs a follow-up. diff --git a/scripts/__tests__/agent-guidance-contract.test.ts b/scripts/__tests__/agent-guidance-contract.test.ts index 61515b9f8b..9118ea6d1b 100644 --- a/scripts/__tests__/agent-guidance-contract.test.ts +++ b/scripts/__tests__/agent-guidance-contract.test.ts @@ -12,6 +12,11 @@ const BYTE_BUDGETS = { const FOCUSED_DOC_BUDGET = 10_000; const AGENT_DOCS_TOTAL_BUDGET = 40_000; +type PackageManifest = { + name: string; + exports?: Record; +}; + async function read(relativePath: string): Promise { return readFile(path.join(ROOT, relativePath), 'utf8'); } @@ -56,6 +61,46 @@ test('CONTEXT.md remains a glossary rather than an architecture or workflow docu assert.doesNotMatch(content, /(?:^|\s)(?:docs|packages|scripts|src|test)\//); }); +test('AGENTS.md routes each shared primitive to a package that publishes it', async () => { + const content = await read('AGENTS.md'); + const specifiers = [ + ...new Set( + [...content.matchAll(/@agent-device\/[a-z0-9-]+(?:\/[a-z0-9-]+)*/g)].map((match) => match[0]), + ), + ]; + assert.ok(specifiers.length > 0, 'AGENTS.md must route shared primitives by workspace specifier'); + + const published = new Map>(); + for (const directory of await readdir(path.join(ROOT, 'packages'))) { + const manifest = JSON.parse( + await read(path.join('packages', directory, 'package.json')), + ) as PackageManifest; + published.set(manifest.name, new Set(Object.keys(manifest.exports ?? {}))); + } + + for (const specifier of specifiers) { + const [scope = '', name = '', ...segments] = specifier.split('/'); + const packageName = `${scope}/${name}`; + const subpaths = published.get(packageName); + assert.ok( + subpaths, + `${specifier}: AGENTS.md names a workspace package that packages/ does not publish`, + ); + if (segments.length === 0) { + assert.ok( + subpaths.has('.'), + `${specifier}: AGENTS.md imports a package root ${packageName} does not export`, + ); + continue; + } + const subpath = `./${segments.join('/')}`; + assert.ok( + subpaths.has(subpath), + `${specifier}: AGENTS.md names a subpath ${packageName} does not export`, + ); + } +}); + test('the AGENTS.md task router points only at files that exist', async () => { const content = await read('AGENTS.md'); const table = content.match(/\| When the task involves \| Read \|([\s\S]*?)\n\n/)?.[1]; diff --git a/website/docs/docs/installation.md b/website/docs/docs/installation.md index 1553277d8c..a3e08f66da 100644 --- a/website/docs/docs/installation.md +++ b/website/docs/docs/installation.md @@ -65,7 +65,10 @@ One-off `npx` usage is fine for humans and scripts that intentionally fetch from ## Requirements -- Node.js 22+ +- Node.js 22.12 or newer +- Node.js 24 or newer for web automation, which hard-fails below it. The rest of the CLI keeps the + 22.12 floor, so check `node --version` in the shell that runs `agent-device web setup` and + `agent-device doctor` before trusting a web result. - Xcode for iOS simulator/device automation (`simctl` + `devicectl`) - Android SDK / ADB for Android - HarmonyOS Command Line Tools for HarmonyOS (`hdc` available through `HDC_SDK_PATH`, `DEVECO_SDK_HOME`, or `HARMONYOS_COMMAND_LINE_TOOLS`)