agent-device 0.14.9 → 0.15.1
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.
- package/README.md +7 -4
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.14.9.apk → agent-device-android-snapshot-helper-0.15.1.apk} +0 -0
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.15.1.apk.sha256 +1 -0
- package/android-snapshot-helper/dist/{agent-device-android-snapshot-helper-0.14.9.manifest.json → agent-device-android-snapshot-helper-0.15.1.manifest.json} +6 -6
- package/dist/src/1393.js +1 -0
- package/dist/src/1769.js +7 -0
- package/dist/src/1974.js +2 -2
- package/dist/src/208.js +1 -1
- package/dist/src/2151.js +434 -0
- package/dist/src/221.js +4 -4
- package/dist/src/2842.js +1 -0
- package/dist/src/3572.js +1 -0
- package/dist/src/4057.js +1 -1
- package/dist/src/4829.js +1 -1
- package/dist/src/9542.js +2 -2
- package/dist/src/9639.js +2 -2
- package/dist/src/989.js +1 -1
- package/dist/src/android-adb.d.ts +38 -9
- package/dist/src/android-adb.js +1 -1
- package/dist/src/android-snapshot-helper.d.ts +23 -0
- package/dist/src/cli.js +60 -57
- package/dist/src/contracts.d.ts +1 -0
- package/dist/src/finders.d.ts +1 -0
- package/dist/src/index.d.ts +56 -27
- package/dist/src/internal/companion-tunnel.js +1 -1
- package/dist/src/internal/daemon.js +51 -23
- package/dist/src/remote-config.d.ts +17 -14
- package/dist/src/selectors.d.ts +2 -0
- package/dist/src/server.js +2 -20
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/xcshareddata/xcschemes/AgentDeviceRunner.xcscheme +7 -1
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Alert.swift +155 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +131 -72
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +734 -10
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +89 -16
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +5 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +9 -0
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +4 -3
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +1 -2
- package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests.xctestplan +26 -0
- package/ios-runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +7 -1
- package/package.json +30 -11
- package/server.json +3 -3
- package/skills/agent-device/SKILL.md +2 -7
- package/android-snapshot-helper/dist/agent-device-android-snapshot-helper-0.14.9.apk.sha256 +0 -1
- package/dist/src/180.js +0 -1
- package/dist/src/6108.js +0 -26
- package/dist/src/6642.js +0 -1
- package/dist/src/7462.js +0 -1
- package/dist/src/8809.js +0 -8
- package/dist/src/command-schema.js +0 -382
|
@@ -72,6 +72,21 @@ extension RunnerTests {
|
|
|
72
72
|
|
|
73
73
|
// MARK: - Target Activation
|
|
74
74
|
|
|
75
|
+
func ensureRunnerHostAppActive(reason: String) {
|
|
76
|
+
NSLog(
|
|
77
|
+
"AGENT_DEVICE_RUNNER_HOST_ACTIVATE state=%d reason=%@",
|
|
78
|
+
app.state.rawValue,
|
|
79
|
+
reason
|
|
80
|
+
)
|
|
81
|
+
if app.state == .unknown || app.state == .notRunning {
|
|
82
|
+
app.launch()
|
|
83
|
+
} else if app.state != .runningForeground {
|
|
84
|
+
app.activate()
|
|
85
|
+
}
|
|
86
|
+
currentApp = app
|
|
87
|
+
currentBundleId = nil
|
|
88
|
+
}
|
|
89
|
+
|
|
75
90
|
func targetNeedsActivation(_ target: XCUIApplication) -> Bool {
|
|
76
91
|
let state = target.state
|
|
77
92
|
#if os(macOS)
|
|
@@ -88,6 +103,24 @@ extension RunnerTests {
|
|
|
88
103
|
return false
|
|
89
104
|
}
|
|
90
105
|
|
|
106
|
+
func canUseFastForegroundAppGuard(
|
|
107
|
+
activeApp: XCUIApplication,
|
|
108
|
+
requestedBundleId: String?,
|
|
109
|
+
command: CommandType
|
|
110
|
+
) -> Bool {
|
|
111
|
+
guard let requestedBundleId, currentBundleId == requestedBundleId, currentApp != nil else {
|
|
112
|
+
return false
|
|
113
|
+
}
|
|
114
|
+
guard activeApp.state == .runningForeground else { return false }
|
|
115
|
+
NSLog(
|
|
116
|
+
"AGENT_DEVICE_RUNNER_FAST_APP_GUARD command=%@ bundle=%@ state=%d",
|
|
117
|
+
String(describing: command),
|
|
118
|
+
requestedBundleId,
|
|
119
|
+
activeApp.state.rawValue
|
|
120
|
+
)
|
|
121
|
+
return true
|
|
122
|
+
}
|
|
123
|
+
|
|
91
124
|
func activateTarget(bundleId: String, reason: String) -> XCUIApplication {
|
|
92
125
|
let target = XCUIApplication(bundleIdentifier: bundleId)
|
|
93
126
|
NSLog(
|
|
@@ -109,31 +142,53 @@ extension RunnerTests {
|
|
|
109
142
|
operation: () -> Void
|
|
110
143
|
) {
|
|
111
144
|
let setter = NSSelectorFromString("setWaitForIdleTimeout:")
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
145
|
+
let supportsWaitForIdleTimeout = target.responds(to: setter)
|
|
146
|
+
let previous = supportsWaitForIdleTimeout
|
|
147
|
+
? (target.value(forKey: "waitForIdleTimeout") as? NSNumber)
|
|
148
|
+
: nil
|
|
149
|
+
if supportsWaitForIdleTimeout {
|
|
150
|
+
target.setValue(scrollInteractionIdleTimeoutDefault, forKey: "waitForIdleTimeout")
|
|
115
151
|
}
|
|
116
|
-
let previous = target.value(forKey: "waitForIdleTimeout") as? NSNumber
|
|
117
|
-
target.setValue(resolveScrollInteractionIdleTimeout(), forKey: "waitForIdleTimeout")
|
|
118
152
|
defer {
|
|
119
153
|
if let previous {
|
|
120
154
|
target.setValue(previous.doubleValue, forKey: "waitForIdleTimeout")
|
|
121
155
|
}
|
|
122
156
|
}
|
|
123
|
-
operation
|
|
157
|
+
performWithQuiescenceSkippedIfSupported(target, operation: operation)
|
|
124
158
|
}
|
|
125
159
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
160
|
+
// Some apps never report post-gesture quiescence, even after XCTest has synthesized the event.
|
|
161
|
+
private func performWithQuiescenceSkippedIfSupported(
|
|
162
|
+
_ target: XCUIApplication,
|
|
163
|
+
operation: () -> Void
|
|
164
|
+
) {
|
|
165
|
+
let selector = NSSelectorFromString("_performWithInteractionOptions:block:")
|
|
166
|
+
guard target.responds(to: selector) else {
|
|
167
|
+
operation()
|
|
168
|
+
return
|
|
132
169
|
}
|
|
133
|
-
|
|
134
|
-
|
|
170
|
+
typealias PerformWithInteractionOptions = @convention(c) (
|
|
171
|
+
NSObject,
|
|
172
|
+
Selector,
|
|
173
|
+
UInt,
|
|
174
|
+
@convention(block) () -> Void
|
|
175
|
+
) -> Void
|
|
176
|
+
let implementation = target.method(for: selector)
|
|
177
|
+
let performWithOptions = unsafeBitCast(
|
|
178
|
+
implementation,
|
|
179
|
+
to: PerformWithInteractionOptions.self
|
|
180
|
+
)
|
|
181
|
+
let skipPreEventQuiescence = UInt(1)
|
|
182
|
+
let skipPostEventQuiescence = UInt(2)
|
|
183
|
+
withoutActuallyEscaping(operation) { escapableOperation in
|
|
184
|
+
let block: @convention(block) () -> Void = escapableOperation
|
|
185
|
+
performWithOptions(
|
|
186
|
+
target,
|
|
187
|
+
selector,
|
|
188
|
+
skipPreEventQuiescence | skipPostEventQuiescence,
|
|
189
|
+
block
|
|
190
|
+
)
|
|
135
191
|
}
|
|
136
|
-
return min(parsed, 30)
|
|
137
192
|
}
|
|
138
193
|
|
|
139
194
|
func shouldRetryCommand(_ command: Command) -> Bool {
|
|
@@ -202,7 +257,7 @@ extension RunnerTests {
|
|
|
202
257
|
|
|
203
258
|
func isRunnerLifecycleCommand(_ command: CommandType) -> Bool {
|
|
204
259
|
switch command {
|
|
205
|
-
case .shutdown, .recordStop, .screenshot:
|
|
260
|
+
case .shutdown, .recordStop, .screenshot, .uptime:
|
|
206
261
|
return true
|
|
207
262
|
default:
|
|
208
263
|
return false
|
|
@@ -224,6 +279,24 @@ extension RunnerTests {
|
|
|
224
279
|
|
|
225
280
|
func sleepFor(_ delay: TimeInterval) {
|
|
226
281
|
guard delay > 0 else { return }
|
|
282
|
+
// Keep XCTest/UI sources moving during command-local pauses such as delayed typing.
|
|
283
|
+
if Thread.isMainThread {
|
|
284
|
+
let deadline = Date().addingTimeInterval(delay)
|
|
285
|
+
while Date() < deadline {
|
|
286
|
+
let slice = min(max(deadline.timeIntervalSinceNow, 0), 0.02)
|
|
287
|
+
if slice <= 0 {
|
|
288
|
+
break
|
|
289
|
+
}
|
|
290
|
+
let handledSource = RunLoop.current.run(
|
|
291
|
+
mode: .default,
|
|
292
|
+
before: Date().addingTimeInterval(slice)
|
|
293
|
+
)
|
|
294
|
+
if !handledSource {
|
|
295
|
+
usleep(useconds_t(slice * 1_000_000))
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return
|
|
299
|
+
}
|
|
227
300
|
usleep(useconds_t(delay * 1_000_000))
|
|
228
301
|
}
|
|
229
302
|
}
|
|
@@ -12,6 +12,7 @@ enum CommandType: String, Codable {
|
|
|
12
12
|
case type
|
|
13
13
|
case swipe
|
|
14
14
|
case findText
|
|
15
|
+
case querySelector
|
|
15
16
|
case readText
|
|
16
17
|
case snapshot
|
|
17
18
|
case screenshot
|
|
@@ -34,7 +35,10 @@ struct Command: Codable {
|
|
|
34
35
|
let command: CommandType
|
|
35
36
|
let appBundleId: String?
|
|
36
37
|
let text: String?
|
|
38
|
+
let selectorKey: String?
|
|
39
|
+
let selectorValue: String?
|
|
37
40
|
let delayMs: Int?
|
|
41
|
+
let textEntryMode: String?
|
|
38
42
|
let clearFirst: Bool?
|
|
39
43
|
let action: String?
|
|
40
44
|
let x: Double?
|
|
@@ -165,6 +169,7 @@ struct SnapshotNode: Codable {
|
|
|
165
169
|
let rect: SnapshotRect
|
|
166
170
|
let enabled: Bool
|
|
167
171
|
let focused: Bool?
|
|
172
|
+
let selected: Bool?
|
|
168
173
|
let hittable: Bool
|
|
169
174
|
let depth: Int
|
|
170
175
|
let parentIndex: Int?
|
|
@@ -29,6 +29,7 @@ extension RunnerTests {
|
|
|
29
29
|
let valueText: String?
|
|
30
30
|
let hittable: Bool
|
|
31
31
|
let focused: Bool
|
|
32
|
+
let selected: Bool
|
|
32
33
|
let visible: Bool
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -343,6 +344,7 @@ extension RunnerTests {
|
|
|
343
344
|
valueText: valueText,
|
|
344
345
|
hittable: computedSnapshotHittable(snapshot, viewport: context.viewport, laterNodes: laterNodes),
|
|
345
346
|
focused: snapshotHasFocus(snapshot),
|
|
347
|
+
selected: snapshotIsSelected(snapshot),
|
|
346
348
|
visible: isVisibleInViewport(snapshot.frame, context.viewport)
|
|
347
349
|
)
|
|
348
350
|
}
|
|
@@ -363,6 +365,7 @@ extension RunnerTests {
|
|
|
363
365
|
rect: snapshotRect(from: snapshot.frame),
|
|
364
366
|
enabled: snapshot.isEnabled,
|
|
365
367
|
focused: evaluation.focused ? true : nil,
|
|
368
|
+
selected: evaluation.selected ? true : nil,
|
|
366
369
|
hittable: evaluation.hittable,
|
|
367
370
|
depth: depth,
|
|
368
371
|
parentIndex: parentIndex,
|
|
@@ -529,6 +532,7 @@ extension RunnerTests {
|
|
|
529
532
|
rect: node.rect,
|
|
530
533
|
enabled: node.enabled,
|
|
531
534
|
focused: node.focused,
|
|
535
|
+
selected: node.selected,
|
|
532
536
|
hittable: node.hittable,
|
|
533
537
|
depth: depth,
|
|
534
538
|
parentIndex: parentIndex,
|
|
@@ -580,6 +584,7 @@ extension RunnerTests {
|
|
|
580
584
|
rect: snapshotRect(from: frame),
|
|
581
585
|
enabled: element.isEnabled,
|
|
582
586
|
focused: elementHasFocus(element) ? true : nil,
|
|
587
|
+
selected: element.isSelected ? true : nil,
|
|
583
588
|
hittable: element.isHittable,
|
|
584
589
|
depth: 0,
|
|
585
590
|
parentIndex: nil,
|
|
@@ -607,6 +612,10 @@ extension RunnerTests {
|
|
|
607
612
|
return focused
|
|
608
613
|
}
|
|
609
614
|
|
|
615
|
+
private func snapshotIsSelected(_ snapshot: XCUIElementSnapshot) -> Bool {
|
|
616
|
+
return snapshot.isSelected
|
|
617
|
+
}
|
|
618
|
+
|
|
610
619
|
private func shouldExpandCollapsedTabContainer(_ snapshot: XCUIElementSnapshot) -> Bool {
|
|
611
620
|
let frame = snapshot.frame
|
|
612
621
|
if frame.isNull || frame.isEmpty { return false }
|
|
@@ -46,7 +46,7 @@ extension RunnerTests {
|
|
|
46
46
|
#endif
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
func firstBlockingSystemModal(in springboard: XCUIApplication) -> XCUIElement? {
|
|
50
50
|
let disableSafeProbe = RunnerEnv.isTruthy("AGENT_DEVICE_RUNNER_DISABLE_SAFE_MODAL_PROBE")
|
|
51
51
|
let queryElements: (() -> [XCUIElement]) -> [XCUIElement] = { fetch in
|
|
52
52
|
if disableSafeProbe {
|
|
@@ -76,7 +76,7 @@ extension RunnerTests {
|
|
|
76
76
|
return nil
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
func safeElementsQuery(_ fetch: () -> [XCUIElement]) -> [XCUIElement] {
|
|
80
80
|
var elements: [XCUIElement] = []
|
|
81
81
|
let exceptionMessage = RunnerObjCExceptionCatcher.catchException({
|
|
82
82
|
elements = fetch()
|
|
@@ -120,7 +120,7 @@ extension RunnerTests {
|
|
|
120
120
|
return true
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
func actionableElements(in element: XCUIElement) -> [XCUIElement] {
|
|
124
124
|
var seen = Set<String>()
|
|
125
125
|
var actions: [XCUIElement] = []
|
|
126
126
|
let descendants = safeElementsQuery {
|
|
@@ -187,6 +187,7 @@ extension RunnerTests {
|
|
|
187
187
|
rect: snapshotRect(from: element.frame),
|
|
188
188
|
enabled: element.isEnabled,
|
|
189
189
|
focused: elementHasFocus(element) ? true : nil,
|
|
190
|
+
selected: element.isSelected ? true : nil,
|
|
190
191
|
hittable: hittableOverride ?? element.isHittable,
|
|
191
192
|
depth: depth,
|
|
192
193
|
parentIndex: nil,
|
|
@@ -90,8 +90,7 @@ final class RunnerTests: XCTestCase {
|
|
|
90
90
|
@MainActor
|
|
91
91
|
func testCommand() throws {
|
|
92
92
|
doneExpectation = expectation(description: "agent-device command handled")
|
|
93
|
-
|
|
94
|
-
currentApp = app
|
|
93
|
+
NSLog("AGENT_DEVICE_RUNNER_HEADLESS_STARTUP=1")
|
|
95
94
|
let queue = DispatchQueue(label: "agent-device.runner")
|
|
96
95
|
let desiredPort = RunnerEnv.resolvePort()
|
|
97
96
|
NSLog("AGENT_DEVICE_RUNNER_DESIRED_PORT=%d", desiredPort)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"configurations" : [
|
|
3
|
+
{
|
|
4
|
+
"id" : "916C7049-FE79-4C78-B55F-79242F92CB19",
|
|
5
|
+
"name" : "Configuration 1",
|
|
6
|
+
"options" : {
|
|
7
|
+
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"defaultOptions" : {
|
|
12
|
+
"preferredScreenCaptureFormat" : "screenshots",
|
|
13
|
+
"systemAttachmentLifetime" : "keepNever",
|
|
14
|
+
"userAttachmentLifetime" : "keepNever"
|
|
15
|
+
},
|
|
16
|
+
"testTargets" : [
|
|
17
|
+
{
|
|
18
|
+
"target" : {
|
|
19
|
+
"containerPath" : "container:AgentDeviceRunner.xcodeproj",
|
|
20
|
+
"identifier" : "20EA2EDC2F2CFC7C001CF0EF",
|
|
21
|
+
"name" : "AgentDeviceRunnerUITests"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"version" : 1
|
|
26
|
+
}
|
|
@@ -145,7 +145,13 @@ func run() throws {
|
|
|
145
145
|
in: parentLayer
|
|
146
146
|
)
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
// Overlay burn-in forces a full re-encode; medium quality keeps simulator videos readable
|
|
149
|
+
// while avoiding very slow highest-quality exports.
|
|
150
|
+
let presetName = AVAssetExportSession.exportPresets(compatibleWith: composition)
|
|
151
|
+
.contains(AVAssetExportPresetMediumQuality)
|
|
152
|
+
? AVAssetExportPresetMediumQuality
|
|
153
|
+
: AVAssetExportPresetHighestQuality
|
|
154
|
+
guard let exporter = AVAssetExportSession(asset: composition, presetName: presetName) else {
|
|
149
155
|
throw OverlayError.exportFailed("Failed to create export session.")
|
|
150
156
|
}
|
|
151
157
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-device",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.1",
|
|
4
4
|
"description": "Agent-native CLI for AI mobile testing and app automation across iOS, Android, tvOS, Android TV, macOS, and Linux.",
|
|
5
5
|
"mcpName": "io.github.callstackincubator/agent-device",
|
|
6
6
|
"license": "MIT",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"url": "https://github.com/callstackincubator/agent-device/issues"
|
|
15
15
|
},
|
|
16
16
|
"type": "module",
|
|
17
|
-
"packageManager": "pnpm@
|
|
17
|
+
"packageManager": "pnpm@11.1.2",
|
|
18
18
|
"main": "dist/src/index.js",
|
|
19
19
|
"types": "dist/src/index.d.ts",
|
|
20
20
|
"exports": {
|
|
@@ -76,11 +76,17 @@
|
|
|
76
76
|
"scripts": {
|
|
77
77
|
"build": "rslib build",
|
|
78
78
|
"clean:daemon": "rm -f ~/.agent-device/daemon.json && rm -f ~/.agent-device/daemon.lock",
|
|
79
|
+
"clean:xcuitest": "node scripts/clean-xcuitest-derived.mjs",
|
|
80
|
+
"clean:xcuitest:ios": "node scripts/clean-xcuitest-derived.mjs ios",
|
|
81
|
+
"clean:xcuitest:macos": "node scripts/clean-xcuitest-derived.mjs macos",
|
|
82
|
+
"clean:xcuitest:tvos": "node scripts/clean-xcuitest-derived.mjs tvos",
|
|
79
83
|
"build:node": "pnpm build && pnpm clean:daemon",
|
|
80
84
|
"build:xcuitest": "pnpm build:xcuitest:ios && pnpm build:xcuitest:macos",
|
|
81
|
-
"build:xcuitest:ios": "AGENT_DEVICE_XCUITEST_PLATFORM=ios
|
|
85
|
+
"build:xcuitest:ios": "AGENT_DEVICE_XCUITEST_PLATFORM=ios sh ./scripts/build-xcuitest-apple.sh",
|
|
86
|
+
"build:xcuitest:ios:clean": "pnpm clean:xcuitest:ios && pnpm build:xcuitest:ios",
|
|
82
87
|
"build:xcuitest:macos": "AGENT_DEVICE_XCUITEST_PLATFORM=macos sh ./scripts/build-xcuitest-apple.sh",
|
|
83
|
-
"build:xcuitest:tvos": "AGENT_DEVICE_XCUITEST_PLATFORM=tvos
|
|
88
|
+
"build:xcuitest:tvos": "AGENT_DEVICE_XCUITEST_PLATFORM=tvos sh ./scripts/build-xcuitest-apple.sh",
|
|
89
|
+
"build:xcuitest:tvos:clean": "pnpm clean:xcuitest:tvos && pnpm build:xcuitest:tvos",
|
|
84
90
|
"build:android-snapshot-helper": "sh ./scripts/build-android-snapshot-helper.sh $(node -p \"require('./package.json').version\") .tmp/android-snapshot-helper",
|
|
85
91
|
"package:android-snapshot-helper": "sh ./scripts/package-android-snapshot-helper.sh $(node -p \"require('./package.json').version\") v$(node -p \"require('./package.json').version\") .tmp/android-snapshot-helper",
|
|
86
92
|
"package:android-snapshot-helper:npm": "rm -rf android-snapshot-helper/dist && sh ./scripts/package-android-snapshot-helper.sh $(node -p \"require('./package.json').version\") v$(node -p \"require('./package.json').version\") android-snapshot-helper/dist",
|
|
@@ -90,7 +96,7 @@
|
|
|
90
96
|
"lint": "oxlint . --deny-warnings",
|
|
91
97
|
"format": "oxfmt --write src test skills package.json tsconfig.json tsconfig.lib.json rslib.config.ts vitest.config.ts .github/actions/setup-node-pnpm/action.yml .oxlintrc.json .oxfmtrc.json '!test/skillgym/.skillgym-results/**'",
|
|
92
98
|
"fallow": "fallow --summary",
|
|
93
|
-
"fallow:baseline": "(fallow dead-code --save-baseline fallow-baselines/dead-code.json --summary || true) && (fallow
|
|
99
|
+
"fallow:baseline": "(fallow dead-code --save-baseline fallow-baselines/dead-code.json --summary || true) && (fallow health --save-baseline fallow-baselines/health.json --summary || true)",
|
|
94
100
|
"check:fallow": "fallow audit",
|
|
95
101
|
"check:quick": "pnpm lint && pnpm typecheck",
|
|
96
102
|
"sync:mcp-metadata": "node scripts/sync-mcp-metadata.mjs",
|
|
@@ -105,11 +111,21 @@
|
|
|
105
111
|
"test-app:ios": "pnpm --dir examples/test-app ios",
|
|
106
112
|
"test-app:android": "pnpm --dir examples/test-app android",
|
|
107
113
|
"test-app:typecheck": "pnpm --dir examples/test-app typecheck",
|
|
108
|
-
"test": "
|
|
109
|
-
"test:
|
|
114
|
+
"test-app:replay:ios": "pnpm ad test examples/test-app/replays --platform ios --artifacts-dir .tmp/test-app-replay/ios",
|
|
115
|
+
"test-app:replay:android": "pnpm ad test examples/test-app/replays --platform android --artifacts-dir .tmp/test-app-replay/android",
|
|
116
|
+
"test-app:maestro": "node scripts/run-test-app-maestro-suite.mjs",
|
|
117
|
+
"test-app:maestro:ios": "node scripts/run-test-app-maestro-suite.mjs --platform ios",
|
|
118
|
+
"test-app:maestro:android": "node scripts/run-test-app-maestro-suite.mjs --platform android",
|
|
119
|
+
"test": "vitest run --project unit",
|
|
120
|
+
"test:unit": "vitest run --project unit",
|
|
121
|
+
"test:coverage": "vitest run --coverage",
|
|
122
|
+
"test:integration:provider": "vitest run --project provider-integration",
|
|
123
|
+
"test:integration:progress": "node scripts/integration-progress.mjs",
|
|
124
|
+
"test:integration:progress:check": "node scripts/integration-progress.mjs --check",
|
|
110
125
|
"test:skillgym": "pnpm build && skillgym run ./test/skillgym/suites/agent-device-smoke-suite.ts --config ./test/skillgym/skillgym.config.ts",
|
|
111
126
|
"test:smoke": "node --test test/integration/smoke-*.test.ts",
|
|
112
|
-
"test:integration": "node --test test/integration/*.test.ts",
|
|
127
|
+
"test:integration:node": "node --test test/integration/*.test.ts",
|
|
128
|
+
"test:integration": "pnpm test:integration:node && pnpm test:integration:provider",
|
|
113
129
|
"test:replay:ios": "node --experimental-strip-types src/bin.ts test test/integration/replays/ios/simulator",
|
|
114
130
|
"test:replay:ios-device": "node --experimental-strip-types src/bin.ts test test/integration/replays/ios/device",
|
|
115
131
|
"test:replay:android": "node --experimental-strip-types src/bin.ts test test/integration/replays/android",
|
|
@@ -183,18 +199,21 @@
|
|
|
183
199
|
],
|
|
184
200
|
"dependencies": {
|
|
185
201
|
"fast-xml-parser": "^5.7.2",
|
|
186
|
-
"pngjs": "^7.0.0"
|
|
202
|
+
"pngjs": "^7.0.0",
|
|
203
|
+
"yaml": "^2.9.0"
|
|
187
204
|
},
|
|
188
205
|
"devDependencies": {
|
|
189
|
-
"
|
|
206
|
+
"@microsoft/api-extractor": "^7.58.7",
|
|
190
207
|
"@rslib/core": "0.20.1",
|
|
191
208
|
"@types/node": "^22.0.0",
|
|
192
209
|
"@types/pngjs": "^6.0.5",
|
|
210
|
+
"@vitest/coverage-v8": "4.1.2",
|
|
193
211
|
"fallow": "^2.52.0",
|
|
194
212
|
"oxfmt": "^0.42.0",
|
|
195
213
|
"oxlint": "^1.57.0",
|
|
196
214
|
"skillgym": "^0.8.0",
|
|
197
215
|
"typescript": "^6.0.2",
|
|
198
|
-
"vite": "^8.0.10"
|
|
216
|
+
"vite": "^8.0.10",
|
|
217
|
+
"vitest": "^4.1.2"
|
|
199
218
|
}
|
|
200
219
|
}
|
package/server.json
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "io.github.callstackincubator/agent-device",
|
|
4
4
|
"title": "agent-device",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Let AI agents inspect, control, and debug real iOS, Android, desktop, and TV apps",
|
|
6
6
|
"repository": {
|
|
7
7
|
"url": "https://github.com/callstackincubator/agent-device",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.15.1",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "agent-device",
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.15.1",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
}
|
|
@@ -11,13 +11,7 @@ Router only. Private setup before using this skill:
|
|
|
11
11
|
agent-device --version
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
If that fails but the user installed `agent-device` globally,
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
zsh -lic 'command -v agent-device'
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
If it prints a path, run that absolute path instead of `agent-device`. For non-zsh shells, use the equivalent login-shell command.
|
|
14
|
+
If that fails but the user may have installed `agent-device` globally, check the user's configured login/interactive shell and environment before using `npx`. Resolve the command the same way the user would from a normal terminal session, then run the absolute binary path if found. This may require inspecting shell startup behavior or package-manager/global bin locations; do not assume the Codex process `PATH` is the user's `PATH`.
|
|
21
15
|
|
|
22
16
|
Require `agent-device >= 0.14.0`; older CLIs lack these help topics. If older, stop and tell the user to upgrade the trusted install or approve an exact-version npm command. Do not run `npm install -g agent-device@latest` or `npx -y agent-device@latest` autonomously, and do not include version/upgrade commands in final plans.
|
|
23
17
|
|
|
@@ -31,6 +25,7 @@ Escalate only when relevant:
|
|
|
31
25
|
|
|
32
26
|
```bash
|
|
33
27
|
agent-device help debugging
|
|
28
|
+
agent-device help react-native
|
|
34
29
|
agent-device help react-devtools
|
|
35
30
|
agent-device help remote
|
|
36
31
|
agent-device help macos
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
6dfb064793721b49e6111162a428f312bc9365dfc06e05adb648c434105fdf4e agent-device-android-snapshot-helper-0.14.9.apk
|
package/dist/src/180.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import e from"node:path";import t from"node:crypto";import n from"node:fs";import{resolveUserPath as a,expandUserHomePath as i}from"./3267.js";import{findProjectRoot as r}from"./9671.js";function o(t){let n,r=(n=(t??"").trim())?a(n):e.join(i("~"),".agent-device");return{baseDir:r,infoPath:e.join(r,"daemon.json"),lockPath:e.join(r,"daemon.lock"),logPath:e.join(r,"daemon.log"),sessionsDir:e.join(r,"sessions")}}function s(e){let t=(e??"").trim().toLowerCase();return"http"===t?"http":"dual"===t?"dual":"socket"}function l(e){let t=(e??"").trim().toLowerCase();return"auto"===t?"auto":"socket"===t?"socket":"http"===t?"http":"auto"}function d(e){return"tenant"===(e??"").trim().toLowerCase()?"tenant":"none"}function u(e){if(!e)return;let t=e.trim();if(t&&/^[a-zA-Z0-9._-]{1,128}$/.test(t))return t}let p=/(?:^|[^\w$.])(?:import|export)\s+(?:type\s+)?(?:[^'"`]*?\s+from\s+)?['"]([^'"]+)['"]/gm,c=/import\(\s*['"]([^'"]+)['"]\s*\)/gm,m=[".ts",".tsx",".js",".jsx",".mjs",".cjs"];function f(){let e=process.argv[1];return e?h(e):"unknown"}function h(a,i=r()){try{let r=e.resolve(i),o=[e.resolve(a)],s=new Set,l=[];for(;o.length>0;){let t=o.pop();if(!t||s.has(t))continue;s.add(t);let a=n.statSync(t);if(!a.isFile())continue;let i=e.relative(r,t)||t;l.push(`${i}:${a.size}:${Math.trunc(a.mtimeMs)}`);let d=n.readFileSync(t,"utf8");for(let n of function(e){let t=new Set;return g(e,p,t),g(e,c,t),[...t]}(d)){let a=function(t,n){let a=e.resolve(e.dirname(t),n),i=I(a);if(i)return i;for(let e of m){let t=I(`${a}${e}`);if(t)return t}for(let t of m){let n=I(e.join(a,`index${t}`));if(n)return n}return null}(t,n);a&&o.push(a)}}let d=l.sort().join("|"),u=t.createHash("sha1").update(d).digest("hex");return`graph:${l.length}:${u}`}catch{return"unknown"}}function g(e,t,n){t.lastIndex=0;let a=null;for(;null!==(a=t.exec(e));){let e=a[1]?.trim();e?.startsWith(".")&&n.add(e)}}function I(e){try{return n.statSync(e).isFile()?e:null}catch{return null}}function v(e){return e?{message:e}:{}}function S(e,t){return t?{...e,message:t}:e}function b(e){return"string"==typeof e?.message&&e.message.length>0?e.message:null}function k(e){let t=e.appId??e.bundleId??e.packageName;return{session:e.session,appId:t,appBundleId:e.bundleId,package:e.packageName}}function N(e,t,n){return{deviceId:t,deviceName:n,..."android"===e?{serial:t}:"ios"===e?{udid:t}:{}}}function $(e,t={}){let n=t.includeAndroidSerial??!0;return{platform:e.platform,target:e.target,device:e.name,id:e.id,..."ios"===e.platform?{device_udid:e.ios?.udid??e.id,ios_simulator_device_set:e.ios?.simulatorSetPath??null}:{},..."android"===e.platform&&n?{serial:e.android?.serial??e.id}:{}}}function _(e){return{name:e.name,...$(e.device,{includeAndroidSerial:!1}),createdAt:e.createdAt}}function z(e){return{platform:e.platform,id:e.id,name:e.name,kind:e.kind,target:e.target,..."boolean"==typeof e.booted?{booted:e.booted}:{}}}function w(e){let t=e.created?"Created":"Reused",n=e.booted?" (booted)":"";return S({udid:e.udid,device:e.device,runtime:e.runtime,ios_simulator_device_set:e.iosSimulatorDeviceSet??null,created:e.created,booted:e.booted},`${t}: ${e.device} ${e.udid}${n}`)}function P(e){return e.bundleId??e.package??e.app}function y(e){return S({app:e.app,appPath:e.appPath,platform:e.platform,...e.appId?{appId:e.appId}:{},...e.bundleId?{bundleId:e.bundleId}:{},...e.package?{package:e.package}:{}},`Installed: ${P(e)}`)}function C(e){return e.appName??e.bundleId??e.packageName??e.launchTarget}function x(e){return S({launchTarget:e.launchTarget,...e.appName?{appName:e.appName}:{},...e.appId?{appId:e.appId}:{},...e.bundleId?{bundleId:e.bundleId}:{},...e.packageName?{package:e.packageName}:{},...e.installablePath?{installablePath:e.installablePath}:{},...e.archivePath?{archivePath:e.archivePath}:{},...e.materializationId?{materializationId:e.materializationId}:{},...e.materializationExpiresAt?{materializationExpiresAt:e.materializationExpiresAt}:{}},`Installed: ${C(e)}`)}function j(e){let t=e.appName??e.appBundleId??e.session;return S({session:e.session,...e.appName?{appName:e.appName}:{},...e.appBundleId?{appBundleId:e.appBundleId}:{},...e.startup?{startup:e.startup}:{},...e.runtime?{runtime:e.runtime}:{},...e.device?$(e.device):{}},t?`Opened: ${t}`:"Opened")}function A(e){return{session:e.session,...e.shutdown?{shutdown:e.shutdown}:{},...v(e.session?`Closed: ${e.session}`:"Closed")}}function D(e){return{nodes:e.nodes,truncated:e.truncated,...e.appName?{appName:e.appName}:{},...e.appBundleId?{appBundleId:e.appBundleId}:{},...e.visibility?{visibility:e.visibility}:{},...e.androidSnapshot?{androidSnapshot:e.androidSnapshot}:{},...e.warnings&&e.warnings.length>0?{warnings:e.warnings}:{}}}export{k as buildAppIdentifiers,N as buildDeviceIdentifiers,h as computeDaemonCodeSignature,u as normalizeTenantId,b as readCommandMessage,f as resolveDaemonCodeSignature,o as resolveDaemonPaths,s as resolveDaemonServerMode,l as resolveDaemonTransportPreference,P as resolveDeployResultTarget,C as resolveInstallFromSourceResultTarget,d as resolveSessionIsolationMode,A as serializeCloseResult,y as serializeDeployResult,z as serializeDevice,w as serializeEnsureSimulatorResult,x as serializeInstallFromSourceResult,j as serializeOpenResult,_ as serializeSessionListEntry,D as serializeSnapshotResult,v as successText,S as withSuccessText};
|