@ait-co/devtools 0.1.144 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +47 -218
- package/README.md +36 -246
- package/dist/in-app/auto.d.ts +1 -138
- package/dist/in-app/auto.js +28 -1102
- package/dist/in-app/auto.js.map +1 -1
- package/dist/in-app/index.d.ts +38 -547
- package/dist/in-app/index.d.ts.map +1 -1
- package/dist/in-app/index.js +62 -939
- package/dist/in-app/index.js.map +1 -1
- package/dist/mcp/cli.d.ts +1 -54
- package/dist/mcp/cli.js +33 -9720
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -88
- package/dist/mcp/server.js +36 -1076
- package/dist/mcp/server.js.map +1 -1
- package/dist/mock/index.d.ts +35 -21
- package/dist/mock/index.d.ts.map +1 -1
- package/dist/mock/index.js +81 -2
- package/dist/mock/index.js.map +1 -1
- package/dist/panel/index.js +80 -104
- package/dist/panel/index.js.map +1 -1
- package/dist/relay-url-store-CkVSQZMq.cjs +110 -0
- package/dist/relay-url-store-CkVSQZMq.cjs.map +1 -0
- package/dist/relay-url-store-dkII-DHD.js +109 -0
- package/dist/relay-url-store-dkII-DHD.js.map +1 -0
- package/dist/stubs/bin-devtools-mcp.js +58 -0
- package/dist/stubs/bin-devtools-mcp.js.map +1 -0
- package/dist/stubs/bin-devtools-test.d.ts +2 -0
- package/dist/stubs/bin-devtools-test.js +55 -0
- package/dist/stubs/bin-devtools-test.js.map +1 -0
- package/dist/test-runner/config.d.ts +1 -231
- package/dist/test-runner/config.js +41 -45
- package/dist/test-runner/config.js.map +1 -1
- package/dist/{tunnel-BGT9Curk.cjs → tunnel-BKZkOyQp.cjs} +1 -1
- package/dist/{tunnel-BGT9Curk.cjs.map → tunnel-BKZkOyQp.cjs.map} +1 -1
- package/dist/{tunnel-BOKmLzBO.js → tunnel-CqSCIrdU.js} +1 -1
- package/dist/{tunnel-BOKmLzBO.js.map → tunnel-CqSCIrdU.js.map} +1 -1
- package/dist/unplugin/index.cjs +9 -18
- package/dist/unplugin/index.cjs.map +1 -1
- package/dist/unplugin/index.d.cts +26 -5
- package/dist/unplugin/index.d.cts.map +1 -1
- package/dist/unplugin/index.d.ts +27 -6
- package/dist/unplugin/index.d.ts.map +1 -1
- package/dist/unplugin/index.js +10 -19
- package/dist/unplugin/index.js.map +1 -1
- package/package.json +10 -25
- package/dist/attach-orchestrator-0F0m_UqQ.js +0 -1845
- package/dist/attach-orchestrator-0F0m_UqQ.js.map +0 -1
- package/dist/attach-orchestrator-D65KxFy_.js +0 -1831
- package/dist/attach-orchestrator-D65KxFy_.js.map +0 -1
- package/dist/attach-orchestrator-DL3NQ9ca.js +0 -1846
- package/dist/attach-orchestrator-DL3NQ9ca.js.map +0 -1
- package/dist/bundle-C796JIwG.d.ts +0 -159
- package/dist/bundle-C796JIwG.d.ts.map +0 -1
- package/dist/capture-DsP525OZ.d.ts +0 -58
- package/dist/capture-DsP525OZ.d.ts.map +0 -1
- package/dist/cdp-connection-rP1WdnH5.d.ts +0 -287
- package/dist/cdp-connection-rP1WdnH5.d.ts.map +0 -1
- package/dist/cell-BaLvusOl.js +0 -68
- package/dist/cell-BaLvusOl.js.map +0 -1
- package/dist/cell-CBUS3-nT.js +0 -274
- package/dist/cell-CBUS3-nT.js.map +0 -1
- package/dist/cell-EBKKpAAT.js +0 -307
- package/dist/cell-EBKKpAAT.js.map +0 -1
- package/dist/chii-relay-B3ZhjGMi.js +0 -304
- package/dist/chii-relay-B3ZhjGMi.js.map +0 -1
- package/dist/chii-relay-CGMlePMd.cjs +0 -304
- package/dist/chii-relay-CGMlePMd.cjs.map +0 -1
- package/dist/debug-server-B3ABDrRI.js +0 -456
- package/dist/debug-server-B3ABDrRI.js.map +0 -1
- package/dist/debug-server-BWhwrVXa.js +0 -1158
- package/dist/debug-server-BWhwrVXa.js.map +0 -1
- package/dist/debug-server-CfQNxxGW.js +0 -600
- package/dist/debug-server-CfQNxxGW.js.map +0 -1
- package/dist/devtools-opener-3Drge_RJ.js +0 -75
- package/dist/devtools-opener-3Drge_RJ.js.map +0 -1
- package/dist/devtools-opener-CJpEsXXQ.js +0 -76
- package/dist/devtools-opener-CJpEsXXQ.js.map +0 -1
- package/dist/devtools-opener-CxtryS8c.js +0 -75
- package/dist/devtools-opener-CxtryS8c.js.map +0 -1
- package/dist/in-app/auto.d.ts.map +0 -1
- package/dist/mcp/cli.d.ts.map +0 -1
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/pool-DcaaOwUq.d.ts +0 -14761
- package/dist/pool-DcaaOwUq.d.ts.map +0 -1
- package/dist/qr-http-server-C_lqOrgc.js +0 -1644
- package/dist/qr-http-server-C_lqOrgc.js.map +0 -1
- package/dist/qr-http-server-CopuMbub.js +0 -1644
- package/dist/qr-http-server-CopuMbub.js.map +0 -1
- package/dist/qr-http-server-DrbIVDjO.js +0 -1645
- package/dist/qr-http-server-DrbIVDjO.js.map +0 -1
- package/dist/relay-factory-N9QobQxG.js +0 -206
- package/dist/relay-factory-N9QobQxG.js.map +0 -1
- package/dist/relay-secret-store-BR0YIkNv.cjs +0 -241
- package/dist/relay-secret-store-BR0YIkNv.cjs.map +0 -1
- package/dist/relay-secret-store-Bmyleu0A.js +0 -154
- package/dist/relay-secret-store-Bmyleu0A.js.map +0 -1
- package/dist/relay-secret-store-CQenfcSL.js +0 -154
- package/dist/relay-secret-store-CQenfcSL.js.map +0 -1
- package/dist/relay-secret-store-CYM8CBIF.js +0 -240
- package/dist/relay-secret-store-CYM8CBIF.js.map +0 -1
- package/dist/relay-secret-store-DKxs7zwq.js +0 -153
- package/dist/relay-secret-store-DKxs7zwq.js.map +0 -1
- package/dist/relay-secret-store-WJ8EGkIl.js +0 -153
- package/dist/relay-secret-store-WJ8EGkIl.js.map +0 -1
- package/dist/relay-url-store-BR2XodiO.js +0 -123
- package/dist/relay-url-store-BR2XodiO.js.map +0 -1
- package/dist/relay-url-store-C1as_m5G.cjs +0 -115
- package/dist/relay-url-store-C1as_m5G.cjs.map +0 -1
- package/dist/relay-url-store-CH63fVCm.js +0 -122
- package/dist/relay-url-store-CH63fVCm.js.map +0 -1
- package/dist/relay-url-store-CzFo_84F.js +0 -114
- package/dist/relay-url-store-CzFo_84F.js.map +0 -1
- package/dist/relay-url-store-DaY1QPes.js +0 -123
- package/dist/relay-url-store-DaY1QPes.js.map +0 -1
- package/dist/relay-url-store-xmUuTjXA.js +0 -122
- package/dist/relay-url-store-xmUuTjXA.js.map +0 -1
- package/dist/relay-worker-B5HKkGUY.js +0 -832
- package/dist/relay-worker-B5HKkGUY.js.map +0 -1
- package/dist/relay-worker-YdlpZQl9.d.ts +0 -214
- package/dist/relay-worker-YdlpZQl9.d.ts.map +0 -1
- package/dist/rolldown-runtime-DGkTqVfb.js +0 -15
- package/dist/rolldown-runtime-DUslC3ob.js +0 -14
- package/dist/runtime-kn9DxOeg.d.ts +0 -249
- package/dist/runtime-kn9DxOeg.d.ts.map +0 -1
- package/dist/test-runner/bin.js +0 -2584
- package/dist/test-runner/bin.js.map +0 -1
- package/dist/test-runner/bridge-stub.d.ts +0 -125
- package/dist/test-runner/bridge-stub.d.ts.map +0 -1
- package/dist/test-runner/bridge-stub.js +0 -92
- package/dist/test-runner/bridge-stub.js.map +0 -1
- package/dist/test-runner/bundle.d.ts +0 -2
- package/dist/test-runner/bundle.js +0 -439
- package/dist/test-runner/bundle.js.map +0 -1
- package/dist/test-runner/capture.d.ts +0 -2
- package/dist/test-runner/capture.js +0 -44
- package/dist/test-runner/capture.js.map +0 -1
- package/dist/test-runner/config.d.ts.map +0 -1
- package/dist/test-runner/method-pace.d.ts +0 -82
- package/dist/test-runner/method-pace.d.ts.map +0 -1
- package/dist/test-runner/method-pace.js +0 -120
- package/dist/test-runner/method-pace.js.map +0 -1
- package/dist/test-runner/pool.d.ts +0 -2
- package/dist/test-runner/pool.js +0 -136
- package/dist/test-runner/pool.js.map +0 -1
- package/dist/test-runner/relay-factory.d.ts +0 -11245
- package/dist/test-runner/relay-factory.d.ts.map +0 -1
- package/dist/test-runner/relay-factory.js +0 -206
- package/dist/test-runner/relay-factory.js.map +0 -1
- package/dist/test-runner/relay-worker.d.ts +0 -2
- package/dist/test-runner/relay-worker.js +0 -2
- package/dist/test-runner/report.d.ts +0 -163
- package/dist/test-runner/report.d.ts.map +0 -1
- package/dist/test-runner/report.js +0 -198
- package/dist/test-runner/report.js.map +0 -1
- package/dist/test-runner/rpc.d.ts +0 -56
- package/dist/test-runner/rpc.d.ts.map +0 -1
- package/dist/test-runner/rpc.js +0 -98
- package/dist/test-runner/rpc.js.map +0 -1
- package/dist/test-runner/runtime.d.ts +0 -2
- package/dist/test-runner/runtime.js +0 -659
- package/dist/test-runner/runtime.js.map +0 -1
- package/dist/test-runner/task-graph.d.ts +0 -38
- package/dist/test-runner/task-graph.d.ts.map +0 -1
- package/dist/test-runner/task-graph.js +0 -182
- package/dist/test-runner/task-graph.js.map +0 -1
- package/dist/throttle-DKKzX1qC.js +0 -59
- package/dist/throttle-DKKzX1qC.js.map +0 -1
- package/dist/totp-BqmCLSNA.js +0 -189
- package/dist/totp-BqmCLSNA.js.map +0 -1
- package/dist/totp-CMHR5lsW.cjs +0 -191
- package/dist/totp-CMHR5lsW.cjs.map +0 -1
- package/dist/totp-CZLLKfOC.js +0 -200
- package/dist/totp-CZLLKfOC.js.map +0 -1
- package/dist/totp-DAxys-r0.js +0 -199
- package/dist/totp-DAxys-r0.js.map +0 -1
- package/dist/totp-DfekTBk3.js +0 -211
- package/dist/totp-DfekTBk3.js.map +0 -1
- package/dist/totp-Dwft0Kz7.js +0 -3
- package/dist/totp-WY6l0ysP.js +0 -190
- package/dist/totp-WY6l0ysP.js.map +0 -1
- /package/dist/{test-runner/bin.d.ts → stubs/bin-devtools-mcp.d.ts} +0 -0
package/dist/mcp/server.js
CHANGED
|
@@ -1,1093 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
-
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
-
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
-
//#region src/mcp/ait-http-source.ts
|
|
6
|
-
function isObject$1(value) {
|
|
7
|
-
return typeof value === "object" && value !== null;
|
|
8
|
-
}
|
|
9
|
-
var HttpAitSource = class {
|
|
10
|
-
stateEndpoint;
|
|
11
|
-
fetchImpl;
|
|
12
|
-
constructor(options) {
|
|
13
|
-
this.stateEndpoint = options.stateEndpoint;
|
|
14
|
-
this.fetchImpl = options.fetchImpl ?? ((url) => fetch(url));
|
|
15
|
-
}
|
|
16
|
-
async fetchState() {
|
|
17
|
-
const res = await this.fetchImpl(this.stateEndpoint);
|
|
18
|
-
if (!res.ok) throw new Error(`Failed to fetch mock state from ${this.stateEndpoint}: HTTP ${res.status} ${res.statusText}. Ensure the Vite dev server is running with the @ait-co/devtools unplugin option \`mcp: true\`.`);
|
|
19
|
-
const body = await res.json();
|
|
20
|
-
return isObject$1(body) ? body : {};
|
|
21
|
-
}
|
|
22
|
-
async get(method) {
|
|
23
|
-
switch (method) {
|
|
24
|
-
case "AIT.getMockState": return await this.fetchState();
|
|
25
|
-
case "AIT.getOperationalEnvironment": {
|
|
26
|
-
const state = await this.fetchState();
|
|
27
|
-
return {
|
|
28
|
-
environment: typeof state.environment === "string" ? state.environment : "unknown",
|
|
29
|
-
sdkVersion: typeof state.appVersion === "string" ? state.appVersion : null
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
case "AIT.getSdkCallHistory": {
|
|
33
|
-
const raw = (await this.fetchState()).sdkCallLog;
|
|
34
|
-
return { calls: Array.isArray(raw) ? raw : [] };
|
|
35
|
-
}
|
|
36
|
-
default: throw new Error(`Unknown AIT method: ${String(method)}`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
//#endregion
|
|
41
|
-
//#region src/mcp/envelope.ts
|
|
42
|
-
/**
|
|
43
|
-
* Returns `true` when `AIT_MCP_COMPAT=chrome-devtools` is set, which bypasses
|
|
44
|
-
* envelope wrapping and returns raw payloads (0.1.x back-compat).
|
|
45
|
-
*/
|
|
46
|
-
function isCompatMode() {
|
|
47
|
-
return process.env.AIT_MCP_COMPAT === "chrome-devtools";
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Maps `McpEnvironment` to `EnvelopeEnv`. These are now the same 3-value
|
|
51
|
-
* union (`mock | relay-dev | relay-mobile`; `relay-live` removed in #665),
|
|
52
|
-
* so this is identity — kept as a named export for surface stability if
|
|
53
|
-
* envelope env diverges in the future.
|
|
54
|
-
*/
|
|
55
|
-
function toEnvelopeEnv(env) {
|
|
56
|
-
return env;
|
|
57
|
-
}
|
|
1
|
+
//#region src/stubs/moved.ts
|
|
58
2
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
3
|
+
* Shared copy for the transition stubs left behind by the debug-surface split
|
|
4
|
+
* (#818).
|
|
61
5
|
*
|
|
62
|
-
*
|
|
6
|
+
* TRANSITION — REMOVE IN 1.0.0. Everything in `src/stubs/` exists only so a
|
|
7
|
+
* consumer still on a pre-0.2.0 wiring gets a sentence telling them where the
|
|
8
|
+
* code went, instead of a bare `ERR_PACKAGE_PATH_NOT_EXPORTED`. Once 1.0.0
|
|
9
|
+
* drops them, the same import fails with the resolver's own error — which is
|
|
10
|
+
* the correct end state, just a worse first encounter.
|
|
63
11
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* return jsonResult(wrapEnvelope(listPages(connection, tunnel), {
|
|
67
|
-
* tool: 'list_pages',
|
|
68
|
-
* env: resolveEnvironment(),
|
|
69
|
-
* attached: connection.listTargets().length > 0,
|
|
70
|
-
* }));
|
|
71
|
-
* ```
|
|
72
|
-
*/
|
|
73
|
-
function wrapEnvelope(data, ctx) {
|
|
74
|
-
if (isCompatMode()) return data;
|
|
75
|
-
return {
|
|
76
|
-
ok: true,
|
|
77
|
-
data,
|
|
78
|
-
meta: {
|
|
79
|
-
tool: ctx.tool,
|
|
80
|
-
env: toEnvelopeEnv(ctx.env),
|
|
81
|
-
attached: ctx.attached,
|
|
82
|
-
contentType: ctx.contentType ?? "json"
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/mcp/errors.ts
|
|
88
|
-
/**
|
|
89
|
-
* 한국어 한 줄 "원인 + 다음 행동" 포맷으로 에러 결과를 빌드한다.
|
|
90
|
-
*
|
|
91
|
-
* @param message - 사용자에게 보여줄 에러 본문 (원인 + 다음 행동 포함).
|
|
92
|
-
*/
|
|
93
|
-
function mcpError(message) {
|
|
94
|
-
return {
|
|
95
|
-
content: [{
|
|
96
|
-
type: "text",
|
|
97
|
-
text: message
|
|
98
|
-
}],
|
|
99
|
-
isError: true
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Tier A/B 환경 불일치 거부 메시지.
|
|
12
|
+
* Two stub shapes, and the difference between them is a safety property, not a
|
|
13
|
+
* style choice:
|
|
104
14
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
15
|
+
* - Node-side tooling subpaths (`/mcp/server`, `/mcp/cli`, `/test-runner`)
|
|
16
|
+
* THROW on import. They only ever run in a developer's terminal, so failing
|
|
17
|
+
* loudly at the earliest possible moment is right.
|
|
18
|
+
* - The in-app subpaths (`/in-app`, `/in-app/auto`) MUST NOT throw. That code
|
|
19
|
+
* could be sitting in a shipped production bundle; a throw there takes the
|
|
20
|
+
* user's mini-app down. They degrade to a no-op plus one `console.error`.
|
|
110
21
|
*/
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
//#endregion
|
|
115
|
-
//#region src/mcp/sdk-signatures.ts
|
|
116
|
-
function isObject(v) {
|
|
117
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
118
|
-
}
|
|
119
|
-
function describeArgs(args) {
|
|
120
|
-
try {
|
|
121
|
-
return JSON.stringify(args);
|
|
122
|
-
} catch {
|
|
123
|
-
return String(args);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
22
|
+
/** The package that now owns the MCP daemon, test runner, and dev bridge. */
|
|
23
|
+
const DEBUGGER_PACKAGE = "@ait-co/debugger";
|
|
126
24
|
/**
|
|
127
|
-
*
|
|
25
|
+
* Builds the migration sentence for a moved subpath.
|
|
128
26
|
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* 그냥 통과시킨다(args 무시하는 stub가 많아서 noArgs 체크가 noise).
|
|
132
|
-
* - 실 SDK 시그니처는 `src/__typecheck.ts`의 `Assert<Mock, Original>` 줄로 보장.
|
|
27
|
+
* SECRET-HANDLING: fixed text plus the two specifiers only — no paths, hosts,
|
|
28
|
+
* URLs, or environment values.
|
|
133
29
|
*/
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
ok: false,
|
|
141
|
-
expected: "{ type: 'portrait' | 'landscape' }",
|
|
142
|
-
received: describeArgs(args)
|
|
143
|
-
};
|
|
144
|
-
const type = arg.type;
|
|
145
|
-
if (type !== "portrait" && type !== "landscape") return {
|
|
146
|
-
ok: false,
|
|
147
|
-
expected: "{ type: 'portrait' | 'landscape' }",
|
|
148
|
-
received: describeArgs(args)
|
|
149
|
-
};
|
|
150
|
-
return { ok: true };
|
|
151
|
-
},
|
|
152
|
-
example: "call_sdk('setDeviceOrientation', [{ type: 'landscape' }])"
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
name: "setIosSwipeGestureEnabled",
|
|
156
|
-
validateArgs(args) {
|
|
157
|
-
const arg = args[0];
|
|
158
|
-
if (!isObject(arg) || typeof arg.isEnabled !== "boolean") return {
|
|
159
|
-
ok: false,
|
|
160
|
-
expected: "{ isEnabled: boolean }",
|
|
161
|
-
received: describeArgs(args)
|
|
162
|
-
};
|
|
163
|
-
return { ok: true };
|
|
164
|
-
},
|
|
165
|
-
example: "call_sdk('setIosSwipeGestureEnabled', [{ isEnabled: false }])"
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
name: "setSecureScreen",
|
|
169
|
-
validateArgs(args) {
|
|
170
|
-
const arg = args[0];
|
|
171
|
-
if (!isObject(arg) || typeof arg.enabled !== "boolean") return {
|
|
172
|
-
ok: false,
|
|
173
|
-
expected: "{ enabled: boolean }",
|
|
174
|
-
received: describeArgs(args)
|
|
175
|
-
};
|
|
176
|
-
return { ok: true };
|
|
177
|
-
},
|
|
178
|
-
example: "call_sdk('setSecureScreen', [{ enabled: true }])"
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
name: "setScreenAwakeMode",
|
|
182
|
-
validateArgs(args) {
|
|
183
|
-
const arg = args[0];
|
|
184
|
-
if (!isObject(arg) || typeof arg.enabled !== "boolean") return {
|
|
185
|
-
ok: false,
|
|
186
|
-
expected: "{ enabled: boolean }",
|
|
187
|
-
received: describeArgs(args)
|
|
188
|
-
};
|
|
189
|
-
return { ok: true };
|
|
190
|
-
},
|
|
191
|
-
example: "call_sdk('setScreenAwakeMode', [{ enabled: true }])"
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
name: "getOperationalEnvironment",
|
|
195
|
-
validateArgs(_args) {
|
|
196
|
-
return { ok: true };
|
|
197
|
-
},
|
|
198
|
-
example: "call_sdk('getOperationalEnvironment', [])"
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
name: "getPlatformOS",
|
|
202
|
-
validateArgs(_args) {
|
|
203
|
-
return { ok: true };
|
|
204
|
-
},
|
|
205
|
-
example: "call_sdk('getPlatformOS', [])"
|
|
206
|
-
},
|
|
207
|
-
{
|
|
208
|
-
name: "getDeviceId",
|
|
209
|
-
validateArgs(_args) {
|
|
210
|
-
return { ok: true };
|
|
211
|
-
},
|
|
212
|
-
example: "call_sdk('getDeviceId', [])"
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
name: "getLocale",
|
|
216
|
-
validateArgs(_args) {
|
|
217
|
-
return { ok: true };
|
|
218
|
-
},
|
|
219
|
-
example: "call_sdk('getLocale', [])"
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
name: "getNetworkStatus",
|
|
223
|
-
validateArgs(_args) {
|
|
224
|
-
return { ok: true };
|
|
225
|
-
},
|
|
226
|
-
example: "call_sdk('getNetworkStatus', [])"
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
name: "getSchemeUri",
|
|
230
|
-
validateArgs(_args) {
|
|
231
|
-
return { ok: true };
|
|
232
|
-
},
|
|
233
|
-
example: "call_sdk('getSchemeUri', [])"
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
name: "requestReview",
|
|
237
|
-
validateArgs(_args) {
|
|
238
|
-
return { ok: true };
|
|
239
|
-
},
|
|
240
|
-
example: "call_sdk('requestReview', [])"
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
name: "closeView",
|
|
244
|
-
validateArgs(_args) {
|
|
245
|
-
return { ok: true };
|
|
246
|
-
},
|
|
247
|
-
example: "call_sdk('closeView', [])"
|
|
248
|
-
}
|
|
249
|
-
];
|
|
250
|
-
new Map(SIGNATURES.map((s) => [s.name, s]));
|
|
251
|
-
SIGNATURES.map((s) => s.name);
|
|
252
|
-
[
|
|
253
|
-
"[ait-debug] AIT_DEBUG_TOTP_SECRET이 필수입니다. 32자 이상 16진수(hex) 문자열을 설정하세요.",
|
|
254
|
-
"발급: openssl rand -hex 32",
|
|
255
|
-
"데몬은 start_debug의 projectRoot 인자로 받은 디렉토리에서 .ait_relay 파일을 읽어 이 시크릿을 채웁니다.",
|
|
256
|
-
"프로젝트에서 pnpm dev:phone:cdp를 한 번 띄우면 unplugin이 .ait_relay를 자동 생성하니(tunnel.cdp 옵션 필요), projectRoot를 전달하세요.",
|
|
257
|
-
"자세히: https://docs.aitc.dev/guides/relay-auth-totp"
|
|
258
|
-
].join("\n");
|
|
259
|
-
new Set([
|
|
260
|
-
{
|
|
261
|
-
name: "list_console_messages",
|
|
262
|
-
description: "Lists recent console messages (console.log/warn/error/info) captured from the attached mini-app page over CDP (Runtime.consoleAPICalled). Read-only. Returns level, text, timestamp, and stringified args, oldest-first.",
|
|
263
|
-
inputSchema: {
|
|
264
|
-
type: "object",
|
|
265
|
-
properties: {},
|
|
266
|
-
required: []
|
|
267
|
-
},
|
|
268
|
-
availableIn: "both"
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
name: "list_network_requests",
|
|
272
|
-
description: "Lists recent network requests (XHR/fetch) captured from the attached mini-app page over CDP (Network.requestWillBeSent + Network.responseReceived). Read-only. Returns url, method, status, and timing, oldest-first.",
|
|
273
|
-
inputSchema: {
|
|
274
|
-
type: "object",
|
|
275
|
-
properties: {},
|
|
276
|
-
required: []
|
|
277
|
-
},
|
|
278
|
-
availableIn: "both"
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
name: "list_pages",
|
|
282
|
-
description: "Returns the single active page (at most one) the relay sees attached. When a second page attaches, the previous one is evicted (last-attach wins — single-attach model). The result includes `singleAttachModel: true` so the agent knows the array is always 0 or 1 entries. Also returns whether the cloudflared tunnel is up and the public wss relay URL. The `tunnel` field includes `droppedAt` (ISO timestamp or null/undefined): when non-null the tunnel has permanently dropped after 3 failed reissue attempts — restart the debug server with `npx @ait-co/devtools devtools-mcp`. Each page entry includes a `lastSeenAt` ISO timestamp (last inbound CDP message from that target — useful to detect stale entries when the phone app backgrounded). The result also includes `crashDetectedAt` (ISO timestamp or null): when non-null, a page crash was detected via Inspector.targetCrashed / Target.targetDestroyed since the last attach, the pages list will be empty, and `crashWarning` shows a Korean hint to re-attach. Call this first to confirm a page is attached before reading console/network. When a page attaches or detaches the server emits notifications/tools/list_changed — call tools/list again to get the full updated tool surface.",
|
|
283
|
-
inputSchema: {
|
|
284
|
-
type: "object",
|
|
285
|
-
properties: {},
|
|
286
|
-
required: []
|
|
287
|
-
},
|
|
288
|
-
availableIn: "both"
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
name: "start_attach",
|
|
292
|
-
description: "The tool result already shows the QR to the user directly (Claude Code renders MCP tool output to the user's screen; they press Ctrl+O to expand if it's collapsed). Do NOT re-print or re-render the QR in your reply — that just wastes output tokens. Simply tell the user to scan the QR shown in this tool's output with their phone camera. Single entry point to attach a real device: switches the debug mode (if `mode` is given), builds the self-attaching deep-link QR for the active relay environment, and waits for the phone to attach — all in one call (replaces the old attach-URL + start_debug two-step). Scan the QR with the phone camera to open the mini-app and attach it to this debug session (QR is the single entry path — no USB cable or platform CLI needed).\n\nmode (optional): pass \"relay-sandbox\" (env 2) or \"relay-staging\" (env 3) to switch the active environment first. When omitted, the current relay environment is used as-is (no switch). Passing \"local-browser\" returns an error — start_attach is relay-only (env 2/3). When the session is already in the requested mode, the switch is skipped.\n\nEnvironment-specific behaviour:\n • env 3 / relay-staging: requires scheme_url — the intoss-private://…?_deploymentId=<uuid> URL from `ait deploy --scheme-only`. Splices debug=1 + relay URL into the scheme URL.\n • env 2 / relay-sandbox: scheme_url is NOT used. Instead, reads AIT_TUNNEL_BASE_URL (the https://*.trycloudflare.com app tunnel from `tunnel:{cdp:true}`) and builds a launcher PWA deep-link (https://devtools.aitc.dev/launcher/?url=…&debug=1&relay=…). When projectRoot is given, the app name from <projectRoot>/package.json is added as name= so the launcher partner bar shows it.\n\nWaits for a page to attach by default (up to wait_timeout_seconds, default 60 s). The server automatically opens the QR dashboard in the OS default browser when running on a local GUI machine — headless/remote environments fall back to the text QR in the tool output.\n\nTOTP auto re-mint: when AIT_DEBUG_TOTP_SECRET is set on the MCP server, the attachUrl carries a one-time code (at=<code>) valid for ~3 minutes (the relay gate accepts ±6 TOTP steps). While waiting, start_attach AUTOMATICALLY re-mints a fresh code before the current one expires and refreshes the dashboard QR in place (no browser re-open). You do NOT need to re-call start_attach every time the code would expire — a single call covers the whole wait window. The response includes a `totp` field with `expiresAt` and a `reminted` count of how many fresh codes were issued during the wait. Without AIT_DEBUG_TOTP_SECRET, the attachUrl has no expiry.\n\nselfdebug (env 2 / relay-sandbox only): pass selfdebug=true to add &selfdebug=1 to the launcher deep-link. The launcher PWA then registers its own document as the CDP target instead of the framed mini-app. SINGLE-ATTACH MODEL: attaching the launcher self-target evicts any currently-attached mini-app target — use this mode exclusively for diagnosing the launcher document itself (DOM, safe-area, console). Not applicable in env 3 (relay-staging) — passing selfdebug=true there returns an error.",
|
|
293
|
-
inputSchema: {
|
|
294
|
-
type: "object",
|
|
295
|
-
properties: {
|
|
296
|
-
mode: {
|
|
297
|
-
type: "string",
|
|
298
|
-
enum: [
|
|
299
|
-
"local-browser",
|
|
300
|
-
"relay-sandbox",
|
|
301
|
-
"relay-staging"
|
|
302
|
-
],
|
|
303
|
-
description: "Optional debug mode to switch into before attaching. \"relay-sandbox\" = env 2 (launcher PWA), \"relay-staging\" = env 3 (intoss-private dog-food). \"local-browser\" returns an error (start_attach is relay-only). Omit to keep the current relay environment."
|
|
304
|
-
},
|
|
305
|
-
scheme_url: {
|
|
306
|
-
type: "string",
|
|
307
|
-
description: "The intoss-private:// scheme URL from `ait deploy --scheme-only` (must carry _deploymentId). Required for env 3/relay-staging mode. Not used in env 2/relay-sandbox mode (use AIT_TUNNEL_BASE_URL instead). The authority (host) must be the app name (e.g. intoss-private://aitc-sdk-example?_deploymentId=…). Generic values like \"web\" or an empty host indicate a malformed URL."
|
|
308
|
-
},
|
|
309
|
-
wait_timeout_seconds: {
|
|
310
|
-
type: "number",
|
|
311
|
-
description: "Maximum seconds to wait for a page to attach (default 60, range 1–600). Values outside the range or invalid inputs (0, negative, NaN) fall back to the default silently. During the wait the TOTP code is auto re-minted as needed, so a single call covers the whole window."
|
|
312
|
-
},
|
|
313
|
-
projectRoot: {
|
|
314
|
-
type: "string",
|
|
315
|
-
description: "Absolute path to the mini-app project root (the directory containing its package.json and .ait_urls). When AIT_TUNNEL_BASE_URL is unset (env 2 / relay-mobile only), the daemon reads the app tunnel URL from <projectRoot>/.ait_urls written by the dev server (tunnel:{cdp:true}). Pass this because the daemon's own cwd is fixed at launch. Omit when AIT_TUNNEL_BASE_URL is set explicitly."
|
|
316
|
-
},
|
|
317
|
-
selfdebug: {
|
|
318
|
-
type: "boolean",
|
|
319
|
-
description: "Env 2 / relay-sandbox only. When true, adds &selfdebug=1 to the launcher deep-link so the launcher PWA registers its own document as the CDP target (launcher diagnostics mode). SINGLE-ATTACH MODEL: self-target attach evicts any currently-attached mini-app target. Use only when you need to inspect the launcher itself (DOM, safe-area, console). Passing selfdebug=true in env 3 (relay-staging) returns an error. Default: false (omitted)."
|
|
320
|
-
}
|
|
321
|
-
},
|
|
322
|
-
required: []
|
|
323
|
-
},
|
|
324
|
-
availableIn: "relay"
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
name: "get_dom_document",
|
|
328
|
-
description: "Returns the DOM tree of the attached mini-app page over CDP (DOM.getDocument). Read-only. Use for structural/layout regression diagnosis (e.g. confirming an element exists, inspecting attributes). Returns the document root node with children.",
|
|
329
|
-
inputSchema: {
|
|
330
|
-
type: "object",
|
|
331
|
-
properties: {},
|
|
332
|
-
required: []
|
|
333
|
-
},
|
|
334
|
-
availableIn: "both"
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
name: "take_snapshot",
|
|
338
|
-
description: "Captures a serialized snapshot of the attached page over CDP (DOMSnapshot.captureSnapshot). Read-only. Returns the documents + interned strings table for visual-regression diagnosis (e.g. checking computed CSS custom properties like --sat against the live layout).",
|
|
339
|
-
inputSchema: {
|
|
340
|
-
type: "object",
|
|
341
|
-
properties: {},
|
|
342
|
-
required: []
|
|
343
|
-
},
|
|
344
|
-
availableIn: "both"
|
|
345
|
-
},
|
|
346
|
-
{
|
|
347
|
-
name: "take_screenshot",
|
|
348
|
-
description: "Captures a PNG screenshot of the attached mini-app page over CDP (Page.captureScreenshot) so the agent can see the phone screen directly. Read-only. Returns an image content block — this is the only debug tool that returns an image; all other debug tools return text (JSON).",
|
|
349
|
-
inputSchema: {
|
|
350
|
-
type: "object",
|
|
351
|
-
properties: {},
|
|
352
|
-
required: []
|
|
353
|
-
},
|
|
354
|
-
availableIn: "both"
|
|
355
|
-
},
|
|
356
|
-
{
|
|
357
|
-
name: "measure_safe_area",
|
|
358
|
-
description: "Runs a safe-area probe on the attached mini-app page via Runtime.evaluate and returns normalized safe-area insets, viewport geometry, device pixel ratio, and User-Agent. Read-only — does not modify page state. Tier C per RFC #277: the same Runtime.evaluate probe runs in both `mock` (devtools panel page with window.__ait state) and `relay` (real-device WebView with window.__sdk). The result includes a `source: \"mock\" | \"relay-dev\" | \"relay-mobile\"` field so consumers can identify provenance without inspecting payload values. (`relay-mobile` = env 2 real-device PWA over an external relay; `relay-dev` = env 3 dog-food WebView; relay-live/env 4 removed #665.) Use in a relay session (phone attached) to get ground-truth values for upgrading a viewport preset from extrapolated/placeholder to measured. Requires a page to be attached — call list_pages first.",
|
|
359
|
-
inputSchema: {
|
|
360
|
-
type: "object",
|
|
361
|
-
properties: {},
|
|
362
|
-
required: []
|
|
363
|
-
},
|
|
364
|
-
availableIn: "both"
|
|
365
|
-
},
|
|
366
|
-
{
|
|
367
|
-
name: "evaluate",
|
|
368
|
-
description: "Evaluates an arbitrary JavaScript expression on the attached mini-app page via CDP Runtime.evaluate (returnByValue: true) and returns the result. NOT read-only — the expression can have side effects (DOM mutations, SDK calls, state changes). Requires the relay to be attached — call list_pages first. Throws if the evaluation throws an exception on the page.\n\nSECURITY: expression and result are not redacted — never include secrets or auth tokens in the expression.\n\nPositive-allowlist kill-switch (#665): this tool is blocked when the attached page is on a non-debug host (apps.tossmini.com / env 4). Only localhost, *.trycloudflare.com, and *.private-apps.tossmini.com are allowed. relay-live (env 4) and the LIVE confirm guard are removed.",
|
|
369
|
-
inputSchema: {
|
|
370
|
-
type: "object",
|
|
371
|
-
properties: { expression: {
|
|
372
|
-
type: "string",
|
|
373
|
-
description: "JavaScript expression to evaluate in the page context."
|
|
374
|
-
} },
|
|
375
|
-
required: ["expression"]
|
|
376
|
-
},
|
|
377
|
-
availableIn: "both"
|
|
378
|
-
},
|
|
379
|
-
{
|
|
380
|
-
name: "list_exceptions",
|
|
381
|
-
description: "Lists JS-level exceptions captured via `Runtime.exceptionThrown` from the relay attached page. Includes timestamp, exception text, source URL/line, and stack trace. Use to root-cause SDK throws that may precede a Toss app crash (#265 / #267). The buffer holds up to 50 most recent exceptions and survives target replaced/crashed/destroyed events so an exception just before a crash is preserved. Returns up to 50 most recent by default.",
|
|
382
|
-
inputSchema: {
|
|
383
|
-
type: "object",
|
|
384
|
-
properties: { limit: {
|
|
385
|
-
type: "number",
|
|
386
|
-
description: "Maximum number of exceptions to return (default 50, max 50)."
|
|
387
|
-
} },
|
|
388
|
-
required: []
|
|
389
|
-
},
|
|
390
|
-
availableIn: "both"
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
name: "call_sdk",
|
|
394
|
-
description: "Calls a dog-food SDK method via the window.__sdkCall bridge (exported by @apps-in-toss/web-framework only in __DEBUG_BUILD__ bundles). NOT read-only — SDK calls have side effects (navigation, payments, permissions, etc.). On env 3/4 (real device relay) this hits the real SDK; on env 1 (local mock) and env 2 (PWA relay — real WebKit, mock SDK) it hits the mock SDK. Requires the relay to be attached — call list_pages first. Returns {ok: true, value} on success or {ok: false, error} on failure. If a Runtime.exceptionThrown event was observed within [callStart-50ms, callEnd+200ms], the result also includes `recentException` for crash triage. Returns a clear error if window.__sdkCall is not available — on relay (env 3/4) that means a non-dog-food bundle (redeploy via `ait build && aitcc app deploy`); on local (--target=local, env 1) it means the dev bridge is not installed (start the dev server with `pnpm dev`).\n\nSECURITY: method name, args, and result value are not redacted — never include secrets.\n\nPositive-allowlist kill-switch (#665): blocked when the attached page is on a non-debug host (apps.tossmini.com / env 4). relay-live and the LIVE guard removed.\n\nIMPORTANT — 인자 시그니처 (잘못된 인자로 호출하면 토스 앱 crash 위험):\n setDeviceOrientation: call_sdk(\"setDeviceOrientation\", [{ type: \"landscape\" }]) // NOT \"landscape\"\n setIosSwipeGestureEnabled: call_sdk(\"setIosSwipeGestureEnabled\", [{ isEnabled: false }])\n setSecureScreen: call_sdk(\"setSecureScreen\", [{ enabled: true }])\n setScreenAwakeMode: call_sdk(\"setScreenAwakeMode\", [{ enabled: true }])\n getOperationalEnvironment: call_sdk(\"getOperationalEnvironment\", [])\n getPlatformOS: call_sdk(\"getPlatformOS\", [])\n getDeviceId: call_sdk(\"getDeviceId\", [])\n getLocale: call_sdk(\"getLocale\", [])\n getNetworkStatus: call_sdk(\"getNetworkStatus\", [])\n getSchemeUri: call_sdk(\"getSchemeUri\", [])\n requestReview: call_sdk(\"requestReview\", [])\n closeView: call_sdk(\"closeView\", [])",
|
|
395
|
-
inputSchema: {
|
|
396
|
-
type: "object",
|
|
397
|
-
properties: {
|
|
398
|
-
name: {
|
|
399
|
-
type: "string",
|
|
400
|
-
description: "SDK method name to call (e.g. \"getOperationalEnvironment\")."
|
|
401
|
-
},
|
|
402
|
-
args: {
|
|
403
|
-
type: "array",
|
|
404
|
-
description: "Arguments to pass to the SDK method (optional, default []).",
|
|
405
|
-
items: {}
|
|
406
|
-
}
|
|
407
|
-
},
|
|
408
|
-
required: ["name"]
|
|
409
|
-
},
|
|
410
|
-
availableIn: "both"
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
name: "AIT.getSdkCallHistory",
|
|
414
|
-
description: "Returns the recent Apps in Toss SDK call trace (method, args, result/error, timestamp) that raw CDP cannot observe. Read-only. Use to confirm an SDK call fired and how it resolved (e.g. a saveBase64Data permission regression).",
|
|
415
|
-
inputSchema: {
|
|
416
|
-
type: "object",
|
|
417
|
-
properties: {},
|
|
418
|
-
required: []
|
|
419
|
-
},
|
|
420
|
-
availableIn: "both"
|
|
421
|
-
},
|
|
422
|
-
{
|
|
423
|
-
name: "AIT.getMockState",
|
|
424
|
-
description: "Returns the devtools mock state snapshot (window.__ait) — environment, permissions, location, auth, network, IAP, and more. Read-only. In dev mode this is the live browser mock state; in debug mode the in-app side reports it over the AIT domain.",
|
|
425
|
-
inputSchema: {
|
|
426
|
-
type: "object",
|
|
427
|
-
properties: {},
|
|
428
|
-
required: []
|
|
429
|
-
},
|
|
430
|
-
availableIn: "both"
|
|
431
|
-
},
|
|
432
|
-
{
|
|
433
|
-
name: "AIT.getOperationalEnvironment",
|
|
434
|
-
description: "Returns getOperationalEnvironment() plus the resolved SDK version — metadata raw CDP cannot observe. Read-only.",
|
|
435
|
-
inputSchema: {
|
|
436
|
-
type: "object",
|
|
437
|
-
properties: {},
|
|
438
|
-
required: []
|
|
439
|
-
},
|
|
440
|
-
availableIn: "both"
|
|
441
|
-
},
|
|
442
|
-
{
|
|
443
|
-
name: "start_debug",
|
|
444
|
-
description: "Switches the active debug environment in-place (issue #348) — no Claude Code restart and no MCP re-handshake. One daemon holds both a local (env 1, mock SDK in a Chromium) and a relay (env 2/3, real-device over the Chii relay + cloudflared tunnel) connection at once; this tool flips which one every other tool reads from, lazily booting the requested family's infra on first use and keeping the inactive one warm so an existing attach survives the switch. After switching it emits notifications/tools/list_changed — call tools/list again to see the updated tool surface for the new environment.\n\nPositive-allowlist kill-switch (#665): relay sessions on apps.tossmini.com (env 4, released production) are silently blocked at both the in-app gate and this MCP layer — relay-live and the LIVE guard have been removed. Only localhost/loopback (env 1), *.trycloudflare.com (env 2), and *.private-apps.tossmini.com (env 3) are allowed.\n\nmodes:\n local-browser — env 1: desktop Chromium with the mock SDK and a local CDP attach. Side-effect tools (call_sdk/evaluate) run unguarded against the mock; nothing touches a real device or real users. No prerequisites — the default, always-available environment for state/contract and visual-layout work.\n relay-sandbox — env 2: a real-device PWA (real WebKit engine, mock SDK) over an external Chii relay. CDP covers real-device WebKit DOM, console, exceptions, and safe-area observation; call_sdk still hits the mock (SDK fidelity needs relay-staging). Side-effect tools run unguarded against the mock. Only the dual-connection daemon can enter relay-sandbox in-place; a single-connection session rejects it with \"동적 전환할 수 없습니다 … relay-sandbox 모드로 재시작하세요\" — follow that hint and restart the MCP server in relay-sandbox mode rather than retrying. Prerequisites: both AIT_RELAY_BASE_URL (the relay base the unplugin emits when started with tunnel:{cdp:true}, used for the CDP attach) and AIT_TUNNEL_BASE_URL (the dev-server tunnel host, required by start_attach to render the launcher QR) must be set before the MCP server starts — the unplugin does not auto-forward either; set them explicitly. Both carry relay/tunnel hosts (secret-class) — keep them out of logs.\n relay-staging — env 3: a real-device Toss WebView dog-food build with the REAL SDK over the intoss-private relay. The first environment where call_sdk exercises the genuine native bridge. Side-effect tools run unguarded (dog-food, not released to real users). Prerequisite: a dog-food candidate bundle built with `RELEASE_CHANNEL=dogfood ait build`, then uploaded with `ait deploy` (add `--scheme-only` to print the resulting intoss-private://…?_deploymentId=… deep-link); open that deep-link/QR on the device to cold-load the bundle with the relay injected. Unlike env 2, env 3 is NOT a dev-server tunnel — it is a deployed bundle reached via the intoss-private scheme, so `pnpm dev` plays no part here.\n\nFor a relay mode (relay-sandbox/relay-staging), also pass projectRoot — the absolute mini-app project root — so the daemon can read the relay auth secret from <projectRoot>/.ait_relay (read-only; the daemon never mints it). Omit it for local-browser.",
|
|
445
|
-
inputSchema: {
|
|
446
|
-
type: "object",
|
|
447
|
-
properties: {
|
|
448
|
-
mode: {
|
|
449
|
-
type: "string",
|
|
450
|
-
enum: [
|
|
451
|
-
"local-browser",
|
|
452
|
-
"relay-sandbox",
|
|
453
|
-
"relay-staging"
|
|
454
|
-
],
|
|
455
|
-
description: "Target environment to switch to. relay-live (env 4) has been removed (#665) — use relay-staging (env 3) for dog-food debugging."
|
|
456
|
-
},
|
|
457
|
-
projectRoot: {
|
|
458
|
-
type: "string",
|
|
459
|
-
description: "Absolute path to the mini-app project root (the directory containing its package.json and .ait_relay). The daemon reads the relay auth secret from <projectRoot>/.ait_relay (read-only) when switching to a relay environment (relay-staging/relay-sandbox). Pass this because the daemon's own cwd is fixed at launch and may not be the project being debugged. Omit for mode=local-browser (no secret needed)."
|
|
460
|
-
}
|
|
461
|
-
},
|
|
462
|
-
required: ["mode"]
|
|
463
|
-
},
|
|
464
|
-
availableIn: "both"
|
|
465
|
-
},
|
|
466
|
-
{
|
|
467
|
-
name: "get_debug_status",
|
|
468
|
-
description: "Reports the current debug session state — which environment/mode is active, whether a page is attached, and a full diagnostic snapshot — in one call. Use this any time to answer \"what mode am I in right now?\" or \"why is this not working?\" without chaining tools. Fields: mcpVersion (MCP SDK version), devtoolsVersion (@ait-co/devtools package version), tunnel (up/wssUrl/pid/startedAt), pages (list_pages result + lastSeenAt stats), lastAttachAt, lastDetachAt, recentErrors (last N server-side errors, PII/secret redacted), authRejects ({count, lastAt} — relay TOTP 401 rejections, secret-free; count > 0 with empty pages means the phone reached the relay but its code was rejected), environment (kind: mock|relay-dev|relay-mobile, env: mock|relay backward-compat, reason, liveGuardActive: always false — relay-live and LIVE guard removed (#665); start_debug mode→kind mapping: relay-sandbox→relay-mobile, relay-staging→relay-dev, local-browser→mock), serverLockHolder (pid + startedAt from the lock file, or null), nextRecommendedAction ({tool, reason} or null — the single next tool to call; in local-target mode tunnel.up=false is normal so \"restart\" is never recommended). All fields are nullable — missing data is null, not an error. debug-mode only — dev-mode (--mode=dev) does not support relay diagnostics. Tier C (both mock and relay).",
|
|
469
|
-
inputSchema: {
|
|
470
|
-
type: "object",
|
|
471
|
-
properties: { recent_errors_limit: {
|
|
472
|
-
type: "number",
|
|
473
|
-
description: "Maximum number of recent server-side errors to include (default 10, max 50)."
|
|
474
|
-
} },
|
|
475
|
-
required: []
|
|
476
|
-
},
|
|
477
|
-
availableIn: "both"
|
|
478
|
-
},
|
|
479
|
-
{
|
|
480
|
-
name: "run_tests",
|
|
481
|
-
description: "Runs mini-app test files on the attached page over CDP (Runtime.evaluate). Each matched file is bundled with esbuild (SDK imports redirected to the live mock/SDK), injected into the attached WebView, and executed; returns per-file results plus flattened totals (passed/failed/skipped/total). When there is no attached page and the current environment is relay (env 3), this tool automatically shows the QR dashboard and waits for a phone to connect before running (scheme_url required for env 3 relay-dev). Files run SEQUENTIALLY (single-attach model: the relay/local target serves one page), and one run_tests call runs at a time (a concurrent call is rejected). Test verification (assert/snapshot) is delegated to the in-page Vitest runtime; this tool is the transport + report. The per-file results array is the progress record — on partial failure you see exactly which files passed/failed/timed-out. Positive-allowlist kill-switch (#665): blocked when the attached page is on a non-debug host. debug-mode only — dev-mode (--mode=dev) has no CDP. Tier C (both mock/local and relay).",
|
|
482
|
-
inputSchema: {
|
|
483
|
-
type: "object",
|
|
484
|
-
properties: {
|
|
485
|
-
files: {
|
|
486
|
-
type: "array",
|
|
487
|
-
items: { type: "string" },
|
|
488
|
-
description: "Glob patterns or file paths to run (e.g. [\"src/**/*.ait.test.ts\"]). Resolved relative to projectRoot when given, else the daemon cwd. Required, non-empty."
|
|
489
|
-
},
|
|
490
|
-
projectRoot: {
|
|
491
|
-
type: "string",
|
|
492
|
-
description: "Absolute path to the mini-app project root used as the glob base. Pass this because the daemon's cwd is fixed at launch. Optional."
|
|
493
|
-
},
|
|
494
|
-
timeout_ms: {
|
|
495
|
-
type: "number",
|
|
496
|
-
description: "Per-file evaluate timeout in ms (default 30000, range 1000–600000). Out-of-range/invalid values fall back to the default."
|
|
497
|
-
},
|
|
498
|
-
scheme_url: {
|
|
499
|
-
type: "string",
|
|
500
|
-
description: "intoss-private:// deep-link URL from `ait deploy --scheme-only` (env 3 relay-dev only). Required when there is no attached page and the environment is relay-dev — the tool uses it to build the QR attach URL and wait for the phone to connect. Ignored when a page is already attached."
|
|
501
|
-
},
|
|
502
|
-
cell: {
|
|
503
|
-
type: "object",
|
|
504
|
-
description: "Optional cell object to inject into globalThis BEFORE running tests (e.g. { \"__AIT_CELL__\": { \"sdkLine\": \"2.x\", \"platform\": \"ios\" } }). Applied only on the auto-attach path (no-page → attach → inject → run). When a page is already attached the caller is responsible for any prior injection. Ignored when empty or absent. Values must be JSON-serialisable.",
|
|
505
|
-
additionalProperties: true
|
|
506
|
-
}
|
|
507
|
-
},
|
|
508
|
-
required: ["files"]
|
|
509
|
-
},
|
|
510
|
-
availableIn: "both"
|
|
511
|
-
}
|
|
512
|
-
].map((t) => t.name));
|
|
513
|
-
`
|
|
514
|
-
(function() {
|
|
515
|
-
var el = document.createElement('div');
|
|
516
|
-
el.style.cssText = 'position:fixed;top:0;left:0;width:0;height:0;visibility:hidden;' +
|
|
517
|
-
'padding-top:env(safe-area-inset-top,0px);' +
|
|
518
|
-
'padding-right:env(safe-area-inset-right,0px);' +
|
|
519
|
-
'padding-bottom:env(safe-area-inset-bottom,0px);' +
|
|
520
|
-
'padding-left:env(safe-area-inset-left,0px)';
|
|
521
|
-
document.documentElement.appendChild(el);
|
|
522
|
-
var cs = window.getComputedStyle(el);
|
|
523
|
-
var cssEnv = {
|
|
524
|
-
top: parseFloat(cs.paddingTop) || 0,
|
|
525
|
-
right: parseFloat(cs.paddingRight) || 0,
|
|
526
|
-
bottom: parseFloat(cs.paddingBottom) || 0,
|
|
527
|
-
left: parseFloat(cs.paddingLeft) || 0
|
|
528
|
-
};
|
|
529
|
-
document.documentElement.removeChild(el);
|
|
530
|
-
var sdkInsets = null;
|
|
531
|
-
var sdkInsetsSource = null;
|
|
532
|
-
var sdkInsetsError = undefined;
|
|
533
|
-
try {
|
|
534
|
-
var sdk = window.__sdk;
|
|
535
|
-
var ait = window.__ait;
|
|
536
|
-
if (sdk && sdk.SafeAreaInsets && typeof sdk.SafeAreaInsets.get === 'function') {
|
|
537
|
-
sdkInsets = sdk.SafeAreaInsets.get();
|
|
538
|
-
sdkInsetsSource = 'window.__sdk';
|
|
539
|
-
} else if (sdk && typeof sdk.getSafeAreaInsets === 'function') {
|
|
540
|
-
sdkInsets = sdk.getSafeAreaInsets();
|
|
541
|
-
sdkInsetsSource = 'window.__sdk';
|
|
542
|
-
} else if (ait && ait.state && ait.state.safeAreaInsets &&
|
|
543
|
-
typeof ait.state.safeAreaInsets.top === 'number') {
|
|
544
|
-
var s = ait.state.safeAreaInsets;
|
|
545
|
-
sdkInsets = { top: s.top, bottom: s.bottom, left: s.left, right: s.right };
|
|
546
|
-
sdkInsetsSource = 'window.__ait';
|
|
547
|
-
} else if (!sdk && !ait) {
|
|
548
|
-
sdkInsetsError = 'neither window.__sdk (relay) nor window.__ait (mock) available';
|
|
549
|
-
} else if (sdk) {
|
|
550
|
-
sdkInsetsError = 'neither SafeAreaInsets.get nor getSafeAreaInsets found on window.__sdk';
|
|
551
|
-
} else {
|
|
552
|
-
sdkInsetsError = 'window.__ait.state.safeAreaInsets is missing or malformed';
|
|
553
|
-
}
|
|
554
|
-
} catch(e) {
|
|
555
|
-
sdkInsetsError = String(e && e.message || e);
|
|
556
|
-
}
|
|
557
|
-
var navBarHeight = null;
|
|
558
|
-
var navBarHeightSource = 'not-exposed-by-sdk';
|
|
559
|
-
try {
|
|
560
|
-
var nb = document.querySelector('.ait-navbar');
|
|
561
|
-
if (nb) {
|
|
562
|
-
navBarHeight = nb.getBoundingClientRect().height;
|
|
563
|
-
navBarHeightSource = 'dom-.ait-navbar';
|
|
564
|
-
}
|
|
565
|
-
} catch(_) {}
|
|
566
|
-
var result = {
|
|
567
|
-
cssEnv: cssEnv,
|
|
568
|
-
sdkInsets: sdkInsets,
|
|
569
|
-
sdkInsetsSource: sdkInsetsSource,
|
|
570
|
-
navBarHeight: navBarHeight,
|
|
571
|
-
navBarHeightSource: navBarHeightSource,
|
|
572
|
-
innerWidth: window.innerWidth,
|
|
573
|
-
innerHeight: window.innerHeight,
|
|
574
|
-
devicePixelRatio: window.devicePixelRatio,
|
|
575
|
-
userAgent: navigator.userAgent
|
|
576
|
-
};
|
|
577
|
-
if (sdkInsetsError !== undefined) result.sdkInsetsError = sdkInsetsError;
|
|
578
|
-
return JSON.stringify(result);
|
|
579
|
-
})()
|
|
580
|
-
`.trim();
|
|
581
|
-
/** Set of tool names served by the AIT source rather than the CDP connection. */
|
|
582
|
-
const AIT_TOOL_NAMES = new Set([
|
|
583
|
-
"AIT.getSdkCallHistory",
|
|
584
|
-
"AIT.getMockState",
|
|
585
|
-
"AIT.getOperationalEnvironment"
|
|
586
|
-
]);
|
|
587
|
-
/** True for the Phase 3 AIT.* tools (served by an `AitSource`, not CDP). */
|
|
588
|
-
function isAitToolName(name) {
|
|
589
|
-
return AIT_TOOL_NAMES.has(name);
|
|
590
|
-
}
|
|
591
|
-
/** Returns the recent SDK call trace (`AIT.getSdkCallHistory`). */
|
|
592
|
-
function getSdkCallHistory(source) {
|
|
593
|
-
return source.get("AIT.getSdkCallHistory");
|
|
594
|
-
}
|
|
595
|
-
/** Returns the devtools mock-state snapshot (`AIT.getMockState`). */
|
|
596
|
-
function getMockState(source) {
|
|
597
|
-
return source.get("AIT.getMockState");
|
|
598
|
-
}
|
|
599
|
-
/** Returns the operational environment + SDK version (`AIT.getOperationalEnvironment`). */
|
|
600
|
-
function getOperationalEnvironment(source) {
|
|
601
|
-
return source.get("AIT.getOperationalEnvironment");
|
|
30
|
+
function movedMessage(oldSubpath, newPackage, install) {
|
|
31
|
+
return [
|
|
32
|
+
`[@ait-co/devtools] '${oldSubpath}' 는 0.2.0에서 제거되었습니다.`,
|
|
33
|
+
`이 기능은 '${newPackage}' 로 이동했습니다.`,
|
|
34
|
+
`설치: ${install}`
|
|
35
|
+
].join(" ");
|
|
602
36
|
}
|
|
603
37
|
//#endregion
|
|
604
|
-
//#region src/mcp
|
|
38
|
+
//#region src/stubs/mcp-server.ts
|
|
605
39
|
/**
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
* Exposes the live browser mock state from a running Vite dev server to AI
|
|
609
|
-
* coding agents via the Model Context Protocol (MCP).
|
|
610
|
-
*
|
|
611
|
-
* Architecture:
|
|
612
|
-
* Browser (aitState) → Vite dev server endpoint (/api/ait-devtools/state)
|
|
613
|
-
* ← HTTP GET ← this stdio MCP server ← AI agent
|
|
614
|
-
*
|
|
615
|
-
* The Vite endpoint is registered by the unplugin when `mcp: true` is set in
|
|
616
|
-
* the plugin options (see `src/unplugin/index.ts`).
|
|
617
|
-
*
|
|
618
|
-
* Phase 3 tool-surface alignment: dev mode and debug mode now expose the same
|
|
619
|
-
* `AIT.*` tools (`AIT.getMockState`, `AIT.getOperationalEnvironment`,
|
|
620
|
-
* `AIT.getSdkCallHistory`). In dev mode they are backed by the HTTP mock-state
|
|
621
|
-
* endpoint (see `HttpAitSource`); in debug mode by the Chii channel. So an AI
|
|
622
|
-
* sees a coherent tool whether attached to a phone (debug) or a dev browser
|
|
623
|
-
* (dev). `devtools_get_mock_state` (the original devtools#130 name) is kept as a
|
|
624
|
-
* backward-compatible alias of `AIT.getMockState`.
|
|
625
|
-
*
|
|
626
|
-
* Issue #305 (M2-1) — dev/debug tool-surface unification:
|
|
627
|
-
* dev-mode now also exposes `list_pages`, `get_debug_status`, `measure_safe_area`,
|
|
628
|
-
* and `call_sdk` so the docs/qa/scenarios.md acceptance sequence
|
|
629
|
-
* `list_pages → measure_safe_area → call_sdk` works in dev mode without
|
|
630
|
-
* "Unknown tool" failures.
|
|
40
|
+
* TRANSITION STUB — REMOVE IN 1.0.0.
|
|
631
41
|
*
|
|
632
|
-
* -
|
|
633
|
-
* - `get_debug_status` — dumps dev-mode server state (endpoint URL, last fetch
|
|
634
|
-
* error, reachability, mode/environment metadata).
|
|
635
|
-
* - `measure_safe_area`— reads safeAreaInsets from the mock state snapshot
|
|
636
|
-
* (source: 'mock-vite').
|
|
637
|
-
* - `call_sdk` — reads mock state and builds a mock-equivalent result
|
|
638
|
-
* using window.__ait.state for supported methods; returns
|
|
639
|
-
* an explicit tier-filter error for methods that require
|
|
640
|
-
* a live CDP bridge.
|
|
641
|
-
* - CDP-only tools (`evaluate`, `take_screenshot`, `get_dom_document`,
|
|
642
|
-
* `take_snapshot`, `list_console_messages`,
|
|
643
|
-
* `list_network_requests`, `list_exceptions`) — return an
|
|
644
|
-
* explicit tier-filter error explaining that CDP is unavailable
|
|
645
|
-
* in dev-mode and pointing to `--mode=local` or `--mode=debug`.
|
|
42
|
+
* `@ait-co/devtools/mcp/server` moved to `@ait-co/debugger/mcp/server` (#818).
|
|
646
43
|
*
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
* {
|
|
652
|
-
* "mcpServers": {
|
|
653
|
-
* "ait-devtools": {
|
|
654
|
-
* "command": "pnpm",
|
|
655
|
-
* "args": ["exec", "devtools-mcp", "--mode=dev"],
|
|
656
|
-
* "env": { "AIT_DEVTOOLS_URL": "http://localhost:5173" }
|
|
657
|
-
* }
|
|
658
|
-
* }
|
|
659
|
-
* }
|
|
660
|
-
*/
|
|
661
|
-
/** Error message prefix for CDP-dependent tools called in dev-mode. */
|
|
662
|
-
const CDP_UNAVAILABLE_IN_DEV_MODE = "dev-mode에서는 CDP 연결이 없어 이 도구를 사용할 수 없습니다. 실기기 또는 로컬 Chromium에 붙이려면 `devtools-mcp --mode=local` 또는 `devtools-mcp` (debug 모드 기본)로 전환하세요.";
|
|
663
|
-
/**
|
|
664
|
-
* Tool descriptors served by the dev-mode server.
|
|
665
|
-
*
|
|
666
|
-
* All dev-mode tools are Tier C (both envs) per RFC #277 — the dev-mode server
|
|
667
|
-
* itself is the mock-side embodiment of those Tier C tools. `availableIn` is
|
|
668
|
-
* declared so the surface stays consistent with the debug-mode registry.
|
|
669
|
-
*
|
|
670
|
-
* Issue #305: CDP-only tools are also listed with explicit descriptions so
|
|
671
|
-
* agents do not get "Unknown tool" failures — they get a clear tier-filter
|
|
672
|
-
* error message instead.
|
|
673
|
-
*/
|
|
674
|
-
const DEV_TOOL_DEFINITIONS = [
|
|
675
|
-
{
|
|
676
|
-
name: "AIT.getMockState",
|
|
677
|
-
description: "Returns the devtools mock state snapshot (window.__ait) from the running browser session — environment, permissions, location, auth, network, IAP, and more. Read-only. Requires the Vite dev server running with the @ait-co/devtools unplugin option `mcp: true`. Same tool as in debug mode, where the in-app side reports it over the AIT domain.",
|
|
678
|
-
inputSchema: {
|
|
679
|
-
type: "object",
|
|
680
|
-
properties: {},
|
|
681
|
-
required: []
|
|
682
|
-
},
|
|
683
|
-
availableIn: "both"
|
|
684
|
-
},
|
|
685
|
-
{
|
|
686
|
-
name: "AIT.getOperationalEnvironment",
|
|
687
|
-
description: "Returns the operational environment + SDK/app version derived from the dev mock state. Read-only.",
|
|
688
|
-
inputSchema: {
|
|
689
|
-
type: "object",
|
|
690
|
-
properties: {},
|
|
691
|
-
required: []
|
|
692
|
-
},
|
|
693
|
-
availableIn: "both"
|
|
694
|
-
},
|
|
695
|
-
{
|
|
696
|
-
name: "AIT.getSdkCallHistory",
|
|
697
|
-
description: "Returns the SDK call trace. In dev mode the HTTP mock-state endpoint records no trace, so this returns an empty list; in debug mode it is populated over the AIT domain. Read-only.",
|
|
698
|
-
inputSchema: {
|
|
699
|
-
type: "object",
|
|
700
|
-
properties: {},
|
|
701
|
-
required: []
|
|
702
|
-
},
|
|
703
|
-
availableIn: "both"
|
|
704
|
-
},
|
|
705
|
-
{
|
|
706
|
-
name: "devtools_get_mock_state",
|
|
707
|
-
description: "Backward-compatible alias of AIT.getMockState (the original devtools#130 name). Returns the current AIT DevTools mock state snapshot. Read-only. Prefer AIT.getMockState in new configs.",
|
|
708
|
-
inputSchema: {
|
|
709
|
-
type: "object",
|
|
710
|
-
properties: {},
|
|
711
|
-
required: []
|
|
712
|
-
},
|
|
713
|
-
availableIn: "both"
|
|
714
|
-
},
|
|
715
|
-
{
|
|
716
|
-
name: "list_pages",
|
|
717
|
-
description: "dev-mode: returns the Vite dev server URL as a single-entry page list. No CDP relay is involved — `tunnel.up` is always false and `devMode: true` marks this as a shim result. Call this first to confirm the dev server is reachable. In debug mode (`devtools-mcp` / `--mode=local`) this returns real attached pages.",
|
|
718
|
-
inputSchema: {
|
|
719
|
-
type: "object",
|
|
720
|
-
properties: {},
|
|
721
|
-
required: []
|
|
722
|
-
},
|
|
723
|
-
availableIn: "both"
|
|
724
|
-
},
|
|
725
|
-
{
|
|
726
|
-
name: "get_debug_status",
|
|
727
|
-
description: "dev-mode: reports the current dev session state — Vite endpoint URL, last fetch timestamp/error, mock state endpoint reachability, mode (\"dev\"), and environment metadata — in one call. Use this any time to confirm what the dev server is doing or when its connection is suspect. In debug mode this returns tunnel/relay/attach status instead.",
|
|
728
|
-
inputSchema: {
|
|
729
|
-
type: "object",
|
|
730
|
-
properties: { recent_errors_limit: {
|
|
731
|
-
type: "number",
|
|
732
|
-
description: "Ignored in dev-mode (no error ring buffer). Present for schema parity."
|
|
733
|
-
} },
|
|
734
|
-
required: []
|
|
735
|
-
},
|
|
736
|
-
availableIn: "both"
|
|
737
|
-
},
|
|
738
|
-
{
|
|
739
|
-
name: "measure_safe_area",
|
|
740
|
-
description: "dev-mode: reads safe-area insets from the mock state snapshot via the Vite endpoint. Returns `{ source: \"mock-vite\", sdkInsets, sdkInsetsSource: \"window.__ait\", ... }`. Values reflect what the DevTools panel reports at the time of the last state push. In debug mode this runs a Runtime.evaluate CDP probe on the attached page.",
|
|
741
|
-
inputSchema: {
|
|
742
|
-
type: "object",
|
|
743
|
-
properties: {},
|
|
744
|
-
required: []
|
|
745
|
-
},
|
|
746
|
-
availableIn: "both"
|
|
747
|
-
},
|
|
748
|
-
{
|
|
749
|
-
name: "call_sdk",
|
|
750
|
-
description: "dev-mode: calls a mock SDK method via the Vite mock state endpoint. Supported methods read from window.__ait mock state (e.g. getOperationalEnvironment). Returns the same `{ok, value}` / `{ok, error}` envelope as debug mode. In debug mode this calls the real SDK via window.__sdkCall over CDP.",
|
|
751
|
-
inputSchema: {
|
|
752
|
-
type: "object",
|
|
753
|
-
properties: {
|
|
754
|
-
name: {
|
|
755
|
-
type: "string",
|
|
756
|
-
description: "Mock SDK method name to call (e.g. \"getOperationalEnvironment\")."
|
|
757
|
-
},
|
|
758
|
-
args: {
|
|
759
|
-
type: "array",
|
|
760
|
-
description: "Arguments (ignored in dev-mode mock path; present for schema parity).",
|
|
761
|
-
items: {}
|
|
762
|
-
}
|
|
763
|
-
},
|
|
764
|
-
required: ["name"]
|
|
765
|
-
},
|
|
766
|
-
availableIn: "both"
|
|
767
|
-
},
|
|
768
|
-
{
|
|
769
|
-
name: "start_attach",
|
|
770
|
-
description: "Switches into a relay mode (if given), builds a self-attaching deep-link QR for a real device, and waits for the phone to attach — all in one call. NOT available in dev-mode — requires a live cloudflared relay (Tier B, relay-only). To use this tool: restart the MCP server with `--mode=debug` (or omit --mode) and set MCP_ENV=relay, then call start_attach to generate the QR for phone scanning. See: https://docs.aitc.dev/guides/debug-relay",
|
|
771
|
-
inputSchema: {
|
|
772
|
-
type: "object",
|
|
773
|
-
properties: {
|
|
774
|
-
mode: {
|
|
775
|
-
type: "string",
|
|
776
|
-
enum: [
|
|
777
|
-
"local-browser",
|
|
778
|
-
"relay-sandbox",
|
|
779
|
-
"relay-staging"
|
|
780
|
-
],
|
|
781
|
-
description: "Optional relay mode to switch into before attaching."
|
|
782
|
-
},
|
|
783
|
-
scheme_url: {
|
|
784
|
-
type: "string",
|
|
785
|
-
description: "The intoss-private:// URL from `ait deploy --scheme-only` (env 3/relay-staging)."
|
|
786
|
-
},
|
|
787
|
-
wait_timeout_seconds: {
|
|
788
|
-
type: "number",
|
|
789
|
-
description: "Maximum seconds to wait for a page to attach (default 60, range 1–600). Invalid inputs fall back to default."
|
|
790
|
-
}
|
|
791
|
-
},
|
|
792
|
-
required: []
|
|
793
|
-
},
|
|
794
|
-
availableIn: "relay"
|
|
795
|
-
},
|
|
796
|
-
{
|
|
797
|
-
name: "evaluate",
|
|
798
|
-
description: "Evaluates an arbitrary JavaScript expression via CDP Runtime.evaluate. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug` for CDP access.",
|
|
799
|
-
inputSchema: {
|
|
800
|
-
type: "object",
|
|
801
|
-
properties: { expression: {
|
|
802
|
-
type: "string",
|
|
803
|
-
description: "JavaScript expression to evaluate."
|
|
804
|
-
} },
|
|
805
|
-
required: ["expression"]
|
|
806
|
-
},
|
|
807
|
-
availableIn: "both"
|
|
808
|
-
},
|
|
809
|
-
{
|
|
810
|
-
name: "take_screenshot",
|
|
811
|
-
description: "Captures a PNG screenshot via CDP Page.captureScreenshot. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
812
|
-
inputSchema: {
|
|
813
|
-
type: "object",
|
|
814
|
-
properties: {},
|
|
815
|
-
required: []
|
|
816
|
-
},
|
|
817
|
-
availableIn: "both"
|
|
818
|
-
},
|
|
819
|
-
{
|
|
820
|
-
name: "get_dom_document",
|
|
821
|
-
description: "Returns the DOM tree via CDP DOM.getDocument. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
822
|
-
inputSchema: {
|
|
823
|
-
type: "object",
|
|
824
|
-
properties: {},
|
|
825
|
-
required: []
|
|
826
|
-
},
|
|
827
|
-
availableIn: "both"
|
|
828
|
-
},
|
|
829
|
-
{
|
|
830
|
-
name: "take_snapshot",
|
|
831
|
-
description: "Captures a serialized page snapshot via CDP DOMSnapshot.captureSnapshot. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
832
|
-
inputSchema: {
|
|
833
|
-
type: "object",
|
|
834
|
-
properties: {},
|
|
835
|
-
required: []
|
|
836
|
-
},
|
|
837
|
-
availableIn: "both"
|
|
838
|
-
},
|
|
839
|
-
{
|
|
840
|
-
name: "list_console_messages",
|
|
841
|
-
description: "Lists console messages captured via CDP Runtime.consoleAPICalled. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
842
|
-
inputSchema: {
|
|
843
|
-
type: "object",
|
|
844
|
-
properties: {},
|
|
845
|
-
required: []
|
|
846
|
-
},
|
|
847
|
-
availableIn: "both"
|
|
848
|
-
},
|
|
849
|
-
{
|
|
850
|
-
name: "list_network_requests",
|
|
851
|
-
description: "Lists network requests captured via CDP Network events. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
852
|
-
inputSchema: {
|
|
853
|
-
type: "object",
|
|
854
|
-
properties: {},
|
|
855
|
-
required: []
|
|
856
|
-
},
|
|
857
|
-
availableIn: "both"
|
|
858
|
-
},
|
|
859
|
-
{
|
|
860
|
-
name: "list_exceptions",
|
|
861
|
-
description: "Lists JS exceptions captured via CDP Runtime.exceptionThrown. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
862
|
-
inputSchema: {
|
|
863
|
-
type: "object",
|
|
864
|
-
properties: { limit: {
|
|
865
|
-
type: "number",
|
|
866
|
-
description: "Maximum exceptions to return."
|
|
867
|
-
} },
|
|
868
|
-
required: []
|
|
869
|
-
},
|
|
870
|
-
availableIn: "both"
|
|
871
|
-
},
|
|
872
|
-
{
|
|
873
|
-
name: "run_tests",
|
|
874
|
-
description: "Runs mini-app test files on the attached page over CDP (Runtime.evaluate). NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
875
|
-
inputSchema: {
|
|
876
|
-
type: "object",
|
|
877
|
-
properties: {
|
|
878
|
-
files: {
|
|
879
|
-
type: "array",
|
|
880
|
-
items: { type: "string" },
|
|
881
|
-
description: "Glob patterns or file paths to run."
|
|
882
|
-
},
|
|
883
|
-
projectRoot: {
|
|
884
|
-
type: "string",
|
|
885
|
-
description: "Glob base directory."
|
|
886
|
-
},
|
|
887
|
-
timeout_ms: {
|
|
888
|
-
type: "number",
|
|
889
|
-
description: "Per-file evaluate timeout in ms."
|
|
890
|
-
}
|
|
891
|
-
},
|
|
892
|
-
required: ["files"]
|
|
893
|
-
},
|
|
894
|
-
availableIn: "both"
|
|
895
|
-
}
|
|
896
|
-
];
|
|
897
|
-
/** All tool names served in dev-mode (including tier-filter stubs). */
|
|
898
|
-
const DEV_TOOL_NAMES = new Set(DEV_TOOL_DEFINITIONS.map((t) => t.name));
|
|
899
|
-
/** CDP-only tools — return a tier-filter error in dev-mode. */
|
|
900
|
-
const CDP_ONLY_TOOL_NAMES = new Set([
|
|
901
|
-
"evaluate",
|
|
902
|
-
"take_screenshot",
|
|
903
|
-
"get_dom_document",
|
|
904
|
-
"take_snapshot",
|
|
905
|
-
"list_console_messages",
|
|
906
|
-
"list_network_requests",
|
|
907
|
-
"list_exceptions",
|
|
908
|
-
"run_tests"
|
|
909
|
-
]);
|
|
910
|
-
/**
|
|
911
|
-
* Tier B tools — relay-only per RFC #277.
|
|
912
|
-
* Listed in dev-mode tool surface (issue #323) so agents get a hand-off hint
|
|
913
|
-
* toward `--mode=debug` instead of "Unknown tool".
|
|
44
|
+
* Throws at module evaluation: this entry only ever loads inside a developer's
|
|
45
|
+
* MCP host / terminal, never in a shipped app bundle, so failing immediately
|
|
46
|
+
* and loudly is the helpful behaviour. Contrast with `src/stubs/in-app.ts`,
|
|
47
|
+
* which must not throw.
|
|
914
48
|
*/
|
|
915
|
-
|
|
916
|
-
/**
|
|
917
|
-
* Builds the `list_pages` dev-mode shim response.
|
|
918
|
-
* Returns the Vite dev URL as a single-entry page list with `devMode: true`.
|
|
919
|
-
*/
|
|
920
|
-
function buildDevListPagesResult(devtoolsUrl) {
|
|
921
|
-
return {
|
|
922
|
-
pages: [{
|
|
923
|
-
url: devtoolsUrl,
|
|
924
|
-
title: "dev fixture",
|
|
925
|
-
attached: true
|
|
926
|
-
}],
|
|
927
|
-
tunnel: { up: false },
|
|
928
|
-
devMode: true,
|
|
929
|
-
singleAttachModel: true
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
/**
|
|
933
|
-
* Builds the `get_debug_status` dev-mode response.
|
|
934
|
-
* Probes the mock state endpoint reachability and returns server metadata.
|
|
935
|
-
*/
|
|
936
|
-
async function buildDevDiagnostics(devtoolsUrl, stateEndpoint, fetchImpl) {
|
|
937
|
-
let reachable = false;
|
|
938
|
-
let lastFetchError = null;
|
|
939
|
-
let lastFetchAt = null;
|
|
940
|
-
try {
|
|
941
|
-
const res = await fetchImpl(stateEndpoint);
|
|
942
|
-
reachable = res.ok;
|
|
943
|
-
lastFetchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
944
|
-
if (!res.ok) lastFetchError = `HTTP ${res.status} ${res.statusText}`;
|
|
945
|
-
} catch (err) {
|
|
946
|
-
lastFetchError = err instanceof Error ? err.message : String(err);
|
|
947
|
-
lastFetchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
948
|
-
}
|
|
949
|
-
return {
|
|
950
|
-
mode: "dev",
|
|
951
|
-
devtoolsUrl,
|
|
952
|
-
mcpStateEndpoint: stateEndpoint,
|
|
953
|
-
mockStateEndpointReachable: reachable,
|
|
954
|
-
lastFetchAt,
|
|
955
|
-
lastFetchError,
|
|
956
|
-
environment: {
|
|
957
|
-
kind: "mock",
|
|
958
|
-
reason: "dev-mode — Vite HTTP endpoint, no CDP connection"
|
|
959
|
-
},
|
|
960
|
-
nextRecommendedAction: reachable ? null : "mock state endpoint가 응답하지 않습니다. Vite dev 서버가 `mcp: true` 옵션으로 실행 중인지 확인하고, 필요하면 dev 서버를 재시작하세요."
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
/**
|
|
964
|
-
* Builds the `measure_safe_area` dev-mode response from mock state.
|
|
965
|
-
* Reads `safeAreaInsets` from the AIT mock state and returns a parity-schema
|
|
966
|
-
* result with `source: 'mock-vite'`.
|
|
967
|
-
*/
|
|
968
|
-
async function buildDevMeasureSafeArea(aitSource) {
|
|
969
|
-
const rawInsets = (await aitSource.get("AIT.getMockState")).safeAreaInsets;
|
|
970
|
-
let sdkInsets = null;
|
|
971
|
-
if (rawInsets !== null && typeof rawInsets === "object" && !Array.isArray(rawInsets)) {
|
|
972
|
-
const r = rawInsets;
|
|
973
|
-
sdkInsets = {
|
|
974
|
-
top: typeof r.top === "number" ? r.top : 0,
|
|
975
|
-
right: typeof r.right === "number" ? r.right : 0,
|
|
976
|
-
bottom: typeof r.bottom === "number" ? r.bottom : 0,
|
|
977
|
-
left: typeof r.left === "number" ? r.left : 0
|
|
978
|
-
};
|
|
979
|
-
}
|
|
980
|
-
return {
|
|
981
|
-
source: "mock-vite",
|
|
982
|
-
cssEnv: {
|
|
983
|
-
top: 0,
|
|
984
|
-
right: 0,
|
|
985
|
-
bottom: 0,
|
|
986
|
-
left: 0
|
|
987
|
-
},
|
|
988
|
-
sdkInsets,
|
|
989
|
-
sdkInsetsSource: sdkInsets !== null ? "window.__ait" : null,
|
|
990
|
-
...sdkInsets === null ? { sdkInsetsError: "window.__ait.state.safeAreaInsets not found in mock state snapshot" } : {},
|
|
991
|
-
innerWidth: null,
|
|
992
|
-
innerHeight: null,
|
|
993
|
-
devicePixelRatio: null,
|
|
994
|
-
userAgent: null,
|
|
995
|
-
navBarHeight: null,
|
|
996
|
-
navBarHeightSource: "not-available-in-dev-mode"
|
|
997
|
-
};
|
|
998
|
-
}
|
|
999
|
-
/**
|
|
1000
|
-
* Builds the `call_sdk` dev-mode response.
|
|
1001
|
-
*
|
|
1002
|
-
* Supported methods are served from the mock state snapshot. Unsupported
|
|
1003
|
-
* methods return `{ ok: false, error: 'dev-mode-unsupported: ...' }` so the
|
|
1004
|
-
* agent gets an informative message rather than a generic failure.
|
|
1005
|
-
*/
|
|
1006
|
-
async function buildDevCallSdk(methodName, aitSource) {
|
|
1007
|
-
switch (methodName) {
|
|
1008
|
-
case "getOperationalEnvironment": return {
|
|
1009
|
-
ok: true,
|
|
1010
|
-
value: (await aitSource.get("AIT.getOperationalEnvironment")).environment
|
|
1011
|
-
};
|
|
1012
|
-
default: return {
|
|
1013
|
-
ok: false,
|
|
1014
|
-
error: `dev-mode-unsupported: "${methodName}"은 dev-mode에서 직접 호출할 수 없습니다. CDP bridge(window.__sdkCall)가 없으므로 실제 SDK 호출은 \`--mode=local\` 또는 debug 모드에서만 가능합니다. 지원 메서드: getOperationalEnvironment (mock state에서 읽음).`
|
|
1015
|
-
};
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
/** Builds the dev-mode MCP server (does not connect a transport). */
|
|
1019
|
-
function createDevServer(deps = {}) {
|
|
1020
|
-
const devtoolsUrl = process.env.AIT_DEVTOOLS_URL ?? "http://localhost:5173";
|
|
1021
|
-
const stateEndpoint = `${devtoolsUrl}/api/ait-devtools/state`;
|
|
1022
|
-
const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
|
|
1023
|
-
const server = new Server({
|
|
1024
|
-
name: "ait-devtools",
|
|
1025
|
-
version: "0.1.144"
|
|
1026
|
-
}, { capabilities: { tools: {} } });
|
|
1027
|
-
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
|
|
1028
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1029
|
-
const name = request.params.name;
|
|
1030
|
-
if (!DEV_TOOL_NAMES.has(name)) return mcpError(`알 수 없는 tool: ${name}`);
|
|
1031
|
-
if (CDP_ONLY_TOOL_NAMES.has(name)) return mcpError(`${name}: ${CDP_UNAVAILABLE_IN_DEV_MODE}`);
|
|
1032
|
-
if (TIER_B_TOOL_NAMES.has(name)) return tierRejectionError(name, "relay", "mock", "dev-mode — Vite HTTP endpoint, no CDP/relay connection. `--mode=debug` (または `devtools-mcp` without --mode) + MCP_ENV=relay로 재시작하세요.");
|
|
1033
|
-
try {
|
|
1034
|
-
const effective = name === "devtools_get_mock_state" ? "AIT.getMockState" : name;
|
|
1035
|
-
if (isAitToolName(effective)) switch (effective) {
|
|
1036
|
-
case "AIT.getMockState": return jsonResult(await getMockState(aitSource));
|
|
1037
|
-
case "AIT.getOperationalEnvironment": return jsonResult(await getOperationalEnvironment(aitSource));
|
|
1038
|
-
case "AIT.getSdkCallHistory": return jsonResult(await getSdkCallHistory(aitSource));
|
|
1039
|
-
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
1040
|
-
}
|
|
1041
|
-
switch (name) {
|
|
1042
|
-
case "list_pages": return envelopeResult("list_pages", buildDevListPagesResult(devtoolsUrl));
|
|
1043
|
-
case "get_debug_status": return envelopeResult("get_debug_status", await buildDevDiagnostics(devtoolsUrl, stateEndpoint, (url) => fetch(url)));
|
|
1044
|
-
case "measure_safe_area": return envelopeResult("measure_safe_area", await buildDevMeasureSafeArea(aitSource));
|
|
1045
|
-
case "call_sdk": {
|
|
1046
|
-
const sdkName = request.params.arguments?.name;
|
|
1047
|
-
if (typeof sdkName !== "string" || sdkName === "") return mcpError("call_sdk: name 인자가 비어 있습니다. 호출할 메서드 이름을 전달하세요.");
|
|
1048
|
-
return envelopeResult("call_sdk", await buildDevCallSdk(sdkName, aitSource));
|
|
1049
|
-
}
|
|
1050
|
-
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
1051
|
-
}
|
|
1052
|
-
} catch (err) {
|
|
1053
|
-
return mcpError(`${name} 실패: ${err instanceof Error ? err.message : String(err)}\nVite dev 서버가 @ait-co/devtools unplugin \`mcp: true\` 옵션으로 실행 중인지 확인하세요. AIT_DEVTOOLS_URL 환경변수가 올바르게 설정됐는지도 확인하세요.`);
|
|
1054
|
-
}
|
|
1055
|
-
});
|
|
1056
|
-
return server;
|
|
1057
|
-
}
|
|
1058
|
-
function jsonResult(value) {
|
|
1059
|
-
return { content: [{
|
|
1060
|
-
type: "text",
|
|
1061
|
-
text: JSON.stringify(value, null, 2)
|
|
1062
|
-
}] };
|
|
1063
|
-
}
|
|
1064
|
-
/**
|
|
1065
|
-
* Wraps `value` in a `ToolEnvelope` (when compat mode is off) and returns it
|
|
1066
|
-
* as a text content block. In dev-mode `env` is always `'mock'` and
|
|
1067
|
-
* `attached` is always `true` (the Vite dev server is the single implicit
|
|
1068
|
-
* "attached" page).
|
|
1069
|
-
*
|
|
1070
|
-
* When `AIT_MCP_COMPAT=chrome-devtools` the envelope is skipped and the raw
|
|
1071
|
-
* value is returned — identical to `jsonResult` (0.1.x back-compat).
|
|
1072
|
-
*/
|
|
1073
|
-
function envelopeResult(tool, value) {
|
|
1074
|
-
const wrapped = wrapEnvelope(value, {
|
|
1075
|
-
tool,
|
|
1076
|
-
env: "mock",
|
|
1077
|
-
attached: true
|
|
1078
|
-
});
|
|
1079
|
-
return { content: [{
|
|
1080
|
-
type: "text",
|
|
1081
|
-
text: JSON.stringify(wrapped, null, 2)
|
|
1082
|
-
}] };
|
|
1083
|
-
}
|
|
1084
|
-
/** Builds the dev-mode server and connects it over stdio. */
|
|
1085
|
-
async function runDevServer() {
|
|
1086
|
-
const server = createDevServer();
|
|
1087
|
-
const transport = new StdioServerTransport();
|
|
1088
|
-
await server.connect(transport);
|
|
1089
|
-
}
|
|
49
|
+
throw new Error(movedMessage("@ait-co/devtools/mcp/server", `${DEBUGGER_PACKAGE}/mcp/server`, `pnpm add -D ${DEBUGGER_PACKAGE}`));
|
|
1090
50
|
//#endregion
|
|
1091
|
-
export {
|
|
51
|
+
export {};
|
|
1092
52
|
|
|
1093
53
|
//# sourceMappingURL=server.js.map
|