@houwert/conductor 0.4.0 → 0.5.0

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 CHANGED
@@ -66,7 +66,7 @@ Claude learns every available command, how to coordinate across devices, and how
66
66
 
67
67
  | Capability | Commands |
68
68
  |---|---|
69
- | App lifecycle | `launch-app`, `stop-app`, `foreground-app`, `copy-app` |
69
+ | App lifecycle | `launch-app`, `stop-app`, `clear-state`, `uninstall-app`, `install-app`, `foreground-app`, `copy-app` |
70
70
  | Interaction | `tap`, `type`, `scroll`, `scroll-until-visible`, `swipe`, `press-key`, `erase-text`, `hide-keyboard` |
71
71
  | Inspection | `inspect`, `focused`, `screenshot`, `list-apps` |
72
72
  | Assertions | `assert-visible`, `assert-not-visible` |
@@ -34,6 +34,7 @@ DEVICE MANAGEMENT
34
34
  session --list List all device sessions
35
35
 
36
36
  APP CONTROL
37
+ install-app <path> Install .app / .ipa / .apk onto device
37
38
  launch-app <appId> [--device <id>] Launch app and save to session
38
39
  --clear-state Wipe app data/state before launching
39
40
  --clear-keychain Wipe keychain before launching
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HELP = void 0;
4
+ exports.installApp = installApp;
5
+ exports.HELP = ` install-app <path> Install .app / .ipa / .apk onto device`;
6
+ const runner_js_1 = require("../runner.js");
7
+ const session_js_1 = require("../session.js");
8
+ const output_js_1 = require("../output.js");
9
+ const bootstrap_js_1 = require("../drivers/bootstrap.js");
10
+ async function resolveDeviceId(sessionName) {
11
+ if (sessionName !== 'default')
12
+ return sessionName;
13
+ const session = await (0, session_js_1.getSession)(sessionName);
14
+ return session.deviceId ?? (await (0, runner_js_1.detectFirstDevice)());
15
+ }
16
+ async function installApp(appPath, opts = {}, sessionName = 'default') {
17
+ if (!appPath) {
18
+ (0, output_js_1.printError)('install-app requires <path> to a .app, .ipa, or .apk', opts);
19
+ return 1;
20
+ }
21
+ const deviceId = await resolveDeviceId(sessionName);
22
+ if (!deviceId) {
23
+ (0, output_js_1.printError)('No device found. Connect a device or start a simulator first.', opts);
24
+ return 1;
25
+ }
26
+ const platform = await (0, bootstrap_js_1.detectPlatform)(deviceId);
27
+ if (platform === 'ios' || platform === 'tvos') {
28
+ const result = await (0, runner_js_1.spawnCommand)('xcrun', ['simctl', 'install', deviceId, appPath]);
29
+ if (!result.success) {
30
+ (0, output_js_1.printError)(`install-app failed: ${result.stderr}`, opts);
31
+ return 1;
32
+ }
33
+ }
34
+ else {
35
+ const result = await (0, runner_js_1.spawnCommand)('adb', [
36
+ '-s',
37
+ deviceId,
38
+ 'install',
39
+ '-r',
40
+ '-t',
41
+ '-g',
42
+ appPath,
43
+ ]);
44
+ if (!result.success) {
45
+ (0, output_js_1.printError)(`install-app failed: ${result.stderr}`, opts);
46
+ return 1;
47
+ }
48
+ }
49
+ (0, output_js_1.printSuccess)(`install-app "${appPath}" — done`, opts);
50
+ return 0;
51
+ }
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ const run_parallel_js_1 = require("./commands/run-parallel.js");
32
32
  const foreground_app_js_1 = require("./commands/foreground-app.js");
33
33
  const list_apps_js_1 = require("./commands/list-apps.js");
34
34
  const copy_app_js_1 = require("./commands/copy-app.js");
35
+ const install_app_js_1 = require("./commands/install-app.js");
35
36
  const erase_text_js_1 = require("./commands/erase-text.js");
36
37
  const assert_not_visible_js_1 = require("./commands/assert-not-visible.js");
37
38
  const open_link_js_1 = require("./commands/open-link.js");
@@ -48,6 +49,7 @@ const COMMAND_HELP = {
48
49
  'foreground-app': foreground_app_js_1.HELP,
49
50
  'list-apps': list_apps_js_1.HELP,
50
51
  'copy-app': copy_app_js_1.HELP,
52
+ 'install-app': install_app_js_1.HELP,
51
53
  'launch-app': launch_app_js_1.HELP,
52
54
  'stop-app': stop_app_js_1.HELP,
53
55
  'clear-state': clear_state_js_1.HELP,
@@ -223,6 +225,11 @@ async function main() {
223
225
  exitCode = await (0, copy_app_js_1.copyApp)(bundleId, from ?? '', to ?? '', opts);
224
226
  break;
225
227
  }
228
+ case 'install-app': {
229
+ const appPath = rest[0] ?? '';
230
+ exitCode = await (0, install_app_js_1.installApp)(appPath, opts, sessionName);
231
+ break;
232
+ }
226
233
  case 'launch-app': {
227
234
  const appId = rest[0] ?? '';
228
235
  // --argument key=value (repeatable) → Record<string, string>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@houwert/conductor",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "CLI tool for mobile app interactions — optimized for AI agents",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -90,6 +90,17 @@ Both flags are required. The command reads the `.app` bundle path from the sourc
90
90
 
91
91
  ---
92
92
 
93
+ ### `install-app <path>`
94
+
95
+ Install an app from a local `.app` bundle, `.ipa`, or `.apk` file onto the device.
96
+
97
+ ```bash
98
+ conductor install-app ./build/MyApp.app
99
+ conductor install-app ./build/app-debug.apk --device emulator-5554
100
+ ```
101
+
102
+ ---
103
+
93
104
  ### `launch-app <appId>`
94
105
 
95
106
  Launch an app by bundle ID and save it to the session.