@sensaiorg/mcp 0.1.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.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Platform auto-detection — discovers which debugging targets are available.
3
+ */
4
+ import type { IPlatformAdapter } from "@sensai/core";
5
+ /**
6
+ * Detect available platforms based on environment and connected devices.
7
+ *
8
+ * If SENSAI_PLATFORMS env var is set, only those platforms are attempted.
9
+ * Otherwise, auto-detect all available platforms.
10
+ */
11
+ export declare function detectPlatforms(): Promise<IPlatformAdapter[]>;
12
+ //# sourceMappingURL=platform-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-detector.d.ts","sourceRoot":"","sources":["../src/platform-detector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAOrD;;;;;GAKG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA2CnE"}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ /**
3
+ * Platform auto-detection — discovers which debugging targets are available.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.detectPlatforms = detectPlatforms;
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_util_1 = require("node:util");
9
+ const adapter_android_1 = require("@sensai/adapter-android");
10
+ const adapter_chrome_1 = require("@sensai/adapter-chrome");
11
+ const adapter_ios_1 = require("@sensai/adapter-ios");
12
+ const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
13
+ /**
14
+ * Detect available platforms based on environment and connected devices.
15
+ *
16
+ * If SENSAI_PLATFORMS env var is set, only those platforms are attempted.
17
+ * Otherwise, auto-detect all available platforms.
18
+ */
19
+ async function detectPlatforms() {
20
+ const explicit = process.env.SENSAI_PLATFORMS;
21
+ const platforms = explicit
22
+ ? explicit.split(",").map((p) => p.trim().toLowerCase())
23
+ : ["android", "chrome", "ios"]; // Try all
24
+ const results = await Promise.allSettled(platforms.map(async (platform) => {
25
+ switch (platform) {
26
+ case "android":
27
+ if (await isAndroidAvailable()) {
28
+ process.stderr.write("[sensai] Detected: Android device/emulator\n");
29
+ return new adapter_android_1.AndroidAdapter();
30
+ }
31
+ return null;
32
+ case "chrome":
33
+ if (await isChromeExtensionAvailable()) {
34
+ process.stderr.write("[sensai] Detected: Chrome Extension\n");
35
+ return new adapter_chrome_1.ChromeAdapter();
36
+ }
37
+ return null;
38
+ case "ios":
39
+ if (await isIosSimulatorAvailable()) {
40
+ process.stderr.write("[sensai] Detected: iOS Simulator\n");
41
+ return new adapter_ios_1.IosAdapter();
42
+ }
43
+ return null;
44
+ default:
45
+ process.stderr.write(`[sensai] Unknown platform: ${platform}\n`);
46
+ return null;
47
+ }
48
+ }));
49
+ const adapters = results
50
+ .filter((r) => r.status === "fulfilled")
51
+ .map((r) => r.value)
52
+ .filter((a) => a !== null);
53
+ return adapters;
54
+ }
55
+ /**
56
+ * Check if an Android device/emulator is connected via ADB.
57
+ */
58
+ async function isAndroidAvailable() {
59
+ try {
60
+ const adbPath = process.env.ADB_PATH ?? "adb";
61
+ const { stdout } = await execFileAsync(adbPath, ["devices"], { timeout: 5000 });
62
+ const lines = stdout.split("\n").filter((l) => l.includes("\tdevice"));
63
+ return lines.length > 0;
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ /**
70
+ * Check if the SensAI Chrome Extension WebSocket server is available.
71
+ */
72
+ async function isChromeExtensionAvailable() {
73
+ const port = parseInt(process.env.SENSAI_CHROME_PORT ?? "9230", 10);
74
+ try {
75
+ // Try to connect briefly to the WebSocket port
76
+ const { default: WebSocket } = await import("ws");
77
+ return new Promise((resolve) => {
78
+ const ws = new WebSocket(`ws://localhost:${port}`);
79
+ const timeout = setTimeout(() => {
80
+ ws.close();
81
+ resolve(false);
82
+ }, 2000);
83
+ ws.on("open", () => {
84
+ clearTimeout(timeout);
85
+ ws.close();
86
+ resolve(true);
87
+ });
88
+ ws.on("error", () => {
89
+ clearTimeout(timeout);
90
+ resolve(false);
91
+ });
92
+ });
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ }
98
+ /**
99
+ * Check if an iOS Simulator is booted.
100
+ */
101
+ async function isIosSimulatorAvailable() {
102
+ try {
103
+ const { stdout } = await execFileAsync("xcrun", [
104
+ "simctl", "list", "devices", "--json",
105
+ ], { timeout: 5000 });
106
+ const data = JSON.parse(stdout);
107
+ for (const devices of Object.values(data.devices)) {
108
+ if (devices.some((d) => d.state === "Booted")) {
109
+ return true;
110
+ }
111
+ }
112
+ return false;
113
+ }
114
+ catch {
115
+ return false;
116
+ }
117
+ }
118
+ //# sourceMappingURL=platform-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-detector.js","sourceRoot":"","sources":["../src/platform-detector.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAiBH,0CA2CC;AA1DD,2DAA8C;AAC9C,yCAAsC;AAEtC,6DAAyD;AACzD,2DAAuD;AACvD,qDAAiD;AAEjD,MAAM,aAAa,GAAG,IAAA,qBAAS,EAAC,6BAAQ,CAAC,CAAC;AAE1C;;;;;GAKG;AACI,KAAK,UAAU,eAAe;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC9C,MAAM,SAAS,GAAG,QAAQ;QACxB,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxD,CAAC,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,UAAU;IAE5C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC/B,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,SAAS;gBACZ,IAAI,MAAM,kBAAkB,EAAE,EAAE,CAAC;oBAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;oBACrE,OAAO,IAAI,gCAAc,EAAsB,CAAC;gBAClD,CAAC;gBACD,OAAO,IAAI,CAAC;YAEd,KAAK,QAAQ;gBACX,IAAI,MAAM,0BAA0B,EAAE,EAAE,CAAC;oBACvC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;oBAC9D,OAAO,IAAI,8BAAa,EAAsB,CAAC;gBACjD,CAAC;gBACD,OAAO,IAAI,CAAC;YAEd,KAAK,KAAK;gBACR,IAAI,MAAM,uBAAuB,EAAE,EAAE,CAAC;oBACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;oBAC3D,OAAO,IAAI,wBAAU,EAAsB,CAAC;gBAC9C,CAAC;gBACD,OAAO,IAAI,CAAC;YAEd;gBACE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,QAAQ,IAAI,CAAC,CAAC;gBACjE,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,QAAQ,GAAuB,OAAO;SACzC,MAAM,CAAC,CAAC,CAAC,EAAwD,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC;SAC7F,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;SACnB,MAAM,CAAC,CAAC,CAAC,EAAyB,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAEpD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,kBAAkB;IAC/B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,KAAK,CAAC;QAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QACvE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,0BAA0B;IACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IACpE,IAAI,CAAC;QACH,+CAA+C;QAC/C,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC,kBAAkB,IAAI,EAAE,CAAC,CAAC;YACnD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC,EAAE,IAAI,CAAC,CAAC;YAET,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;gBACjB,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBAClB,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,uBAAuB;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE;YAC9C,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ;SACtC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAEtB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAE7B,CAAC;QAEF,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAClD,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,EAAE,CAAC;gBAC9C,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Unit tests for platform-detector.ts
3
+ *
4
+ * Mocks child_process.execFile, the ws module, and adapter constructors
5
+ * to test platform detection logic in isolation.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=platform-detector.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-detector.test.d.ts","sourceRoot":"","sources":["../src/platform-detector.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ /**
3
+ * Unit tests for platform-detector.ts
4
+ *
5
+ * Mocks child_process.execFile, the ws module, and adapter constructors
6
+ * to test platform detection logic in isolation.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const vitest_1 = require("vitest");
10
+ const node_util_1 = require("node:util");
11
+ /* ── Mock setup ────────────────────────────────────────────────────── */
12
+ // The real execFile has a [util.promisify.custom] symbol, so promisify()
13
+ // returns that custom implementation rather than wrapping callbacks.
14
+ // We create an execFile function that carries our mock on that symbol.
15
+ const execFileMock = vitest_1.vi.fn();
16
+ function fakeExecFile(..._args) {
17
+ // This callback form is never actually called because promisify
18
+ // will use the custom symbol instead. But it satisfies the shape.
19
+ }
20
+ fakeExecFile[node_util_1.promisify.custom] = execFileMock;
21
+ vitest_1.vi.mock("node:child_process", () => ({
22
+ execFile: fakeExecFile,
23
+ }));
24
+ // Mock the ws module for Chrome extension detection
25
+ let wsOnHandlers = {};
26
+ const wsCloseMock = vitest_1.vi.fn();
27
+ vitest_1.vi.mock("ws", () => ({
28
+ default: class MockWebSocket {
29
+ constructor(_url) {
30
+ // Schedule handler registration to complete before triggering events
31
+ }
32
+ on(event, handler) {
33
+ wsOnHandlers[event] = handler;
34
+ }
35
+ close() {
36
+ wsCloseMock();
37
+ }
38
+ },
39
+ }));
40
+ // Mock adapter modules
41
+ vitest_1.vi.mock("@sensai/adapter-android", () => ({
42
+ AndroidAdapter: vitest_1.vi.fn().mockImplementation(() => ({ platform: "android" })),
43
+ }));
44
+ vitest_1.vi.mock("@sensai/adapter-chrome", () => ({
45
+ ChromeAdapter: vitest_1.vi.fn().mockImplementation(() => ({ platform: "chrome" })),
46
+ }));
47
+ vitest_1.vi.mock("@sensai/adapter-ios", () => ({
48
+ IosAdapter: vitest_1.vi.fn().mockImplementation(() => ({ platform: "ios" })),
49
+ }));
50
+ // Suppress stderr output from the detection code
51
+ const stderrWriteMock = vitest_1.vi
52
+ .spyOn(process.stderr, "write")
53
+ .mockImplementation(() => true);
54
+ /* ── Helpers ────────────────────────────────────────────────────────── */
55
+ /** Simulate adb devices returning connected devices */
56
+ function mockAdbDevices(deviceLines) {
57
+ execFileMock.mockImplementation((cmd) => {
58
+ if (cmd === "adb" || cmd.endsWith("adb")) {
59
+ const stdout = "List of devices attached\n" + deviceLines.join("\n") + "\n";
60
+ return Promise.resolve({ stdout, stderr: "" });
61
+ }
62
+ return Promise.reject(new Error(`Unexpected command: ${cmd}`));
63
+ });
64
+ }
65
+ /** Simulate xcrun simctl returning device data */
66
+ function mockXcrunSimctl(devices) {
67
+ execFileMock.mockImplementation((cmd) => {
68
+ if (cmd === "xcrun") {
69
+ return Promise.resolve({
70
+ stdout: JSON.stringify({ devices }),
71
+ stderr: "",
72
+ });
73
+ }
74
+ return Promise.reject(new Error(`Unexpected command: ${cmd}`));
75
+ });
76
+ }
77
+ /** Simulate both adb and xcrun responses */
78
+ function mockAllCommands(opts) {
79
+ execFileMock.mockImplementation((cmd) => {
80
+ if (cmd === "adb" || cmd.endsWith("adb")) {
81
+ if (opts.adbFails)
82
+ return Promise.reject(new Error("adb not found"));
83
+ const stdout = "List of devices attached\n" +
84
+ (opts.adbLines ?? []).join("\n") +
85
+ "\n";
86
+ return Promise.resolve({ stdout, stderr: "" });
87
+ }
88
+ if (cmd === "xcrun") {
89
+ if (opts.xcrunFails)
90
+ return Promise.reject(new Error("xcrun not found"));
91
+ return Promise.resolve({
92
+ stdout: JSON.stringify({ devices: opts.xcrunDevices ?? {} }),
93
+ stderr: "",
94
+ });
95
+ }
96
+ return Promise.reject(new Error(`Unexpected command: ${cmd}`));
97
+ });
98
+ }
99
+ /* ── Tests ──────────────────────────────────────────────────────────── */
100
+ (0, vitest_1.describe)("detectPlatforms", () => {
101
+ let originalEnv;
102
+ (0, vitest_1.beforeEach)(() => {
103
+ originalEnv = { ...process.env };
104
+ vitest_1.vi.clearAllMocks();
105
+ wsOnHandlers = {};
106
+ });
107
+ (0, vitest_1.afterEach)(() => {
108
+ process.env = originalEnv;
109
+ });
110
+ // Lazy-import so mocks are in place before module loads
111
+ async function loadDetectPlatforms() {
112
+ const mod = await import("./platform-detector.js");
113
+ return mod.detectPlatforms;
114
+ }
115
+ (0, vitest_1.it)("returns empty array when no platforms detected", async () => {
116
+ delete process.env.SENSAI_PLATFORMS;
117
+ // adb returns no devices, xcrun returns no booted sims
118
+ mockAllCommands({ adbLines: [], xcrunDevices: {} });
119
+ // Chrome WS will error (trigger after handlers are registered)
120
+ const detectPromise = loadDetectPlatforms().then((fn) => fn());
121
+ // Give the ws constructor time to register handlers, then trigger error
122
+ await new Promise((r) => setTimeout(r, 10));
123
+ wsOnHandlers["error"]?.();
124
+ const result = await detectPromise;
125
+ (0, vitest_1.expect)(result).toEqual([]);
126
+ });
127
+ (0, vitest_1.it)("detects Android when adb devices returns a device line", async () => {
128
+ process.env.SENSAI_PLATFORMS = "android";
129
+ mockAdbDevices(["emulator-5554\tdevice"]);
130
+ const detectPlatforms = await loadDetectPlatforms();
131
+ const result = await detectPlatforms();
132
+ (0, vitest_1.expect)(result).toHaveLength(1);
133
+ (0, vitest_1.expect)(result[0]).toEqual({ platform: "android" });
134
+ });
135
+ (0, vitest_1.it)("does not detect Android when adb devices returns no devices", async () => {
136
+ process.env.SENSAI_PLATFORMS = "android";
137
+ mockAdbDevices([]);
138
+ const detectPlatforms = await loadDetectPlatforms();
139
+ const result = await detectPlatforms();
140
+ (0, vitest_1.expect)(result).toEqual([]);
141
+ });
142
+ (0, vitest_1.it)("handles ADB command failure gracefully", async () => {
143
+ process.env.SENSAI_PLATFORMS = "android";
144
+ execFileMock.mockRejectedValue(new Error("adb: command not found"));
145
+ const detectPlatforms = await loadDetectPlatforms();
146
+ const result = await detectPlatforms();
147
+ (0, vitest_1.expect)(result).toEqual([]);
148
+ });
149
+ (0, vitest_1.it)("detects iOS when xcrun returns booted device", async () => {
150
+ process.env.SENSAI_PLATFORMS = "ios";
151
+ mockXcrunSimctl({
152
+ "com.apple.CoreSimulator.SimRuntime.iOS-17-0": [
153
+ { state: "Shutdown" },
154
+ { state: "Booted" },
155
+ ],
156
+ });
157
+ const detectPlatforms = await loadDetectPlatforms();
158
+ const result = await detectPlatforms();
159
+ (0, vitest_1.expect)(result).toHaveLength(1);
160
+ (0, vitest_1.expect)(result[0]).toEqual({ platform: "ios" });
161
+ });
162
+ (0, vitest_1.it)("does not detect iOS when no booted simulators", async () => {
163
+ process.env.SENSAI_PLATFORMS = "ios";
164
+ mockXcrunSimctl({
165
+ "com.apple.CoreSimulator.SimRuntime.iOS-17-0": [
166
+ { state: "Shutdown" },
167
+ { state: "Shutdown" },
168
+ ],
169
+ });
170
+ const detectPlatforms = await loadDetectPlatforms();
171
+ const result = await detectPlatforms();
172
+ (0, vitest_1.expect)(result).toEqual([]);
173
+ });
174
+ (0, vitest_1.it)("handles xcrun failure gracefully", async () => {
175
+ process.env.SENSAI_PLATFORMS = "ios";
176
+ execFileMock.mockRejectedValue(new Error("xcrun: command not found"));
177
+ const detectPlatforms = await loadDetectPlatforms();
178
+ const result = await detectPlatforms();
179
+ (0, vitest_1.expect)(result).toEqual([]);
180
+ });
181
+ (0, vitest_1.it)("respects SENSAI_PLATFORMS env var to limit detection", async () => {
182
+ process.env.SENSAI_PLATFORMS = "android";
183
+ mockAdbDevices(["emulator-5554\tdevice"]);
184
+ const detectPlatforms = await loadDetectPlatforms();
185
+ const result = await detectPlatforms();
186
+ // Should only have android, not ios or chrome
187
+ (0, vitest_1.expect)(result).toHaveLength(1);
188
+ (0, vitest_1.expect)(result[0]).toEqual({ platform: "android" });
189
+ // xcrun should never have been called since we only asked for android
190
+ const xcrunCalls = execFileMock.mock.calls.filter((call) => call[0] === "xcrun");
191
+ (0, vitest_1.expect)(xcrunCalls).toHaveLength(0);
192
+ });
193
+ (0, vitest_1.it)("logs warning for unknown platform in SENSAI_PLATFORMS", async () => {
194
+ process.env.SENSAI_PLATFORMS = "unknown_platform";
195
+ const detectPlatforms = await loadDetectPlatforms();
196
+ const result = await detectPlatforms();
197
+ (0, vitest_1.expect)(result).toEqual([]);
198
+ (0, vitest_1.expect)(stderrWriteMock).toHaveBeenCalledWith("[sensai] Unknown platform: unknown_platform\n");
199
+ });
200
+ (0, vitest_1.it)("auto-detects all platforms when SENSAI_PLATFORMS not set", async () => {
201
+ delete process.env.SENSAI_PLATFORMS;
202
+ mockAllCommands({
203
+ adbLines: ["emulator-5554\tdevice"],
204
+ xcrunDevices: {
205
+ "com.apple.CoreSimulator.SimRuntime.iOS-17-0": [
206
+ { state: "Booted" },
207
+ ],
208
+ },
209
+ });
210
+ // Start detection
211
+ const detectPlatforms = await loadDetectPlatforms();
212
+ const detectPromise = detectPlatforms();
213
+ // Give time for ws constructor to register handlers, then trigger open
214
+ await new Promise((r) => setTimeout(r, 10));
215
+ wsOnHandlers["open"]?.();
216
+ const result = await detectPromise;
217
+ // All 3 should be detected
218
+ (0, vitest_1.expect)(result).toHaveLength(3);
219
+ const platforms = result.map((a) => a.platform);
220
+ (0, vitest_1.expect)(platforms).toContain("android");
221
+ (0, vitest_1.expect)(platforms).toContain("chrome");
222
+ (0, vitest_1.expect)(platforms).toContain("ios");
223
+ });
224
+ (0, vitest_1.it)("detects multiple platforms simultaneously", async () => {
225
+ process.env.SENSAI_PLATFORMS = "android,ios";
226
+ mockAllCommands({
227
+ adbLines: ["device-123\tdevice"],
228
+ xcrunDevices: {
229
+ "com.apple.CoreSimulator.SimRuntime.iOS-17-0": [
230
+ { state: "Booted" },
231
+ ],
232
+ },
233
+ });
234
+ const detectPlatforms = await loadDetectPlatforms();
235
+ const result = await detectPlatforms();
236
+ (0, vitest_1.expect)(result).toHaveLength(2);
237
+ const platforms = result.map((a) => a.platform);
238
+ (0, vitest_1.expect)(platforms).toContain("android");
239
+ (0, vitest_1.expect)(platforms).toContain("ios");
240
+ });
241
+ });
242
+ //# sourceMappingURL=platform-detector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-detector.test.js","sourceRoot":"","sources":["../src/platform-detector.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * SensAI MCP Server — Unified multi-platform UI debugging for AI agents.
4
+ *
5
+ * Auto-detects available platforms (Android, Chrome, iOS) and registers
6
+ * appropriate debugging tools for each.
7
+ *
8
+ * Usage:
9
+ * node dist/server.js
10
+ *
11
+ * Environment variables:
12
+ * # Android
13
+ * ADB_DEVICE - ADB device serial (default: "emulator-5554")
14
+ * DEBUG_AGENT_PORT - TCP port for on-device agent (default: "8463")
15
+ * TARGET_PACKAGE - Android package to debug (default: "com.chronocrew")
16
+ *
17
+ * # Chrome
18
+ * SENSAI_CHROME_PORT - WebSocket port for Chrome extension (default: "9230")
19
+ * SENSAI_CHROME_TAB_URL - Auto-attach to tab matching this URL
20
+ *
21
+ * # iOS
22
+ * IOS_BUNDLE_ID - iOS app bundle ID (default: "com.chronocrew")
23
+ * IOS_SIMULATOR_ID - Simulator UDID (default: "booted")
24
+ *
25
+ * # General
26
+ * SENSAI_PLATFORMS - Comma-separated list: "android,chrome,ios" (default: auto-detect)
27
+ */
28
+ export {};
29
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG"}
package/dist/server.js ADDED
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * SensAI MCP Server — Unified multi-platform UI debugging for AI agents.
5
+ *
6
+ * Auto-detects available platforms (Android, Chrome, iOS) and registers
7
+ * appropriate debugging tools for each.
8
+ *
9
+ * Usage:
10
+ * node dist/server.js
11
+ *
12
+ * Environment variables:
13
+ * # Android
14
+ * ADB_DEVICE - ADB device serial (default: "emulator-5554")
15
+ * DEBUG_AGENT_PORT - TCP port for on-device agent (default: "8463")
16
+ * TARGET_PACKAGE - Android package to debug (default: "com.chronocrew")
17
+ *
18
+ * # Chrome
19
+ * SENSAI_CHROME_PORT - WebSocket port for Chrome extension (default: "9230")
20
+ * SENSAI_CHROME_TAB_URL - Auto-attach to tab matching this URL
21
+ *
22
+ * # iOS
23
+ * IOS_BUNDLE_ID - iOS app bundle ID (default: "com.chronocrew")
24
+ * IOS_SIMULATOR_ID - Simulator UDID (default: "booted")
25
+ *
26
+ * # General
27
+ * SENSAI_PLATFORMS - Comma-separated list: "android,chrome,ios" (default: auto-detect)
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
31
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
32
+ const platform_detector_js_1 = require("./platform-detector.js");
33
+ const shared_tools_js_1 = require("./tools/shared-tools.js");
34
+ async function main() {
35
+ // Create the MCP server
36
+ const server = new mcp_js_1.McpServer({
37
+ name: "sensai",
38
+ version: "0.1.0",
39
+ });
40
+ // Detect and initialize available platforms
41
+ const adapters = await (0, platform_detector_js_1.detectPlatforms)();
42
+ const connectedAdapters = [];
43
+ for (const adapter of adapters) {
44
+ try {
45
+ const status = await adapter.initialize();
46
+ process.stderr.write(`[sensai] ${status.platform}: ${status.connected ? "CONNECTED" : "FAILED"} — ${status.device}\n`);
47
+ if (status.connected) {
48
+ connectedAdapters.push(adapter);
49
+ // Register platform-specific tools
50
+ adapter.registerPlatformTools(server);
51
+ }
52
+ }
53
+ catch (err) {
54
+ process.stderr.write(`[sensai] ${adapter.platform}: ERROR — ${err instanceof Error ? err.message : String(err)}\n`);
55
+ }
56
+ }
57
+ if (connectedAdapters.length === 0) {
58
+ process.stderr.write("[sensai] WARNING: No platforms connected. Server will start but tools may fail.\n" +
59
+ "[sensai] Ensure at least one target is available:\n" +
60
+ "[sensai] - Android: adb devices (emulator or device)\n" +
61
+ "[sensai] - Chrome: SensAI Chrome Extension running\n" +
62
+ "[sensai] - iOS: xcrun simctl list devices (simulator booted)\n");
63
+ }
64
+ // Register shared cross-platform tools
65
+ (0, shared_tools_js_1.registerSharedTools)(server, connectedAdapters);
66
+ // Count total registered tools across all adapters
67
+ // Shared tools (7) + Chrome (10) + Android (25) + iOS (24) per registration counts
68
+ const platformNames = connectedAdapters.map((a) => a.platform);
69
+ // ── MCP Resources ─────────────────────────────────────────────────
70
+ // Resource: sensai://version — server metadata and platform overview
71
+ server.resource("version", "sensai://version", { description: "SensAI server version, Node.js version, and platform info", mimeType: "application/json" }, async () => ({
72
+ contents: [{
73
+ uri: "sensai://version",
74
+ mimeType: "application/json",
75
+ text: JSON.stringify({
76
+ sensai: "0.1.0",
77
+ node: process.version,
78
+ platforms: platformNames,
79
+ toolCount: 70,
80
+ }, null, 2),
81
+ }],
82
+ }));
83
+ // Resource: sensai://platforms — detailed platform adapter status
84
+ server.resource("platforms", "sensai://platforms", { description: "Detailed status for each connected platform adapter", mimeType: "application/json" }, async () => {
85
+ const platformDetails = connectedAdapters.map((a) => ({
86
+ platform: a.platform,
87
+ displayName: a.displayName,
88
+ connected: a.isConnected(),
89
+ capabilities: a.capabilities,
90
+ }));
91
+ return {
92
+ contents: [{
93
+ uri: "sensai://platforms",
94
+ mimeType: "application/json",
95
+ text: JSON.stringify({
96
+ connectedCount: connectedAdapters.length,
97
+ platforms: platformDetails,
98
+ }, null, 2),
99
+ }],
100
+ };
101
+ });
102
+ // Graceful shutdown
103
+ const shutdown = () => {
104
+ process.stderr.write("[sensai] Shutting down...\n");
105
+ for (const adapter of connectedAdapters) {
106
+ adapter.shutdown();
107
+ }
108
+ process.exit(0);
109
+ };
110
+ process.on("SIGINT", shutdown);
111
+ process.on("SIGTERM", shutdown);
112
+ // Start MCP server on stdio
113
+ const transport = new stdio_js_1.StdioServerTransport();
114
+ await server.connect(transport);
115
+ const platformSummary = platformNames.join(", ") || "none";
116
+ process.stderr.write(`[sensai] MCP server running on stdio | platforms: ${platformSummary}\n`);
117
+ }
118
+ main().catch((err) => {
119
+ process.stderr.write(`[sensai] Fatal error: ${err instanceof Error ? err.message : String(err)}\n`);
120
+ process.exit(1);
121
+ });
122
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared cross-platform MCP tools.
3
+ *
4
+ * These tools work identically on any platform by delegating to the
5
+ * appropriate adapter's providers. When multiple platforms are connected,
6
+ * tools are prefixed with the platform name (e.g., android_get_ui_tree).
7
+ *
8
+ * Unified tools (diagnose, screenshot, tap, type_text, swipe, get_logs)
9
+ * are only registered when a SINGLE platform is connected, to avoid
10
+ * ambiguity about which device is being targeted.
11
+ */
12
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13
+ import type { IPlatformAdapter } from "@sensai/core";
14
+ /**
15
+ * Register shared tools that delegate to platform adapters.
16
+ *
17
+ * During the migration period (Phase 1), Android tools are registered
18
+ * directly from the adapter's legacy tool files. As providers are extracted,
19
+ * these shared tools will replace them.
20
+ */
21
+ export declare function registerSharedTools(server: McpServer, adapters: IPlatformAdapter[]): void;
22
+ //# sourceMappingURL=shared-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-tools.d.ts","sourceRoot":"","sources":["../../src/tools/shared-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,gBAAgB,EAAE,GAC3B,IAAI,CA0EN"}
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+ /**
3
+ * Shared cross-platform MCP tools.
4
+ *
5
+ * These tools work identically on any platform by delegating to the
6
+ * appropriate adapter's providers. When multiple platforms are connected,
7
+ * tools are prefixed with the platform name (e.g., android_get_ui_tree).
8
+ *
9
+ * Unified tools (diagnose, screenshot, tap, type_text, swipe, get_logs)
10
+ * are only registered when a SINGLE platform is connected, to avoid
11
+ * ambiguity about which device is being targeted.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.registerSharedTools = registerSharedTools;
15
+ const zod_1 = require("zod");
16
+ /**
17
+ * Register shared tools that delegate to platform adapters.
18
+ *
19
+ * During the migration period (Phase 1), Android tools are registered
20
+ * directly from the adapter's legacy tool files. As providers are extracted,
21
+ * these shared tools will replace them.
22
+ */
23
+ function registerSharedTools(server, adapters) {
24
+ const multiPlatform = adapters.length > 1;
25
+ // Register a meta-tool for server version and info
26
+ server.tool("get_version", "Get SensAI server version, Node.js version, connected platforms, and tool count", {}, async () => {
27
+ const platforms = adapters.map((a) => ({
28
+ platform: a.platform,
29
+ name: a.displayName,
30
+ connected: a.isConnected(),
31
+ }));
32
+ return {
33
+ content: [{
34
+ type: "text",
35
+ text: JSON.stringify({
36
+ sensai: "0.1.0",
37
+ node: process.version,
38
+ platforms,
39
+ toolCount: 70,
40
+ }),
41
+ }],
42
+ };
43
+ });
44
+ // Register a meta-tool for listing connected platforms
45
+ server.tool("list_platforms", "List all connected debugging platforms and their capabilities", {}, async () => {
46
+ const platforms = adapters.map((a) => ({
47
+ platform: a.platform,
48
+ name: a.displayName,
49
+ connected: a.isConnected(),
50
+ capabilities: a.capabilities,
51
+ }));
52
+ return {
53
+ content: [{
54
+ type: "text",
55
+ text: JSON.stringify({ platforms, activePlatforms: platforms.length }),
56
+ }],
57
+ };
58
+ });
59
+ // For each adapter, register the Android legacy tools during migration
60
+ for (const adapter of adapters) {
61
+ if (adapter.platform === "android") {
62
+ // During migration, Android tools are registered via registerPlatformTools()
63
+ // which calls the legacy emudebug tool registration functions.
64
+ // These will be migrated to provider-based shared tools over time.
65
+ registerAndroidLegacyTools(server, adapter, multiPlatform);
66
+ }
67
+ if (adapter.platform === "chrome") {
68
+ // Chrome tools are now registered directly via adapter.registerPlatformTools()
69
+ }
70
+ if (adapter.platform === "ios") {
71
+ // iOS tools are registered directly via adapter.registerPlatformTools()
72
+ }
73
+ }
74
+ // Register unified cross-platform tools only when a single platform is connected.
75
+ // This avoids ambiguity about which device/simulator to target.
76
+ if (!multiPlatform && adapters.length === 1) {
77
+ registerUnifiedTools(server, adapters[0]);
78
+ }
79
+ }
80
+ /**
81
+ * Register unified tools that delegate to the single connected adapter.
82
+ * These provide a platform-agnostic interface for common operations.
83
+ */
84
+ function registerUnifiedTools(server, adapter) {
85
+ const platform = adapter.platform;
86
+ // ── diagnose ────────────────────────────────────────────────────────
87
+ // Delegates to the platform's diagnose_screen tool.
88
+ // Since MCP tools are already registered by the adapter, we create a
89
+ // convenience alias that calls the platform-specific tool name.
90
+ server.tool("diagnose", `[Unified] Comprehensive screen diagnosis for the connected ${platform} device. Returns screenshot, logs, device info, and screen state in a unified format. Delegates to the platform-specific diagnose tool.`, {}, async () => {
91
+ if (!adapter.isConnected()) {
92
+ return {
93
+ content: [{ type: "text", text: JSON.stringify({ error: `${platform} adapter is not connected` }) }],
94
+ isError: true,
95
+ };
96
+ }
97
+ // Build diagnosis using available providers
98
+ const diagnosis = { platform };
99
+ const results = await Promise.allSettled([
100
+ adapter.screenshot?.capture(),
101
+ adapter.logs?.getLogs({ maxEntries: 50 }),
102
+ ]);
103
+ // Screenshot
104
+ const screenshotResult = results[0];
105
+ if (screenshotResult.status === "fulfilled" && screenshotResult.value) {
106
+ diagnosis.hasScreenshot = true;
107
+ }
108
+ else {
109
+ diagnosis.hasScreenshot = false;
110
+ }
111
+ // Logs
112
+ const logsResult = results[1];
113
+ if (logsResult.status === "fulfilled" && logsResult.value) {
114
+ const logs = logsResult.value;
115
+ diagnosis.recentLogCount = logs.length;
116
+ diagnosis.recentErrors = logs.filter((l) => l.level === "E" || l.level === "F").length;
117
+ }
118
+ diagnosis.deviceName = adapter.displayName;
119
+ diagnosis.capabilities = adapter.capabilities;
120
+ const content = [
121
+ { type: "text", text: JSON.stringify(diagnosis) },
122
+ ];
123
+ if (screenshotResult.status === "fulfilled" && screenshotResult.value) {
124
+ content.push({
125
+ type: "image",
126
+ data: screenshotResult.value.base64,
127
+ mimeType: screenshotResult.value.mimeType,
128
+ });
129
+ }
130
+ return { content };
131
+ });
132
+ // ── screenshot ──────────────────────────────────────────────────────
133
+ server.tool("screenshot", `[Unified] Take a screenshot of the connected ${platform} device screen. Returns a base64-encoded PNG image.`, {}, async () => {
134
+ if (!adapter.screenshot) {
135
+ return {
136
+ content: [{ type: "text", text: JSON.stringify({ error: `${platform} does not support screenshots` }) }],
137
+ isError: true,
138
+ };
139
+ }
140
+ try {
141
+ const result = await adapter.screenshot.capture();
142
+ return {
143
+ content: [{
144
+ type: "image",
145
+ data: result.base64,
146
+ mimeType: result.mimeType,
147
+ }],
148
+ };
149
+ }
150
+ catch (err) {
151
+ return {
152
+ content: [{ type: "text", text: `Screenshot failed: ${err instanceof Error ? err.message : String(err)}` }],
153
+ isError: true,
154
+ };
155
+ }
156
+ });
157
+ // ── tap ─────────────────────────────────────────────────────────────
158
+ server.tool("unified_tap", `[Unified] Tap at x,y coordinates on the connected ${platform} device.`, {
159
+ x: zod_1.z.number().describe("X coordinate to tap"),
160
+ y: zod_1.z.number().describe("Y coordinate to tap"),
161
+ }, async ({ x, y }) => {
162
+ if (!adapter.interaction) {
163
+ return {
164
+ content: [{ type: "text", text: JSON.stringify({ error: `${platform} does not support interactions` }) }],
165
+ isError: true,
166
+ };
167
+ }
168
+ try {
169
+ const result = await adapter.interaction.tap({ x, y });
170
+ return {
171
+ content: [{ type: "text", text: JSON.stringify({ ok: true, ...result }) }],
172
+ };
173
+ }
174
+ catch (err) {
175
+ return {
176
+ content: [{ type: "text", text: `Tap failed: ${err instanceof Error ? err.message : String(err)}` }],
177
+ isError: true,
178
+ };
179
+ }
180
+ });
181
+ // ── type_text ───────────────────────────────────────────────────────
182
+ server.tool("unified_type_text", `[Unified] Type text into the focused field on the connected ${platform} device.`, {
183
+ text: zod_1.z.string().describe("Text to type"),
184
+ clearFirst: zod_1.z.boolean().optional().describe("Clear the field before typing (default: false)"),
185
+ }, async ({ text, clearFirst }) => {
186
+ if (!adapter.interaction) {
187
+ return {
188
+ content: [{ type: "text", text: JSON.stringify({ error: `${platform} does not support interactions` }) }],
189
+ isError: true,
190
+ };
191
+ }
192
+ try {
193
+ await adapter.interaction.typeText(text, { clearFirst: clearFirst ?? false });
194
+ return {
195
+ content: [{ type: "text", text: JSON.stringify({ ok: true }) }],
196
+ };
197
+ }
198
+ catch (err) {
199
+ return {
200
+ content: [{ type: "text", text: `Type failed: ${err instanceof Error ? err.message : String(err)}` }],
201
+ isError: true,
202
+ };
203
+ }
204
+ });
205
+ // ── swipe ───────────────────────────────────────────────────────────
206
+ server.tool("unified_swipe", `[Unified] Swipe from one point to another on the connected ${platform} device.`, {
207
+ startX: zod_1.z.number().describe("Start X coordinate"),
208
+ startY: zod_1.z.number().describe("Start Y coordinate"),
209
+ endX: zod_1.z.number().describe("End X coordinate"),
210
+ endY: zod_1.z.number().describe("End Y coordinate"),
211
+ durationMs: zod_1.z.number().optional().describe("Swipe duration in milliseconds (default: 300)"),
212
+ }, async ({ startX, startY, endX, endY, durationMs }) => {
213
+ if (!adapter.interaction) {
214
+ return {
215
+ content: [{ type: "text", text: JSON.stringify({ error: `${platform} does not support interactions` }) }],
216
+ isError: true,
217
+ };
218
+ }
219
+ try {
220
+ await adapter.interaction.swipe({ x: startX, y: startY }, { x: endX, y: endY }, durationMs ?? 300);
221
+ return {
222
+ content: [{ type: "text", text: JSON.stringify({ ok: true }) }],
223
+ };
224
+ }
225
+ catch (err) {
226
+ return {
227
+ content: [{ type: "text", text: `Swipe failed: ${err instanceof Error ? err.message : String(err)}` }],
228
+ isError: true,
229
+ };
230
+ }
231
+ });
232
+ // ── get_logs ────────────────────────────────────────────────────────
233
+ server.tool("unified_get_logs", `[Unified] Get recent logs from the connected ${platform} device. Returns filtered log entries.`, {
234
+ level: zod_1.z.enum(["V", "D", "I", "W", "E", "F"]).optional().describe("Minimum log level"),
235
+ grep: zod_1.z.string().optional().describe("Regex pattern to filter messages"),
236
+ maxLines: zod_1.z.number().optional().describe("Maximum entries to return (default: 100)"),
237
+ }, async ({ level, grep, maxLines }) => {
238
+ if (!adapter.logs) {
239
+ return {
240
+ content: [{ type: "text", text: JSON.stringify({ error: `${platform} does not support log reading` }) }],
241
+ isError: true,
242
+ };
243
+ }
244
+ try {
245
+ let entries = await adapter.logs.getLogs({
246
+ level: level,
247
+ filter: grep,
248
+ maxEntries: maxLines ?? 100,
249
+ });
250
+ const limit = maxLines ?? 100;
251
+ const totalMatches = entries.length;
252
+ entries = entries.slice(-limit);
253
+ return {
254
+ content: [{
255
+ type: "text",
256
+ text: JSON.stringify({
257
+ totalMatches,
258
+ returned: entries.length,
259
+ truncated: totalMatches > limit,
260
+ entries,
261
+ }),
262
+ }],
263
+ };
264
+ }
265
+ catch (err) {
266
+ return {
267
+ content: [{ type: "text", text: `Log retrieval failed: ${err instanceof Error ? err.message : String(err)}` }],
268
+ isError: true,
269
+ };
270
+ }
271
+ });
272
+ }
273
+ function registerAndroidLegacyTools(_server, _adapter, _multiPlatform) {
274
+ // Android legacy tools are already registered via adapter.registerPlatformTools()
275
+ // and the original emudebug tool files (ui-tree.ts, interaction.ts, etc.)
276
+ // This function will progressively take over as providers are extracted.
277
+ }
278
+ // Chrome tools are implemented in @sensai/adapter-chrome/src/tools/chrome-tools.ts
279
+ // iOS tools are implemented in @sensai/adapter-ios/src/tools/ios-tools.ts
280
+ //# sourceMappingURL=shared-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-tools.js","sourceRoot":"","sources":["../../src/tools/shared-tools.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@sensaiorg/mcp",
3
+ "version": "0.1.0",
4
+ "description": "SensAI MCP Server — The fastest AI-to-mobile debugging bridge. Structured UI debugging for AI agents across Android, iOS, and Chrome.",
5
+ "main": "dist/server.js",
6
+ "types": "dist/server.d.ts",
7
+ "bin": {
8
+ "sensai-mcp": "dist/server.js",
9
+ "sensai": "dist/server.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -b",
17
+ "dev": "node --watch dist/server.js",
18
+ "start": "node dist/server.js",
19
+ "clean": "rm -rf dist .tsbuildinfo",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "ai",
26
+ "debugging",
27
+ "android",
28
+ "ios",
29
+ "chrome",
30
+ "adb",
31
+ "react-native",
32
+ "ui-testing",
33
+ "mobile-debugging",
34
+ "claude",
35
+ "cursor",
36
+ "windsurf"
37
+ ],
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/Chrono-Crew/sensai.git",
41
+ "directory": "packages/server"
42
+ },
43
+ "homepage": "https://github.com/Chrono-Crew/sensai",
44
+ "bugs": {
45
+ "url": "https://github.com/Chrono-Crew/sensai/issues"
46
+ },
47
+ "author": "Chrono-Crew",
48
+ "license": "Apache-2.0",
49
+ "dependencies": {
50
+ "@sensaiorg/core": "0.1.0",
51
+ "@sensaiorg/adapter-android": "0.1.0",
52
+ "@sensaiorg/adapter-chrome": "0.1.0",
53
+ "@sensaiorg/adapter-ios": "0.1.0",
54
+ "@modelcontextprotocol/sdk": "^1.12.0",
55
+ "zod": "^3.24.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^22.0.0",
59
+ "typescript": "^5.7.0"
60
+ },
61
+ "engines": {
62
+ "node": ">=18.0.0"
63
+ }
64
+ }