@beeos-ai/device-agent 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. package/.pi/extensions/android-tools.ts +146 -15
  2. package/dist/adapters/agent-gateway-client.d.ts +37 -0
  3. package/dist/adapters/agent-gateway-client.js +45 -0
  4. package/dist/adapters/agent-gateway-client.js.map +1 -1
  5. package/dist/adapters/agentcore-pi.d.ts +22 -0
  6. package/dist/adapters/agentcore-pi.js +48 -0
  7. package/dist/adapters/agentcore-pi.js.map +1 -1
  8. package/dist/adapters/device-android-adb.d.ts +47 -0
  9. package/dist/adapters/device-android-adb.js +50 -0
  10. package/dist/adapters/device-android-adb.js.map +1 -1
  11. package/dist/adapters/device-desktop.d.ts +12 -0
  12. package/dist/adapters/device-desktop.js +31 -0
  13. package/dist/adapters/device-desktop.js.map +1 -1
  14. package/dist/adapters/identity-file.d.ts +33 -5
  15. package/dist/adapters/identity-file.js +52 -6
  16. package/dist/adapters/identity-file.js.map +1 -1
  17. package/dist/agent-runtime/adapters/base.d.ts +20 -0
  18. package/dist/agent-runtime/adapters/base.js.map +1 -1
  19. package/dist/agent-runtime/agent-runner.d.ts +4 -2
  20. package/dist/agent-runtime/agent-runner.js.map +1 -1
  21. package/dist/agent-runtime/core.d.ts +60 -0
  22. package/dist/agent-runtime/core.js +190 -9
  23. package/dist/agent-runtime/core.js.map +1 -1
  24. package/dist/agent-runtime/feedback.d.ts +56 -0
  25. package/dist/agent-runtime/feedback.js +54 -0
  26. package/dist/agent-runtime/feedback.js.map +1 -0
  27. package/dist/agent-runtime/index.d.ts +1 -0
  28. package/dist/agent-runtime/index.js +1 -0
  29. package/dist/agent-runtime/index.js.map +1 -1
  30. package/dist/agent-runtime/plan-executor.js +24 -0
  31. package/dist/agent-runtime/plan-executor.js.map +1 -1
  32. package/dist/agent-runtime/planner/base.d.ts +10 -0
  33. package/dist/agent-runtime/planner/base.js.map +1 -1
  34. package/dist/agent-runtime/planner/llm-planner.js +1 -0
  35. package/dist/agent-runtime/planner/llm-planner.js.map +1 -1
  36. package/dist/agent-runtime/planner/prompts.d.ts +3 -0
  37. package/dist/agent-runtime/planner/prompts.js +12 -0
  38. package/dist/agent-runtime/planner/prompts.js.map +1 -1
  39. package/dist/agent-runtime/reflection.d.ts +25 -6
  40. package/dist/agent-runtime/reflection.js +64 -22
  41. package/dist/agent-runtime/reflection.js.map +1 -1
  42. package/dist/agent-runtime/reflectors/policy.d.ts +10 -4
  43. package/dist/agent-runtime/reflectors/policy.js +19 -6
  44. package/dist/agent-runtime/reflectors/policy.js.map +1 -1
  45. package/dist/agent-runtime/shortcuts/fs-store.d.ts +41 -0
  46. package/dist/agent-runtime/shortcuts/fs-store.js +122 -0
  47. package/dist/agent-runtime/shortcuts/fs-store.js.map +1 -0
  48. package/dist/agent-runtime/shortcuts/in-memory-store.d.ts +20 -0
  49. package/dist/agent-runtime/shortcuts/in-memory-store.js +64 -0
  50. package/dist/agent-runtime/shortcuts/in-memory-store.js.map +1 -0
  51. package/dist/agent-runtime/shortcuts/index.d.ts +10 -0
  52. package/dist/agent-runtime/shortcuts/index.js +10 -0
  53. package/dist/agent-runtime/shortcuts/index.js.map +1 -0
  54. package/dist/agent-runtime/shortcuts/types.d.ts +69 -0
  55. package/dist/agent-runtime/shortcuts/types.js +17 -0
  56. package/dist/agent-runtime/shortcuts/types.js.map +1 -0
  57. package/dist/app/agent-host.d.ts +83 -0
  58. package/dist/app/agent-host.js +345 -32
  59. package/dist/app/agent-host.js.map +1 -1
  60. package/dist/app/session-manager.d.ts +33 -4
  61. package/dist/app/session-manager.js +27 -5
  62. package/dist/app/session-manager.js.map +1 -1
  63. package/dist/bootstrap.js +187 -3
  64. package/dist/bootstrap.js.map +1 -1
  65. package/dist/config/loader.js +22 -0
  66. package/dist/config/loader.js.map +1 -1
  67. package/dist/config/schema.d.ts +18 -0
  68. package/dist/config/schema.js +118 -0
  69. package/dist/config/schema.js.map +1 -1
  70. package/dist/fleet/adapters/process/node-process-manager.js +97 -17
  71. package/dist/fleet/adapters/process/node-process-manager.js.map +1 -1
  72. package/dist/fleet/adapters/state/beeos-cli-store.d.ts +75 -9
  73. package/dist/fleet/adapters/state/beeos-cli-store.js +201 -17
  74. package/dist/fleet/adapters/state/beeos-cli-store.js.map +1 -1
  75. package/dist/fleet/domain/device.d.ts +9 -0
  76. package/dist/fleet/domain/device.js.map +1 -1
  77. package/dist/fleet/domain/fsm.js +34 -0
  78. package/dist/fleet/domain/fsm.js.map +1 -1
  79. package/dist/fleet/installer/spawn-env.d.ts +3 -0
  80. package/dist/fleet/installer/spawn-env.js +186 -3
  81. package/dist/fleet/installer/spawn-env.js.map +1 -1
  82. package/dist/fleet/state/state-json.d.ts +116 -0
  83. package/dist/fleet/state/state-json.js +87 -0
  84. package/dist/fleet/state/state-json.js.map +1 -0
  85. package/dist/fleet/supervisor.js +14 -2
  86. package/dist/fleet/supervisor.js.map +1 -1
  87. package/dist/inbound/acp/handlers/session.js.map +1 -1
  88. package/dist/mcp-client/client.d.ts +6 -0
  89. package/dist/mcp-client/client.js +11 -0
  90. package/dist/mcp-client/client.js.map +1 -1
  91. package/dist/mcp-client/runtime.d.ts +13 -0
  92. package/dist/orchestrator-system-prompt.d.ts +26 -0
  93. package/dist/orchestrator-system-prompt.js +118 -2
  94. package/dist/orchestrator-system-prompt.js.map +1 -1
  95. package/dist/pi-context.d.ts +50 -0
  96. package/dist/pi-context.js.map +1 -1
  97. package/dist/ports/device.d.ts +18 -0
  98. package/dist/resources/augmenter.d.ts +48 -0
  99. package/dist/resources/augmenter.js +126 -0
  100. package/dist/resources/augmenter.js.map +1 -0
  101. package/dist/resources/cache.d.ts +57 -0
  102. package/dist/resources/cache.js +107 -0
  103. package/dist/resources/cache.js.map +1 -0
  104. package/dist/resources/index.d.ts +17 -0
  105. package/dist/resources/index.js +15 -0
  106. package/dist/resources/index.js.map +1 -0
  107. package/dist/resources/lifecycle/disk-pressure.d.ts +75 -0
  108. package/dist/resources/lifecycle/disk-pressure.js +148 -0
  109. package/dist/resources/lifecycle/disk-pressure.js.map +1 -0
  110. package/dist/resources/lifecycle/index.d.ts +7 -0
  111. package/dist/resources/lifecycle/index.js +7 -0
  112. package/dist/resources/lifecycle/index.js.map +1 -0
  113. package/dist/resources/lifecycle/manager.d.ts +38 -0
  114. package/dist/resources/lifecycle/manager.js +205 -0
  115. package/dist/resources/lifecycle/manager.js.map +1 -0
  116. package/dist/resources/lifecycle/sweeper.d.ts +36 -0
  117. package/dist/resources/lifecycle/sweeper.js +179 -0
  118. package/dist/resources/lifecycle/sweeper.js.map +1 -0
  119. package/dist/resources/lifecycle/types.d.ts +180 -0
  120. package/dist/resources/lifecycle/types.js +46 -0
  121. package/dist/resources/lifecycle/types.js.map +1 -0
  122. package/dist/resources/parsers.d.ts +28 -0
  123. package/dist/resources/parsers.js +88 -0
  124. package/dist/resources/parsers.js.map +1 -0
  125. package/dist/resources/registry.d.ts +47 -0
  126. package/dist/resources/registry.js +107 -0
  127. package/dist/resources/registry.js.map +1 -0
  128. package/dist/resources/resolvers/beeos-file-resolver.d.ts +62 -0
  129. package/dist/resources/resolvers/beeos-file-resolver.js +109 -0
  130. package/dist/resources/resolvers/beeos-file-resolver.js.map +1 -0
  131. package/dist/resources/resolvers/errors.d.ts +11 -0
  132. package/dist/resources/resolvers/errors.js +23 -0
  133. package/dist/resources/resolvers/errors.js.map +1 -0
  134. package/dist/resources/resolvers/mime-table.d.ts +41 -0
  135. package/dist/resources/resolvers/mime-table.js +92 -0
  136. package/dist/resources/resolvers/mime-table.js.map +1 -0
  137. package/dist/resources/resolvers/url-resolver.d.ts +85 -0
  138. package/dist/resources/resolvers/url-resolver.js +495 -0
  139. package/dist/resources/resolvers/url-resolver.js.map +1 -0
  140. package/dist/resources/shortcut-facade.d.ts +51 -0
  141. package/dist/resources/shortcut-facade.js +72 -0
  142. package/dist/resources/shortcut-facade.js.map +1 -0
  143. package/dist/resources/telemetry.d.ts +52 -0
  144. package/dist/resources/telemetry.js +59 -0
  145. package/dist/resources/telemetry.js.map +1 -0
  146. package/dist/resources/types.d.ts +249 -0
  147. package/dist/resources/types.js +29 -0
  148. package/dist/resources/types.js.map +1 -0
  149. package/dist/shortcuts/builtins/download-to-device.d.ts +83 -0
  150. package/dist/shortcuts/builtins/download-to-device.js +125 -0
  151. package/dist/shortcuts/builtins/download-to-device.js.map +1 -0
  152. package/dist/shortcuts/builtins/find-app-package.d.ts +79 -0
  153. package/dist/shortcuts/builtins/find-app-package.js +168 -0
  154. package/dist/shortcuts/builtins/find-app-package.js.map +1 -0
  155. package/dist/shortcuts/builtins/index.d.ts +32 -0
  156. package/dist/shortcuts/builtins/index.js +37 -0
  157. package/dist/shortcuts/builtins/index.js.map +1 -0
  158. package/dist/shortcuts/builtins/open-deeplink.d.ts +68 -0
  159. package/dist/shortcuts/builtins/open-deeplink.js +142 -0
  160. package/dist/shortcuts/builtins/open-deeplink.js.map +1 -0
  161. package/dist/shortcuts/builtins/set-clipboard.d.ts +65 -0
  162. package/dist/shortcuts/builtins/set-clipboard.js +112 -0
  163. package/dist/shortcuts/builtins/set-clipboard.js.map +1 -0
  164. package/dist/shortcuts/index.d.ts +11 -0
  165. package/dist/shortcuts/index.js +11 -0
  166. package/dist/shortcuts/index.js.map +1 -0
  167. package/dist/shortcuts/registry.d.ts +56 -0
  168. package/dist/shortcuts/registry.js +70 -0
  169. package/dist/shortcuts/registry.js.map +1 -0
  170. package/dist/shortcuts/router.d.ts +91 -0
  171. package/dist/shortcuts/router.js +158 -0
  172. package/dist/shortcuts/router.js.map +1 -0
  173. package/dist/shortcuts/types.d.ts +219 -0
  174. package/dist/shortcuts/types.js +46 -0
  175. package/dist/shortcuts/types.js.map +1 -0
  176. package/package.json +3 -3
  177. package/dist/agent-runtime/skills/sqlite-store.d.ts +0 -60
  178. package/dist/agent-runtime/skills/sqlite-store.js +0 -234
  179. package/dist/agent-runtime/skills/sqlite-store.js.map +0 -1
  180. package/dist/test-lan-autoglm.d.ts +0 -7
  181. package/dist/test-lan-autoglm.js +0 -46
  182. package/dist/test-lan-autoglm.js.map +0 -1
  183. package/dist/test-mem-breakdown.d.ts +0 -1
  184. package/dist/test-mem-breakdown.js +0 -103
  185. package/dist/test-mem-breakdown.js.map +0 -1
  186. package/dist/test-mem.d.ts +0 -1
  187. package/dist/test-mem.js +0 -60
  188. package/dist/test-mem.js.map +0 -1
  189. package/dist/test-mobile-use.d.ts +0 -1
  190. package/dist/test-mobile-use.js +0 -18
  191. package/dist/test-mobile-use.js.map +0 -1
  192. package/dist/test-screenshot-loop.d.ts +0 -1
  193. package/dist/test-screenshot-loop.js +0 -43
  194. package/dist/test-screenshot-loop.js.map +0 -1
  195. package/dist/test-screenshot.d.ts +0 -1
  196. package/dist/test-screenshot.js +0 -10
  197. package/dist/test-screenshot.js.map +0 -1
  198. package/dist/test-ui-xml-dump.d.ts +0 -15
  199. package/dist/test-ui-xml-dump.js +0 -49
  200. 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
+ }