mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
d26b0786fb
* 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.
561 lines
30 KiB
JSON
561 lines
30 KiB
JSON
{
|
|
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
|
|
"entry": [
|
|
"tsdown.config.ts",
|
|
"vitest.mutation.config.ts",
|
|
"src/sdk/index.ts",
|
|
"src/sdk/io.ts",
|
|
"src/sdk/artifacts.ts",
|
|
"src/sdk/metro.ts",
|
|
"src/sdk/remote-config.ts",
|
|
"src/sdk/install-source.ts",
|
|
"src/sdk/android-adb.ts",
|
|
"src/sdk/contracts.ts",
|
|
"src/sdk/selectors.ts",
|
|
"src/sdk/finders.ts",
|
|
"src/ai-sdk/index.ts",
|
|
"src/bin.ts",
|
|
"src/client/companion-tunnel.ts",
|
|
"src/daemon.ts",
|
|
"packages/capture-kit/src/png-worker.ts",
|
|
"scripts/patch-xcuitest-runner-icon.ts",
|
|
"scripts/runner-request-count/run.ts",
|
|
"packages/capture-kit/src/ios-snapshot-engine/replay.ts",
|
|
// #1596 regression fixture: runs as a real `node --experimental-strip-types`
|
|
// subprocess (test/integration/daemon-replace-exit-flush.test.ts), so
|
|
// dependency analysis cannot follow the runCmdSync string path to it.
|
|
"test/integration/support/exit-after-flush.ts",
|
|
"src/cli/update-check-entry.ts",
|
|
"examples/sdk/client-session.ts",
|
|
"examples/sdk/metro-runtime.ts",
|
|
"examples/sdk/contracts-result.ts",
|
|
"examples/sdk/batch-orchestration.ts",
|
|
"examples/sdk/ai-sdk-tools.ts",
|
|
"test/scripts/metro-prepare-packaged-smoke.mjs",
|
|
"test/integration/*.test.ts",
|
|
"website/docs/404.mdx",
|
|
"website/rspress.config.ts"
|
|
],
|
|
"ignorePatterns": [
|
|
"examples/test-app/**",
|
|
"scripts/perf/**",
|
|
"scripts/layering/**",
|
|
"scripts/di-seams/**",
|
|
"scripts/maestro-conformance/corpus/**",
|
|
"apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests.xctestplan",
|
|
"scripts/write-xcuitest-cache-metadata.mjs",
|
|
"scripts/help-conformance-sample-outputs.d.mts",
|
|
"scripts/help-conformance-runner-output.d.mts"
|
|
],
|
|
"dynamicallyLoaded": ["src/daemon/interaction/index.ts"],
|
|
"ignoreDependencies": [
|
|
"@theme",
|
|
// @agent-device/maestro owns the source import, while the published root
|
|
// build externalizes yaml and retains runtime imports in packed chunks.
|
|
"yaml",
|
|
// @agent-device/provider-limrun owns the source import, while the published
|
|
// root build externalizes @limrun/api and retains runtime imports in packed chunks.
|
|
"@limrun/api",
|
|
// Oxlint resolves the shared config's JS plugins dynamically from their package names.
|
|
"@nkzw/eslint-plugin",
|
|
"eslint-plugin-no-only-tests",
|
|
"eslint-plugin-perfectionist",
|
|
// Packaging linters with no importable API surface here: scripts/check-package.ts runs their
|
|
// `node_modules/.bin` shims as subprocesses, which dependency analysis cannot follow to an import.
|
|
"publint",
|
|
"@arethetypeswrong/cli"
|
|
],
|
|
"ignoreExports": [
|
|
{
|
|
"comment": "Android perf mechanics are selected through the lazy platform host so importing agent-device does not eagerly load adb mechanics. Fallow cannot follow the dynamic property read in src/platform-runtime-perf-host.ts.",
|
|
"file": "packages/platform-android/src/perf.ts",
|
|
"exports": ["sampleAndroidMemoryPerf"]
|
|
},
|
|
{
|
|
"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.",
|
|
"file": "packages/platform-apple/src/core/perf.ts",
|
|
"exports": ["buildAppleFrameSamplingMetadata", "buildAppleMemorySamplingMetadata"]
|
|
},
|
|
{
|
|
"comment": "These host-process helpers are consumed only by integration leak-oracle support and host-process unit tests; Fallow's production graph intentionally excludes both consumers.",
|
|
"file": "packages/host-kit/src/process.ts",
|
|
"exports": ["uniquePositivePids", "readOwnedProcessRecordFile"]
|
|
},
|
|
{
|
|
"comment": "Apple app-resolution helpers are reached through the named lazy façade in packages/platform-apple/src/app-resolution-facade.ts. Fallow cannot connect dynamic import member reads to these source exports; keep this list limited to the facade's re-exports.",
|
|
"file": "packages/platform-apple/src/core/app-resolution.ts",
|
|
"exports": ["buildAppNotInstalledError", "resolveIosAppAlias"]
|
|
},
|
|
{
|
|
"comment": "The app-resolution package facade is consumed through workspace package exports. Fallow does not follow that package boundary, so keep only its externally consumed helper that has no visible production edge here.",
|
|
"file": "packages/platform-apple/src/app-resolution-facade.ts",
|
|
"exports": ["buildAppNotInstalledError"]
|
|
},
|
|
{
|
|
"comment": "Runner operations reach the daemon only through the memoized loader in src/platform-runtime-apple-application-tools.ts (one dynamic import per specifier, #2314). Fallow cannot connect a member read off that loader's promise to these re-exports; keep the list to the facade members no static import consumes.",
|
|
"file": "packages/platform-apple/src/runner-operations-facade.ts",
|
|
"exports": [
|
|
"detachIosSimulatorRunnerSessionsForShutdown",
|
|
"hasLiveIosRunnerSession",
|
|
"releaseSpeculativeIosRunnerSessionFor",
|
|
"stopAllIosRunnerSessions"
|
|
]
|
|
},
|
|
{
|
|
"comment": "Apple install mechanics are reached through the named install-artifact façade. Fallow cannot connect workspace package exports to these source exports; keep this list limited to the actual facade re-exports.",
|
|
"file": "packages/platform-apple/src/core/install-artifact.ts",
|
|
"exports": ["prepareIosInstallArtifact", "readIosBundleInfo"]
|
|
},
|
|
{
|
|
"comment": "Apple perf mechanics are reached through the named lazy perf façade. Fallow cannot connect dynamic import member reads to these source exports; keep this list limited to the facade's re-exports.",
|
|
"file": "packages/platform-apple/src/perf-facade.ts",
|
|
"exports": [
|
|
"buildAppleFrameSamplingMetadata",
|
|
"buildAppleMemorySamplingMetadata",
|
|
"buildAppleMemorySnapshotSupport",
|
|
"isRetryableIosDeviceTraceRecordFailure",
|
|
"resolveIosDevicePerfHint",
|
|
"captureAppleMemorySnapshot",
|
|
"readAppleProcessSamples",
|
|
"resolveAppleExecutable",
|
|
"resolveIosDevicePerfTarget",
|
|
"sampleAppleFramePerf",
|
|
"sampleAppleMemoryPerf",
|
|
"cleanupAppleXctracePerfCapture",
|
|
"startAppleXctracePerfCapture",
|
|
"stopAppleXctracePerfCapture",
|
|
"writeAppleXctracePerfReport",
|
|
"AppleXctraceCpuProfileReport",
|
|
"AppleXctracePerfMode",
|
|
"AppleXctracePerfResult"
|
|
]
|
|
},
|
|
{
|
|
"comment": "Apple tool-provider mechanics are reached through the named lazy tool-provider façade. Fallow cannot connect dynamic import member reads to these source exports; keep this list limited to the facade's re-exports.",
|
|
"file": "packages/platform-apple/src/tool-provider-facade.ts",
|
|
"exports": [
|
|
"hasScopedAppleToolProvider",
|
|
"resolveAppleToolProvider",
|
|
"createLocalAppleToolProvider",
|
|
"readApplePlistJson",
|
|
"runAppleToolCommand",
|
|
"runXcrun"
|
|
]
|
|
},
|
|
{
|
|
"comment": "The device-aware simctl argument builder is reached through the named lazy simctl façade. Fallow cannot connect the dynamic member read to this source export; keep the suppression limited to that re-export.",
|
|
"file": "packages/platform-apple/src/core/simctl.ts",
|
|
"exports": ["buildSimctlArgsForDevice"]
|
|
},
|
|
{
|
|
"comment": "The device-aware simctl argument builder is a named package entrypoint reached through dynamic platform-runtime imports. Fallow cannot connect those member reads to the re-export; keep the suppression limited to this one facade symbol.",
|
|
"file": "packages/platform-apple/src/simctl-facade.ts",
|
|
"exports": ["buildSimctlArgsForDevice"]
|
|
},
|
|
{
|
|
"comment": "Apple runner mechanics are reached through the named runner operations façade. Fallow cannot connect workspace package exports to these source exports; keep this list limited to the façade and its cleanup composition.",
|
|
"file": "packages/platform-apple/src/core/runner-client.ts",
|
|
"exports": [
|
|
"notifyIosRunnerAppRelaunched",
|
|
"prewarmIosRunnerSession",
|
|
"prepareIosRunner",
|
|
"resolveRunnerAppBundleId",
|
|
"detachIosSimulatorRunnerSessionsForShutdown",
|
|
"getRunnerSessionSnapshot",
|
|
"scheduleIosRunnerIdleStop",
|
|
"stopIosRunnerSession",
|
|
"stopAllIosRunnerSessions",
|
|
"readStaleRunnerLease",
|
|
"verifyLeaseRunnerPidIdentity",
|
|
"applyXctestRunnerAppIconFromDerivedPath"
|
|
]
|
|
},
|
|
{
|
|
"comment": "The named runner-owner façade owns this mutator; Fallow cannot connect the workspace package export to the moved source export.",
|
|
"file": "packages/platform-apple/src/core/runner-owner-state.ts",
|
|
"exports": ["setRunnerLeaseOwnerStateDir"]
|
|
},
|
|
{
|
|
"comment": "Apple diagnostics are reached through the named doctor façade. Fallow cannot connect workspace package exports to these source exports.",
|
|
"file": "packages/platform-apple/src/doctor.ts",
|
|
"exports": ["appleToolchainCheck", "appleRunnerWarmupCheck"]
|
|
},
|
|
{
|
|
"comment": "macOS helper mechanics are reached through the named macOS façade. Fallow cannot connect workspace package exports to these source exports.",
|
|
"file": "packages/platform-apple/src/os/macos/helper.ts",
|
|
"exports": ["startMacOsAudioProbeProcess", "resolveFrontmostMacOsApp"]
|
|
},
|
|
{
|
|
"comment": "The legacy Maestro fallback wording remains contracts vocabulary for wire/fixture compatibility, but has no in-repo production consumer. The Apple migration changes this file's documentation path, so keep the existing declaration explicit without treating it as a new W4 export leak.",
|
|
"file": "packages/contracts/src/interactor-types.ts",
|
|
"exports": ["MAESTRO_NON_HITTABLE_FALLBACK_MESSAGE"]
|
|
},
|
|
{
|
|
"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.",
|
|
"file": "src/daemon/handlers/{human-control,lease,session,snapshot,react-native,record-trace}.ts",
|
|
"exports": [
|
|
"handleHumanControlCommand",
|
|
"handleLeaseCommands",
|
|
"handleSessionCommands",
|
|
"handleSnapshotCommands",
|
|
"handleReactNativeCommands",
|
|
"handleRecordTraceCommands"
|
|
]
|
|
},
|
|
{
|
|
"comment": "The interaction facade exposes #2178's named route inputs and deferred handlers, plus the existing ref mutation response consumed by help conformance. Fallow's production graph cannot follow the request-handler-chain dynamic imports, so this exact list is the facade contract.",
|
|
"file": "src/daemon/interaction/index.ts",
|
|
"exports": [
|
|
"FindRouteInput",
|
|
"refMutationAdmissionResponse",
|
|
"handleFindCommands",
|
|
"handleInteractionCommands"
|
|
]
|
|
},
|
|
{
|
|
"comment": "The #2178 route implementations are reached only through the interaction facade's deferred delegates; Fallow's production graph cannot follow those dynamic imports. Keep this exemption limited to the two route entrypoints.",
|
|
"file": "src/daemon/interaction/internal/{find,interaction}.ts",
|
|
"exports": ["handleFindCommands", "handleInteractionCommands"]
|
|
},
|
|
{
|
|
"comment": "Dedicated CLI command handlers are reached only through the dynamic `import()` table `dedicatedCliCommandHandlerLoaders` in src/cli/commands/router.ts, which --production analysis cannot follow to a consumer. Same shape as the daemon route-handler entry above; that table is what enumerates this list, so add/remove here whenever a loader is added/removed.",
|
|
"file": "src/cli/commands/{auth,connection,daemon,device,proxy,replay,screenshot,takeover}.ts",
|
|
"exports": [
|
|
"authCommand",
|
|
"connectCommand",
|
|
"disconnectCommand",
|
|
"connectionCommand",
|
|
"daemonCommand",
|
|
"deviceCommand",
|
|
"proxyCommand",
|
|
"replayCommand",
|
|
"screenshotCommand",
|
|
"diffCommand",
|
|
"takeoverCommand"
|
|
]
|
|
},
|
|
{
|
|
"comment": "Test fixtures: every *.fixtures.ts builds doubles for co-located *.test.ts files (several import `vi` directly) and none is imported by production source, so --production analysis sees no consumer for any of them. Scoped to unused-exports rather than ignorePatterns so fixtures stay inside every other Fallow rule (health, dead-code, cycles); `*` rather than today's three symbols because the property being asserted is per-file, not per-symbol.",
|
|
"file": "**/*.fixtures.ts",
|
|
"exports": ["*"]
|
|
},
|
|
{
|
|
"comment": "Published package surface (see package.json#exports); consumed by SDK users, not internally.",
|
|
"file": "{src/sdk/*.ts,src/ai-sdk/index.ts}",
|
|
"exports": ["*"]
|
|
},
|
|
{
|
|
"comment": "#1642: its three consumers (src/__tests__/cli-device-status.test.ts, src/daemon/__tests__/device-claims.test.ts, src/daemon/__tests__/device-claim-prune.test.ts) all reach it the only way a Vitest module mock can — `vi.mock(path, async (importOriginal) => (await import('...host-process-mock.ts')).pinOwnProcessStartTime(importOriginal))`. Dependency analysis cannot follow that dynamic import to a consumer, the same limitation the daemon route-handler entry above records.",
|
|
"file": "src/__tests__/test-utils/host-process-mock.ts",
|
|
"exports": ["pinOwnProcessStartTime"]
|
|
},
|
|
{
|
|
"comment": "Tool config default exports, loaded by the tool rather than imported.",
|
|
"file": "{oxlint.config.ts,tsdown.config.ts,vitest.mutation.config.ts,website/rspress.config.ts}",
|
|
"exports": ["default"]
|
|
},
|
|
{
|
|
"comment": "Type-level `AssertTrue<...>` registry-totality guards. Exported only so `noUnusedLocals` keeps them alive; a consumer would defeat the point.",
|
|
"file": "{packages/command-registry/src/registry.ts,src/core/interactors/register-builtins.ts,src/core/platform-descriptor/registry.ts,src/daemon/request-platform-providers.ts}",
|
|
"exports": [
|
|
"CommandOwnerFileClaimsAreComplete",
|
|
"BuiltinPluginsCoverAllPlatforms",
|
|
"PlatformDescriptorsAreTotal",
|
|
"GatedKeysAreResolverKeys"
|
|
]
|
|
},
|
|
{
|
|
"comment": "resolveVitestMaxWorkers is consumed by vitest.config.ts \u2014 a tool config outside --production analysis.",
|
|
"file": "scripts/lib/vitest-concurrency.ts",
|
|
"exports": ["resolveVitestMaxWorkers"]
|
|
},
|
|
{
|
|
"comment": "Mutation-lane seam: readTestScope is consumed by vitest.mutation.config.ts, a tool config outside --production analysis.",
|
|
"file": "scripts/mutation/test-scope.ts",
|
|
"exports": ["readTestScope"]
|
|
},
|
|
{
|
|
"comment": "Mutation-lane completeness gate: ownedTestFiles enumerates the whole derived ownership map, which only the assertion in ownership.test.ts consumes — a production consumer would defeat the point.",
|
|
"file": "scripts/mutation/ownership.ts",
|
|
"exports": ["ownedTestFiles"]
|
|
},
|
|
{
|
|
"comment": "ADR 0010 shared-hint pin: the facade re-export's only consumer is src/__tests__/is-argument-surface-parity.test.ts, which asserts the daemon and CLI `is` surfaces raise the SAME hint text. The constant is live inside the package (predicates.ts raises it); a production consumer of the re-export would defeat the point, since it exists so neither surface copies the string.",
|
|
"file": "packages/selectors/src/index.ts",
|
|
"exports": ["IS_PREDICATE_USAGE_HINT"]
|
|
},
|
|
{
|
|
"comment": "Help-benchmark conformance seams: helpTopicIds feeds the topic-coverage gate, and the *_SAMPLE constants feed the bench sample producers (scripts/__tests__/help-conformance-sample-producers.ts); every consumer is a test-tree file outside --production analysis.",
|
|
"file": "{src/cli/parser/cli-help.ts,scripts/help-conformance-sample-outputs.mjs}",
|
|
"exports": ["helpTopicIds", "PRIVATE_AX_RECOVERY_SAMPLE", "DEVICE_CLAIM_IN_USE_SAMPLE"]
|
|
},
|
|
{
|
|
"comment": "#1458: getSessionCommandKind's former production consumer (the session.ts if-chain) was replaced by SESSION_COMMAND_HANDLER_IMPLS, which encodes command-kind groupings directly via shared handler references instead of a kind lookup. The accessor and its SessionCommandKind classification remain covered by daemon-command-registry.test.ts, a test-tree file outside --production analysis.",
|
|
"file": "src/daemon/daemon-command-registry.ts",
|
|
"exports": ["getSessionCommandKind"]
|
|
},
|
|
{
|
|
"comment": "Workspace-package symbols whose only consumers are test-tree files, which --production analysis does not see. Each import is the package specifier, so the façade entry is load-bearing: parseTargetAnnotationV1Payload/TARGET_ANNOTATION_MAX_FIELD_BYTES from src/daemon/__tests__/session-target-evidence.test.ts, MAESTRO_COMPAT_* from src/cli/parser/__tests__/maestro-support-matrix.test.ts, createAppLogLiveHandle from src/__tests__/test-utils/app-log-live-handle.ts (its production sibling createAppLogLiveHandleFromFinish wraps it, and scripts/layering/platform-package-policy.test.ts pins the specifier form).",
|
|
"file": "packages/{ad-script,maestro,capture-kit}/src/index.ts",
|
|
"exports": [
|
|
"parseTargetAnnotationV1Payload",
|
|
"TARGET_ANNOTATION_MAX_FIELD_BYTES",
|
|
"MAESTRO_COMPAT_LIMITATIONS",
|
|
"MAESTRO_COMPAT_SUPPORTED_CAPABILITIES",
|
|
"createAppLogLiveHandle"
|
|
]
|
|
},
|
|
{
|
|
"comment": "Android mechanics facet: the package exports the complete named implementation seam for root/core/SDK consumers and package-owned tests; Fallow's production graph does not follow workspace subpath imports through the package exports map.",
|
|
"file": "packages/platform-android/src/mechanics.ts",
|
|
"exports": ["*"]
|
|
},
|
|
{
|
|
"comment": "Apple Simulator snapshot acquisition is a private package facet consumed by downstream runtime work; Fallow cannot see external consumers through the workspace exports map. Keep only the deliberately narrow public factory, source interface, and request/outcome types here; host injection, cache metadata, and preparation internals stay private.",
|
|
"file": "packages/platform-apple/src/snapshot-source-facade.ts",
|
|
"exports": [
|
|
"createSimulatorSnapshotSource",
|
|
"SimulatorSnapshotSource",
|
|
"SnapshotSourceFailure",
|
|
"SnapshotSourceFailureKind",
|
|
"SnapshotSourceLimits",
|
|
"SnapshotSourceOutcome",
|
|
"SnapshotSourceRequest",
|
|
"SnapshotSourceTarget"
|
|
]
|
|
},
|
|
{
|
|
"comment": "The native wire vocabulary is exported only so the parity test can pin the Objective-C literals; it is not part of the snapshot-source package facet.",
|
|
"file": "packages/platform-apple/src/snapshot-source/protocol.ts",
|
|
"exports": [
|
|
"SNAPSHOT_SOURCE_ATTRIBUTE_KEYS",
|
|
"SNAPSHOT_SOURCE_RESPONSE_KEYS",
|
|
"SNAPSHOT_SOURCE_WIRE_KEYS"
|
|
]
|
|
},
|
|
{
|
|
"comment": "Deliberately kept off the @agent-device/maestro façade (index.test.ts asserts its absence) and consumed only by the conformance harness under packages/maestro/test/.",
|
|
"file": "packages/maestro/src/internal/program-ir-command-parser.ts",
|
|
"exports": ["SUPPORTED_MAESTRO_COMMAND_NAMES"]
|
|
},
|
|
{
|
|
"comment": "Published type surface: re-exported by src/sdk/limrun.ts to agent-device/limrun, where test/integration/limrun-public-types.test.ts pins that consumers can import it. Its only importer compiles in a temp checkout, so no static in-repo edge reaches it — the same reason src/sdk/*.ts is exempt above.",
|
|
"file": "packages/provider-limrun/src/index.ts",
|
|
"exports": ["LimrunIosCommandExecution"]
|
|
},
|
|
{
|
|
"comment": "Converting the contracts façades from `export *` to explicit named re-exports (the pin-table retirement) made these individually visible to --production analysis for the first time; a bare star previously hid them from this exact check. isRecord/IOS_SAFARI_BUNDLE_ID/REPLAY_DIVERGENCE_* have no production consumer. Kept rather than narrowed here so the façade's re-export surface stays byte-identical to the symbol set the retired pin table asserted — narrowing the surface is a follow-up with its own review, not a side effect of this mechanical conversion.",
|
|
"file": "packages/contracts/src/facades/{client,command,divergence,recording}.ts",
|
|
"exports": [
|
|
"isRecord",
|
|
"IOS_SAFARI_BUNDLE_ID",
|
|
"REPLAY_DIVERGENCE_DEFAULT_REF_LIMIT",
|
|
"REPLAY_DIVERGENCE_DIGEST_REF_LIMIT",
|
|
"REPLAY_DIVERGENCE_LEVEL_BYTE_LIMITS",
|
|
"applyReplayDivergenceLevelCaps",
|
|
"measureReplayDivergenceBytes",
|
|
"sanitizeReplayDivergenceField",
|
|
"truncateUtf8Field",
|
|
"isRecordingExportQuality"
|
|
]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its selected host route explicit here.",
|
|
"file": "packages/platform-harmonyos/src/hdc.ts",
|
|
"exports": ["ensureHarmonyToolchainPathConfigured"]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its selected lifecycle route explicit here.",
|
|
"file": "packages/platform-harmonyos/src/app-lifecycle.ts",
|
|
"exports": ["listHarmonyApps", "openHarmonyApp", "closeHarmonyApp"]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS archive metadata parsing is exercised by package-owned tests but has no production caller; keep the direct test seam explicit while the implementation remains colocated with app lifecycle mechanics.",
|
|
"file": "packages/platform-harmonyos/src/app-lifecycle.ts",
|
|
"exports": ["resolveHarmonyArchiveBundleName"]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its selected diagnostics route explicit here.",
|
|
"file": "packages/platform-harmonyos/src/doctor.ts",
|
|
"exports": ["harmonyToolchainCheck"]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its selected interaction route explicit here.",
|
|
"file": "packages/platform-harmonyos/src/input-actions.ts",
|
|
"exports": [
|
|
"pressHarmony",
|
|
"doubleClickHarmony",
|
|
"longPressHarmony",
|
|
"typeHarmony",
|
|
"fillHarmony",
|
|
"scrollHarmony",
|
|
"performHarmonyGesture",
|
|
"homeHarmony",
|
|
"appSwitcherHarmony",
|
|
"pressHarmonyKeyboardKey",
|
|
"setHarmonyOrientation"
|
|
]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-harmonyos/src/perf.ts",
|
|
"exports": ["sampleHarmonyMemoryPerf"]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-harmonyos/src/screenshot.ts",
|
|
"exports": ["screenshotHarmony"]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-harmonyos/src/settings.ts",
|
|
"exports": ["setHarmonySetting"]
|
|
},
|
|
{
|
|
"comment": "HarmonyOS package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its selected host route explicit here.",
|
|
"file": "packages/platform-harmonyos/src/index.ts",
|
|
"exports": ["sampleHarmonyMemoryPerf"]
|
|
},
|
|
{
|
|
"comment": "Linux package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its selected interactor/snapshot routes explicit here.",
|
|
"file": "packages/platform-linux/src/app-lifecycle.ts",
|
|
"exports": ["openLinuxApp", "closeLinuxApp", "backLinux", "homeLinux"]
|
|
},
|
|
{
|
|
"comment": "Linux package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its selected interactor route explicit here.",
|
|
"file": "packages/platform-linux/src/input-actions.ts",
|
|
"exports": [
|
|
"rightClickLinux",
|
|
"middleClickLinux",
|
|
"doubleClickLinux",
|
|
"longPressLinux",
|
|
"focusLinux",
|
|
"swipeLinux"
|
|
]
|
|
},
|
|
{
|
|
"comment": "Linux package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-linux/src/screenshot.ts",
|
|
"exports": ["screenshotLinux"]
|
|
},
|
|
{
|
|
"comment": "Linux package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-linux/src/snapshot.ts",
|
|
"exports": ["readLinuxTextAtPoint"]
|
|
},
|
|
{
|
|
"comment": "Linux package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis.",
|
|
"file": "packages/platform-linux/src/clipboard.ts",
|
|
"exports": ["readLinuxClipboard", "writeLinuxClipboard"]
|
|
},
|
|
{
|
|
"comment": "Linux package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis.",
|
|
"file": "packages/platform-linux/src/input-actions.ts",
|
|
"exports": ["scrollLinux", "fillLinux"]
|
|
},
|
|
{
|
|
"comment": "Linux package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-linux/src/surface-snapshot.ts",
|
|
"exports": ["captureLinuxSurfaceSnapshot"]
|
|
},
|
|
{
|
|
"comment": "Linux package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-linux/src/index.ts",
|
|
"exports": ["createLocalLinuxToolProvider"]
|
|
},
|
|
{
|
|
"comment": "Vega package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-vega/src/doctor.ts",
|
|
"exports": ["vegaToolchainCheck"]
|
|
},
|
|
{
|
|
"comment": "Web package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its managed-backend/provider routes explicit here.",
|
|
"file": "packages/platform-web/src/agent-browser-tool.ts",
|
|
"exports": ["doctorManagedAgentBrowser"]
|
|
},
|
|
{
|
|
"comment": "Web package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-web/src/agent-browser-tool.ts",
|
|
"exports": ["setupManagedAgentBrowser"]
|
|
},
|
|
{
|
|
"comment": "Web package façade loader is a named external seam. Its dynamic property read is not visible to --production analysis.",
|
|
"file": "packages/platform-web/src/doctor.ts",
|
|
"exports": ["webBrowserLifecycleCheck"]
|
|
},
|
|
{
|
|
"comment": "Web package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, so keep the façade and its request-scoped provider routes explicit here.",
|
|
"file": "packages/platform-web/src/provider.ts",
|
|
"exports": ["resolveWebProvider", "hasScopedWebProvider"]
|
|
},
|
|
{
|
|
"comment": "Web package façade loaders are named external seams. Their dynamic property reads are not visible to --production analysis, and the timeout is pinned by the daemon teardown test.",
|
|
"file": "packages/platform-web/src/index.ts",
|
|
"exports": [
|
|
"AGENT_BROWSER_TIMEOUT_MS",
|
|
"inspectManagedAgentBrowserProcesses",
|
|
"summarizeAgentBrowserProcesses"
|
|
]
|
|
},
|
|
{
|
|
"comment": "Web process matching helpers are retained for package-owned lifecycle tests; production export analysis does not traverse those test consumers.",
|
|
"file": "packages/platform-web/src/agent-browser-lifecycle.ts",
|
|
"exports": [
|
|
"agentBrowserChromeLaunchMarker",
|
|
"matchAgentBrowserChromeProcess",
|
|
"summarizeAgentBrowserProcesses",
|
|
"summarizeManagedAgentBrowserProcesses"
|
|
]
|
|
}
|
|
],
|
|
"usedClassMembers": [
|
|
"name",
|
|
"listActiveLeases",
|
|
"delete",
|
|
"values",
|
|
"elapsedMs",
|
|
"isExpired",
|
|
"findByDevice"
|
|
],
|
|
"rules": {
|
|
"unused-types": "error",
|
|
"duplicate-exports": "off"
|
|
},
|
|
"overrides": [
|
|
{
|
|
"comment": "unused-types counts importers, not signature reachability. A façade names every type its re-exported functions/values put in a public signature, and callers use those types structurally without ever importing the name — the same false-positive shape already fixed for other workspace-package façades. unused-exports (a VALUE check) stays on for this glob; that is what would catch a real leak.",
|
|
"files": ["packages/contracts/src/facades/*.ts"],
|
|
"rules": {
|
|
"unused-types": "off"
|
|
}
|
|
},
|
|
{
|
|
"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.",
|
|
"files": ["packages/host-kit/src/*.ts"],
|
|
"rules": {
|
|
"unused-types": "off"
|
|
}
|
|
},
|
|
{
|
|
"comment": "Android mechanics facet types are named explicitly for the same package-subpath public seam; unused-exports remains governed by the facet entry above.",
|
|
"files": ["packages/platform-android/src/mechanics.ts"],
|
|
"rules": {
|
|
"unused-types": "off"
|
|
}
|
|
}
|
|
],
|
|
"production": {
|
|
"dupes": true
|
|
},
|
|
"publicPackages": ["agent-device"],
|
|
"audit": {
|
|
"deadCodeBaseline": "fallow-baselines/dead-code.json",
|
|
"healthBaseline": "fallow-baselines/health.json"
|
|
},
|
|
"includeEntryExports": true,
|
|
"ignoreExportsUsedInFile": {
|
|
"type": true,
|
|
"interface": true
|
|
}
|
|
}
|