@elizaos/app-core 2.0.3-beta.2 → 2.0.3-beta.4

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 (361) hide show
  1. package/agent-bridge.d.ts +5 -5
  2. package/api/auth/audit.d.ts +1 -1
  3. package/api/auth/auth-context.d.ts +1 -1
  4. package/api/auth/bootstrap-token.d.ts +1 -1
  5. package/api/auth/sessions.d.ts +1 -1
  6. package/api/auth-bootstrap-routes.d.ts +1 -1
  7. package/api/auth-pairing-routes.d.ts +1 -1
  8. package/api/auth-pairing-routes.d.ts.map +1 -1
  9. package/api/auth-pairing-routes.js +2 -3
  10. package/api/auth-session-routes.d.ts +2 -2
  11. package/api/auth.d.ts +1 -1
  12. package/api/automations-compat-routes.d.ts +1 -1
  13. package/api/background-tasks-routes.d.ts +1 -1
  14. package/api/catalog-routes.d.ts +1 -1
  15. package/api/cloud-voice-routes.d.ts +1 -1
  16. package/api/compat-route-shared.d.ts +12 -5
  17. package/api/compat-route-shared.d.ts.map +1 -1
  18. package/api/compat-route-shared.js +22 -187
  19. package/api/database-rows-compat-routes.d.ts +1 -1
  20. package/api/dev-compat-routes.d.ts +1 -1
  21. package/api/dev-route-catalog.d.ts.map +1 -1
  22. package/api/dev-route-catalog.js +20 -0
  23. package/api/drop-status-compat-route.d.ts +3 -0
  24. package/api/drop-status-compat-route.d.ts.map +1 -0
  25. package/api/drop-status-compat-route.js +12 -0
  26. package/api/first-run-routes.d.ts +1 -1
  27. package/api/internal-routes.d.ts +1 -1
  28. package/api/runtime-mode-routes.d.ts +1 -1
  29. package/api/secrets-manager-routes.d.ts.map +1 -1
  30. package/api/sensitive-request-routes.d.ts +2 -2
  31. package/api/server-config-filter.d.ts.map +1 -1
  32. package/api/server-config-filter.js +0 -1
  33. package/api/server-first-run-helpers.d.ts.map +1 -1
  34. package/api/server-first-run-helpers.js +0 -3
  35. package/api/server.d.ts +8 -8
  36. package/api/server.d.ts.map +1 -1
  37. package/api/server.js +13 -59
  38. package/api/training-benchmarks.d.ts +1 -1
  39. package/api/training-benchmarks.d.ts.map +1 -1
  40. package/api/training-benchmarks.js +31 -9
  41. package/api/workbench-compat-routes.d.ts +1 -1
  42. package/benchmark/server-utils.d.ts +2 -2
  43. package/browser.d.ts +4 -4
  44. package/cli/plugins-cli.d.ts.map +1 -1
  45. package/cli/plugins-cli.js +5 -0
  46. package/cli/program/register.auth.d.ts +27 -1
  47. package/cli/program/register.auth.d.ts.map +1 -1
  48. package/cli/program/register.auth.js +187 -0
  49. package/cli/program/register.dashboard.d.ts.map +1 -1
  50. package/cli/program/register.dashboard.js +11 -1
  51. package/cli/program.d.ts +1 -1
  52. package/first-run/first-run-config.d.ts +1 -1
  53. package/index.d.ts +46 -47
  54. package/index.d.ts.map +1 -1
  55. package/index.js +3 -7
  56. package/package.json +42 -36
  57. package/packaging/PUBLISHING_GUIDE.md +20 -20
  58. package/platform/elizaos-agent-browser-stub.d.ts +0 -1
  59. package/platform/elizaos-agent-browser-stub.d.ts.map +1 -1
  60. package/platform/elizaos-agent-browser-stub.js +0 -1
  61. package/platform/ios-runtime-bridge.d.ts.map +1 -1
  62. package/platform/ios-runtime-bridge.js +0 -1
  63. package/platform/native-plugin-entrypoints.d.ts +2 -2
  64. package/platforms/android/app/build.gradle +30 -7
  65. package/platforms/android/app/src/main/elizavoice-jni/elizavoice-jni.cpp +179 -35
  66. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAgentService.java +60 -32
  67. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaBionicInferenceServer.java +405 -65
  68. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoiceNative.java +35 -0
  69. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoicePlugin.java +13 -6
  70. package/platforms/android/app/src/main/res/drawable/splash.png +0 -0
  71. package/platforms/android/app/src/main/res/drawable-land-hdpi/splash.png +0 -0
  72. package/platforms/android/app/src/main/res/drawable-land-mdpi/splash.png +0 -0
  73. package/platforms/android/app/src/main/res/drawable-land-xhdpi/splash.png +0 -0
  74. package/platforms/android/app/src/main/res/drawable-land-xxhdpi/splash.png +0 -0
  75. package/platforms/android/app/src/main/res/drawable-land-xxxhdpi/splash.png +0 -0
  76. package/platforms/android/app/src/main/res/drawable-port-hdpi/splash.png +0 -0
  77. package/platforms/android/app/src/main/res/drawable-port-mdpi/splash.png +0 -0
  78. package/platforms/android/app/src/main/res/drawable-port-xhdpi/splash.png +0 -0
  79. package/platforms/android/app/src/main/res/drawable-port-xxhdpi/splash.png +0 -0
  80. package/platforms/android/app/src/main/res/drawable-port-xxxhdpi/splash.png +0 -0
  81. package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  82. package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
  83. package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png +0 -0
  84. package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  85. package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  86. package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
  87. package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png +0 -0
  88. package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  89. package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  90. package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
  91. package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png +0 -0
  92. package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  93. package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  94. package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
  95. package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png +0 -0
  96. package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  97. package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  98. package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
  99. package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png +0 -0
  100. package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  101. package/platforms/android/app/src/main/res/values/colors.xml +5 -1
  102. package/platforms/android/app/src/main/res/values/ic_launcher_background.xml +1 -1
  103. package/platforms/android/app/src/main/res/values/styles.xml +4 -1
  104. package/platforms/electrobun/electrobun.config.ts +0 -1
  105. package/platforms/electrobun/native/macos/window-effects.mm +4 -0
  106. package/platforms/electrobun/package.json +11 -9
  107. package/platforms/electrobun/remotes/local-model/src/bun/eliza1-catalog.ts +1 -1
  108. package/platforms/electrobun/remotes/runtime/src/dev/phase2-smoke.ts +10 -5
  109. package/platforms/electrobun/remotes/runtime/src/dev/phase3-smoke.ts +11 -15
  110. package/platforms/electrobun/src/application-menu.ts +0 -7
  111. package/platforms/electrobun/src/desktop-http-request.test.ts +30 -1
  112. package/platforms/electrobun/src/desktop-http-request.ts +14 -2
  113. package/platforms/electrobun/src/desktop-test-bridge-server.ts +28 -0
  114. package/platforms/electrobun/src/fatal-shutdown.test.ts +3 -7
  115. package/platforms/electrobun/src/index.ts +64 -13
  116. package/platforms/electrobun/src/lifecycle/api-base-owner.test.ts +83 -0
  117. package/platforms/electrobun/src/lifecycle/api-base-owner.ts +37 -16
  118. package/platforms/electrobun/src/native/agent.ts +28 -17
  119. package/platforms/electrobun/src/native/credentials.ts +6 -1
  120. package/platforms/electrobun/src/native/desktop-window.test.ts +142 -26
  121. package/platforms/electrobun/src/native/desktop.ts +8 -4
  122. package/platforms/electrobun/src/native/index.ts +6 -0
  123. package/platforms/electrobun/src/native/remote-plugin-host.ts +18 -8
  124. package/platforms/electrobun/src/preload.js +1 -1
  125. package/platforms/electrobun/src/voice/voice-live-validation.test.ts +10 -5
  126. package/platforms/electrobun/src/voice/voice-runtime-adapter.ts +3 -2
  127. package/platforms/electrobun/src/voice/voice-service.test.ts +26 -0
  128. package/platforms/electrobun/src/voice/voice-service.ts +57 -17
  129. package/platforms/electrobun/tsconfig.json +17 -1
  130. package/platforms/ios/App/App/Base.lproj/LaunchScreen.storyboard +4 -6
  131. package/registry/index.d.ts +1 -6
  132. package/registry/index.d.ts.map +1 -1
  133. package/registry/index.js +9 -101
  134. package/runtime/android-avf-microdroid-bridge.d.ts +1 -1
  135. package/runtime/bundled-fused-lib.d.ts +36 -0
  136. package/runtime/bundled-fused-lib.d.ts.map +1 -0
  137. package/runtime/bundled-fused-lib.js +77 -0
  138. package/runtime/channel-plugin-map.d.ts +1 -5
  139. package/runtime/channel-plugin-map.d.ts.map +1 -1
  140. package/runtime/channel-plugin-map.js +11 -31
  141. package/runtime/desktop/index.d.ts +5 -5
  142. package/runtime/dev-server.js +11 -2
  143. package/runtime/eliza.d.ts.map +1 -1
  144. package/runtime/eliza.js +18 -8
  145. package/runtime/mode/route-mode-guard.d.ts +1 -1
  146. package/runtime/mode/route-mode-matrix.d.ts +1 -1
  147. package/runtime/voice-warmup.d.ts +4 -19
  148. package/runtime/voice-warmup.d.ts.map +1 -1
  149. package/runtime/voice-warmup.js +4 -14
  150. package/scripts/aosp/README.md +10 -1
  151. package/scripts/aosp/compile-libllama-paths.mjs +110 -0
  152. package/scripts/aosp/compile-libllama-zig-pin.test.mjs +147 -0
  153. package/scripts/aosp/compile-libllama.mjs +377 -81
  154. package/scripts/aosp/compile-libllama.test.mjs +133 -0
  155. package/scripts/aosp/compile-shim.mjs +21 -1
  156. package/scripts/aosp/deploy-pixel.mjs +1 -1
  157. package/scripts/aosp/stage-default-models.mjs +24 -31
  158. package/scripts/aosp/stage-default-models.test.mjs +23 -0
  159. package/scripts/assert-required-bundled-packages.test.ts +22 -1
  160. package/scripts/build-helpers/verify-fused-symbols.mjs +33 -0
  161. package/scripts/build-helpers/verify-fused-symbols.test.mjs +0 -0
  162. package/scripts/build-image.sh +1 -3
  163. package/scripts/build-llama-cpp-mtp.mjs +17 -16
  164. package/scripts/check-i18n.mjs +0 -1
  165. package/scripts/copy-runtime-node-modules.ts +147 -0
  166. package/scripts/desktop-build.mjs +317 -4
  167. package/scripts/docker-ci-smoke.sh +33 -8
  168. package/scripts/ensure-type-package-aliases.mjs +1 -1
  169. package/scripts/ios-xcframework/run-physical-device-smoke.mjs +1 -1
  170. package/scripts/lib/agent-source-watcher.mjs +0 -1
  171. package/scripts/lib/artifact-staleness.d.mts +33 -0
  172. package/scripts/lib/artifact-staleness.mjs +122 -0
  173. package/scripts/lib/artifact-staleness.test.mts +98 -0
  174. package/scripts/lib/duet-bridge.mjs +1 -1
  175. package/scripts/lib/ios-plist-url-scheme.mjs +80 -0
  176. package/scripts/lib/mobile-build-decisions.mjs +97 -0
  177. package/scripts/lib/renderer-build-manifest.d.mts +65 -0
  178. package/scripts/lib/renderer-build-manifest.mjs +257 -0
  179. package/scripts/lib/renderer-build-manifest.test.mts +277 -0
  180. package/scripts/lib/stage-android-agent.mjs +13 -4
  181. package/scripts/lib/verify-ondevice-artifact.d.mts +16 -0
  182. package/scripts/lib/verify-ondevice-artifact.mjs +61 -0
  183. package/scripts/lib/verify-ondevice-artifact.test.mts +98 -0
  184. package/scripts/lib/websocket-pending-queue.ts +92 -0
  185. package/scripts/link-docker-local-app-packages.mjs +6 -0
  186. package/scripts/playwright-ui-live-stack.ts +430 -144
  187. package/scripts/playwright-ui-smoke-api-stub.mjs +160 -168
  188. package/scripts/run-local-plugin-live-smoke.mjs +1 -6
  189. package/scripts/run-mobile-build-brand-separation.test.mts +33 -0
  190. package/scripts/run-mobile-build-ios-engine-gate.test.mjs +85 -0
  191. package/scripts/run-mobile-build-mtp-staleness.test.mts +198 -0
  192. package/scripts/run-mobile-build.mjs +408 -86
  193. package/scripts/serve-real-local-agent.ts +72 -0
  194. package/scripts/stage-desktop-fused-lib.mjs +43 -14
  195. package/scripts/verify-ondevice-artifact.mjs +111 -0
  196. package/scripts/voice-attribution-smoke.ts +144 -38
  197. package/scripts/voice-duet.mjs +6 -6
  198. package/scripts/voice-e2e-hardware.ts +22 -16
  199. package/scripts/voice-interactive.mjs +16 -45
  200. package/security/agent-vault-id.d.ts +1 -1
  201. package/security/platform-secure-store-node.d.ts +1 -1
  202. package/services/ambient-audio/consent.d.ts +1 -1
  203. package/services/ambient-audio/index.d.ts +6 -6
  204. package/services/ambient-audio/replay-buffer.d.ts +1 -1
  205. package/services/ambient-audio/response-gate.d.ts +1 -1
  206. package/services/ambient-audio/service.d.ts +3 -3
  207. package/services/connector-target-catalog.d.ts +1 -1
  208. package/services/sensitive-requests/index.d.ts +6 -6
  209. package/services/steward-sidecar/wallet-setup.d.ts +1 -1
  210. package/services/steward-sidecar.d.ts +3 -3
  211. package/services/tunnel-to-mobile/index.d.ts +1 -1
  212. package/services/vault-bootstrap.d.ts.map +1 -1
  213. package/services/vault-bootstrap.js +14 -10
  214. package/services/voice-profiles/diarization-pipeline.d.ts +1 -1
  215. package/services/voice-profiles/index.d.ts +11 -11
  216. package/services/voice-profiles/owner-confidence.d.ts +1 -1
  217. package/services/voice-profiles/private-challenge.d.ts +1 -1
  218. package/services/voice-profiles/store.d.ts +1 -1
  219. package/test/helpers/live-provider.test.ts +91 -1
  220. package/test/helpers/live-provider.ts +195 -51
  221. package/test/scripts/websocket-pending-queue.test.ts +119 -0
  222. package/test-support/test-helpers.d.ts +0 -33
  223. package/test-support/test-helpers.d.ts.map +1 -1
  224. package/test-support/test-helpers.js +81 -189
  225. package/ui-compat.d.ts +1 -0
  226. package/ui-compat.d.ts.map +1 -1
  227. package/ui-compat.js +4 -0
  228. package/platforms/electrobun/docs/convergence-audit.json +0 -3505
  229. package/platforms/electrobun/docs/convergence-audit.md +0 -694
  230. package/platforms/electrobun/scripts/ensure-whisper-gguf.sh +0 -55
  231. package/platforms/electrobun/scripts/ensure-whisper-model.sh +0 -35
  232. package/platforms/electrobun/scripts/generate-convergence-audit.ts +0 -1203
  233. package/platforms/electrobun/src/native/whisper-env.test.ts +0 -71
  234. package/platforms/electrobun/src/native/whisper-env.ts +0 -68
  235. package/registry/app-registry.d.ts +0 -14
  236. package/registry/app-registry.d.ts.map +0 -1
  237. package/registry/app-registry.js +0 -29
  238. package/registry/entries/apps/app-polymarket.json +0 -31
  239. package/registry/entries/apps/clawville.json +0 -27
  240. package/registry/entries/apps/companion.json +0 -28
  241. package/registry/entries/apps/database-viewer.json +0 -27
  242. package/registry/entries/apps/defense-of-the-agents.json +0 -27
  243. package/registry/entries/apps/documents.json +0 -30
  244. package/registry/entries/apps/feed.json +0 -27
  245. package/registry/entries/apps/hyperliquid.json +0 -31
  246. package/registry/entries/apps/log-viewer.json +0 -27
  247. package/registry/entries/apps/memory-viewer.json +0 -27
  248. package/registry/entries/apps/model-tester.json +0 -31
  249. package/registry/entries/apps/plugin-viewer.json +0 -27
  250. package/registry/entries/apps/relationship-viewer.json +0 -27
  251. package/registry/entries/apps/runtime-debugger.json +0 -27
  252. package/registry/entries/apps/shopify.json +0 -31
  253. package/registry/entries/apps/skills-viewer.json +0 -27
  254. package/registry/entries/apps/steward.json +0 -31
  255. package/registry/entries/apps/training.json +0 -54
  256. package/registry/entries/apps/trajectory-viewer.json +0 -27
  257. package/registry/entries/apps/vincent.json +0 -31
  258. package/registry/entries/connectors/bluebubbles.json +0 -99
  259. package/registry/entries/connectors/bluesky.json +0 -173
  260. package/registry/entries/connectors/discord.json +0 -119
  261. package/registry/entries/connectors/farcaster.json +0 -174
  262. package/registry/entries/connectors/feishu.json +0 -79
  263. package/registry/entries/connectors/google-chat.json +0 -120
  264. package/registry/entries/connectors/google.json +0 -82
  265. package/registry/entries/connectors/imessage.json +0 -96
  266. package/registry/entries/connectors/instagram.json +0 -64
  267. package/registry/entries/connectors/line.json +0 -86
  268. package/registry/entries/connectors/matrix.json +0 -94
  269. package/registry/entries/connectors/mattermost.json +0 -110
  270. package/registry/entries/connectors/msteams.json +0 -104
  271. package/registry/entries/connectors/nextcloud-talk.json +0 -104
  272. package/registry/entries/connectors/nostr.json +0 -70
  273. package/registry/entries/connectors/signal.json +0 -81
  274. package/registry/entries/connectors/slack.json +0 -102
  275. package/registry/entries/connectors/telegram.json +0 -71
  276. package/registry/entries/connectors/tlon.json +0 -94
  277. package/registry/entries/connectors/twitch.json +0 -110
  278. package/registry/entries/connectors/whatsapp.json +0 -113
  279. package/registry/entries/connectors/x.json +0 -231
  280. package/registry/entries/connectors/zalo.json +0 -112
  281. package/registry/entries/connectors/zalouser.json +0 -122
  282. package/registry/entries/plugins/agent-orchestrator.json +0 -33
  283. package/registry/entries/plugins/agent-skills.json +0 -72
  284. package/registry/entries/plugins/anthropic.json +0 -73
  285. package/registry/entries/plugins/app-control.json +0 -23
  286. package/registry/entries/plugins/auto-trader.json +0 -203
  287. package/registry/entries/plugins/background-runner.json +0 -26
  288. package/registry/entries/plugins/blooio.json +0 -102
  289. package/registry/entries/plugins/browser.json +0 -75
  290. package/registry/entries/plugins/cli.json +0 -40
  291. package/registry/entries/plugins/clipboard.json +0 -44
  292. package/registry/entries/plugins/coding-tools.json +0 -71
  293. package/registry/entries/plugins/commands.json +0 -63
  294. package/registry/entries/plugins/computeruse.json +0 -74
  295. package/registry/entries/plugins/copilot-proxy.json +0 -93
  296. package/registry/entries/plugins/directives.json +0 -63
  297. package/registry/entries/plugins/edge-tts.json +0 -97
  298. package/registry/entries/plugins/elevenlabs.json +0 -169
  299. package/registry/entries/plugins/elizacloud.json +0 -208
  300. package/registry/entries/plugins/evm.json +0 -134
  301. package/registry/entries/plugins/experience.json +0 -34
  302. package/registry/entries/plugins/facewear.json +0 -131
  303. package/registry/entries/plugins/form.json +0 -26
  304. package/registry/entries/plugins/github.json +0 -93
  305. package/registry/entries/plugins/gmail-watch.json +0 -25
  306. package/registry/entries/plugins/goals.json +0 -77
  307. package/registry/entries/plugins/google-genai.json +0 -106
  308. package/registry/entries/plugins/groq.json +0 -93
  309. package/registry/entries/plugins/hedera.json +0 -48
  310. package/registry/entries/plugins/inmemorydb.json +0 -25
  311. package/registry/entries/plugins/linear.json +0 -51
  312. package/registry/entries/plugins/local-inference.json +0 -137
  313. package/registry/entries/plugins/local-storage.json +0 -36
  314. package/registry/entries/plugins/localdb.json +0 -25
  315. package/registry/entries/plugins/mcp.json +0 -44
  316. package/registry/entries/plugins/memory.json +0 -124
  317. package/registry/entries/plugins/minecraft.json +0 -79
  318. package/registry/entries/plugins/moltbook.json +0 -83
  319. package/registry/entries/plugins/music.json +0 -155
  320. package/registry/entries/plugins/mysticism.json +0 -48
  321. package/registry/entries/plugins/nearai.json +0 -82
  322. package/registry/entries/plugins/ngrok.json +0 -69
  323. package/registry/entries/plugins/ollama.json +0 -96
  324. package/registry/entries/plugins/openai.json +0 -189
  325. package/registry/entries/plugins/openrouter.json +0 -188
  326. package/registry/entries/plugins/pdf.json +0 -26
  327. package/registry/entries/plugins/plugin-manager.json +0 -23
  328. package/registry/entries/plugins/prose.json +0 -48
  329. package/registry/entries/plugins/rlm.json +0 -26
  330. package/registry/entries/plugins/roblox.json +0 -88
  331. package/registry/entries/plugins/rss.json +0 -64
  332. package/registry/entries/plugins/s3-storage.json +0 -91
  333. package/registry/entries/plugins/scheduling.json +0 -35
  334. package/registry/entries/plugins/shell.json +0 -94
  335. package/registry/entries/plugins/social-alpha.json +0 -72
  336. package/registry/entries/plugins/tailscale.json +0 -81
  337. package/registry/entries/plugins/tee.json +0 -53
  338. package/registry/entries/plugins/todos.json +0 -26
  339. package/registry/entries/plugins/trajectory-logger.json +0 -33
  340. package/registry/entries/plugins/trust.json +0 -39
  341. package/registry/entries/plugins/tts.json +0 -71
  342. package/registry/entries/plugins/tunnel.json +0 -45
  343. package/registry/entries/plugins/twilio.json +0 -168
  344. package/registry/entries/plugins/vercel-ai-gateway.json +0 -128
  345. package/registry/entries/plugins/video.json +0 -23
  346. package/registry/entries/plugins/vision.json +0 -43
  347. package/registry/entries/plugins/webhooks.json +0 -23
  348. package/registry/entries/plugins/workflow.json +0 -25
  349. package/registry/entries/plugins/xai.json +0 -75
  350. package/registry/loader.d.ts +0 -28
  351. package/registry/loader.d.ts.map +0 -1
  352. package/registry/loader.js +0 -158
  353. package/registry/schema.d.ts +0 -1199
  354. package/registry/schema.d.ts.map +0 -1
  355. package/registry/schema.js +0 -300
  356. package/scripts/patches/llama-mobile-kokoro-tts.patch +0 -480
  357. package/scripts/release-workflow-drift.test.ts +0 -57
  358. package/test/helpers/i18n.ts +0 -5
  359. package/test/helpers/loopback.ts +0 -33
  360. package/test/helpers/react-test.ts +0 -40
  361. package/test/helpers/skip-without.ts +0 -53
