tapflow 0.1.0-alpha.1 โ†’ 0.1.0-alpha.2

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 (66) hide show
  1. package/README.md +5 -11
  2. package/dist/commands/agent-start.d.ts +7 -0
  3. package/dist/commands/agent-start.d.ts.map +1 -0
  4. package/dist/commands/agent-start.js +78 -0
  5. package/dist/commands/agent-start.js.map +1 -0
  6. package/dist/commands/boot.d.ts +2 -0
  7. package/dist/commands/boot.d.ts.map +1 -0
  8. package/dist/commands/boot.js +47 -0
  9. package/dist/commands/boot.js.map +1 -0
  10. package/dist/commands/devices.d.ts +2 -0
  11. package/dist/commands/devices.d.ts.map +1 -0
  12. package/dist/commands/devices.js +85 -0
  13. package/dist/commands/devices.js.map +1 -0
  14. package/dist/commands/doctor.d.ts +2 -0
  15. package/dist/commands/doctor.d.ts.map +1 -0
  16. package/dist/commands/doctor.js +41 -0
  17. package/dist/commands/doctor.js.map +1 -0
  18. package/dist/commands/init.d.ts +5 -0
  19. package/dist/commands/init.d.ts.map +1 -0
  20. package/dist/commands/init.js +64 -0
  21. package/dist/commands/init.js.map +1 -0
  22. package/dist/commands/logs.d.ts +5 -0
  23. package/dist/commands/logs.d.ts.map +1 -0
  24. package/dist/commands/logs.js +22 -0
  25. package/dist/commands/logs.js.map +1 -0
  26. package/dist/commands/relay-start.d.ts +5 -0
  27. package/dist/commands/relay-start.d.ts.map +1 -0
  28. package/dist/commands/relay-start.js +24 -0
  29. package/dist/commands/relay-start.js.map +1 -0
  30. package/dist/commands/reset.d.ts +2 -0
  31. package/dist/commands/reset.d.ts.map +1 -0
  32. package/dist/commands/reset.js +49 -0
  33. package/dist/commands/reset.js.map +1 -0
  34. package/dist/commands/start.d.ts +6 -0
  35. package/dist/commands/start.d.ts.map +1 -0
  36. package/dist/commands/start.js +77 -0
  37. package/dist/commands/start.js.map +1 -0
  38. package/dist/commands/status.d.ts +4 -0
  39. package/dist/commands/status.d.ts.map +1 -0
  40. package/dist/commands/status.js +56 -0
  41. package/dist/commands/status.js.map +1 -0
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +56 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/lib/doctor.d.ts +12 -0
  47. package/dist/lib/doctor.d.ts.map +1 -0
  48. package/dist/lib/doctor.js +118 -0
  49. package/dist/lib/doctor.js.map +1 -0
  50. package/dist/lib/ios-boot.d.ts +3 -0
  51. package/dist/lib/ios-boot.d.ts.map +1 -0
  52. package/dist/lib/ios-boot.js +44 -0
  53. package/dist/lib/ios-boot.js.map +1 -0
  54. package/dist/lib/platform.d.ts +2 -0
  55. package/dist/lib/platform.d.ts.map +1 -0
  56. package/dist/lib/platform.js +10 -0
  57. package/dist/lib/platform.js.map +1 -0
  58. package/dist/lib/print.d.ts +13 -0
  59. package/dist/lib/print.d.ts.map +1 -0
  60. package/dist/lib/print.js +55 -0
  61. package/dist/lib/print.js.map +1 -0
  62. package/dist/lib/tapflow-dir.d.ts +3 -0
  63. package/dist/lib/tapflow-dir.d.ts.map +1 -0
  64. package/dist/lib/tapflow-dir.js +8 -0
  65. package/dist/lib/tapflow-dir.js.map +1 -0
  66. package/package.json +7 -5
package/README.md CHANGED
@@ -20,17 +20,11 @@
20
20
 
21
21
  ## Demo
22
22
 
