@ceraph/react-native-mcp 0.2.2 → 0.3.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 (124) hide show
  1. package/LICENSE +116 -15
  2. package/README.md +79 -77
  3. package/assets/default.png +0 -0
  4. package/dist/app-lifecycle.d.ts +50 -0
  5. package/dist/app-lifecycle.js +487 -0
  6. package/dist/camera-image-writer.d.ts +43 -0
  7. package/dist/camera-image-writer.js +280 -0
  8. package/dist/camera-registry-sync.d.ts +18 -0
  9. package/dist/camera-registry-sync.js +117 -0
  10. package/dist/cli.d.ts +0 -7
  11. package/dist/cli.js +41 -9
  12. package/dist/device-autonomy.d.ts +30 -0
  13. package/dist/device-autonomy.js +117 -0
  14. package/dist/error-parser.d.ts +6 -26
  15. package/dist/error-parser.js +4 -74
  16. package/dist/expo-manager.d.ts +2 -74
  17. package/dist/expo-manager.js +11 -125
  18. package/dist/index.d.ts +0 -7
  19. package/dist/index.js +1266 -56
  20. package/dist/init/ast-camera.d.ts +29 -0
  21. package/dist/init/ast-camera.js +267 -0
  22. package/dist/init/ast-layout.d.ts +15 -0
  23. package/dist/init/ast-layout.js +167 -0
  24. package/dist/init/claude-hook-constants.d.ts +9 -0
  25. package/dist/init/claude-hook-constants.js +91 -0
  26. package/dist/init/lan-ip.d.ts +11 -0
  27. package/dist/init/lan-ip.js +51 -0
  28. package/dist/init/monorepo.d.ts +13 -0
  29. package/dist/init/monorepo.js +185 -0
  30. package/dist/init/oauth.d.ts +52 -0
  31. package/dist/init/oauth.js +220 -0
  32. package/dist/init/package-manager.d.ts +11 -0
  33. package/dist/init/package-manager.js +60 -0
  34. package/dist/init/prompt.d.ts +12 -0
  35. package/dist/init/prompt.js +68 -0
  36. package/dist/init/shell-profile.d.ts +22 -0
  37. package/dist/init/shell-profile.js +85 -0
  38. package/dist/init/steps.d.ts +135 -0
  39. package/dist/init/steps.js +399 -0
  40. package/dist/init/url-scheme.d.ts +42 -0
  41. package/dist/init/url-scheme.js +187 -0
  42. package/dist/init/walkthrough.d.ts +76 -0
  43. package/dist/init/walkthrough.js +340 -0
  44. package/dist/init.d.ts +7 -7
  45. package/dist/init.js +280 -120
  46. package/dist/iproxy-manager.d.ts +32 -0
  47. package/dist/iproxy-manager.js +216 -0
  48. package/dist/mac-caffeinate.d.ts +10 -0
  49. package/dist/mac-caffeinate.js +56 -0
  50. package/dist/permission-interceptor.d.ts +29 -0
  51. package/dist/permission-interceptor.js +185 -0
  52. package/dist/prebuild-detector.d.ts +0 -30
  53. package/dist/prebuild-detector.js +1 -42
  54. package/dist/preflight.d.ts +34 -0
  55. package/dist/preflight.js +847 -0
  56. package/dist/screen.d.ts +132 -43
  57. package/dist/screen.js +668 -94
  58. package/dist/shim/boot.d.ts +41 -0
  59. package/dist/shim/boot.js +141 -0
  60. package/dist/shim/camera.d.ts +22 -0
  61. package/dist/shim/camera.js +62 -0
  62. package/dist/shim/config.d.ts +6 -0
  63. package/dist/shim/config.js +56 -0
  64. package/dist/shim/deep-link.d.ts +1 -0
  65. package/dist/shim/deep-link.js +25 -0
  66. package/dist/shim/dev-guard.d.ts +1 -0
  67. package/dist/shim/dev-guard.js +3 -0
  68. package/dist/shim/error-handler.d.ts +20 -0
  69. package/dist/shim/error-handler.js +66 -0
  70. package/dist/shim/fetch-interceptor.d.ts +13 -0
  71. package/dist/shim/fetch-interceptor.js +93 -0
  72. package/dist/shim/index.d.ts +6 -0
  73. package/dist/shim/index.js +6 -0
  74. package/dist/shim/keep-awake.d.ts +13 -0
  75. package/dist/shim/keep-awake.js +118 -0
  76. package/dist/shim/reload.d.ts +23 -0
  77. package/dist/shim/reload.js +76 -0
  78. package/dist/shim/signal-capture.d.ts +11 -0
  79. package/dist/shim/signal-capture.js +15 -0
  80. package/dist/shim/signal-transport.d.ts +17 -0
  81. package/dist/shim/signal-transport.js +43 -0
  82. package/dist/signal-listener.d.ts +27 -0
  83. package/dist/signal-listener.js +135 -0
  84. package/dist/simulator-boot.d.ts +52 -0
  85. package/dist/simulator-boot.js +227 -0
  86. package/dist/target.d.ts +48 -0
  87. package/dist/target.js +267 -0
  88. package/dist/uninstall/cli-runner.d.ts +32 -0
  89. package/dist/uninstall/cli-runner.js +223 -0
  90. package/dist/uninstall/footprint.d.ts +40 -0
  91. package/dist/uninstall/footprint.js +288 -0
  92. package/dist/uninstall/mcp-tools.d.ts +14 -0
  93. package/dist/uninstall/mcp-tools.js +175 -0
  94. package/dist/uninstall/revert-auth.d.ts +22 -0
  95. package/dist/uninstall/revert-auth.js +31 -0
  96. package/dist/uninstall/revert-boot.d.ts +24 -0
  97. package/dist/uninstall/revert-boot.js +242 -0
  98. package/dist/uninstall/revert-camera.d.ts +12 -0
  99. package/dist/uninstall/revert-camera.js +199 -0
  100. package/dist/uninstall/revert-ceraph-dir.d.ts +27 -0
  101. package/dist/uninstall/revert-ceraph-dir.js +38 -0
  102. package/dist/uninstall/revert-claude-hooks.d.ts +19 -0
  103. package/dist/uninstall/revert-claude-hooks.js +191 -0
  104. package/dist/uninstall/revert-gitignore.d.ts +17 -0
  105. package/dist/uninstall/revert-gitignore.js +43 -0
  106. package/dist/uninstall/revert-mcp-clients.d.ts +57 -0
  107. package/dist/uninstall/revert-mcp-clients.js +194 -0
  108. package/dist/uninstall/revert-package.d.ts +34 -0
  109. package/dist/uninstall/revert-package.js +98 -0
  110. package/dist/uninstall/revert-scheme.d.ts +36 -0
  111. package/dist/uninstall/revert-scheme.js +139 -0
  112. package/dist/uninstall/revert-signal-host-env.d.ts +31 -0
  113. package/dist/uninstall/revert-signal-host-env.js +61 -0
  114. package/dist/uninstall/walkthrough.d.ts +80 -0
  115. package/dist/uninstall/walkthrough.js +1244 -0
  116. package/dist/utils/atomic-write.d.ts +1 -0
  117. package/dist/utils/atomic-write.js +30 -0
  118. package/dist/wait-for-device.d.ts +68 -0
  119. package/dist/wait-for-device.js +368 -0
  120. package/dist/wda-manager.d.ts +38 -0
  121. package/dist/wda-manager.js +186 -0
  122. package/dist/wda-simulator.d.ts +28 -0
  123. package/dist/wda-simulator.js +257 -0
  124. package/package.json +59 -5
