@zhihand/mcp 0.26.0 → 0.26.3
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/bin/zhihand +155 -46
- package/dist/core/command.d.ts +0 -1
- package/dist/core/command.js +26 -8
- package/dist/core/device.d.ts +1 -1
- package/dist/core/device.js +46 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/tools/schemas.d.ts +0 -1
- package/dist/tools/schemas.js +0 -1
- package/package.json +1 -1
package/bin/zhihand
CHANGED
|
@@ -291,6 +291,7 @@ switch (command) {
|
|
|
291
291
|
const { createControlCommand, enqueueCommand } = await import("../dist/core/command.js");
|
|
292
292
|
const { waitForCommandAck } = await import("../dist/core/sse.js");
|
|
293
293
|
const { fetchScreenshotBinary } = await import("../dist/core/screenshot.js");
|
|
294
|
+
const { fetchDeviceProfile, getStaticContext, isDeviceProfileLoaded, formatDeviceStatus } = await import("../dist/core/device.js");
|
|
294
295
|
|
|
295
296
|
let testConfig;
|
|
296
297
|
try {
|
|
@@ -305,68 +306,176 @@ switch (command) {
|
|
|
305
306
|
console.log(` Device: ${testConfig.credentialId}`);
|
|
306
307
|
console.log(` Endpoint: ${testConfig.controlPlaneEndpoint}\n`);
|
|
307
308
|
|
|
308
|
-
const steps = [
|
|
309
|
-
{ label: "1. Screenshot", type: "screenshot" },
|
|
310
|
-
{ label: "2. Click center", type: "hid", params: { action: "click", xRatio: 0.5, yRatio: 0.5 } },
|
|
311
|
-
{ label: "3. Swipe up", type: "hid", params: { action: "swipe", startXRatio: 0.5, startYRatio: 0.7, endXRatio: 0.5, endYRatio: 0.3, durationMs: 300 } },
|
|
312
|
-
{ label: "4. Swipe down", type: "hid", params: { action: "swipe", startXRatio: 0.5, startYRatio: 0.3, endXRatio: 0.5, endYRatio: 0.7, durationMs: 300 } },
|
|
313
|
-
{ label: "5. Press Home", type: "hid", params: { action: "home" } },
|
|
314
|
-
{ label: "6. Open WeChat", type: "hid", params: { action: "open_app", appPackage: "com.tencent.mm" } },
|
|
315
|
-
{ label: "7. Press Back", type: "hid", params: { action: "back" } },
|
|
316
|
-
{ label: "8. Screenshot", type: "screenshot" },
|
|
317
|
-
];
|
|
318
|
-
|
|
319
309
|
let passed = 0;
|
|
320
310
|
let failed = 0;
|
|
311
|
+
let totalSteps = 0;
|
|
321
312
|
|
|
322
|
-
|
|
323
|
-
|
|
313
|
+
// ── Helper: run a single HID step ──
|
|
314
|
+
async function runHidStep(label, params) {
|
|
315
|
+
totalSteps++;
|
|
316
|
+
process.stdout.write(` ${label}... `);
|
|
324
317
|
const t0 = Date.now();
|
|
325
318
|
try {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
console.log(`⏱️ Timeout (${Date.now() - t0}ms)`);
|
|
338
|
-
failed++;
|
|
339
|
-
}
|
|
319
|
+
const cmd = createControlCommand(params);
|
|
320
|
+
const queued = await enqueueCommand(testConfig, cmd);
|
|
321
|
+
const ack = await waitForCommandAck(testConfig, { commandId: queued.id, timeoutMs: 10_000 });
|
|
322
|
+
const ms = Date.now() - t0;
|
|
323
|
+
if (ack.acked) {
|
|
324
|
+
const ackStatus = ack.command?.ack_status ?? "ok";
|
|
325
|
+
const detail = ackStatus !== "ok" ? ` [${ackStatus}]` : "";
|
|
326
|
+
const resultInfo = ack.command?.ack_result ? ` ${JSON.stringify(ack.command.ack_result)}` : "";
|
|
327
|
+
console.log(`✅ (${ms}ms)${detail}${resultInfo}`);
|
|
328
|
+
passed++;
|
|
329
|
+
return ack;
|
|
340
330
|
} else {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
331
|
+
console.log(`⏱️ Timeout (${ms}ms)`);
|
|
332
|
+
failed++;
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
} catch (err) {
|
|
336
|
+
console.log(`❌ ${err.message} (${Date.now() - t0}ms)`);
|
|
337
|
+
failed++;
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── Helper: run a screenshot step ──
|
|
343
|
+
async function runScreenshotStep(label) {
|
|
344
|
+
totalSteps++;
|
|
345
|
+
process.stdout.write(` ${label}... `);
|
|
346
|
+
const t0 = Date.now();
|
|
347
|
+
try {
|
|
348
|
+
const cmd = createControlCommand({ action: "screenshot" });
|
|
349
|
+
const queued = await enqueueCommand(testConfig, cmd);
|
|
350
|
+
const ack = await waitForCommandAck(testConfig, { commandId: queued.id, timeoutMs: 10_000 });
|
|
351
|
+
if (ack.acked) {
|
|
352
|
+
const buf = await fetchScreenshotBinary(testConfig);
|
|
344
353
|
const ms = Date.now() - t0;
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
passed++;
|
|
351
|
-
} else {
|
|
352
|
-
console.log(`⏱️ Timeout (${ms}ms)`);
|
|
353
|
-
failed++;
|
|
354
|
-
}
|
|
354
|
+
console.log(`✅ ${(buf.length / 1024).toFixed(0)}KB (${ms}ms)`);
|
|
355
|
+
passed++;
|
|
356
|
+
} else {
|
|
357
|
+
console.log(`⏱️ Timeout (${Date.now() - t0}ms)`);
|
|
358
|
+
failed++;
|
|
355
359
|
}
|
|
356
360
|
} catch (err) {
|
|
361
|
+
console.log(`❌ ${err.message} (${Date.now() - t0}ms)`);
|
|
362
|
+
failed++;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const pause = () => new Promise((r) => setTimeout(r, 1500));
|
|
367
|
+
|
|
368
|
+
// ── Phase 1: Device Profile ──────────────────────────────
|
|
369
|
+
console.log(" ── Phase 1: Device Info ──");
|
|
370
|
+
totalSteps++;
|
|
371
|
+
process.stdout.write(" 1. Fetch device profile... ");
|
|
372
|
+
{
|
|
373
|
+
const t0 = Date.now();
|
|
374
|
+
try {
|
|
375
|
+
await fetchDeviceProfile(testConfig);
|
|
357
376
|
const ms = Date.now() - t0;
|
|
358
|
-
|
|
377
|
+
if (isDeviceProfileLoaded()) {
|
|
378
|
+
const s = getStaticContext();
|
|
379
|
+
console.log(`✅ ${s.platform} ${s.model}, ${s.osVersion}, ${s.screenWidthPx}x${s.screenHeightPx} (${ms}ms)`);
|
|
380
|
+
passed++;
|
|
381
|
+
} else {
|
|
382
|
+
console.log(`⚠️ Loaded but empty (${ms}ms)`);
|
|
383
|
+
failed++;
|
|
384
|
+
}
|
|
385
|
+
} catch (err) {
|
|
386
|
+
console.log(`❌ ${err.message} (${Date.now() - t0}ms)`);
|
|
359
387
|
failed++;
|
|
360
388
|
}
|
|
361
|
-
// Pause between commands: let phone process + user can observe
|
|
362
|
-
await new Promise((r) => setTimeout(r, 2000));
|
|
363
389
|
}
|
|
364
390
|
|
|
365
|
-
|
|
391
|
+
totalSteps++;
|
|
392
|
+
process.stdout.write(" 2. Device status fields... ");
|
|
393
|
+
{
|
|
394
|
+
try {
|
|
395
|
+
const status = formatDeviceStatus();
|
|
396
|
+
const ignoredDefaults = new Set(["unknown", "0x0", "-1% (unknown)", "0"]);
|
|
397
|
+
const fields = Object.keys(status).filter((k) => {
|
|
398
|
+
const v = status[k];
|
|
399
|
+
if (v === null || v === undefined) return false;
|
|
400
|
+
if (ignoredDefaults.has(String(v))) return false;
|
|
401
|
+
return true;
|
|
402
|
+
});
|
|
403
|
+
console.log(`✅ ${fields.length} fields (${fields.join(", ")})`);
|
|
404
|
+
passed++;
|
|
405
|
+
} catch (err) {
|
|
406
|
+
console.log(`❌ ${err.message}`);
|
|
407
|
+
failed++;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
await pause();
|
|
412
|
+
|
|
413
|
+
// ── Phase 2: Screenshot + Basic HID ──────────────────────
|
|
414
|
+
console.log(" ── Phase 2: Screenshot + HID ──");
|
|
415
|
+
await runScreenshotStep("3. Screenshot");
|
|
416
|
+
await pause();
|
|
417
|
+
await runHidStep("4. Click center", { action: "click", xRatio: 0.5, yRatio: 0.5 });
|
|
418
|
+
await pause();
|
|
419
|
+
await runHidStep("5. Swipe up", { action: "swipe", startXRatio: 0.5, startYRatio: 0.7, endXRatio: 0.5, endYRatio: 0.3, durationMs: 300 });
|
|
420
|
+
await pause();
|
|
421
|
+
await runHidStep("6. Swipe down", { action: "swipe", startXRatio: 0.5, startYRatio: 0.3, endXRatio: 0.5, endYRatio: 0.7, durationMs: 300 });
|
|
422
|
+
await pause();
|
|
423
|
+
await runHidStep("7. Scroll down", { action: "scroll", xRatio: 0.5, yRatio: 0.5, direction: "down", amount: 3 });
|
|
424
|
+
await pause();
|
|
425
|
+
await runHidStep("8. Scroll up", { action: "scroll", xRatio: 0.5, yRatio: 0.5, direction: "up", amount: 3 });
|
|
426
|
+
await pause();
|
|
427
|
+
|
|
428
|
+
// ── Phase 3: App + Navigation ────────────────────────────
|
|
429
|
+
console.log(" ── Phase 3: App + Navigation ──");
|
|
430
|
+
await runHidStep("9. Press Home", { action: "home" });
|
|
431
|
+
await pause();
|
|
432
|
+
{
|
|
433
|
+
const platform = isDeviceProfileLoaded() ? getStaticContext().platform : "android";
|
|
434
|
+
const openParams = platform === "ios"
|
|
435
|
+
? { action: "open_app", bundleId: "com.tencent.xin" }
|
|
436
|
+
: { action: "open_app", appPackage: "com.tencent.mm" };
|
|
437
|
+
await runHidStep(`10. Open WeChat (${platform})`, openParams);
|
|
438
|
+
}
|
|
439
|
+
await pause();
|
|
440
|
+
await runHidStep("11. Press Back", { action: "back" });
|
|
441
|
+
await pause();
|
|
442
|
+
|
|
443
|
+
// ── Phase 4: Clipboard Roundtrip ─────────────────────────
|
|
444
|
+
console.log(" ── Phase 4: Clipboard Roundtrip ──");
|
|
445
|
+
const clipboardTestText = `zhihand_test_${Date.now()}`;
|
|
446
|
+
|
|
447
|
+
const setAck = await runHidStep("12. Clipboard set", { action: "clipboard", clipboardAction: "set", text: clipboardTestText });
|
|
448
|
+
await pause();
|
|
449
|
+
|
|
450
|
+
const getAck = await runHidStep("13. Clipboard get", { action: "clipboard", clipboardAction: "get" });
|
|
451
|
+
await pause();
|
|
452
|
+
|
|
453
|
+
// Verify roundtrip
|
|
454
|
+
totalSteps++;
|
|
455
|
+
process.stdout.write(" 14. Clipboard roundtrip verify... ");
|
|
456
|
+
if (setAck && getAck) {
|
|
457
|
+
const returned = getAck.command?.ack_result?.text ?? getAck.command?.ack_result?.clipboard ?? null;
|
|
458
|
+
if (returned === clipboardTestText) {
|
|
459
|
+
console.log(`✅ Match: "${clipboardTestText}"`);
|
|
460
|
+
passed++;
|
|
461
|
+
} else if (returned) {
|
|
462
|
+
console.log(`⚠️ Mismatch: sent "${clipboardTestText}", got "${returned}"`);
|
|
463
|
+
failed++;
|
|
464
|
+
} else {
|
|
465
|
+
console.log(`⚠️ No text in ack_result (keys: ${JSON.stringify(Object.keys(getAck.command?.ack_result ?? {}))})`);
|
|
466
|
+
failed++;
|
|
467
|
+
}
|
|
468
|
+
} else {
|
|
469
|
+
console.log(`⏭️ Skipped (clipboard set/get failed)`);
|
|
470
|
+
failed++;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// ── Summary ──────────────────────────────────────────────
|
|
474
|
+
console.log(`\n Result: ${passed}/${totalSteps} passed`);
|
|
366
475
|
if (failed === 0) {
|
|
367
|
-
console.log(" ✅ Device is
|
|
476
|
+
console.log(" ✅ All tests passed! Device is fully responsive.");
|
|
368
477
|
} else {
|
|
369
|
-
console.log(
|
|
478
|
+
console.log(` ⚠️ ${failed} test(s) failed. Check phone connectivity.`);
|
|
370
479
|
}
|
|
371
480
|
process.exit(failed > 0 ? 1 : 0);
|
|
372
481
|
}
|
package/dist/core/command.d.ts
CHANGED
package/dist/core/command.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getStaticContext, isDeviceProfileLoaded } from "./device.js";
|
|
1
2
|
import { dbg } from "../daemon/logger.js";
|
|
2
3
|
let messageCounter = 0;
|
|
3
4
|
function nextMessageId() {
|
|
@@ -54,17 +55,34 @@ export function createControlCommand(params) {
|
|
|
54
55
|
};
|
|
55
56
|
case "open_app": {
|
|
56
57
|
const appPayload = {};
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
const platform = isDeviceProfileLoaded() ? getStaticContext().platform : "unknown";
|
|
59
|
+
// Only send platform-appropriate fields — Android strict JSON rejects unknown keys
|
|
60
|
+
if (platform === "android") {
|
|
61
|
+
// Android: only app_package
|
|
62
|
+
if (params.appPackage)
|
|
63
|
+
appPayload.app_package = params.appPackage;
|
|
64
|
+
}
|
|
65
|
+
else if (platform === "ios") {
|
|
66
|
+
// iOS: bundleId or urlScheme
|
|
67
|
+
if (params.bundleId)
|
|
68
|
+
appPayload.bundle_id = params.bundleId;
|
|
69
|
+
if (params.urlScheme)
|
|
70
|
+
appPayload.url_scheme = params.urlScheme;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// Unknown platform: send only what's provided, prefer appPackage
|
|
74
|
+
if (params.appPackage)
|
|
75
|
+
appPayload.app_package = params.appPackage;
|
|
76
|
+
else if (params.bundleId)
|
|
77
|
+
appPayload.bundle_id = params.bundleId;
|
|
78
|
+
else if (params.urlScheme)
|
|
79
|
+
appPayload.url_scheme = params.urlScheme;
|
|
80
|
+
}
|
|
81
|
+
// Never send app_name — phone strict JSON parser rejects unknown keys
|
|
65
82
|
if (!appPayload.app_package && !appPayload.bundle_id && !appPayload.url_scheme) {
|
|
66
83
|
throw new Error("open_app requires at least one of: appPackage, bundleId, urlScheme");
|
|
67
84
|
}
|
|
85
|
+
dbg(`[cmd] open_app: platform=${platform}, payload=${JSON.stringify(appPayload)}`);
|
|
68
86
|
return { type: "receive_app", payload: appPayload };
|
|
69
87
|
}
|
|
70
88
|
case "screenshot":
|
package/dist/core/device.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export declare function getDynamicContext(): DynamicContext;
|
|
|
40
40
|
export declare function isDeviceProfileLoaded(): boolean;
|
|
41
41
|
export declare function extractStatic(profile: Record<string, unknown>): StaticContext;
|
|
42
42
|
export declare function extractDynamic(profile: Record<string, unknown>): DynamicContext;
|
|
43
|
-
export declare function updateDeviceProfile(
|
|
43
|
+
export declare function updateDeviceProfile(raw: Record<string, unknown>): void;
|
|
44
44
|
export declare function fetchDeviceProfile(config: ZhiHandConfig): Promise<void>;
|
|
45
45
|
export declare function buildControlToolDescription(): string;
|
|
46
46
|
export declare function buildScreenshotToolDescription(): string;
|
package/dist/core/device.js
CHANGED
|
@@ -57,16 +57,37 @@ function bool(v, fallback) {
|
|
|
57
57
|
return typeof v === "boolean" ? v : fallback;
|
|
58
58
|
}
|
|
59
59
|
export function extractStatic(profile) {
|
|
60
|
+
// Build OS version string from platform + system_release + api_level
|
|
61
|
+
const platform = str(profile.platform, DEFAULT_STATIC.platform);
|
|
62
|
+
const sysRelease = str(profile.system_release, "");
|
|
63
|
+
const apiLevel = typeof profile.api_level === "number" ? profile.api_level : null;
|
|
64
|
+
let osVersion;
|
|
65
|
+
if (platform === "android" && sysRelease && apiLevel) {
|
|
66
|
+
osVersion = `Android ${sysRelease} (API ${apiLevel})`;
|
|
67
|
+
}
|
|
68
|
+
else if (platform === "ios" && sysRelease) {
|
|
69
|
+
osVersion = `iOS ${sysRelease}`;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
osVersion = sysRelease || DEFAULT_STATIC.osVersion;
|
|
73
|
+
}
|
|
74
|
+
// Screen size: Android uses display_width_px/display_height_px, iOS uses display_width_pixels/display_height_pixels
|
|
75
|
+
const screenW = num(profile.display_width_px, num(profile.display_width_pixels, DEFAULT_STATIC.screenWidthPx));
|
|
76
|
+
const screenH = num(profile.display_height_px, num(profile.display_height_pixels, DEFAULT_STATIC.screenHeightPx));
|
|
77
|
+
// Density: Android uses density, iOS uses display_scale
|
|
78
|
+
const density = num(profile.density, num(profile.display_scale, DEFAULT_STATIC.density));
|
|
79
|
+
// Text direction: rtl is boolean
|
|
80
|
+
const textDirection = profile.rtl === true ? "rtl" : "ltr";
|
|
60
81
|
return {
|
|
61
|
-
platform
|
|
82
|
+
platform,
|
|
62
83
|
model: str(profile.model, DEFAULT_STATIC.model),
|
|
63
|
-
osVersion
|
|
64
|
-
screenWidthPx:
|
|
65
|
-
screenHeightPx:
|
|
66
|
-
density
|
|
84
|
+
osVersion,
|
|
85
|
+
screenWidthPx: screenW,
|
|
86
|
+
screenHeightPx: screenH,
|
|
87
|
+
density,
|
|
67
88
|
formFactor: str(profile.form_factor, DEFAULT_STATIC.formFactor),
|
|
68
89
|
locale: str(profile.locale, DEFAULT_STATIC.locale),
|
|
69
|
-
textDirection
|
|
90
|
+
textDirection,
|
|
70
91
|
timezone: str(profile.timezone, DEFAULT_STATIC.timezone),
|
|
71
92
|
navigationMode: typeof profile.navigation_mode === "string" ? profile.navigation_mode : undefined,
|
|
72
93
|
romFamily: typeof profile.rom_family === "string" ? profile.rom_family : undefined,
|
|
@@ -88,7 +109,16 @@ export function extractDynamic(profile) {
|
|
|
88
109
|
};
|
|
89
110
|
}
|
|
90
111
|
// ── Update from SSE event ─────────────────────────────────
|
|
91
|
-
export function updateDeviceProfile(
|
|
112
|
+
export function updateDeviceProfile(raw) {
|
|
113
|
+
// SSE events may also wrap in { platform, attributes: {...} } — flatten if needed
|
|
114
|
+
let profile;
|
|
115
|
+
if (typeof raw.attributes === "object" && raw.attributes !== null) {
|
|
116
|
+
const attrs = raw.attributes;
|
|
117
|
+
profile = { ...attrs, platform: raw.platform ?? attrs.platform };
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
profile = raw;
|
|
121
|
+
}
|
|
92
122
|
staticCtx = extractStatic(profile);
|
|
93
123
|
dynamicCtx = extractDynamic(profile);
|
|
94
124
|
loaded = true;
|
|
@@ -108,10 +138,16 @@ export async function fetchDeviceProfile(config) {
|
|
|
108
138
|
return;
|
|
109
139
|
}
|
|
110
140
|
const data = await response.json();
|
|
111
|
-
// API
|
|
112
|
-
const
|
|
113
|
-
? data.
|
|
141
|
+
// API returns { profile: { credential_id, platform, attributes: {...} } }
|
|
142
|
+
const wrapper = (typeof data.profile === "object" && data.profile !== null)
|
|
143
|
+
? data.profile
|
|
114
144
|
: data;
|
|
145
|
+
// Merge top-level fields (platform, edge_id) with attributes for flat extraction
|
|
146
|
+
const attrs = (typeof wrapper.attributes === "object" && wrapper.attributes !== null)
|
|
147
|
+
? wrapper.attributes
|
|
148
|
+
: {};
|
|
149
|
+
const profile = { ...attrs, platform: wrapper.platform ?? attrs.platform };
|
|
150
|
+
dbg(`[device] Raw profile keys: ${Object.keys(profile).join(", ")}`);
|
|
115
151
|
updateDeviceProfile(profile);
|
|
116
152
|
}
|
|
117
153
|
catch (err) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
-
export declare const PACKAGE_VERSION = "0.26.
|
|
2
|
+
export declare const PACKAGE_VERSION = "0.26.3";
|
|
3
3
|
export declare function createServer(deviceName?: string): McpServer;
|
|
4
4
|
export declare function startStdioServer(deviceName?: string): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { executeControl } from "./tools/control.js";
|
|
|
6
6
|
import { handleScreenshot } from "./tools/screenshot.js";
|
|
7
7
|
import { handlePair } from "./tools/pair.js";
|
|
8
8
|
import { getStaticContext, getDynamicContext, fetchDeviceProfile, buildControlToolDescription, buildScreenshotToolDescription, formatDeviceStatus, } from "./core/device.js";
|
|
9
|
-
export const PACKAGE_VERSION = "0.26.
|
|
9
|
+
export const PACKAGE_VERSION = "0.26.3";
|
|
10
10
|
export function createServer(deviceName) {
|
|
11
11
|
const server = new McpServer({
|
|
12
12
|
name: "zhihand",
|
package/dist/tools/schemas.d.ts
CHANGED
|
@@ -16,7 +16,6 @@ export declare const controlSchema: {
|
|
|
16
16
|
appPackage: z.ZodOptional<z.ZodString>;
|
|
17
17
|
bundleId: z.ZodOptional<z.ZodString>;
|
|
18
18
|
urlScheme: z.ZodOptional<z.ZodString>;
|
|
19
|
-
appName: z.ZodOptional<z.ZodString>;
|
|
20
19
|
};
|
|
21
20
|
export declare const screenshotSchema: {};
|
|
22
21
|
export declare const pairSchema: {
|
package/dist/tools/schemas.js
CHANGED
|
@@ -22,7 +22,6 @@ export const controlSchema = {
|
|
|
22
22
|
appPackage: z.string().optional().describe("Android package name, e.g. 'com.tencent.mm'"),
|
|
23
23
|
bundleId: z.string().optional().describe("iOS bundle ID, e.g. 'com.tencent.xin'"),
|
|
24
24
|
urlScheme: z.string().optional().describe("URL scheme, e.g. 'weixin://'"),
|
|
25
|
-
appName: z.string().optional().describe("Human-readable app name (for logging)"),
|
|
26
25
|
};
|
|
27
26
|
export const screenshotSchema = {};
|
|
28
27
|
export const pairSchema = {
|