@ait-co/devtools 0.1.74 → 0.1.76
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 +22 -1
- package/README.md +22 -1
- package/dist/devtools-opener-BbUXBzgA.js.map +1 -1
- package/dist/devtools-opener-Bp671YXu.cjs.map +1 -1
- package/dist/devtools-opener-D84kZFtR.js.map +1 -1
- package/dist/devtools-opener-h6A-UjzC.cjs.map +1 -1
- package/dist/in-app/auto.d.ts +86 -0
- package/dist/in-app/auto.d.ts.map +1 -0
- package/dist/in-app/auto.js +549 -0
- package/dist/in-app/auto.js.map +1 -0
- package/dist/mcp/cli.js +77 -37
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/mock/index.d.ts +50 -2
- package/dist/mock/index.d.ts.map +1 -1
- package/dist/mock/index.js +1210 -1110
- package/dist/mock/index.js.map +1 -1
- package/dist/panel/index.js +822 -820
- package/dist/panel/index.js.map +1 -1
- package/dist/{qr-http-server-Bn2ciFuC.js → qr-http-server-CDO6o2nr.js} +19 -7
- package/dist/qr-http-server-CDO6o2nr.js.map +1 -0
- package/dist/{qr-http-server-DNGVwI0P.cjs → qr-http-server-D0v9ooAD.cjs} +19 -7
- package/dist/qr-http-server-D0v9ooAD.cjs.map +1 -0
- package/dist/{qr-http-server-Cpc4jfTA.js → qr-http-server-DznDIcJF.js} +19 -7
- package/dist/qr-http-server-DznDIcJF.js.map +1 -0
- package/dist/{qr-http-server-BqZ8c0Bp.cjs → qr-http-server-jMC1nVqY.cjs} +19 -7
- package/dist/qr-http-server-jMC1nVqY.cjs.map +1 -0
- package/dist/{tunnel-CAxygywQ.cjs → tunnel-D7f-0enB.cjs} +2 -2
- package/dist/{tunnel-CAxygywQ.cjs.map → tunnel-D7f-0enB.cjs.map} +1 -1
- package/dist/{tunnel-BuymAS3O.js → tunnel-km3KkZrF.js} +2 -2
- package/dist/{tunnel-BuymAS3O.js.map → tunnel-km3KkZrF.js.map} +1 -1
- package/dist/unplugin/index.cjs +1 -1
- package/dist/unplugin/index.js +1 -1
- package/dist/unplugin/tunnel.cjs +1 -1
- package/dist/unplugin/tunnel.js +1 -1
- package/package.json +6 -1
- package/dist/qr-http-server-Bn2ciFuC.js.map +0 -1
- package/dist/qr-http-server-BqZ8c0Bp.cjs.map +0 -1
- package/dist/qr-http-server-Cpc4jfTA.js.map +0 -1
- package/dist/qr-http-server-DNGVwI0P.cjs.map +0 -1
package/dist/mcp/cli.js
CHANGED
|
@@ -1169,9 +1169,8 @@ function buildDeepLinkAttachUrl(schemeUrl, wssUrl, totpCode) {
|
|
|
1169
1169
|
* Chii serves its own DevTools frontend at
|
|
1170
1170
|
* `<relayHttpBaseUrl>/front_end/chii_app.html`. The `ws=` (plain HTTP relay)
|
|
1171
1171
|
* or `wss=` (HTTPS relay) query parameter is a URL-encoded string of the form
|
|
1172
|
-
* `<relay-host>/client/<uuid>?target=<id
|
|
1173
|
-
*
|
|
1174
|
-
* `chii/public/index.js`).
|
|
1172
|
+
* `<relay-host>/client/<uuid>?target=<id>&at=<totp>` — the same format used
|
|
1173
|
+
* by Chii's own target list page (derived from `chii/public/index.js`).
|
|
1175
1174
|
*
|
|
1176
1175
|
* The `at=` TOTP code is minted at call time via `mintTotp()`. It is valid
|
|
1177
1176
|
* for ~3 minutes (relay gate accepts ±RELAY_VERIFY_SKEW_STEPS=6 steps =
|
|
@@ -1179,6 +1178,15 @@ function buildDeepLinkAttachUrl(schemeUrl, wssUrl, totpCode) {
|
|
|
1179
1178
|
* If the window expires before the browser connects, the relay will reject the
|
|
1180
1179
|
* WebSocket upgrade with close code 4401.
|
|
1181
1180
|
*
|
|
1181
|
+
* FAIL-CLOSED (issue #509): `mintTotp` is REQUIRED. When omitted (i.e.
|
|
1182
|
+
* `undefined`), this function returns `null` — the caller must treat `null` as
|
|
1183
|
+
* "inspector not yet available" and show a waiting hint instead of a broken
|
|
1184
|
+
* link. Relay sessions gate every WS upgrade with TOTP (#452), so a URL built
|
|
1185
|
+
* without `at=` would be rejected with WS 4401 immediately — there is no
|
|
1186
|
+
* non-TOTP relay path in production. Returning `null` surfaces this cleanly as
|
|
1187
|
+
* a "TOTP not yet configured" state rather than silently producing a URL that
|
|
1188
|
+
* will always fail at the WS handshake.
|
|
1189
|
+
*
|
|
1182
1190
|
* SECRET-HANDLING: `mintTotp` returns a code, not a secret. The code is
|
|
1183
1191
|
* embedded in the `wss=` parameter (inside the `at=` param) of the returned
|
|
1184
1192
|
* URL. Callers MUST NOT log the returned URL to stdout (stderr is OK — it is
|
|
@@ -1187,11 +1195,14 @@ function buildDeepLinkAttachUrl(schemeUrl, wssUrl, totpCode) {
|
|
|
1187
1195
|
* @param relayHttpBaseUrl - Local HTTP base URL of the Chii relay, e.g.
|
|
1188
1196
|
* `http://127.0.0.1:9100`. No trailing slash.
|
|
1189
1197
|
* @param targetId - Chii target id (from `GET <relay>/targets`).
|
|
1190
|
-
* @param mintTotp -
|
|
1191
|
-
*
|
|
1192
|
-
*
|
|
1198
|
+
* @param mintTotp - Function that returns a fresh 6-digit TOTP code string.
|
|
1199
|
+
* Called at most once. **Required** — when `undefined`, the function returns
|
|
1200
|
+
* `null` (fail-closed: no `at=` param means the relay WS gate rejects the
|
|
1201
|
+
* handshake, so a null result is safer than a URL that always 404s).
|
|
1193
1202
|
* @param panel - Initial panel. Defaults to `"console"`.
|
|
1194
1203
|
*
|
|
1204
|
+
* @returns The inspector URL string, or `null` when `mintTotp` is absent.
|
|
1205
|
+
*
|
|
1195
1206
|
* @example
|
|
1196
1207
|
* buildChiiInspectorUrl(
|
|
1197
1208
|
* 'http://127.0.0.1:9100',
|
|
@@ -1201,6 +1212,7 @@ function buildDeepLinkAttachUrl(schemeUrl, wssUrl, totpCode) {
|
|
|
1201
1212
|
* // → 'http://127.0.0.1:9100/front_end/chii_app.html?ws=127.0.0.1%3A9100%2Fclient%2F<uuid>%3Ftarget%3Dabc123%26at%3D<code>'
|
|
1202
1213
|
*/
|
|
1203
1214
|
function buildChiiInspectorUrl(relayHttpBaseUrl, targetId, mintTotp, panel = "console") {
|
|
1215
|
+
if (!mintTotp) return null;
|
|
1204
1216
|
let relayHost;
|
|
1205
1217
|
let wsParamName;
|
|
1206
1218
|
try {
|
|
@@ -1212,11 +1224,8 @@ function buildChiiInspectorUrl(relayHttpBaseUrl, targetId, mintTotp, panel = "co
|
|
|
1212
1224
|
wsParamName = /^https:/i.test(relayHttpBaseUrl) ? "wss" : "ws";
|
|
1213
1225
|
}
|
|
1214
1226
|
const clientId = `devtools-opener-${Date.now().toString(36)}`;
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
const code = mintTotp();
|
|
1218
|
-
wsPath += `&at=${encodeURIComponent(code)}`;
|
|
1219
|
-
}
|
|
1227
|
+
const code = mintTotp();
|
|
1228
|
+
const wsPath = `${relayHost}/client/${clientId}?target=${encodeURIComponent(targetId)}&at=${encodeURIComponent(code)}`;
|
|
1220
1229
|
const params = new URLSearchParams({
|
|
1221
1230
|
[wsParamName]: wsPath,
|
|
1222
1231
|
panel
|
|
@@ -1325,6 +1334,10 @@ var AutoDevtoolsOpener = class {
|
|
|
1325
1334
|
if (!options.targetId) return;
|
|
1326
1335
|
this._opened = true;
|
|
1327
1336
|
const inspectorUrl = buildChiiInspectorUrl(options.relayHttpBaseUrl, options.targetId, options.mintTotp);
|
|
1337
|
+
if (inspectorUrl === null) {
|
|
1338
|
+
process.stderr.write("[ait-debug] 기기가 연결됐습니다 — TOTP secret 미설정으로 인스펙터 URL을 생성할 수 없습니다.\n[ait-debug] relay 세션은 AIT_DEBUG_TOTP_SECRET 설정이 필요합니다.\n");
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1328
1341
|
process.stderr.write(`[ait-debug] 기기가 연결됐습니다 — Chii DevTools를 자동으로 엽니다.
|
|
1329
1342
|
[ait-debug] DevTools URL: ${inspectorUrl}\n[ait-debug] (AIT_AUTO_DEVTOOLS=0 으로 자동 열기를 끌 수 있습니다)
|
|
1330
1343
|
[ait-debug] 주의: URL의 at= 코드는 ~3분 안에서만 유효합니다.
|
|
@@ -2142,6 +2155,7 @@ const en = {
|
|
|
2142
2155
|
"launcher.diagNo": "no",
|
|
2143
2156
|
"launcher.letterboxDetected": "Display area is {pt}pt short — likely an iOS standalone letterbox. Removing and re-adding the launcher to the home screen may fix it.",
|
|
2144
2157
|
"launcher.navbar.defaultTitle": "Mini App",
|
|
2158
|
+
"launcher.navbar.back": "Back",
|
|
2145
2159
|
"launcher.navbar.menu": "Menu",
|
|
2146
2160
|
"launcher.navbar.close": "Close",
|
|
2147
2161
|
"launcher.navbar.menuRescan": "Rescan",
|
|
@@ -2393,6 +2407,7 @@ const tables = {
|
|
|
2393
2407
|
"launcher.diagNo": "아니요",
|
|
2394
2408
|
"launcher.letterboxDetected": "표시 영역이 {pt}pt 부족합니다 — iOS standalone letterbox로 보입니다. 런처를 홈 화면에서 제거 후 다시 설치하면 해소될 수 있어요.",
|
|
2395
2409
|
"launcher.navbar.defaultTitle": "미니앱",
|
|
2410
|
+
"launcher.navbar.back": "뒤로가기",
|
|
2396
2411
|
"launcher.navbar.menu": "메뉴",
|
|
2397
2412
|
"launcher.navbar.close": "닫기",
|
|
2398
2413
|
"launcher.navbar.menuRescan": "다시 스캔",
|
|
@@ -3100,8 +3115,9 @@ function buildAttachHtml(qrDataUrl, safeLabel, safeAttachUrl, locale, path = "/a
|
|
|
3100
3115
|
*
|
|
3101
3116
|
* @param getDashboardState - dashboard 상태를 반환하는 클로저. 주입 시 `GET /` dashboard와
|
|
3102
3117
|
* `GET /events` SSE 스트림이 활성화된다. 미주입 시 두 라우트는 204/서비스 없음으로 응답.
|
|
3118
|
+
* @param options - 서버 옵션. `sseRefreshIntervalMs`로 idle 탭 TOTP 만료 방지 주기를 조정.
|
|
3103
3119
|
*/
|
|
3104
|
-
async function startQrHttpServer(getDashboardState) {
|
|
3120
|
+
async function startQrHttpServer(getDashboardState, options) {
|
|
3105
3121
|
const { default: QRCode } = await import("qrcode");
|
|
3106
3122
|
/** SSE 활성 연결 목록 — `notifyStateChange()` 시 전체 push. */
|
|
3107
3123
|
const sseClients = [];
|
|
@@ -3234,19 +3250,28 @@ async function startQrHttpServer(getDashboardState) {
|
|
|
3234
3250
|
const address = server.address();
|
|
3235
3251
|
if (!address || typeof address === "string") throw new Error("qr-http-server: server.address()가 예상하지 못한 형태입니다.");
|
|
3236
3252
|
const port = address.port;
|
|
3253
|
+
/** idle 탭 TOTP 만료 방지용 주기 SSE 갱신 interval. */
|
|
3254
|
+
function notifyStateChangeInternal() {
|
|
3255
|
+
if (!getDashboardState) return;
|
|
3256
|
+
const state = getDashboardState();
|
|
3257
|
+
for (const client of sseClients) try {
|
|
3258
|
+
pushStateToClient(client, state);
|
|
3259
|
+
} catch {}
|
|
3260
|
+
}
|
|
3261
|
+
const refreshIntervalMs = options?.sseRefreshIntervalMs ?? 9e4;
|
|
3262
|
+
const refreshHandle = setInterval(() => {
|
|
3263
|
+
if (sseClients.length > 0 && getDashboardState) notifyStateChangeInternal();
|
|
3264
|
+
}, refreshIntervalMs).unref();
|
|
3237
3265
|
return {
|
|
3238
3266
|
port,
|
|
3239
3267
|
buildAttachPageUrl(attachUrl) {
|
|
3240
3268
|
return `http://127.0.0.1:${port}/attach?u=${encodeURIComponent(attachUrl)}`;
|
|
3241
3269
|
},
|
|
3242
3270
|
notifyStateChange() {
|
|
3243
|
-
|
|
3244
|
-
const state = getDashboardState();
|
|
3245
|
-
for (const client of sseClients) try {
|
|
3246
|
-
pushStateToClient(client, state);
|
|
3247
|
-
} catch {}
|
|
3271
|
+
notifyStateChangeInternal();
|
|
3248
3272
|
},
|
|
3249
3273
|
close() {
|
|
3274
|
+
clearInterval(refreshHandle);
|
|
3250
3275
|
return new Promise((resolve, reject) => {
|
|
3251
3276
|
server.close((err) => err ? reject(err) : resolve());
|
|
3252
3277
|
});
|
|
@@ -4635,7 +4660,7 @@ async function readMcpSdkVersion() {
|
|
|
4635
4660
|
* some test environments that skip the build step).
|
|
4636
4661
|
*/
|
|
4637
4662
|
function readDevtoolsVersion() {
|
|
4638
|
-
return "0.1.
|
|
4663
|
+
return "0.1.76";
|
|
4639
4664
|
}
|
|
4640
4665
|
/**
|
|
4641
4666
|
* Derives the next recommended action from a completed diagnostics snapshot.
|
|
@@ -5139,7 +5164,7 @@ function createDebugServer(deps) {
|
|
|
5139
5164
|
const collector = collectorDep ?? new InMemoryDiagnosticsCollector();
|
|
5140
5165
|
const server = new Server({
|
|
5141
5166
|
name: "ait-debug",
|
|
5142
|
-
version: "0.1.
|
|
5167
|
+
version: "0.1.76"
|
|
5143
5168
|
}, { capabilities: { tools: { listChanged: true } } });
|
|
5144
5169
|
server.setRequestHandler(ListToolsRequestSchema, () => {
|
|
5145
5170
|
const conn = router.active;
|
|
@@ -5738,37 +5763,52 @@ function errorResult(err, name, isLocal = false) {
|
|
|
5738
5763
|
return classifyToolError(err, name, isLocal);
|
|
5739
5764
|
}
|
|
5740
5765
|
/**
|
|
5741
|
-
* Starts a polling watcher that detects
|
|
5766
|
+
* Starts a polling watcher that detects target-set changes on
|
|
5742
5767
|
* `connection.listTargets()` and sends a `notifications/tools/list_changed`
|
|
5743
5768
|
* notification on the given server.
|
|
5744
5769
|
*
|
|
5745
5770
|
* The watcher polls every `intervalMs` (default 1 000 ms). It fires
|
|
5746
|
-
* `server.sendToolListChanged()`
|
|
5747
|
-
*
|
|
5771
|
+
* `server.sendToolListChanged()` + `onAttach()` whenever the sorted target-id
|
|
5772
|
+
* signature changes AND the new target set is non-empty. This covers:
|
|
5773
|
+
* - 0→N first attach
|
|
5774
|
+
* - 1→1 target replacement (same count, different id — e.g. rescan)
|
|
5775
|
+
* - N→M any change where the result is still non-empty
|
|
5776
|
+
*
|
|
5777
|
+
* Full detach (→ empty) updates the stored signature but does NOT fire the
|
|
5778
|
+
* callback — `onAttach` semantics are about a live target being present.
|
|
5779
|
+
*
|
|
5780
|
+
* The interval is **never cleared automatically** — it keeps running until
|
|
5781
|
+
* `stop()` is called during shutdown. This ensures that a target replacement
|
|
5782
|
+
* after the first attach is always detected.
|
|
5748
5783
|
*
|
|
5749
|
-
* `
|
|
5750
|
-
* already attached). Use this to trigger side-effects such as
|
|
5751
|
-
*
|
|
5752
|
-
* the previous behaviour exactly.
|
|
5784
|
+
* `onAttach` is called on every non-empty signature change (or immediately when
|
|
5785
|
+
* already attached). Use this to trigger side-effects such as pushing a fresh
|
|
5786
|
+
* SSE state to open dashboard tabs (issue #509). The callback is optional;
|
|
5787
|
+
* omitting it preserves the previous behaviour exactly.
|
|
5753
5788
|
*
|
|
5754
5789
|
* SECRET-HANDLING: target `id`/`title`/`url` are not written to any log here.
|
|
5755
5790
|
* Only an attach-detected stderr line is emitted (no target details).
|
|
5756
5791
|
*
|
|
5757
5792
|
* @returns `stop` — call this during shutdown to clear the interval.
|
|
5758
5793
|
*/
|
|
5759
|
-
function startAttachWatcher(connection, server, intervalMs = 1e3,
|
|
5760
|
-
|
|
5761
|
-
|
|
5794
|
+
function startAttachWatcher(connection, server, intervalMs = 1e3, onAttach) {
|
|
5795
|
+
/** Sorted, comma-joined target-id string — '' means no targets attached. */
|
|
5796
|
+
function signature() {
|
|
5797
|
+
return connection.listTargets().map((t) => t.id).sort().join(",");
|
|
5798
|
+
}
|
|
5799
|
+
let lastSignature = signature();
|
|
5800
|
+
if (lastSignature !== "") {
|
|
5762
5801
|
server.sendToolListChanged();
|
|
5763
|
-
|
|
5802
|
+
onAttach?.();
|
|
5764
5803
|
}
|
|
5765
5804
|
const handle = setInterval(() => {
|
|
5766
|
-
const
|
|
5767
|
-
if (
|
|
5768
|
-
|
|
5769
|
-
|
|
5770
|
-
|
|
5771
|
-
|
|
5805
|
+
const current = signature();
|
|
5806
|
+
if (current !== lastSignature) {
|
|
5807
|
+
lastSignature = current;
|
|
5808
|
+
if (current !== "") {
|
|
5809
|
+
server.sendToolListChanged();
|
|
5810
|
+
onAttach?.();
|
|
5811
|
+
}
|
|
5772
5812
|
}
|
|
5773
5813
|
}, intervalMs);
|
|
5774
5814
|
return { stop() {
|
|
@@ -7065,7 +7105,7 @@ function createDevServer(deps = {}) {
|
|
|
7065
7105
|
const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
|
|
7066
7106
|
const server = new Server({
|
|
7067
7107
|
name: "ait-devtools",
|
|
7068
|
-
version: "0.1.
|
|
7108
|
+
version: "0.1.76"
|
|
7069
7109
|
}, { capabilities: { tools: {} } });
|
|
7070
7110
|
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
|
|
7071
7111
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|