agent-device 0.20.3 → 0.20.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.3.apk → agent-device-android-ime-helper-0.20.4.apk} +0 -0
  2. package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.4.apk.sha256 +1 -0
  3. package/android/ime-helper/dist/{agent-device-android-ime-helper-0.20.3.manifest.json → agent-device-android-ime-helper-0.20.4.manifest.json} +4 -4
  4. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.4.apk +0 -0
  5. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.4.apk.sha256 +1 -0
  6. package/android/snapshot-helper/dist/{agent-device-android-snapshot-helper-0.20.3.manifest.json → agent-device-android-snapshot-helper-0.20.4.manifest.json} +6 -6
  7. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +57 -4
  8. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +45 -9
  9. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Keyboard.swift +73 -0
  10. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Navigation.swift +1 -0
  11. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScrollGesture.swift +3 -2
  12. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SequenceExecution.swift +1 -1
  13. package/dist/apple/runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SynthesizedGesturePolicy.swift +8 -2
  14. package/dist/src/agent-browser-tool.js +1 -1
  15. package/dist/src/agent-device-client.js +2 -2
  16. package/dist/src/android-adb.d.ts +1 -1
  17. package/dist/src/android.js +1 -1
  18. package/dist/src/app-helpers.js +1 -1
  19. package/dist/src/app-inventory.d.ts +4 -0
  20. package/dist/src/app-lifecycle.js +7 -7
  21. package/dist/src/app-resolution.js +1 -1
  22. package/dist/src/apps.js +5 -5
  23. package/dist/src/boot-diagnostics.js +1 -1
  24. package/dist/src/cli-config.js +1 -1
  25. package/dist/src/cli-help.js +27 -19
  26. package/dist/src/cli-runner.js +1 -1
  27. package/dist/src/cli.js +15 -14
  28. package/dist/src/client-metro.js +1 -1
  29. package/dist/src/{tv-remote.d.ts → cloud-artifacts.d.ts} +109 -126
  30. package/dist/src/command-metadata.js +1 -1
  31. package/dist/src/command-schema.js +1 -1
  32. package/dist/src/command-surface.js +1 -1
  33. package/dist/src/context.js +1 -1
  34. package/dist/src/contracts.d.ts +1 -1
  35. package/dist/src/debug-symbols.js +4 -4
  36. package/dist/src/device-input-state.d.ts +2 -2
  37. package/dist/src/device-input-state.js +1 -1
  38. package/dist/src/device.js +1 -9
  39. package/dist/src/devices2.js +1 -1
  40. package/dist/src/entities.js +1 -0
  41. package/dist/src/find.js +1 -1
  42. package/dist/src/finders.d.ts +1 -1
  43. package/dist/src/finders.js +1 -1
  44. package/dist/src/generic.js +1 -1
  45. package/dist/src/helper.js +2 -2
  46. package/dist/src/ime-lifecycle.js +9 -0
  47. package/dist/src/index.d.ts +592 -555
  48. package/dist/src/input-actions.js +4 -4
  49. package/dist/src/install-artifact.js +4 -4
  50. package/dist/src/install-artifact2.js +1 -1
  51. package/dist/src/install-source2.js +1 -1
  52. package/dist/src/interaction-snapshot.js +1 -1
  53. package/dist/src/interaction.d.ts +7 -4
  54. package/dist/src/interaction.js +1 -1
  55. package/dist/src/interactor.js +2 -2
  56. package/dist/src/interactor2.js +1 -1
  57. package/dist/src/internal/bin.js +1 -1
  58. package/dist/src/internal/daemon.js +14 -14
  59. package/dist/src/internal/png-worker.js +1 -1
  60. package/dist/src/lease-context.js +1 -1
  61. package/dist/src/lease.js +1 -1
  62. package/dist/src/limrun.d.ts +103 -198
  63. package/dist/src/limrun.js +1 -1
  64. package/dist/src/linux.js +1 -1
  65. package/dist/src/logcat.js +1 -1
  66. package/dist/src/manifest.js +1 -1
  67. package/dist/src/metro.d.ts +1 -1
  68. package/dist/src/parser.js +2 -0
  69. package/dist/src/path-resolution.js +1 -1
  70. package/dist/src/physical-device-control.js +1 -1
  71. package/dist/src/plist-xml.js +1 -0
  72. package/dist/src/plist.js +1 -1
  73. package/dist/src/png-worker-contract.js +1 -1
  74. package/dist/src/process-lock.js +1 -1
  75. package/dist/src/provider-limrun-runtime.js +1 -0
  76. package/dist/src/react-native.js +1 -1
  77. package/dist/src/record-trace.js +1 -1
  78. package/dist/src/register-builtins.js +1 -1
  79. package/dist/src/registry.js +22 -22
  80. package/dist/src/remote-config2.js +1 -1
  81. package/dist/src/reporting.js +7 -7
  82. package/dist/src/runner-client.js +1 -1
  83. package/dist/src/runner-disposal.js +1 -1
  84. package/dist/src/runner-lease.js +1 -1
  85. package/dist/src/runner-provider.js +1 -1
  86. package/dist/src/runner-sequence.js +1 -1
  87. package/dist/src/runtime-transport.js +1 -1
  88. package/dist/src/runtime.js +3 -3
  89. package/dist/src/screenshot-geometry.js +1 -0
  90. package/dist/src/screenshot-result.js +6 -0
  91. package/dist/src/sdk-android-adb.d.ts +5 -6
  92. package/dist/src/sdk-android-adb.js +3 -3
  93. package/dist/src/sdk-batch-runner.d.ts +2 -2
  94. package/dist/src/sdk-batch-runner.js +3 -3
  95. package/dist/src/sdk-contracts.d.ts +21 -25
  96. package/dist/src/sdk-contracts.js +2 -2
  97. package/dist/src/sdk-finders.d.ts +1 -1
  98. package/dist/src/sdk-finders.js +1 -1
  99. package/dist/src/sdk-io.js +1 -1
  100. package/dist/src/sdk-remote-config.d.ts +19 -4
  101. package/dist/src/sdk-remote-config.js +1 -1
  102. package/dist/src/sdk-selectors.js +1 -1
  103. package/dist/src/selector-runtime.js +1 -1
  104. package/dist/src/selector-vocabulary.js +1 -1
  105. package/dist/src/selectors.d.ts +1 -1
  106. package/dist/src/selectors.js +1 -1
  107. package/dist/src/server.js +2 -2
  108. package/dist/src/session-target-evidence.js +1 -1
  109. package/dist/src/session.js +8 -8
  110. package/dist/src/setting-state.js +1 -1
  111. package/dist/src/simulator.js +1 -1
  112. package/dist/src/snapshot.js +1 -1
  113. package/dist/src/snapshot2.js +1 -1
  114. package/dist/src/src.js +1 -0
  115. package/dist/src/tool-provider.js +3 -3
  116. package/dist/src/tool-provider2.js +1 -1
  117. package/dist/src/tool-provider3.js +1 -1
  118. package/dist/src/update-check.js +1 -1
  119. package/dist/src/version.js +1 -1
  120. package/dist/src/viewport-dimension.js +14 -0
  121. package/package.json +17 -7
  122. package/server.json +2 -2
  123. package/android/ime-helper/dist/agent-device-android-ime-helper-0.20.3.apk.sha256 +0 -1
  124. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.3.apk +0 -0
  125. package/android/snapshot-helper/dist/agent-device-android-snapshot-helper-0.20.3.apk.sha256 +0 -1
  126. package/dist/src/android-input-method-overlays.js +0 -1
  127. package/dist/src/android-input-ownership.js +0 -1
  128. package/dist/src/apple-multitouch-support.js +0 -1
  129. package/dist/src/click-button.d.ts +0 -5
  130. package/dist/src/compatibility-policy.js +0 -1
  131. package/dist/src/gesture-plan-types.js +0 -1
  132. package/dist/src/gesture-plan.js +0 -1
  133. package/dist/src/launch-console.js +0 -1
  134. package/dist/src/recording-export-quality.js +0 -14
  135. package/dist/src/rolldown-runtime.js +0 -1
  136. package/dist/src/runtime2.js +0 -1
  137. package/dist/src/sdk-app-inventory.d.ts +0 -4
  138. package/dist/src/sdk-app-inventory.js +0 -1
  139. package/dist/src/snapshot-diagnostics.js +0 -6
  140. package/dist/src/xml.js +0 -2
@@ -1,55 +1,169 @@
1
- import { A as SnapshotNode, B as DeviceTarget, C as normalizeAgentDeviceError, F as SnapshotVisibility, H as PlatformSelector, I as centerOfRect, L as AppleOS, P as SnapshotUnchanged, S as isAgentDeviceError, U as PublicPlatform, _ as SessionIsolationMode, a as DaemonLockPolicy, b as NormalizedError, c as DaemonResponseData, g as ResponseLevel, i as DaemonInstallSource, m as NetworkIncludeMode, o as DaemonRequest, p as LeaseBackend, r as DaemonError, s as DaemonResponse, t as DaemonArtifact, v as SessionRuntimeHints, y as AppError, z as DeviceKind } from "./sdk-contracts.js";
1
+ import { A as SnapshotNode, B as DeviceTarget, C as normalizeAgentDeviceError, F as SnapshotVisibility, H as PlatformSelector, I as centerOfRect, L as AppleOS, M as SnapshotQualityVerdict, P as SnapshotUnchanged, S as isAgentDeviceError, U as PublicPlatform, _ as SessionRuntimeHints, a as DaemonRequest, b as NormalizedError, f as LeaseBackend, g as SessionIsolationMode, h as ResponseLevel, i as DaemonLockPolicy, o as DaemonResponse, p as NetworkIncludeMode, r as DaemonInstallSource, s as DaemonResponseData, t as DaemonArtifact, v as AppError, y as DaemonError, z as DeviceKind } from "./sdk-contracts.js";
2
2
  import { c as ScrollDirection, d as SwipePreset, f as TransformGestureParams, l as ScrollInputDirection, s as GesturePointerCount, u as SwipePattern } from "./sdk-android-adb.js";
