@houwert/conductor 0.2.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/.claude-plugin/plugin.json +6 -0
- package/README.md +39 -0
- package/dist/commands/assert-not-visible.js +47 -0
- package/dist/commands/assert-visible.js +58 -0
- package/dist/commands/back.js +25 -0
- package/dist/commands/cheat-sheet.js +100 -0
- package/dist/commands/daemon.js +61 -0
- package/dist/commands/device-pool.js +202 -0
- package/dist/commands/erase-text.js +26 -0
- package/dist/commands/foreground-app.js +50 -0
- package/dist/commands/hide-keyboard.js +27 -0
- package/dist/commands/inspect.js +37 -0
- package/dist/commands/install.js +64 -0
- package/dist/commands/launch-app.js +42 -0
- package/dist/commands/list-apps.js +60 -0
- package/dist/commands/list-devices.js +61 -0
- package/dist/commands/open-link.js +22 -0
- package/dist/commands/press-key.js +91 -0
- package/dist/commands/run-flow-inline.js +25 -0
- package/dist/commands/run-flow.js +29 -0
- package/dist/commands/run-parallel.js +143 -0
- package/dist/commands/screenshot.js +29 -0
- package/dist/commands/scroll-until-visible.js +69 -0
- package/dist/commands/scroll.js +36 -0
- package/dist/commands/session.js +49 -0
- package/dist/commands/set-location.js +18 -0
- package/dist/commands/set-orientation.js +23 -0
- package/dist/commands/start-device.js +178 -0
- package/dist/commands/stop-app.js +32 -0
- package/dist/commands/swipe.js +72 -0
- package/dist/commands/tap.js +69 -0
- package/dist/commands/type.js +22 -0
- package/dist/daemon/client.js +112 -0
- package/dist/daemon/protocol.js +25 -0
- package/dist/daemon/server.js +208 -0
- package/dist/drivers/android.js +343 -0
- package/dist/drivers/bootstrap.js +371 -0
- package/dist/drivers/element-resolver.js +371 -0
- package/dist/drivers/flow-runner.js +1309 -0
- package/dist/drivers/ios.js +328 -0
- package/dist/drivers/js-engine.js +150 -0
- package/dist/drivers/wait.js +211 -0
- package/dist/index.js +426 -0
- package/dist/output.js +36 -0
- package/dist/pkg-root.js +28 -0
- package/dist/postinstall.js +12 -0
- package/dist/runner.js +190 -0
- package/dist/session.js +66 -0
- package/dist/update-check.js +109 -0
- package/dist/utils.js +19 -0
- package/dist/verbose.js +17 -0
- package/drivers/android/conductor-app.apk +0 -0
- package/drivers/android/conductor-server.apk +0 -0
- package/drivers/ios/conductor-driver-ios-config.xctestrun +126 -0
- package/drivers/ios/conductor-driver-ios.zip +0 -0
- package/drivers/ios/conductor-driver-iosUITests-Runner.zip +0 -0
- package/package.json +52 -0
- package/proto/conductor_android.proto +116 -0
- package/skills/conductor/SKILL.md +677 -0
- package/skills/conductor/references/flow-syntax.md +179 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const minimist_1 = __importDefault(require("minimist"));
|
|
8
|
+
const verbose_js_1 = require("./verbose.js");
|
|
9
|
+
const list_devices_js_1 = require("./commands/list-devices.js");
|
|
10
|
+
const launch_app_js_1 = require("./commands/launch-app.js");
|
|
11
|
+
const stop_app_js_1 = require("./commands/stop-app.js");
|
|
12
|
+
const tap_js_1 = require("./commands/tap.js");
|
|
13
|
+
const type_js_1 = require("./commands/type.js");
|
|
14
|
+
const back_js_1 = require("./commands/back.js");
|
|
15
|
+
const scroll_js_1 = require("./commands/scroll.js");
|
|
16
|
+
const swipe_js_1 = require("./commands/swipe.js");
|
|
17
|
+
const assert_visible_js_1 = require("./commands/assert-visible.js");
|
|
18
|
+
const screenshot_js_1 = require("./commands/screenshot.js");
|
|
19
|
+
const inspect_js_1 = require("./commands/inspect.js");
|
|
20
|
+
const run_flow_js_1 = require("./commands/run-flow.js");
|
|
21
|
+
const run_flow_inline_js_1 = require("./commands/run-flow-inline.js");
|
|
22
|
+
const press_key_js_1 = require("./commands/press-key.js");
|
|
23
|
+
const session_js_1 = require("./commands/session.js");
|
|
24
|
+
const cheat_sheet_js_1 = require("./commands/cheat-sheet.js");
|
|
25
|
+
const daemon_js_1 = require("./commands/daemon.js");
|
|
26
|
+
const install_js_1 = require("./commands/install.js");
|
|
27
|
+
const device_pool_js_1 = require("./commands/device-pool.js");
|
|
28
|
+
const run_parallel_js_1 = require("./commands/run-parallel.js");
|
|
29
|
+
const foreground_app_js_1 = require("./commands/foreground-app.js");
|
|
30
|
+
const list_apps_js_1 = require("./commands/list-apps.js");
|
|
31
|
+
const erase_text_js_1 = require("./commands/erase-text.js");
|
|
32
|
+
const assert_not_visible_js_1 = require("./commands/assert-not-visible.js");
|
|
33
|
+
const open_link_js_1 = require("./commands/open-link.js");
|
|
34
|
+
const hide_keyboard_js_1 = require("./commands/hide-keyboard.js");
|
|
35
|
+
const scroll_until_visible_js_1 = require("./commands/scroll-until-visible.js");
|
|
36
|
+
const set_location_js_1 = require("./commands/set-location.js");
|
|
37
|
+
const set_orientation_js_1 = require("./commands/set-orientation.js");
|
|
38
|
+
const start_device_js_1 = require("./commands/start-device.js");
|
|
39
|
+
const runner_js_1 = require("./runner.js");
|
|
40
|
+
const update_check_js_1 = require("./update-check.js");
|
|
41
|
+
const HELP = `
|
|
42
|
+
Usage: conductor <command> [args] [options]
|
|
43
|
+
|
|
44
|
+
Commands:
|
|
45
|
+
start-device --platform <ios|android> Boot a simulator or emulator
|
|
46
|
+
--os-version <n> iOS version (e.g. 18) or Android API level (e.g. 33)
|
|
47
|
+
--avd <name> Android AVD name (default: first available)
|
|
48
|
+
list-devices List connected devices/simulators
|
|
49
|
+
foreground-app Print bundle ID / package of the foreground app
|
|
50
|
+
list-apps List installed app IDs / package names
|
|
51
|
+
launch-app <appId> Launch app (saves to session)
|
|
52
|
+
--clear-state Clear app data/state before launching
|
|
53
|
+
--clear-keychain Clear keychain before launching
|
|
54
|
+
--no-stop-app Do not stop the app before launching (resume instead of restart)
|
|
55
|
+
--argument key=value Set launch argument (repeatable)
|
|
56
|
+
stop-app [<appId>] Stop app
|
|
57
|
+
tap <element> Tap element by text or id
|
|
58
|
+
--id <id> Match by accessibility id instead of text
|
|
59
|
+
--text <text> Match by text only (not id)
|
|
60
|
+
--index <n> Pick the nth match (0-based)
|
|
61
|
+
--long-press Hold instead of tap
|
|
62
|
+
--double-tap Double-tap the element
|
|
63
|
+
--optional Do not fail if element is not found
|
|
64
|
+
--focused Match only focused elements
|
|
65
|
+
--enabled / --no-enabled Match by enabled state
|
|
66
|
+
--checked / --no-checked Match by checked state
|
|
67
|
+
--selected / --no-selected Match by selected state
|
|
68
|
+
--below <text> Match element below the given reference
|
|
69
|
+
--above <text> Match element above the given reference
|
|
70
|
+
--left-of <text> Match element left of the given reference
|
|
71
|
+
--right-of <text> Match element right of the given reference
|
|
72
|
+
--verbose Log all candidates and chosen element
|
|
73
|
+
type <text> Type text into focused field
|
|
74
|
+
erase-text [n] Erase n characters (default: 50)
|
|
75
|
+
back Press back button
|
|
76
|
+
press-key <key> Press a key (Enter, Backspace, Home, ...)
|
|
77
|
+
hide-keyboard Dismiss the on-screen keyboard
|
|
78
|
+
scroll [--direction down|up|left|right]
|
|
79
|
+
swipe --direction <UP|DOWN|LEFT|RIGHT>
|
|
80
|
+
--start <x,y> Start coordinate (0–1 normalised or absolute px)
|
|
81
|
+
--end <x,y> End coordinate (0–1 normalised or absolute px)
|
|
82
|
+
--duration <ms> Swipe duration in milliseconds (default: 500)
|
|
83
|
+
scroll-until-visible <element> Scroll until element is visible
|
|
84
|
+
--id <id> Match by accessibility id instead of text
|
|
85
|
+
--text <text> Match by text only (not id)
|
|
86
|
+
--direction <down|up|left|right> Scroll direction (default: down)
|
|
87
|
+
--timeout <ms> Max time in milliseconds (default: 30000)
|
|
88
|
+
assert-visible <element> Assert element is visible
|
|
89
|
+
--id <id> Match by accessibility id instead of text
|
|
90
|
+
--text <text> Match by text only (not id)
|
|
91
|
+
--index <n> Pick the nth match (0-based)
|
|
92
|
+
--timeout <ms> Max wait time in milliseconds
|
|
93
|
+
--optional Do not fail if element is not found
|
|
94
|
+
--focused Match only focused elements
|
|
95
|
+
--enabled / --no-enabled Match by enabled state
|
|
96
|
+
--checked / --no-checked Match by checked state
|
|
97
|
+
--selected / --no-selected Match by selected state
|
|
98
|
+
--below <text> Match element below the given reference
|
|
99
|
+
--above <text> Match element above the given reference
|
|
100
|
+
--left-of <text> Match element left of the given reference
|
|
101
|
+
--right-of <text> Match element right of the given reference
|
|
102
|
+
assert-not-visible <element> Assert element is absent from screen
|
|
103
|
+
--id <id> Match by accessibility id instead of text
|
|
104
|
+
--text <text> Match by text only (not id)
|
|
105
|
+
--timeout <ms> Max check time in milliseconds (default: 1000)
|
|
106
|
+
open-link <url> Open a URL / deep link
|
|
107
|
+
set-location --lat <n> --lng <n> Set GPS coordinates
|
|
108
|
+
set-orientation <portrait|landscape> Set device orientation
|
|
109
|
+
screenshot [--output <path>] Take screenshot
|
|
110
|
+
inspect Print UI hierarchy
|
|
111
|
+
run-flow <file> [--device <id>] Run a Maestro YAML flow file
|
|
112
|
+
--env KEY=VALUE Inject env var (repeatable; overrides flow env block)
|
|
113
|
+
--benchmark Print elapsed time for each command and total flow time
|
|
114
|
+
run-flow-inline <yaml> Run inline YAML commands
|
|
115
|
+
--benchmark Print elapsed time for each command and total flow time
|
|
116
|
+
session [--clear] [--list] Show, clear, or list device sessions
|
|
117
|
+
cheat-sheet Print command reference
|
|
118
|
+
install Install/reinstall Claude Code plugin
|
|
119
|
+
daemon-start Start background daemon (manages driver process)
|
|
120
|
+
daemon-stop [--all] Stop background daemon (--all stops every session's daemon)
|
|
121
|
+
daemon-status Show daemon status
|
|
122
|
+
device-pool --list List all devices and pool status
|
|
123
|
+
device-pool --acquire Claim a free device (prints device ID)
|
|
124
|
+
device-pool --release <id> Release a device back to the pool
|
|
125
|
+
run-parallel --flows-dir <path> Run flows in parallel across all devices
|
|
126
|
+
|
|
127
|
+
Options:
|
|
128
|
+
--device <id> Target device ID (also keys the session and daemon)
|
|
129
|
+
--json Output as machine-readable JSON
|
|
130
|
+
--verbose, -v Log daemon calls, fallbacks, and raw output
|
|
131
|
+
--help, -h Show this help
|
|
132
|
+
`.trim();
|
|
133
|
+
async function main() {
|
|
134
|
+
(0, update_check_js_1.checkForUpdates)();
|
|
135
|
+
const argv = (0, minimist_1.default)(process.argv.slice(2), {
|
|
136
|
+
boolean: [
|
|
137
|
+
'json',
|
|
138
|
+
'help',
|
|
139
|
+
'clear',
|
|
140
|
+
'list',
|
|
141
|
+
'verbose',
|
|
142
|
+
'skills',
|
|
143
|
+
'all',
|
|
144
|
+
'acquire',
|
|
145
|
+
'release',
|
|
146
|
+
'clear-state',
|
|
147
|
+
'clear-keychain',
|
|
148
|
+
'stop-app',
|
|
149
|
+
'long-press',
|
|
150
|
+
'double-tap',
|
|
151
|
+
'optional',
|
|
152
|
+
'benchmark',
|
|
153
|
+
],
|
|
154
|
+
string: [
|
|
155
|
+
'device',
|
|
156
|
+
'output',
|
|
157
|
+
'direction',
|
|
158
|
+
'flows-dir',
|
|
159
|
+
'yaml',
|
|
160
|
+
'id',
|
|
161
|
+
'text',
|
|
162
|
+
'start',
|
|
163
|
+
'end',
|
|
164
|
+
'env',
|
|
165
|
+
'below',
|
|
166
|
+
'above',
|
|
167
|
+
'left-of',
|
|
168
|
+
'right-of',
|
|
169
|
+
'lat',
|
|
170
|
+
'lng',
|
|
171
|
+
'platform',
|
|
172
|
+
'os-version',
|
|
173
|
+
'avd',
|
|
174
|
+
],
|
|
175
|
+
alias: { h: 'help', v: 'verbose' },
|
|
176
|
+
});
|
|
177
|
+
if (argv['verbose'])
|
|
178
|
+
(0, verbose_js_1.setVerbose)(true);
|
|
179
|
+
const [command, ...rest] = argv._;
|
|
180
|
+
const opts = { json: argv['json'] };
|
|
181
|
+
// The device ID is the natural key for both the session file and the daemon.
|
|
182
|
+
// Use --device if given, otherwise detect the first booted device, otherwise 'default'.
|
|
183
|
+
const explicitDevice = argv['device'];
|
|
184
|
+
const sessionName = explicitDevice ?? (await (0, runner_js_1.detectFirstDevice)()) ?? 'default';
|
|
185
|
+
if (!command || argv['help']) {
|
|
186
|
+
console.log(HELP);
|
|
187
|
+
process.exit(0);
|
|
188
|
+
}
|
|
189
|
+
let exitCode = 0;
|
|
190
|
+
switch (command) {
|
|
191
|
+
case 'start-device':
|
|
192
|
+
exitCode = await (0, start_device_js_1.startDevice)(argv['platform'], opts, {
|
|
193
|
+
osVersion: argv['os-version'],
|
|
194
|
+
avd: argv['avd'],
|
|
195
|
+
});
|
|
196
|
+
break;
|
|
197
|
+
case 'list-devices':
|
|
198
|
+
exitCode = await (0, list_devices_js_1.listDevices)(opts);
|
|
199
|
+
break;
|
|
200
|
+
case 'foreground-app':
|
|
201
|
+
exitCode = await (0, foreground_app_js_1.foregroundApp)(opts, sessionName);
|
|
202
|
+
break;
|
|
203
|
+
case 'list-apps':
|
|
204
|
+
exitCode = await (0, list_apps_js_1.listApps)(opts, sessionName);
|
|
205
|
+
break;
|
|
206
|
+
case 'launch-app': {
|
|
207
|
+
const appId = rest[0] ?? '';
|
|
208
|
+
// --argument key=value (repeatable) → Record<string, string>
|
|
209
|
+
const rawArgs = argv['argument'] ?? argv['arg'];
|
|
210
|
+
const argPairs = Array.isArray(rawArgs) ? rawArgs : rawArgs ? [rawArgs] : [];
|
|
211
|
+
const launchArgs = argPairs.length
|
|
212
|
+
? Object.fromEntries(argPairs.map((a) => a.split('=', 2)))
|
|
213
|
+
: undefined;
|
|
214
|
+
exitCode = await (0, launch_app_js_1.launchApp)(appId, argv['device'], opts, sessionName, {
|
|
215
|
+
clearState: argv['clear-state'],
|
|
216
|
+
clearKeychain: argv['clear-keychain'],
|
|
217
|
+
stopApp: argv['stop-app'] !== false,
|
|
218
|
+
launchArgs,
|
|
219
|
+
});
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
case 'stop-app': {
|
|
223
|
+
const appId = rest[0];
|
|
224
|
+
exitCode = await (0, stop_app_js_1.stopApp)(appId, opts, sessionName);
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
case 'tap': {
|
|
228
|
+
const element = rest.join(' ');
|
|
229
|
+
exitCode = await (0, tap_js_1.tap)(element, opts, sessionName, {
|
|
230
|
+
id: argv['id'],
|
|
231
|
+
text: argv['text'],
|
|
232
|
+
index: argv['index'] !== undefined ? Number(argv['index']) : undefined,
|
|
233
|
+
longPress: argv['long-press'],
|
|
234
|
+
doubleTap: argv['double-tap'],
|
|
235
|
+
optional: argv['optional'],
|
|
236
|
+
focused: argv['focused'] !== undefined ? argv['focused'] : undefined,
|
|
237
|
+
enabled: argv['enabled'] !== undefined ? argv['enabled'] : undefined,
|
|
238
|
+
checked: argv['checked'] !== undefined ? argv['checked'] : undefined,
|
|
239
|
+
selected: argv['selected'] !== undefined ? argv['selected'] : undefined,
|
|
240
|
+
below: argv['below'],
|
|
241
|
+
above: argv['above'],
|
|
242
|
+
leftOf: argv['left-of'],
|
|
243
|
+
rightOf: argv['right-of'],
|
|
244
|
+
});
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
case 'type': {
|
|
248
|
+
const text = rest.join(' ');
|
|
249
|
+
exitCode = await (0, type_js_1.typeText)(text, opts, sessionName);
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
case 'erase-text': {
|
|
253
|
+
const n = rest[0] !== undefined
|
|
254
|
+
? Number(rest[0])
|
|
255
|
+
: argv['characters'] !== undefined
|
|
256
|
+
? Number(argv['characters'])
|
|
257
|
+
: 50;
|
|
258
|
+
exitCode = await (0, erase_text_js_1.eraseText)(n, opts, sessionName);
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
case 'back':
|
|
262
|
+
exitCode = await (0, back_js_1.back)(opts, sessionName);
|
|
263
|
+
break;
|
|
264
|
+
case 'hide-keyboard':
|
|
265
|
+
exitCode = await (0, hide_keyboard_js_1.hideKeyboard)(opts, sessionName);
|
|
266
|
+
break;
|
|
267
|
+
case 'press-key': {
|
|
268
|
+
const key = rest[0] ?? '';
|
|
269
|
+
exitCode = await (0, press_key_js_1.pressKey)(key, opts, sessionName);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
case 'scroll': {
|
|
273
|
+
const dir = (argv['direction'] || 'down').toLowerCase();
|
|
274
|
+
exitCode = await (0, scroll_js_1.scroll)(dir, opts, sessionName);
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
case 'swipe': {
|
|
278
|
+
const dir = argv['direction'] || '';
|
|
279
|
+
exitCode = await (0, swipe_js_1.swipe)(dir, opts, sessionName, {
|
|
280
|
+
start: argv['start'],
|
|
281
|
+
end: argv['end'],
|
|
282
|
+
duration: argv['duration'] !== undefined ? Number(argv['duration']) : undefined,
|
|
283
|
+
});
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
case 'scroll-until-visible': {
|
|
287
|
+
const element = rest.join(' ');
|
|
288
|
+
const rawDir = (argv['direction'] || 'down').toLowerCase();
|
|
289
|
+
exitCode = await (0, scroll_until_visible_js_1.scrollUntilVisible)(element, opts, sessionName, {
|
|
290
|
+
id: argv['id'],
|
|
291
|
+
text: argv['text'],
|
|
292
|
+
index: argv['index'] !== undefined ? Number(argv['index']) : undefined,
|
|
293
|
+
direction: rawDir,
|
|
294
|
+
timeout: argv['timeout'] !== undefined ? Number(argv['timeout']) : undefined,
|
|
295
|
+
focused: argv['focused'] !== undefined ? argv['focused'] : undefined,
|
|
296
|
+
enabled: argv['enabled'] !== undefined ? argv['enabled'] : undefined,
|
|
297
|
+
checked: argv['checked'] !== undefined ? argv['checked'] : undefined,
|
|
298
|
+
selected: argv['selected'] !== undefined ? argv['selected'] : undefined,
|
|
299
|
+
});
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
case 'assert-visible': {
|
|
303
|
+
const element = rest.join(' ');
|
|
304
|
+
exitCode = await (0, assert_visible_js_1.assertVisible)(element, opts, sessionName, {
|
|
305
|
+
id: argv['id'],
|
|
306
|
+
text: argv['text'],
|
|
307
|
+
index: argv['index'] !== undefined ? Number(argv['index']) : undefined,
|
|
308
|
+
timeout: argv['timeout'] !== undefined ? Number(argv['timeout']) : undefined,
|
|
309
|
+
optional: argv['optional'],
|
|
310
|
+
focused: argv['focused'] !== undefined ? argv['focused'] : undefined,
|
|
311
|
+
enabled: argv['enabled'] !== undefined ? argv['enabled'] : undefined,
|
|
312
|
+
checked: argv['checked'] !== undefined ? argv['checked'] : undefined,
|
|
313
|
+
selected: argv['selected'] !== undefined ? argv['selected'] : undefined,
|
|
314
|
+
below: argv['below'],
|
|
315
|
+
above: argv['above'],
|
|
316
|
+
leftOf: argv['left-of'],
|
|
317
|
+
rightOf: argv['right-of'],
|
|
318
|
+
});
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
case 'assert-not-visible': {
|
|
322
|
+
const element = rest.join(' ');
|
|
323
|
+
exitCode = await (0, assert_not_visible_js_1.assertNotVisible)(element, opts, sessionName, {
|
|
324
|
+
id: argv['id'],
|
|
325
|
+
text: argv['text'],
|
|
326
|
+
index: argv['index'] !== undefined ? Number(argv['index']) : undefined,
|
|
327
|
+
timeout: argv['timeout'] !== undefined ? Number(argv['timeout']) : undefined,
|
|
328
|
+
focused: argv['focused'] !== undefined ? argv['focused'] : undefined,
|
|
329
|
+
enabled: argv['enabled'] !== undefined ? argv['enabled'] : undefined,
|
|
330
|
+
checked: argv['checked'] !== undefined ? argv['checked'] : undefined,
|
|
331
|
+
selected: argv['selected'] !== undefined ? argv['selected'] : undefined,
|
|
332
|
+
below: argv['below'],
|
|
333
|
+
above: argv['above'],
|
|
334
|
+
leftOf: argv['left-of'],
|
|
335
|
+
rightOf: argv['right-of'],
|
|
336
|
+
});
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
case 'open-link': {
|
|
340
|
+
const url = rest[0] ?? argv['url'] ?? '';
|
|
341
|
+
exitCode = await (0, open_link_js_1.openLink)(url, opts, sessionName);
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
case 'set-location': {
|
|
345
|
+
const lat = Number(argv['lat'] ?? argv['latitude']);
|
|
346
|
+
const lng = Number(argv['lng'] ?? argv['longitude']);
|
|
347
|
+
if (isNaN(lat) || isNaN(lng)) {
|
|
348
|
+
console.error('set-location requires --lat <n> --lng <n>');
|
|
349
|
+
exitCode = 1;
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
exitCode = await (0, set_location_js_1.setLocation)(lat, lng, opts, sessionName);
|
|
353
|
+
}
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
case 'set-orientation': {
|
|
357
|
+
const orientation = (rest[0] ??
|
|
358
|
+
argv['orientation'] ??
|
|
359
|
+
'').toLowerCase();
|
|
360
|
+
exitCode = await (0, set_orientation_js_1.setOrientation)(orientation, opts, sessionName);
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
case 'screenshot': {
|
|
364
|
+
const outPath = argv['output'];
|
|
365
|
+
exitCode = await (0, screenshot_js_1.screenshot)(outPath, opts, sessionName);
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
case 'inspect':
|
|
369
|
+
exitCode = await (0, inspect_js_1.inspect)(opts, sessionName);
|
|
370
|
+
break;
|
|
371
|
+
case 'run-flow': {
|
|
372
|
+
const file = rest[0] ?? '';
|
|
373
|
+
const rawEnv = argv['env'];
|
|
374
|
+
const envPairs = Array.isArray(rawEnv) ? rawEnv : rawEnv ? [rawEnv] : [];
|
|
375
|
+
const flowEnv = Object.fromEntries(envPairs.map((e) => e.split('=', 2)));
|
|
376
|
+
exitCode = await (0, run_flow_js_1.runFlow)(file, opts, sessionName, flowEnv, argv['benchmark']);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
case 'run-flow-inline': {
|
|
380
|
+
const yaml = argv['yaml'] || rest.join(' ');
|
|
381
|
+
exitCode = await (0, run_flow_inline_js_1.runFlowInline)(yaml, opts, sessionName, argv['benchmark']);
|
|
382
|
+
break;
|
|
383
|
+
}
|
|
384
|
+
case 'session':
|
|
385
|
+
exitCode = await (0, session_js_1.sessionCmd)(argv['clear'], argv['list'], opts, sessionName);
|
|
386
|
+
break;
|
|
387
|
+
case 'cheat-sheet':
|
|
388
|
+
exitCode = await (0, cheat_sheet_js_1.cheatSheet)();
|
|
389
|
+
break;
|
|
390
|
+
case 'install':
|
|
391
|
+
exitCode = await (0, install_js_1.installSkills)(opts);
|
|
392
|
+
break;
|
|
393
|
+
case 'daemon-start':
|
|
394
|
+
exitCode = await (0, daemon_js_1.daemonStart)(opts, sessionName);
|
|
395
|
+
break;
|
|
396
|
+
case 'daemon-stop':
|
|
397
|
+
exitCode = await (0, daemon_js_1.daemonStop)(opts, sessionName, argv['all']);
|
|
398
|
+
break;
|
|
399
|
+
case 'daemon-status':
|
|
400
|
+
exitCode = await (0, daemon_js_1.daemonStatusCmd)(opts, sessionName);
|
|
401
|
+
break;
|
|
402
|
+
case 'device-pool': {
|
|
403
|
+
const acquire = argv['acquire'];
|
|
404
|
+
const release = argv['release'];
|
|
405
|
+
const releaseId = typeof argv['release'] === 'string' ? argv['release'] : rest[0];
|
|
406
|
+
const action = acquire ? 'acquire' : release || releaseId ? 'release' : 'list';
|
|
407
|
+
exitCode = await (0, device_pool_js_1.devicePool)(action, releaseId, opts);
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
case 'run-parallel': {
|
|
411
|
+
const flowsDir = argv['flows-dir'] ?? rest[0] ?? '';
|
|
412
|
+
exitCode = await (0, run_parallel_js_1.runParallel)(flowsDir, opts);
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
default:
|
|
416
|
+
console.error(`Unknown command: ${command}`);
|
|
417
|
+
console.error('Run `conductor --help` for usage.');
|
|
418
|
+
exitCode = 1;
|
|
419
|
+
}
|
|
420
|
+
process.exit(exitCode);
|
|
421
|
+
}
|
|
422
|
+
main().catch((err) => {
|
|
423
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
424
|
+
console.error(`Error: ${message}`);
|
|
425
|
+
process.exit(1);
|
|
426
|
+
});
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.printSuccess = printSuccess;
|
|
4
|
+
exports.printError = printError;
|
|
5
|
+
exports.printData = printData;
|
|
6
|
+
exports.exit = exit;
|
|
7
|
+
function printSuccess(message, opts) {
|
|
8
|
+
if (opts?.json) {
|
|
9
|
+
console.log(JSON.stringify({ status: 'ok', message }));
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
console.log(`✓ ${message}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function printError(message, opts) {
|
|
16
|
+
if (opts?.json) {
|
|
17
|
+
console.log(JSON.stringify({ status: 'error', message }));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.error(`✗ ${message}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function printData(data, opts) {
|
|
24
|
+
if (opts?.json) {
|
|
25
|
+
console.log(JSON.stringify(data));
|
|
26
|
+
}
|
|
27
|
+
else if (typeof data === 'string') {
|
|
28
|
+
console.log(data);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
console.log(JSON.stringify(data, null, 2));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function exit(code) {
|
|
35
|
+
process.exit(code);
|
|
36
|
+
}
|
package/dist/pkg-root.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findPkgRoot = findPkgRoot;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Walk up from __dirname to find the package root (the directory containing
|
|
11
|
+
* package.json). This handles both the normal build (dist/...) and the test
|
|
12
|
+
* build (dist-tests/packages/cli/src/...) where __dirname has extra path
|
|
13
|
+
* levels, making a fixed relative path incorrect.
|
|
14
|
+
*/
|
|
15
|
+
function findPkgRoot(fromDir) {
|
|
16
|
+
let dir = fromDir;
|
|
17
|
+
while (true) {
|
|
18
|
+
if (fs_1.default.existsSync(path_1.default.join(dir, 'package.json'))) {
|
|
19
|
+
return dir;
|
|
20
|
+
}
|
|
21
|
+
const parent = path_1.default.dirname(dir);
|
|
22
|
+
if (parent === dir)
|
|
23
|
+
break;
|
|
24
|
+
dir = parent;
|
|
25
|
+
}
|
|
26
|
+
// Fallback: two levels up from the file's directory (dist/commands/ → pkg root)
|
|
27
|
+
return path_1.default.join(fromDir, '..', '..');
|
|
28
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const install_js_1 = require("./commands/install.js");
|
|
4
|
+
// Runs as `postinstall` after `npm install -g @houwert/conductor`.
|
|
5
|
+
// Silent on failure so it never breaks the npm install.
|
|
6
|
+
try {
|
|
7
|
+
(0, install_js_1.installPlugin)();
|
|
8
|
+
process.stdout.write('✓ Conductor Claude Code plugin installed\n');
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
// Silent on failure — never break npm install
|
|
12
|
+
}
|