Repository navigation
Expand file tree
/
Copy path.fallowrc.json
More file actions
418 lines (418 loc) · 22.2 KB
/
Copy path.fallowrc.json
File metadata and controls
418 lines (418 loc) · 22.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
{
"$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json",
"entry": [
"tsdown.config.ts",
"scripts/check-provider-plugin.mjs",
"scripts/check-affected/command.ts",
"packages/provider-testmu/test/package-smoke.mjs",
"packages/provider-testmu/tsdown.config.ts",
"packages/provider-testmu/src/plugin.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/plugins.ts",
"src/sdk/plugin-webdriver.ts",
"src/sdk/android-adb.ts",
"src/sdk/contracts.ts",
"src/sdk/selectors.ts",
"src/sdk/finders.ts",
"src/ai-sdk/index.ts",
"packages/proxy/src/index.ts",
"packages/proxy/tsdown.config.ts",
"src/bin.ts",
"packages/react-native/src/companion/companion-tunnel.ts",
"src/daemon.ts",
"packages/capture-kit/src/png-worker.ts",
"scripts/patch-xcuitest-runner-icon.ts",
"scripts/write-xcuitest-cache-metadata.ts",
"scripts/xcuitest-build-settings.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/integration/*.test.ts",
"website/docs/404.mdx",
"website/rspress.config.ts"
],
"framework": [
{
"name": "mutation-pilot",
"enablers": ["@stryker-mutator/core"],
"entryPointRole": "test",
"entryPoints": ["scripts/mutation/coverage-reporter.mjs", "scripts/mutation/seed-setup.ts"],
"usedExports": [
{ "pattern": "scripts/mutation/coverage-reporter.mjs", "exports": ["strykerPlugins"] }
]
}
],
"ignorePatterns": [
"examples/test-app/**",
"scripts/perf/**",
"scripts/layering/**",
"scripts/di-seams/**",
"scripts/maestro-conformance/corpus/**",
"apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests.xctestplan",
"scripts/help-conformance-sample-outputs.d.mts",
"scripts/help-conformance-runner-output.d.mts",
// A hand-written type surface for a plain-Node .mjs the typechecked program (and Fallow's
// graph) cannot import; its only consumer is the .mjs's real importers, resolved by tsc, not
// by an import edge. Same shape as the help-conformance declaration files above.
"scripts/size-report-package.d.mts"
],
"dynamicallyLoaded": ["packages/daemon/src/execution/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",
// @agent-device/testmu imports agent-device type-only, and its tsconfig maps those specifiers
// through this workspace link to core source so typecheck needs no build; Fallow then credits
// the source files rather than the package.
"agent-device",
// 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": [
{
// The standalone packed-install harness loads this fixture from the selected package path and reads its request scenarios dynamically.
"file": "packages/provider-*/test/package-smoke.mjs",
"exports": ["*"]
},
{
// A published provider package's default export is its plugin contract; packages/plugins/src/load.ts imports the package by name at runtime and reads `default`.
"file": "packages/provider-*/src/index.ts",
"exports": ["default"]
},
{
// The version 1 entry a provider package's `agentDevicePlugin.entry` names; hosts without the version 2 contract import the built file and read `default`.
"file": "packages/provider-*/src/plugin.ts",
"exports": ["default"]
},
{
// packages/platform-apple/src/lifecycle.ts loads this module on demand and reads the member off the memoized import() promise, which Fallow cannot follow.
"file": "packages/platform-apple/src/expo-dev-client-launch.ts",
"exports": ["resolveExpoDevClientLaunchUrl"]
},
{
// 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"]
},
{
// 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", "detectSoleRunningIosSimulatorApp"]
},
{
// 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": [
"notifyIosRunnerAppRelaunched",
"prepareIosRunner",
"prewarmIosRunnerSession",
"detachIosRunnerSessionsForShutdown",
"hasLiveIosRunnerSession",
"releaseIosRunnerOnClose",
"releaseSpeculativeIosRunnerSessionFor",
"stopAllIosRunnerSessions"
]
},
{
// 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": ["readIosBundleInfo"]
},
{
// Apple perf façade types put values from the lazy perf seam in a public signature without a static in-repo importer; Fallow cannot connect dynamic import member reads through the façade to these source types; keep the list limited to the façade types that actually report.
"file": "packages/platform-apple/src/perf-facade.ts",
"exports": ["AppleXctraceCpuProfileReport", "AppleXctracePerfMode", "AppleXctracePerfResult"]
},
{
// 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"
]
},
{
// 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"]
},
{
// 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": "packages/daemon/src/sessions/handlers/{human-control,lease,session,snapshot,record-trace}.ts",
"exports": [
"handleHumanControlCommand",
"handleLeaseCommands",
"handleSessionCommands",
"handleSnapshotCommands",
"handleRecordTraceCommands"
]
},
{
// The react-native route handler lives in the execution layer with its mechanics; same dynamic-loader exemption as the sessions-side route handlers above.
"file": "packages/daemon/src/execution/handlers/react-native.ts",
"exports": ["handleReactNativeCommands"]
},
{
// The interaction facade exposes #2178's deferred route 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": "packages/daemon/src/execution/interaction/index.ts",
"exports": ["refMutationAdmissionResponse", "handleFindCommands", "handleInteractionCommands"]
},
{
// The macOS façade members are read off the memoized loadMacOs() loader in src/platform-runtime-apple-application-tools.ts. Fallow cannot connect that dynamic member read to the re-exports.
"file": "packages/platform-apple/src/macos-facade.ts",
"exports": ["resolveFrontmostMacOsApp", "runMacOsAlertAction"]
},
{
// answerSimulatorLaunchConfirmation is called from packages/platform-apple/src/lifecycle.ts through the lazy loadLaunchConfirmation() import; Fallow cannot connect the dynamic member read.
"file": "packages/platform-apple/src/launch-confirmation.ts",
"exports": ["answerSimulatorLaunchConfirmation"]
},
{
// The CLI and MCP process entrypoints are loaded lazily by the module table in src/cli/entry.ts; Fallow cannot connect those dynamic member reads.
"file": "{src/cli/process-entry.ts,src/mcp/server.ts}",
"exports": ["runCliProcess", "runAgentDeviceMcpServer"]
},
{
// Runtime hint application is reached from the Android and Apple application tools through the lazy loadRuntimeHints() import; Fallow cannot connect the dynamic member read.
"file": "src/platform-runtime-runtime-hints.ts",
"exports": ["applyRuntimeHintValues", "clearRuntimeHintValues"]
},
{
// The contracts snapshot façade must re-export every symbol of ../snapshot-scope.ts (scripts/layering/package-boundaries.test.ts, façade exhaustiveness); callers import it from @agent-device/contracts/snapshot-scope, so the façade copy has no consumer.
"file": "packages/contracts/src/facades/snapshot.ts",
"exports": ["findSnapshotScopeRange"]
},
{
// Same façade-exhaustiveness rule (scripts/layering/facade-surface.test.ts): these façades must re-export every symbol of ../screenshot.ts, ../remote-config-fields.ts and ../snapshot-visibility.ts, whose production callers import the source module directly.
"file": "packages/contracts/src/facades/{capture,remote,snapshot}.ts",
"exports": [
"SCREENSHOT_ACTION_FLAG_KEYS",
"PROVIDER_PROFILE_FIELD_FLAG_ALIASES",
"collectViewportRects"
]
},
{
// 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": ["*"]
},
{
// @agent-device/test-kit is the test-helper package: every module is consumed only from the test trees (root, scripts/, packages/, test/), which --production analysis does not see, exactly like the *.fixtures.ts entry above. The package manifest's exports map owns its surface; the same per-file blanket keeps it inside every other Fallow rule.
"file": "packages/test-kit/src/*.ts",
"exports": ["*"]
},
{
// Published package surfaces (see each package.json#exports); consumers may be external or reach them through workspace package exports Fallow does not follow.
"file": "{src/sdk/*.ts,src/ai-sdk/index.ts,packages/proxy/src/index.ts}",
"exports": ["*"]
},
{
// Tool config default exports, loaded by the tool rather than imported.
"file": "{oxlint.config.ts,tsdown.config.ts,packages/provider-*/tsdown.config.ts,packages/proxy/tsdown.config.ts,vitest.mutation.config.ts,website/rspress.config.ts}",
"exports": ["default"]
},
{
// 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}",
"exports": [
"CommandOwnerFileClaimsAreComplete",
"CommandUnionStaysLiteral",
"CliCommandUnionStaysLiteral",
"BuiltinPluginsCoverAllPlatforms"
]
},
{
// 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"]
},
{
// 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 from packages/selectors/src/target-evidence.test.ts, MAESTRO_COMPAT_* from src/cli/parser/__tests__/maestro-support-matrix.test.ts, SCRIPT_FLAG_COMMANDS/scriptFlagEntries from src/commands/replay/script-flag-admission.test.ts (the #3197 two-way drift guard between the .ad grammar and the CLI schema).
"file": "packages/{ad-script,maestro,capture-kit}/src/index.ts",
"exports": [
"parseTargetAnnotationV1Payload",
"MAESTRO_COMPAT_LIMITATIONS",
"MAESTRO_COMPAT_SUPPORTED_CAPABILITIES",
"SCRIPT_FLAG_COMMANDS",
"scriptFlagEntries"
]
},
{
// packages/daemon/src/core/__tests__/request-runtime-binding.test.ts drives the daemon's exact bind through the recovery authority, whose cancellation race is what rejects; production reaches it only through finishRecoveredDurableCapture and recoverDurableCaptureResource in the same package.
"file": "packages/capture-kit/src/durable-capture/index.ts",
"exports": ["acquireDurableCaptureRecoveryAuthorityBeforeDeadline"]
},
{
// The collected copy's path is part of the stop-sequence contract (ADR 0024 §2.3) beside nativeRecordingPath; provider-scenario and Apple recovery tests assert pulls land on it, while production derives it inside the stop sequence.
"file": "packages/capture-kit/src/recording/stop-sequence.ts",
"exports": ["collectedRecordingPath"]
},
{
// 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": ["*"]
},
{
// Apple Simulator snapshot acquisition is a private package facet consumed by downstream runtime work; Fallow cannot see external consumers through the workspace exports map. Only the shared failure/limits/request-target types report without an exemption; the factory and its source interface resolve through the package boundary.
"file": "packages/platform-apple/src/snapshot-source-facade.ts",
"exports": ["SnapshotSourceFailureKind", "SnapshotSourceLimits", "SnapshotSourceTarget"]
},
{
// 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"
]
},
{
// 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"]
},
{
// 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"]
},
{
// 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"]
},
{
// 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"
]
},
{
// 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": [
{
// 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"
}
},
{
// 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"
}
},
{
// 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": {
"healthBaseline": "fallow-baselines/health.json"
},
// CRAP needs measured coverage: estimated from imports it disagrees with measured scores on most
// findings, so it stays off here and the CI Coverage job's `check:coverage-crap` re-enables it
// with `--max-crap 30` beside the Vitest coverage map. Functions that cannot be instrumented by
// the Node coverage run (browser-evaluated scripts, worker threads) carry a per-function ceiling
// below, high enough for their current score and low enough that growth still blocks.
"health": {
"maxCrap": 0,
"thresholdOverrides": [
{
// These seven are the audioProbe* functions already scoring at or above the global CRAP
// bar under 0% measured coverage: they are serialized with Function.toString into one
// string and evaluated inside the browser page (buildAudioProbeEvalScript is what ships
// them; the normalize side is unit-tested), so no test added in Node can move their
// number. Their untested siblings keep the global bar, where one added branch would
// block. The ceiling is 90: every one scores 72 or less today, so growth past that blocks.
"files": ["packages/platform-web/src/agent-browser-audio-probe.ts"],
"functions": [
"audioProbeStop",
"audioProbeEvalScript",
"audioProbeCreateElementAudioSource",
"audioProbeDiscover",
"audioProbeStart",
"audioProbeSample",
"audioProbeGetContext"
],
"maxCrap": 90,
"reason": "Browser-evaluated page script; the Node coverage map never records it."
},
{
// `pnpm exec vitest run packages/capture-kit/src/png-worker-client.test.ts` proves every
// job kind answers on the worker thread, but that thread's execution is not in the
// coverage map, so the job switch always measures 0% (CRAP 72 today; 90 blocks growth).
"files": ["packages/capture-kit/src/png-worker.ts"],
"functions": ["runJob"],
"maxCrap": 90,
"reason": "node:worker_threads entry; the coverage map only records the main thread."
}
]
},
"includeEntryExports": true,
"ignoreExportsUsedInFile": {
"type": true,
"interface": true
}
}