3
- import { t as AppsFilter } from "./sdk-app-inventory.js";
3
+ import { c as SnapshotDiagnosticsSummary, d as DeviceRotation, f as BackMode, i as AndroidSnapshotBackendMetadata, l as SessionSurface, o as FindLocator, r as CloudProviderSessionResult, s as ScreenshotResultData, t as AgentArtifactsResult, u as TvRemoteButton } from "./cloud-artifacts.js";
4
+ import { a as LongPressCommandResponseData, i as FindCommandResponseData, o as PressCommandResponseData, r as FillCommandResponseData, s as ClickButton, t as ClickCommandResponseData } from "./interaction.js";
5
+ import { t as AppsFilter } from "./app-inventory.js";
4
6
  import { t as BatchRunResult } from "./sdk-batch-runner.js";
5
- import { r as FindLocator } from "./sdk-finders.js";
6
7
  import { a as RemoteConnectionProfileFields, c as MetroPrepareResult, i as CloudProviderProfileFields, l as MetroReloadOptions, s as MetroPrepareOptions, u as MetroReloadResult } from "./sdk-remote-config.js";
7
- import { c as RecordingExportQuality, d as PublicSnapshotCaptureAnnotations, i as AgentArtifactsResult, l as ScreenshotResultData, m as JsonObject, n as DeviceRotation, o as CloudProviderSessionResult, p as SessionSurface, r as AlertAction, s as BackMode, t as TvRemoteButton, u as SnapshotDiagnosticsSummary } from "./tv-remote.js";
8
- import { t as ClickButton } from "./click-button.js";
9
- import { a as LongPressCommandResponseData, i as FindCommandResponseData, o as PressCommandResponseData, r as FillCommandResponseData, t as ClickCommandResponseData } from "./interaction.js";
10
8
  import { p as createLocalArtifactAdapter } from "./sdk-io.js";
