@beeos-ai/device-agent 0.4.3 → 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.
Files changed (180) 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/agent-runtime/adapters/base.d.ts +20 -0
  15. package/dist/agent-runtime/adapters/base.js.map +1 -1
  16. package/dist/agent-runtime/agent-runner.d.ts +4 -2
  17. package/dist/agent-runtime/agent-runner.js.map +1 -1
  18. package/dist/agent-runtime/core.d.ts +60 -0
  19. package/dist/agent-runtime/core.js +190 -9
  20. package/dist/agent-runtime/core.js.map +1 -1
  21. package/dist/agent-runtime/feedback.d.ts +56 -0
  22. package/dist/agent-runtime/feedback.js +54 -0
  23. package/dist/agent-runtime/feedback.js.map +1 -0
  24. package/dist/agent-runtime/index.d.ts +1 -0
  25. package/dist/agent-runtime/index.js +1 -0
  26. package/dist/agent-runtime/index.js.map +1 -1
  27. package/dist/agent-runtime/plan-executor.js +24 -0
  28. package/dist/agent-runtime/plan-executor.js.map +1 -1
  29. package/dist/agent-runtime/planner/base.d.ts +10 -0
  30. package/dist/agent-runtime/planner/base.js.map +1 -1
  31. package/dist/agent-runtime/planner/llm-planner.js +1 -0
  32. package/dist/agent-runtime/planner/llm-planner.js.map +1 -1
  33. package/dist/agent-runtime/planner/prompts.d.ts +3 -0
  34. package/dist/agent-runtime/planner/prompts.js +12 -0
  35. package/dist/agent-runtime/planner/prompts.js.map +1 -1
  36. package/dist/agent-runtime/reflection.d.ts +25 -6
  37. package/dist/agent-runtime/reflection.js +64 -22
  38. package/dist/agent-runtime/reflection.js.map +1 -1
  39. package/dist/agent-runtime/reflectors/policy.d.ts +10 -4
  40. package/dist/agent-runtime/reflectors/policy.js +19 -6
  41. package/dist/agent-runtime/reflectors/policy.js.map +1 -1
  42. package/dist/agent-runtime/shortcuts/fs-store.d.ts +41 -0
  43. package/dist/agent-runtime/shortcuts/fs-store.js +122 -0
  44. package/dist/agent-runtime/shortcuts/fs-store.js.map +1 -0
  45. package/dist/agent-runtime/shortcuts/in-memory-store.d.ts +20 -0
  46. package/dist/agent-runtime/shortcuts/in-memory-store.js +64 -0
  47. package/dist/agent-runtime/shortcuts/in-memory-store.js.map +1 -0
  48. package/dist/agent-runtime/shortcuts/index.d.ts +10 -0
  49. package/dist/agent-runtime/shortcuts/index.js +10 -0
  50. package/dist/agent-runtime/shortcuts/index.js.map +1 -0
  51. package/dist/agent-runtime/shortcuts/types.d.ts +69 -0
  52. package/dist/agent-runtime/shortcuts/types.js +17 -0
  53. package/dist/agent-runtime/shortcuts/types.js.map +1 -0
  54. package/dist/app/agent-host.d.ts +83 -0
  55. package/dist/app/agent-host.js +345 -32
  56. package/dist/app/agent-host.js.map +1 -1
  57. package/dist/app/session-manager.d.ts +33 -4
  58. package/dist/app/session-manager.js +27 -5
  59. package/dist/app/session-manager.js.map +1 -1
  60. package/dist/bootstrap.js +187 -3
  61. package/dist/bootstrap.js.map +1 -1
  62. package/dist/config/loader.js +22 -0
  63. package/dist/config/loader.js.map +1 -1
  64. package/dist/config/schema.d.ts +18 -0
  65. package/dist/config/schema.js +118 -0
  66. package/dist/config/schema.js.map +1 -1
  67. package/dist/inbound/acp/handlers/session.js.map +1 -1
  68. package/dist/mcp-client/client.d.ts +6 -0
  69. package/dist/mcp-client/client.js +11 -0
  70. package/dist/mcp-client/client.js.map +1 -1
  71. package/dist/mcp-client/runtime.d.ts +13 -0
  72. package/dist/orchestrator-system-prompt.d.ts +26 -0
  73. package/dist/orchestrator-system-prompt.js +118 -2
  74. package/dist/orchestrator-system-prompt.js.map +1 -1
  75. package/dist/pi-context.d.ts +50 -0
  76. package/dist/pi-context.js.map +1 -1
  77. package/dist/ports/device.d.ts +18 -0
  78. package/dist/resources/augmenter.d.ts +48 -0
  79. package/dist/resources/augmenter.js +126 -0
  80. package/dist/resources/augmenter.js.map +1 -0
  81. package/dist/resources/cache.d.ts +57 -0
  82. package/dist/resources/cache.js +107 -0
  83. package/dist/resources/cache.js.map +1 -0
  84. package/dist/resources/index.d.ts +17 -0
  85. package/dist/resources/index.js +15 -0
  86. package/dist/resources/index.js.map +1 -0
  87. package/dist/resources/lifecycle/disk-pressure.d.ts +75 -0
  88. package/dist/resources/lifecycle/disk-pressure.js +148 -0
  89. package/dist/resources/lifecycle/disk-pressure.js.map +1 -0
  90. package/dist/resources/lifecycle/index.d.ts +7 -0
  91. package/dist/resources/lifecycle/index.js +7 -0
  92. package/dist/resources/lifecycle/index.js.map +1 -0
  93. package/dist/resources/lifecycle/manager.d.ts +38 -0
  94. package/dist/resources/lifecycle/manager.js +205 -0
  95. package/dist/resources/lifecycle/manager.js.map +1 -0
  96. package/dist/resources/lifecycle/sweeper.d.ts +36 -0
  97. package/dist/resources/lifecycle/sweeper.js +179 -0
  98. package/dist/resources/lifecycle/sweeper.js.map +1 -0
  99. package/dist/resources/lifecycle/types.d.ts +180 -0
  100. package/dist/resources/lifecycle/types.js +46 -0
  101. package/dist/resources/lifecycle/types.js.map +1 -0
  102. package/dist/resources/parsers.d.ts +28 -0
  103. package/dist/resources/parsers.js +88 -0
  104. package/dist/resources/parsers.js.map +1 -0
  105. package/dist/resources/registry.d.ts +47 -0
  106. package/dist/resources/registry.js +107 -0
  107. package/dist/resources/registry.js.map +1 -0
  108. package/dist/resources/resolvers/beeos-file-resolver.d.ts +62 -0
  109. package/dist/resources/resolvers/beeos-file-resolver.js +109 -0
  110. package/dist/resources/resolvers/beeos-file-resolver.js.map +1 -0
  111. package/dist/resources/resolvers/errors.d.ts +11 -0
  112. package/dist/resources/resolvers/errors.js +23 -0
  113. package/dist/resources/resolvers/errors.js.map +1 -0
  114. package/dist/resources/resolvers/mime-table.d.ts +41 -0
  115. package/dist/resources/resolvers/mime-table.js +92 -0
  116. package/dist/resources/resolvers/mime-table.js.map +1 -0
  117. package/dist/resources/resolvers/url-resolver.d.ts +85 -0
  118. package/dist/resources/resolvers/url-resolver.js +495 -0
  119. package/dist/resources/resolvers/url-resolver.js.map +1 -0
  120. package/dist/resources/shortcut-facade.d.ts +51 -0
  121. package/dist/resources/shortcut-facade.js +72 -0
  122. package/dist/resources/shortcut-facade.js.map +1 -0
  123. package/dist/resources/telemetry.d.ts +52 -0
  124. package/dist/resources/telemetry.js +59 -0
  125. package/dist/resources/telemetry.js.map +1 -0
  126. package/dist/resources/types.d.ts +249 -0
  127. package/dist/resources/types.js +29 -0
  128. package/dist/resources/types.js.map +1 -0
  129. package/dist/shortcuts/builtins/download-to-device.d.ts +83 -0
  130. package/dist/shortcuts/builtins/download-to-device.js +125 -0
  131. package/dist/shortcuts/builtins/download-to-device.js.map +1 -0
  132. package/dist/shortcuts/builtins/find-app-package.d.ts +79 -0
  133. package/dist/shortcuts/builtins/find-app-package.js +168 -0
  134. package/dist/shortcuts/builtins/find-app-package.js.map +1 -0
  135. package/dist/shortcuts/builtins/index.d.ts +32 -0
  136. package/dist/shortcuts/builtins/index.js +37 -0
  137. package/dist/shortcuts/builtins/index.js.map +1 -0
  138. package/dist/shortcuts/builtins/open-deeplink.d.ts +68 -0
  139. package/dist/shortcuts/builtins/open-deeplink.js +142 -0
  140. package/dist/shortcuts/builtins/open-deeplink.js.map +1 -0
  141. package/dist/shortcuts/builtins/set-clipboard.d.ts +65 -0
  142. package/dist/shortcuts/builtins/set-clipboard.js +112 -0
  143. package/dist/shortcuts/builtins/set-clipboard.js.map +1 -0
  144. package/dist/shortcuts/index.d.ts +11 -0
  145. package/dist/shortcuts/index.js +11 -0
  146. package/dist/shortcuts/index.js.map +1 -0
  147. package/dist/shortcuts/registry.d.ts +56 -0
  148. package/dist/shortcuts/registry.js +70 -0
  149. package/dist/shortcuts/registry.js.map +1 -0
  150. package/dist/shortcuts/router.d.ts +91 -0
  151. package/dist/shortcuts/router.js +158 -0
  152. package/dist/shortcuts/router.js.map +1 -0
  153. package/dist/shortcuts/types.d.ts +219 -0
  154. package/dist/shortcuts/types.js +46 -0
  155. package/dist/shortcuts/types.js.map +1 -0
  156. package/package.json +3 -3
  157. package/dist/agent-runtime/skills/sqlite-store.d.ts +0 -60
  158. package/dist/agent-runtime/skills/sqlite-store.js +0 -234
  159. package/dist/agent-runtime/skills/sqlite-store.js.map +0 -1
  160. package/dist/test-lan-autoglm.d.ts +0 -7
  161. package/dist/test-lan-autoglm.js +0 -46
  162. package/dist/test-lan-autoglm.js.map +0 -1
  163. package/dist/test-mem-breakdown.d.ts +0 -1
  164. package/dist/test-mem-breakdown.js +0 -103
  165. package/dist/test-mem-breakdown.js.map +0 -1
  166. package/dist/test-mem.d.ts +0 -1
  167. package/dist/test-mem.js +0 -60
  168. package/dist/test-mem.js.map +0 -1
  169. package/dist/test-mobile-use.d.ts +0 -1
  170. package/dist/test-mobile-use.js +0 -18
  171. package/dist/test-mobile-use.js.map +0 -1
  172. package/dist/test-screenshot-loop.d.ts +0 -1
  173. package/dist/test-screenshot-loop.js +0 -43
  174. package/dist/test-screenshot-loop.js.map +0 -1
  175. package/dist/test-screenshot.d.ts +0 -1
  176. package/dist/test-screenshot.js +0 -10
  177. package/dist/test-screenshot.js.map +0 -1
  178. package/dist/test-ui-xml-dump.d.ts +0 -15
  179. package/dist/test-ui-xml-dump.js +0 -49
  180. package/dist/test-ui-xml-dump.js.map +0 -1
