@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
@@ -1,6 +1,14 @@
1
1
  import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { access, cp, mkdtemp, readFile, rm } from "node:fs/promises";
2
+ import { existsSync, rmSync } from "node:fs";
3
+ import {
4
+ access,
5
+ cp,
6
+ mkdir,
7
+ mkdtemp,
8
+ readFile,
9
+ rm,
10
+ writeFile,
11
+ } from "node:fs/promises";
4
12
  import {
5
13
  createServer,
6
14
  type IncomingMessage,
@@ -12,13 +20,22 @@ import path from "node:path";
12
20
  import { setTimeout as sleep } from "node:timers/promises";
13
21
  import { WebSocket, WebSocketServer } from "ws";
14
22
  import { buildFirstRunRuntimeConfig } from "../src/first-run/first-run-config.ts";
23
+ import { createLiveRuntimeChildEnv } from "../test/helpers/live-child-env.ts";
15
24
  import {
16
25
  getFirstRunProviderForLiveProvider,
17
- selectLiveProvider,
26
+ selectLiveProviderAsync,
18
27
  } from "../test/helpers/live-provider.ts";
19
28
  import { resolveMainAppDir } from "./lib/app-dir.mjs";
20
29
  import { shouldForceStubStack } from "./lib/ui-smoke-stub-decision.mjs";
21
30
  import { viteRendererBuildNeeded } from "./lib/vite-renderer-dist-stale.mjs";
31
+ import {
32
+ clearPendingWebSocketQueue,
33
+ createPendingWebSocketQueueState,
34
+ DEFAULT_PENDING_WEBSOCKET_QUEUE_LIMITS,
35
+ drainPendingWebSocketQueue,
36
+ enqueuePendingWebSocketMessage,
37
+ type WebSocketSendData,
38
+ } from "./lib/websocket-pending-queue.ts";
22
39
 
23
40
  const REPO_ROOT = path.resolve(import.meta.dirname, "..", "..", "..");
24
41
  const APP_DIR = resolveMainAppDir(REPO_ROOT, "app");
@@ -36,12 +53,55 @@ const UI_SMOKE_STUB_SCRIPT = path.join(
36
53
  const READY_TIMEOUT_MS = 180_000;
37
54
  const API_PORT = Number(process.env.ELIZA_UI_SMOKE_API_PORT ?? "31337");
38
55
  const UI_PORT = Number(process.env.ELIZA_UI_SMOKE_PORT ?? "2138");
39
- const LIVE_PROVIDER = selectLiveProvider();
56
+ const UI_SMOKE_RUN_ID = process.env.ELIZA_UI_SMOKE_RUN_ID?.trim() ?? "";
57
+ const LIVE_PROVIDER = await selectLiveProviderAsync();
40
58
  // Precedence (force-stub > live opt-in > CI default) lives in one tested helper.
41
59
  // The key behavior: ELIZA_UI_SMOKE_LIVE_STACK=1 overrides the CI-based stub force
42
60
  // so a genuinely-real lane is possible (GitHub Actions always sets CI=true, which
43
61
  // would otherwise re-force the stub even when a provider key was supplied).
44
62
  const FORCE_STUB_STACK = shouldForceStubStack(process.env);
63
+ const LIVE_STACK_OPTIONAL_VIEW_PLUGIN_ENTRIES = [
64
+ "calendar",
65
+ "inbox",
66
+ "todos",
67
+ "wallet-ui",
68
+ ] as const;
69
+ const LIVE_STACK_OPTIONAL_VIEW_PLUGIN_PACKAGES: ReadonlyArray<{
70
+ id: (typeof LIVE_STACK_OPTIONAL_VIEW_PLUGIN_ENTRIES)[number];
71
+ dir: string;
72
+ requiredBuildOutputs: readonly string[];
73
+ }> = [
74
+ {
75
+ id: "calendar",
76
+ dir: "plugin-calendar",
77
+ requiredBuildOutputs: [
78
+ "dist/index.js",
79
+ "dist/plugin.js",
80
+ "dist/views/bundle.js",
81
+ ],
82
+ },
83
+ {
84
+ id: "inbox",
85
+ dir: "plugin-inbox",
86
+ requiredBuildOutputs: [
87
+ "dist/index.js",
88
+ "dist/plugin.js",
89
+ "dist/views/bundle.js",
90
+ ],
91
+ },
92
+ {
93
+ id: "todos",
94
+ dir: "plugin-todos",
95
+ requiredBuildOutputs: ["dist/index.js", "dist/views/bundle.js"],
96
+ },
97
+ {
98
+ id: "wallet-ui",
99
+ dir: "plugin-wallet-ui",
100
+ requiredBuildOutputs: ["dist/index.js", "dist/views/bundle.js"],
101
+ },
102
+ ];
103
+ const pendingStateDirs = new Set<string>();
104
+ const ownedStateDirs = new Set<string>();
45
105
 
46
106
  type StartedStack = {
47
107
  apiBase: string;
@@ -51,6 +111,45 @@ type StartedStack = {
51
111
  uiServer: Server;
52
112
  };
53
113
 
114
+ async function createStateDir(prefix: string): Promise<string> {
115
+ const stateDir = await mkdtemp(path.join(os.tmpdir(), prefix));
116
+ pendingStateDirs.add(stateDir);
117
+ if (UI_SMOKE_RUN_ID) {
118
+ await writeFile(
119
+ path.join(stateDir, ".eliza-ui-smoke-run-id"),
120
+ `${UI_SMOKE_RUN_ID}\n`,
121
+ "utf8",
122
+ );
123
+ }
124
+ return stateDir;
125
+ }
126
+
127
+ function markStateDirOwnedByStack(stateDir: string): void {
128
+ pendingStateDirs.delete(stateDir);
129
+ ownedStateDirs.add(stateDir);
130
+ }
131
+
132
+ async function cleanupPendingStateDirs(): Promise<void> {
133
+ const stateDirs = Array.from(pendingStateDirs);
134
+ pendingStateDirs.clear();
135
+ await Promise.all(
136
+ stateDirs.map((stateDir) => rm(stateDir, { force: true, recursive: true })),
137
+ );
138
+ }
139
+
140
+ function cleanupKnownStateDirsSync(): void {
141
+ const stateDirs = new Set([...pendingStateDirs, ...ownedStateDirs]);
142
+ pendingStateDirs.clear();
143
+ ownedStateDirs.clear();
144
+ for (const stateDir of stateDirs) {
145
+ try {
146
+ rmSync(stateDir, { force: true, recursive: true });
147
+ } catch {
148
+ // Best effort during process teardown.
149
+ }
150
+ }
151
+ }
152
+
54
153
  function resolveBunCommand(): string {
55
154
  const bunFromEnv = process.env.BUN?.trim();
56
155
  if (bunFromEnv && existsSync(bunFromEnv)) {
@@ -268,17 +367,15 @@ function relayWebSocket(args: {
268
367
  : undefined,
269
368
  });
270
369
 
271
- const pendingClientMessages: Array<{
272
- data: Parameters<WebSocket["send"]>[0];
273
- isBinary: boolean;
274
- }> = [];
370
+ const pendingClientQueue =
371
+ createPendingWebSocketQueueState<WebSocketSendData>();
275
372
 
276
- const closeSocket = (socket: WebSocket) => {
373
+ const closeSocket = (socket: WebSocket, code?: number, reason?: string) => {
277
374
  if (
278
375
  socket.readyState === WebSocket.OPEN ||
279
376
  socket.readyState === WebSocket.CONNECTING
280
377
  ) {
281
- socket.close();
378
+ socket.close(code, reason);
282
379
  }
283
380
  };
284
381
 
@@ -288,12 +385,25 @@ function relayWebSocket(args: {
288
385
  return;
289
386
  }
290
387
  if (upstreamSocket.readyState === WebSocket.CONNECTING) {
291
- pendingClientMessages.push({ data, isBinary });
388
+ const accepted = enqueuePendingWebSocketMessage(
389
+ pendingClientQueue,
390
+ { data, isBinary },
391
+ DEFAULT_PENDING_WEBSOCKET_QUEUE_LIMITS,
392
+ );
393
+ if (!accepted) {
394
+ clearPendingWebSocketQueue(pendingClientQueue);
395
+ closeSocket(
396
+ args.clientSocket,
397
+ 1009,
398
+ "Pending websocket queue overflow",
399
+ );
400
+ closeSocket(upstreamSocket);
401
+ }
292
402
  }
293
403
  });
294
404
 
295
405
  upstreamSocket.on("open", () => {
296
- for (const message of pendingClientMessages.splice(0)) {
406
+ for (const message of drainPendingWebSocketQueue(pendingClientQueue)) {
297
407
  upstreamSocket.send(message.data, { binary: message.isBinary });
298
408
  }
299
409
  });
@@ -306,16 +416,20 @@ function relayWebSocket(args: {
306
416
  });
307
417
 
308
418
  args.clientSocket.on("close", () => {
419
+ clearPendingWebSocketQueue(pendingClientQueue);
309
420
  closeSocket(upstreamSocket);
310
421
  });
311
422
  upstreamSocket.on("close", () => {
423
+ clearPendingWebSocketQueue(pendingClientQueue);
312
424
  closeSocket(args.clientSocket);
313
425
  });
314
426
 
315
427
  args.clientSocket.on("error", () => {
428
+ clearPendingWebSocketQueue(pendingClientQueue);
316
429
  closeSocket(upstreamSocket);
317
430
  });
318
431
  upstreamSocket.on("error", () => {
432
+ clearPendingWebSocketQueue(pendingClientQueue);
319
433
  closeSocket(args.clientSocket);
320
434
  });
321
435
  }
@@ -407,6 +521,29 @@ async function waitForChildExit(
407
521
  });
408
522
  }
409
523
 
524
+ async function closeUiServer(uiServer: Server | null): Promise<void> {
525
+ if (!uiServer) return;
526
+ try {
527
+ await new Promise<void>((resolve, reject) =>
528
+ uiServer.close((error) => (error ? reject(error) : resolve())),
529
+ );
530
+ } catch {
531
+ // Best effort during shutdown.
532
+ }
533
+ }
534
+
535
+ async function stopApiChild(
536
+ apiChild: ChildProcessWithoutNullStreams | null,
537
+ ): Promise<void> {
538
+ if (!apiChild || apiChild.exitCode != null) return;
539
+ apiChild.kill("SIGTERM");
540
+ const exitedAfterTerm = await waitForChildExit(apiChild, 5_000);
541
+ if (!exitedAfterTerm && apiChild.exitCode == null) {
542
+ apiChild.kill("SIGKILL");
543
+ await waitForChildExit(apiChild, 5_000);
544
+ }
545
+ }
546
+
410
547
  async function fetchJson<T>(url: string): Promise<T> {
411
548
  const response = await fetch(url);
412
549
  if (!response.ok) {
@@ -465,6 +602,54 @@ async function waitForJsonPredicate<T>(
465
602
  : new Error(`Timed out waiting for ${url}`);
466
603
  }
467
604
 
605
+ function createProcessLogSignal(matchText: string): {
606
+ observe: (chunk: Buffer | string) => void;
607
+ wait: (timeoutMs: number, label: string) => Promise<void>;
608
+ } {
609
+ let matched = false;
610
+ let tail = "";
611
+ const waiters = new Set<() => void>();
612
+
613
+ return {
614
+ observe(chunk) {
615
+ if (matched) {
616
+ return;
617
+ }
618
+ const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
619
+ tail = `${tail}${text}`.slice(-Math.max(matchText.length * 2, 4096));
620
+ if (!tail.includes(matchText)) {
621
+ return;
622
+ }
623
+ matched = true;
624
+ tail = "";
625
+ for (const resolve of waiters) {
626
+ resolve();
627
+ }
628
+ waiters.clear();
629
+ },
630
+ async wait(timeoutMs, label) {
631
+ if (matched) {
632
+ return;
633
+ }
634
+ await new Promise<void>((resolve, reject) => {
635
+ const timeout = setTimeout(() => {
636
+ cleanup();
637
+ reject(new Error(`Timed out waiting for ${label}`));
638
+ }, timeoutMs);
639
+ const finish = () => {
640
+ cleanup();
641
+ resolve();
642
+ };
643
+ const cleanup = () => {
644
+ clearTimeout(timeout);
645
+ waiters.delete(finish);
646
+ };
647
+ waiters.add(finish);
648
+ });
649
+ },
650
+ };
651
+ }
652
+
468
653
  async function ensureUiDistReady(): Promise<void> {
469
654
  const distIndex = path.join(APP_DIST_DIR, "index.html");
470
655
  let needsBuild = false;
@@ -605,56 +790,138 @@ async function submitFirstRun(apiBase: string): Promise<void> {
605
790
  );
606
791
  }
607
792
 
608
- async function startStubStack(): Promise<StartedStack> {
609
- const stateDir = await mkdtemp(
610
- path.join(os.tmpdir(), "eliza-ui-smoke-stub-"),
793
+ async function seedLiveStackConfig(stateDir: string): Promise<void> {
794
+ await mkdir(stateDir, { recursive: true });
795
+ const configPath = path.join(stateDir, "eliza.json");
796
+ await writeFile(
797
+ configPath,
798
+ `${JSON.stringify(
799
+ {
800
+ logging: { level: "error" },
801
+ plugins: {
802
+ entries: Object.fromEntries(
803
+ LIVE_STACK_OPTIONAL_VIEW_PLUGIN_ENTRIES.map((pluginId) => [
804
+ pluginId,
805
+ { enabled: true },
806
+ ]),
807
+ ),
808
+ },
809
+ },
810
+ null,
811
+ 2,
812
+ )}\n`,
813
+ "utf8",
611
814
  );
612
- const uiDistDir = await snapshotUiDist(stateDir);
613
- const apiBase = `http://127.0.0.1:${API_PORT}`;
614
- const apiChild = spawn("node", [UI_SMOKE_STUB_SCRIPT], {
615
- cwd: REPO_ROOT,
616
- env: {
617
- ...process.env,
618
- FORCE_COLOR: "0",
619
- ELIZA_UI_SMOKE_API_PORT: String(API_PORT),
620
- ELIZA_UI_SMOKE_STUB_IGNORE_SIGTERM: "1",
621
- },
622
- stdio: ["ignore", "pipe", "pipe"],
623
- });
815
+ }
624
816
 
625
- apiChild.stdout.on("data", (chunk) => {
626
- process.stdout.write(`[ui-smoke][stub] ${chunk}`);
627
- });
628
- apiChild.stderr.on("data", (chunk) => {
629
- process.stdout.write(`[ui-smoke][stub-err] ${chunk}`);
630
- });
817
+ async function ensureLiveStackOptionalViewPluginsReady(): Promise<void> {
818
+ for (const plugin of LIVE_STACK_OPTIONAL_VIEW_PLUGIN_PACKAGES) {
819
+ const pluginDir = path.join(REPO_ROOT, "plugins", plugin.dir);
820
+ const outputPaths = plugin.requiredBuildOutputs.map((output) =>
821
+ path.join(pluginDir, output),
822
+ );
823
+ const missingOutputPaths: string[] = [];
824
+ for (const outputPath of outputPaths) {
825
+ try {
826
+ await access(outputPath);
827
+ } catch {
828
+ missingOutputPaths.push(outputPath);
829
+ }
830
+ }
831
+ if (missingOutputPaths.length === 0) continue;
631
832
 
632
- await waitForJson<{ complete: boolean }>(`${apiBase}/api/first-run/status`);
633
- await waitForJsonPredicate<{ state?: string }>(
634
- `${apiBase}/api/status`,
635
- (status) => status.state === "running",
636
- READY_TIMEOUT_MS,
637
- );
638
- await waitForJsonPredicate<{ session?: { kind?: string } }>(
639
- `${apiBase}/api/auth/me`,
640
- (me) => me.session?.kind === "local",
641
- READY_TIMEOUT_MS,
642
- );
833
+ const logs: string[] = [];
834
+ const child = spawn(resolveBunCommand(), ["run", "build"], {
835
+ cwd: pluginDir,
836
+ env: {
837
+ ...process.env,
838
+ FORCE_COLOR: "0",
839
+ },
840
+ stdio: ["ignore", "pipe", "pipe"],
841
+ });
842
+ child.stdout.on("data", (chunk) => logs.push(String(chunk)));
843
+ child.stderr.on("data", (chunk) => logs.push(String(chunk)));
643
844
 
644
- const uiServer = await startUiProxyServer({
645
- apiBase,
646
- port: UI_PORT,
647
- uiDistDir,
648
- });
649
- process.env.ELIZA_API_PORT = String(API_PORT);
845
+ const BUILD_TIMEOUT_MS = 300_000;
846
+ const exited = await waitForChildExit(child, BUILD_TIMEOUT_MS);
847
+ if (!exited) {
848
+ child.kill("SIGKILL");
849
+ throw new Error(
850
+ `Timed out building optional live-stack plugin ${plugin.id} after ${BUILD_TIMEOUT_MS}ms.\n${logs.join("").slice(-8_000)}`,
851
+ );
852
+ }
853
+ if (child.exitCode !== 0) {
854
+ throw new Error(
855
+ `Failed to build optional live-stack plugin ${plugin.id}.\n${logs.join("").slice(-8_000)}`,
856
+ );
857
+ }
858
+ for (const outputPath of outputPaths) {
859
+ await access(outputPath);
860
+ }
861
+ }
862
+ }
650
863
 
651
- return {
652
- apiBase,
653
- apiChild,
654
- stateDir,
655
- uiBase: `http://127.0.0.1:${UI_PORT}`,
656
- uiServer,
657
- };
864
+ async function startStubStack(): Promise<StartedStack> {
865
+ const stateDir = await createStateDir("eliza-ui-smoke-stub-");
866
+ let apiChild: ChildProcessWithoutNullStreams | null = null;
867
+ let uiServer: Server | null = null;
868
+ try {
869
+ const uiDistDir = await snapshotUiDist(stateDir);
870
+ const apiBase = `http://127.0.0.1:${API_PORT}`;
871
+ apiChild = spawn("node", [UI_SMOKE_STUB_SCRIPT], {
872
+ cwd: REPO_ROOT,
873
+ env: {
874
+ ...process.env,
875
+ FORCE_COLOR: "0",
876
+ ELIZA_UI_SMOKE_API_PORT: String(API_PORT),
877
+ ELIZA_UI_SMOKE_STUB_IGNORE_SIGTERM: "1",
878
+ },
879
+ stdio: ["ignore", "pipe", "pipe"],
880
+ });
881
+
882
+ apiChild.stdout.on("data", (chunk) => {
883
+ process.stdout.write(`[ui-smoke][stub] ${chunk}`);
884
+ });
885
+ apiChild.stderr.on("data", (chunk) => {
886
+ process.stdout.write(`[ui-smoke][stub-err] ${chunk}`);
887
+ });
888
+
889
+ await waitForJson<{ complete: boolean }>(`${apiBase}/api/first-run/status`);
890
+ await waitForJsonPredicate<{ state?: string }>(
891
+ `${apiBase}/api/status`,
892
+ (status) => status.state === "running",
893
+ READY_TIMEOUT_MS,
894
+ );
895
+ await waitForJsonPredicate<{ session?: { kind?: string } }>(
896
+ `${apiBase}/api/auth/me`,
897
+ (me) => me.session?.kind === "local",
898
+ READY_TIMEOUT_MS,
899
+ );
900
+
901
+ uiServer = await startUiProxyServer({
902
+ apiBase,
903
+ port: UI_PORT,
904
+ uiDistDir,
905
+ });
906
+ process.env.ELIZA_API_PORT = String(API_PORT);
907
+ markStateDirOwnedByStack(stateDir);
908
+ const startedApiChild = apiChild;
909
+ const startedUiServer = uiServer;
910
+
911
+ return {
912
+ apiBase,
913
+ apiChild: startedApiChild,
914
+ stateDir,
915
+ uiBase: `http://127.0.0.1:${UI_PORT}`,
916
+ uiServer: startedUiServer,
917
+ };
918
+ } catch (error) {
919
+ await closeUiServer(uiServer);
920
+ await stopApiChild(apiChild);
921
+ await rm(stateDir, { force: true, recursive: true });
922
+ pendingStateDirs.delete(stateDir);
923
+ throw error;
924
+ }
658
925
  }
659
926
 
660
927
  async function startRealStack(): Promise<StartedStack> {
@@ -664,84 +931,112 @@ async function startRealStack(): Promise<StartedStack> {
664
931
  return startStubStack();
665
932
  }
666
933
 
667
- const stateDir = await mkdtemp(
668
- path.join(os.tmpdir(), "eliza-ui-smoke-live-"),
669
- );
670
- const uiDistDir = await snapshotUiDist(stateDir);
671
- const apiBase = `http://127.0.0.1:${API_PORT}`;
672
- const apiChild = spawn(
673
- "node",
674
- [
675
- path.join(REPO_ROOT, "packages/app-core/scripts/run-node-tsx.mjs"),
676
- path.join(REPO_ROOT, "packages/app-core/src/runtime/eliza.ts"),
677
- ],
678
- {
679
- cwd: REPO_ROOT,
680
- env: {
681
- ...process.env,
682
- ALLOW_NO_DATABASE: "",
683
- FORCE_COLOR: "0",
684
- ELIZA_API_PORT: String(API_PORT),
685
- ELIZA_HOME_PORT: String(UI_PORT),
686
- ELIZA_PORT: String(API_PORT),
687
- ELIZA_STATE_DIR: stateDir,
934
+ await ensureLiveStackOptionalViewPluginsReady();
935
+
936
+ const stateDir = await createStateDir("eliza-ui-smoke-live-");
937
+ let apiChild: ChildProcessWithoutNullStreams | null = null;
938
+ let uiServer: Server | null = null;
939
+ try {
940
+ await seedLiveStackConfig(stateDir);
941
+ const uiDistDir = await snapshotUiDist(stateDir);
942
+ const apiBase = `http://127.0.0.1:${API_PORT}`;
943
+ const deferredBootComplete = createProcessLogSignal(
944
+ "[eliza-boot] deferred:complete",
945
+ );
946
+ apiChild = spawn(
947
+ "node",
948
+ [
949
+ path.join(REPO_ROOT, "packages/app-core/scripts/run-node-tsx.mjs"),
950
+ path.join(REPO_ROOT, "packages/app-core/src/runtime/eliza.ts"),
951
+ ],
952
+ {
953
+ cwd: REPO_ROOT,
954
+ env: createLiveRuntimeChildEnv({
955
+ ...(LIVE_PROVIDER?.env ?? {}),
956
+ ALLOW_NO_DATABASE: "",
957
+ FORCE_COLOR: "0",
958
+ ELIZA_API_PORT: String(API_PORT),
959
+ ELIZA_HOME_PORT: String(UI_PORT),
960
+ ELIZA_PORT: String(API_PORT),
961
+ ELIZA_STATE_DIR: stateDir,
962
+ }),
963
+ stdio: ["ignore", "pipe", "pipe"],
688
964
  },
689
- stdio: ["ignore", "pipe", "pipe"],
690
- },
691
- );
965
+ );
692
966
 
693
- apiChild.stdout.on("data", (chunk) => {
694
- process.stdout.write(`[ui-smoke][api] ${chunk}`);
695
- });
696
- apiChild.stderr.on("data", (chunk) => {
697
- process.stdout.write(`[ui-smoke][api-err] ${chunk}`);
698
- });
967
+ apiChild.stdout.on("data", (chunk) => {
968
+ deferredBootComplete.observe(chunk);
969
+ process.stdout.write(`[ui-smoke][api] ${chunk}`);
970
+ });
971
+ apiChild.stderr.on("data", (chunk) => {
972
+ deferredBootComplete.observe(chunk);
973
+ process.stdout.write(`[ui-smoke][api-err] ${chunk}`);
974
+ });
699
975
 
700
- await waitForJson<{ complete: boolean }>(`${apiBase}/api/first-run/status`);
701
- // Cloud-live mode (ELIZA_UI_SMOKE_CLOUD_LIVE=1) leaves first-run UNcompleted so
702
- // the spec can drive the real cloud onboarding (login -> provision) through the
703
- // UI against real Eliza Cloud. The default lane auto-completes a local first-run
704
- // so chat/view specs land on a ready agent.
705
- const skipAutoFirstRun = process.env.ELIZA_UI_SMOKE_CLOUD_LIVE === "1";
706
- if (!skipAutoFirstRun) {
707
- const onboardingStatus = await fetchJson<{ complete: boolean }>(
708
- `${apiBase}/api/first-run/status`,
709
- );
710
- if (!onboardingStatus.complete) {
711
- await submitFirstRun(apiBase);
712
- }
976
+ await waitForJson<{ complete: boolean }>(`${apiBase}/api/first-run/status`);
977
+ // Cloud-live mode (ELIZA_UI_SMOKE_CLOUD_LIVE=1) leaves first-run UNcompleted so
978
+ // the spec can drive the real cloud onboarding (login -> provision) through the
979
+ // UI against real Eliza Cloud. The default lane auto-completes a local first-run
980
+ // so chat/view specs land on a ready agent.
981
+ const skipAutoFirstRun = process.env.ELIZA_UI_SMOKE_CLOUD_LIVE === "1";
982
+ if (!skipAutoFirstRun) {
983
+ const onboardingStatus = await fetchJson<{ complete: boolean }>(
984
+ `${apiBase}/api/first-run/status`,
985
+ );
986
+ if (!onboardingStatus.complete) {
987
+ await submitFirstRun(apiBase);
988
+ }
713
989
 
714
- await waitForJsonPredicate<{ complete: boolean }>(
715
- `${apiBase}/api/first-run/status`,
716
- (status) => status.complete === true,
990
+ await waitForJsonPredicate<{ complete: boolean }>(
991
+ `${apiBase}/api/first-run/status`,
992
+ (status) => status.complete === true,
993
+ READY_TIMEOUT_MS,
994
+ );
995
+ }
996
+ await waitForJsonPredicate<{ state?: string }>(
997
+ `${apiBase}/api/status`,
998
+ (status) => status.state === "running",
717
999
  READY_TIMEOUT_MS,
718
1000
  );
719
- }
720
- await waitForJsonPredicate<{ state?: string }>(
721
- `${apiBase}/api/status`,
722
- (status) => status.state === "running",
723
- READY_TIMEOUT_MS,
724
- );
725
- await waitForJsonPredicate<{ session?: { kind?: string } }>(
726
- `${apiBase}/api/auth/me`,
727
- (me) => me.session?.kind === "local",
728
- READY_TIMEOUT_MS,
729
- );
730
-
731
- const uiServer = await startUiProxyServer({
732
- apiBase,
733
- port: UI_PORT,
734
- uiDistDir,
735
- });
736
- process.env.ELIZA_API_PORT = String(API_PORT);
1001
+ await waitForJsonPredicate<{ session?: { kind?: string } }>(
1002
+ `${apiBase}/api/auth/me`,
1003
+ (me) => me.session?.kind === "local",
1004
+ READY_TIMEOUT_MS,
1005
+ );
1006
+ if (!skipAutoFirstRun) {
1007
+ // App-control and plugin views are deferred capabilities. Treat the live
1008
+ // harness as ready only after those runtime plugins have had a chance to
1009
+ // register; otherwise chat-driven view switching can race boot.
1010
+ await deferredBootComplete.wait(
1011
+ READY_TIMEOUT_MS,
1012
+ "deferred runtime plugin registration",
1013
+ );
1014
+ }
737
1015
 
738
- return {
739
- apiBase,
740
- apiChild,
741
- stateDir,
742
- uiBase: `http://127.0.0.1:${UI_PORT}`,
743
- uiServer,
744
- };
1016
+ uiServer = await startUiProxyServer({
1017
+ apiBase,
1018
+ port: UI_PORT,
1019
+ uiDistDir,
1020
+ });
1021
+ process.env.ELIZA_API_PORT = String(API_PORT);
1022
+ markStateDirOwnedByStack(stateDir);
1023
+ const startedApiChild = apiChild;
1024
+ const startedUiServer = uiServer;
1025
+
1026
+ return {
1027
+ apiBase,
1028
+ apiChild: startedApiChild,
1029
+ stateDir,
1030
+ uiBase: `http://127.0.0.1:${UI_PORT}`,
1031
+ uiServer: startedUiServer,
1032
+ };
1033
+ } catch (error) {
1034
+ await closeUiServer(uiServer);
1035
+ await stopApiChild(apiChild);
1036
+ await rm(stateDir, { force: true, recursive: true });
1037
+ pendingStateDirs.delete(stateDir);
1038
+ throw error;
1039
+ }
745
1040
  }
746
1041
 
747
1042
  async function stopRealStack(stack: StartedStack | null): Promise<void> {
@@ -749,35 +1044,25 @@ async function stopRealStack(stack: StartedStack | null): Promise<void> {
749
1044
  return;
750
1045
  }
751
1046
 
752
- try {
753
- await new Promise<void>((resolve, reject) =>
754
- stack.uiServer.close((error) => (error ? reject(error) : resolve())),
755
- );
756
- } catch {
757
- // Best effort during shutdown.
758
- }
759
-
760
- if (stack.apiChild.exitCode == null) {
761
- stack.apiChild.kill("SIGTERM");
762
- const exitedAfterTerm = await waitForChildExit(stack.apiChild, 5_000);
763
- if (!exitedAfterTerm && stack.apiChild.exitCode == null) {
764
- stack.apiChild.kill("SIGKILL");
765
- await waitForChildExit(stack.apiChild, 5_000);
766
- }
767
- }
1047
+ await closeUiServer(stack.uiServer);
1048
+ await stopApiChild(stack.apiChild);
768
1049
 
769
1050
  await rm(stack.stateDir, { force: true, recursive: true });
1051
+ ownedStateDirs.delete(stack.stateDir);
770
1052
  }
771
1053
 
772
1054
  let stack: StartedStack | null = null;
773
1055
  let shuttingDown = false;
774
1056
 
1057
+ process.once("exit", cleanupKnownStateDirsSync);
1058
+
775
1059
  async function shutdown(exitCode: number): Promise<void> {
776
1060
  if (shuttingDown) {
777
1061
  return;
778
1062
  }
779
1063
  shuttingDown = true;
780
1064
  await stopRealStack(stack);
1065
+ await cleanupPendingStateDirs();
781
1066
  process.exit(exitCode);
782
1067
  }
783
1068
 
@@ -808,5 +1093,6 @@ try {
808
1093
  }`,
809
1094
  );
810
1095
  await stopRealStack(stack);
1096
+ await cleanupPendingStateDirs();
811
1097
  process.exit(1);
812
1098
  }