@beeos-ai/device-agent 0.4.2 → 0.5.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/.pi/extensions/android-tools.ts +146 -15
- package/LICENSE +201 -0
- package/dist/adapters/agent-gateway-client.d.ts +37 -0
- package/dist/adapters/agent-gateway-client.js +45 -0
- package/dist/adapters/agent-gateway-client.js.map +1 -1
- package/dist/adapters/agentcore-pi.d.ts +22 -0
- package/dist/adapters/agentcore-pi.js +48 -0
- package/dist/adapters/agentcore-pi.js.map +1 -1
- package/dist/adapters/device-android-adb.d.ts +47 -0
- package/dist/adapters/device-android-adb.js +50 -0
- package/dist/adapters/device-android-adb.js.map +1 -1
- package/dist/adapters/device-desktop.d.ts +12 -0
- package/dist/adapters/device-desktop.js +31 -0
- package/dist/adapters/device-desktop.js.map +1 -1
- package/dist/agent-runtime/adapters/base.d.ts +20 -0
- package/dist/agent-runtime/adapters/base.js.map +1 -1
- package/dist/agent-runtime/agent-runner.d.ts +4 -2
- package/dist/agent-runtime/agent-runner.js.map +1 -1
- package/dist/agent-runtime/core.d.ts +60 -0
- package/dist/agent-runtime/core.js +190 -9
- package/dist/agent-runtime/core.js.map +1 -1
- package/dist/agent-runtime/feedback.d.ts +56 -0
- package/dist/agent-runtime/feedback.js +54 -0
- package/dist/agent-runtime/feedback.js.map +1 -0
- package/dist/agent-runtime/index.d.ts +1 -0
- package/dist/agent-runtime/index.js +1 -0
- package/dist/agent-runtime/index.js.map +1 -1
- package/dist/agent-runtime/plan-executor.js +24 -0
- package/dist/agent-runtime/plan-executor.js.map +1 -1
- package/dist/agent-runtime/planner/base.d.ts +10 -0
- package/dist/agent-runtime/planner/base.js.map +1 -1
- package/dist/agent-runtime/planner/llm-planner.js +1 -0
- package/dist/agent-runtime/planner/llm-planner.js.map +1 -1
- package/dist/agent-runtime/planner/prompts.d.ts +3 -0
- package/dist/agent-runtime/planner/prompts.js +12 -0
- package/dist/agent-runtime/planner/prompts.js.map +1 -1
- package/dist/agent-runtime/reflection.d.ts +25 -6
- package/dist/agent-runtime/reflection.js +64 -22
- package/dist/agent-runtime/reflection.js.map +1 -1
- package/dist/agent-runtime/reflectors/policy.d.ts +10 -4
- package/dist/agent-runtime/reflectors/policy.js +19 -6
- package/dist/agent-runtime/reflectors/policy.js.map +1 -1
- package/dist/agent-runtime/shortcuts/fs-store.d.ts +41 -0
- package/dist/agent-runtime/shortcuts/fs-store.js +122 -0
- package/dist/agent-runtime/shortcuts/fs-store.js.map +1 -0
- package/dist/agent-runtime/shortcuts/in-memory-store.d.ts +20 -0
- package/dist/agent-runtime/shortcuts/in-memory-store.js +64 -0
- package/dist/agent-runtime/shortcuts/in-memory-store.js.map +1 -0
- package/dist/agent-runtime/shortcuts/index.d.ts +10 -0
- package/dist/agent-runtime/shortcuts/index.js +10 -0
- package/dist/agent-runtime/shortcuts/index.js.map +1 -0
- package/dist/agent-runtime/shortcuts/types.d.ts +69 -0
- package/dist/agent-runtime/shortcuts/types.js +17 -0
- package/dist/agent-runtime/shortcuts/types.js.map +1 -0
- package/dist/app/agent-host.d.ts +83 -0
- package/dist/app/agent-host.js +345 -32
- package/dist/app/agent-host.js.map +1 -1
- package/dist/app/session-manager.d.ts +33 -4
- package/dist/app/session-manager.js +27 -5
- package/dist/app/session-manager.js.map +1 -1
- package/dist/bootstrap.js +187 -3
- package/dist/bootstrap.js.map +1 -1
- package/dist/config/loader.js +22 -0
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.js +118 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/inbound/acp/handlers/session.js.map +1 -1
- package/dist/mcp-client/client.d.ts +6 -0
- package/dist/mcp-client/client.js +11 -0
- package/dist/mcp-client/client.js.map +1 -1
- package/dist/mcp-client/runtime.d.ts +13 -0
- package/dist/orchestrator-system-prompt.d.ts +26 -0
- package/dist/orchestrator-system-prompt.js +118 -2
- package/dist/orchestrator-system-prompt.js.map +1 -1
- package/dist/pi-context.d.ts +50 -0
- package/dist/pi-context.js.map +1 -1
- package/dist/ports/device.d.ts +18 -0
- package/dist/resources/augmenter.d.ts +48 -0
- package/dist/resources/augmenter.js +126 -0
- package/dist/resources/augmenter.js.map +1 -0
- package/dist/resources/cache.d.ts +57 -0
- package/dist/resources/cache.js +107 -0
- package/dist/resources/cache.js.map +1 -0
- package/dist/resources/index.d.ts +17 -0
- package/dist/resources/index.js +15 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/lifecycle/disk-pressure.d.ts +75 -0
- package/dist/resources/lifecycle/disk-pressure.js +148 -0
- package/dist/resources/lifecycle/disk-pressure.js.map +1 -0
- package/dist/resources/lifecycle/index.d.ts +7 -0
- package/dist/resources/lifecycle/index.js +7 -0
- package/dist/resources/lifecycle/index.js.map +1 -0
- package/dist/resources/lifecycle/manager.d.ts +38 -0
- package/dist/resources/lifecycle/manager.js +205 -0
- package/dist/resources/lifecycle/manager.js.map +1 -0
- package/dist/resources/lifecycle/sweeper.d.ts +36 -0
- package/dist/resources/lifecycle/sweeper.js +179 -0
- package/dist/resources/lifecycle/sweeper.js.map +1 -0
- package/dist/resources/lifecycle/types.d.ts +180 -0
- package/dist/resources/lifecycle/types.js +46 -0
- package/dist/resources/lifecycle/types.js.map +1 -0
- package/dist/resources/parsers.d.ts +28 -0
- package/dist/resources/parsers.js +88 -0
- package/dist/resources/parsers.js.map +1 -0
- package/dist/resources/registry.d.ts +47 -0
- package/dist/resources/registry.js +107 -0
- package/dist/resources/registry.js.map +1 -0
- package/dist/resources/resolvers/beeos-file-resolver.d.ts +62 -0
- package/dist/resources/resolvers/beeos-file-resolver.js +109 -0
- package/dist/resources/resolvers/beeos-file-resolver.js.map +1 -0
- package/dist/resources/resolvers/errors.d.ts +11 -0
- package/dist/resources/resolvers/errors.js +23 -0
- package/dist/resources/resolvers/errors.js.map +1 -0
- package/dist/resources/resolvers/mime-table.d.ts +41 -0
- package/dist/resources/resolvers/mime-table.js +92 -0
- package/dist/resources/resolvers/mime-table.js.map +1 -0
- package/dist/resources/resolvers/url-resolver.d.ts +85 -0
- package/dist/resources/resolvers/url-resolver.js +495 -0
- package/dist/resources/resolvers/url-resolver.js.map +1 -0
- package/dist/resources/shortcut-facade.d.ts +51 -0
- package/dist/resources/shortcut-facade.js +72 -0
- package/dist/resources/shortcut-facade.js.map +1 -0
- package/dist/resources/telemetry.d.ts +52 -0
- package/dist/resources/telemetry.js +59 -0
- package/dist/resources/telemetry.js.map +1 -0
- package/dist/resources/types.d.ts +249 -0
- package/dist/resources/types.js +29 -0
- package/dist/resources/types.js.map +1 -0
- package/dist/shortcuts/builtins/download-to-device.d.ts +83 -0
- package/dist/shortcuts/builtins/download-to-device.js +125 -0
- package/dist/shortcuts/builtins/download-to-device.js.map +1 -0
- package/dist/shortcuts/builtins/find-app-package.d.ts +79 -0
- package/dist/shortcuts/builtins/find-app-package.js +168 -0
- package/dist/shortcuts/builtins/find-app-package.js.map +1 -0
- package/dist/shortcuts/builtins/index.d.ts +32 -0
- package/dist/shortcuts/builtins/index.js +37 -0
- package/dist/shortcuts/builtins/index.js.map +1 -0
- package/dist/shortcuts/builtins/open-deeplink.d.ts +68 -0
- package/dist/shortcuts/builtins/open-deeplink.js +142 -0
- package/dist/shortcuts/builtins/open-deeplink.js.map +1 -0
- package/dist/shortcuts/builtins/set-clipboard.d.ts +65 -0
- package/dist/shortcuts/builtins/set-clipboard.js +112 -0
- package/dist/shortcuts/builtins/set-clipboard.js.map +1 -0
- package/dist/shortcuts/index.d.ts +11 -0
- package/dist/shortcuts/index.js +11 -0
- package/dist/shortcuts/index.js.map +1 -0
- package/dist/shortcuts/registry.d.ts +56 -0
- package/dist/shortcuts/registry.js +70 -0
- package/dist/shortcuts/registry.js.map +1 -0
- package/dist/shortcuts/router.d.ts +91 -0
- package/dist/shortcuts/router.js +158 -0
- package/dist/shortcuts/router.js.map +1 -0
- package/dist/shortcuts/types.d.ts +219 -0
- package/dist/shortcuts/types.js +46 -0
- package/dist/shortcuts/types.js.map +1 -0
- package/package.json +24 -25
- package/dist/agent-runtime/skills/sqlite-store.d.ts +0 -60
- package/dist/agent-runtime/skills/sqlite-store.js +0 -234
- package/dist/agent-runtime/skills/sqlite-store.js.map +0 -1
- package/dist/test-lan-autoglm.d.ts +0 -7
- package/dist/test-lan-autoglm.js +0 -46
- package/dist/test-lan-autoglm.js.map +0 -1
- package/dist/test-mem-breakdown.d.ts +0 -1
- package/dist/test-mem-breakdown.js +0 -103
- package/dist/test-mem-breakdown.js.map +0 -1
- package/dist/test-mem.d.ts +0 -1
- package/dist/test-mem.js +0 -60
- package/dist/test-mem.js.map +0 -1
- package/dist/test-mobile-use.d.ts +0 -1
- package/dist/test-mobile-use.js +0 -18
- package/dist/test-mobile-use.js.map +0 -1
- package/dist/test-screenshot-loop.d.ts +0 -1
- package/dist/test-screenshot-loop.js +0 -43
- package/dist/test-screenshot-loop.js.map +0 -1
- package/dist/test-screenshot.d.ts +0 -1
- package/dist/test-screenshot.js +0 -10
- package/dist/test-screenshot.js.map +0 -1
- package/dist/test-ui-xml-dump.d.ts +0 -15
- package/dist/test-ui-xml-dump.js +0 -49
- package/dist/test-ui-xml-dump.js.map +0 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shortcut: `find_app_package`
|
|
3
|
+
*
|
|
4
|
+
* Look up Android package names by fuzzy-matching against the output
|
|
5
|
+
* of `pm list packages`.
|
|
6
|
+
*
|
|
7
|
+
* Why a shortcut:
|
|
8
|
+
*
|
|
9
|
+
* The orchestrator often needs the package name to (a) generate a
|
|
10
|
+
* deep link with the package as host, (b) issue `monkey -p <pkg> 1`
|
|
11
|
+
* to launch an app cold, or (c) reason about which app currently
|
|
12
|
+
* owns the foreground. Discovering it from the GUI VLM alone is
|
|
13
|
+
* wasteful — the package name is one ADB call away.
|
|
14
|
+
*
|
|
15
|
+
* Matching strategy:
|
|
16
|
+
*
|
|
17
|
+
* - Lowercase compare on every package line returned by
|
|
18
|
+
* `pm list packages` (one entry per line, prefixed `package:`).
|
|
19
|
+
* - Substring match against the user-supplied `query` (lowercased).
|
|
20
|
+
* - Returns up to `limit` matches (default 10), preserving original
|
|
21
|
+
* order (`pm` returns alphabetical order on most ROMs, which is
|
|
22
|
+
* stable enough for the LLM).
|
|
23
|
+
*
|
|
24
|
+
* Why fuzzy and not exact:
|
|
25
|
+
*
|
|
26
|
+
* - The LLM rarely knows the exact reverse-domain package; it
|
|
27
|
+
* knows fragments like "wechat" / "amap" / "bilibili". Substring
|
|
28
|
+
* match is the cheapest heuristic that still works.
|
|
29
|
+
* - We do NOT depend on `dumpsys` or `cmd package` — `pm list` is
|
|
30
|
+
* supported on Android 5+ without root.
|
|
31
|
+
*
|
|
32
|
+
* Failure modes:
|
|
33
|
+
*
|
|
34
|
+
* - No matches → `app_not_found`.
|
|
35
|
+
* - `pm list` exit != 0 → `intent_rejected` (mirrors the rest of
|
|
36
|
+
* the shortcut contract; the orchestrator can interpret it
|
|
37
|
+
* uniformly).
|
|
38
|
+
*
|
|
39
|
+
* Platform: Android only.
|
|
40
|
+
*/
|
|
41
|
+
import type { Shortcut, ShortcutContext, ShortcutResult } from "../types.js";
|
|
42
|
+
interface FindAppPackageArgs {
|
|
43
|
+
query: string;
|
|
44
|
+
limit?: number;
|
|
45
|
+
}
|
|
46
|
+
interface FindAppPackageOutput {
|
|
47
|
+
matches: string[];
|
|
48
|
+
/** Total number of installed packages observed (for telemetry). */
|
|
49
|
+
totalSeen: number;
|
|
50
|
+
}
|
|
51
|
+
export declare class FindAppPackageShortcut implements Shortcut<FindAppPackageArgs, FindAppPackageOutput> {
|
|
52
|
+
readonly descriptor: {
|
|
53
|
+
id: string;
|
|
54
|
+
displayName: string;
|
|
55
|
+
description: string;
|
|
56
|
+
jsonSchema: {
|
|
57
|
+
type: string;
|
|
58
|
+
properties: {
|
|
59
|
+
query: {
|
|
60
|
+
type: string;
|
|
61
|
+
description: string;
|
|
62
|
+
};
|
|
63
|
+
limit: {
|
|
64
|
+
type: string;
|
|
65
|
+
minimum: number;
|
|
66
|
+
maximum: number;
|
|
67
|
+
description: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
required: string[];
|
|
71
|
+
additionalProperties: boolean;
|
|
72
|
+
};
|
|
73
|
+
kind: "api";
|
|
74
|
+
platforms: readonly ["android"];
|
|
75
|
+
timeoutMs: number;
|
|
76
|
+
};
|
|
77
|
+
execute(args: FindAppPackageArgs, ctx: ShortcutContext): Promise<ShortcutResult<FindAppPackageOutput>>;
|
|
78
|
+
}
|
|
79
|
+
export {};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shortcut: `find_app_package`
|
|
3
|
+
*
|
|
4
|
+
* Look up Android package names by fuzzy-matching against the output
|
|
5
|
+
* of `pm list packages`.
|
|
6
|
+
*
|
|
7
|
+
* Why a shortcut:
|
|
8
|
+
*
|
|
9
|
+
* The orchestrator often needs the package name to (a) generate a
|
|
10
|
+
* deep link with the package as host, (b) issue `monkey -p <pkg> 1`
|
|
11
|
+
* to launch an app cold, or (c) reason about which app currently
|
|
12
|
+
* owns the foreground. Discovering it from the GUI VLM alone is
|
|
13
|
+
* wasteful — the package name is one ADB call away.
|
|
14
|
+
*
|
|
15
|
+
* Matching strategy:
|
|
16
|
+
*
|
|
17
|
+
* - Lowercase compare on every package line returned by
|
|
18
|
+
* `pm list packages` (one entry per line, prefixed `package:`).
|
|
19
|
+
* - Substring match against the user-supplied `query` (lowercased).
|
|
20
|
+
* - Returns up to `limit` matches (default 10), preserving original
|
|
21
|
+
* order (`pm` returns alphabetical order on most ROMs, which is
|
|
22
|
+
* stable enough for the LLM).
|
|
23
|
+
*
|
|
24
|
+
* Why fuzzy and not exact:
|
|
25
|
+
*
|
|
26
|
+
* - The LLM rarely knows the exact reverse-domain package; it
|
|
27
|
+
* knows fragments like "wechat" / "amap" / "bilibili". Substring
|
|
28
|
+
* match is the cheapest heuristic that still works.
|
|
29
|
+
* - We do NOT depend on `dumpsys` or `cmd package` — `pm list` is
|
|
30
|
+
* supported on Android 5+ without root.
|
|
31
|
+
*
|
|
32
|
+
* Failure modes:
|
|
33
|
+
*
|
|
34
|
+
* - No matches → `app_not_found`.
|
|
35
|
+
* - `pm list` exit != 0 → `intent_rejected` (mirrors the rest of
|
|
36
|
+
* the shortcut contract; the orchestrator can interpret it
|
|
37
|
+
* uniformly).
|
|
38
|
+
*
|
|
39
|
+
* Platform: Android only.
|
|
40
|
+
*/
|
|
41
|
+
const DEFAULT_LIMIT = 10;
|
|
42
|
+
const MAX_LIMIT = 50;
|
|
43
|
+
export class FindAppPackageShortcut {
|
|
44
|
+
descriptor = {
|
|
45
|
+
id: "find_app_package",
|
|
46
|
+
displayName: "Find App Package",
|
|
47
|
+
description: "Look up Android package names that contain `query` as a substring. " +
|
|
48
|
+
"Useful when you know the app by display name / English fragment but " +
|
|
49
|
+
"need the reverse-domain identifier (`com.tencent.mm`, `com.autonavi.minimap`, " +
|
|
50
|
+
"etc.) to generate a deep link or launch the app via `monkey -p`. " +
|
|
51
|
+
"Substring match is case-insensitive; results are returned in the order " +
|
|
52
|
+
"`pm list packages` emits them.",
|
|
53
|
+
jsonSchema: {
|
|
54
|
+
type: "object",
|
|
55
|
+
properties: {
|
|
56
|
+
query: {
|
|
57
|
+
type: "string",
|
|
58
|
+
description: "Substring fragment to match against package names. Case-insensitive.",
|
|
59
|
+
},
|
|
60
|
+
limit: {
|
|
61
|
+
type: "integer",
|
|
62
|
+
minimum: 1,
|
|
63
|
+
maximum: MAX_LIMIT,
|
|
64
|
+
description: `Maximum number of matches to return (default ${DEFAULT_LIMIT}).`,
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
required: ["query"],
|
|
68
|
+
additionalProperties: false,
|
|
69
|
+
},
|
|
70
|
+
kind: "api",
|
|
71
|
+
platforms: ["android"],
|
|
72
|
+
timeoutMs: 10_000,
|
|
73
|
+
};
|
|
74
|
+
async execute(args, ctx) {
|
|
75
|
+
if (typeof args?.query !== "string" || args.query.length === 0) {
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
code: "invalid_args",
|
|
79
|
+
message: "query must be a non-empty string",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const limitRaw = args.limit ?? DEFAULT_LIMIT;
|
|
83
|
+
if (!Number.isInteger(limitRaw) || limitRaw < 1 || limitRaw > MAX_LIMIT) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
code: "invalid_args",
|
|
87
|
+
message: `limit must be an integer in [1, ${MAX_LIMIT}]`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
if (!ctx.mcp || typeof ctx.mcp.executeCommand !== "function") {
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
code: "permission_denied",
|
|
94
|
+
message: "active MCP runtime cannot execute shell commands",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
let res;
|
|
98
|
+
try {
|
|
99
|
+
res = await ctx.mcp.executeCommand("pm list packages", { timeoutS: 8 });
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
return { ok: false, code: "internal_error", message: e.message };
|
|
103
|
+
}
|
|
104
|
+
if (res.exitCode !== 0) {
|
|
105
|
+
return {
|
|
106
|
+
ok: false,
|
|
107
|
+
code: "intent_rejected",
|
|
108
|
+
message: `pm list exit=${res.exitCode}: ${(res.stderr || res.stdout).trim()}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const all = parsePackageList(res.stdout);
|
|
112
|
+
const needle = args.query.toLowerCase();
|
|
113
|
+
const matches = [];
|
|
114
|
+
for (const pkg of all) {
|
|
115
|
+
if (pkg.toLowerCase().includes(needle)) {
|
|
116
|
+
matches.push(pkg);
|
|
117
|
+
if (matches.length >= limitRaw)
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (matches.length === 0) {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
code: "app_not_found",
|
|
125
|
+
message: `no installed package contains "${args.query}" (scanned ${all.length})`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return { ok: true, output: { matches, totalSeen: all.length } };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Parse `pm list packages` output. Each line looks like:
|
|
133
|
+
*
|
|
134
|
+
* package:com.android.systemui
|
|
135
|
+
* package:com.tencent.mm
|
|
136
|
+
* package:com.example.app:1.2.3 (rare but legal — version suffix)
|
|
137
|
+
*
|
|
138
|
+
* We strip the `package:` prefix and any trailing `:<version>` / `=<path>`
|
|
139
|
+
* decorations (`pm list packages -f` adds the path; we never pass `-f`
|
|
140
|
+
* but we tolerate the shape just in case).
|
|
141
|
+
*/
|
|
142
|
+
function parsePackageList(stdout) {
|
|
143
|
+
if (!stdout)
|
|
144
|
+
return [];
|
|
145
|
+
const out = [];
|
|
146
|
+
for (const raw of stdout.split(/\r?\n/)) {
|
|
147
|
+
const line = raw.trim();
|
|
148
|
+
if (!line)
|
|
149
|
+
continue;
|
|
150
|
+
const idx = line.indexOf("package:");
|
|
151
|
+
if (idx < 0)
|
|
152
|
+
continue;
|
|
153
|
+
const tail = line.slice(idx + "package:".length);
|
|
154
|
+
// Strip optional `:<version>` and `=<path>` decorations.
|
|
155
|
+
const eqIdx = tail.indexOf("=");
|
|
156
|
+
const colonIdx = tail.indexOf(":");
|
|
157
|
+
let cut = tail.length;
|
|
158
|
+
if (colonIdx >= 0)
|
|
159
|
+
cut = Math.min(cut, colonIdx);
|
|
160
|
+
if (eqIdx >= 0)
|
|
161
|
+
cut = Math.min(cut, eqIdx);
|
|
162
|
+
const pkg = tail.slice(0, cut).trim();
|
|
163
|
+
if (pkg)
|
|
164
|
+
out.push(pkg);
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=find-app-package.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-app-package.js","sourceRoot":"","sources":["../../../src/shortcuts/builtins/find-app-package.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in shortcuts (Phase 2 of the GUI-Shortcut Hybrid Plan).
|
|
3
|
+
*
|
|
4
|
+
* Adding a shortcut:
|
|
5
|
+
* 1. Implement `Shortcut` in a new file under this folder.
|
|
6
|
+
* 2. Export the class here.
|
|
7
|
+
* 3. Add it to `registerBuiltinShortcuts(reg)` below.
|
|
8
|
+
*
|
|
9
|
+
* The bootstrap layer calls `registerBuiltinShortcuts` once on startup
|
|
10
|
+
* — there is no dynamic-load magic. Tests that need a different set
|
|
11
|
+
* of shortcuts construct their own `ShortcutRegistry` and register
|
|
12
|
+
* only what they need.
|
|
13
|
+
*/
|
|
14
|
+
import { ShortcutRegistry } from "../registry.js";
|
|
15
|
+
import { SetClipboardShortcut } from "./set-clipboard.js";
|
|
16
|
+
import { OpenDeeplinkShortcut } from "./open-deeplink.js";
|
|
17
|
+
import { FindAppPackageShortcut } from "./find-app-package.js";
|
|
18
|
+
import { DownloadToDeviceShortcut } from "./download-to-device.js";
|
|
19
|
+
export { SetClipboardShortcut, OpenDeeplinkShortcut, FindAppPackageShortcut, DownloadToDeviceShortcut, };
|
|
20
|
+
/**
|
|
21
|
+
* Register the four canonical Phase-2 shortcuts.
|
|
22
|
+
*
|
|
23
|
+
* Order matters for the LLM tool descriptor list (insertion order is
|
|
24
|
+
* preserved by the registry). The current ordering puts the most
|
|
25
|
+
* frequently useful shortcuts first:
|
|
26
|
+
*
|
|
27
|
+
* 1. `download_to_device` — most powerful; pairs with most flows
|
|
28
|
+
* 2. `set_clipboard` — reliable text-input bypass
|
|
29
|
+
* 3. `open_deeplink` — fastest cross-app navigation
|
|
30
|
+
* 4. `find_app_package` — supporting query helper for the others
|
|
31
|
+
*/
|
|
32
|
+
export declare function registerBuiltinShortcuts(reg: ShortcutRegistry): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in shortcuts (Phase 2 of the GUI-Shortcut Hybrid Plan).
|
|
3
|
+
*
|
|
4
|
+
* Adding a shortcut:
|
|
5
|
+
* 1. Implement `Shortcut` in a new file under this folder.
|
|
6
|
+
* 2. Export the class here.
|
|
7
|
+
* 3. Add it to `registerBuiltinShortcuts(reg)` below.
|
|
8
|
+
*
|
|
9
|
+
* The bootstrap layer calls `registerBuiltinShortcuts` once on startup
|
|
10
|
+
* — there is no dynamic-load magic. Tests that need a different set
|
|
11
|
+
* of shortcuts construct their own `ShortcutRegistry` and register
|
|
12
|
+
* only what they need.
|
|
13
|
+
*/
|
|
14
|
+
import { SetClipboardShortcut } from "./set-clipboard.js";
|
|
15
|
+
import { OpenDeeplinkShortcut } from "./open-deeplink.js";
|
|
16
|
+
import { FindAppPackageShortcut } from "./find-app-package.js";
|
|
17
|
+
import { DownloadToDeviceShortcut } from "./download-to-device.js";
|
|
18
|
+
export { SetClipboardShortcut, OpenDeeplinkShortcut, FindAppPackageShortcut, DownloadToDeviceShortcut, };
|
|
19
|
+
/**
|
|
20
|
+
* Register the four canonical Phase-2 shortcuts.
|
|
21
|
+
*
|
|
22
|
+
* Order matters for the LLM tool descriptor list (insertion order is
|
|
23
|
+
* preserved by the registry). The current ordering puts the most
|
|
24
|
+
* frequently useful shortcuts first:
|
|
25
|
+
*
|
|
26
|
+
* 1. `download_to_device` — most powerful; pairs with most flows
|
|
27
|
+
* 2. `set_clipboard` — reliable text-input bypass
|
|
28
|
+
* 3. `open_deeplink` — fastest cross-app navigation
|
|
29
|
+
* 4. `find_app_package` — supporting query helper for the others
|
|
30
|
+
*/
|
|
31
|
+
export function registerBuiltinShortcuts(reg) {
|
|
32
|
+
reg.register(new DownloadToDeviceShortcut());
|
|
33
|
+
reg.register(new SetClipboardShortcut());
|
|
34
|
+
reg.register(new OpenDeeplinkShortcut());
|
|
35
|
+
reg.register(new FindAppPackageShortcut());
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shortcuts/builtins/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAEnE,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,EACtB,wBAAwB,GACzB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAqB;IAC5D,GAAG,CAAC,QAAQ,CAAC,IAAI,wBAAwB,EAAE,CAAC,CAAC;IAC7C,GAAG,CAAC,QAAQ,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACzC,GAAG,CAAC,QAAQ,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACzC,GAAG,CAAC,QAAQ,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shortcut: `open_deeplink`
|
|
3
|
+
*
|
|
4
|
+
* Open a URI on the device using `am start -a android.intent.action.VIEW`.
|
|
5
|
+
*
|
|
6
|
+
* Why a shortcut:
|
|
7
|
+
*
|
|
8
|
+
* Deep links jump straight to the target screen of a target app
|
|
9
|
+
* without any navigation steps the VLM would otherwise have to
|
|
10
|
+
* click through (typically 3–6 taps on a launcher → app → category
|
|
11
|
+
* → search → result). For navigation (`geo:`, `amap://route`),
|
|
12
|
+
* payments, sharing flows, etc., this is dramatically faster *and*
|
|
13
|
+
* more reliable than visual reasoning.
|
|
14
|
+
*
|
|
15
|
+
* Why we accept failure on success:
|
|
16
|
+
*
|
|
17
|
+
* `am start` reports "Starting: Intent {…}" on stdout when it
|
|
18
|
+
* *dispatched* the intent — but Android then silently drops
|
|
19
|
+
* intents nothing handles. Per D5 we deliberately do NOT try to
|
|
20
|
+
* verify post-condition (the plan defers that to phase 3+ when
|
|
21
|
+
* we have screenshot-diff or ActivityManager hooks). The shortcut
|
|
22
|
+
* succeeds iff `am start` exits 0; if no app handled the intent
|
|
23
|
+
* the agent will see it visually on the next screenshot and can
|
|
24
|
+
* recover.
|
|
25
|
+
*
|
|
26
|
+
* Validation:
|
|
27
|
+
*
|
|
28
|
+
* - URI must parse via `new URL(uri)`.
|
|
29
|
+
* - URI must NOT use the `file:` scheme (path-traversal-style
|
|
30
|
+
* attacks against `am start -a VIEW`).
|
|
31
|
+
* - The whole URI is enforced into the `am start -d <uri>` slot via
|
|
32
|
+
* defensive single-quote shell escaping; intent extras are not
|
|
33
|
+
* accepted in Phase 2 (kept simple by design).
|
|
34
|
+
*
|
|
35
|
+
* Platform: Android only. Desktop has no equivalent.
|
|
36
|
+
*/
|
|
37
|
+
import type { Shortcut, ShortcutContext, ShortcutResult } from "../types.js";
|
|
38
|
+
interface DeeplinkOutput {
|
|
39
|
+
uri: string;
|
|
40
|
+
starterStdout: string;
|
|
41
|
+
}
|
|
42
|
+
export declare class OpenDeeplinkShortcut implements Shortcut<{
|
|
43
|
+
uri: string;
|
|
44
|
+
}, DeeplinkOutput> {
|
|
45
|
+
readonly descriptor: {
|
|
46
|
+
id: string;
|
|
47
|
+
displayName: string;
|
|
48
|
+
description: string;
|
|
49
|
+
jsonSchema: {
|
|
50
|
+
type: string;
|
|
51
|
+
properties: {
|
|
52
|
+
uri: {
|
|
53
|
+
type: string;
|
|
54
|
+
description: string;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
required: string[];
|
|
58
|
+
additionalProperties: boolean;
|
|
59
|
+
};
|
|
60
|
+
kind: "deeplink";
|
|
61
|
+
platforms: readonly ["android"];
|
|
62
|
+
timeoutMs: number;
|
|
63
|
+
};
|
|
64
|
+
execute(args: {
|
|
65
|
+
uri: string;
|
|
66
|
+
}, ctx: ShortcutContext): Promise<ShortcutResult<DeeplinkOutput>>;
|
|
67
|
+
}
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shortcut: `open_deeplink`
|
|
3
|
+
*
|
|
4
|
+
* Open a URI on the device using `am start -a android.intent.action.VIEW`.
|
|
5
|
+
*
|
|
6
|
+
* Why a shortcut:
|
|
7
|
+
*
|
|
8
|
+
* Deep links jump straight to the target screen of a target app
|
|
9
|
+
* without any navigation steps the VLM would otherwise have to
|
|
10
|
+
* click through (typically 3–6 taps on a launcher → app → category
|
|
11
|
+
* → search → result). For navigation (`geo:`, `amap://route`),
|
|
12
|
+
* payments, sharing flows, etc., this is dramatically faster *and*
|
|
13
|
+
* more reliable than visual reasoning.
|
|
14
|
+
*
|
|
15
|
+
* Why we accept failure on success:
|
|
16
|
+
*
|
|
17
|
+
* `am start` reports "Starting: Intent {…}" on stdout when it
|
|
18
|
+
* *dispatched* the intent — but Android then silently drops
|
|
19
|
+
* intents nothing handles. Per D5 we deliberately do NOT try to
|
|
20
|
+
* verify post-condition (the plan defers that to phase 3+ when
|
|
21
|
+
* we have screenshot-diff or ActivityManager hooks). The shortcut
|
|
22
|
+
* succeeds iff `am start` exits 0; if no app handled the intent
|
|
23
|
+
* the agent will see it visually on the next screenshot and can
|
|
24
|
+
* recover.
|
|
25
|
+
*
|
|
26
|
+
* Validation:
|
|
27
|
+
*
|
|
28
|
+
* - URI must parse via `new URL(uri)`.
|
|
29
|
+
* - URI must NOT use the `file:` scheme (path-traversal-style
|
|
30
|
+
* attacks against `am start -a VIEW`).
|
|
31
|
+
* - The whole URI is enforced into the `am start -d <uri>` slot via
|
|
32
|
+
* defensive single-quote shell escaping; intent extras are not
|
|
33
|
+
* accepted in Phase 2 (kept simple by design).
|
|
34
|
+
*
|
|
35
|
+
* Platform: Android only. Desktop has no equivalent.
|
|
36
|
+
*/
|
|
37
|
+
const FORBIDDEN_SCHEMES = new Set(["file"]);
|
|
38
|
+
export class OpenDeeplinkShortcut {
|
|
39
|
+
descriptor = {
|
|
40
|
+
id: "open_deeplink",
|
|
41
|
+
displayName: "Open Deeplink",
|
|
42
|
+
description: "Launch a URI via `am start -a android.intent.action.VIEW -d <uri>` on " +
|
|
43
|
+
"the connected Android device. Use this for app deep links " +
|
|
44
|
+
"(`weixin://`, `bilibili://`, `geo:39.9,116.3`, `https://...`) so the " +
|
|
45
|
+
"agent can skip multi-step manual navigation. Returns once `am start` " +
|
|
46
|
+
"exits — does NOT verify the target app actually handled the intent.",
|
|
47
|
+
jsonSchema: {
|
|
48
|
+
type: "object",
|
|
49
|
+
properties: {
|
|
50
|
+
uri: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "Fully-qualified URI (any scheme except file://).",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
required: ["uri"],
|
|
56
|
+
additionalProperties: false,
|
|
57
|
+
},
|
|
58
|
+
kind: "deeplink",
|
|
59
|
+
platforms: ["android"],
|
|
60
|
+
timeoutMs: 8_000,
|
|
61
|
+
};
|
|
62
|
+
async execute(args, ctx) {
|
|
63
|
+
if (typeof args?.uri !== "string" || args.uri.length === 0) {
|
|
64
|
+
return { ok: false, code: "invalid_args", message: "uri must be a non-empty string" };
|
|
65
|
+
}
|
|
66
|
+
let parsed;
|
|
67
|
+
try {
|
|
68
|
+
parsed = new URL(args.uri);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
code: "invalid_args",
|
|
74
|
+
message: `uri is not a valid URL: ${args.uri}`,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const scheme = parsed.protocol.replace(/:$/, "").toLowerCase();
|
|
78
|
+
if (!scheme) {
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
code: "invalid_args",
|
|
82
|
+
message: "uri is missing a scheme",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (FORBIDDEN_SCHEMES.has(scheme)) {
|
|
86
|
+
return {
|
|
87
|
+
ok: false,
|
|
88
|
+
code: "invalid_args",
|
|
89
|
+
message: `uri scheme "${scheme}" is forbidden`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (!ctx.mcp || typeof ctx.mcp.executeCommand !== "function") {
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
code: "permission_denied",
|
|
96
|
+
message: "active MCP runtime cannot execute shell commands",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
const cmd = `am start -a android.intent.action.VIEW -d ${shellQuote(args.uri)}`;
|
|
100
|
+
try {
|
|
101
|
+
const res = await ctx.mcp.executeCommand(cmd, { timeoutS: 6 });
|
|
102
|
+
if (res.exitCode !== 0) {
|
|
103
|
+
// `am start` returns 0 even when no activity handles the
|
|
104
|
+
// intent (it just prints "Activity not started, …"). A
|
|
105
|
+
// non-zero exit therefore really is an OS-level rejection,
|
|
106
|
+
// mapped to intent_rejected per the plan's error contract.
|
|
107
|
+
return {
|
|
108
|
+
ok: false,
|
|
109
|
+
code: "intent_rejected",
|
|
110
|
+
message: `am start exit=${res.exitCode}: ${(res.stderr || res.stdout).trim()}`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Detect "no Activity found to handle Intent" in stdout — Android
|
|
114
|
+
// doesn't surface it as a non-zero exit, but the message is
|
|
115
|
+
// stable enough for a string match. We map it to app_not_found
|
|
116
|
+
// so the LLM can fallback to mobile_use.
|
|
117
|
+
const out = (res.stdout || "").toLowerCase();
|
|
118
|
+
if (out.includes("error: activity class") || out.includes("does not exist")) {
|
|
119
|
+
return {
|
|
120
|
+
ok: false,
|
|
121
|
+
code: "app_not_found",
|
|
122
|
+
message: res.stdout.trim(),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
ok: true,
|
|
127
|
+
output: { uri: args.uri, starterStdout: res.stdout },
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
return {
|
|
132
|
+
ok: false,
|
|
133
|
+
code: "internal_error",
|
|
134
|
+
message: e.message,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function shellQuote(s) {
|
|
140
|
+
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=open-deeplink.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-deeplink.js","sourceRoot":"","sources":["../../../src/shortcuts/builtins/open-deeplink.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shortcut: `set_clipboard`
|
|
3
|
+
*
|
|
4
|
+
* Set the device clipboard contents to a caller-supplied string.
|
|
5
|
+
*
|
|
6
|
+
* Why a shortcut:
|
|
7
|
+
*
|
|
8
|
+
* The GUI-only VLM cannot type long strings reliably (especially
|
|
9
|
+
* non-Latin scripts and emoji), and the legacy `apply({kind:"type"})`
|
|
10
|
+
* path piggybacks on the IME — which on most ROMs strips zero-width
|
|
11
|
+
* characters and re-encodes emoji. The shortcut bypasses both
|
|
12
|
+
* problems by placing the text on the system clipboard via the ADB
|
|
13
|
+
* Keyboard input method's broadcast hook
|
|
14
|
+
* (`ime.adb.android.ADB_INPUT_TEXT`); the VLM's later
|
|
15
|
+
* long-press → "粘贴 / Paste" works against bit-exact text.
|
|
16
|
+
*
|
|
17
|
+
* Compatibility note:
|
|
18
|
+
*
|
|
19
|
+
* ADBKeyboard (com.android.adbkeyboard) must be the active IME for
|
|
20
|
+
* the broadcast to take effect. On stock ROMs the user / agent
|
|
21
|
+
* needs to install + select it once. When the broadcast is dropped
|
|
22
|
+
* silently (no error code from `am`), the shortcut still returns
|
|
23
|
+
* `ok: true` because there is no observable failure mode short of
|
|
24
|
+
* reading the clipboard back. A future Phase-3 verification step
|
|
25
|
+
* may add a clipboard read-back via `cmd clipboard get-text`, but
|
|
26
|
+
* per D5 we don't gate on it now.
|
|
27
|
+
*
|
|
28
|
+
* Platform: Android only. Desktop has no equivalent ADB-keyboard
|
|
29
|
+
* primitive; calling the shortcut on a desktop device returns
|
|
30
|
+
* `unsupported_platform` from the router's platform gate.
|
|
31
|
+
*
|
|
32
|
+
* Telemetry: `shortcut.invoke` log line; counter dimension
|
|
33
|
+
* `shortcut_id="set_clipboard"`.
|
|
34
|
+
*/
|
|
35
|
+
import type { Shortcut, ShortcutContext, ShortcutResult } from "../types.js";
|
|
36
|
+
export declare class SetClipboardShortcut implements Shortcut<{
|
|
37
|
+
text: string;
|
|
38
|
+
}, {
|
|
39
|
+
length: number;
|
|
40
|
+
}> {
|
|
41
|
+
readonly descriptor: {
|
|
42
|
+
id: string;
|
|
43
|
+
displayName: string;
|
|
44
|
+
description: string;
|
|
45
|
+
jsonSchema: {
|
|
46
|
+
type: string;
|
|
47
|
+
properties: {
|
|
48
|
+
text: {
|
|
49
|
+
type: string;
|
|
50
|
+
description: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
required: string[];
|
|
54
|
+
additionalProperties: boolean;
|
|
55
|
+
};
|
|
56
|
+
kind: "api";
|
|
57
|
+
platforms: readonly ["android"];
|
|
58
|
+
timeoutMs: number;
|
|
59
|
+
};
|
|
60
|
+
execute(args: {
|
|
61
|
+
text: string;
|
|
62
|
+
}, ctx: ShortcutContext): Promise<ShortcutResult<{
|
|
63
|
+
length: number;
|
|
64
|
+
}>>;
|
|
65
|
+
}
|