@@ -64,16 +64,38 @@ import {
64
64
  resolveAppConfigPath,
65
65
  } from "./aosp/lib/load-variant-config.mjs";
66
66
  import { resolveMainAppDir } from "./lib/app-dir.mjs";
67
+ import { artifactStaleness } from "./lib/artifact-staleness.mjs";
67
68
  import {
68
69
  isCapacitorPlatformReady as isCapacitorPlatformReadyImpl,
69
70
  resolvePlatformTemplateRoot as resolvePlatformTemplateRootImpl,
70
71
  syncPlatformTemplateFiles as syncPlatformTemplateFilesImpl,
71
72
  } from "./lib/capacitor-platform-templates.mjs";
73
+ import { ensurePlistUrlScheme } from "./lib/ios-plist-url-scheme.mjs";
74
+ import {
75
+ androidUsesAppDirFor,
76
+ MTP_FORK_SRC_CANDIDATES,
77
+ mtpForceRebuildRequested,
78
+ mtpSliceReuse,
79
+ } from "./lib/mobile-build-decisions.mjs";
80
+ import {
81
+ assertStagedRendererMatchesBuild,
82
+ overlayFreshRendererIntoPublic,
83
+ readRendererBuildManifest,
84
+ } from "./lib/renderer-build-manifest.mjs";
72
85
  import { resolveRepoRootFromImportMeta } from "./lib/repo-root.mjs";
