dodo-mcp 1.0.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -20
- package/dist/cli/main.js +152 -28
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/menu.js +2 -2
- package/dist/cli/menu.js.map +1 -1
- package/dist/config/globalConfig.js +7 -3
- package/dist/config/globalConfig.js.map +1 -1
- package/dist/config/tunnelConfig.js +2 -1
- package/dist/config/tunnelConfig.js.map +1 -1
- package/dist/projects/ownerAdmin.js +86 -0
- package/dist/projects/ownerAdmin.js.map +1 -0
- package/dist/projects/registry.js +90 -9
- package/dist/projects/registry.js.map +1 -1
- package/dist/security/projectAccess.js +69 -0
- package/dist/security/projectAccess.js.map +1 -0
- package/dist/security/projectAuthority.js +5 -1
- package/dist/security/projectAuthority.js.map +1 -1
- package/dist/server/appServer.js +23 -9
- package/dist/server/appServer.js.map +1 -1
- package/dist/server/bootstrap.js +9 -1
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/server/configUi/app.css +8 -0
- package/dist/server/configUi/app.js +142 -18
- package/dist/server/configUi/index.html +50 -13
- package/dist/server/installationRuntime.js +6 -2
- package/dist/server/installationRuntime.js.map +1 -1
- package/dist/server/instructions.js +1 -1
- package/dist/server/instructions.js.map +1 -1
- package/dist/server/ipcDispatch.js +3 -0
- package/dist/server/ipcDispatch.js.map +1 -1
- package/dist/server/localConfig.js +80 -13
- package/dist/server/localConfig.js.map +1 -1
- package/dist/services/ai/subagents.js +1 -1
- package/dist/services/ai/subagents.js.map +1 -1
- package/dist/services/android/adbBackend.js +106 -0
- package/dist/services/android/adbBackend.js.map +1 -0
- package/dist/services/android/androidPolicy.js +61 -0
- package/dist/services/android/androidPolicy.js.map +1 -0
- package/dist/services/android/androidService.js +444 -0
- package/dist/services/android/androidService.js.map +1 -0
- package/dist/services/android/protocol.js +39 -0
- package/dist/services/android/protocol.js.map +1 -0
- package/dist/services/multimodal/storage.js +10 -1
- package/dist/services/multimodal/storage.js.map +1 -1
- package/dist/services/schedules/scheduleService.js +8 -1
- package/dist/services/schedules/scheduleService.js.map +1 -1
- package/dist/setup/componentProbes.js +7 -1
- package/dist/setup/componentProbes.js.map +1 -1
- package/dist/setup/setup.js +11 -1
- package/dist/setup/setup.js.map +1 -1
- package/dist/store/db.js +14 -0
- package/dist/store/db.js.map +1 -1
- package/dist/tools/agentRuntimeTools.js +2 -3
- package/dist/tools/agentRuntimeTools.js.map +1 -1
- package/dist/tools/androidTools.js +113 -0
- package/dist/tools/androidTools.js.map +1 -0
- package/dist/tools/catalog.js +3 -0
- package/dist/tools/catalog.js.map +1 -1
- package/dist/tools/context.js +85 -5
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/projectTools.js +1 -1
- package/dist/tools/projectTools.js.map +1 -1
- package/dist/tools/surface.js +18 -11
- package/dist/tools/surface.js.map +1 -1
- package/dist/tunnel/control.js +11 -4
- package/dist/tunnel/control.js.map +1 -1
- package/dist/tunnel/log.js +32 -0
- package/dist/tunnel/log.js.map +1 -1
- package/dist/tunnel/supervisor.js +103 -24
- package/dist/tunnel/supervisor.js.map +1 -1
- package/docs/ANDROID.md +105 -28
- package/docs/ARCHITECTURE.md +16 -7
- package/docs/AUTH.md +6 -0
- package/docs/COMPATIBILITY.md +14 -7
- package/docs/MANUAL_ACCEPTANCE.md +40 -6
- package/docs/PROJECTS.md +73 -2
- package/docs/RELEASE_1.1.0.md +69 -0
- package/docs/RELEASE_1.2.0.md +75 -0
- package/docs/RELEASE_NOTES.md +30 -0
- package/docs/SECURITY.md +45 -6
- package/docs/TEST_REPORT.md +96 -0
- package/docs/TUNNEL.md +79 -16
- package/docs/adr/048-persistent-connection-mode.md +3 -1
- package/docs/adr/049-android-adb-control.md +52 -0
- package/docs/adr/050-cloudflare-local-and-project-access.md +67 -0
- package/docs/adr/README.md +2 -0
- package/package.json +6 -2
- package/schemas/global-config.schema.json +1 -0
- package/schemas/tools.compact.json +312 -9
- package/schemas/tools.hybrid.json +485 -152
- package/schemas/tools.json +3610 -534
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { digestOf } from '../../util/hash.js';
|
|
4
|
+
import { AndroidModeSchema, AndroidPolicySchema, AndroidSerialSchema } from './protocol.js';
|
|
5
|
+
const INSTALLATION_POLICY_KEY = 'android-policy:installation';
|
|
6
|
+
const workspacePolicyKey = (workspaceId) => `android-policy:${workspaceId}`;
|
|
7
|
+
export const AndroidPolicyInputSchema = z.object({
|
|
8
|
+
mode: AndroidModeSchema,
|
|
9
|
+
allowedDevices: z.array(AndroidSerialSchema).max(20).default([]),
|
|
10
|
+
minutes: z.number().int().min(1).max(480).optional(),
|
|
11
|
+
persistent: z.boolean().default(false),
|
|
12
|
+
}).strict()
|
|
13
|
+
.refine((p) => p.mode === 'off' || p.allowedDevices.length > 0, 'choose at least one exact ADB serial')
|
|
14
|
+
.refine((p) => !p.persistent || p.minutes === undefined, 'use persistent or minutes, not both');
|
|
15
|
+
export function readAndroidPolicy(store, workspaceId, epoch, now = Date.now()) {
|
|
16
|
+
const off = { mode: 'off', allowedDevices: [], epoch, expiresAt: 0, persistent: false };
|
|
17
|
+
const temporary = store.getMeta(workspacePolicyKey(workspaceId));
|
|
18
|
+
if (temporary) {
|
|
19
|
+
try {
|
|
20
|
+
const parsed = AndroidPolicySchema.parse(JSON.parse(temporary));
|
|
21
|
+
if (!parsed.persistent && parsed.epoch === epoch && parsed.expiresAt !== null && parsed.expiresAt > now)
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
catch { /* corrupt private state fails closed */ }
|
|
25
|
+
}
|
|
26
|
+
const installed = store.getMeta(INSTALLATION_POLICY_KEY);
|
|
27
|
+
if (installed) {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = AndroidPolicySchema.parse(JSON.parse(installed));
|
|
30
|
+
if (parsed.persistent && parsed.mode !== 'off')
|
|
31
|
+
return { ...parsed, epoch };
|
|
32
|
+
}
|
|
33
|
+
catch { /* corrupt private state fails closed */ }
|
|
34
|
+
}
|
|
35
|
+
return off;
|
|
36
|
+
}
|
|
37
|
+
/** Local owner control only. This is deliberately absent from the MCP catalog. */
|
|
38
|
+
export function saveAndroidPolicy(store, workspaceId, epoch, input, now = Date.now()) {
|
|
39
|
+
const args = AndroidPolicyInputSchema.parse(input);
|
|
40
|
+
const persistent = args.mode !== 'off' && args.persistent;
|
|
41
|
+
const policy = {
|
|
42
|
+
mode: args.mode,
|
|
43
|
+
allowedDevices: args.mode === 'off' ? [] : [...new Set(args.allowedDevices)],
|
|
44
|
+
epoch,
|
|
45
|
+
persistent,
|
|
46
|
+
revision: randomUUID(),
|
|
47
|
+
expiresAt: args.mode === 'off' ? 0 : persistent ? null : now + (args.minutes ?? 60) * 60_000,
|
|
48
|
+
};
|
|
49
|
+
store.db.transaction(() => {
|
|
50
|
+
if (args.mode === 'off' || persistent) {
|
|
51
|
+
store.db.prepare("DELETE FROM meta WHERE key LIKE 'android-policy:%'").run();
|
|
52
|
+
store.setMeta(INSTALLATION_POLICY_KEY, JSON.stringify(policy));
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
store.setMeta(workspacePolicyKey(workspaceId), JSON.stringify(policy));
|
|
56
|
+
}
|
|
57
|
+
store.audit({ workspaceId, principal: 'local-owner', tool: 'android.policy', inputDigest: digestOf(policy).slice(0, 24), durationMs: 0, result: args.mode });
|
|
58
|
+
})();
|
|
59
|
+
return policy;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=androidPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"androidPolicy.js","sourceRoot":"","sources":["../../../src/services/android/androidPolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,444 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
4
|
+
import { DodoError } from '../../errors.js';
|
|
5
|
+
import { decodeUtf8Strict } from '../../util/bytes.js';
|
|
6
|
+
import { digestOf, sha256Bytes } from '../../util/hash.js';
|
|
7
|
+
import { readAndroidPolicy, saveAndroidPolicy } from './androidPolicy.js';
|
|
8
|
+
import { AndroidActionSchema, AndroidAppActionSchema, AndroidSerialSchema } from './protocol.js';
|
|
9
|
+
import { parseAdbDevices } from './adbBackend.js';
|
|
10
|
+
import { ensurePrivateDirectory } from '../../platform/privateFs.js';
|
|
11
|
+
import { removeWithRetry } from '../../platform/fsRetry.js';
|
|
12
|
+
const DEVICE_PATH_MAX = 512;
|
|
13
|
+
const SNAPSHOT_TTL = 30_000;
|
|
14
|
+
// One DODO process can host several project runtimes. Device effects/reads must
|
|
15
|
+
// still serialize across those runtimes so two agents cannot interleave ADB
|
|
16
|
+
// commands merely by targeting different projects.
|
|
17
|
+
const PROCESS_DEVICE_BUSY = new Set();
|
|
18
|
+
function devicePath(value) {
|
|
19
|
+
if (typeof value !== 'string' || value.length < 2 || value.length > DEVICE_PATH_MAX || !value.startsWith('/') || /[\0\r\n]/.test(value)) {
|
|
20
|
+
throw new DodoError('INVALID_INPUT', 'device path must be an absolute Android path without control characters');
|
|
21
|
+
}
|
|
22
|
+
if (value.split('/').some((part) => part === '..'))
|
|
23
|
+
throw new DodoError('PATH_DENIED', 'device path traversal is rejected');
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
function pngDimensions(bytes) {
|
|
27
|
+
if (bytes.length < 24 || bytes.subarray(0, 8).toString('hex') !== '89504e470d0a1a0a' || bytes.subarray(12, 16).toString('ascii') !== 'IHDR') {
|
|
28
|
+
throw new DodoError('INTERNAL_ERROR', 'ADB screenshot did not return a valid PNG');
|
|
29
|
+
}
|
|
30
|
+
const width = bytes.readUInt32BE(16), height = bytes.readUInt32BE(20);
|
|
31
|
+
if (width < 1 || height < 1 || width > 20_000 || height > 20_000)
|
|
32
|
+
throw new DodoError('RESOURCE_LIMIT', 'Android screenshot dimensions are outside the supported range');
|
|
33
|
+
return { width, height };
|
|
34
|
+
}
|
|
35
|
+
function decodeXml(value) {
|
|
36
|
+
return value.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
|
37
|
+
}
|
|
38
|
+
export function parseUiHierarchy(xml, maxNodes = 300) {
|
|
39
|
+
const nodes = [];
|
|
40
|
+
const matches = xml.matchAll(/<node\s+([^>]*?)(?:\/?>)/g);
|
|
41
|
+
let total = 0;
|
|
42
|
+
for (const match of matches) {
|
|
43
|
+
total += 1;
|
|
44
|
+
if (nodes.length >= maxNodes)
|
|
45
|
+
continue;
|
|
46
|
+
const attrs = new Map();
|
|
47
|
+
for (const attr of match[1].matchAll(/([A-Za-z][A-Za-z0-9_-]*)="([^"]*)"/g))
|
|
48
|
+
attrs.set(attr[1], decodeXml(attr[2]));
|
|
49
|
+
const boundsMatch = /^\[(\d+),(\d+)\]\[(\d+),(\d+)\]$/.exec(attrs.get('bounds') ?? '');
|
|
50
|
+
const password = attrs.get('password') === 'true';
|
|
51
|
+
nodes.push({
|
|
52
|
+
index: total - 1,
|
|
53
|
+
className: (attrs.get('class') ?? '').slice(0, 200),
|
|
54
|
+
resourceId: (attrs.get('resource-id') ?? '').slice(0, 300),
|
|
55
|
+
packageName: (attrs.get('package') ?? '').slice(0, 220),
|
|
56
|
+
...(password ? { redacted: true } : {
|
|
57
|
+
...(attrs.get('text') ? { text: attrs.get('text').slice(0, 500) } : {}),
|
|
58
|
+
...(attrs.get('content-desc') ? { description: attrs.get('content-desc').slice(0, 500) } : {}),
|
|
59
|
+
}),
|
|
60
|
+
clickable: attrs.get('clickable') === 'true',
|
|
61
|
+
enabled: attrs.get('enabled') !== 'false',
|
|
62
|
+
focusable: attrs.get('focusable') === 'true',
|
|
63
|
+
...(boundsMatch ? { bounds: { x: Number(boundsMatch[1]), y: Number(boundsMatch[2]), width: Number(boundsMatch[3]) - Number(boundsMatch[1]), height: Number(boundsMatch[4]) - Number(boundsMatch[2]) } } : {}),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return { nodes, truncated: total > nodes.length };
|
|
67
|
+
}
|
|
68
|
+
export class AndroidService {
|
|
69
|
+
store;
|
|
70
|
+
wfs;
|
|
71
|
+
workspaceId;
|
|
72
|
+
epoch;
|
|
73
|
+
backend;
|
|
74
|
+
configDir;
|
|
75
|
+
clock;
|
|
76
|
+
snapshots = new Map();
|
|
77
|
+
busy = new Set();
|
|
78
|
+
closed = false;
|
|
79
|
+
constructor(store, wfs, workspaceId, epoch, backend, configDir, clock = Date.now) {
|
|
80
|
+
this.store = store;
|
|
81
|
+
this.wfs = wfs;
|
|
82
|
+
this.workspaceId = workspaceId;
|
|
83
|
+
this.epoch = epoch;
|
|
84
|
+
this.backend = backend;
|
|
85
|
+
this.configDir = configDir;
|
|
86
|
+
this.clock = clock;
|
|
87
|
+
}
|
|
88
|
+
policy() { return readAndroidPolicy(this.store, this.workspaceId, this.epoch, this.clock()); }
|
|
89
|
+
setPolicy(input) {
|
|
90
|
+
const policy = saveAndroidPolicy(this.store, this.workspaceId, this.epoch, input, this.clock());
|
|
91
|
+
this.snapshots.clear();
|
|
92
|
+
return policy;
|
|
93
|
+
}
|
|
94
|
+
async status() {
|
|
95
|
+
const policy = this.policy();
|
|
96
|
+
return {
|
|
97
|
+
// The MCP status tool is readable with dodo:read. Exact device serials
|
|
98
|
+
// remain behind dodo:exec/android_devices and the local owner plane.
|
|
99
|
+
policy: { mode: policy.mode, persistent: policy.persistent, expiresAt: policy.expiresAt, allowedDeviceCount: policy.allowedDevices.length },
|
|
100
|
+
adbAvailable: this.backend.available(),
|
|
101
|
+
version: this.backend.available() ? await this.backend.version() : null,
|
|
102
|
+
setup: 'Install Android SDK Platform-Tools, enable USB/Wireless debugging, authorize the host on the phone, then run dodo android devices.',
|
|
103
|
+
permissionCommand: 'dodo android allow --device <serial> --mode view|control --persist --yes',
|
|
104
|
+
scope: 'dodo:exec',
|
|
105
|
+
snapshotTtlMs: SNAPSHOT_TTL,
|
|
106
|
+
note: 'ADB controls the selected device with that device user\'s privileges. DODO does not pair, connect, root, or bypass the Android authorization dialog.',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async allDevices() {
|
|
110
|
+
this.checkOpen();
|
|
111
|
+
const result = await this.backend.run(['devices', '-l'], { maxStdoutBytes: 128 * 1024 });
|
|
112
|
+
this.expectOk(result.code, 'list Android devices');
|
|
113
|
+
return parseAdbDevices(result.stdout.toString('utf8'));
|
|
114
|
+
}
|
|
115
|
+
async devices() {
|
|
116
|
+
const policy = this.authorize(undefined, false);
|
|
117
|
+
const all = await this.allDevices();
|
|
118
|
+
const devices = all.filter((d) => policy.allowedDevices.includes(d.serial));
|
|
119
|
+
return { devices, hiddenCount: all.length - devices.length };
|
|
120
|
+
}
|
|
121
|
+
async info(serialInput) {
|
|
122
|
+
const serial = this.serial(serialInput);
|
|
123
|
+
const policy = this.authorize(serial, false);
|
|
124
|
+
return this.exclusive(serial, async () => {
|
|
125
|
+
await this.assertOnline(serial);
|
|
126
|
+
const props = await this.adbText(serial, ['shell', 'getprop'], 512 * 1024);
|
|
127
|
+
const get = (name) => new RegExp(`^\\[${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\]: \\[(.*)\\]$`, 'm').exec(props)?.[1]?.slice(0, 300) ?? '';
|
|
128
|
+
const display = await this.adbText(serial, ['shell', 'wm', 'size'], 4096);
|
|
129
|
+
const battery = await this.adbText(serial, ['shell', 'dumpsys', 'battery'], 32 * 1024);
|
|
130
|
+
this.checkPolicy(policy, serial);
|
|
131
|
+
return {
|
|
132
|
+
serial,
|
|
133
|
+
manufacturer: get('ro.product.manufacturer'), model: get('ro.product.model'), device: get('ro.product.device'),
|
|
134
|
+
androidVersion: get('ro.build.version.release'), sdk: get('ro.build.version.sdk'), abi: get('ro.product.cpu.abi'),
|
|
135
|
+
display: display.trim().slice(0, 500),
|
|
136
|
+
battery: {
|
|
137
|
+
level: Number(/^\s*level:\s*(\d+)/m.exec(battery)?.[1] ?? -1),
|
|
138
|
+
status: Number(/^\s*status:\s*(\d+)/m.exec(battery)?.[1] ?? -1),
|
|
139
|
+
powered: /AC powered:\s*true|USB powered:\s*true|Wireless powered:\s*true/.test(battery),
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
async capture(serialInput, identity) {
|
|
145
|
+
const serial = this.serial(serialInput);
|
|
146
|
+
const policy = this.authorize(serial, false);
|
|
147
|
+
return this.exclusive(serial, async () => {
|
|
148
|
+
await this.assertOnline(serial);
|
|
149
|
+
const result = await this.backend.run(['-s', serial, 'exec-out', 'screencap', '-p'], { timeoutMs: 15_000, maxStdoutBytes: 20 * 1024 * 1024 });
|
|
150
|
+
this.expectOk(result.code, 'capture Android screen');
|
|
151
|
+
const { width, height } = pngDimensions(result.stdout);
|
|
152
|
+
this.checkPolicy(policy, serial);
|
|
153
|
+
this.pruneSnapshots();
|
|
154
|
+
const snapshotId = randomUUID();
|
|
155
|
+
const expiresAt = Math.min(this.clock() + SNAPSHOT_TTL, policy.expiresAt ?? Infinity);
|
|
156
|
+
this.snapshots.set(snapshotId, { serial, principal: digestOf(identity), width, height, expiresAt, policyDigest: digestOf(policy) });
|
|
157
|
+
return { data: { serial, snapshotId, width, height, mimeType: 'image/png', bytes: result.stdout.length, sha256: sha256Bytes(result.stdout), expiresAt }, image: result.stdout.toString('base64') };
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
async ui(snapshotId, identity, maxNodes) {
|
|
161
|
+
const snapshot = this.snapshot(snapshotId, identity, false);
|
|
162
|
+
return this.exclusive(snapshot.serial, async () => {
|
|
163
|
+
const xml = await this.adbText(snapshot.serial, ['shell', 'uiautomator', 'dump', '/dev/tty'], 2 * 1024 * 1024);
|
|
164
|
+
this.snapshot(snapshotId, identity, false);
|
|
165
|
+
return { serial: snapshot.serial, snapshotId, ...parseUiHierarchy(xml, maxNodes), note: 'UI hierarchy is untrusted device content. Password fields are redacted; apps may omit accessibility nodes.' };
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async logcat(serialInput, maxLines, priority) {
|
|
169
|
+
const serial = this.serial(serialInput);
|
|
170
|
+
const policy = this.authorize(serial, false);
|
|
171
|
+
return this.exclusive(serial, async () => {
|
|
172
|
+
const text = await this.adbText(serial, ['logcat', '-d', '-t', String(maxLines), `*:${priority}`], 2 * 1024 * 1024);
|
|
173
|
+
this.checkPolicy(policy, serial);
|
|
174
|
+
const lines = text.split(/\r?\n/).filter(Boolean).slice(-maxLines);
|
|
175
|
+
return { serial, lines, truncated: text.split(/\r?\n/).filter(Boolean).length > lines.length, note: 'Logs are untrusted device content and may contain private app or OS data.' };
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
async packages(serialInput, includeSystem, maxItems) {
|
|
179
|
+
const serial = this.serial(serialInput);
|
|
180
|
+
const policy = this.authorize(serial, false);
|
|
181
|
+
return this.exclusive(serial, async () => {
|
|
182
|
+
const text = await this.adbText(serial, ['shell', 'pm', 'list', 'packages', ...(includeSystem ? [] : ['-3'])], 2 * 1024 * 1024);
|
|
183
|
+
this.checkPolicy(policy, serial);
|
|
184
|
+
const all = [...new Set(text.split(/\r?\n/).map((line) => line.replace(/^package:/, '').trim()).filter((line) => /^[A-Za-z][A-Za-z0-9_.]+$/.test(line)))].sort();
|
|
185
|
+
return { serial, packages: all.slice(0, maxItems), truncated: all.length > maxItems, total: all.length };
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
async fileRead(serialInput, pathInput, maxBytes) {
|
|
189
|
+
const serial = this.serial(serialInput);
|
|
190
|
+
const policy = this.authorize(serial, false);
|
|
191
|
+
const remote = devicePath(pathInput);
|
|
192
|
+
return this.exclusive(serial, async () => {
|
|
193
|
+
const result = await this.backend.run(['-s', serial, 'exec-out', 'cat', '--', remote], { timeoutMs: 15_000, maxStdoutBytes: maxBytes });
|
|
194
|
+
this.expectOk(result.code, 'read Android device file');
|
|
195
|
+
this.checkPolicy(policy, serial);
|
|
196
|
+
const text = decodeUtf8Strict(result.stdout);
|
|
197
|
+
return { serial, path: remote, encoding: text === undefined ? 'base64' : 'utf8', data: text ?? result.stdout.toString('base64'), bytes: result.stdout.length, sha256: sha256Bytes(result.stdout) };
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
async action(serialInput, snapshotId, actionInput, identity) {
|
|
201
|
+
const serial = this.serial(serialInput);
|
|
202
|
+
const snapshot = this.snapshot(snapshotId, identity, true);
|
|
203
|
+
if (snapshot.serial !== serial)
|
|
204
|
+
throw new DodoError('INVALID_INPUT', 'snapshot belongs to another Android device');
|
|
205
|
+
const action = AndroidActionSchema.parse(actionInput);
|
|
206
|
+
const points = [];
|
|
207
|
+
if (action.kind === 'tap' || action.kind === 'long_press')
|
|
208
|
+
points.push([action.x, action.y]);
|
|
209
|
+
if (action.kind === 'swipe')
|
|
210
|
+
points.push([action.fromX, action.fromY], [action.toX, action.toY]);
|
|
211
|
+
if (points.some(([x, y]) => x >= snapshot.width || y >= snapshot.height))
|
|
212
|
+
throw new DodoError('INVALID_INPUT', 'coordinates are outside the captured Android screen');
|
|
213
|
+
this.snapshots.clear();
|
|
214
|
+
return this.exclusive(serial, async () => {
|
|
215
|
+
let args;
|
|
216
|
+
switch (action.kind) {
|
|
217
|
+
case 'tap':
|
|
218
|
+
args = ['shell', 'input', 'tap', String(action.x), String(action.y)];
|
|
219
|
+
break;
|
|
220
|
+
case 'long_press':
|
|
221
|
+
args = ['shell', 'input', 'swipe', String(action.x), String(action.y), String(action.x), String(action.y), String(action.durationMs)];
|
|
222
|
+
break;
|
|
223
|
+
case 'swipe':
|
|
224
|
+
args = ['shell', 'input', 'swipe', String(action.fromX), String(action.fromY), String(action.toX), String(action.toY), String(action.durationMs)];
|
|
225
|
+
break;
|
|
226
|
+
case 'text':
|
|
227
|
+
args = ['shell', 'input', 'text', action.text.replace(/ /g, '%s')];
|
|
228
|
+
break;
|
|
229
|
+
case 'key':
|
|
230
|
+
args = ['shell', 'input', 'keyevent', action.keyCode];
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
const result = await this.backend.run(['-s', serial, ...args], { timeoutMs: 10_000, maxStdoutBytes: 64 * 1024 });
|
|
234
|
+
this.expectOk(result.code, 'perform Android input action');
|
|
235
|
+
return { posted: true, serial, note: 'ADB input was dispatched. Capture the screen again to verify the resulting device state.' };
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
async app(serialInput, actionInput) {
|
|
239
|
+
const serial = this.serial(serialInput);
|
|
240
|
+
this.authorize(serial, true);
|
|
241
|
+
const action = AndroidAppActionSchema.parse(actionInput);
|
|
242
|
+
return this.exclusive(serial, async () => {
|
|
243
|
+
let args;
|
|
244
|
+
switch (action.kind) {
|
|
245
|
+
case 'launch':
|
|
246
|
+
args = ['shell', 'monkey', '-p', action.packageName, '-c', 'android.intent.category.LAUNCHER', '1'];
|
|
247
|
+
break;
|
|
248
|
+
case 'start_activity':
|
|
249
|
+
args = ['shell', 'am', 'start', '-n', action.component];
|
|
250
|
+
break;
|
|
251
|
+
case 'force_stop':
|
|
252
|
+
args = ['shell', 'am', 'force-stop', action.packageName];
|
|
253
|
+
break;
|
|
254
|
+
case 'clear_data':
|
|
255
|
+
args = ['shell', 'pm', 'clear', action.packageName];
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
const result = await this.backend.run(['-s', serial, ...args], { timeoutMs: 20_000, maxStdoutBytes: 256 * 1024 });
|
|
259
|
+
this.expectOk(result.code, 'perform Android app action');
|
|
260
|
+
this.snapshots.clear();
|
|
261
|
+
return { posted: true, serial, action: action.kind, note: 'ADB app action was dispatched; inspect the device before depending on the result.' };
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async install(serialInput, apkPath, expectedHash, opts) {
|
|
265
|
+
const serial = this.serial(serialInput);
|
|
266
|
+
this.authorize(serial, true);
|
|
267
|
+
const rel = this.wfs.normalizeRel(apkPath);
|
|
268
|
+
if (!rel.toLowerCase().endsWith('.apk'))
|
|
269
|
+
throw new DodoError('INVALID_INPUT', 'android_install requires a workspace .apk file');
|
|
270
|
+
return this.exclusive(serial, async () => {
|
|
271
|
+
const staged = await this.stageWorkspaceFile(rel, expectedHash);
|
|
272
|
+
try {
|
|
273
|
+
// Staging a large APK can take long enough for the owner to revoke the
|
|
274
|
+
// device grant. Re-check immediately before the first device effect.
|
|
275
|
+
this.authorize(serial, true);
|
|
276
|
+
const flags = [...(opts.replace ? ['-r'] : []), ...(opts.downgrade ? ['-d'] : []), ...(opts.grantRuntimePermissions ? ['-g'] : [])];
|
|
277
|
+
const result = await this.backend.run(['-s', serial, 'install', ...flags, staged.path], { timeoutMs: 5 * 60_000, maxStdoutBytes: 256 * 1024 });
|
|
278
|
+
this.expectOk(result.code, 'install APK');
|
|
279
|
+
return { posted: true, serial, path: rel, bytes: staged.bytes, sha256: staged.sha256, note: 'ADB reported the install command completed from a hash-verified private staging copy; verify package state before assuming app behavior.' };
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
removeWithRetry(staged.path);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
async push(serialInput, sourcePath, expectedHash, destinationInput) {
|
|
287
|
+
const serial = this.serial(serialInput);
|
|
288
|
+
this.authorize(serial, true);
|
|
289
|
+
const destination = devicePath(destinationInput);
|
|
290
|
+
const rel = this.wfs.normalizeRel(sourcePath);
|
|
291
|
+
return this.exclusive(serial, async () => {
|
|
292
|
+
const staged = await this.stageWorkspaceFile(rel, expectedHash);
|
|
293
|
+
try {
|
|
294
|
+
this.authorize(serial, true);
|
|
295
|
+
const result = await this.backend.run(['-s', serial, 'push', staged.path, destination], { timeoutMs: 5 * 60_000, maxStdoutBytes: 256 * 1024 });
|
|
296
|
+
this.expectOk(result.code, 'push file to Android device');
|
|
297
|
+
return { posted: true, serial, source: rel, destination, bytes: staged.bytes, sha256: staged.sha256, note: 'Hash-verified workspace bytes were sent to the device path through ADB.' };
|
|
298
|
+
}
|
|
299
|
+
finally {
|
|
300
|
+
removeWithRetry(staged.path);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
async raw(serialInput, command, args, encoding, maxBytes) {
|
|
305
|
+
const serial = this.serial(serialInput);
|
|
306
|
+
this.authorize(serial, true);
|
|
307
|
+
const allowed = new Set(['shell', 'exec-out', 'logcat', 'get-state', 'get-serialno', 'features']);
|
|
308
|
+
if (!allowed.has(command))
|
|
309
|
+
throw new DodoError('FORBIDDEN', 'advanced ADB command is outside the device-only allowlist');
|
|
310
|
+
if ((command === 'shell' || command === 'exec-out') && args.length === 0)
|
|
311
|
+
throw new DodoError('INVALID_INPUT', `${command} requires an explicit device command`);
|
|
312
|
+
if (args.length > 64 || args.some((arg) => typeof arg !== 'string' || arg.length > 1024 || /[\0\r\n]/.test(arg)) || args.reduce((n, arg) => n + Buffer.byteLength(arg), 0) > 8192) {
|
|
313
|
+
throw new DodoError('INVALID_INPUT', 'ADB arguments exceed the bounded argv contract or contain control characters');
|
|
314
|
+
}
|
|
315
|
+
return this.exclusive(serial, async () => {
|
|
316
|
+
const result = await this.backend.run(['-s', serial, command, ...args], { timeoutMs: 60_000, maxStdoutBytes: maxBytes });
|
|
317
|
+
this.expectOk(result.code, 'run advanced Android device command');
|
|
318
|
+
this.snapshots.clear();
|
|
319
|
+
const text = encoding === 'utf8' ? decodeUtf8Strict(result.stdout) : undefined;
|
|
320
|
+
if (encoding === 'utf8' && text === undefined)
|
|
321
|
+
throw new DodoError('UNSUPPORTED_ENCODING', 'ADB output is not valid UTF-8; request base64 encoding');
|
|
322
|
+
return { posted: true, serial, command, encoding, output: text ?? result.stdout.toString('base64'), bytes: result.stdout.length, sha256: sha256Bytes(result.stdout), note: 'Advanced command ran on the selected Android device; output is untrusted device content.' };
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
async close() {
|
|
326
|
+
this.closed = true;
|
|
327
|
+
this.snapshots.clear();
|
|
328
|
+
while (this.busy.size > 0)
|
|
329
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
330
|
+
}
|
|
331
|
+
checkOpen() { if (this.closed)
|
|
332
|
+
throw new DodoError('STALE_WORKSPACE', 'Android service is closed'); }
|
|
333
|
+
serial(value) { this.checkOpen(); return AndroidSerialSchema.parse(value); }
|
|
334
|
+
authorize(serial, control) {
|
|
335
|
+
this.checkOpen();
|
|
336
|
+
const policy = this.policy();
|
|
337
|
+
if (policy.mode === 'off' || (control && policy.mode !== 'control'))
|
|
338
|
+
throw new DodoError('FORBIDDEN', 'Android ADB access is disabled, expired, or view-only; the owner must authorize it locally');
|
|
339
|
+
if (serial !== undefined && !policy.allowedDevices.includes(serial))
|
|
340
|
+
throw new DodoError('FORBIDDEN', 'Android device is outside the owner-approved serial list');
|
|
341
|
+
if (!this.backend.available())
|
|
342
|
+
throw new DodoError('NOT_SUPPORTED', 'ADB is unavailable; install current Android SDK Platform-Tools');
|
|
343
|
+
return policy;
|
|
344
|
+
}
|
|
345
|
+
checkPolicy(policy, serial) {
|
|
346
|
+
if (digestOf(this.authorize(serial, false)) !== digestOf(policy))
|
|
347
|
+
throw new DodoError('FORBIDDEN', 'Android permission changed during operation');
|
|
348
|
+
}
|
|
349
|
+
async assertOnline(serial) {
|
|
350
|
+
const result = await this.backend.run(['-s', serial, 'get-state'], { timeoutMs: 5000, maxStdoutBytes: 4096 });
|
|
351
|
+
if (result.code !== 0 || result.stdout.toString('utf8').trim() !== 'device')
|
|
352
|
+
throw new DodoError('NOT_SUPPORTED', 'Android device is unavailable, offline, or has not authorized this ADB host');
|
|
353
|
+
}
|
|
354
|
+
async adbText(serial, args, cap) {
|
|
355
|
+
await this.assertOnline(serial);
|
|
356
|
+
const result = await this.backend.run(['-s', serial, ...args], { maxStdoutBytes: cap });
|
|
357
|
+
this.expectOk(result.code, 'read Android device data');
|
|
358
|
+
const text = decodeUtf8Strict(result.stdout);
|
|
359
|
+
if (text === undefined)
|
|
360
|
+
throw new DodoError('UNSUPPORTED_ENCODING', 'Android command returned non-UTF-8 data');
|
|
361
|
+
return text;
|
|
362
|
+
}
|
|
363
|
+
expectOk(code, operation) {
|
|
364
|
+
if (code !== 0)
|
|
365
|
+
throw new DodoError('NOT_SUPPORTED', `ADB could not ${operation}; verify the selected device is online and authorized`);
|
|
366
|
+
}
|
|
367
|
+
pruneSnapshots() {
|
|
368
|
+
for (const [id, snapshot] of this.snapshots)
|
|
369
|
+
if (snapshot.expiresAt <= this.clock())
|
|
370
|
+
this.snapshots.delete(id);
|
|
371
|
+
while (this.snapshots.size >= 32)
|
|
372
|
+
this.snapshots.delete(this.snapshots.keys().next().value);
|
|
373
|
+
}
|
|
374
|
+
snapshot(id, identity, control) {
|
|
375
|
+
const policy = this.authorize(undefined, control);
|
|
376
|
+
const snapshot = this.snapshots.get(id);
|
|
377
|
+
if (!snapshot || snapshot.principal !== digestOf(identity) || snapshot.expiresAt <= this.clock() || snapshot.policyDigest !== digestOf(policy) || !policy.allowedDevices.includes(snapshot.serial)) {
|
|
378
|
+
throw new DodoError('STALE_WORKSPACE', 'capture a fresh Android screen for this client; snapshot is stale, revoked, or belongs to another caller');
|
|
379
|
+
}
|
|
380
|
+
return snapshot;
|
|
381
|
+
}
|
|
382
|
+
async exclusive(serial, fn) {
|
|
383
|
+
if (PROCESS_DEVICE_BUSY.has(serial))
|
|
384
|
+
throw new DodoError('RESOURCE_LIMIT', 'another Android operation is active for this device; operations are serialized per serial across project runtimes');
|
|
385
|
+
PROCESS_DEVICE_BUSY.add(serial);
|
|
386
|
+
this.busy.add(serial);
|
|
387
|
+
try {
|
|
388
|
+
return await fn();
|
|
389
|
+
}
|
|
390
|
+
finally {
|
|
391
|
+
this.busy.delete(serial);
|
|
392
|
+
PROCESS_DEVICE_BUSY.delete(serial);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
async stageWorkspaceFile(input, expectedHash) {
|
|
396
|
+
const resolved = this.wfs.resolve(input);
|
|
397
|
+
const before = this.wfs.assertRegularFileForDirectAccess(resolved);
|
|
398
|
+
if (before.size > 512 * 1024 * 1024)
|
|
399
|
+
throw new DodoError('FILE_TOO_LARGE', 'Android transfer source exceeds 512 MiB');
|
|
400
|
+
const directory = path.join(this.configDir, 'android-staging');
|
|
401
|
+
ensurePrivateDirectory(directory);
|
|
402
|
+
const target = path.join(directory, `${randomUUID()}.bin`);
|
|
403
|
+
const source = await fs.promises.open(resolved.abs, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
404
|
+
let output;
|
|
405
|
+
try {
|
|
406
|
+
const opened = await source.stat();
|
|
407
|
+
if (!opened.isFile() || opened.nlink !== 1 || opened.dev !== before.dev || opened.ino !== before.ino || opened.size !== before.size)
|
|
408
|
+
throw new DodoError('FILE_CHANGED', 'workspace transfer source changed while opening');
|
|
409
|
+
output = await fs.promises.open(target, 'wx', 0o600);
|
|
410
|
+
const hash = createHash('sha256'), buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
411
|
+
let offset = 0;
|
|
412
|
+
while (offset < opened.size) {
|
|
413
|
+
const chunk = await source.read(buffer, 0, Math.min(buffer.length, opened.size - offset), offset);
|
|
414
|
+
if (chunk.bytesRead <= 0)
|
|
415
|
+
throw new DodoError('FILE_CHANGED', 'workspace transfer source ended during staging');
|
|
416
|
+
hash.update(buffer.subarray(0, chunk.bytesRead));
|
|
417
|
+
await output.write(buffer, 0, chunk.bytesRead, offset);
|
|
418
|
+
offset += chunk.bytesRead;
|
|
419
|
+
}
|
|
420
|
+
await output.sync();
|
|
421
|
+
await output.close();
|
|
422
|
+
output = undefined;
|
|
423
|
+
const afterOpen = await source.stat();
|
|
424
|
+
const afterPath = this.wfs.assertRegularFileForDirectAccess(this.wfs.resolve(input));
|
|
425
|
+
if (afterOpen.dev !== opened.dev || afterOpen.ino !== opened.ino || afterOpen.size !== opened.size || afterPath.dev !== opened.dev || afterPath.ino !== opened.ino || afterPath.size !== opened.size)
|
|
426
|
+
throw new DodoError('FILE_CHANGED', 'workspace transfer source changed during staging');
|
|
427
|
+
const sha256 = `sha256:${hash.digest('hex')}`;
|
|
428
|
+
if (sha256 !== expectedHash)
|
|
429
|
+
throw new DodoError('FILE_CHANGED', 'workspace transfer source does not match expectedHash', { detail: { path: resolved.rel, expectedHash, actualHash: sha256 } });
|
|
430
|
+
return { path: target, bytes: opened.size, sha256 };
|
|
431
|
+
}
|
|
432
|
+
catch (error) {
|
|
433
|
+
if (fs.existsSync(target))
|
|
434
|
+
removeWithRetry(target);
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
finally {
|
|
438
|
+
await output?.close().catch(() => undefined);
|
|
439
|
+
await source.close().catch(() => undefined);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
export const __androidTest = { devicePath, pngDimensions };
|
|
444
|
+
//# sourceMappingURL=androidService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"androidService.js","sourceRoot":"","sources":["../../../src/services/android/androidService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const AndroidModeSchema = z.enum(['off', 'view', 'control']);
|
|
3
|
+
export const AndroidSerialSchema = z.string()
|
|
4
|
+
.min(1)
|
|
5
|
+
.max(200)
|
|
6
|
+
.regex(/^(?!-)[!-~]+$/, 'ADB serial must be printable ASCII without whitespace and cannot start with dash');
|
|
7
|
+
export const AndroidPolicySchema = z.object({
|
|
8
|
+
mode: AndroidModeSchema,
|
|
9
|
+
allowedDevices: z.array(AndroidSerialSchema).max(20),
|
|
10
|
+
epoch: z.string(),
|
|
11
|
+
expiresAt: z.number().int().nonnegative().nullable(),
|
|
12
|
+
persistent: z.boolean().default(false),
|
|
13
|
+
revision: z.string().uuid().optional(),
|
|
14
|
+
}).strict()
|
|
15
|
+
.refine((p) => p.persistent === (p.expiresAt === null), 'only persistent grants have no expiry')
|
|
16
|
+
.refine((p) => p.mode === 'off' ? !p.persistent : p.allowedDevices.length > 0, 'enabled grants require exact devices');
|
|
17
|
+
export const AndroidDeviceSchema = z.object({
|
|
18
|
+
serial: AndroidSerialSchema,
|
|
19
|
+
state: z.enum(['device', 'offline', 'unauthorized', 'recovery', 'sideload', 'bootloader', 'unknown']),
|
|
20
|
+
product: z.string().max(200).optional(),
|
|
21
|
+
model: z.string().max(200).optional(),
|
|
22
|
+
device: z.string().max(200).optional(),
|
|
23
|
+
transportId: z.string().max(40).optional(),
|
|
24
|
+
}).strict();
|
|
25
|
+
const Coord = z.number().int().min(0).max(20_000);
|
|
26
|
+
export const AndroidActionSchema = z.discriminatedUnion('kind', [
|
|
27
|
+
z.object({ kind: z.literal('tap'), x: Coord, y: Coord }).strict(),
|
|
28
|
+
z.object({ kind: z.literal('long_press'), x: Coord, y: Coord, durationMs: z.number().int().min(300).max(5000).default(800) }).strict(),
|
|
29
|
+
z.object({ kind: z.literal('swipe'), fromX: Coord, fromY: Coord, toX: Coord, toY: Coord, durationMs: z.number().int().min(100).max(5000).default(300) }).strict(),
|
|
30
|
+
z.object({ kind: z.literal('text'), text: z.string().min(1).max(1000) }).strict(),
|
|
31
|
+
z.object({ kind: z.literal('key'), keyCode: z.string().regex(/^(?:KEYCODE_[A-Z0-9_]{1,60}|[0-9]{1,3})$/) }).strict(),
|
|
32
|
+
]);
|
|
33
|
+
export const AndroidAppActionSchema = z.discriminatedUnion('kind', [
|
|
34
|
+
z.object({ kind: z.literal('launch'), packageName: z.string().regex(/^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)+$/).max(220) }).strict(),
|
|
35
|
+
z.object({ kind: z.literal('start_activity'), component: z.string().regex(/^[A-Za-z][A-Za-z0-9_.]*\/[A-Za-z0-9_.$]+$/).max(440) }).strict(),
|
|
36
|
+
z.object({ kind: z.literal('force_stop'), packageName: z.string().regex(/^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)+$/).max(220) }).strict(),
|
|
37
|
+
z.object({ kind: z.literal('clear_data'), packageName: z.string().regex(/^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)+$/).max(220) }).strict(),
|
|
38
|
+
]);
|
|
39
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/services/android/protocol.ts"],"names":[],"mappings":"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"}
|