@@ -0,0 +1,112 @@
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
+ const MAX_TEXT_LEN = 50_000;
36
+ export class SetClipboardShortcut {
37
+ descriptor = {
38
+ id: "set_clipboard",
39
+ displayName: "Set Clipboard",
40
+ description: "Place arbitrary text (including non-Latin scripts and emoji) on " +
41
+ "the Android device's clipboard. The VLM can paste it later via " +
42
+ "long-press. Use this for any long / exotic text input that the " +
43
+ "GUI keyboard would mangle. Requires ADBKeyboard IME to be the " +
44
+ "active input method on the device.",
45
+ jsonSchema: {
46
+ type: "object",
47
+ properties: {
48
+ text: {
49
+ type: "string",
50
+ description: "Verbatim text to place on the clipboard. Up to 50,000 chars.",
51
+ },
52
+ },
53
+ required: ["text"],
54
+ additionalProperties: false,
55
+ },
56
+ kind: "api",
57
+ platforms: ["android"],
58
+ timeoutMs: 5_000,
59
+ };
60
+ async execute(args, ctx) {
61
+ if (typeof args?.text !== "string") {
62
+ return { ok: false, code: "invalid_args", message: "text must be a string" };
63
+ }
64
+ if (args.text.length > MAX_TEXT_LEN) {
65
+ return {
66
+ ok: false,
67
+ code: "invalid_args",
68
+ message: `text exceeds ${MAX_TEXT_LEN} chars`,
69
+ };
70
+ }
71
+ if (!ctx.mcp || typeof ctx.mcp.executeCommand !== "function") {
72
+ return {
73
+ ok: false,
74
+ code: "permission_denied",
75
+ message: "active MCP runtime cannot execute shell commands",
76
+ };
77
+ }
78
+ // Encode text → base64 so single-quote / newline / shell escape
79
+ // hazards never reach `am broadcast`. ADBKeyboard accepts the
80
+ // base64 form via `--es msg <b64>` paired with `--ei type 1`
81
+ // (1 = base64 input).
82
+ const b64 = Buffer.from(args.text, "utf8").toString("base64");
83
+ const cmd = `am broadcast -a ADB_INPUT_B64 --es msg ${shellQuote(b64)}`;
84
+ try {
85
+ const res = await ctx.mcp.executeCommand(cmd, { timeoutS: 4 });
86
+ if (res.exitCode !== 0) {
87
+ return {
88
+ ok: false,
89
+ code: "intent_rejected",
90
+ message: `am broadcast exit=${res.exitCode}: ${res.stderr.trim() || res.stdout.trim()}`,
91
+ };
92
+ }
93
+ }
94
+ catch (e) {
95
+ return {
96
+ ok: false,
97
+ code: "internal_error",
98
+ message: e.message,
99
+ };
100
+ }
101
+ return { ok: true, output: { length: args.text.length } };
102
+ }
103
+ }
104
+ /**
105
+ * Quote `s` for safe inclusion in a single-quoted shell argument.
106
+ * The string is base64-encoded ASCII (no quotes possible) but we keep
107
+ * the quoting defensively in case the encoder ever changes.
108
+ */
109
+ function shellQuote(s) {
110
+ return `'${s.replace(/'/g, "'\\''")}'`;
111
+ }
112
+ //# sourceMappingURL=set-clipboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"set-clipboard.js","sourceRoot":"","sources":["../../../src/shortcuts/builtins/set-clipboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH,MAAM,YAAY,GAAG,MAAM,CAAC;AAE5B,MAAM,OAAO,oBAAoB;IACtB,UAAU,GAAG;QACpB,EAAE,EAAE,eAAe;QACnB,WAAW,EAAE,eAAe;QAC5B,WAAW,EACT,kEAAkE;YAClE,iEAAiE;YACjE,iEAAiE;YACjE,gEAAgE;YAChE,oCAAoC;QACtC,UAAU,EAAE;YACV,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,8DAA8D;iBAC5E;aACF;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;YAClB,oBAAoB,EAAE,KAAK;SAC5B;QACD,IAAI,EAAE,KAAc;QACpB,SAAS,EAAE,CAAC,SAAS,CAAU;QAC/B,SAAS,EAAE,KAAK;KACjB,CAAC;IAEF,KAAK,CAAC,OAAO,CACX,IAAsB,EACtB,GAAoB;QAEpB,IAAI,OAAO,IAAI,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC;QAC/E,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;YACpC,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,gBAAgB,YAAY,QAAQ;aAC9C,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,GAAG,CAAC,cAAc,KAAK,UAAU,EAAE,CAAC;YAC7D,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,mBAAmB;gBACzB,OAAO,EAAE,kDAAkD;aAC5D,CAAC;QACJ,CAAC;QAED,gEAAgE;QAChE,8DAA8D;QAC9D,6DAA6D;QAC7D,sBAAsB;QACtB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC9D,MAAM,GAAG,GACP,0CAA0C,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAE9D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;YAC/D,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBACvB,OAAO;oBACL,EAAE,EAAE,KAAK;oBACT,IAAI,EAAE,iBAAiB;oBACvB,OAAO,EACL,qBAAqB,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;iBACjF,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,gBAAgB;gBACtB,OAAO,EAAG,CAAW,CAAC,OAAO;aAC9B,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;IAC5D,CAAC;CACF;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AACzC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * shortcuts/ — Hybrid Action Space barrel.
3
+ *
4
+ * Public surface for Phase 2 of the GUI-Shortcut Hybrid Plan. Mirrors
5
+ * the structure of `resources/index.ts` so callers reach for one
6
+ * import path and don't have to spelunk into the submodules.
7
+ */
8
+ export type { Shortcut, ShortcutContext, ShortcutDescriptor, ShortcutDeviceFacade, ShortcutErrorCode, ShortcutFailure, ShortcutJsonSchema, ShortcutKind, ShortcutLogger, ShortcutMcpRuntime, ShortcutPlatform, ShortcutResourceFacade, ShortcutResult, ShortcutSuccess, } from "./types.js";
9
+ export { ShortcutRegistry } from "./registry.js";
10
+ export { ShortcutRouter, type InvokeCallerContext, type ShortcutInvoker, } from "./router.js";
11
+ export { DownloadToDeviceShortcut, FindAppPackageShortcut, OpenDeeplinkShortcut, SetClipboardShortcut, registerBuiltinShortcuts, } from "./builtins/index.js";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * shortcuts/ — Hybrid Action Space barrel.
3
+ *
4
+ * Public surface for Phase 2 of the GUI-Shortcut Hybrid Plan. Mirrors
5
+ * the structure of `resources/index.ts` so callers reach for one
6
+ * import path and don't have to spelunk into the submodules.
7
+ */
8
+ export { ShortcutRegistry } from "./registry.js";
9
+ export { ShortcutRouter, } from "./router.js";
10
+ export { DownloadToDeviceShortcut, FindAppPackageShortcut, OpenDeeplinkShortcut, SetClipboardShortcut, registerBuiltinShortcuts, } from "./builtins/index.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shortcuts/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAmBH,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EACL,cAAc,GAGf,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Shortcut registry — owns the in-process catalogue of shortcuts.
3
+ *
4
+ * The registry is intentionally tiny: register / unregister / list /
5
+ * get. There is no recall yet (D7) — the .pi extension reads `list()`
6
+ * once at session start and synthesises an outer-LLM tool descriptor
7
+ * for every entry.
8
+ *
9
+ * Lifecycle:
10
+ * 1. Bootstrap constructs ONE registry per device-agent process.
11
+ * 2. Each phase-2 shortcut module exports a `register(reg)` helper
12
+ * that calls `reg.register(new MyShortcut())`. Bootstrap fans out
13
+ * to every helper so adding a shortcut is one import + one
14
+ * register call away.
15
+ * 3. The .pi extension reads `reg.list()` and emits descriptors.
16
+ * 4. The router (`router.ts`) calls `reg.get(id)` on every invoke.
17
+ *
18
+ * Recall seam:
19
+ *
20
+ * `recallCandidates(taskHint)` is a no-op stub that returns the full
21
+ * list. Phase 3+ can swap the implementation for a real recall (e.g.
22
+ * embedding similarity over `descriptor.description`) without
23
+ * touching call sites.
24
+ */
25
+ import type { Shortcut } from "./types.js";
26
+ export declare class ShortcutRegistry {
27
+ private readonly entries;
28
+ /**
29
+ * Register a shortcut. Throws on duplicate id — duplicate registrations
30
+ * almost always indicate a bootstrap-ordering bug, and the registry
31
+ * is process-wide so silent overwrites would be invisible.
32
+ */
33
+ register<TArgs, TOut>(shortcut: Shortcut<TArgs, TOut>): void;
34
+ /**
35
+ * Remove a shortcut by id. Returns true if the id existed. Mostly
36
+ * used in tests; the production process never tears shortcuts down.
37
+ */
38
+ unregister(id: string): boolean;
39
+ /** Look up a shortcut by id. Undefined when missing. */
40
+ get(id: string): Shortcut<unknown, unknown> | undefined;
41
+ /**
42
+ * Return every registered shortcut in insertion order. The .pi
43
+ * extension uses this for tool-descriptor generation; tests use it
44
+ * for snapshot assertions. The returned array is a copy so callers
45
+ * are free to filter / sort / iterate without disturbing the
46
+ * registry's internal map.
47
+ */
48
+ list(): Shortcut<unknown, unknown>[];
49
+ /**
50
+ * Future recall hook. Phase 2 returns the full list verbatim — the
51
+ * orchestrator gets every shortcut every time, which is fine at 4
52
+ * entries (D7). Phase 3+ may implement a real recall by replacing
53
+ * this implementation; downstream code never has to change.
54
+ */
55
+ recallCandidates(_taskHint?: string): Shortcut<unknown, unknown>[];
56
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Shortcut registry — owns the in-process catalogue of shortcuts.
3
+ *
4
+ * The registry is intentionally tiny: register / unregister / list /
5
+ * get. There is no recall yet (D7) — the .pi extension reads `list()`
6
+ * once at session start and synthesises an outer-LLM tool descriptor
7
+ * for every entry.
8
+ *
9
+ * Lifecycle:
10
+ * 1. Bootstrap constructs ONE registry per device-agent process.
11
+ * 2. Each phase-2 shortcut module exports a `register(reg)` helper
12
+ * that calls `reg.register(new MyShortcut())`. Bootstrap fans out
13
+ * to every helper so adding a shortcut is one import + one
14
+ * register call away.
15
+ * 3. The .pi extension reads `reg.list()` and emits descriptors.
16
+ * 4. The router (`router.ts`) calls `reg.get(id)` on every invoke.
17
+ *
18
+ * Recall seam:
19
+ *
20
+ * `recallCandidates(taskHint)` is a no-op stub that returns the full
21
+ * list. Phase 3+ can swap the implementation for a real recall (e.g.
22
+ * embedding similarity over `descriptor.description`) without
23
+ * touching call sites.
24
+ */
25
+ export class ShortcutRegistry {
26
+ entries = new Map();
27
+ /**
28
+ * Register a shortcut. Throws on duplicate id — duplicate registrations
29
+ * almost always indicate a bootstrap-ordering bug, and the registry
30
+ * is process-wide so silent overwrites would be invisible.
31
+ */
32
+ register(shortcut) {
33
+ const id = shortcut.descriptor.id;
34
+ if (this.entries.has(id)) {
35
+ throw new Error(`ShortcutRegistry: duplicate shortcut id "${id}" — already registered`);
36
+ }
37
+ this.entries.set(id, shortcut);
38
+ }
39
+ /**
40
+ * Remove a shortcut by id. Returns true if the id existed. Mostly
41
+ * used in tests; the production process never tears shortcuts down.
42
+ */
43
+ unregister(id) {
44
+ return this.entries.delete(id);
45
+ }
46
+ /** Look up a shortcut by id. Undefined when missing. */
47
+ get(id) {
48
+ return this.entries.get(id);
49
+ }
50
+ /**
51
+ * Return every registered shortcut in insertion order. The .pi
52
+ * extension uses this for tool-descriptor generation; tests use it
53
+ * for snapshot assertions. The returned array is a copy so callers
54
+ * are free to filter / sort / iterate without disturbing the
55
+ * registry's internal map.
56
+ */
57
+ list() {
58
+ return Array.from(this.entries.values());
59
+ }
60
+ /**
61
+ * Future recall hook. Phase 2 returns the full list verbatim — the
62
+ * orchestrator gets every shortcut every time, which is fine at 4
63
+ * entries (D7). Phase 3+ may implement a real recall by replacing
64
+ * this implementation; downstream code never has to change.
65
+ */
66
+ recallCandidates(_taskHint) {
67
+ return this.list();
68
+ }
69
+ }
70
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/shortcuts/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,MAAM,OAAO,gBAAgB;IACV,OAAO,GAAG,IAAI,GAAG,EAAsC,CAAC;IAEzE;;;;OAIG;IACH,QAAQ,CAAc,QAA+B;QACnD,MAAM,EAAE,GAAG,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,4CAA4C,EAAE,wBAAwB,CACvE,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,QAAsC,CAAC,CAAC;IAC/D,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,wDAAwD;IACxD,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;OAMG;IACH,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACH,gBAAgB,CAAC,SAAkB;QACjC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC;CACF"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Shortcut router / invoker — the single call site every entry point
3
+ * (extension, ACP plugin, future programmatic API) goes through.
4
+ *
5
+ * Responsibilities:
6
+ *
7
+ * 1. **Lookup** — resolve `id` against the registry; return
8
+ * `invalid_args` when the id is unknown so the LLM gets a
9
+ * structured error instead of a 500.
10
+ * 2. **Platform gate** — check the active device's `info.os` /
11
+ * `info.type` against the shortcut's `descriptor.platforms`.
12
+ * Mismatch → `unsupported_platform`. `"any"` always passes.
13
+ * 3. **Timeout** — wrap the call in a per-shortcut AbortController
14
+ * that honors both `descriptor.timeoutMs` and the host's
15
+ * `AbortSignal`. The two are merged by linking listeners.
16
+ * 4. **Failure shaping** — translate thrown exceptions into
17
+ * `ShortcutFailure { code: "internal_error" }` so the LLM never
18
+ * sees a stack trace. Aborts (host cancel or local timeout) are
19
+ * mapped to `timeout`.
20
+ * 5. **Telemetry** — emit a structured pino log line on every
21
+ * invoke (`event: "shortcut.invoke"`, with id / outcome /
22
+ * durationMs). The label set is the same closed vocabulary as
23
+ * the metric `device_agent_shortcut_invocation_total` (`ok` plus
24
+ * every `ShortcutErrorCode`), so a future Prometheus shim can
25
+ * derive the counter directly from log lines.
26
+ *
27
+ * Why a router and not just direct `shortcut.execute` calls?
28
+ *
29
+ * The plan deliberately separates the registry (catalogue) from the
30
+ * router (call-time concerns). Tests can construct a registry
31
+ * without a router; the router can be swapped (e.g. a future
32
+ * recall-aware variant) without rewriting every call site. The
33
+ * extension only depends on `ShortcutInvoker` — see android-tools.ts.
34
+ */
35
+ import type { Logger } from "../logger/index.js";
36
+ import type { ShortcutContext, ShortcutResult } from "./types.js";
37
+ import type { ShortcutRegistry } from "./registry.js";
38
+ import type { ShortcutMemoryStore } from "../agent-runtime/shortcuts/index.js";
39
+ export interface ShortcutInvoker {
40
+ invoke<TOut = unknown>(id: string, args: unknown, callerCtx: InvokeCallerContext): Promise<ShortcutResult<TOut>>;
41
+ /** Expose the underlying registry for descriptor generation. */
42
+ readonly registry: ShortcutRegistry;
43
+ }
44
+ export interface ShortcutRouterOptions {
45
+ /**
46
+ * Phase 3 telemetry sink. When provided, every invoke increments the
47
+ * matching counter via `recordSuccess` / `recordFailure`. Failures
48
+ * inside the store are swallowed — telemetry must never break the
49
+ * shortcut path.
50
+ */
51
+ memoryStore?: ShortcutMemoryStore;
52
+ }
53
+ /**
54
+ * Minimal context the caller is required to supply on every invoke.
55
+ * The router fills in the per-call AbortSignal merge and constructs
56
+ * the final `ShortcutContext` so the shortcut author never has to
57
+ * thread its own controller chain.
58
+ */
59
+ export interface InvokeCallerContext {
60
+ abortSignal: AbortSignal;
61
+ log: Logger;
62
+ /** Optional MCP runtime forwarded into `ShortcutContext.mcp`. */
63
+ mcp?: ShortcutContext["mcp"];
64
+ /** Optional device facade forwarded into `ShortcutContext.device`. */
65
+ device?: ShortcutContext["device"];
66
+ /** Optional resource facade forwarded into `ShortcutContext.resources`. */
67
+ resources?: ShortcutContext["resources"];
68
+ /**
69
+ * Optional digest of the originating user task — used as the memory
70
+ * store key. Callers SHOULD provide this when memory recording is
71
+ * enabled; absent, the router records under an empty pattern (still
72
+ * usable as a global "shortcut X failure rate" counter, just no
73
+ * task-specific bucketing).
74
+ */
75
+ taskPattern?: string;
76
+ }
77
+ export declare class ShortcutRouter implements ShortcutInvoker {
78
+ readonly registry: ShortcutRegistry;
79
+ private readonly memoryStore?;
80
+ constructor(registry: ShortcutRegistry, opts?: ShortcutRouterOptions);
81
+ invoke<TOut = unknown>(id: string, args: unknown, caller: InvokeCallerContext): Promise<ShortcutResult<TOut>>;
82
+ /**
83
+ * Phase 3 — fire-and-forget telemetry write. Errors are swallowed by
84
+ * the caller via `.catch(() => undefined)` so a malfunctioning store
85
+ * never blocks the shortcut return path. We still log inside the
86
+ * store on the way down via its own logger when wired by bootstrap.
87
+ */
88
+ private recordMemory;
89
+ private checkPlatform;
90
+ private logOutcome;
91
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Shortcut router / invoker — the single call site every entry point
3
+ * (extension, ACP plugin, future programmatic API) goes through.
4
+ *
5
+ * Responsibilities:
6
+ *
7
+ * 1. **Lookup** — resolve `id` against the registry; return
8
+ * `invalid_args` when the id is unknown so the LLM gets a
9
+ * structured error instead of a 500.
10
+ * 2. **Platform gate** — check the active device's `info.os` /
11
+ * `info.type` against the shortcut's `descriptor.platforms`.
12
+ * Mismatch → `unsupported_platform`. `"any"` always passes.
13
+ * 3. **Timeout** — wrap the call in a per-shortcut AbortController
14
+ * that honors both `descriptor.timeoutMs` and the host's
15
+ * `AbortSignal`. The two are merged by linking listeners.
16
+ * 4. **Failure shaping** — translate thrown exceptions into
17
+ * `ShortcutFailure { code: "internal_error" }` so the LLM never
18
+ * sees a stack trace. Aborts (host cancel or local timeout) are
19
+ * mapped to `timeout`.
20
+ * 5. **Telemetry** — emit a structured pino log line on every
21
+ * invoke (`event: "shortcut.invoke"`, with id / outcome /
22
+ * durationMs). The label set is the same closed vocabulary as
23
+ * the metric `device_agent_shortcut_invocation_total` (`ok` plus
24
+ * every `ShortcutErrorCode`), so a future Prometheus shim can
25
+ * derive the counter directly from log lines.
26
+ *
27
+ * Why a router and not just direct `shortcut.execute` calls?
28
+ *
29
+ * The plan deliberately separates the registry (catalogue) from the
30
+ * router (call-time concerns). Tests can construct a registry
31
+ * without a router; the router can be swapped (e.g. a future
32
+ * recall-aware variant) without rewriting every call site. The
33
+ * extension only depends on `ShortcutInvoker` — see android-tools.ts.
34
+ */
35
+ const DEFAULT_TIMEOUT_MS = 30_000;
36
+ export class ShortcutRouter {
37
+ registry;
38
+ memoryStore;
39
+ constructor(registry, opts = {}) {
40
+ this.registry = registry;
41
+ if (opts.memoryStore !== undefined) {
42
+ this.memoryStore = opts.memoryStore;
43
+ }
44
+ }
45
+ async invoke(id, args, caller) {
46
+ const startedAt = Date.now();
47
+ const sc = this.registry.get(id);
48
+ if (!sc) {
49
+ const fail = makeFailure("invalid_args", `unknown shortcut id: ${id}`);
50
+ this.logOutcome(caller.log, id, fail, Date.now() - startedAt);
51
+ return fail;
52
+ }
53
+ const platformErr = await this.checkPlatform(sc, caller);
54
+ if (platformErr) {
55
+ this.logOutcome(caller.log, id, platformErr, Date.now() - startedAt);
56
+ return platformErr;
57
+ }
58
+ const timeoutMs = sc.descriptor.timeoutMs ?? DEFAULT_TIMEOUT_MS;
59
+ const localCtl = new AbortController();
60
+ const onHostAbort = () => localCtl.abort();
61
+ if (caller.abortSignal.aborted)
62
+ localCtl.abort();
63
+ else
64
+ caller.abortSignal.addEventListener("abort", onHostAbort, { once: true });
65
+ const timer = setTimeout(() => localCtl.abort(), timeoutMs);
66
+ const ctx = {
67
+ ...(caller.mcp !== undefined ? { mcp: caller.mcp } : {}),
68
+ ...(caller.device !== undefined ? { device: caller.device } : {}),
69
+ ...(caller.resources !== undefined ? { resources: caller.resources } : {}),
70
+ abortSignal: localCtl.signal,
71
+ log: caller.log,
72
+ };
73
+ let outcome;
74
+ try {
75
+ const out = await sc.execute(args, ctx);
76
+ outcome = out;
77
+ }
78
+ catch (e) {
79
+ // Aborts (host cancel + local timeout) collapse to "timeout";
80
+ // anything else is an unhandled bug and surfaces as
81
+ // internal_error so the LLM still gets a structured failure.
82
+ if (localCtl.signal.aborted) {
83
+ outcome = makeFailure("timeout", `shortcut timed out after ${timeoutMs}ms`);
84
+ }
85
+ else {
86
+ const message = e instanceof Error ? e.message : String(e);
87
+ outcome = makeFailure("internal_error", message);
88
+ }
89
+ }
90
+ finally {
91
+ caller.abortSignal.removeEventListener("abort", onHostAbort);
92
+ clearTimeout(timer);
93
+ }
94
+ const durationMs = Date.now() - startedAt;
95
+ const stamped = withDuration(outcome, durationMs);
96
+ this.logOutcome(caller.log, id, stamped, durationMs);
97
+ this.recordMemory(id, stamped, caller).catch(() => undefined);
98
+ return stamped;
99
+ }
100
+ /**
101
+ * Phase 3 — fire-and-forget telemetry write. Errors are swallowed by
102
+ * the caller via `.catch(() => undefined)` so a malfunctioning store
103
+ * never blocks the shortcut return path. We still log inside the
104
+ * store on the way down via its own logger when wired by bootstrap.
105
+ */
106
+ async recordMemory(id, res, caller) {
107
+ if (!this.memoryStore)
108
+ return;
109
+ const pattern = caller.taskPattern ?? "";
110
+ if (res.ok) {
111
+ await this.memoryStore.recordSuccess(pattern, id);
112
+ }
113
+ else {
114
+ await this.memoryStore.recordFailure(pattern, id, res.code);
115
+ }
116
+ }
117
+ async checkPlatform(sc, caller) {
118
+ const platforms = sc.descriptor.platforms;
119
+ if (platforms.includes("any"))
120
+ return null;
121
+ if (!caller.device) {
122
+ // No device facade — we can't check, so fail closed.
123
+ return makeFailure("unsupported_platform", `shortcut "${sc.descriptor.id}" requires a device but none is attached`);
124
+ }
125
+ let info;
126
+ try {
127
+ info = await caller.device.getInfo();
128
+ }
129
+ catch (e) {
130
+ return makeFailure("unsupported_platform", `shortcut "${sc.descriptor.id}" platform check failed: ${e.message}`);
131
+ }
132
+ const tag = (info.type ?? info.os ?? "").toLowerCase();
133
+ const matches = platforms.some((p) => p === "any" || tag.includes(p));
134
+ if (matches)
135
+ return null;
136
+ return makeFailure("unsupported_platform", `shortcut "${sc.descriptor.id}" not supported on platform "${tag}"`);
137
+ }
138
+ logOutcome(log, id, res, durationMs) {
139
+ log.info({
140
+ event: "shortcut.invoke",
141
+ shortcut_id: id,
142
+ result: res.ok ? "ok" : res.code,
143
+ durationMs,
144
+ }, "shortcut.invoke");
145
+ }
146
+ }
147
+ /* -------------------------------------------------------------------- */
148
+ /* Helpers */
149
+ /* -------------------------------------------------------------------- */
150
+ function makeFailure(code, message) {
151
+ return { ok: false, code, message };
152
+ }
153
+ function withDuration(res, durationMs) {
154
+ if (res.ok)
155
+ return { ...res, durationMs };
156
+ return { ...res, durationMs };
157
+ }
158
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/shortcuts/router.ts"],"names":[],"mappings":"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"}