73
86
  import {
74
87
  RUNTIME_PROVENANCE_FILENAME,
75
88
  stageAndroidAgentRuntime,
76
89
  } from "./lib/stage-android-agent.mjs";
90
+ import { viteRendererBuildNeeded } from "./lib/vite-renderer-dist-stale.mjs";
91
+
92
+ export {
93
+ androidUsesAppDirFor,
94
+ MTP_FORK_SRC_CANDIDATES,
95
+ mtpBuilderRepoRoot,
96
+ mtpForceRebuildRequested,
97
+ mtpSliceReuse,
98
+ } from "./lib/mobile-build-decisions.mjs";
77
99
 
78
100
  // ── Paths ───────────────────────────────────────────────────────────────
79
101
 
@@ -103,10 +125,11 @@ const iosDir = path.join(appDir, "ios", "App");
103
125
  // treating app-core/platforms/android as a read-only template copied in by
104
126
  // overlayAndroid/patchAndroidGradle/syncAndroidAppActionsResources. That keeps
105
127
  // the two brands' Android builds fully separate.
106
- const androidDir =
107
- process.env.ELIZA_ANDROID_USE_APP_DIR === "1"
108
- ? path.join(appDir, "android")
109
- : path.join(appCoreRoot, "platforms", "android");
128
+ const androidBuildAppId = readAppIdentity().appId;
129
+ const androidUsesAppDir = androidUsesAppDirFor(androidBuildAppId, process.env);
130
+ const androidDir = androidUsesAppDir
131
+ ? path.join(appDir, "android")
132
+ : path.join(appCoreRoot, "platforms", "android");
110
133
  const localArtifactsDir = path.join(elizaRepoRoot, ".eliza-local", "artifacts");