11
- //#region src/contracts/client-connection.d.ts
12
- type AgentDeviceDaemonTransport = (req: Omit<DaemonRequest, 'token'>) => Promise<DaemonResponse>;
13
- type AgentDeviceClientConfig = RemoteConnectionProfileFields & CloudProviderProfileFields & {
14
- session?: string;
15
- lockPolicy?: DaemonLockPolicy;
16
- lockPlatform?: PlatformSelector;
17
- requestId?: string;
18
- sessionIsolation?: SessionIsolationMode;
19
- leaseBackend?: LeaseBackend;
20
- leaseTtlMs?: number;
21
- runtime?: SessionRuntimeHints;
22
- cwd?: string;
23
- debug?: boolean;
24
- cost?: boolean;
25
- responseLevel?: ResponseLevel;
26
- iosXctestrunFile?: string;
27
- iosXctestDerivedDataPath?: string;
28
- iosXctestEnvDir?: string;
9
+ //#region packages/contracts/src/alert-contract.d.ts
10
+ declare const ALERT_ACTIONS: readonly ['get', 'accept', 'dismiss', 'wait'];
11
+ type AlertAction = (typeof ALERT_ACTIONS)[number];
12
+ //#endregion
13
+ //#region packages/contracts/src/clipboard.d.ts
14
+ /**
15
+ * Closed result of the `clipboard` command. Mirrors the dispatch handler's
16
+ * literal return EXACTLY (src/core/dispatch.ts `handleClipboardCommand`): a
17
+ * discriminated union on `action`. `read` returns the clipboard `text`; `write`
18
+ * reports the written `textLength` plus the `successText` message. The handler
19
+ * spreads nothing else, so each branch is closed.
20
+ */
21
+ type ClipboardCommandResult = {
22
+ action: 'read';
23
+ text: string;
24
+ } | {
25
+ action: 'write';
26
+ textLength: number;
27
+ message: string;
29
28
  };
30
- type AgentDeviceRequestOverrides = Pick<AgentDeviceClientConfig, 'session' | 'lockPolicy' | 'lockPlatform' | 'requestId' | 'daemonBaseUrl' | 'daemonAuthToken' | 'daemonTransport' | 'daemonServerMode' | 'tenant' | 'sessionIsolation' | 'runId' | 'leaseId' | 'leaseBackend' | 'leaseProvider' | 'deviceKey' | 'clientId' | 'providerApp' | 'providerOsVersion' | 'providerProject' | 'providerBuild' | 'providerSessionName' | 'awsProjectArn' | 'awsDeviceArn' | 'awsAppArn' | 'awsRegion' | 'awsInteractionMode' | 'leaseTtlMs' | 'cwd' | 'debug' | 'cost' | 'responseLevel' | 'iosXctestrunFile' | 'iosXctestDerivedDataPath' | 'iosXctestEnvDir'>;
31
- type AgentDeviceIdentifiers = {
32
- session?: string;
33
- deviceId?: string;
34
- deviceName?: string;
35
- udid?: string;
36
- serial?: string;
37
- appId?: string;
38
- appBundleId?: string;
39
- package?: string;
29
+ //#endregion
30
+ //#region packages/contracts/src/keyboard.d.ts
31
+ /**
32
+ * Closed result of the `keyboard` command, grounded in the dispatch handlers'
33
+ * literal returns (src/core/dispatch.ts `handleAndroidKeyboardCommand` /
34
+ * `handleIosKeyboardCommand`).
35
+ *
36
+ * `platform` and `action` are always present; the remaining fields appear per
37
+ * branch (Android `status`/`dismiss` carry the keyboard-state fields; `enter`
38
+ * and iOS `dismiss` carry a `message`). It is kept as a flat closed shape rather
39
+ * than a five-way `platform`×`action` union because the per-branch field sets
40
+ * overlap heavily and the underlying Android keyboard-state types live in the
41
+ * platform layer (below the public contract). The `Record` index signature of
42
+ * the previous hand-written mirror is dropped, and the spurious `| null`s are
43
+ * removed (the handler never returns `null` for these).
44
+ */
45
+ type KeyboardCommandResult = {
46
+ platform: 'android' | 'ios';
47
+ action: 'status' | 'dismiss' | 'enter';
48
+ visible?: boolean;
49
+ wasVisible?: boolean;
50
+ dismissed?: boolean;
51
+ attempts?: number;
52
+ inputType?: string;
53
+ type?: 'text' | 'number' | 'email' | 'phone' | 'password' | 'datetime' | 'unknown';
54
+ inputMethodPackage?: string;
55
+ focusedPackage?: string;
56
+ focusedResourceId?: string;
57
+ inputOwner?: 'app' | 'ime' | 'unknown';
58
+ message?: string;
40
59
  };
41
- type AgentDeviceSelectionOptions = {
42
- platform?: PlatformSelector;
43
- target?: DeviceTarget;
44
- device?: string;
45
- udid?: string;
46
- serial?: string;
47
- iosSimulatorDeviceSet?: string;
48
- androidDeviceAllowlist?: string;
60
+ //#endregion
61
+ //#region packages/contracts/src/navigation.d.ts
62
+ /**
63
+ * Closed results of the navigation/global action commands. Each mirrors the
64
+ * dispatch handler's literal return EXACTLY (src/core/dispatch.ts
65
+ * `DISPATCH_HANDLERS`): a fixed `action` discriminant plus the always-present
66
+ * `successText` message (the handlers always pass a non-empty message, so it is
67
+ * required here). The handlers spread nothing else, so the shapes are closed —
68
+ * consistent with the `viewport` contract, the generic-dispatch Android
69
+ * dialog-recovery `warning` annotation is intentionally not part of the contract.
70
+ */
71
+ /** `home` — `{ action: 'home', message: 'Home' }`. */
72
+ type HomeCommandResult = {
73
+ action: 'home';
74
+ message: string;
75
+ };
76
+ /** `back` — `{ action: 'back', mode, message: 'Back' }`; `mode` defaults to `'in-app'`. */
77
+ type BackCommandResult = {
78
+ action: 'back';
79
+ mode: BackMode;
80
+ message: string;
81
+ };
82
+ /** `orientation` — `{ action: 'orientation', orientation, message: 'Rotated to <orientation>' }`. */
83
+ type OrientationCommandResult = {
84
+ action: 'orientation';
85
+ orientation: DeviceRotation;
86
+ message: string;
87
+ };
88
+ /**
89
+ * @deprecated The `rotate` command was renamed to `orientation`. This is the
90
+ * legacy response contract (`action: 'rotate'`) that shipped in v0.18/v0.19,
91
+ * retained for existing SDK consumers until the next major version. New code
92
+ * should use {@link OrientationCommandResult}.
93
+ */
94
+ type RotateCommandResult = {
95
+ action: 'rotate';
96
+ orientation: DeviceRotation;
97
+ message: string;
98
+ };
99
+ /** `app-switcher` — `{ action: 'app-switcher', message: 'Opened app switcher' }`. */
100
+ type AppSwitcherCommandResult = {
101
+ action: 'app-switcher';
102
+ message: string;
103
+ };
104
+ /** `tv-remote` — `{ action: 'tv-remote', button, durationMs?, message }`. */
105
+ type TvRemoteCommandResult = {
106
+ action: 'tv-remote';
107
+ button: TvRemoteButton;
108
+ durationMs?: number;
109
+ message: string;
110
+ };
111
+ //#endregion
112
+ //#region packages/contracts/src/wait.d.ts
113
+ /**
114
+ * Public daemon result for `wait`. The runtime-local result carries a `kind`
115
+ * discriminant, but `toDaemonWaitData` intentionally projects the normal daemon
116
+ * payload to this compact shape. The direct iOS selector fast path may still
117
+ * include `kind: 'selector'` additively.
118
+ */
119
+ type WaitCommandResult = {
120
+ waitedMs: number;
121
+ kind?: 'selector';
122
+ text?: string;
123
+ selector?: string;
124
+ captures?: number;
125
+ nodeCount?: number;
126
+ hint?: string;
127
+ warning?: string;
128
+ };
129
+ //#endregion
130
+ //#region packages/contracts/src/app-events.d.ts
131
+ type TriggerAppEventCommandResult = {
132
+ event: string;
133
+ eventUrl: string;
134
+ transport: 'deep-link';
135
+ message: string;
136
+ };
137
+ //#endregion
138
+ //#region packages/contracts/src/app-state.d.ts
139
+ /**
140
+ * Closed result of the `appstate` command, grounded in the daemon handler's
141
+ * success returns (src/daemon/handlers/session-state.ts `handleAppStateCommand`).
142
+ * A discriminated union on `platform`:
143
+ * - Apple (`ios` / `macos`) session state, with iOS-only device locators that
144
+ * the previous hand-written mirror omitted; and
145
+ * - Android foreground `package` / `activity`.
146
+ *
147
+ * The handler returns one of these fixed objects (errors take the `ok: false`
148
+ * path), so each branch is closed.
149
+ */
150
+ type AppStateCommandResult = {
151
+ platform: 'ios' | 'macos';
152
+ appName: string;
153
+ appBundleId?: string;
154
+ source: 'session';
155
+ surface: SessionSurface;
156
+ /** iOS only — the session device's UDID. */
157
+ device_udid?: string;
158
+ /** iOS only — the simulator set path, or `null` when unknown. */
159
+ ios_simulator_device_set?: string | null;
160
+ } | {
161
+ platform: 'android';
162
+ package: string;
163
+ activity: string;
49
164
  };
50
- type DeviceCommandBaseOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions;
51
165
  //#endregion
52
- //#region src/contracts/target-shutdown-contract.d.ts
166
+ //#region packages/contracts/src/target-shutdown-contract.d.ts
53
167
  type TargetShutdownResult = {
54
168
  success: boolean;
55
169
  exitCode: number;
@@ -58,67 +172,285 @@ type TargetShutdownResult = {
58
172
  error?: NormalizedError;
59
173
  };
60
174
  //#endregion
61
- //#region src/contracts/client-device-view.d.ts
62
- type AgentDeviceDevice = {
175
+ //#region packages/contracts/src/device.d.ts
176
+ /**
177
+ * Closed result of the `boot` command. Mirrors the daemon handler's only
178
+ * success return EXACTLY (src/daemon/handlers/session-state.ts) — the fixed
179
+ * object literal `{ platform, target, device, id, kind, booted }` plus the
180
+ * additive `appleOs` discriminant, emitted only for Apple devices.
181
+ */
182
+ type BootCommandResult = {
63
183
  platform: PublicPlatform;
64
184
  target: DeviceTarget;
65
- kind: DeviceKind;
185
+ /** Human-readable device name (`device.name`). */
186
+ device: string;
187
+ /** Stable device id (`device.id`). */
66
188
  id: string;
67
- name: string;
68
- booted?: boolean;
189
+ kind: DeviceKind;
190
+ /** Always `true` on the success path. */
191
+ booted: true;
69
192
  /**
70
- * Additive Apple-OS discriminant (iPhone/iPad/tvOS/visionOS/macOS). Present only for
71
- * Apple devices; `platform` still carries the leaf (`ios`/`macos`).
193
+ * Additive Apple-OS discriminant (`device.appleOs`): iPhone/iPad/tvOS/visionOS/macOS.
194
+ * Present only for Apple devices; absent for non-Apple platforms. `platform` stays the
195
+ * leaf (`ios`/`macos`) — this is an extra field, not a replacement.
72
196
  */
73
197
  appleOs?: AppleOS;
74
- identifiers: AgentDeviceIdentifiers;
75
- ios?: {
76
- udid: string;
77
- };
78
- android?: {
79
- serial: string;
80
- };
81
- vega?: {
82
- serial: string;
83
- };
84
- };
85
- type AgentDeviceCapabilitiesResult = {
86
- device: AgentDeviceDevice;
87
- availableCommands: string[];
88
198
  };
89
- type AgentDeviceSessionDevice = {
199
+ /**
200
+ * Closed result of the `shutdown` command. Mirrors the daemon handler's success
201
+ * return EXACTLY (src/daemon/handlers/session-state.ts) — the fixed object
202
+ * literal `{ platform, target, device, id, kind, shutdown }` plus the additive
203
+ * `appleOs` discriminant (Apple devices only). The `shutdown` field is the raw
204
+ * {@link TargetShutdownResult} from `shutdownDeviceTarget`.
205
+ */
206
+ type ShutdownCommandResult = {
90
207
  platform: PublicPlatform;
91
208
  target: DeviceTarget;
209
+ /** Human-readable device name (`device.name`). */
210
+ device: string;
211
+ /** Stable device id (`device.id`). */
92
212
  id: string;
93
- name: string;
213
+ kind: DeviceKind;
214
+ shutdown: TargetShutdownResult;
94
215
  /**
95
- * Additive Apple-OS discriminant (iPhone/iPad/tvOS/visionOS/macOS). Present only for
96
- * Apple devices; `platform` still carries the leaf (`ios`/`macos`).
216
+ * Additive Apple-OS discriminant (`device.appleOs`): iPhone/iPad/tvOS/visionOS/macOS.
217
+ * Present only for Apple devices; absent for non-Apple platforms. `platform` stays the
218
+ * leaf (`ios`/`macos`) — this is an extra field, not a replacement.
97
219
  */
98
220
  appleOs?: AppleOS;
99
- identifiers: AgentDeviceIdentifiers;
100
- ios?: {
101
- udid: string;
102
- simulatorSetPath?: string | null;
103
- };
104
- android?: {
105
- serial: string;
106
- };
107
- vega?: {
108
- serial: string;
109
- };
110
- };
111
- type AgentDeviceSession = {
112
- name: string;
113
- createdAt: number;
114
- sessionStateDir?: string;
115
- runnerLogPath?: string;
116
- device: AgentDeviceSessionDevice;
117
- identifiers: AgentDeviceIdentifiers;
118
221
  };
119
- type StartupPerfSample = {
120
- durationMs: number;
121
- measuredAt: string;
222
+ //#endregion
223
+ //#region packages/contracts/src/logs.d.ts
224
+ declare const LOG_ACTION_VALUES: readonly ['path', 'start', 'stop', 'doctor', 'mark', 'clear'];
225
+ type LogAction = (typeof LOG_ACTION_VALUES)[number];
226
+ //#endregion
227
+ //#region packages/contracts/src/recording-scope.d.ts
228
+ declare const RECORDING_SCOPE_VALUES: readonly ['app', 'device', 'system'];
229
+ type RecordingScope = (typeof RECORDING_SCOPE_VALUES)[number];
230
+ //#endregion
231
+ //#region packages/contracts/src/recording.d.ts
232
+ type RecordingAppIdentity = {
233
+ bundleId: string;
234
+ name?: string;
235
+ };
236
+ type RecordingStartCommandResult = {
237
+ recording: 'started';
238
+ outPath: string;
239
+ sessionStateDir: string;
240
+ recordingBackend?: string;
241
+ recordingScope?: RecordingScope;
242
+ recordOnlySession?: boolean;
243
+ activeSessionApp?: RecordingAppIdentity;
244
+ showTouches: boolean;
245
+ };
246
+ type RecordingStopCommandResult = {
247
+ recording: 'stopped';
248
+ outPath: string;
249
+ telemetryPath?: string;
250
+ artifacts: DaemonArtifact[];
251
+ recordingBackend?: string;
252
+ recordingScope?: RecordingScope;
253
+ recordOnlySession?: boolean;
254
+ activeSessionApp?: RecordingAppIdentity;
255
+ durationMs: number;
256
+ showTouches: boolean;
257
+ warning?: string;
258
+ overlayWarning?: string;
259
+ chunks?: Array<{
260
+ index: number;
261
+ path: string;
262
+ }>;
263
+ };
264
+ type RecordingCommandResult = RecordingStartCommandResult | RecordingStopCommandResult;
265
+ type TraceCommandResult = {
266
+ trace: 'started';
267
+ outPath: string;
268
+ } | {
269
+ trace: 'stopped';
270
+ outPath: string;
271
+ artifacts: DaemonArtifact[];
272
+ };
273
+ //#endregion
274
+ //#region packages/contracts/src/perf.d.ts
275
+ declare const PERF_AREA_VALUES: readonly ['metrics', 'frames', 'memory', 'cpu', 'trace'];
276
+ declare const PERF_ACTION_VALUES: readonly ['sample', 'snapshot', 'start', 'stop', 'report'];
277
+ declare const PERF_SUBJECT_VALUES: readonly ['profile'];
278
+ declare const PERF_KIND_VALUES: readonly ['xctrace', 'simpleperf', 'perfetto', 'android-hprof', 'memgraph'];
279
+ type PerfArea = (typeof PERF_AREA_VALUES)[number];
280
+ type PerfAction = (typeof PERF_ACTION_VALUES)[number];
281
+ type PerfSubject = (typeof PERF_SUBJECT_VALUES)[number];
282
+ type PerfKind = (typeof PERF_KIND_VALUES)[number];
283
+ //#endregion
284
+ //#region packages/contracts/src/recording-export-quality.d.ts
285
+ declare const RECORDING_EXPORT_QUALITIES: readonly ['medium', 'high'];
286
+ type RecordingExportQuality = (typeof RECORDING_EXPORT_QUALITIES)[number];
287
+ //#endregion
288
+ //#region packages/contracts/src/json.d.ts
289
+ type JsonPrimitive = string | number | boolean | null;
290
+ type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
291
+ type JsonObject = {
292
+ [key: string]: JsonValue;
293
+ };
294
+ //#endregion
295
+ //#region packages/contracts/src/prepare.d.ts
296
+ type PrepareIosRunnerCacheKind = 'exact' | 'restore-key' | 'miss' | 'external';
297
+ type PrepareIosRunnerArtifactState = 'valid' | 'rebuilt';
298
+ type PrepareIosRunnerTiming = {
299
+ totalMs: number;
300
+ additiveParts: {
301
+ buildMs?: number;
302
+ connectAfterBuildMs: number;
303
+ healthCheckMs: number;
304
+ };
305
+ containment: {
306
+ connectMs?: ['buildMs'];
307
+ healthCheckMs: [];
308
+ };
309
+ note: string;
310
+ };
311
+ /**
312
+ * Public daemon result for `prepare ios-runner`. The runner-local prepare result
313
+ * is projected by `prepareIosRunnerResponseData` with device identity and timing
314
+ * guidance before it reaches the client.
315
+ */
316
+ type PrepareCommandResult = {
317
+ action: 'ios-runner';
318
+ platform: PublicPlatform;
319
+ deviceId: string;
320
+ deviceName: string;
321
+ kind: DeviceKind;
322
+ durationMs: number;
323
+ runner: JsonObject;
324
+ cache?: PrepareIosRunnerCacheKind;
325
+ artifact?: PrepareIosRunnerArtifactState;
326
+ buildMs?: number;
327
+ connectMs: number;
328
+ healthCheckMs: number;
329
+ xctestrunPath?: string;
330
+ recoveryReason?: string;
331
+ failureReason?: string;
332
+ timing: PrepareIosRunnerTiming;
333
+ message: string;
334
+ };
335
+ //#endregion
336
+ //#region packages/contracts/src/push.d.ts
337
+ type PushCommandResult = {
338
+ platform: 'ios';
339
+ bundleId: string;
340
+ message: string;
341
+ } | {
342
+ platform: 'android';
343
+ package: string;
344
+ action: string;
345
+ extrasCount: number;
346
+ message: string;
347
+ };
348
+ //#endregion
349
+ //#region packages/contracts/src/client-connection.d.ts
350
+ type AgentDeviceDaemonTransportContext = {
351
+ authToken?: string;
352
+ };
353
+ type AgentDeviceDaemonTransport = (req: Omit<DaemonRequest, 'token'>, context?: AgentDeviceDaemonTransportContext) => Promise<DaemonResponse>;
354
+ type AgentDeviceClientConfig = RemoteConnectionProfileFields & CloudProviderProfileFields & {
355
+ session?: string;
356
+ lockPolicy?: DaemonLockPolicy;
357
+ lockPlatform?: PlatformSelector;
358
+ requestId?: string;
359
+ sessionIsolation?: SessionIsolationMode;
360
+ leaseBackend?: LeaseBackend;
361
+ leaseTtlMs?: number;
362
+ runtime?: SessionRuntimeHints;
363
+ cwd?: string;
364
+ debug?: boolean;
365
+ cost?: boolean;
366
+ responseLevel?: ResponseLevel;
367
+ iosXctestrunFile?: string;
368
+ iosXctestDerivedDataPath?: string;
369
+ iosXctestEnvDir?: string;
370
+ };
371
+ type AgentDeviceRequestOverrides = Pick<AgentDeviceClientConfig, 'session' | 'lockPolicy' | 'lockPlatform' | 'requestId' | 'daemonBaseUrl' | 'daemonAuthToken' | 'daemonTransport' | 'daemonServerMode' | 'tenant' | 'sessionIsolation' | 'runId' | 'leaseId' | 'leaseBackend' | 'leaseProvider' | 'deviceKey' | 'clientId' | 'providerApp' | 'providerOsVersion' | 'providerProject' | 'providerBuild' | 'providerSessionName' | 'providerDeviceOrientation' | 'providerGeoLocation' | 'providerTimezone' | 'providerLanguage' | 'providerLocale' | 'providerNetworkProfile' | 'providerCustomNetwork' | 'providerNoResignApp' | 'awsProjectArn' | 'awsDeviceArn' | 'awsAppArn' | 'awsRegion' | 'awsInteractionMode' | 'leaseTtlMs' | 'cwd' | 'debug' | 'cost' | 'responseLevel' | 'iosXctestrunFile' | 'iosXctestDerivedDataPath' | 'iosXctestEnvDir'>;
372
+ type AgentDeviceIdentifiers = {
373
+ session?: string;
374
+ deviceId?: string;
375
+ deviceName?: string;
376
+ udid?: string;
377
+ serial?: string;
378
+ appId?: string;
379
+ appBundleId?: string;
380
+ package?: string;
381
+ };
382
+ type AgentDeviceSelectionOptions = {
383
+ platform?: PlatformSelector;
384
+ target?: DeviceTarget;
385
+ device?: string;
386
+ udid?: string;
387
+ serial?: string;
388
+ iosSimulatorDeviceSet?: string;
389
+ androidDeviceAllowlist?: string;
390
+ };
391
+ type DeviceCommandBaseOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions;
392
+ //#endregion
393
+ //#region packages/contracts/src/client-device-view.d.ts
394
+ type AgentDeviceDevice = {
395
+ platform: PublicPlatform;
396
+ target: DeviceTarget;
397
+ kind: DeviceKind;
398
+ id: string;
399
+ name: string;
400
+ booted?: boolean;
401
+ /**
402
+ * Additive Apple-OS discriminant (iPhone/iPad/tvOS/visionOS/macOS). Present only for
403
+ * Apple devices; `platform` still carries the leaf (`ios`/`macos`).
404
+ */
405
+ appleOs?: AppleOS;
406
+ identifiers: AgentDeviceIdentifiers;
407
+ ios?: {
408
+ udid: string;
409
+ };
410
+ android?: {
411
+ serial: string;
412
+ };
413
+ vega?: {
414
+ serial: string;
415
+ };
416
+ };
417
+ type AgentDeviceCapabilitiesResult = {
418
+ device: AgentDeviceDevice;
419
+ availableCommands: string[];
420
+ };
421
+ type AgentDeviceSessionDevice = {
422
+ platform: PublicPlatform;
423
+ target: DeviceTarget;
424
+ id: string;
425
+ name: string;
426
+ /**
427
+ * Additive Apple-OS discriminant (iPhone/iPad/tvOS/visionOS/macOS). Present only for
428
+ * Apple devices; `platform` still carries the leaf (`ios`/`macos`).
429
+ */
430
+ appleOs?: AppleOS;
431
+ identifiers: AgentDeviceIdentifiers;
432
+ ios?: {
433
+ udid: string;
434
+ simulatorSetPath?: string | null;
435
+ };
436
+ android?: {
437
+ serial: string;
438
+ };
439
+ vega?: {
440
+ serial: string;
441
+ };
442
+ };
443
+ type AgentDeviceSession = {
444
+ name: string;
445
+ createdAt: number;
446
+ sessionStateDir?: string;
447
+ runnerLogPath?: string;
448
+ device: AgentDeviceSessionDevice;
449
+ identifiers: AgentDeviceIdentifiers;
450
+ };
451
+ type StartupPerfSample = {
452
+ durationMs: number;
453
+ measuredAt: string;
122
454
  method: string;
123
455
  appTarget?: string;
124
456
  appBundleId?: string;
@@ -128,7 +460,7 @@ type DeviceBootOptions = DeviceCommandBaseOptions & {
128
460
  };
129
461
  type DeviceShutdownOptions = DeviceCommandBaseOptions;
130
462
  //#endregion
131
- //#region src/contracts/client-app.d.ts
463
+ //#region packages/contracts/src/client-app.d.ts
132
464
  type AppInstallOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions & {
133
465
  app?: string;
134
466
  appPath: string;
@@ -233,7 +565,29 @@ type MaterializationReleaseResult = {
233
565
  identifiers: AgentDeviceIdentifiers;
234
566
  };
235
567
  //#endregion
236
- //#region src/contracts/client-capture.d.ts
568
+ //#region packages/contracts/src/snapshot-capture-annotations.d.ts
569
+ type SnapshotCaptureAnalysis = {
570
+ rawNodeCount: number;
571
+ maxDepth: number;
572
+ };
573
+ type SnapshotCaptureFreshness = {
574
+ action: string;
575
+ retryCount: number;
576
+ staleAfterRetries: boolean;
577
+ reason?: 'empty-interactive' | 'sharp-drop' | 'stuck-route';
578
+ };
579
+ type SnapshotCaptureAnnotations = {
580
+ analysis?: SnapshotCaptureAnalysis;
581
+ androidSnapshot?: AndroidSnapshotBackendMetadata;
582
+ freshness?: SnapshotCaptureFreshness;
583
+ quality?: SnapshotQualityVerdict;
584
+ warnings?: string[];
585
+ };
586
+ type PublicSnapshotCaptureAnnotations = Pick<SnapshotCaptureAnnotations, 'androidSnapshot' | 'warnings'> & {
587
+ snapshotQuality?: SnapshotQualityVerdict;
588
+ };
589
+ //#endregion
590
+ //#region packages/contracts/src/client-capture.d.ts
237
591
  type CaptureSnapshotOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions & {
238
592
  interactiveOnly?: boolean;
239
593
  depth?: number;
@@ -295,7 +649,7 @@ type CaptureDiffOptions = DeviceCommandBaseOptions & Pick<CaptureSnapshotOptions
295
649
  type SelectorSnapshotCommandOptions = Pick<CaptureSnapshotOptions, 'depth' | 'scope' | 'raw'>;
296
650
  type FindSnapshotCommandOptions = Pick<CaptureSnapshotOptions, 'depth' | 'raw'>;
297
651
  //#endregion
298
- //#region src/contracts/client-target.d.ts
652
+ //#region packages/contracts/src/client-target.d.ts
299
653
  type PointTarget = {
300
654
  x: number;
301
655
  y: number;
@@ -320,7 +674,7 @@ type SelectorTarget = {
320
674
  type InteractionTarget = PointTarget | RefTarget | SelectorTarget;
321
675
  type ElementTarget = RefTarget | SelectorTarget;
322
676
  //#endregion
323
- //#region src/contracts/client-gesture.d.ts
677
+ //#region packages/contracts/src/client-gesture.d.ts
324
678
  type RepeatedPressOptions = {
325
679
  count?: number;
326
680
  intervalMs?: number;
@@ -419,7 +773,7 @@ type ScrollOptions = DeviceCommandBaseOptions & {
419
773
  durationMs?: number;
420
774
  };
421
775
  //#endregion
422
- //#region src/contracts/client-lease.d.ts
776
+ //#region packages/contracts/src/client-lease.d.ts
423
777
  type Lease = {
424
778
  leaseId: string;
425
779
  tenantId: string;
@@ -459,25 +813,7 @@ type CloudArtifactsOptions = AgentDeviceRequestOverrides & {
459
813
  providerSessionId?: string;
460
814
  };
461
815
  //#endregion
462
- //#region src/contracts/logs.d.ts
463
- declare const LOG_ACTION_VALUES: readonly ['path', 'start', 'stop', 'doctor', 'mark', 'clear'];
464
- type LogAction = (typeof LOG_ACTION_VALUES)[number];
465
- //#endregion
466
- //#region src/contracts/perf.d.ts
467
- declare const PERF_AREA_VALUES: readonly ['metrics', 'frames', 'memory', 'cpu', 'trace'];
468
- declare const PERF_ACTION_VALUES: readonly ['sample', 'snapshot', 'start', 'stop', 'report'];
469
- declare const PERF_SUBJECT_VALUES: readonly ['profile'];
470
- declare const PERF_KIND_VALUES: readonly ['xctrace', 'simpleperf', 'perfetto', 'android-hprof', 'memgraph'];
471
- type PerfArea = (typeof PERF_AREA_VALUES)[number];
472
- type PerfAction = (typeof PERF_ACTION_VALUES)[number];
473
- type PerfSubject = (typeof PERF_SUBJECT_VALUES)[number];
474
- type PerfKind = (typeof PERF_KIND_VALUES)[number];
475
- //#endregion
476
- //#region src/contracts/recording-scope.d.ts
477
- declare const RECORDING_SCOPE_VALUES: readonly ['app', 'device', 'system'];
478
- type RecordingScope = (typeof RECORDING_SCOPE_VALUES)[number];
479
- //#endregion
480
- //#region src/contracts/client-observability.d.ts
816
+ //#region packages/contracts/src/client-observability.d.ts
481
817
  type PerfOptions = DeviceCommandBaseOptions & {
482
818
  area?: PerfArea;
483
819
  subject?: PerfSubject;
@@ -521,7 +857,7 @@ type TraceOptions = AgentDeviceRequestOverrides & {
521
857
  path?: string;
522
858
  };
523
859
  //#endregion
524
- //#region src/contracts/client-replay.d.ts
860
+ //#region packages/contracts/src/client-replay.d.ts
525
861
  type ReplayRunOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOptions & {
526
862
  path: string;
527
863
  runtime?: SessionRuntimeHints;
@@ -545,6 +881,8 @@ type ReplayRunOptions = AgentDeviceRequestOverrides & AgentDeviceSelectionOption
545
881
  resumeFrom?: number;
546
882
  /** The `resume.planDigest` from the divergence report `resumeFrom` came from. */
547
883
  resumePlanDigest?: string;
884
+ /** Leave the session active by suppressing an authored terminal `close` in native `.ad`. */
885
+ keepSession?: boolean;
548
886
  /**
549
887
  * ADR 0012 decision 6, R1/R6: arms agent-supervised re-record repair
550
888
  * from this replay attempt onward. Optional string value is the healed
@@ -585,10 +923,10 @@ type BatchRunOptions = AgentDeviceRequestOverrides & {
585
923
  out?: string;
586
924
  };
587
925
  //#endregion
588
- //#region src/contracts/client-request.d.ts
926
+ //#region packages/contracts/src/client-request.d.ts
589
927
  type CommandRequestResult = DaemonResponseData;
590
928
  //#endregion
591
- //#region src/contracts/client-selector-read.d.ts
929
+ //#region packages/contracts/src/client-selector-read.d.ts
592
930
  /**
593
931
  * #1271 stage 2 (ADR 0012 amendment): `get`/`is`/`find` are observation-only
594
932
  * and excluded from a repair-armed heal by default. `record` forces this
@@ -629,7 +967,7 @@ type FindOptions = (FindBaseOptions & {
629
967
  value: string;
630
968
  });
631
969
  //#endregion
632
- //#region src/contracts/client-session.d.ts
970
+ //#region packages/contracts/src/client-session.d.ts
633
971
  type SessionCloseResult = {
634
972
  session: string;
635
973
  shutdown?: TargetShutdownResult;
@@ -654,7 +992,7 @@ type SessionSaveScriptResult = {
654
992
  identifiers: AgentDeviceIdentifiers;
655
993
  };
656
994
  //#endregion
657
- //#region src/contracts/client-settings.d.ts
995
+ //#region packages/contracts/src/client-settings.d.ts
658
996
  type PermissionTarget = 'camera' | 'microphone' | 'photos' | 'contacts' | 'contacts-limited' | 'notifications' | 'calendar' | 'location' | 'location-always' | 'media-library' | 'motion' | 'reminders' | 'siri' | 'accessibility' | 'screen-recording' | 'input-monitoring';
659
997
  type SettingsUpdateOptions = (DeviceCommandBaseOptions & {
660
998
  setting: 'clear-app-state';
@@ -687,7 +1025,7 @@ type SettingsUpdateOptions = (DeviceCommandBaseOptions & {
687
1025
  mode?: 'full' | 'limited';
688
1026
  });
689
1027
  //#endregion
690
- //#region src/contracts/client-system.d.ts
1028
+ //#region packages/contracts/src/client-system.d.ts
691
1029
  type WaitCommandTarget = {
692
1030
  durationMs: number;
693
1031
  text?: never;
@@ -734,399 +1072,130 @@ type AlertCommandOptions = DeviceCommandBaseOptions & {
734
1072
  action?: AlertAction;
735
1073
  timeoutMs?: number;
736
1074
  };
737
- type AppStateCommandOptions = DeviceCommandBaseOptions;
738
- type KeyboardCommandOptions = DeviceCommandBaseOptions & {
739
- action?: 'status' | 'dismiss' | 'enter' | 'return';
740
- };
741
- type ClipboardCommandOptions = (DeviceCommandBaseOptions & {
742
- action: 'read';
743
- }) | (DeviceCommandBaseOptions & {
744
- action: 'write';
745
- text: string;
746
- });
747
- type ReactNativeCommandOptions = DeviceCommandBaseOptions & {
748
- action: 'dismiss-overlay';
749
- };
750
- type PrepareCommandOptions = DeviceCommandBaseOptions & {
751
- action: 'ios-runner';
752
- timeoutMs?: number;
753
- };
754
- type DoctorCommandOptions = DeviceCommandBaseOptions & {
755
- targetApp?: string;
756
- remote?: boolean;
757
- };
758
- type ViewportCommandOptions = DeviceCommandBaseOptions & {
759
- width: number;
760
- height: number;
761
- };
762
- //#endregion
763
- //#region src/contracts/navigation.d.ts
764
- /**
765
- * Closed results of the navigation/global action commands. Each mirrors the
766
- * dispatch handler's literal return EXACTLY (src/core/dispatch.ts
767
- * `DISPATCH_HANDLERS`): a fixed `action` discriminant plus the always-present
768
- * `successText` message (the handlers always pass a non-empty message, so it is
769
- * required here). The handlers spread nothing else, so the shapes are closed —
770
- * consistent with the `viewport` contract, the generic-dispatch Android
771
- * dialog-recovery `warning` annotation is intentionally not part of the contract.
772
- */
773
- /** `home` — `{ action: 'home', message: 'Home' }`. */
774
- type HomeCommandResult = {
775
- action: 'home';
776
- message: string;
777
- };
778
- /** `back` — `{ action: 'back', mode, message: 'Back' }`; `mode` defaults to `'in-app'`. */
779
- type BackCommandResult = {
780
- action: 'back';
781
- mode: BackMode;
782
- message: string;
783
- };
784
- /** `orientation` — `{ action: 'orientation', orientation, message: 'Rotated to <orientation>' }`. */
785
- type OrientationCommandResult = {
786
- action: 'orientation';
787
- orientation: DeviceRotation;
788
- message: string;
789
- };
790
- /**
791
- * @deprecated The `rotate` command was renamed to `orientation`. This is the
792
- * legacy response contract (`action: 'rotate'`) that shipped in v0.18/v0.19,
793
- * retained for existing SDK consumers until the next major version. New code
794
- * should use {@link OrientationCommandResult}.
795
- */
796
- type RotateCommandResult = {
797
- action: 'rotate';
798
- orientation: DeviceRotation;
799
- message: string;
800
- };
801
- /** `app-switcher` — `{ action: 'app-switcher', message: 'Opened app switcher' }`. */
802
- type AppSwitcherCommandResult = {
803
- action: 'app-switcher';
804
- message: string;
805
- };
806
- /** `tv-remote` — `{ action: 'tv-remote', button, durationMs?, message }`. */
807
- type TvRemoteCommandResult = {
808
- action: 'tv-remote';
809
- button: TvRemoteButton;
810
- durationMs?: number;
811
- message: string;
812
- };
813
- //#endregion
814
- //#region src/commands/command-contract.d.ts
815
- type JsonSchema = {
816
- type?: string | readonly string[];
817
- description?: string;
818
- properties?: Record<string, JsonSchema>;
819
- required?: readonly string[];
820
- additionalProperties?: boolean | JsonSchema;
821
- items?: JsonSchema;
822
- prefixItems?: readonly JsonSchema[];
823
- oneOf?: readonly JsonSchema[];
824
- enum?: readonly unknown[];
825
- const?: unknown;
826
- minimum?: number;
827
- maximum?: number;
828
- };
829
- type ExecutableCommandProjection<ClientMethod extends string = string> = {
830
- clientMethod: ClientMethod;
831
- outputSchema: JsonSchema;
832
- };
833
- //#endregion
834
- //#region src/commands/system/navigation-projection.d.ts
835
- declare const navigationCommandProjectionType: unique symbol;
836
- type NavigationCommandProjection<Options, Result, Required extends boolean, ClientMethod extends string> = ExecutableCommandProjection<ClientMethod> & {
837
- readonly [navigationCommandProjectionType]?: {
838
- options: Options;
839
- result: Result;
840
- required: Required;
841
- };
842
- };
843
- declare const NAVIGATION_COMMAND_PROJECTIONS: {
844
- readonly back: NavigationCommandProjection<{
845
- mode?: BackMode;
846
- }, BackCommandResult, false, "back">;
847
- readonly home: NavigationCommandProjection<{}, HomeCommandResult, false, "home">;
848
- readonly orientation: NavigationCommandProjection<{
849
- orientation: DeviceRotation;
850
- }, OrientationCommandResult, true, "orientation">;
851
- readonly 'app-switcher': NavigationCommandProjection<{}, AppSwitcherCommandResult, false, "appSwitcher">;
852
- readonly 'tv-remote': NavigationCommandProjection<{
853
- button: TvRemoteButton;
854
- durationMs?: number;
855
- }, TvRemoteCommandResult, true, "tvRemote">;
856
- };
857
- type NavigationCommandName = keyof typeof NAVIGATION_COMMAND_PROJECTIONS;
858
- type NavigationCommandOptions<Name extends NavigationCommandName> = (typeof NAVIGATION_COMMAND_PROJECTIONS)[Name] extends NavigationCommandProjection<infer Options, unknown, boolean, string> ? Options : never;
859
- type ProjectedNavigationCommandMethod<BaseOptions, Projection> = Projection extends NavigationCommandProjection<infer Options, infer Result, infer Required, string> ? Required extends true ? (options: BaseOptions & Options) => Promise<Result> : (options?: BaseOptions & Options) => Promise<Result> : never;
860
- type ProjectedNavigationCommandClient<BaseOptions> = { [Name in NavigationCommandName as (typeof NAVIGATION_COMMAND_PROJECTIONS)[Name]['clientMethod']]: ProjectedNavigationCommandMethod<BaseOptions, (typeof NAVIGATION_COMMAND_PROJECTIONS)[Name]>; };
861
- //#endregion
862
- //#region src/contracts/debug-symbols.d.ts
863
- type DebugSymbolsOptions = {
864
- action?: 'symbols';
865
- artifact: string;
866
- dsym?: string;
867
- searchPath?: string;
868
- out?: string;
869
- cwd?: string;
870
- };
871
- type DebugSymbolsImage = {
872
- name: string;
873
- uuid: string;
874
- arch?: string;
875
- dsymPath: string;
876
- binaryPath: string;
877
- };
878
- type DebugSymbolsCrashFrame = {
879
- index: number;
880
- image: string;
881
- address: string;
882
- symbol?: string;
883
- };
884
- type DebugSymbolsCrashSummary = {
885
- format: 'ips' | 'text';
886
- appName?: string;
887
- bundleId?: string;
888
- version?: string;
889
- incident?: string;
890
- timestamp?: string;
891
- exceptionType?: string;
892
- exceptionCodes?: string;
893
- terminationReason?: string;
894
- crashedThread?: number;
895
- topFrames: DebugSymbolsCrashFrame[];
896
- findings: string[];
897
- };
898
- type DebugSymbolsResult = {
899
- kind: 'debugSymbols';
900
- platform: 'apple';
901
- artifactPath: string;
902
- outPath: string;
903
- crash: DebugSymbolsCrashSummary;
904
- matchedImages: DebugSymbolsImage[];
905
- symbolicatedFrames: number;
906
- skippedImages: number;
907
- warnings?: string[];
908
- message: string;
909
- };
910
- //#endregion
911
- //#region src/contracts/device.d.ts
912
- /**
913
- * Closed result of the `boot` command. Mirrors the daemon handler's only
914
- * success return EXACTLY (src/daemon/handlers/session-state.ts) — the fixed
915
- * object literal `{ platform, target, device, id, kind, booted }` plus the
916
- * additive `appleOs` discriminant, emitted only for Apple devices.
917
- */
918
- type BootCommandResult = {
919
- platform: PublicPlatform;
920
- target: DeviceTarget;
921
- /** Human-readable device name (`device.name`). */
922
- device: string;
923
- /** Stable device id (`device.id`). */
924
- id: string;
925
- kind: DeviceKind;
926
- /** Always `true` on the success path. */
927
- booted: true;
928
- /**
929
- * Additive Apple-OS discriminant (`device.appleOs`): iPhone/iPad/tvOS/visionOS/macOS.
930
- * Present only for Apple devices; absent for non-Apple platforms. `platform` stays the
931
- * leaf (`ios`/`macos`) — this is an extra field, not a replacement.
932
- */
933
- appleOs?: AppleOS;
934
- };
935
- /**
936
- * Closed result of the `shutdown` command. Mirrors the daemon handler's success
937
- * return EXACTLY (src/daemon/handlers/session-state.ts) — the fixed object
938
- * literal `{ platform, target, device, id, kind, shutdown }` plus the additive
939
- * `appleOs` discriminant (Apple devices only). The `shutdown` field is the raw
940
- * {@link TargetShutdownResult} from `shutdownDeviceTarget`.
941
- */
942
- type ShutdownCommandResult = {
943
- platform: PublicPlatform;
944
- target: DeviceTarget;
945
- /** Human-readable device name (`device.name`). */
946
- device: string;
947
- /** Stable device id (`device.id`). */
948
- id: string;
949
- kind: DeviceKind;
950
- shutdown: TargetShutdownResult;
951
- /**
952
- * Additive Apple-OS discriminant (`device.appleOs`): iPhone/iPad/tvOS/visionOS/macOS.
953
- * Present only for Apple devices; absent for non-Apple platforms. `platform` stays the
954
- * leaf (`ios`/`macos`) — this is an extra field, not a replacement.
955
- */
956
- appleOs?: AppleOS;
957
- };
958
- //#endregion
959
- //#region src/contracts/viewport.d.ts
960
- /**
961
- * Closed result of the `viewport` command. Mirrors the dispatch handler's return
962
- * EXACTLY (src/core/dispatch.ts `handleViewportCommand`) — `{ width, height }`
963
- * plus the always-present `successText` message. The generic dispatch path
964
- * returns this object unchanged (viewport has no Android dialog guard, so no
965
- * `warning` is ever appended), so the shape is intentionally closed.
966
- */
967
- type ViewportCommandResult = {
968
- width: number;
969
- height: number;
970
- message: string;
971
- };
972
- //#endregion
973
- //#region src/contracts/clipboard.d.ts
974
- /**
975
- * Closed result of the `clipboard` command. Mirrors the dispatch handler's
976
- * literal return EXACTLY (src/core/dispatch.ts `handleClipboardCommand`): a
977
- * discriminated union on `action`. `read` returns the clipboard `text`; `write`
978
- * reports the written `textLength` plus the `successText` message. The handler
979
- * spreads nothing else, so each branch is closed.
980
- */
981
- type ClipboardCommandResult = {
982
- action: 'read';
983
- text: string;
984
- } | {
985
- action: 'write';
986
- textLength: number;
987
- message: string;
988
- };
989
- //#endregion
990
- //#region src/contracts/app-state.d.ts
991
- /**
992
- * Closed result of the `appstate` command, grounded in the daemon handler's
993
- * success returns (src/daemon/handlers/session-state.ts `handleAppStateCommand`).
994
- * A discriminated union on `platform`:
995
- * - Apple (`ios` / `macos`) session state, with iOS-only device locators that
996
- * the previous hand-written mirror omitted; and
997
- * - Android foreground `package` / `activity`.
998
- *
999
- * The handler returns one of these fixed objects (errors take the `ok: false`
1000
- * path), so each branch is closed.
1001
- */
1002
- type AppStateCommandResult = {
1003
- platform: 'ios' | 'macos';
1004
- appName: string;
1005
- appBundleId?: string;
1006
- source: 'session';
1007
- surface: SessionSurface;
1008
- /** iOS only — the session device's UDID. */
1009
- device_udid?: string;
1010
- /** iOS only — the simulator set path, or `null` when unknown. */
1011
- ios_simulator_device_set?: string | null;
1012
- } | {
1013
- platform: 'android';
1014
- package: string;
1015
- activity: string;
1016
- };
1017
- //#endregion
1018
- //#region src/contracts/keyboard.d.ts
1019
- /**
1020
- * Closed result of the `keyboard` command, grounded in the dispatch handlers'
1021
- * literal returns (src/core/dispatch.ts `handleAndroidKeyboardCommand` /
1022
- * `handleIosKeyboardCommand`).
1023
- *
1024
- * `platform` and `action` are always present; the remaining fields appear per
1025
- * branch (Android `status`/`dismiss` carry the keyboard-state fields; `enter`
1026
- * and iOS `dismiss` carry a `message`). It is kept as a flat closed shape rather
1027
- * than a five-way `platform`×`action` union because the per-branch field sets
1028
- * overlap heavily and the underlying Android keyboard-state types live in the
1029
- * platform layer (below the public contract). The `Record` index signature of
1030
- * the previous hand-written mirror is dropped, and the spurious `| null`s are
1031
- * removed (the handler never returns `null` for these).
1032
- */
1033
- type KeyboardCommandResult = {
1034
- platform: 'android' | 'ios';
1035
- action: 'status' | 'dismiss' | 'enter';
1036
- visible?: boolean;
1037
- wasVisible?: boolean;
1038
- dismissed?: boolean;
1039
- attempts?: number;
1040
- inputType?: string;
1041
- type?: 'text' | 'number' | 'email' | 'phone' | 'password' | 'datetime' | 'unknown';
1042
- inputMethodPackage?: string;
1043
- focusedPackage?: string;
1044
- focusedResourceId?: string;
1045
- inputOwner?: 'app' | 'ime' | 'unknown';
1046
- message?: string;
1075
+ type AppStateCommandOptions = DeviceCommandBaseOptions;
1076
+ type KeyboardCommandOptions = DeviceCommandBaseOptions & {
1077
+ action?: 'status' | 'dismiss' | 'enter' | 'return';
1078
+ };
1079
+ type ClipboardCommandOptions = (DeviceCommandBaseOptions & {
1080
+ action: 'read';
1081
+ }) | (DeviceCommandBaseOptions & {
1082
+ action: 'write';
1083
+ text: string;
1084
+ });
1085
+ type ReactNativeCommandOptions = DeviceCommandBaseOptions & {
1086
+ action: 'dismiss-overlay';
1087
+ };
1088
+ type PrepareCommandOptions = DeviceCommandBaseOptions & {
1089
+ action: 'ios-runner';
1090
+ timeoutMs?: number;
1091
+ };
1092
+ type DoctorCommandOptions = DeviceCommandBaseOptions & {
1093
+ targetApp?: string;
1094
+ remote?: boolean;
1095
+ };
1096
+ type ViewportCommandOptions = DeviceCommandBaseOptions & {
1097
+ width: number;
1098
+ height: number;
1047
1099
  };
1048
1100
  //#endregion
1049
- //#region src/contracts/wait.d.ts
1050
- /**
1051
- * Public daemon result for `wait`. The runtime-local result carries a `kind`
1052
- * discriminant, but `toDaemonWaitData` intentionally projects the normal daemon
1053
- * payload to this compact shape. The direct iOS selector fast path may still
1054
- * include `kind: 'selector'` additively.
1055
- */
1056
- type WaitCommandResult = {
1057
- waitedMs: number;
1058
- kind?: 'selector';
1059
- text?: string;
1060
- selector?: string;
1061
- captures?: number;
1062
- nodeCount?: number;
1063
- hint?: string;
1064
- warning?: string;
1101
+ //#region src/commands/command-contract.d.ts
1102
+ type JsonSchema = {
1103
+ type?: string | readonly string[];
1104
+ description?: string;
1105
+ properties?: Record<string, JsonSchema>;
1106
+ required?: readonly string[];
1107
+ additionalProperties?: boolean | JsonSchema;
1108
+ items?: JsonSchema;
1109
+ prefixItems?: readonly JsonSchema[];
1110
+ oneOf?: readonly JsonSchema[];
1111
+ enum?: readonly unknown[];
1112
+ const?: unknown;
1113
+ minimum?: number;
1114
+ maximum?: number;
1115
+ };
1116
+ type ExecutableCommandProjection<ClientMethod extends string = string> = {
1117
+ clientMethod: ClientMethod;
1118
+ outputSchema: JsonSchema;
1065
1119
  };
1066
1120
  //#endregion
1067
- //#region src/contracts/prepare.d.ts
1068
- type PrepareIosRunnerCacheKind = 'exact' | 'restore-key' | 'miss' | 'external';
1069
- type PrepareIosRunnerArtifactState = 'valid' | 'rebuilt';
1070
- type PrepareIosRunnerTiming = {
1071
- totalMs: number;
1072
- additiveParts: {
1073
- buildMs?: number;
1074
- connectAfterBuildMs: number;
1075
- healthCheckMs: number;
1076
- };
1077
- containment: {
1078
- connectMs?: ['buildMs'];
1079
- healthCheckMs: [];
1121
+ //#region src/commands/system/navigation-projection.d.ts
1122
+ declare const navigationCommandProjectionType: unique symbol;
1123
+ type NavigationCommandProjection<Options, Result, Required extends boolean, ClientMethod extends string> = ExecutableCommandProjection<ClientMethod> & {
1124
+ readonly [navigationCommandProjectionType]?: {
1125
+ options: Options;
1126
+ result: Result;
1127
+ required: Required;
1080
1128
  };
1081
- note: string;
1082
1129
  };
1083
- /**
1084
- * Public daemon result for `prepare ios-runner`. The runner-local prepare result
1085
- * is projected by `prepareIosRunnerResponseData` with device identity and timing
1086
- * guidance before it reaches the client.
1087
- */
1088
- type PrepareCommandResult = {
1089
- action: 'ios-runner';
1090
- platform: PublicPlatform;
1091
- deviceId: string;
1092
- deviceName: string;
1093
- kind: DeviceKind;
1094
- durationMs: number;
1095
- runner: JsonObject;
1096
- cache?: PrepareIosRunnerCacheKind;
1097
- artifact?: PrepareIosRunnerArtifactState;
1098
- buildMs?: number;
1099
- connectMs: number;
1100
- healthCheckMs: number;
1101
- xctestrunPath?: string;
1102
- recoveryReason?: string;
1103
- failureReason?: string;
1104
- timing: PrepareIosRunnerTiming;
1105
- message: string;
1130
+ declare const NAVIGATION_COMMAND_PROJECTIONS: {
1131
+ readonly back: NavigationCommandProjection<{
1132
+ mode?: BackMode;
1133
+ }, BackCommandResult, false, "back">;
1134
+ readonly home: NavigationCommandProjection<{}, HomeCommandResult, false, "home">;
1135
+ readonly orientation: NavigationCommandProjection<{
1136
+ orientation: DeviceRotation;
1137
+ }, OrientationCommandResult, true, "orientation">;
1138
+ readonly 'app-switcher': NavigationCommandProjection<{}, AppSwitcherCommandResult, false, "appSwitcher">;
1139
+ readonly 'tv-remote': NavigationCommandProjection<{
1140
+ button: TvRemoteButton;
1141
+ durationMs?: number;
1142
+ }, TvRemoteCommandResult, true, "tvRemote">;
1106
1143
  };
1144
+ type NavigationCommandName = keyof typeof NAVIGATION_COMMAND_PROJECTIONS;
1145
+ type NavigationCommandOptions<Name extends NavigationCommandName> = (typeof NAVIGATION_COMMAND_PROJECTIONS)[Name] extends NavigationCommandProjection<infer Options, unknown, boolean, string> ? Options : never;
1146
+ type ProjectedNavigationCommandMethod<BaseOptions, Projection> = Projection extends NavigationCommandProjection<infer Options, infer Result, infer Required, string> ? Required extends true ? (options: BaseOptions & Options) => Promise<Result> : (options?: BaseOptions & Options) => Promise<Result> : never;
1147
+ type ProjectedNavigationCommandClient<BaseOptions> = { [Name in NavigationCommandName as (typeof NAVIGATION_COMMAND_PROJECTIONS)[Name]['clientMethod']]: ProjectedNavigationCommandMethod<BaseOptions, (typeof NAVIGATION_COMMAND_PROJECTIONS)[Name]>; };
1107
1148
  //#endregion
1108
- //#region src/contracts/push.d.ts
1109
- type PushCommandResult = {
1110
- platform: 'ios';
1111
- bundleId: string;
1112
- message: string;
1113
- } | {
1114
- platform: 'android';
1115
- package: string;
1116
- action: string;
1117
- extrasCount: number;
1118
- message: string;
1149
+ //#region packages/contracts/src/debug-symbols.d.ts
1150
+ type DebugSymbolsOptions = {
1151
+ action?: 'symbols';
1152
+ artifact: string;
1153
+ dsym?: string;
1154
+ searchPath?: string;
1155
+ out?: string;
1156
+ cwd?: string;
1119
1157
  };
1120
- //#endregion
1121
- //#region src/contracts/app-events.d.ts
1122
- type TriggerAppEventCommandResult = {
1123
- event: string;
1124
- eventUrl: string;
1125
- transport: 'deep-link';
1158
+ type DebugSymbolsImage = {
1159
+ name: string;
1160
+ uuid: string;
1161
+ arch?: string;
1162
+ dsymPath: string;
1163
+ binaryPath: string;
1164
+ };
1165
+ type DebugSymbolsCrashFrame = {
1166
+ index: number;
1167
+ image: string;
1168
+ address: string;
1169
+ symbol?: string;
1170
+ };
1171
+ type DebugSymbolsCrashSummary = {
1172
+ format: 'ips' | 'text';
1173
+ appName?: string;
1174
+ bundleId?: string;
1175
+ version?: string;
1176
+ incident?: string;
1177
+ timestamp?: string;
1178
+ exceptionType?: string;
1179
+ exceptionCodes?: string;
1180
+ terminationReason?: string;
1181
+ crashedThread?: number;
1182
+ topFrames: DebugSymbolsCrashFrame[];
1183
+ findings: string[];
1184
+ };
1185
+ type DebugSymbolsResult = {
1186
+ kind: 'debugSymbols';
1187
+ platform: 'apple';
1188
+ artifactPath: string;
1189
+ outPath: string;
1190
+ crash: DebugSymbolsCrashSummary;
1191
+ matchedImages: DebugSymbolsImage[];
1192
+ symbolicatedFrames: number;
1193
+ skippedImages: number;
1194
+ warnings?: string[];
1126
1195
  message: string;
1127
1196
  };
1128
1197
  //#endregion
1129
- //#region src/contracts/doctor.d.ts
1198
+ //#region packages/contracts/src/doctor.d.ts
1130
1199
  type DoctorStatus = 'pass' | 'warn' | 'fail' | 'info';
1131
1200
  type DoctorKind = 'auto' | 'react-native' | 'expo' | 'repack';
1132
1201
  type DoctorCheck = {
@@ -1151,15 +1220,13 @@ type DoctorCommandResult = {
1151
1220
  checks: DoctorCheck[];
1152
1221
  };
1153
1222
  //#endregion
1154
- //#region src/snapshot/snapshot-diff.d.ts
1223
+ //#region packages/contracts/src/diff.d.ts
1155
1224
  type SnapshotDiffLine = {
1156
1225
  kind: 'added' | 'removed' | 'unchanged';
1157
1226
  text: string;
1158
1227
  /**
1159
- * Plain ref body (`e12`) of the CURRENT-tree node behind an added line.
1160
- * Only populated with `withRefs` (interaction `--settle`, #1101) so the
1161
- * `diff` command's wire shape stays byte-identical. Removed/unchanged lines
1162
- * never carry it: a removed line's ref names a node of the replaced tree.
1228
+ * Plain ref body (`e12`) of the current-tree node behind an added line.
1229
+ * Only populated with `withRefs`; removed and unchanged lines never carry it.
1163
1230
  */
1164
1231
  ref?: string;
1165
1232
  };
@@ -1168,8 +1235,6 @@ type SnapshotDiffSummary = {
1168
1235
  removals: number;
1169
1236
  unchanged: number;
1170
1237
  };
1171
- //#endregion
1172
- //#region src/contracts/diff.d.ts
1173
1238
  type DiffSnapshotCommandResult = {
1174
1239
  mode: 'snapshot';
1175
1240
  baselineInitialized: boolean;
@@ -1178,59 +1243,31 @@ type DiffSnapshotCommandResult = {
1178
1243
  warnings?: string[];
1179
1244
  };
1180
1245
  //#endregion
1181
- //#region src/contracts/recording.d.ts
1182
- type RecordingAppIdentity = {
1183
- bundleId: string;
1184
- name?: string;
1185
- };
1186
- type RecordingStartCommandResult = {
1187
- recording: 'started';
1188
- outPath: string;
1189
- sessionStateDir: string;
1190
- recordingBackend?: string;
1191
- recordingScope?: RecordingScope;
1192
- recordOnlySession?: boolean;
1193
- activeSessionApp?: RecordingAppIdentity;
1194
- showTouches: boolean;
1195
- };
1196
- type RecordingStopCommandResult = {
1197
- recording: 'stopped';
1198
- outPath: string;
1199
- telemetryPath?: string;
1200
- artifacts: DaemonArtifact[];
1201
- recordingBackend?: string;
1202
- recordingScope?: RecordingScope;
1203
- recordOnlySession?: boolean;
1204
- activeSessionApp?: RecordingAppIdentity;
1205
- durationMs: number;
1206
- showTouches: boolean;
1207
- warning?: string;
1208
- overlayWarning?: string;
1209
- chunks?: Array<{
1210
- index: number;
1211
- path: string;
1212
- }>;
1213
- };
1214
- type RecordingCommandResult = RecordingStartCommandResult | RecordingStopCommandResult;
1215
- type TraceCommandResult = {
1216
- trace: 'started';
1217
- outPath: string;
1218
- } | {
1219
- trace: 'stopped';
1220
- outPath: string;
1246
+ //#region packages/contracts/src/viewport.d.ts
1247
+ /**
1248
+ * Closed result of the `viewport` command. Mirrors the dispatch handler's return
1249
+ * EXACTLY (src/core/dispatch.ts `handleViewportCommand`) — `{ width, height }`
1250
+ * plus the always-present `successText` message. The generic dispatch path
1251
+ * returns this object unchanged (viewport has no Android dialog guard, so no
1252
+ * `warning` is ever appended), so the shape is intentionally closed.
1253
+ */
1254
+ type ViewportCommandResult = {
1255
+ width: number;
1256
+ height: number;
1257
+ message: string;
1221
1258
  };
1222
1259
  //#endregion
1223
- //#region src/contracts/replay.d.ts
1260
+ //#region packages/contracts/src/replay.d.ts
1224
1261
  type ReplayCommandResult = {
1225
1262
  replayed: number;
1226
1263
  healed: number;
1227
1264
  session: string;
1228
1265
  /**
1229
1266
  * True iff `session` still exists in the daemon's session store when the
1230
- * response is built — i.e. the replayed script had no terminal `close`
1231
- * (ADR 0016's consumption contract). The client uses this, not script
1232
- * parsing, to decide whether an owned one-shot daemon must stay alive so
1233
- * the caller can keep addressing this session.
1267
+ * response is built. This remains true when replay suppresses an authored
1268
+ * terminal `close` for an explicit live-session handoff. The client uses
1269
+ * this, not script parsing, to decide whether an owned one-shot daemon must
1270
+ * stay alive so the caller can keep addressing this session.
1234
1271
  */
1235
1272
  sessionActive: boolean;
1236
1273
  artifactPaths: string[];
@@ -1304,7 +1341,7 @@ type ReplaySuiteResult = {
1304
1341
  /**
1305
1342
  * The additive typed-result spine (ADR-0008, Phase 1 step 6).
1306
1343
  *
1307
- * Maps a command name to the per-command result type from `src/contracts/*`. It
1344
+ * Maps a command name to the per-command result type from `@agent-device/contracts`. It
1308
1345
  * is SEEDED, not exhaustive: a command is listed here only once its accurate,
1309
1346
  * closed result shape lives in the contracts layer. Commands whose daemon
1310
1347
  * handler spreads dynamic/Record data (screenshot overlays, gesture