mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
main
8 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
22a46d12d2 |
refactor(move): move the remaining package-ready modules out of src/core (#2401)
* refactor(move): move remaining package-ready modules out of src/core - validation.ts -> @agent-device/kernel/validation - android-system-surface-disclosure.ts -> @agent-device/contracts/android-system-surface-disclosure - project-runtime.ts -> @agent-device/host-kit/project-runtime - runtime-transport-hints(.test).ts -> @agent-device/host-kit/runtime-transport-hints - app-events.ts (+tests) -> src/daemon/app-events.ts - dispatch-payload.ts (+test), payload-input.ts -> src/daemon/ - fill-backend-result.ts (+test) -> src/daemon/ interaction-outcome.ts stays in core: it correlates ResolvedInteractionTarget with error objects across the commands(rank3)/daemon(rank4) boundary, and contracts explicitly refuses mutable interaction-outcome lifecycle (R18). * chore(gates): pin the exports and boundary snapshots for the moved core modules |
||
|
|
d26b0786fb |
perf(ios): derive runner demand for Simulator opens and stop observation from awaiting the runner (#2329)
* perf(ios): derive runner demand for Simulator opens and stop observation from awaiting the runner Local Simulator opens now decide how much the XCTest runner is needed from the runtime operations declared by the steps still ahead in the same batch: an observation-only plan starts no runner, an unknown plan keeps the speculative prewarm without ever awaiting it, and a plan with an interaction prepares readiness for that step. open --relaunch no longer waits for runner readiness on a Simulator and resets the runner target only when a session is already alive. The Apple find ports report not-proven instead of starting a runner on a Simulator without a live session, so wait and read-only find observe through the canonical AX-bridge tree. Physical devices keep their lifecycle unchanged. The plan travels through the server-private internal request channel, never the wire; the Apple owner maps declared operations to a runner demand through a record complete over the runtime operation union. Refs #2198 * test(fixtures): share one inert audio-probe host across the platform runtime fixtures The Apple and Android runtime fixtures carried identical audio-probe doubles; host-kit now owns the one copy and both fixtures import it. Also folds the two Apple native-find ports onto one admission helper and lifts the Simulator runner prewarm policy out of the open sequence, keeping both under the complexity gate. * fix(ios): answer runner liveness through the runner provider seam The find ports and the relaunch target reset asked the local session registry whether a runner was alive, which misreads scripted and request-scoped runner providers as absent. Liveness is now a provider question: the local provider consults its session registry, a provider without startup cost counts as live, and an awaited prewarm proves liveness without asking. * perf(ios): select plan uses from step input and give young Simulator targets a bounded bridge grace A snapshot, diff, or find step now selects the runtime uses its structured input reaches, the way its handler does, so a plain snapshot no longer counts the custom-actions alternative and an observation-only batch resolves runner demand none. The descriptor declares the selector next to its alternatives; the daemon plan derivation honors it and keeps the union for every other command. Without the runner wait, the first snapshot after an open reached the AX bridge while the app was still becoming the primary foreground owner or registering its accessibility server, and the typed fallback then started the runner the plan had just avoided. A target younger than ten seconds is re-read for a bounded grace measured from the first such failure: five seconds for a missing AX server, one second for an ownership miss so a launch-time system dialog still reaches the fallback quickly. Established targets get no grace. * fix(ios): a registered runner session counts as live only once it has answered A session record exists while xcodebuild is still connecting, so an alive child pid is not a runner that can answer. Treating it as live sent the relaunch target reset into a starting runner, queued behind its connection retries, and the failed reset invalidated the very session the prewarm was building. Liveness now also requires the session's readiness flag, which the first successful runner response sets. * refactor(ios): lift the bridge launch grace out of the snapshot route capture * test(descriptors): pin the snapshot, diff, and find step-use selectors * test: stub runner operations in the replay test-runner suite and keep runner-session tests within the size ratchet A Simulator open schedules a best-effort runner prewarm that outlives its request. The replay test-runner suite opened a Simulator with the real Apple tools, so the prewarm's deferred import resolved after the file finished and spawned into whichever file the worker ran next, where the hermetic signal guard failed an unrelated test. * fix(plan): count only required operations and read find and snapshot steps the way their handlers do Runner demand now counts a command's required operations only: a preferred or conditional operation is a measured fast path the command succeeds without, so get, wait, and read-only find stay observation-only. The step selectors for snapshot, diff, and find live next to the registry and read the daemon step exactly as the handlers do: the daemon flag for custom actions, and find's positionals through the same parser, where a missing action is a click and an unparseable step keeps every declared alternative. The handler and the selector share one action-to-intent map. The batch runner hands each step its remaining steps in handler shape, and the derived operations reach the platform as a typed list on the lifecycle execution instead of an untyped plan on every open. * perf(ios): let open wait for the launched app to become observable, and make runner liveness explicit The snapshot route no longer infers a launch from process start text and retries inside its own capture. Open owns launch timing instead: a local Simulator open asks the AX bridge whether the launched app is observable, bounded by per-code windows measured from the first typed launch-transition failure and never extended, so an ownership miss seen after an AX-server miss shrinks the deadline to the ownership window and a launch-time system dialog still reaches the typed fallback quickly. Any other device, or a bridge that cannot answer, keeps the fixed settle. The open response reports what it learned. Every runner provider now states whether it can answer without a startup wait; a bare executor answers directly by construction and scripted providers say so. The runner prewarm policy and the observation settle move out of the open sequence into their own module, and the native find admission is named for what it admits. * docs(context): keep the runner-demand vocabulary within the guidance budget The enumeration and the no-public-flag rule live on the contract type that owns them; CONTEXT.md keeps the term itself, and two neighbouring entries lose words that carried no meaning. * refactor(contracts): name the runtime operation vocabulary below the operations union The lifecycle execution carries the operations a plan requires, but typing that list with the operations union closed a 36-file type cycle: the operations types depend on the lifecycle types. The vocabulary now lives as a const list below both, proven equal to the union by a type test, so the plan is typed end to end, the Apple host table indexes it without casts, and the daemon narrows descriptor names through a guard instead of a cast. * fix(apple): reach runner liveness through the memoized operations loader Every Apple tool port loads the runner operations through the one memoized loader (#2314): a port that opens its own dynamic import can resolve the unmocked module while a test's mock factory is still loading and let a real local runner escape. The liveness port now uses the loader like its siblings; the facade members consumed only through the loader are declared to fallow, and the plan resolver reads one step per helper to stay under the complexity threshold. * fix(ios): keep bridge-only behavior to iOS Simulators The launch observation, the runner-free find admission, and the relaunch policy apply only where the host AX bridge exists: iOS Simulators. A tvOS Simulator keeps its awaited prewarm and asks for no observation, which the tvOS provider scenario now pins. * bench(ios): add a first-interaction cell to the snapshot convergence harness An open that defers runner readiness moves its cost to the first runner-dependent command. The cell starts each sample like cold, opens the fixture untimed, then times the first press that follows (the deep-link confirmation when the launch URL raises it, otherwise the screen anchor). * bench(ios): read the deep-link confirmation from a snapshot and by node type The open response carries no tree and regular snapshots publish the node type, so the confirmation iOS raises for a launch URL was never seen on this runtime and every deep-linked cell failed its anchor check. * refactor(plan): keep the step-use selectors inside the registry The eager-closure ratchet counts every module the registry loads; the selectors need nothing the registry does not already import, so they live beside find's recording-effect reader instead of adding a module to every entry that loads the registry. * feat(apple): release a speculative runner when the plan is proven observation-only #2198 requires a `none` runner demand to retain no runner, not only to start none. A runner a prewarm started that no command has used yet is speculative: the session records that mark at creation, the first command that is not a readiness probe clears it, and a Simulator open whose plan is proven observation-only asks the runner owner to release a speculative session in the background, so the observation path never waits for a runner to stop either. A runner that has served a command is the session's working runner and stays under the existing idle-stop policy, so a mixed workload does not pay a cold runner start at every observation-only open. The release goes through the runner provider seam: the local provider stops its own speculative session; a provider that never starts speculative work omits the operation and releases nothing. * bench(ios): press an unambiguous target on the catalog and Settings screens The first-interaction cell pressed the screen's anchor text, which on the catalog and iOS Settings screens names two actionable elements (the native tab and the screen title); the CLI refuses that as AMBIGUOUS_MATCH by design, so those two cells could never measure anything. Each such screen now names the element the cell presses. * fix(ios): keep observation on the bridge while app discovery is pending and no runner is live #2331 bounds one capture's wait for the Simulator app discovery and takes the XCTest fallback past it; #2198 stops a Simulator open from awaiting the runner. Together, a `wait` right after a relaunch on a loaded host fell back to XCTest while the runner was still starting, spent its poll budget on that start, and timed out (the iOS smoke lane after the main merge). A capture with no live runner now stays on the single-flight discovery, one wait slice at a time, until the discovery's own deadline or the request signal ends it; a runner that is already live still takes the fallback at once, the cheaper route #2331 chose. * fix(apple): queue a speculative-runner release behind a start that is still in flight A `possible` open's prewarm registers its session only when the start completes, so a `none` open that released in that window found nothing and the runner it meant to release survived as a retained speculative session. The release now takes the runner session lock: it queues behind the in-flight start, sees the registered speculative session, and stops it; a start a command asked for is left alone. Two deferred-start regressions pin both outcomes. |
||
|
|
b4ebd778cc |
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 <noreply@anthropic.com> 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 <noreply@anthropic.com> 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 <noreply@anthropic.com> 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 <noreply@anthropic.com> 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 <noreply@anthropic.com> 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 <noreply@anthropic.com> 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 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BPFjVXwbDrXPqp5W6K2iDK --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
7a2d48d160 |
perf: bundle runtime dependencies and report full install size (#2310)
* perf: bundle runtime dependencies and report full install size * refactor: remove unused size report breakdowns |
||
|
|
a90d95aab7 |
perf: bundle tar-stream to reduce install footprint (#2286)
* perf: bundle tar-stream to reduce install footprint * fix: align bundled archive dependencies and simplify config |
||
|
|
110c08c947 | refactor(transport): move shared host mechanics (#2221) | ||
|
|
838ed223b5 |
refactor: move W6 platform families behind package facades (#2116)
* refactor: move W6 platform families behind package facades * fix: address W6 loading and composition review |
||
|
|
e832325e87 |
refactor(substrate): split host mechanics into @agent-device/host-kit capability ports (#2088)
* 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 * refactor(host-kit): one narrow capability port per export The four technical barrels (exec/fs/values/request) grouped by category rather than by capability, so a consumer needing one mechanic evaluated unrelated ones. Each export is now a single capability over the host machine: command, process, diagnostics, retry, archive, file, request, version. A port re-exports only what a consumer of that capability uses, and every port carries its own eager-closure row. Most of the old values barrel was never host mechanics. Pure record readers, config-source values, result text, memoization, async scoping, coordinate validation, and device-scope parsing touch no process, file, or environment, so they join kernel's other primitives instead. Closures fall accordingly: capture-kit's png-worker-client from 20 to 10, png-resize from 28 to 18, session-teardown from 79 to 68, and the CLI from 386 to 380. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH * chore: drop the migration inventories and trim the touched comments Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH * docs: trim the touched host-kit and mutation-lane comments Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH * docs: keep tool directives only in the touched files Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH * docs: keep tool directives only across the touched tree Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH * fix: point the Swift parity comment at the real TS twin and test The W1 move rewrote this citation to packages/contracts/src/mobile-snapshot-semantics.ts, which does not exist: the module went to capture-kit while isTapPointInsideViewport itself went to packages/contracts/src/snapshot-visibility.ts. The TS test line was left pointing at the pre-move path. Both now resolve. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH * fix: repoint comment citations at the homes this refactor moved them to The W1 move left ~20 comment citations pointing at src/utils/*.ts and src/request/*.ts paths that no longer exist. Each now names the capability port that owns the symbol, which survives further file moves: exec -> host-kit/command host-process, owner-identity -> host-kit/process diagnostics -> host-kit/diagnostics atomic-file, process-lock -> host-kit/file retry -> host-kit/retry request progress/cancel -> host-kit/request version -> host-kit/version ttl-memo, source-value, parsing, device-isolation, keyed-lock, success-text -> kernel subpaths Comment-only; no closure, budget, or behavior change. ADR citations are left as written, being dated records of the decision rather than live references. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018VngeKZH6zBuJzNBk5YzUH --------- Co-authored-by: Claude <noreply@anthropic.com> |