111
134
  const androidSmsGatewayDebugApkArtifact = path.join(
112
135
  localArtifactsDir,
@@ -291,8 +314,23 @@ function withMobileBuildNodeOptions(env = process.env) {
291
314
  }
292
315
 
293
316
  function run(command, args, { cwd, env = process.env } = {}) {
317
+ // Windows: gradlew is gradlew.bat, and Node cannot spawn `./gradlew` (ENOENT)
318
+ // nor a .bat/.cmd directly (EINVAL since CVE-2024-27980). Translate
319
+ // ./gradlew -> the sibling gradlew.bat (resolved against cwd) and run any
320
+ // .bat/.cmd through cmd.exe with args as separate argv (no shell:true).
321
+ let spawnCmd = command;
322
+ let spawnArgs = args;
323
+ if (process.platform === "win32") {
324
+ if (command === "./gradlew" || command === "gradlew") {
325
+ spawnCmd = path.join(cwd || process.cwd(), "gradlew.bat");
326
+ }
327
+ if (/.(?:bat|cmd)$/i.test(spawnCmd)) {
328
+ spawnArgs = ["/d", "/s", "/c", spawnCmd, ...args];
329
+ spawnCmd = process.env.ComSpec || "cmd.exe";
330
+ }
331
+ }
294
332
  return new Promise((resolve, reject) => {
295
- const child = spawn(command, args, { cwd, env, stdio: "inherit" });
333
+ const child = spawn(spawnCmd, spawnArgs, { cwd, env, stdio: "inherit" });
296
334
  child.on("exit", (code, signal) => {
297
335
  if (signal) return reject(new Error(`${command} killed by ${signal}`));
298
336
  if ((code ?? 1) !== 0)
@@ -386,6 +424,11 @@ function resolveAndroidSdkRoot() {
386
424
  process.env.ANDROID_HOME,
387
425
  path.join(os.homedir(), "Library", "Android", "sdk"),
388
426
  path.join(os.homedir(), "Android", "Sdk"),
427
+ path.join(
428
+ process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local"),
429
+ "Android",
430
+ "Sdk",
431
+ ),
389
432
  ]);
390
433
  }
391
434
 
@@ -402,15 +445,66 @@ function resolveViteCli() {
402
445
  return viteCli;
403
446
  }
404
447
 
448
+ function javaMajorVersion(javaHome) {
449
+ if (!javaHome || !fs.existsSync(javaHome)) return null;
450
+ // `release` is the cheapest, most reliable source (no JVM spawn).
451
+ const releaseFile = path.join(javaHome, "release");
452
+ if (fs.existsSync(releaseFile)) {
453
+ const m = fs
454
+ .readFileSync(releaseFile, "utf8")
455
+ .match(/JAVA_VERSION="?(\d+)/);
456
+ if (m) return Number.parseInt(m[1], 10);
457
+ }
458
+ const javaBin = path.join(
459
+ javaHome,
460
+ "bin",
461
+ process.platform === "win32" ? "java.exe" : "java",
462
+ );
463
+ if (fs.existsSync(javaBin)) {
464
+ const r = spawnSync(javaBin, ["-version"], { encoding: "utf8" });
465
+ const m = `${r.stderr ?? ""}${r.stdout ?? ""}`.match(/version "?(\d+)/);
466
+ if (m) return Number.parseInt(m[1], 10);
467
+ }
468
+ return null;
469
+ }
470
+
471
+ // Auto-select a JDK >= 21 so a plain `build:android` "just works" with no
472
+ // JAVA_HOME juggling. JAVA_HOME is honored ONLY when it actually is >= 21;
473
+ // otherwise we fall through to the well-known JDK 21 install paths and finally
474
+ // scan /usr/lib/jvm. (AGP 9 + the Android toolchain require 21.)
405
475
  function resolveJavaHome() {
406
- return firstExisting([
476
+ const candidates = [
407
477
  process.env.JAVA_HOME,
408
478
  "/opt/homebrew/opt/openjdk@21",
409
479
  "/usr/local/opt/openjdk@21",
410
480
  "/usr/lib/jvm/temurin-21-jdk-amd64",
411
481
  "/usr/lib/jvm/java-21-openjdk-amd64",
412
482
  "/usr/lib/jvm/java-21-openjdk",
413
- ]);
483
+ ];
484
+ for (const candidate of candidates) {
485
+ if (candidate && (javaMajorVersion(candidate) ?? 0) >= 21) return candidate;
486
+ }
487
+ const jvmRoot = "/usr/lib/jvm";
488
+ if (fs.existsSync(jvmRoot)) {
489
+ for (const name of fs.readdirSync(jvmRoot)) {
490
+ const full = path.join(jvmRoot, name);
491
+ if ((javaMajorVersion(full) ?? 0) >= 21) return full;
492
+ }
493
+ }
494
+ if (process.platform === "win32") {
495
+ const programFiles = process.env.ProgramFiles || "C:\\Program Files";
496
+ for (const vendor of ["Eclipse Adoptium", "Microsoft", "Java", "Zulu"]) {
497
+ const vendorRoot = path.join(programFiles, vendor);
498
+ if (!fs.existsSync(vendorRoot)) continue;
499
+ for (const name of fs.readdirSync(vendorRoot)) {
500
+ const full = path.join(vendorRoot, name);
501
+ if ((javaMajorVersion(full) ?? 0) >= 21) return full;
502
+ }
503
+ }
504
+ }
505
+ // Nothing >= 21 found — return the first path that exists so the caller's
506
+ // "JDK 21 not found" error fires with a concrete (if wrong-version) hint.
507
+ return firstExisting(candidates);
414
508
  }
415
509
 
416
510
  function prependPath(env, entries) {
@@ -487,32 +581,6 @@ function insertBeforeRootPlistDictClose(content, insertion) {
487
581
  return `${content.slice(0, fallbackIndex)}${insertion}${content.slice(fallbackIndex + "</dict>".length)}`;
488
582
  }
489
583
 
490
- function ensurePlistUrlScheme(content, urlScheme) {
491
- const escapedScheme = escapeXmlText(urlScheme);
492
- const urlTypesRe =
493
- /(<key>CFBundleURLTypes<\/key>\s*<array>)([\s\S]*?)(\s*<\/array>)/;
494
- const entry = `
495
- <dict>
496
- <key>CFBundleURLName</key>
497
- <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
498
- <key>CFBundleURLSchemes</key>
499
- <array>
500
- <string>${escapedScheme}</string>
501
- </array>
502
- </dict>`;
503
- const match = content.match(urlTypesRe);
504
- if (!match) {
505
- return insertBeforeRootPlistDictClose(
506
- content,
507
- `\t<key>CFBundleURLTypes</key>\n\t<array>${entry}\n\t</array>\n</dict>`,
508
- );
509
- }
510
- if (match[2].includes(`<string>${escapedScheme}</string>`)) {
511
- return content;
512
- }
513
- return content.replace(urlTypesRe, `$1${match[2]}${entry}$3`);
514
- }
515
-
516
584
  /**
517
585
  * Resolve the real filesystem path to a node_modules package (follows bun
518
586
  * symlinks). Returns a path relative to `relativeTo`.
@@ -912,14 +980,69 @@ export function resolveMobileBuildPolicy(platform) {
912
980
 
913
981
  async function buildWeb(platform) {
914
982
  if (process.env.ELIZA_MOBILE_SKIP_WEB_BUILD === "1") {
915
- const indexPath = path.join(appDir, "dist", "index.html");
983
+ const distDir = path.join(appDir, "dist");
984
+ const indexPath = path.join(distDir, "index.html");
916
985
  if (!fs.existsSync(indexPath)) {
917
986
  throw new Error(
918
987
  `[mobile-build] ELIZA_MOBILE_SKIP_WEB_BUILD=1 but ${indexPath} is missing.`,
919
988
  );
920
989
  }
990
+ // Never SILENTLY reuse a stale renderer (issue #9309). The skip flag is an
991
+ // explicit "reuse the existing dist" request, but it must still fail loudly
992
+ // when that dist is stale relative to sources or was built for a different
993
+ // variant/target than this build needs. A deliberate stale reuse can be
994
+ // forced with ELIZA_MOBILE_SKIP_WEB_BUILD_ALLOW_STALE=1.
995
+ const allowStale =
996
+ process.env.ELIZA_MOBILE_SKIP_WEB_BUILD_ALLOW_STALE === "1";
997
+ const policy = resolveMobileBuildPolicy(platform);
998
+ const expectedVariant =
999
+ process.env.ELIZA_BUILD_VARIANT || policy.buildVariant;
1000
+ const expectedTarget = policy.capacitorTarget;
1001
+ const manifest = readRendererBuildManifest(distDir);
1002
+ const problems = [];
1003
+ if (!manifest) {
1004
+ problems.push(
1005
+ `no ${path.join("dist", "eliza-renderer-build.json")} (renderer not built with the build-manifest plugin)`,
1006
+ );
1007
+ } else {
1008
+ if (
1009
+ expectedVariant &&
1010
+ manifest.variant != null &&
1011
+ manifest.variant !== expectedVariant
1012
+ ) {
1013
+ problems.push(
1014
+ `dist built for variant '${manifest.variant}' but this build targets '${expectedVariant}'`,
1015
+ );
1016
+ }
1017
+ if (
1018
+ expectedTarget &&
1019
+ manifest.capacitorTarget != null &&
1020
+ manifest.capacitorTarget !== expectedTarget
1021
+ ) {
1022
+ problems.push(
1023
+ `dist built for capacitor target '${manifest.capacitorTarget}' but this build targets '${expectedTarget}'`,
1024
+ );
1025
+ }
1026
+ }
1027
+ if (viteRendererBuildNeeded(appDir, repoRoot)) {
1028
+ problems.push("dist is older than renderer sources (stale)");
1029
+ }
1030
+ if (problems.length > 0) {
1031
+ const detail = problems.map((p) => ` - ${p}`).join("\n");
1032
+ if (!allowStale) {
1033
+ throw new Error(
1034
+ `[mobile-build] ELIZA_MOBILE_SKIP_WEB_BUILD=1 refused — the existing web build is stale or mismatched:\n${detail}\n` +
1035
+ `Drop ELIZA_MOBILE_SKIP_WEB_BUILD to rebuild, or set ` +
1036
+ `ELIZA_MOBILE_SKIP_WEB_BUILD_ALLOW_STALE=1 to ship this dist anyway (NOT recommended).`,
1037
+ );
1038
+ }
1039
+ console.warn(
1040
+ `[mobile-build] ELIZA_MOBILE_SKIP_WEB_BUILD_ALLOW_STALE=1 — shipping a renderer flagged as stale/mismatched:\n${detail}`,
1041
+ );
1042
+ }
921
1043
  console.log(
922
- `[mobile-build] Reusing existing web build: ${path.relative(repoRoot, path.dirname(indexPath))}`,
1044
+ `[mobile-build] Reusing existing web build: ${path.relative(repoRoot, distDir)}` +
1045
+ (manifest ? ` (buildId=${manifest.buildId.slice(0, 12)})` : ""),
923
1046
  );
924
1047
  return;
925
1048
  }
@@ -1098,6 +1221,23 @@ function stageIosAgentRuntime({
1098
1221
  }
1099
1222
  }
1100
1223
 
1224
+ // The agent bundle must be the freshly built one — never a stale leftover that
1225
+ // forces a manual hot-swap to get latest (issue #9309). buildIos rebuilds it
1226
+ // before staging, so this is a hard guarantee; fail loudly if it regressed.
1227
+ if (process.env.ELIZA_MOBILE_ALLOW_STALE_AGENT_BUNDLE !== "1") {
1228
+ const bundleStale = artifactStaleness(
1229
+ path.join(sourceDir, "agent-bundle.js"),
1230
+ { sourceDirs: [path.join(packagesRoot, "agent", "src")] },
1231
+ );
1232
+ if (bundleStale.stale) {
1233
+ throw new Error(
1234
+ `[mobile-build] iOS agent bundle is stale (${bundleStale.reason}). ` +
1235
+ `Run \`bun run --cwd packages/agent build:ios-bun\` to rebuild, or set ` +
1236
+ `ELIZA_MOBILE_ALLOW_STALE_AGENT_BUNDLE=1 to stage it anyway (NOT recommended).`,
1237
+ );
1238
+ }
1239
+ }
1240
+
1101
1241
  const targetDir = path.join(iosDir, "App", "public", "agent");
1102
1242
  fs.rmSync(targetDir, { recursive: true, force: true });
1103
1243
  fs.mkdirSync(targetDir, { recursive: true });
@@ -1117,6 +1257,19 @@ function stageIosAgentRuntime({
1117
1257
  for (const file of assetPlan.rootAssets) {
1118
1258
  fs.copyFileSync(path.join(sourceDir, file), path.join(publicDir, file));
1119
1259
  }
1260
+ // Verify the staged bundle is a faithful copy (catch a torn/partial copy that
1261
+ // would ship a corrupt agent runtime).
1262
+ if (assetPlan.agentAssets?.includes("agent-bundle.js")) {
1263
+ const sha = (p) =>
1264
+ crypto.createHash("sha256").update(fs.readFileSync(p)).digest("hex");
1265
+ const srcSha = sha(path.join(sourceDir, "agent-bundle.js"));
1266
+ const dstSha = sha(path.join(targetDir, "agent-bundle.js"));
1267
+ if (srcSha !== dstSha) {
1268
+ throw new Error(
1269
+ `[mobile-build] staged iOS agent-bundle.js hash ${dstSha} != source ${srcSha} — partial/corrupt copy.`,
1270
+ );
1271
+ }
1272
+ }
1120
1273
  const stagedModelCount = stageIosBundledLocalModels(targetDir);
1121
1274
  console.log(
1122
1275
  `[mobile-build] Staged iOS Bun agent payload${appStoreBuild ? " (App Store allowlist)" : ""}: ${path.relative(repoRoot, targetDir)}${stagedModelCount > 0 ? ` with ${stagedModelCount} local model file(s)` : ""}`,
@@ -1303,7 +1456,85 @@ function mirrorCapacitorWebPayloadIntoAndroidDir() {
1303
1456
  `[mobile-build] Stale-web guard: overlaid fresh ${path.relative(repoRoot, freshWeb)} → ${path.relative(repoRoot, targetPublic)}`,
1304
1457
  );
1305
1458
  }
1459
+ dropRetiredLlamaCppFromAndroidGradle();
1306
1460
  reconcilePluginManifestWithGradle(targetAssets);
1461
+ // Verify the staged Android renderer is exactly the freshly built one. The
1462
+ // overlay above makes it so; this turns "should be fresh" into a hard,
1463
+ // build-failing guarantee (issue #9309).
1464
+ if (fs.existsSync(path.join(freshWeb, "index.html"))) {
1465
+ assertStagedRendererMatchesBuild(freshWeb, targetPublic, {
1466
+ label: "android",
1467
+ });
1468
+ }
1469
+ }
1470
+
1471
+ /**
1472
+ * iOS stale-web guard — the iOS counterpart to
1473
+ * mirrorCapacitorWebPayloadIntoAndroidDir. `cap sync ios` (and a skipped sync)
1474
+ * have both been observed to leave a STALE `ios/App/App/public` — an old entry
1475
+ * hash shipping an ancient UI despite a fresh `dist`. The freshly vite-built
1476
+ * bundle is the source of truth, so overlay it unconditionally: clear the hashed
1477
+ * assets/ then copy dist over public. The on-device agent payload
1478
+ * (`public/agent`) and PGlite root extension assets staged by
1479
+ * stageIosAgentRuntime live OUTSIDE dist and survive — we only clear
1480
+ * `public/assets` and cpSync never deletes existing non-dist files. After the
1481
+ * overlay we assert the staged renderer matches the build so a stale/missing UI
1482
+ * FAILS THE BUILD instead of shipping (issue #9309).
1483
+ */
1484
+ function mirrorCapacitorWebPayloadIntoIosDir() {
1485
+ const freshWeb = path.join(appDir, "dist");
1486
+ const targetPublic = path.join(iosDir, "App", "public");
1487
+ overlayFreshRendererIntoPublic(freshWeb, targetPublic, { label: "ios" });
1488
+ console.log(
1489
+ `[mobile-build] Stale-web guard: overlaid fresh ${path.relative(repoRoot, freshWeb)} → ${path.relative(repoRoot, targetPublic)}`,
1490
+ );
1491
+ }
1492
+
1493
+ /**
1494
+ * Remove the RETIRED llama-cpp-capacitor Android module from the gradle build
1495
+ * entirely — the `include ':llama-cpp-capacitor'` + project line in
1496
+ * capacitor.settings.gradle and the `implementation project(':llama-cpp-capacitor')`
1497
+ * in app/capacitor.build.gradle. `cap sync` re-adds these on every sync because
1498
+ * the package ships an android/ dir, but agent inference runs solely through the
1499
+ * fused libelizainference.so and nothing on Android loads this plugin's separate
1500
+ * libllama-cpp-arm64.so. Leaving the gradle project in only made gradle configure
1501
+ * its CMake — which built a no-op stub and used to require the
1502
+ * ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB opt-out. Dropping the project removes the
1503
+ * stub build outright (no flag needed). iOS is untouched: ios-local-agent-kernel
1504
+ * loads the package via a dynamic import, so the npm dependency stays.
1505
+ *
1506
+ * Opt back into the full second library (not the stub) with
1507
+ * ELIZA_ANDROID_INCLUDE_LLAMA_CPP_CAPACITOR=1. Idempotent.
1508
+ */
1509
+ function dropRetiredLlamaCppFromAndroidGradle() {
1510
+ if (
1511
+ process.env.ELIZA_ANDROID_INCLUDE_LLAMA_CPP_CAPACITOR === "1" ||
1512
+ process.env.elizaIncludeLlamaCppCapacitor === "true"
1513
+ ) {
1514
+ return;
1515
+ }
1516
+ const targets = [
1517
+ path.join(androidDir, "capacitor.settings.gradle"),
1518
+ path.join(androidDir, "app", "capacitor.build.gradle"),
1519
+ ];
1520
+ let dropped = false;
1521
+ for (const target of targets) {
1522
+ if (!fs.existsSync(target)) continue;
1523
+ const before = fs.readFileSync(target, "utf8");
1524
+ const after = before
1525
+ .split("\n")
1526
+ .filter((line) => !line.includes("llama-cpp-capacitor"))
1527
+ .join("\n");
1528
+ if (after !== before) {
1529
+ fs.writeFileSync(target, after, "utf8");
1530
+ dropped = true;
1531
+ }
1532
+ }
1533
+ if (dropped) {
1534
+ console.log(
1535
+ "[mobile-build] Dropped retired llama-cpp-capacitor from the Android gradle build (no stub CMake; libelizainference is the sole in-process inference lib).",
1536
+ );
1537
+ }
1307
1538
  }
1308
1539
 
1309
1540
  /**
@@ -1342,22 +1573,19 @@ function reconcilePluginManifestWithGradle(targetAssets) {
1342
1573
  String(pkg ?? "")
1343
1574
  .replace(/@/g, "")
1344
1575
  .replace(/\//g, "-");
1345
- // When ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB=1 the llama-cpp-capacitor CMake builds
1346
- // a no-op stub (`ELIZA_SKIP_MTP_ANDROID_LIB`). The stub registers and
1347
- // System.loadLibrary()s fine, but its JNI methods have no implementation, so a
1348
- // native call (LlamaCpp.toggleNativeLog during WebView device-bridge init)
1349
- // raises java.lang.UnsatisfiedLinkError. The call site is now defended the
1350
- // patches/llama-cpp-capacitor@0.1.5.patch hardening makes LlamaCpp.toggleNativeLog
1351
- // catch Throwable and reject the Capacitor call instead of letting the Error
1352
- // escape to crash MainActivity so registering the stub no longer kills the
1353
- // app. We still drop it from the manifest here because a stub Capacitor plugin
1354
- // is pure dead weight: agent-side local inference (ELIZA_LOCAL_LLAMA, libllama
1355
- // via bun:ffi) does NOT use this Capacitor plugin, so the device-bridge import
1356
- // failing as a catchable "LlamaCpp plugin not implemented" JS error costs
1357
- // nothing and keeps the JS↔native surface honest.
1576
+ // The llama-cpp-capacitor plugin is RETIRED on Android: agent inference runs
1577
+ // entirely through the single fused libelizainference.so, and nothing loads
1578
+ // this plugin's separate libllama-cpp-arm64.so (its JS adapter is retired).
1579
+ // dropRetiredLlamaCppFromAndroidGradle() (called above) removes its gradle
1580
+ // project outright, so its CMake never runs — there is no stub to register
1581
+ // and no ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB opt-out to set. We also drop it from
1582
+ // the plugins manifest here so the LlamaCpp class never auto-registers. The
1583
+ // device-bridge's optional LlamaCpp import resolves to a catchable "plugin not
1584
+ // implemented" JS error, which costs nothing. Opt the full second library back
1585
+ // in (gradle project + manifest) only with ELIZA_ANDROID_INCLUDE_LLAMA_CPP_CAPACITOR=1.
1358
1586
  const stubLlamaCpp =
1359
- process.env.ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB === "1" ||
1360
- process.env.elizaSkipForkLlamaLib === "true";
1587
+ process.env.ELIZA_ANDROID_INCLUDE_LLAMA_CPP_CAPACITOR !== "1" &&
1588
+ process.env.elizaIncludeLlamaCppCapacitor !== "true";
1361
1589
  // Third-party Capacitor plugins that `cap sync` includes (they ship an
1362
1590
  // android/ dir, so they ARE in capacitor.settings.gradle) but whose Kotlin
1363
1591
  // plugin class never lands in the app dex on AGP 8.x: both rely on AGP's
@@ -1670,34 +1898,20 @@ export function injectNativeLibLegacyPackaging(content) {
1670
1898
  *
1671
1899
  * Fails local builds when no path is configured or the dir doesn't exist. The
1672
1900
  * Android Capacitor JNI wrapper links against these MTP libraries and cannot
1673
- * honestly support Eliza-1/Qwen3.5 without them. Cloud builds skip the task.
1674
- * CI smoke builds that intentionally install no native deps can opt out with
1675
- * -PelizaSkipForkLlamaLib=true or ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB=1.
1901
+ * honestly support Eliza-1/Gemma 4 without them. Cloud builds skip the task.
1902
+ * A build with no fresh source dir falls back to the already-staged fused lib
1903
+ * set (the common dev case); only a genuinely missing arm64 lib is a hard error.
1676
1904
  *
1677
1905
  * Idempotent: re-runs are no-ops once the block is present.
1678
1906
  */
1679
1907
  function ensureCopyForkLlamaLibGuards(content) {
1680
1908
  if (!/\[copyForkLlamaLib\]/.test(content)) return content;
1681
- const hasCloudGuard = /skipped for cloud build/.test(content);
1682
- const hasExplicitSkipGuard =
1683
- /elizaSkipForkLlamaLib/.test(content) ||
1684
- /ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB/.test(content);
1685
- if (hasCloudGuard && hasExplicitSkipGuard) return content;
1686
- let guards = "";
1687
- if (!hasCloudGuard) {
1688
- guards +=
1689
- ` if (project.findProperty('elizaCloudBuild') == 'true') {\n` +
1690
- ` println "[copyForkLlamaLib] skipped for cloud build"\n` +
1691
- ` return\n` +
1692
- ` }\n`;
1693
- }
1694
- if (!hasExplicitSkipGuard) {
1695
- guards +=
1696
- ` if (project.findProperty('elizaSkipForkLlamaLib') == 'true' || System.getenv('ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB') == '1') {\n` +
1697
- ` println "[copyForkLlamaLib] skipped by explicit native-lib opt-out"\n` +
1698
- ` return\n` +
1699
- ` }\n`;
1700
- }
1909
+ if (/skipped for cloud build/.test(content)) return content;
1910
+ const guards =
1911
+ ` if (project.findProperty('elizaCloudBuild') == 'true') {\n` +
1912
+ ` println "[copyForkLlamaLib] skipped for cloud build"\n` +
1913
+ ` return\n` +
1914
+ ` }\n`;
1701
1915
  return content.replace(
1702
1916
  /(task copyForkLlamaLib\s*\{\s*\n\s*doLast\s*\{\s*\n)/,
1703
1917
  `$1${guards}`,
@@ -1710,7 +1924,7 @@ export function injectCopyForkLlamaLibTask(content) {
1710
1924
  }
1711
1925
  const block =
1712
1926
  `\n// Bundle the MTP Android llama.cpp stack into the APK so mobile\n` +
1713
- `// gets Eliza-1/Qwen3.5 support across every supported Android ABI\n` +
1927
+ `// gets Eliza-1/Gemma 4 support across every supported Android ABI\n` +
1714
1928
  `// (arm64-v8a, x86_64, riscv64). The arm64-v8a slice is mandatory for\n` +
1715
1929
  `// local-agent capable builds; x86_64 and riscv64 ship when their\n` +
1716
1930
  `// per-ABI artifacts exist (Wave 2 cross-compiles land them\n` +
@@ -1783,25 +1997,35 @@ export function injectCopyForkLlamaLibTask(content) {
1783
1997
  ` return null\n` +
1784
1998
  `}\n` +
1785
1999
  `\n` +
2000
+ `// NOTE: despite the legacy "ForkLlama" name, this stages the SINGLE canonical\n` +
2001
+ `// fused inference lib — libelizainference.so — with its own DT_NEEDED runtime\n` +
2002
+ `// siblings (libggml*, libllama.so, libllama-common.so, libmtmd.so, libomp.so),\n` +
2003
+ `// which ARE libelizainference's GPU/CPU backends, NOT a separate llama.cpp fork.\n` +
2004
+ `// There is no second inference library; do NOT delete this task or its siblings.\n` +
1786
2005
  `task copyForkLlamaLib {\n` +
1787
2006
  ` doLast {\n` +
1788
2007
  ` if (project.findProperty('elizaCloudBuild') == 'true') {\n` +
1789
2008
  ` println "[copyForkLlamaLib] skipped for cloud build"\n` +
1790
2009
  ` return\n` +
1791
2010
  ` }\n` +
1792
- ` if (project.findProperty('elizaSkipForkLlamaLib') == 'true' || System.getenv('ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB') == '1') {\n` +
1793
- ` println "[copyForkLlamaLib] skipped by explicit native-lib opt-out"\n` +
1794
- ` return\n` +
1795
- ` }\n` +
1796
2011
  ` boolean stagedArm64 = false\n` +
1797
2012
  ` int totalCopied = 0\n` +
1798
2013
  ` boolean stagedKernels = false\n` +
1799
2014
  ` project.ext.elizaForkLlamaAbis.each { abi ->\n` +
1800
2015
  ` def libDir = resolveForkLlamaLibDir(abi)\n` +
1801
2016
  ` if (!libDir) {\n` +
2017
+ ` // No fresh source configured. If the fused lib set is already\n` +
2018
+ ` // staged in jniLibs (a prior build, the common dev case), use it\n` +
2019
+ ` // as-is so a plain build:android "just works" without any flag.\n` +
2020
+ ` def alreadyStaged = new File(file("src/main/jniLibs/\${abi}"), 'libelizainference.so')\n` +
2021
+ ` if (alreadyStaged.isFile()) {\n` +
2022
+ ` logger.lifecycle("[copyForkLlamaLib] no source dir for \${abi}; libelizainference.so already staged in jniLibs — using the pre-staged fused lib set")\n` +
2023
+ ` if (abi == 'arm64-v8a') stagedArm64 = true\n` +
2024
+ ` return\n` +
2025
+ ` }\n` +
1802
2026
  ` if (abi == 'arm64-v8a') {\n` +
1803
- ` // arm64-v8a is the mandatory baseline ABI; missing it is a hard error.\n` +
1804
- ` throw new GradleException("[copyForkLlamaLib] no MTP Android lib dir configured for arm64-v8a. Run packages/app-core/scripts/aosp/compile-libllama.mjs --target android-arm64-vulkan-fused (the Android cross-compiler; build-llama-cpp-mtp.mjs has no Android targets) or set -Peliza.mtp.android.libdir / ELIZA_MTP_ANDROID_LIBDIR.")\n` +
2027
+ ` // arm64-v8a is the mandatory baseline ABI; missing it (and no pre-staged lib) is a hard error.\n` +
2028
+ ` throw new GradleException("[copyForkLlamaLib] no fused inference lib for arm64-v8a (not configured, not pre-staged). Run packages/app-core/scripts/aosp/compile-libllama.mjs --target android-arm64-vulkan-fused (the Android cross-compiler; build-llama-cpp-mtp.mjs has no Android targets) or set -Peliza.mtp.android.libdir / ELIZA_MTP_ANDROID_LIBDIR.")\n` +
1805
2029
  ` }\n` +
1806
2030
  ` logger.lifecycle("[copyForkLlamaLib] no fork lib dir for ABI \${abi}; skipping")\n` +
1807
2031
  ` return\n` +
@@ -2540,7 +2764,20 @@ export function validateAndroidAppActionsXmlResource(
2540
2764
  return failures;
2541
2765
  }
2542
2766
 
2767
+ function assertSharedTreeOnlyForEliza(what) {
2768
+ if (
2769
+ APP.appId !== "ai.elizaos.app" &&
2770
+ path.resolve(androidDir) === path.resolve(platformsDir, "android")
2771
+ ) {
2772
+ throw new Error(
2773
+ `[mobile-build] Refusing to ${what} for brand '${APP.appId}' in the shared elizaOS android tree (${androidDir}). ` +
2774
+ "Whitelabel builds must use apps/app/android (set ELIZA_ANDROID_USE_APP_DIR=1); the elizaOS build owns the shared tree.",
2775
+ );
2776
+ }
2777
+ }
2778
+
2543
2779
  function syncAndroidAppActionsResources() {
2780
+ assertSharedTreeOnlyForEliza("patch app-actions resources");
2544
2781
  const templateResDir = path.join(
2545
2782
  platformsDir,
2546
2783
  "android",
@@ -2690,6 +2927,7 @@ function restoreAndroidManifestFromPlatformTemplateIfMissing() {
2690
2927
  }
2691
2928
 
2692
2929
  function overlayAndroid({ includeAospRoleLaunchers = false } = {}) {
2930
+ assertSharedTreeOnlyForEliza("overlay Java sources");
2693
2931
  const templateJavaRoot = path.join(
2694
2932
  platformsDir,
2695
2933
  "android",
@@ -2806,7 +3044,23 @@ function overlayAndroid({ includeAospRoleLaunchers = false } = {}) {
2806
3044
  code = injectBrandUserAgentMarkers(code, APP.userAgentMarkers ?? []);
2807
3045
  }
2808
3046
  fs.writeFileSync(path.join(dstJava, file), code, "utf8");
2809
- if (path.resolve(src) !== path.resolve(path.join(dstJava, file))) {
3047
+ // Rewrite the legacy-package copy's R/BuildConfig imports so any file left
3048
+ // behind in the old package still resolves — but ONLY when that copy lives
3049
+ // in THIS build's own android dir. NEVER write into the shared elizaOS
3050
+ // template tree (platforms/android): a whitelabel build
3051
+ // (ELIZA_ANDROID_USE_APP_DIR) reads that template READ-ONLY, and writing
3052
+ // the brand package back into it corrupts the elizaOS checkout's
3053
+ // ai/elizaos/app sources (the recurring "package ai.milady.app does not
3054
+ // exist" pollution that breaks the next elizaOS build). srcJava resolves
3055
+ // to templateJava for a whitelabel build, so this guard is what keeps the
3056
+ // two brands' source trees separate.
3057
+ const srcInOwnAndroidDir = path
3058
+ .resolve(src)
3059
+ .startsWith(`${path.resolve(androidDir)}${path.sep}`);
3060
+ if (
3061
+ srcInOwnAndroidDir &&
3062
+ path.resolve(src) !== path.resolve(path.join(dstJava, file))
3063
+ ) {
2810
3064
  const legacyCode = fs
2811
3065
  .readFileSync(src, "utf8")
2812
3066
  .replaceAll(
@@ -3699,7 +3953,14 @@ function shouldSkipIosPodInstall(env = process.env) {
3699
3953
  return isTruthyEnv(env.ELIZA_IOS_SKIP_POD_INSTALL);
3700
3954
  }
3701
3955
 
3702
- function shouldIncludeIosFullBunEngine(env = process.env) {
3956
+ // An iOS build ships the on-device no-JIT Bun engine (and thus a real local
3957
+ // agent) when it is explicitly requested, OR when it is a store/App Store build
3958
+ // with the local runtime left enabled (the default). App Store builds are
3959
+ // cloud-hybrid: they keep the App Store-safe local runtime unless an operator
3960
+ // opts into a cloud-only thin client via ELIZA_IOS_APP_STORE_LOCAL_RUNTIME=0.
3961
+ // Exported so the release preflight + tests share one definition of "will the
3962
+ // shipped IPA actually contain a local agent runtime".
3963
+ export function shouldIncludeIosFullBunEngine(env = process.env) {
3703
3964
  return (
3704
3965
  isFullIosBunEngineRequested(env) ||
3705
3966
  (isIosAppStoreBuild(env) && isIosAppStoreLocalRuntimeEnabled(env))
@@ -4061,6 +4322,7 @@ function patchInstalledLlamaCapacitorBuildGradle() {
4061
4322
  }
4062
4323
 
4063
4324
  function patchAndroidGradle() {
4325
+ assertSharedTreeOnlyForEliza("patch gradle identity");
4064
4326
  patchAndroidGradleWrapperForReleaseCompat();
4065
4327
  patchAndroidGradleProperties();
4066
4328
  patchInstalledLlamaCapacitorBuildGradle();
@@ -4529,6 +4791,7 @@ async function generateIosBrandAssets() {
4529
4791
  }
4530
4792
 
4531
4793
  async function generateAndroidBrandAssets() {
4794
+ assertSharedTreeOnlyForEliza("write brand icons");
4532
4795
  const resDir = path.join(androidDir, "app", "src", "main", "res");
4533
4796
  if (!fs.existsSync(resDir)) return;
4534
4797
 
@@ -4729,17 +4992,55 @@ function mtpTargetOutDir(target) {
4729
4992
  );
4730
4993
  }
4731
4994
 
4995
+ function resolveMtpForkSrc() {
4996
+ for (const candidate of MTP_FORK_SRC_CANDIDATES) {
4997
+ if (fs.existsSync(path.join(candidate, "CMakeLists.txt"))) return candidate;
4998
+ }
4999
+ return null;
5000
+ }
5001
+
5002
+ /** `git describe --always --dirty` of the fork, or null when git/desc fails. */
5003
+ function currentMtpForkRevision(forkSrc) {
5004
+ if (!forkSrc) return null;
5005
+ const result = spawnSync(
5006
+ "git",
5007
+ ["-C", forkSrc, "describe", "--always", "--dirty"],
5008
+ { encoding: "utf8" },
5009
+ );
5010
+ if (result.status !== 0) return null;
5011
+ return result.stdout?.trim() || null;
5012
+ }
5013
+
4732
5014
  async function ensureMtpIosTarget(target) {
4733
5015
  const outDir = mtpTargetOutDir(target);
4734
5016
  const capabilities = path.join(outDir, "CAPABILITIES.json");
4735
- if (fs.existsSync(capabilities)) {
5017
+ const forkSrc = resolveMtpForkSrc();
5018
+ const reuse = mtpSliceReuse(
5019
+ capabilities,
5020
+ forkSrc,
5021
+ currentMtpForkRevision(forkSrc),
5022
+ );
5023
+ const forceRebuild = mtpForceRebuildRequested(reuse, process.env);
5024
+ if (!forceRebuild) {
4736
5025
  console.log(
4737
- `[mobile-build] Reusing existing mtp artifact for ${target} at ${outDir}`,
5026
+ `[mobile-build] Reusing fresh mtp artifact for ${target} at ${outDir}`,
4738
5027
  );
4739
5028
  return outDir;
4740
5029
  }
4741
- console.log(`[mobile-build] Building mtp artifact for ${target}`);
4742
- await run("node", [MTP_BUILD_SCRIPT, "--target", target]);
5030
+ if (fs.existsSync(capabilities)) {
5031
+ console.log(
5032
+ `[mobile-build] Rebuilding mtp artifact for ${target} — ${process.env.ELIZA_IOS_REBUILD_MTP === "1" ? "ELIZA_IOS_REBUILD_MTP=1" : reuse.reason}`,
5033
+ );
5034
+ } else {
5035
+ console.log(`[mobile-build] Building mtp artifact for ${target}`);
5036
+ }
5037
+ // The child builder (build-llama-cpp-mtp.mjs) has its OWN presence-only reuse
5038
+ // gate keyed on ELIZA_MTP_FORCE_REBUILD. Without propagating it, the child
5039
+ // would see the stale CAPABILITIES.json and reuse it — turning this staleness
5040
+ // gate into a no-op. Force the child to actually rebuild (#9309).
5041
+ await run("node", [MTP_BUILD_SCRIPT, "--target", target], {
5042
+ env: { ...process.env, ELIZA_MTP_FORCE_REBUILD: "1" },
5043
+ });
4743
5044
  if (!fs.existsSync(capabilities)) {
4744
5045
  throw new Error(
4745
5046
  `[mobile-build] mtp build for ${target} did not produce CAPABILITIES.json at ${capabilities}. ` +
@@ -7162,6 +7463,8 @@ async function buildAndroidSystem() {
7162
7463
  androidDir,
7163
7464
  spikeDir: androidAgentSpikeDir,
7164
7465
  bunChannel: "canary",
7466
+ // Objective AOSP/chip image: riscv64 bun stays fail-closed (it ships it).
7467
+ objective: true,
7165
7468
  });
7166
7469
  auditAndroidSystemSource("pre-gradle");
7167
7470
 
@@ -7329,6 +7632,11 @@ async function buildIos({ local = false } = {}) {
7329
7632
  } else {
7330
7633
  await runCapacitor(["sync", "ios"]);
7331
7634
  }
7635
+ // Overlay the freshly built renderer onto ios/App/App/public and assert it
7636
+ // matches the build — never ship a stale UI whether sync ran, was skipped, or
7637
+ // left old hashed assets behind (issue #9309). Runs before the post-sync agent
7638
+ // re-stage so the agent payload remains the final authority on public/agent.
7639
+ mirrorCapacitorWebPayloadIntoIosDir();
7332
7640
  if (includesLocalAgentPayload) {
7333
7641
  stageIosAgentRuntime({
7334
7642
  appStoreBuild: isIosAppStoreBuild() && !local,
@@ -7445,6 +7753,20 @@ export async function main(argv = process.argv.slice(2)) {
7445
7753
  } else {
7446
7754
  prepareIosOverlay();
7447
7755
  await generateIosBrandAssets();
7756
+ // The App Store release pipeline splits the build into `bun run build`
7757
+ // (web) + `cap:sync:ios` + this overlay + fastlane, so it never runs
7758
+ // buildIos()'s local-agent staging. When the build embeds the full Bun
7759
+ // engine, stage the agent runtime payload here (after cap sync, before
7760
+ // pod install / fastlane archive) so the shipped IPA actually contains the
7761
+ // agent the engine runs — without it the engine boots with nothing to
7762
+ // execute. The agent bundle must already be built (packages/agent
7763
+ // build:ios-bun); stageIosAgentRuntime throws with that hint if missing.
7764
+ if (shouldIncludeIosFullBunEngine()) {
7765
+ stageIosAgentRuntime({
7766
+ appStoreBuild: isIosAppStoreBuild(),
7767
+ includeFullBunEngine: true,
7768
+ });
7769
+ }
7448
7770
  }
7449
7771
  }
7450
7772