@@ -0,0 +1,118 @@
1
+ import { isDevRuntime } from "./dev-guard.js";
2
+ let resolvedProvider;
3
+ let resolvedProviderId;
4
+ let active = false;
5
+ export function _resetForTesting() {
6
+ resolvedProvider = undefined;
7
+ resolvedProviderId = undefined;
8
+ active = false;
9
+ }
10
+ export function _setProviderForTesting(provider) {
11
+ resolvedProvider = provider;
12
+ resolvedProviderId = provider ? "test-injected" : null;
13
+ active = false;
14
+ }
15
+ function resolveProvider() {
16
+ const req = globalThis.require;
17
+ if (typeof req === "function") {
18
+ try {
19
+ const mod = req("expo-keep-awake");
20
+ if (mod) {
21
+ const activate = typeof mod.activateKeepAwakeAsync === "function"
22
+ ? () => {
23
+ void mod.activateKeepAwakeAsync?.();
24
+ }
25
+ : typeof mod.activateKeepAwake === "function"
26
+ ? () => mod.activateKeepAwake()
27
+ : undefined;
28
+ const deactivate = typeof mod.deactivateKeepAwake === "function"
29
+ ? () => mod.deactivateKeepAwake()
30
+ : undefined;
31
+ if (activate) {
32
+ return {
33
+ provider: { activate, deactivate },
34
+ id: "expo-keep-awake",
35
+ };
36
+ }
37
+ }
38
+ }
39
+ catch {
40
+ }
41
+ try {
42
+ const mod = req("react-native-keep-awake");
43
+ const candidate = (mod && mod.default) ??
44
+ mod;
45
+ if (candidate && typeof candidate.activate === "function") {
46
+ return { provider: candidate, id: "react-native-keep-awake" };
47
+ }
48
+ }
49
+ catch {
50
+ }
51
+ try {
52
+ const rn = req("react-native");
53
+ const nm = rn?.NativeModules?.RNCKeepAwake;
54
+ if (nm && typeof nm.activate === "function") {
55
+ return { provider: nm, id: "RNCKeepAwake" };
56
+ }
57
+ }
58
+ catch {
59
+ }
60
+ }
61
+ return null;
62
+ }
63
+ export function enableKeepAwake() {
64
+ if (!isDevRuntime())
65
+ return { applied: false, provider: null };
66
+ if (active) {
67
+ return { applied: true, provider: providerIdForResult() };
68
+ }
69
+ if (resolvedProvider === undefined) {
70
+ const resolution = resolveProvider();
71
+ if (resolution) {
72
+ resolvedProvider = resolution.provider;
73
+ resolvedProviderId = resolution.id;
74
+ }
75
+ else {
76
+ resolvedProvider = null;
77
+ resolvedProviderId = null;
78
+ }
79
+ }
80
+ if (!resolvedProvider || typeof resolvedProvider.activate !== "function") {
81
+ return { applied: false, provider: null };
82
+ }
83
+ try {
84
+ resolvedProvider.activate();
85
+ active = true;
86
+ return { applied: true, provider: providerIdForResult() };
87
+ }
88
+ catch (err) {
89
+ const consoleObj = globalThis.console;
90
+ consoleObj?.warn?.(`[ceraph] keep-awake: provider activate() threw — ${err.message ?? "unknown"}`);
91
+ return { applied: false, provider: null };
92
+ }
93
+ }
94
+ export function disableKeepAwake() {
95
+ if (!active)
96
+ return;
97
+ active = false;
98
+ const provider = resolvedProvider;
99
+ if (!provider || typeof provider.deactivate !== "function")
100
+ return;
101
+ try {
102
+ provider.deactivate();
103
+ }
104
+ catch {
105
+ }
106
+ }
107
+ function providerIdForResult() {
108
+ if (!resolvedProvider)
109
+ return null;
110
+ switch (resolvedProviderId) {
111
+ case "expo-keep-awake":
112
+ case "react-native-keep-awake":
113
+ case "RNCKeepAwake":
114
+ return resolvedProviderId;
115
+ default:
116
+ return null;
117
+ }
118
+ }
@@ -0,0 +1,23 @@
1
+ interface DevSettingsLike {
2
+ reload?: () => void;
3
+ }
4
+ interface LinkingLike {
5
+ addEventListener: (type: "url", handler: (event: {
6
+ url: string;
7
+ }) => void) => {
8
+ remove?: () => void;
9
+ } | undefined;
10
+ }
11
+ interface ReloadDeps {
12
+ devSettings?: DevSettingsLike;
13
+ linking?: LinkingLike;
14
+ }
15
+ export declare function triggerJsReload(deps?: ReloadDeps): boolean;
16
+ export interface InstallReloadListenerResult {
17
+ installed: boolean;
18
+ remove: () => void;
19
+ }
20
+ export declare function installReloadListener(deps?: ReloadDeps): InstallReloadListenerResult;
21
+ export declare function _resetForTesting(): void;
22
+ export declare function _isInstalledForTesting(): boolean;
23
+ export {};
@@ -0,0 +1,76 @@
1
+ import { isDevRuntime } from "./dev-guard.js";
2
+ let installed = false;
3
+ let currentSubscription;
4
+ export function triggerJsReload(deps = {}) {
5
+ if (!isDevRuntime())
6
+ return false;
7
+ try {
8
+ const devSettings = deps.devSettings ?? loadDevSettings();
9
+ if (devSettings && typeof devSettings.reload === "function") {
10
+ devSettings.reload();
11
+ return true;
12
+ }
13
+ }
14
+ catch {
15
+ }
16
+ return false;
17
+ }
18
+ export function installReloadListener(deps = {}) {
19
+ const noop = {
20
+ installed: false,
21
+ remove: () => undefined,
22
+ };
23
+ if (!isDevRuntime())
24
+ return noop;
25
+ currentSubscription?.remove?.();
26
+ currentSubscription = undefined;
27
+ let linking;
28
+ try {
29
+ linking = deps.linking ?? loadLinking();
30
+ }
31
+ catch {
32
+ return noop;
33
+ }
34
+ if (!linking || typeof linking.addEventListener !== "function") {
35
+ return noop;
36
+ }
37
+ const sub = linking.addEventListener("url", (event) => {
38
+ if (typeof event?.url !== "string")
39
+ return;
40
+ if (event.url === "ceraph://reload" || event.url.startsWith("ceraph://reload?")) {
41
+ triggerJsReload(deps);
42
+ }
43
+ });
44
+ currentSubscription = sub;
45
+ installed = true;
46
+ return {
47
+ installed: true,
48
+ remove: () => {
49
+ sub?.remove?.();
50
+ if (currentSubscription === sub)
51
+ currentSubscription = undefined;
52
+ },
53
+ };
54
+ }
55
+ function loadDevSettings() {
56
+ const req = globalThis.require;
57
+ if (typeof req !== "function")
58
+ return undefined;
59
+ const mod = req("react-native");
60
+ return mod?.DevSettings;
61
+ }
62
+ function loadLinking() {
63
+ const req = globalThis.require;
64
+ if (typeof req !== "function")
65
+ return undefined;
66
+ const mod = req("react-native");
67
+ return mod?.Linking;
68
+ }
69
+ export function _resetForTesting() {
70
+ currentSubscription?.remove?.();
71
+ currentSubscription = undefined;
72
+ installed = false;
73
+ }
74
+ export function _isInstalledForTesting() {
75
+ return installed;
76
+ }
@@ -0,0 +1,11 @@
1
+ import type { TransportOptions } from "./signal-transport.js";
2
+ export interface InstallSignalCaptureOptions {
3
+ transport?: TransportOptions;
4
+ installReloadListener?: boolean;
5
+ }
6
+ export interface InstallSignalCaptureResult {
7
+ errorHandler: boolean;
8
+ fetchInterceptor: boolean;
9
+ reloadListener: boolean;
10
+ }
11
+ export declare function installSignalCapture(opts?: InstallSignalCaptureOptions): InstallSignalCaptureResult;
@@ -0,0 +1,15 @@
1
+ import { installErrorHandler } from "./error-handler.js";
2
+ import { installFetchInterceptor } from "./fetch-interceptor.js";
3
+ import { installReloadListener } from "./reload.js";
4
+ export function installSignalCapture(opts = {}) {
5
+ const wantReload = opts.installReloadListener !== false;
6
+ let reloadListener = false;
7
+ if (wantReload) {
8
+ reloadListener = installReloadListener().installed;
9
+ }
10
+ return {
11
+ errorHandler: installErrorHandler({ transport: opts.transport }),
12
+ fetchInterceptor: installFetchInterceptor({ transport: opts.transport }),
13
+ reloadListener,
14
+ };
15
+ }
@@ -0,0 +1,17 @@
1
+ export type SignalKind = "js-error" | "unhandled-rejection" | "network-error" | "network-4xx";
2
+ export interface SignalPayload {
3
+ kind: SignalKind;
4
+ message: string;
5
+ stack?: string;
6
+ timestampMs: number;
7
+ url?: string;
8
+ status?: number;
9
+ method?: string;
10
+ durationMs?: number;
11
+ }
12
+ export interface TransportOptions {
13
+ host?: string;
14
+ port?: number;
15
+ rethrowOnFailure?: boolean;
16
+ }
17
+ export declare function postSignal(payload: SignalPayload, opts?: TransportOptions): Promise<void>;
@@ -0,0 +1,43 @@
1
+ import { isDevRuntime } from "./dev-guard.js";
2
+ const DEFAULT_HOST = "localhost";
3
+ const DEFAULT_PORT = 8101;
4
+ const POST_TIMEOUT_MS = 1500;
5
+ function resolveEndpoint(opts = {}) {
6
+ let envHost;
7
+ let envPort;
8
+ if (typeof globalThis !== "undefined") {
9
+ const proc = globalThis.process;
10
+ envHost = proc?.env?.CERAPH_SIGNAL_HOST;
11
+ envPort = proc?.env?.CERAPH_SIGNAL_PORT;
12
+ }
13
+ const host = opts.host ?? envHost ?? DEFAULT_HOST;
14
+ const port = opts.port ?? (envPort ? Number.parseInt(envPort, 10) : DEFAULT_PORT);
15
+ return { host, port: Number.isFinite(port) ? port : DEFAULT_PORT };
16
+ }
17
+ export async function postSignal(payload, opts = {}) {
18
+ if (!isDevRuntime())
19
+ return;
20
+ const { host, port } = resolveEndpoint(opts);
21
+ const controller = new AbortController();
22
+ const timer = setTimeout(() => controller.abort(), POST_TIMEOUT_MS);
23
+ try {
24
+ const fetchFn = globalThis.fetch;
25
+ if (typeof fetchFn !== "function")
26
+ return;
27
+ await fetchFn(`http://${host}:${port}/signal`, {
28
+ method: "POST",
29
+ headers: { "Content-Type": "application/json" },
30
+ body: JSON.stringify(payload),
31
+ signal: controller.signal,
32
+ });
33
+ }
34
+ catch (err) {
35
+ if (opts.rethrowOnFailure)
36
+ throw err;
37
+ const consoleObj = globalThis.console;
38
+ consoleObj?.warn?.(`[ceraph] signal transport: failed to post ${payload.kind} (${err.message ?? "unknown"})`);
39
+ }
40
+ finally {
41
+ clearTimeout(timer);
42
+ }
43
+ }
@@ -0,0 +1,27 @@
1
+ import type { RNManager } from "./expo-manager.js";
2
+ export interface SignalListenerOptions {
3
+ port?: number;
4
+ host?: string;
5
+ }
6
+ export interface SignalListenerStartResult {
7
+ ok: boolean;
8
+ port: number;
9
+ error?: string;
10
+ errorCode?: string;
11
+ }
12
+ export declare class SignalListener {
13
+ private rnManager;
14
+ private server;
15
+ private port;
16
+ private hostOverride;
17
+ constructor(rnManager: Pick<RNManager, "appendShimSignal">, opts?: SignalListenerOptions);
18
+ start(): Promise<SignalListenerStartResult>;
19
+ stop(): Promise<void>;
20
+ handleForTesting(payload: unknown): Promise<{
21
+ ok: boolean;
22
+ error?: string;
23
+ }>;
24
+ private handle;
25
+ private appendIfValid;
26
+ private readBody;
27
+ }
@@ -0,0 +1,135 @@
1
+ import { createServer } from "node:http";
2
+ const DEFAULT_PORT = 8101;
3
+ const MAX_BODY_BYTES = 64 * 1024;
4
+ const KNOWN_KINDS = new Set([
5
+ "metro-error",
6
+ "js-error",
7
+ "unhandled-rejection",
8
+ "network-error",
9
+ "network-4xx",
10
+ ]);
11
+ const DEFAULT_HOST = "127.0.0.1";
12
+ export class SignalListener {
13
+ rnManager;
14
+ server = null;
15
+ port;
16
+ hostOverride;
17
+ constructor(rnManager, opts = {}) {
18
+ this.rnManager = rnManager;
19
+ this.port = opts.port ?? DEFAULT_PORT;
20
+ this.hostOverride = opts.host ?? null;
21
+ }
22
+ async start() {
23
+ const host = this.hostOverride ?? process.env.CERAPH_SIGNAL_HOST ?? DEFAULT_HOST;
24
+ return new Promise((resolve) => {
25
+ const server = createServer((req, res) => this.handle(req, res));
26
+ server.once("error", (err) => {
27
+ resolve({
28
+ ok: false,
29
+ port: this.port,
30
+ error: err.message ?? err.code ?? "listen failed",
31
+ errorCode: err.code,
32
+ });
33
+ });
34
+ server.listen(this.port, host, () => {
35
+ this.server = server;
36
+ resolve({ ok: true, port: this.port });
37
+ });
38
+ });
39
+ }
40
+ async stop() {
41
+ const server = this.server;
42
+ if (!server)
43
+ return;
44
+ this.server = null;
45
+ await new Promise((resolve) => server.close(() => resolve()));
46
+ }
47
+ async handleForTesting(payload) {
48
+ return this.appendIfValid(payload);
49
+ }
50
+ async handle(req, res) {
51
+ if (req.method !== "POST" || req.url !== "/signal") {
52
+ res.statusCode = 404;
53
+ res.end();
54
+ return;
55
+ }
56
+ const body = await this.readBody(req).catch((err) => ({
57
+ tooLarge: false,
58
+ err: err,
59
+ }));
60
+ if ("err" in body) {
61
+ res.statusCode = 400;
62
+ res.end(JSON.stringify({ ok: false, error: body.err.message }));
63
+ return;
64
+ }
65
+ if (body.tooLarge) {
66
+ res.statusCode = 413;
67
+ res.end(JSON.stringify({ ok: false, error: "payload too large" }));
68
+ return;
69
+ }
70
+ let parsed;
71
+ try {
72
+ parsed = JSON.parse(body.text);
73
+ }
74
+ catch (err) {
75
+ res.statusCode = 400;
76
+ res.end(JSON.stringify({ ok: false, error: err.message }));
77
+ return;
78
+ }
79
+ const outcome = await this.appendIfValid(parsed);
80
+ if (!outcome.ok) {
81
+ res.statusCode = 400;
82
+ res.end(JSON.stringify(outcome));
83
+ return;
84
+ }
85
+ res.statusCode = 204;
86
+ res.end();
87
+ }
88
+ async appendIfValid(payload) {
89
+ if (!payload || typeof payload !== "object") {
90
+ return { ok: false, error: "payload must be an object" };
91
+ }
92
+ const p = payload;
93
+ if (typeof p.message !== "string" || p.message.length === 0) {
94
+ return { ok: false, error: "message is required" };
95
+ }
96
+ if (typeof p.kind !== "string" || !KNOWN_KINDS.has(p.kind)) {
97
+ return { ok: false, error: `unknown kind: ${String(p.kind)}` };
98
+ }
99
+ const timestamp = typeof p.timestampMs === "number" && Number.isFinite(p.timestampMs)
100
+ ? new Date(p.timestampMs).toISOString()
101
+ : new Date().toISOString();
102
+ await this.rnManager.appendShimSignal({
103
+ message: p.message,
104
+ stack: typeof p.stack === "string" ? p.stack : "",
105
+ timestamp,
106
+ kind: p.kind,
107
+ url: typeof p.url === "string" ? p.url : undefined,
108
+ status: typeof p.status === "number" ? p.status : undefined,
109
+ method: typeof p.method === "string" ? p.method : undefined,
110
+ durationMs: typeof p.durationMs === "number" ? p.durationMs : undefined,
111
+ });
112
+ return { ok: true };
113
+ }
114
+ readBody(req) {
115
+ return new Promise((resolve, reject) => {
116
+ let received = 0;
117
+ const chunks = [];
118
+ req.on("data", (chunk) => {
119
+ received += chunk.length;
120
+ if (received > MAX_BODY_BYTES) {
121
+ chunks.length = 0;
122
+ resolve({ text: "", tooLarge: true });
123
+ req.removeAllListeners("data");
124
+ req.removeAllListeners("end");
125
+ req.on("data", () => undefined);
126
+ req.on("end", () => undefined);
127
+ return;
128
+ }
129
+ chunks.push(chunk);
130
+ });
131
+ req.on("end", () => resolve({ text: Buffer.concat(chunks).toString("utf-8"), tooLarge: false }));
132
+ req.on("error", reject);
133
+ });
134
+ }
135
+ }
@@ -0,0 +1,52 @@
1
+ export interface BootSimulatorOpts {
2
+ udid?: string;
3
+ deviceType?: string;
4
+ bootTimeoutMs?: number;
5
+ }
6
+ export type BootSimulatorResult = {
7
+ udid: string;
8
+ deviceType: string;
9
+ alreadyBooted: boolean;
10
+ booted: true;
11
+ runtime: string;
12
+ durationMs: number;
13
+ };
14
+ export interface SimctlDeviceEntry {
15
+ udid: string;
16
+ name: string;
17
+ state: string;
18
+ runtime?: string;
19
+ isAvailable?: boolean;
20
+ }
21
+ export interface SimctlListResult {
22
+ devices: Record<string, SimctlDeviceEntry[]>;
23
+ }
24
+ export interface CommandResult {
25
+ code: number;
26
+ stdout: string;
27
+ stderr: string;
28
+ }
29
+ export interface BootSimulatorDeps {
30
+ runner: (cmd: string, args: string[], timeoutMs?: number) => Promise<CommandResult>;
31
+ }
32
+ export declare function runXcrun(cmd: string, args: string[], timeoutMs?: number): Promise<CommandResult>;
33
+ export declare const defaultBootSimulatorDeps: BootSimulatorDeps;
34
+ export declare function parseIosRuntimeVersion(runtimeKey: string): {
35
+ major: number;
36
+ minor: number;
37
+ label: string;
38
+ } | null;
39
+ export declare function pickBestSimulator(list: SimctlListResult, deviceType?: string): {
40
+ udid: string;
41
+ name: string;
42
+ runtimeLabel: string;
43
+ state: string;
44
+ } | null;
45
+ export declare function findSimulatorByUdid(list: SimctlListResult, udid: string): {
46
+ udid: string;
47
+ name: string;
48
+ runtimeLabel: string;
49
+ state: string;
50
+ } | null;
51
+ export declare function isAlreadyBootedError(stderr: string): boolean;
52
+ export declare function bootSimulator(opts?: BootSimulatorOpts, deps?: BootSimulatorDeps): Promise<BootSimulatorResult>;