23
- <!--
24
- Demo video placeholder.
25
- When the recording is ready, replace this block with:
26
-
27
- [![tapflow demo](docs/public/demo-thumbnail.png)](https://YOUR_VIDEO_URL)
28
-
29
- Recommended thumbnail size: 1280ร—720, saved to docs/public/demo-thumbnail.png
30
- -->
31
-
32
23
  <div align="center">
33
- <strong>๐ŸŽฌ Demo video coming soon</strong>
24
+ <a href="https://github.com/user-attachments/assets/01914ed2-f35c-4230-ae01-166ffe6af395" target="_blank" rel="noopener noreferrer">
25
+ <img src="https://raw.githubusercontent.com/jo-duchan/tapflow/main/docs/public/demo-thumbnail.png" alt="tapflow demo โ€” click to play" width="100%" />
26
+ </a>
27
+ <p><em>Click to play</em></p>
34
28
  </div>
35
29
 
36
30
  ---
@@ -59,7 +53,7 @@
59
53
  ## How it works
60
54
 
61
55
  ```
62
- Browser (QA team) โ†โ€”WebSocketโ€”โ†’ Relay Server โ†โ€”WebSocket (outbound)โ€”โ†’ Mac Agent
56
+ Browser (QA team) โ†โ”€ WebSocket โ”€โ†’ Relay Server โ†โ”€ WebSocket (outbound) โ”€โ†’ Mac Agent
63
57
  (Linux / Mac) (iOS ยท Android)
64
58
  ```
65
59
 
@@ -0,0 +1,7 @@
1
+ export interface AgentStartOptions {
2
+ device?: string;
3
+ relay?: string;
4
+ platform?: 'ios' | 'android' | 'all';
5
+ }
6
+ export declare function cmdAgentStart(opts: AgentStartOptions): Promise<void>;
7
+ //# sourceMappingURL=agent-start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-start.d.ts","sourceRoot":"","sources":["../../src/commands/agent-start.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,CAAA;CACrC;AAUD,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqE1E"}
@@ -0,0 +1,78 @@
1
+ import { z } from 'zod';
2
+ import { AndroidAgent } from '@tapflowio/android-agent';
3
+ import { banner, createSpinner } from '../lib/print.js';
4
+ import { hasAdb } from '../lib/platform.js';
5
+ import { resolveAndBootIOSDevice } from '../lib/ios-boot.js';
6
+ const DEFAULT_RELAY = 'ws://localhost:4000';
7
+ const relayUrlSchema = z
8
+ .string()
9
+ .refine((v) => v.startsWith('ws://') || v.startsWith('wss://'), {
10
+ message: '--relay must start with ws:// or wss://',
11
+ });
12
+ export async function cmdAgentStart(opts) {
13
+ const isMac = process.platform === 'darwin';
14
+ const rawRelay = opts.relay ?? DEFAULT_RELAY;
15
+ const relayResult = relayUrlSchema.safeParse(rawRelay);
16
+ if (!relayResult.success) {
17
+ banner('error', 'INVALID CONFIG', [relayResult.error.issues[0].message]);
18
+ process.exit(1);
19
+ }
20
+ const relayUrl = relayResult.data;
21
+ const explicit = opts.platform;
22
+ const runIOS = explicit === 'ios' || explicit === 'all' || (!explicit && isMac);
23
+ const runAndroid = explicit === 'android' || explicit === 'all' || (!explicit && hasAdb());
24
+ if (!runIOS && !runAndroid) {
25
+ banner('error', 'NO PLATFORM AVAILABLE', [
26
+ 'No iOS simulator or Android adb found.',
27
+ 'Run `tapflow doctor` to diagnose.',
28
+ ]);
29
+ process.exit(1);
30
+ }
31
+ const agents = [];
32
+ // โ”€โ”€ iOS Agent โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
33
+ if (runIOS) {
34
+ const iosAgent = await resolveAndBootIOSDevice(opts.device);
35
+ const iosSpinner = createSpinner('Connecting iOS agentโ€ฆ');
36
+ iosSpinner.start();
37
+ try {
38
+ await iosAgent.connect(relayUrl);
39
+ iosSpinner.stop(true);
40
+ agents.push(iosAgent);
41
+ }
42
+ catch (e) {
43
+ iosSpinner.stop(false);
44
+ banner('error', 'IOS CONNECTION FAILED', [e.message]);
45
+ process.exit(1);
46
+ }
47
+ }
48
+ // โ”€โ”€ Android Agent โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
49
+ if (runAndroid) {
50
+ const androidAgent = new AndroidAgent({ deviceFilter: opts.device });
51
+ const androidSpinner = createSpinner('Connecting Android agentโ€ฆ');
52
+ androidSpinner.start();
53
+ try {
54
+ await androidAgent.connect(relayUrl);
55
+ androidSpinner.stop(true);
56
+ agents.push(androidAgent);
57
+ }
58
+ catch (e) {
59
+ androidSpinner.stop(false);
60
+ if (runIOS && agents.length > 0) {
61
+ console.log(` โš  Android: ${e.message}`);
62
+ }
63
+ else {
64
+ banner('error', 'ANDROID CONNECTION FAILED', [e.message]);
65
+ process.exit(1);
66
+ }
67
+ }
68
+ }
69
+ banner('success', 'TAPFLOW AGENT READY', [
70
+ `Relay : ${relayUrl}`,
71
+ 'Press Ctrl+C to stop.',
72
+ ]);
73
+ process.on('SIGINT', () => {
74
+ agents.forEach((a) => a.disconnect());
75
+ process.exit(0);
76
+ });
77
+ }
78
+ //# sourceMappingURL=agent-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-start.js","sourceRoot":"","sources":["../../src/commands/agent-start.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function cmdBoot(nameOrUdid: string): Promise<void>;
2
+ //# sourceMappingURL=boot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../../src/commands/boot.ts"],"names":[],"mappings":"AAGA,wBAAsB,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+C/D"}
@@ -0,0 +1,47 @@
1
+ import { execSync, spawn } from 'node:child_process';
2
+ import { banner, createSpinner, step } from '../lib/print.js';
3
+ export async function cmdBoot(nameOrUdid) {
4
+ // iOS ๋จผ์ € ํƒ์ƒ‰
5
+ if (process.platform === 'darwin') {
6
+ try {
7
+ const raw = execSync('xcrun simctl list devices --json', { encoding: 'utf8', stdio: 'pipe' });
8
+ const data = JSON.parse(raw);
9
+ const target = Object.values(data.devices).flat().find((d) => d.udid === nameOrUdid || d.name === nameOrUdid);
10
+ if (target) {
11
+ if (target.state === 'Booted') {
12
+ step(`${target.name} is already booted.`);
13
+ return;
14
+ }
15
+ const spinner = createSpinner(`Booting iOS Simulator: ${target.name}โ€ฆ`);
16
+ spinner.start();
17
+ execSync(`xcrun simctl boot ${target.udid}`, { stdio: 'pipe' });
18
+ spinner.stop(true);
19
+ step(`${target.name} booted.`);
20
+ return;
21
+ }
22
+ }
23
+ catch { /* xcrun unavailable */ }
24
+ }
25
+ // Android AVD ํƒ์ƒ‰
26
+ try {
27
+ execSync('which emulator', { stdio: 'pipe' });
28
+ const avdList = execSync('emulator -list-avds', { encoding: 'utf8', stdio: 'pipe' })
29
+ .trim().split('\n').map((l) => l.trim()).filter(Boolean);
30
+ const target = avdList.find((avd) => avd === nameOrUdid);
31
+ if (target) {
32
+ // emulator๋Š” ์‹คํ–‰ ํ›„ ์ข…๋ฃŒ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ detached๋กœ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๊ธฐ๋™
33
+ const child = spawn('emulator', [`@${target}`], { detached: true, stdio: 'ignore' });
34
+ child.unref();
35
+ step(`Android AVD: ${target} is starting in the background.`);
36
+ step('Run `tapflow devices` to check boot status.');
37
+ return;
38
+ }
39
+ }
40
+ catch { /* emulator unavailable */ }
41
+ banner('error', 'DEVICE NOT FOUND', [
42
+ `"${nameOrUdid}" does not match any simulator or AVD.`,
43
+ 'Run `tapflow devices` to see available devices.',
44
+ ]);
45
+ process.exit(1);
46
+ }
47
+ //# sourceMappingURL=boot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boot.js","sourceRoot":"","sources":["../../src/commands/boot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAE7D,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,UAAkB;IAC9C,YAAY;IACZ,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,QAAQ,CAAC,kCAAkC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;YAC7F,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAE1B,CAAA;YACD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CACpD,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,CACtD,CAAA;YACD,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC9B,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,qBAAqB,CAAC,CAAA;oBACzC,OAAM;gBACR,CAAC;gBACD,MAAM,OAAO,GAAG,aAAa,CAAC,0BAA0B,MAAM,CAAC,IAAI,GAAG,CAAC,CAAA;gBACvE,OAAO,CAAC,KAAK,EAAE,CAAA;gBACf,QAAQ,CAAC,qBAAqB,MAAM,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;gBAC/D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBAClB,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,UAAU,CAAC,CAAA;gBAC9B,OAAM;YACR,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,uBAAuB,CAAC,CAAC;IACrC,CAAC;IAED,iBAAiB;IACjB,IAAI,CAAC;QACH,QAAQ,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QAC7C,MAAM,OAAO,GAAG,QAAQ,CAAC,qBAAqB,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;aACjF,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAC1D,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,UAAU,CAAC,CAAA;QACxD,IAAI,MAAM,EAAE,CAAC;YACX,8CAA8C;YAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;YACpF,KAAK,CAAC,KAAK,EAAE,CAAA;YACb,IAAI,CAAC,gBAAgB,MAAM,iCAAiC,CAAC,CAAA;YAC7D,IAAI,CAAC,6CAA6C,CAAC,CAAA;YACnD,OAAM;QACR,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,0BAA0B,CAAC,CAAC;IAEtC,MAAM,CAAC,OAAO,EAAE,kBAAkB,EAAE;QAClC,IAAI,UAAU,wCAAwC;QACtD,iDAAiD;KAClD,CAAC,CAAA;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function cmdDevices(): void;
2
+ //# sourceMappingURL=devices.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devices.d.ts","sourceRoot":"","sources":["../../src/commands/devices.ts"],"names":[],"mappings":"AASA,wBAAgB,UAAU,IAAI,IAAI,CA+EjC"}
@@ -0,0 +1,85 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { banner } from '../lib/print.js';
3
+ export function cmdDevices() {
4
+ const sections = [];
5
+ // โ”€โ”€ iOS โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
6
+ try {
7
+ const raw = execSync('xcrun simctl list devices --json', { encoding: 'utf8', stdio: 'pipe' });
8
+ const data = JSON.parse(raw);
9
+ const all = Object.values(data.devices).flat().filter((d) => d.udid);
10
+ const booted = all.filter((d) => d.state === 'Booted');
11
+ const available = all.filter((d) => d.state === 'Shutdown');
12
+ const lines = [];
13
+ if (booted.length > 0) {
14
+ lines.push(' Booted:');
15
+ for (const d of booted)
16
+ lines.push(` โ— ${d.name} ${d.udid}`);
17
+ }
18
+ if (available.length > 0) {
19
+ lines.push(' Available:');
20
+ for (const d of available.slice(0, 20))
21
+ lines.push(` โ—‹ ${d.name} ${d.udid}`);
22
+ if (available.length > 20)
23
+ lines.push(` โ€ฆ and ${available.length - 20} more`);
24
+ }
25
+ if (lines.length > 0)
26
+ sections.push('iOS Simulators:\n' + lines.join('\n'));
27
+ }
28
+ catch {
29
+ // xcrun not available โ€” skip iOS section
30
+ }
31
+ // โ”€โ”€ Android โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
32
+ try {
33
+ execSync('which adb', { stdio: 'pipe' });
34
+ const runningLines = [];
35
+ try {
36
+ const adbOut = execSync('adb devices', { encoding: 'utf8', stdio: 'pipe' });
37
+ const running = adbOut.trim().split('\n').slice(1).filter((l) => l.startsWith('emulator-'));
38
+ for (const line of running) {
39
+ const serial = line.split('\t')[0]?.trim() ?? '';
40
+ try {
41
+ const name = execSync(`adb -s ${serial} emu avd name`, { encoding: 'utf8', stdio: 'pipe' })
42
+ .split('\n')[0]?.trim() ?? serial;
43
+ runningLines.push(` โ— ${name} ${serial}`);
44
+ }
45
+ catch {
46
+ runningLines.push(` โ— ${serial}`);
47
+ }
48
+ }
49
+ }
50
+ catch { /* adb devices failed */ }
51
+ const availableLines = [];
52
+ try {
53
+ const avdOut = execSync('emulator -list-avds', { encoding: 'utf8', stdio: 'pipe' }).trim();
54
+ const allAvds = avdOut ? avdOut.split('\n').map((l) => l.trim()).filter(Boolean) : [];
55
+ const runningNames = runningLines.map((l) => l.split(' ')[0]?.replace(' โ— ', '') ?? '');
56
+ for (const avd of allAvds) {
57
+ if (!runningNames.includes(avd))
58
+ availableLines.push(` โ—‹ ${avd}`);
59
+ }
60
+ }
61
+ catch { /* emulator not in PATH */ }
62
+ const lines = [];
63
+ if (runningLines.length > 0) {
64
+ lines.push(' Running:');
65
+ lines.push(...runningLines);
66
+ }
67
+ if (availableLines.length > 0) {
68
+ lines.push(' Available:');
69
+ lines.push(...availableLines);
70
+ }
71
+ if (lines.length > 0)
72
+ sections.push('Android AVDs:\n' + lines.join('\n'));
73
+ }
74
+ catch {
75
+ // adb not in PATH โ€” skip Android section
76
+ }
77
+ if (sections.length === 0) {
78
+ banner('error', 'NO DEVICES FOUND', ['Run `tapflow doctor` to diagnose your environment.']);
79
+ return;
80
+ }
81
+ console.log();
82
+ console.log(sections.join('\n\n'));
83
+ console.log();
84
+ }
85
+ //# sourceMappingURL=devices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devices.js","sourceRoot":"","sources":["../../src/commands/devices.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function cmdDoctor(): Promise<void>;
2
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAiBA,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAyB/C"}
@@ -0,0 +1,41 @@
1
+ import { runDoctorChecks } from '../lib/doctor.js';
2
+ import { banner, step, GREEN, RED, BOLD, DIM, R } from '../lib/print.js';
3
+ function printChecks(checks) {
4
+ let hasFailure = false;
5
+ for (const check of checks) {
6
+ if (check.ok) {
7
+ console.log(` ${GREEN}โœ“${R} ${check.label}`);
8
+ }
9
+ else {
10
+ console.log(` ${RED}โœ—${R} ${check.label}`);
11
+ if (check.detail)
12
+ console.log(`${DIM} โ†’ ${check.detail}${R}`);
13
+ hasFailure = true;
14
+ }
15
+ }
16
+ return hasFailure;
17
+ }
18
+ export async function cmdDoctor() {
19
+ console.log('\ntapflow doctor\n');
20
+ const result = await runDoctorChecks();
21
+ let hasFailure = false;
22
+ hasFailure = printChecks(result.common) || hasFailure;
23
+ if (result.ios) {
24
+ console.log(`\n ${BOLD}iOS${R}`);
25
+ hasFailure = printChecks(result.ios) || hasFailure;
26
+ }
27
+ if (result.android) {
28
+ console.log(`\n ${BOLD}Android${R}`);
29
+ hasFailure = printChecks(result.android) || hasFailure;
30
+ }
31
+ console.log();
32
+ if (hasFailure) {
33
+ banner('error', 'SOME CHECKS FAILED', ['Fix the issues above before running `tapflow start`.']);
34
+ process.exit(1);
35
+ }
36
+ else {
37
+ step('All checks passed.');
38
+ console.log();
39
+ }
40
+ }
41
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAoB,MAAM,kBAAkB,CAAA;AACpE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAA;AAExE,SAAS,WAAW,CAAC,MAAqB;IACxC,IAAI,UAAU,GAAG,KAAK,CAAA;IACtB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;QAChD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;YAC5C,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,YAAY,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,CAAA;YACnE,UAAU,GAAG,IAAI,CAAA;QACnB,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAA;IACjC,MAAM,MAAM,GAAG,MAAM,eAAe,EAAE,CAAA;IACtC,IAAI,UAAU,GAAG,KAAK,CAAA;IAEtB,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,UAAU,CAAA;IAErD,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC,EAAE,CAAC,CAAA;QACjC,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,UAAU,CAAA;IACpD,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;QACrC,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,UAAU,CAAA;IACxD,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,EAAE,oBAAoB,EAAE,CAAC,sDAAsD,CAAC,CAAC,CAAA;QAC/F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,oBAAoB,CAAC,CAAA;QAC1B,OAAO,CAAC,GAAG,EAAE,CAAA;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface InitOptions {
2
+ relay?: string;
3
+ }
4
+ export declare function cmdInit(opts: InitOptions): Promise<void>;
5
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgE9D"}
@@ -0,0 +1,64 @@
1
+ import * as readline from 'node:readline/promises';
2
+ import { stdin as input, stdout as output } from 'node:process';
3
+ import { createSpinner, banner, step } from '../lib/print.js';
4
+ export async function cmdInit(opts) {
5
+ const baseUrl = (opts.relay ?? 'http://localhost:4000').replace(/^wss?:\/\//, 'http://');
6
+ const rl = readline.createInterface({ input, output });
7
+ const email = (await rl.question(' ? Admin email: ')).trim();
8
+ // Node.js has no native password-input API. Suppress echo via readline's internal
9
+ // _writeToOutput hook โ€” a widely used convention that remains stable across versions.
10
+ process.stdout.write(' ? Password: ');
11
+ const rlAny = rl;
12
+ const origWriteToOutput = rlAny._writeToOutput;
13
+ if (origWriteToOutput)
14
+ rlAny._writeToOutput = () => { };
15
+ const password = (await rl.question('')).trim();
16
+ if (origWriteToOutput)
17
+ rlAny._writeToOutput = origWriteToOutput;
18
+ process.stdout.write('\n');
19
+ rl.close();
20
+ if (!email) {
21
+ banner('error', 'INVALID INPUT', ['Email is required.']);
22
+ process.exit(1);
23
+ }
24
+ if (!password || password.length < 8) {
25
+ banner('error', 'INVALID INPUT', ['Password must be at least 8 characters.']);
26
+ process.exit(1);
27
+ }
28
+ const spinner = createSpinner('Creating admin account...');
29
+ spinner.start();
30
+ let res = null;
31
+ try {
32
+ res = await fetch(`${baseUrl}/api/v1/auth/init`, {
33
+ method: 'POST',
34
+ headers: { 'Content-Type': 'application/json' },
35
+ body: JSON.stringify({ email, password }),
36
+ });
37
+ }
38
+ catch {
39
+ spinner.stop(false);
40
+ banner('error', 'Could not connect to relay', [
41
+ `Relay not found at ${baseUrl}`,
42
+ 'Run tapflow start first, then tapflow init.',
43
+ ]);
44
+ process.exit(1);
45
+ }
46
+ if (!res.ok) {
47
+ spinner.stop(false);
48
+ const data = await res.json();
49
+ if (res.status === 403) {
50
+ banner('error', 'Already initialized', [
51
+ 'An admin account already exists.',
52
+ 'Use Settings โ†’ Team in the dashboard to manage users.',
53
+ ]);
54
+ }
55
+ else {
56
+ banner('error', 'Failed to create admin', [data.error ?? `HTTP ${res.status}`]);
57
+ }
58
+ process.exit(1);
59
+ }
60
+ spinner.stop(true);
61
+ banner('success', 'Admin account created', [`Email: ${email}`]);
62
+ step(`Open ${baseUrl} to sign in`);
63
+ }
64
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function cmdLogs(opts: {
2
+ relay?: string;
3
+ lines?: number;
4
+ }): Promise<void>;
5
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAEA,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrF"}
@@ -0,0 +1,22 @@
1
+ import { DIM, RED, R } from '../lib/print.js';
2
+ export async function cmdLogs(opts) {
3
+ const base = (opts.relay ?? 'http://localhost:4000').replace(/^ws/, 'http');
4
+ const lines = opts.lines ?? 100;
5
+ const url = `${base}/api/v1/logs?lines=${lines}`;
6
+ const res = await fetch(url).catch(() => null);
7
+ if (!res || !res.ok) {
8
+ console.error(`\n ${RED}โœ—${R} Could not reach relay at ${base}\n Make sure tapflow is running.\n`);
9
+ process.exit(1);
10
+ }
11
+ const entries = await res.json();
12
+ if (entries.length === 0) {
13
+ console.log(`\n ${DIM}No log entries yet.${R}\n`);
14
+ return;
15
+ }
16
+ console.log();
17
+ for (const line of entries) {
18
+ console.log(` ${DIM}${line}${R}`);
19
+ }
20
+ console.log();
21
+ }
22
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAA;AAE7C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAwC;IACpE,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,uBAAuB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAC3E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,CAAA;IAC/B,MAAM,GAAG,GAAG,GAAG,IAAI,sBAAsB,KAAK,EAAE,CAAA;IAEhD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IAE9C,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,8BAA8B,IAAI,qCAAqC,CAAC,CAAA;QACrG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,OAAO,GAAa,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;IAE1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAA;QAClD,OAAM;IACR,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,CAAA;IACpC,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAA;AACf,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface RelayStartOptions {
2
+ port?: number;
3
+ }
4
+ export declare function cmdRelayStart(opts: RelayStartOptions): Promise<void>;
5
+ //# sourceMappingURL=relay-start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-start.d.ts","sourceRoot":"","sources":["../../src/commands/relay-start.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAMD,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB1E"}
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod';
2
+ import { RelayServer } from '@tapflowio/relay';
3
+ import { banner, step } from '../lib/print.js';
4
+ const DEFAULT_PORT = 4000;
5
+ const portSchema = z.number().int().min(1).max(65535, 'port must be between 1 and 65535');
6
+ export async function cmdRelayStart(opts) {
7
+ const rawPort = opts.port ?? DEFAULT_PORT;
8
+ const portResult = portSchema.safeParse(rawPort);
9
+ if (!portResult.success) {
10
+ banner('error', 'INVALID CONFIG', [`--port: ${portResult.error.issues[0].message}`]);
11
+ process.exit(1);
12
+ }
13
+ const port = portResult.data;
14
+ const server = new RelayServer({ port });
15
+ await server.start();
16
+ step(`Relay started on ws://localhost:${port}`);
17
+ banner('success', 'TAPFLOW RELAY READY', [
18
+ `Relay : http://localhost:${port}`,
19
+ `Connect Mac agents: tapflow start --relay ws://<host>:${port}`,
20
+ 'Press Ctrl+C to stop.',
21
+ ]);
22
+ process.on('SIGINT', () => process.exit(0));
23
+ }
24
+ //# sourceMappingURL=relay-start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay-start.js","sourceRoot":"","sources":["../../src/commands/relay-start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAM9C,MAAM,YAAY,GAAG,IAAI,CAAA;AAEzB,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,kCAAkC,CAAC,CAAA;AAEzF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAuB;IACzD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,IAAI,YAAY,CAAA;IACzC,MAAM,UAAU,GAAG,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IAChD,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,CAAC,OAAO,EAAE,gBAAgB,EAAE,CAAC,WAAW,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QACpF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAA;IAC5B,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;IACxC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAA;IACpB,IAAI,CAAC,mCAAmC,IAAI,EAAE,CAAC,CAAA;IAE/C,MAAM,CAAC,SAAS,EAAE,qBAAqB,EAAE;QACvC,6BAA6B,IAAI,EAAE;QACnC,0DAA0D,IAAI,EAAE;QAChE,uBAAuB;KACxB,CAAC,CAAA;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AAC7C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function cmdReset(): Promise<void>;
2
+ //# sourceMappingURL=reset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset.d.ts","sourceRoot":"","sources":["../../src/commands/reset.ts"],"names":[],"mappings":"AAKA,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CA8C9C"}
@@ -0,0 +1,49 @@
1
+ import { execSync } from 'node:child_process';
2
+ import * as readline from 'node:readline/promises';
3
+ import { stdin as input, stdout as output } from 'node:process';
4
+ import { banner, step } from '../lib/print.js';
5
+ export async function cmdReset() {
6
+ const rl = readline.createInterface({ input, output });
7
+ const answer = await rl.question('This will shut down all simulators and emulators (no data loss). Continue? [y/N] ');
8
+ rl.close();
9
+ if (!answer.trim().toLowerCase().startsWith('y')) {
10
+ console.log('\n Aborted.\n');
11
+ return;
12
+ }
13
+ // iOS
14
+ if (process.platform === 'darwin') {
15
+ try {
16
+ execSync('xcrun simctl shutdown all', { stdio: 'pipe' });
17
+ step('iOS: all simulators shut down.');
18
+ }
19
+ catch {
20
+ step('iOS: no simulators to shut down.');
21
+ }
22
+ }
23
+ // Android
24
+ try {
25
+ execSync('which adb', { stdio: 'pipe' });
26
+ const out = execSync('adb devices', { encoding: 'utf8', stdio: 'pipe' });
27
+ const emulators = out.trim().split('\n').slice(1)
28
+ .filter((l) => l.startsWith('emulator-'))
29
+ .map((l) => l.split('\t')[0]?.trim() ?? '')
30
+ .filter(Boolean);
31
+ if (emulators.length === 0) {
32
+ step('Android: no running emulators.');
33
+ }
34
+ else {
35
+ for (const serial of emulators) {
36
+ try {
37
+ execSync(`adb -s ${serial} emu kill`, { stdio: 'pipe' });
38
+ step(`Android: ${serial} shut down.`);
39
+ }
40
+ catch {
41
+ step(`Android: could not shut down ${serial}.`);
42
+ }
43
+ }
44
+ }
45
+ }
46
+ catch { /* adb not available */ }
47
+ banner('success', 'RESET COMPLETE');
48
+ }
49
+ //# sourceMappingURL=reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset.js","sourceRoot":"","sources":["../../src/commands/reset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAA;AAClD,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,cAAc,CAAA;AAC/D,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAE9C,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;IACtD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAC9B,mFAAmF,CACpF,CAAA;IACD,EAAE,CAAC,KAAK,EAAE,CAAA;IAEV,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;QAC7B,OAAM;IACR,CAAC;IAED,MAAM;IACN,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,QAAQ,CAAC,2BAA2B,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;YACxD,IAAI,CAAC,gCAAgC,CAAC,CAAA;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,kCAAkC,CAAC,CAAA;QAC1C,CAAC;IACH,CAAC;IAED,UAAU;IACV,IAAI,CAAC;QACH,QAAQ,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;QACxE,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;aAC9C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;aACxC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;aAC1C,MAAM,CAAC,OAAO,CAAC,CAAA;QAElB,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,gCAAgC,CAAC,CAAA;QACxC,CAAC;aAAM,CAAC;YACN,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;gBAC/B,IAAI,CAAC;oBACH,QAAQ,CAAC,UAAU,MAAM,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAA;oBACxD,IAAI,CAAC,YAAY,MAAM,aAAa,CAAC,CAAA;gBACvC,CAAC;gBAAC,MAAM,CAAC;oBACP,IAAI,CAAC,gCAAgC,MAAM,GAAG,CAAC,CAAA;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,uBAAuB,CAAC,CAAC;IAEnC,MAAM,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;AACrC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface StartOptions {
2
+ device?: string;
3
+ platform?: 'ios' | 'android' | 'all';
4
+ }
5
+ export declare function cmdStart(opts: StartOptions): Promise<void>;
6
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,CAAA;CACrC;AAID,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EhE"}