@elizaos/app-core 2.0.0-beta.2 → 2.0.11-beta.5

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 (1534) hide show
  1. package/agent-bridge.d.ts +27 -0
  2. package/agent-bridge.d.ts.map +1 -0
  3. package/agent-bridge.js +26 -0
  4. package/api/__tests__/sandbox-test-helpers.js +1 -1
  5. package/api/auth/audit.js +1 -1
  6. package/api/auth/auth-context.js +1 -1
  7. package/api/auth/bootstrap-token.js +2 -2
  8. package/api/auth/index.d.ts +9 -10
  9. package/api/auth/index.d.ts.map +1 -1
  10. package/api/auth/index.js +9 -10
  11. package/api/auth/passwords.js +2 -2
  12. package/api/auth/sensitive-rate-limit.d.ts +1 -4
  13. package/api/auth/sensitive-rate-limit.d.ts.map +1 -1
  14. package/api/auth/sensitive-rate-limit.js +6 -6
  15. package/api/auth/sessions.js +2 -2
  16. package/api/auth-bootstrap-routes.d.ts +6 -13
  17. package/api/auth-bootstrap-routes.d.ts.map +1 -1
  18. package/api/auth-bootstrap-routes.js +14 -27
  19. package/api/auth-pairing-routes.d.ts +17 -0
  20. package/api/auth-pairing-routes.d.ts.map +1 -0
  21. package/api/auth-pairing-routes.js +300 -0
  22. package/api/auth-session-routes.d.ts.map +1 -1
  23. package/api/auth-session-routes.js +36 -15
  24. package/api/auth.d.ts +12 -19
  25. package/api/auth.d.ts.map +1 -1
  26. package/api/auth.js +32 -27
  27. package/api/automations-compat-routes.d.ts.map +1 -1
  28. package/api/automations-compat-routes.js +5 -5
  29. package/api/background-tasks-routes.d.ts +4 -0
  30. package/api/background-tasks-routes.d.ts.map +1 -0
  31. package/api/background-tasks-routes.js +63 -0
  32. package/api/catalog-routes.js +3 -3
  33. package/api/cloud-pair-route.d.ts +26 -0
  34. package/api/cloud-pair-route.d.ts.map +1 -0
  35. package/api/cloud-pair-route.js +222 -0
  36. package/api/cloud-voice-routes.d.ts +52 -0
  37. package/api/cloud-voice-routes.d.ts.map +1 -0
  38. package/api/cloud-voice-routes.js +50 -0
  39. package/api/compat-route-shared.d.ts +2 -2
  40. package/api/compat-route-shared.d.ts.map +1 -1
  41. package/api/compat-route-shared.js +11 -7
  42. package/api/credential-resolver.d.ts +2 -2
  43. package/api/credential-resolver.d.ts.map +1 -1
  44. package/api/credential-resolver.js +8 -2
  45. package/api/database-rows-compat-routes.d.ts.map +1 -1
  46. package/api/database-rows-compat-routes.js +69 -31
  47. package/api/dev-boot-history.d.ts +26 -0
  48. package/api/dev-boot-history.d.ts.map +1 -0
  49. package/api/dev-boot-history.js +69 -0
  50. package/api/dev-compat-routes.d.ts +5 -0
  51. package/api/dev-compat-routes.d.ts.map +1 -1
  52. package/api/dev-compat-routes.js +127 -4
  53. package/api/dev-console-log.d.ts +2 -2
  54. package/api/dev-console-log.d.ts.map +1 -1
  55. package/api/dev-console-log.js +8 -5
  56. package/api/dev-route-catalog.d.ts +58 -0
  57. package/api/dev-route-catalog.d.ts.map +1 -0
  58. package/api/dev-route-catalog.js +447 -0
  59. package/api/dev-stack.d.ts.map +1 -1
  60. package/api/dev-stack.js +6 -9
  61. package/api/first-run-routes.d.ts +4 -0
  62. package/api/first-run-routes.d.ts.map +1 -0
  63. package/api/first-run-routes.js +208 -0
  64. package/api/first-run-tts-route.d.ts +19 -0
  65. package/api/first-run-tts-route.d.ts.map +1 -0
  66. package/api/first-run-tts-route.js +59 -0
  67. package/api/internal-routes.d.ts +23 -0
  68. package/api/internal-routes.d.ts.map +1 -0
  69. package/api/internal-routes.js +203 -0
  70. package/api/ios-local-agent-transport.d.ts +36 -0
  71. package/api/ios-local-agent-transport.d.ts.map +1 -0
  72. package/api/ios-local-agent-transport.js +566 -0
  73. package/api/onboarding-voice-lines.d.ts +23 -0
  74. package/api/onboarding-voice-lines.d.ts.map +1 -0
  75. package/api/onboarding-voice-lines.js +8 -0
  76. package/api/perf-instrument.d.ts +43 -0
  77. package/api/perf-instrument.d.ts.map +1 -0
  78. package/api/perf-instrument.js +113 -0
  79. package/api/response.d.ts.map +1 -1
  80. package/api/response.js +14 -14
  81. package/api/runtime-mode-routes.d.ts.map +1 -1
  82. package/api/runtime-mode-routes.js +2 -2
  83. package/api/secrets-inventory-routes.js +2 -2
  84. package/api/secrets-manager-routes.d.ts +1 -1
  85. package/api/secrets-manager-routes.d.ts.map +1 -1
  86. package/api/secrets-manager-routes.js +9 -10
  87. package/api/sensitive-request-routes.d.ts.map +1 -1
  88. package/api/sensitive-request-routes.js +5 -5
  89. package/api/sensitive-request-store.d.ts +12 -3
  90. package/api/sensitive-request-store.d.ts.map +1 -1
  91. package/api/server-cors.d.ts.map +1 -1
  92. package/api/server-cors.js +13 -2
  93. package/api/server-first-run-helpers.d.ts +26 -0
  94. package/api/server-first-run-helpers.d.ts.map +1 -0
  95. package/api/server-first-run-helpers.js +271 -0
  96. package/api/server-security.js +1 -1
  97. package/api/server-startup.d.ts.map +1 -1
  98. package/api/server-startup.js +3 -4
  99. package/api/server-wallet-trade.js +1 -1
  100. package/api/server.d.ts +4 -4
  101. package/api/server.d.ts.map +1 -1
  102. package/api/server.js +222 -88
  103. package/api/setup-contract.d.ts +63 -0
  104. package/api/setup-contract.d.ts.map +1 -0
  105. package/api/setup-contract.js +39 -0
  106. package/api/training-benchmarks.d.ts +97 -0
  107. package/api/training-benchmarks.d.ts.map +1 -0
  108. package/api/training-benchmarks.js +307 -0
  109. package/api/workbench-compat-routes.js +2 -2
  110. package/benchmark/cerebras-autowire.d.ts +28 -0
  111. package/benchmark/cerebras-autowire.d.ts.map +1 -0
  112. package/benchmark/cerebras-autowire.js +62 -0
  113. package/benchmark/lifeops-bench-handler.d.ts +36 -0
  114. package/benchmark/lifeops-bench-handler.d.ts.map +1 -1
  115. package/benchmark/lifeops-bench-handler.js +63 -1
  116. package/benchmark/lifeops-fake-backend.d.ts +39 -0
  117. package/benchmark/lifeops-fake-backend.d.ts.map +1 -1
  118. package/benchmark/lifeops-fake-backend.js +993 -21
  119. package/benchmark/mock-plugin.d.ts.map +1 -1
  120. package/benchmark/mock-plugin.js +0 -24
  121. package/benchmark/plugin.d.ts +2 -1
  122. package/benchmark/plugin.d.ts.map +1 -1
  123. package/benchmark/plugin.js +989 -68
  124. package/benchmark/replay-capture.d.ts +2 -2
  125. package/benchmark/replay-capture.d.ts.map +1 -1
  126. package/benchmark/replay-capture.js +3 -3
  127. package/benchmark/server-utils.d.ts +162 -9
  128. package/benchmark/server-utils.d.ts.map +1 -1
  129. package/benchmark/server-utils.js +625 -62
  130. package/benchmark/server.d.ts.map +1 -1
  131. package/benchmark/server.js +1962 -118
  132. package/boot-profile.d.ts +3 -0
  133. package/boot-profile.d.ts.map +1 -0
  134. package/boot-profile.js +30 -0
  135. package/browser.d.ts +23 -1
  136. package/browser.d.ts.map +1 -1
  137. package/browser.js +20 -1
  138. package/cli/argv.js +1 -1
  139. package/cli/banner.js +1 -1
  140. package/cli/command-format.js +2 -2
  141. package/cli/doctor/checks.d.ts.map +1 -1
  142. package/cli/doctor/checks.js +6 -6
  143. package/cli/plugins-cli.d.ts.map +1 -1
  144. package/cli/plugins-cli.js +77 -32
  145. package/cli/profile.d.ts.map +1 -1
  146. package/cli/profile.js +5 -4
  147. package/cli/program/build-program.js +4 -4
  148. package/cli/program/command-registry.d.ts.map +1 -1
  149. package/cli/program/command-registry.js +13 -11
  150. package/cli/program/help.js +5 -5
  151. package/cli/program/preaction.js +5 -5
  152. package/cli/program/register.auth.d.ts.map +1 -1
  153. package/cli/program/register.auth.js +6 -12
  154. package/cli/program/register.capability-router.d.ts +29 -0
  155. package/cli/program/register.capability-router.d.ts.map +1 -0
  156. package/cli/program/register.capability-router.js +568 -0
  157. package/cli/program/register.config.js +1 -1
  158. package/cli/program/register.configure.d.ts.map +1 -1
  159. package/cli/program/register.configure.js +1 -1
  160. package/cli/program/register.dashboard.d.ts.map +1 -1
  161. package/cli/program/register.dashboard.js +6 -7
  162. package/cli/program/register.db.d.ts.map +1 -1
  163. package/cli/program/register.db.js +3 -4
  164. package/cli/program/register.doctor.js +7 -7
  165. package/cli/program/register.setup.d.ts.map +1 -1
  166. package/cli/program/register.setup.js +14 -10
  167. package/cli/program/register.start.d.ts.map +1 -1
  168. package/cli/program/register.start.js +5 -3
  169. package/cli/program/register.subclis.js +3 -3
  170. package/cli/program/register.update.d.ts +6 -0
  171. package/cli/program/register.update.d.ts.map +1 -1
  172. package/cli/program/register.update.js +58 -6
  173. package/cli/program.js +1 -1
  174. package/cli/run-main.js +4 -4
  175. package/config/app-config.d.ts +2 -0
  176. package/config/app-config.d.ts.map +1 -0
  177. package/config/app-config.js +1 -0
  178. package/connectors/capacitor-jsc.d.ts.map +1 -1
  179. package/connectors/capacitor-jsc.js +16 -10
  180. package/connectors/capacitor-quickjs.d.ts.map +1 -1
  181. package/connectors/capacitor-quickjs.js +18 -13
  182. package/connectors/capacitor-sqlite.d.ts.map +1 -1
  183. package/connectors/capacitor-sqlite.js +27 -12
  184. package/dispatch/approval-queue.d.ts +37 -0
  185. package/dispatch/approval-queue.d.ts.map +1 -0
  186. package/dispatch/approval-queue.js +25 -0
  187. package/dispatch/channel-registry.d.ts +30 -0
  188. package/dispatch/channel-registry.d.ts.map +1 -0
  189. package/dispatch/channel-registry.js +22 -0
  190. package/dispatch/connector-registry.d.ts +39 -0
  191. package/dispatch/connector-registry.d.ts.map +1 -0
  192. package/dispatch/connector-registry.js +24 -0
  193. package/dispatch/index.d.ts +14 -0
  194. package/dispatch/index.d.ts.map +1 -0
  195. package/dispatch/index.js +13 -0
  196. package/dispatch/send-policy.d.ts +36 -0
  197. package/dispatch/send-policy.d.ts.map +1 -0
  198. package/dispatch/send-policy.js +16 -0
  199. package/entry.js +28 -11
  200. package/first-run/first-run-config.d.ts +55 -0
  201. package/first-run/first-run-config.d.ts.map +1 -0
  202. package/first-run/first-run-config.js +178 -0
  203. package/first-run/runtime-target.d.ts +4 -0
  204. package/first-run/runtime-target.d.ts.map +1 -0
  205. package/first-run/runtime-target.js +13 -0
  206. package/index.d.ts +16 -3
  207. package/index.d.ts.map +1 -1
  208. package/index.js +57 -33
  209. package/package.json +159 -50
  210. package/packaging/debian/apt-repo-config/README.md +18 -0
  211. package/packaging/debian/apt-repo-config/conf/distributions +11 -0
  212. package/packaging/flatpak/README.md +26 -16
  213. package/packaging/flatpak/ai.elizaos.App.metainfo.xml +17 -12
  214. package/packaging/flatpak/ai.elizaos.App.store.yml +5 -5
  215. package/packaging/flatpak/ai.elizaos.App.yml +10 -24
  216. package/packaging/flatpak/elizaos-app-wrapper.store.sh +2 -2
  217. package/packaging/flatpak/generate-sources.sh +74 -0
  218. package/packaging/flatpak/node-sources.json +7930 -0
  219. package/packaging/inno/build-inno.ps1 +34 -9
  220. package/packaging/msix/AppxManifest.store.xml +1 -1
  221. package/packaging/msix/README.md +39 -19
  222. package/packaging/msix/build-msix.ps1 +44 -14
  223. package/packaging/snap/snapcraft.yaml +22 -21
  224. package/packaging/test-packaging.sh +2 -2
  225. package/permissions/types.d.ts +1 -1
  226. package/permissions/types.js +1 -1
  227. package/platform/elizaos-agent-browser-stub.d.ts +144 -0
  228. package/platform/elizaos-agent-browser-stub.d.ts.map +1 -0
  229. package/platform/elizaos-agent-browser-stub.js +158 -0
  230. package/platform/elizaos-plugin-elizacloud-browser-stub.d.ts +34 -0
  231. package/platform/elizaos-plugin-elizacloud-browser-stub.d.ts.map +1 -0
  232. package/platform/elizaos-plugin-elizacloud-browser-stub.js +51 -0
  233. package/platform/empty-node-module.d.ts +148 -0
  234. package/platform/empty-node-module.d.ts.map +1 -1
  235. package/platform/empty-node-module.js +140 -3
  236. package/platform/ios-runtime-backends.d.ts +83 -0
  237. package/platform/ios-runtime-backends.d.ts.map +1 -0
  238. package/platform/ios-runtime-backends.js +133 -0
  239. package/platform/ios-runtime-bridge.d.ts +15 -0
  240. package/platform/ios-runtime-bridge.d.ts.map +1 -0
  241. package/platform/ios-runtime-bridge.js +527 -0
  242. package/platform/native-library-policy.d.ts +23 -0
  243. package/platform/native-library-policy.d.ts.map +1 -0
  244. package/platform/native-library-policy.js +112 -0
  245. package/platform/native-plugin-entrypoints.d.ts +19 -0
  246. package/platform/native-plugin-entrypoints.d.ts.map +1 -0
  247. package/platform/native-plugin-entrypoints.js +29 -0
  248. package/platforms/android/README.md +68 -10
  249. package/platforms/android/app/build.gradle +268 -3
  250. package/platforms/android/app/capacitor.build.gradle +18 -1
  251. package/platforms/android/app/proguard-rules.pro +17 -2
  252. package/platforms/android/app/src/androidTest/java/ai/elizaos/app/ElizaOsInstrumentedTest.java +1 -1
  253. package/platforms/android/app/src/main/AndroidManifest.xml +334 -17
  254. package/platforms/android/app/src/main/assets/runners/eliza-tasks.js +177 -0
  255. package/platforms/android/app/src/main/elizavoice-jni/CMakeLists.txt +75 -0
  256. package/platforms/android/app/src/main/elizavoice-jni/elizavoice-jni.cpp +1045 -0
  257. package/platforms/android/app/src/main/java/ai/elizaos/app/AgentPlugin.java +111 -171
  258. package/platforms/android/app/src/main/java/ai/elizaos/app/AndroidVirtualizationBridge.java +284 -0
  259. package/platforms/android/app/src/main/java/ai/elizaos/app/BatteryOptimizationPlugin.java +95 -0
  260. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAccessibilityService.java +55 -0
  261. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAgentService.java +1198 -141
  262. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAndroidSystemBridge.java +83 -0
  263. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAssistActivity.java +50 -1
  264. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaBootReceiver.java +90 -8
  265. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaBrowserActivity.java +2 -2
  266. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaCalendarActivity.java +1 -1
  267. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaCameraActivity.java +1 -1
  268. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaClockActivity.java +2 -2
  269. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaContactsActivity.java +1 -1
  270. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaDialActivity.java +1 -1
  271. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaInCallService.java +1 -1
  272. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaMmsReceiver.java +1 -1
  273. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaNativeBridge.java +22 -0
  274. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaNotificationListenerService.java +45 -0
  275. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaQuickActionsWidgetProvider.java +68 -0
  276. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaShareActivity.java +132 -0
  277. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaSmsComposeActivity.java +1 -1
  278. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaSmsGatewayService.java +268 -0
  279. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaSmsReceiver.java +12 -1
  280. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaTasksWorker.java +194 -0
  281. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoiceCaptureService.java +198 -0
  282. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoiceNative.java +160 -0
  283. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoicePlugin.java +450 -0
  284. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoiceTileService.java +39 -0
  285. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaWorkScheduler.java +60 -0
  286. package/platforms/android/app/src/main/java/ai/elizaos/app/GatewayConnectionService.java +53 -19
  287. package/platforms/android/app/src/main/java/ai/elizaos/app/MainActivity.java +160 -33
  288. package/platforms/android/app/src/main/java/ai/elizaos/app/ResourceProbePlugin.java +169 -0
  289. package/platforms/android/app/src/main/java/ai/elizaos/app/VoiceCapturePlugin.java +119 -0
  290. package/platforms/android/app/src/main/res/drawable/eliza_widget_background.xml +10 -0
  291. package/platforms/android/app/src/main/res/drawable/eliza_widget_button_background.xml +13 -0
  292. package/platforms/android/app/src/main/res/drawable/splash.png +0 -0
  293. package/platforms/android/app/src/main/res/drawable-land-hdpi/splash.png +0 -0
  294. package/platforms/android/app/src/main/res/drawable-land-mdpi/splash.png +0 -0
  295. package/platforms/android/app/src/main/res/drawable-land-xhdpi/splash.png +0 -0
  296. package/platforms/android/app/src/main/res/drawable-land-xxhdpi/splash.png +0 -0
  297. package/platforms/android/app/src/main/res/drawable-land-xxxhdpi/splash.png +0 -0
  298. package/platforms/android/app/src/main/res/drawable-port-hdpi/splash.png +0 -0
  299. package/platforms/android/app/src/main/res/drawable-port-mdpi/splash.png +0 -0
  300. package/platforms/android/app/src/main/res/drawable-port-xhdpi/splash.png +0 -0
  301. package/platforms/android/app/src/main/res/drawable-port-xxhdpi/splash.png +0 -0
  302. package/platforms/android/app/src/main/res/drawable-port-xxxhdpi/splash.png +0 -0
  303. package/platforms/android/app/src/main/res/layout/eliza_quick_actions_widget.xml +86 -0
  304. package/platforms/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +2 -1
  305. package/platforms/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +2 -1
  306. package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  307. package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
  308. package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png +0 -0
  309. package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  310. package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  311. package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
  312. package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png +0 -0
  313. package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  314. package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  315. package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
  316. package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png +0 -0
  317. package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  318. package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  319. package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
  320. package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png +0 -0
  321. package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  322. package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  323. package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
  324. package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png +0 -0
  325. package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  326. package/platforms/android/app/src/main/res/values/android_app_actions.xml +48 -0
  327. package/platforms/android/app/src/main/res/values/colors.xml +8 -0
  328. package/platforms/android/app/src/main/res/values/ic_launcher_background.xml +2 -2
  329. package/platforms/android/app/src/main/res/values/strings.xml +2 -2
  330. package/platforms/android/app/src/main/res/values/styles.xml +25 -1
  331. package/platforms/android/app/src/main/res/xml/eliza_accessibility_service.xml +9 -0
  332. package/platforms/android/app/src/main/res/xml/eliza_quick_actions_widget.xml +13 -0
  333. package/platforms/android/app/src/main/res/xml/shortcuts.xml +121 -0
  334. package/platforms/android/build.gradle +2 -2
  335. package/platforms/android/capacitor-cordova-android-plugins/build.gradle +9 -3
  336. package/platforms/android/capacitor-cordova-android-plugins/cordova.variables.gradle +6 -2
  337. package/platforms/android/capacitor-cordova-android-plugins/src/main/AndroidManifest.xml +7 -2
  338. package/platforms/android/capacitor-cordova-android-plugins/src/main/java/.gitkeep +0 -1
  339. package/platforms/android/capacitor.settings.gradle +66 -16
  340. package/platforms/android/gradle.properties +1 -0
  341. package/platforms/android/update-manifest/generate-manifest.mjs +97 -0
  342. package/platforms/android/update-manifest/schema.json +26 -0
  343. package/platforms/apple-store-entitlements.reviewed.json +155 -0
  344. package/platforms/electrobun/.generated/brand-config.json +3 -2
  345. package/platforms/electrobun/LICENSE +21 -0
  346. package/platforms/electrobun/README.md +15 -1
  347. package/platforms/electrobun/assets/appIcon.icns +0 -0
  348. package/platforms/electrobun/assets/appIcon.ico +0 -0
  349. package/platforms/electrobun/assets/appIcon.iconset/icon_128x128.png +0 -0
  350. package/platforms/electrobun/assets/appIcon.iconset/icon_128x128@2x.png +0 -0
  351. package/platforms/electrobun/assets/appIcon.iconset/icon_16x16.png +0 -0
  352. package/platforms/electrobun/assets/appIcon.iconset/icon_16x16@2x.png +0 -0
  353. package/platforms/electrobun/assets/appIcon.iconset/icon_256x256.png +0 -0
  354. package/platforms/electrobun/assets/appIcon.iconset/icon_256x256@2x.png +0 -0
  355. package/platforms/electrobun/assets/appIcon.iconset/icon_32x32.png +0 -0
  356. package/platforms/electrobun/assets/appIcon.iconset/icon_32x32@2x.png +0 -0
  357. package/platforms/electrobun/assets/appIcon.iconset/icon_512x512.png +0 -0
  358. package/platforms/electrobun/assets/brand-config.json +6 -6
  359. package/platforms/electrobun/biome.json +9 -9
  360. package/platforms/electrobun/docs/capability-collapse-matrix.json +318 -0
  361. package/platforms/electrobun/docs/capability-collapse-matrix.md +129 -0
  362. package/platforms/electrobun/docs/capability-routing.md +86 -0
  363. package/platforms/electrobun/docs/convergence-audit.json +3505 -0
  364. package/platforms/electrobun/docs/convergence-audit.md +694 -0
  365. package/platforms/electrobun/docs/database-boot-policy.md +90 -0
  366. package/platforms/electrobun/docs/riscv64-port.md +175 -0
  367. package/platforms/electrobun/docs/startup-first-run-cleanup.md +18 -0
  368. package/platforms/electrobun/docs/trace-first-annotations.md +52 -0
  369. package/platforms/electrobun/docs/ui-boundary-audit.json +580 -0
  370. package/platforms/electrobun/docs/ui-boundary-audit.md +257 -0
  371. package/platforms/electrobun/electrobun.config.ts +592 -364
  372. package/platforms/electrobun/entitlements/JUSTIFICATIONS.md +141 -0
  373. package/platforms/electrobun/entitlements/README.md +34 -6
  374. package/platforms/electrobun/entitlements/mas-bun.entitlements +15 -0
  375. package/platforms/electrobun/entitlements/mas.entitlements +6 -4
  376. package/platforms/electrobun/native/macos/window-effects.mm +1522 -0
  377. package/platforms/electrobun/package.json +18 -12
  378. package/platforms/electrobun/remotes/fs/README.md +70 -0
  379. package/platforms/electrobun/remotes/fs/electrobun.config.ts +38 -0
  380. package/platforms/electrobun/remotes/fs/package.json +12 -0
  381. package/platforms/electrobun/remotes/fs/plugin.json +25 -0
  382. package/platforms/electrobun/remotes/fs/src/bun/errors.ts +57 -0
  383. package/platforms/electrobun/remotes/fs/src/bun/file-limits.ts +50 -0
  384. package/platforms/electrobun/remotes/fs/src/bun/fs-service.ts +389 -0
  385. package/platforms/electrobun/remotes/fs/src/bun/path-guard.ts +270 -0
  386. package/platforms/electrobun/remotes/fs/src/bun/protocol.ts +149 -0
  387. package/platforms/electrobun/remotes/fs/src/bun/worker.ts +174 -0
  388. package/platforms/electrobun/remotes/fs/src/dev/phase5-smoke.ts +171 -0
  389. package/platforms/electrobun/remotes/fs/src/web/index.html +8 -0
  390. package/platforms/electrobun/remotes/git/README.md +75 -0
  391. package/platforms/electrobun/remotes/git/electrobun.config.ts +44 -0
  392. package/platforms/electrobun/remotes/git/package.json +12 -0
  393. package/platforms/electrobun/remotes/git/plugin.json +31 -0
  394. package/platforms/electrobun/remotes/git/src/bun/errors.ts +69 -0
  395. package/platforms/electrobun/remotes/git/src/bun/git-command.ts +156 -0
  396. package/platforms/electrobun/remotes/git/src/bun/git-service.ts +446 -0
  397. package/platforms/electrobun/remotes/git/src/bun/operation-history.ts +124 -0
  398. package/platforms/electrobun/remotes/git/src/bun/protocol.ts +252 -0
  399. package/platforms/electrobun/remotes/git/src/bun/worker.ts +316 -0
  400. package/platforms/electrobun/remotes/git/src/dev/phase7-smoke.ts +141 -0
  401. package/platforms/electrobun/remotes/git/src/web/index.html +8 -0
  402. package/platforms/electrobun/remotes/local-model/README.md +138 -0
  403. package/platforms/electrobun/remotes/local-model/electrobun.config.ts +46 -0
  404. package/platforms/electrobun/remotes/local-model/package.json +12 -0
  405. package/platforms/electrobun/remotes/local-model/plugin.json +33 -0
  406. package/platforms/electrobun/remotes/local-model/src/bun/download-state.ts +115 -0
  407. package/platforms/electrobun/remotes/local-model/src/bun/eliza1-catalog.ts +425 -0
  408. package/platforms/electrobun/remotes/local-model/src/bun/errors.ts +74 -0
  409. package/platforms/electrobun/remotes/local-model/src/bun/hf-eliza1-client.ts +169 -0
  410. package/platforms/electrobun/remotes/local-model/src/bun/local-inference-api-client.ts +245 -0
  411. package/platforms/electrobun/remotes/local-model/src/bun/model-service.ts +490 -0
  412. package/platforms/electrobun/remotes/local-model/src/bun/protocol.ts +301 -0
  413. package/platforms/electrobun/remotes/local-model/src/bun/worker.ts +248 -0
  414. package/platforms/electrobun/remotes/local-model/src/dev/phase8-smoke.ts +117 -0
  415. package/platforms/electrobun/remotes/local-model/src/web/index.html +13 -0
  416. package/platforms/electrobun/remotes/pty/README.md +65 -0
  417. package/platforms/electrobun/remotes/pty/electrobun.config.ts +47 -0
  418. package/platforms/electrobun/remotes/pty/package.json +12 -0
  419. package/platforms/electrobun/remotes/pty/plugin.json +34 -0
  420. package/platforms/electrobun/remotes/pty/src/bun/errors.ts +57 -0
  421. package/platforms/electrobun/remotes/pty/src/bun/output-buffer.ts +127 -0
  422. package/platforms/electrobun/remotes/pty/src/bun/protocol.ts +192 -0
  423. package/platforms/electrobun/remotes/pty/src/bun/pty-service.ts +562 -0
  424. package/platforms/electrobun/remotes/pty/src/bun/worker.ts +218 -0
  425. package/platforms/electrobun/remotes/pty/src/dev/phase6-smoke.ts +127 -0
  426. package/platforms/electrobun/remotes/pty/src/web/index.html +8 -0
  427. package/platforms/electrobun/remotes/runtime/README.md +370 -0
  428. package/platforms/electrobun/remotes/runtime/electrobun.config.ts +48 -0
  429. package/platforms/electrobun/remotes/runtime/package.json +14 -0
  430. package/platforms/electrobun/remotes/runtime/plugin.json +30 -0
  431. package/platforms/electrobun/remotes/runtime/src/bun/api-client.ts +620 -0
  432. package/platforms/electrobun/remotes/runtime/src/bun/errors.ts +45 -0
  433. package/platforms/electrobun/remotes/runtime/src/bun/log-buffer.ts +33 -0
  434. package/platforms/electrobun/remotes/runtime/src/bun/protocol.ts +366 -0
  435. package/platforms/electrobun/remotes/runtime/src/bun/route-discovery.ts +419 -0
  436. package/platforms/electrobun/remotes/runtime/src/bun/runtime-manager.ts +423 -0
  437. package/platforms/electrobun/remotes/runtime/src/bun/sse-parser.ts +99 -0
  438. package/platforms/electrobun/remotes/runtime/src/bun/stream-manager.ts +887 -0
  439. package/platforms/electrobun/remotes/runtime/src/bun/worker.ts +1231 -0
  440. package/platforms/electrobun/remotes/runtime/src/dev/phase1-smoke.ts +34 -0
  441. package/platforms/electrobun/remotes/runtime/src/dev/phase2-smoke.ts +86 -0
  442. package/platforms/electrobun/remotes/runtime/src/dev/phase3-smoke.ts +141 -0
  443. package/platforms/electrobun/remotes/runtime/src/web/index.css +187 -0
  444. package/platforms/electrobun/remotes/runtime/src/web/index.html +76 -0
  445. package/platforms/electrobun/remotes/runtime/src/web/index.ts +192 -0
  446. package/platforms/electrobun/remotes/surface/README.md +201 -0
  447. package/platforms/electrobun/remotes/surface/electrobun.config.ts +38 -0
  448. package/platforms/electrobun/remotes/surface/package.json +12 -0
  449. package/platforms/electrobun/remotes/surface/plugin.json +28 -0
  450. package/platforms/electrobun/remotes/surface/src/bun/worker.ts +132 -0
  451. package/platforms/electrobun/remotes/surface/src/dev/phase4-smoke.ts +566 -0
  452. package/platforms/electrobun/remotes/surface/src/protocol/event-types.ts +84 -0
  453. package/platforms/electrobun/remotes/surface/src/protocol/runtime-client.ts +673 -0
  454. package/platforms/electrobun/remotes/surface/src/web/app.ts +595 -0
  455. package/platforms/electrobun/remotes/surface/src/web/index.css +460 -0
  456. package/platforms/electrobun/remotes/surface/src/web/index.html +466 -0
  457. package/platforms/electrobun/remotes/surface/src/web/index.ts +5 -0
  458. package/platforms/electrobun/remotes/surface/src/web/render.ts +455 -0
  459. package/platforms/electrobun/remotes/surface/src/web/state.ts +427 -0
  460. package/platforms/electrobun/scripts/build-macos-effects.sh +4 -0
  461. package/platforms/electrobun/scripts/ensure-build-folder.ts +28 -0
  462. package/platforms/electrobun/scripts/ensure-whisper-gguf.sh +55 -0
  463. package/platforms/electrobun/scripts/ensure-whisper-model.sh +22 -80
  464. package/platforms/electrobun/scripts/generate-convergence-audit.ts +1203 -0
  465. package/platforms/electrobun/scripts/local-adhoc-sign-macos.ts +159 -159
  466. package/platforms/electrobun/scripts/postwrap-diagnostics.ts +424 -339
  467. package/platforms/electrobun/scripts/postwrap-sign-runtime-macos.ts +302 -271
  468. package/platforms/electrobun/scripts/smoke-test-windows.ps1 +17 -16
  469. package/platforms/electrobun/scripts/smoke-test.sh +5 -7
  470. package/platforms/electrobun/scripts/sync-web-assets.mjs +13 -13
  471. package/platforms/electrobun/scripts/verify-rpc-handlers.ts +109 -110
  472. package/platforms/electrobun/scripts/verify-windows-installer-proof.ps1 +3 -8
  473. package/platforms/electrobun/src/__stubs__/bun-ffi.ts +31 -31
  474. package/platforms/electrobun/src/__stubs__/electrobun-bun.ts +1 -1
  475. package/platforms/electrobun/src/agent-ready-state.ts +8 -8
  476. package/platforms/electrobun/src/agent-reset-from-main.test.ts +162 -0
  477. package/platforms/electrobun/src/agent-reset-from-main.ts +62 -62
  478. package/platforms/electrobun/src/agent-status-rpc.test.ts +95 -0
  479. package/platforms/electrobun/src/agent-status-rpc.ts +156 -0
  480. package/platforms/electrobun/src/api-base.test.ts +247 -0
  481. package/platforms/electrobun/src/api-base.ts +202 -93
  482. package/platforms/electrobun/src/application-menu-action-registry.ts +9 -9
  483. package/platforms/electrobun/src/application-menu.ts +348 -348
  484. package/platforms/electrobun/src/background-notice.ts +36 -36
  485. package/platforms/electrobun/src/boot-progress.test.ts +188 -0
  486. package/platforms/electrobun/src/boot-progress.ts +111 -0
  487. package/platforms/electrobun/src/brand-config.test.ts +39 -0
  488. package/platforms/electrobun/src/brand-config.ts +141 -129
  489. package/platforms/electrobun/src/bridge/browser-tabs-renderer-registry.ts +28 -28
  490. package/platforms/electrobun/src/bridge/electrobun-boot-config.ts +42 -0
  491. package/platforms/electrobun/src/bridge/electrobun-crypto-ready.ts +120 -0
  492. package/platforms/electrobun/src/bridge/electrobun-direct-rpc.ts +342 -357
  493. package/platforms/electrobun/src/bridge/electrobun-stub.ts +13 -13
  494. package/platforms/electrobun/src/browser-workspace-bridge-server.ts +285 -243
  495. package/platforms/electrobun/src/cloud-auth-window.ts +136 -136
  496. package/platforms/electrobun/src/cloud-disconnect-from-main.ts +90 -90
  497. package/platforms/electrobun/src/config-and-auth-rpc.test.ts +256 -0
  498. package/platforms/electrobun/src/config-and-auth-rpc.ts +302 -0
  499. package/platforms/electrobun/src/conversations-and-character-rpc.test.ts +185 -0
  500. package/platforms/electrobun/src/conversations-and-character-rpc.ts +131 -0
  501. package/platforms/electrobun/src/dashboard-rpc.test.ts +200 -0
  502. package/platforms/electrobun/src/dashboard-rpc.ts +344 -0
  503. package/platforms/electrobun/src/database/database-lock.ts +141 -0
  504. package/platforms/electrobun/src/database/database-mode.ts +149 -0
  505. package/platforms/electrobun/src/database/database-recovery.ts +72 -0
  506. package/platforms/electrobun/src/database/database-snapshot.ts +190 -0
  507. package/platforms/electrobun/src/database/database.test.ts +196 -0
  508. package/platforms/electrobun/src/database/index.ts +5 -0
  509. package/platforms/electrobun/src/database/pglite-paths.ts +100 -0
  510. package/platforms/electrobun/src/desktop-deep-link-events.test.ts +30 -0
  511. package/platforms/electrobun/src/desktop-deep-link-events.ts +17 -0
  512. package/platforms/electrobun/src/desktop-http-request.test.ts +73 -73
  513. package/platforms/electrobun/src/desktop-http-request.ts +85 -85
  514. package/platforms/electrobun/src/desktop-pill-config.test.ts +27 -0
  515. package/platforms/electrobun/src/desktop-pill-config.ts +40 -0
  516. package/platforms/electrobun/src/desktop-test-bridge-server.ts +204 -204
  517. package/platforms/electrobun/src/desktop-tray-config.test.ts +87 -0
  518. package/platforms/electrobun/src/desktop-tray-config.ts +84 -0
  519. package/platforms/electrobun/src/devtools-layout.ts +41 -41
  520. package/platforms/electrobun/src/diagnostic-format.test.ts +71 -0
  521. package/platforms/electrobun/src/diagnostic-format.ts +75 -36
  522. package/platforms/electrobun/src/dynamic-view-rpc-schema.test.ts +37 -0
  523. package/platforms/electrobun/src/dynamic-views/README.md +44 -0
  524. package/platforms/electrobun/src/dynamic-views/demo/agent-run-trace.html +135 -0
  525. package/platforms/electrobun/src/dynamic-views/errors.ts +29 -0
  526. package/platforms/electrobun/src/dynamic-views/host.test.ts +353 -0
  527. package/platforms/electrobun/src/dynamic-views/host.ts +332 -0
  528. package/platforms/electrobun/src/dynamic-views/index.ts +57 -0
  529. package/platforms/electrobun/src/dynamic-views/kiosk-canvas.ts +89 -0
  530. package/platforms/electrobun/src/dynamic-views/registry.test.ts +139 -0
  531. package/platforms/electrobun/src/dynamic-views/registry.ts +196 -0
  532. package/platforms/electrobun/src/dynamic-views/session-manager.test.ts +355 -0
  533. package/platforms/electrobun/src/dynamic-views/session-manager.ts +348 -0
  534. package/platforms/electrobun/src/dynamic-views/types.ts +105 -0
  535. package/platforms/electrobun/src/electrobun-boot-config.test.ts +50 -0
  536. package/platforms/electrobun/src/electrobun-config.test.ts +62 -0
  537. package/platforms/electrobun/src/electrobun-crypto-ready.test.ts +65 -0
  538. package/platforms/electrobun/src/electrobun-window-options.ts +25 -0
  539. package/platforms/electrobun/src/extension-rpc.test.ts +88 -0
  540. package/platforms/electrobun/src/extension-rpc.ts +102 -0
  541. package/platforms/electrobun/src/fatal-shutdown.test.ts +10 -10
  542. package/platforms/electrobun/src/fatal-shutdown.ts +1 -1
  543. package/platforms/electrobun/src/first-party-remotes.test.ts +169 -0
  544. package/platforms/electrobun/src/first-party-remotes.ts +297 -0
  545. package/platforms/electrobun/src/first-run-rpc.test.ts +192 -0
  546. package/platforms/electrobun/src/first-run-rpc.ts +146 -0
  547. package/platforms/electrobun/src/floating-chat-window.ts +181 -181
  548. package/platforms/electrobun/src/inbox-rpc.test.ts +123 -0
  549. package/platforms/electrobun/src/inbox-rpc.ts +158 -0
  550. package/platforms/electrobun/src/index.ts +2555 -2096
  551. package/platforms/electrobun/src/kiosk-mode.ts +50 -0
  552. package/platforms/electrobun/src/launch/index.ts +4 -0
  553. package/platforms/electrobun/src/launch/launch-dynamic-view.ts +37 -0
  554. package/platforms/electrobun/src/launch/launch-orchestrator.test.ts +224 -0
  555. package/platforms/electrobun/src/launch/launch-orchestrator.ts +456 -0
  556. package/platforms/electrobun/src/launch/launch-store.test.ts +97 -0
  557. package/platforms/electrobun/src/launch/launch-store.ts +134 -0
  558. package/platforms/electrobun/src/launch/types.ts +103 -0
  559. package/platforms/electrobun/src/launch/views/launch-diagnostics.html +205 -0
  560. package/platforms/electrobun/src/lifecycle/agent-ready-publish.test.ts +50 -0
  561. package/platforms/electrobun/src/lifecycle/agent-ready-publish.ts +27 -0
  562. package/platforms/electrobun/src/lifecycle/api-base-owner.ts +42 -31
  563. package/platforms/electrobun/src/lifecycle/desktop-session-prime.ts +44 -44
  564. package/platforms/electrobun/src/logger.ts +14 -14
  565. package/platforms/electrobun/src/main-window-runtime.ts +83 -83
  566. package/platforms/electrobun/src/main-window-session.test.ts +109 -0
  567. package/platforms/electrobun/src/main-window-session.ts +87 -51
  568. package/platforms/electrobun/src/menu-reset-from-main.ts +158 -158
  569. package/platforms/electrobun/src/native/agent-env.test.ts +52 -0
  570. package/platforms/electrobun/src/native/agent-runtime-layout.test.ts +42 -0
  571. package/platforms/electrobun/src/native/agent-state-dir.test.ts +91 -0
  572. package/platforms/electrobun/src/native/agent.ts +2122 -1682
  573. package/platforms/electrobun/src/native/auth-bridge.test.ts +67 -0
  574. package/platforms/electrobun/src/native/auth-bridge.ts +464 -360
  575. package/platforms/electrobun/src/native/browser-workspace.ts +723 -471
  576. package/platforms/electrobun/src/native/camera.ts +50 -50
  577. package/platforms/electrobun/src/native/canvas.ts +444 -445
  578. package/platforms/electrobun/src/native/credentials.ts +673 -616
  579. package/platforms/electrobun/src/native/desktop-window.test.ts +300 -0
  580. package/platforms/electrobun/src/native/desktop.ts +2196 -2156
  581. package/platforms/electrobun/src/native/editor-bridge.ts +201 -201
  582. package/platforms/electrobun/src/native/file-watcher.ts +154 -154
  583. package/platforms/electrobun/src/native/gateway.ts +179 -180
  584. package/platforms/electrobun/src/native/gpu-window.ts +256 -256
  585. package/platforms/electrobun/src/native/index.ts +76 -74
  586. package/platforms/electrobun/src/native/location.test.ts +44 -0
  587. package/platforms/electrobun/src/native/location.ts +90 -80
  588. package/platforms/electrobun/src/native/loopback-port.ts +60 -60
  589. package/platforms/electrobun/src/native/mac-window-effects.ts +166 -104
  590. package/platforms/electrobun/src/native/music-player.ts +38 -38
  591. package/platforms/electrobun/src/native/permissions-shared.ts +249 -150
  592. package/platforms/electrobun/src/native/permissions.ts +301 -208
  593. package/platforms/electrobun/src/native/power-state.ts +129 -129
  594. package/platforms/electrobun/src/native/remote-plugin-host.test.ts +1394 -0
  595. package/platforms/electrobun/src/native/remote-plugin-host.ts +1531 -0
  596. package/platforms/electrobun/src/native/screencapture.ts +667 -573
  597. package/platforms/electrobun/src/native/steward.ts +207 -204
  598. package/platforms/electrobun/src/native/swabble.ts +68 -324
  599. package/platforms/electrobun/src/native/talkmode.ts +253 -422
  600. package/platforms/electrobun/src/native/webgpu-browser-support.test.ts +18 -0
  601. package/platforms/electrobun/src/native/webgpu-browser-support.ts +165 -147
  602. package/platforms/electrobun/src/native/whisper-env.test.ts +71 -0
  603. package/platforms/electrobun/src/native/whisper-env.ts +68 -0
  604. package/platforms/electrobun/src/native-onboarding.ts +270 -0
  605. package/platforms/electrobun/src/onboarding-overlay-window.ts +141 -0
  606. package/platforms/electrobun/src/persisted-deployment.ts +91 -0
  607. package/platforms/electrobun/src/pill-window.test.ts +91 -0
  608. package/platforms/electrobun/src/pill-window.ts +99 -0
  609. package/platforms/electrobun/src/preload-validation.ts +44 -44
  610. package/platforms/electrobun/src/preload.js +1 -1
  611. package/platforms/electrobun/src/print-electrobun-dev-settings-banner.ts +120 -120
  612. package/platforms/electrobun/src/renderer-api-proxy.test.ts +73 -0
  613. package/platforms/electrobun/src/renderer-api-proxy.ts +86 -0
  614. package/platforms/electrobun/src/renderer-static.test.ts +53 -0
  615. package/platforms/electrobun/src/renderer-static.ts +144 -57
  616. package/platforms/electrobun/src/rpc-handler-slices.ts +121 -0
  617. package/platforms/electrobun/src/rpc-handlers.test.ts +267 -0
  618. package/platforms/electrobun/src/rpc-handlers.ts +1306 -913
  619. package/platforms/electrobun/src/rpc-parse-utils.ts +57 -0
  620. package/platforms/electrobun/src/rpc-port-resolver.test.ts +45 -0
  621. package/platforms/electrobun/src/rpc-port-resolver.ts +31 -0
  622. package/platforms/electrobun/src/rpc-schema.ts +2556 -1619
  623. package/platforms/electrobun/src/runtime-layout.ts +105 -105
  624. package/platforms/electrobun/src/runtime-permissions.ts +95 -95
  625. package/platforms/electrobun/src/runtime-rpc.test.ts +126 -0
  626. package/platforms/electrobun/src/runtime-rpc.ts +237 -0
  627. package/platforms/electrobun/src/screenshot-dev-server.ts +87 -87
  628. package/platforms/electrobun/src/settings-mutations-rpc.test.ts +193 -0
  629. package/platforms/electrobun/src/settings-mutations-rpc.ts +220 -0
  630. package/platforms/electrobun/src/startup-trace.ts +274 -270
  631. package/platforms/electrobun/src/subscription-rpc.test.ts +89 -0
  632. package/platforms/electrobun/src/subscription-rpc.ts +192 -0
  633. package/platforms/electrobun/src/surface-windows.test.ts +355 -0
  634. package/platforms/electrobun/src/surface-windows.ts +410 -410
  635. package/platforms/electrobun/src/trace/README.md +73 -0
  636. package/platforms/electrobun/src/trace/errors.ts +21 -0
  637. package/platforms/electrobun/src/trace/index.ts +40 -0
  638. package/platforms/electrobun/src/trace/trace-dynamic-view.ts +40 -0
  639. package/platforms/electrobun/src/trace/trace-host-requests.ts +473 -0
  640. package/platforms/electrobun/src/trace/trace-service.test.ts +186 -0
  641. package/platforms/electrobun/src/trace/trace-service.ts +324 -0
  642. package/platforms/electrobun/src/trace/trace-store.test.ts +141 -0
  643. package/platforms/electrobun/src/trace/trace-store.ts +551 -0
  644. package/platforms/electrobun/src/trace/types.ts +250 -0
  645. package/platforms/electrobun/src/trace/views/agent-run-trace.html +311 -0
  646. package/platforms/electrobun/src/types/web-speech.d.ts +28 -28
  647. package/platforms/electrobun/src/types.ts +5 -5
  648. package/platforms/electrobun/src/update-availability.test.ts +72 -0
  649. package/platforms/electrobun/src/update-availability.ts +90 -0
  650. package/platforms/electrobun/src/update-rpc.test.ts +83 -0
  651. package/platforms/electrobun/src/update-rpc.ts +123 -0
  652. package/platforms/electrobun/src/voice/README.md +184 -0
  653. package/platforms/electrobun/src/voice/errors.ts +42 -0
  654. package/platforms/electrobun/src/voice/index.ts +78 -0
  655. package/platforms/electrobun/src/voice/types.ts +316 -0
  656. package/platforms/electrobun/src/voice/voice-host-requests.ts +259 -0
  657. package/platforms/electrobun/src/voice/voice-latency-budget.test.ts +66 -0
  658. package/platforms/electrobun/src/voice/voice-latency-budget.ts +243 -0
  659. package/platforms/electrobun/src/voice/voice-live-validation.test.ts +352 -0
  660. package/platforms/electrobun/src/voice/voice-live-validation.ts +838 -0
  661. package/platforms/electrobun/src/voice/voice-pipeline.ts +250 -0
  662. package/platforms/electrobun/src/voice/voice-playback-adapter.ts +31 -0
  663. package/platforms/electrobun/src/voice/voice-runtime-adapter.test.ts +213 -0
  664. package/platforms/electrobun/src/voice/voice-runtime-adapter.ts +686 -0
  665. package/platforms/electrobun/src/voice/voice-service.test.ts +561 -0
  666. package/platforms/electrobun/src/voice/voice-service.ts +1027 -0
  667. package/platforms/electrobun/src/voice/voice-stream-coordinator.test.ts +115 -0
  668. package/platforms/electrobun/src/voice/voice-stream-coordinator.ts +270 -0
  669. package/platforms/electrobun/src/voice/voice-trace.ts +97 -0
  670. package/platforms/electrobun/src/voice/voice-tts-chunker.test.ts +91 -0
  671. package/platforms/electrobun/src/voice/voice-tts-chunker.ts +194 -0
  672. package/platforms/electrobun/src/windows-cef-profile.ts +88 -88
  673. package/platforms/electrobun/tsconfig.json +73 -13
  674. package/platforms/electrobun/update-channels.json +22 -0
  675. package/platforms/electrobun/vitest.electrobun.config.ts +72 -42
  676. package/platforms/ios/App/App/App.entitlements +4 -0
  677. package/platforms/ios/App/App/AppDelegate.swift +80 -18
  678. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ios-marketing-1024.png +0 -0
  679. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20@1x.png +0 -0
  680. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20@2x.png +0 -0
  681. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29@1x.png +0 -0
  682. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29@2x.png +0 -0
  683. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40@1x.png +0 -0
  684. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40@2x.png +0 -0
  685. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76@1x.png +0 -0
  686. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76@2x.png +0 -0
  687. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-83_5x83_5@2x.png +0 -0
  688. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@2x.png +0 -0
  689. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@3x.png +0 -0
  690. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@2x.png +0 -0
  691. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@3x.png +0 -0
  692. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@2x.png +0 -0
  693. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@3x.png +0 -0
  694. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@2x.png +0 -0
  695. package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@3x.png +0 -0
  696. package/platforms/ios/App/App/Base.lproj/LaunchScreen.storyboard +1 -4
  697. package/platforms/ios/App/App/ComputerUseBridge.swift +589 -0
  698. package/platforms/ios/App/App/DeviceActivityMonitorExtension/DeviceActivityMonitorExtension.entitlements +12 -0
  699. package/platforms/ios/App/App/DeviceActivityMonitorExtension/DeviceActivityMonitorExtension.swift +34 -0
  700. package/platforms/ios/App/App/DeviceActivityMonitorExtension/Info.plist +29 -0
  701. package/platforms/ios/App/App/DeviceActivityReportExtension/DeviceActivityReportExtension.entitlements +12 -0
  702. package/platforms/ios/App/App/DeviceActivityReportExtension/DeviceActivityReportExtension.swift +53 -0
  703. package/platforms/ios/App/App/DeviceActivityReportExtension/Info.plist +27 -0
  704. package/platforms/ios/App/App/ElizaAppIntents.swift +183 -0
  705. package/platforms/ios/App/App/ElizaIntentPlugin.swift +342 -5
  706. package/platforms/ios/App/App/Info.plist +17 -1
  707. package/platforms/ios/App/App/runners/eliza-tasks.js +177 -0
  708. package/platforms/ios/App/App.xcodeproj/project.pbxproj +262 -6
  709. package/platforms/ios/App/BroadcastExtension/SampleHandler.swift +100 -0
  710. package/platforms/ios/App/Podfile +5 -0
  711. package/platforms/ios/App/Podfile.lock +83 -59
  712. package/register-runtime-hooks.js +11 -5
  713. package/registry/app-registry.d.ts +14 -0
  714. package/registry/app-registry.d.ts.map +1 -0
  715. package/registry/app-registry.js +29 -0
  716. package/registry/entries/apps/app-polymarket.json +31 -0
  717. package/registry/entries/apps/clawville.json +27 -0
  718. package/registry/entries/apps/companion.json +28 -0
  719. package/registry/entries/apps/database-viewer.json +27 -0
  720. package/registry/entries/apps/defense-of-the-agents.json +27 -0
  721. package/registry/entries/apps/documents.json +30 -0
  722. package/registry/entries/apps/feed.json +27 -0
  723. package/registry/entries/apps/hyperliquid.json +31 -0
  724. package/registry/entries/apps/log-viewer.json +27 -0
  725. package/registry/entries/apps/memory-viewer.json +27 -0
  726. package/registry/entries/apps/model-tester.json +31 -0
  727. package/registry/entries/apps/plugin-viewer.json +27 -0
  728. package/registry/entries/apps/relationship-viewer.json +27 -0
  729. package/registry/entries/apps/runtime-debugger.json +27 -0
  730. package/registry/entries/apps/shopify.json +31 -0
  731. package/registry/entries/apps/skills-viewer.json +27 -0
  732. package/registry/entries/apps/steward.json +31 -0
  733. package/registry/entries/apps/training.json +54 -0
  734. package/registry/entries/apps/trajectory-viewer.json +27 -0
  735. package/registry/entries/apps/vincent.json +31 -0
  736. package/registry/entries/connectors/bluebubbles.json +99 -0
  737. package/registry/entries/connectors/bluesky.json +173 -0
  738. package/registry/entries/connectors/discord.json +119 -0
  739. package/registry/entries/connectors/farcaster.json +174 -0
  740. package/registry/entries/connectors/feishu.json +79 -0
  741. package/registry/entries/connectors/google-chat.json +120 -0
  742. package/registry/entries/connectors/google.json +82 -0
  743. package/registry/entries/connectors/imessage.json +96 -0
  744. package/registry/entries/connectors/instagram.json +64 -0
  745. package/registry/entries/connectors/line.json +86 -0
  746. package/registry/entries/connectors/matrix.json +94 -0
  747. package/registry/entries/connectors/mattermost.json +110 -0
  748. package/registry/entries/connectors/msteams.json +104 -0
  749. package/registry/entries/connectors/nextcloud-talk.json +104 -0
  750. package/registry/entries/connectors/nostr.json +70 -0
  751. package/registry/entries/connectors/signal.json +81 -0
  752. package/registry/entries/connectors/slack.json +102 -0
  753. package/registry/entries/connectors/telegram.json +71 -0
  754. package/registry/entries/connectors/tlon.json +94 -0
  755. package/registry/entries/connectors/twitch.json +110 -0
  756. package/registry/entries/connectors/whatsapp.json +113 -0
  757. package/registry/entries/connectors/x.json +231 -0
  758. package/registry/entries/connectors/zalo.json +112 -0
  759. package/registry/entries/connectors/zalouser.json +122 -0
  760. package/registry/entries/plugins/agent-orchestrator.json +33 -0
  761. package/registry/entries/plugins/agent-skills.json +72 -0
  762. package/registry/entries/plugins/anthropic.json +73 -0
  763. package/registry/entries/plugins/app-control.json +23 -0
  764. package/registry/entries/plugins/auto-trader.json +203 -0
  765. package/registry/entries/plugins/background-runner.json +26 -0
  766. package/registry/entries/plugins/blooio.json +102 -0
  767. package/registry/entries/plugins/browser.json +75 -0
  768. package/registry/entries/plugins/cli.json +40 -0
  769. package/registry/entries/plugins/clipboard.json +44 -0
  770. package/registry/entries/plugins/coding-tools.json +71 -0
  771. package/registry/entries/plugins/commands.json +63 -0
  772. package/registry/entries/plugins/computeruse.json +74 -0
  773. package/registry/entries/plugins/copilot-proxy.json +93 -0
  774. package/registry/entries/plugins/directives.json +63 -0
  775. package/registry/entries/plugins/edge-tts.json +97 -0
  776. package/registry/entries/plugins/elevenlabs.json +169 -0
  777. package/registry/entries/plugins/elizacloud.json +208 -0
  778. package/registry/entries/plugins/evm.json +134 -0
  779. package/registry/entries/plugins/experience.json +34 -0
  780. package/registry/entries/plugins/facewear.json +131 -0
  781. package/registry/entries/plugins/form.json +26 -0
  782. package/registry/entries/plugins/github.json +93 -0
  783. package/registry/entries/plugins/gmail-watch.json +25 -0
  784. package/registry/entries/plugins/goals.json +77 -0
  785. package/registry/entries/plugins/google-genai.json +106 -0
  786. package/registry/entries/plugins/groq.json +93 -0
  787. package/registry/entries/plugins/hedera.json +48 -0
  788. package/registry/entries/plugins/inmemorydb.json +25 -0
  789. package/registry/entries/plugins/linear.json +51 -0
  790. package/registry/entries/plugins/local-inference.json +142 -0
  791. package/registry/entries/plugins/local-storage.json +36 -0
  792. package/registry/entries/plugins/localdb.json +25 -0
  793. package/registry/entries/plugins/mcp.json +44 -0
  794. package/registry/entries/plugins/memory.json +124 -0
  795. package/registry/entries/plugins/minecraft.json +79 -0
  796. package/registry/entries/plugins/moltbook.json +83 -0
  797. package/registry/entries/plugins/music.json +155 -0
  798. package/registry/entries/plugins/mysticism.json +48 -0
  799. package/registry/entries/plugins/nearai.json +82 -0
  800. package/registry/entries/plugins/ngrok.json +69 -0
  801. package/registry/entries/plugins/ollama.json +96 -0
  802. package/registry/entries/plugins/openai.json +189 -0
  803. package/registry/entries/plugins/openrouter.json +188 -0
  804. package/registry/entries/plugins/pdf.json +26 -0
  805. package/registry/entries/plugins/plugin-manager.json +23 -0
  806. package/registry/entries/plugins/prose.json +48 -0
  807. package/registry/entries/plugins/rlm.json +26 -0
  808. package/registry/entries/plugins/roblox.json +88 -0
  809. package/registry/entries/plugins/rss.json +64 -0
  810. package/registry/entries/plugins/s3-storage.json +91 -0
  811. package/registry/entries/plugins/scheduling.json +35 -0
  812. package/registry/entries/plugins/shell.json +94 -0
  813. package/registry/entries/plugins/social-alpha.json +72 -0
  814. package/registry/entries/plugins/tailscale.json +81 -0
  815. package/registry/entries/plugins/tee.json +53 -0
  816. package/registry/entries/plugins/todos.json +26 -0
  817. package/registry/entries/plugins/trajectory-logger.json +33 -0
  818. package/registry/entries/plugins/trust.json +39 -0
  819. package/registry/entries/plugins/tts.json +71 -0
  820. package/registry/entries/plugins/tunnel.json +45 -0
  821. package/registry/entries/plugins/twilio.json +168 -0
  822. package/registry/entries/plugins/vercel-ai-gateway.json +128 -0
  823. package/registry/entries/plugins/video.json +23 -0
  824. package/registry/entries/plugins/vision.json +43 -0
  825. package/registry/entries/plugins/webhooks.json +23 -0
  826. package/registry/entries/plugins/workflow.json +25 -0
  827. package/registry/entries/plugins/xai.json +75 -0
  828. package/registry/index.d.ts +2 -1
  829. package/registry/index.d.ts.map +1 -1
  830. package/registry/index.js +46 -12
  831. package/registry/loader.d.ts +2 -1
  832. package/registry/loader.d.ts.map +1 -1
  833. package/registry/loader.js +49 -2
  834. package/registry/schema.d.ts +244 -34
  835. package/registry/schema.d.ts.map +1 -1
  836. package/registry/schema.js +36 -0
  837. package/runtime/android-avf-microdroid-bridge.d.ts +29 -0
  838. package/runtime/android-avf-microdroid-bridge.d.ts.map +1 -0
  839. package/runtime/android-avf-microdroid-bridge.js +149 -0
  840. package/runtime/api-dev-settings-banner.d.ts.map +1 -1
  841. package/runtime/api-dev-settings-banner.js +5 -13
  842. package/runtime/app-core-runtime-hooks.d.ts +21 -0
  843. package/runtime/app-core-runtime-hooks.d.ts.map +1 -0
  844. package/runtime/app-core-runtime-hooks.js +10 -0
  845. package/runtime/autonomy-policy.d.ts +2 -0
  846. package/runtime/autonomy-policy.d.ts.map +1 -0
  847. package/runtime/autonomy-policy.js +4 -0
  848. package/runtime/desktop/AppWindowRenderer.d.ts +17 -0
  849. package/runtime/desktop/AppWindowRenderer.d.ts.map +1 -0
  850. package/runtime/desktop/AppWindowRenderer.js +360 -0
  851. package/runtime/desktop/DesktopSurfaceNavigationRuntime.d.ts +2 -0
  852. package/runtime/desktop/DesktopSurfaceNavigationRuntime.d.ts.map +1 -0
  853. package/runtime/desktop/DesktopSurfaceNavigationRuntime.js +41 -0
  854. package/runtime/desktop/DesktopTrayRuntime.d.ts +2 -0
  855. package/runtime/desktop/DesktopTrayRuntime.d.ts.map +1 -0
  856. package/runtime/desktop/DesktopTrayRuntime.js +174 -0
  857. package/runtime/desktop/DetachedShellRoot.d.ts +10 -0
  858. package/runtime/desktop/DetachedShellRoot.d.ts.map +1 -0
  859. package/runtime/desktop/DetachedShellRoot.js +111 -0
  860. package/runtime/desktop/index.d.ts +6 -0
  861. package/runtime/desktop/index.d.ts.map +1 -0
  862. package/runtime/desktop/index.js +5 -0
  863. package/runtime/desktop/tray-menu.d.ts +20 -0
  864. package/runtime/desktop/tray-menu.d.ts.map +1 -0
  865. package/runtime/desktop/tray-menu.js +143 -0
  866. package/runtime/dev-server.d.ts +1 -1
  867. package/runtime/dev-server.d.ts.map +1 -1
  868. package/runtime/dev-server.js +93 -17
  869. package/runtime/eliza.d.ts +75 -1
  870. package/runtime/eliza.d.ts.map +1 -1
  871. package/runtime/eliza.js +596 -122
  872. package/runtime/ensure-text-to-speech-handler.d.ts.map +1 -1
  873. package/runtime/ensure-text-to-speech-handler.js +10 -3
  874. package/runtime/mobile-safe-runtime.d.ts +181 -2
  875. package/runtime/mobile-safe-runtime.d.ts.map +1 -1
  876. package/runtime/mobile-safe-runtime.js +1019 -12
  877. package/runtime/mode/remote-forwarder.d.ts.map +1 -1
  878. package/runtime/mode/remote-forwarder.js +2 -2
  879. package/runtime/mode/route-mode-guard.d.ts +1 -2
  880. package/runtime/mode/route-mode-guard.d.ts.map +1 -1
  881. package/runtime/mode/route-mode-guard.js +4 -5
  882. package/runtime/mode/route-mode-matrix.d.ts.map +1 -1
  883. package/runtime/mode/route-mode-matrix.js +14 -1
  884. package/runtime/mode/runtime-mode.d.ts +1 -1
  885. package/runtime/mode/runtime-mode.d.ts.map +1 -1
  886. package/runtime/mode/runtime-mode.js +15 -4
  887. package/runtime/runtime-bootstrap-policy.d.ts.map +1 -1
  888. package/runtime/runtime-bootstrap-policy.js +14 -2
  889. package/runtime/telegram-standalone-handler.d.ts.map +1 -1
  890. package/runtime/telegram-standalone-handler.js +10 -9
  891. package/runtime/tts-cache-wiring.d.ts +29 -0
  892. package/runtime/tts-cache-wiring.d.ts.map +1 -0
  893. package/runtime/tts-cache-wiring.js +114 -0
  894. package/runtime/voice-warmup.d.ts +81 -0
  895. package/runtime/voice-warmup.d.ts.map +1 -0
  896. package/runtime/voice-warmup.js +111 -0
  897. package/scripts/android-sms-gateway-template.test.mjs +1014 -0
  898. package/scripts/aosp/README.md +19 -15
  899. package/scripts/aosp/compile-libllama.mjs +1344 -248
  900. package/scripts/aosp/compile-shim.mjs +47 -18
  901. package/scripts/aosp/deploy-pixel.mjs +405 -0
  902. package/scripts/aosp/lib/load-variant-config.mjs +3 -3
  903. package/scripts/aosp/llama-cpp-patches/README.md +8 -8
  904. package/scripts/aosp/llama-cpp-patches/apply-patches.mjs +23 -6
  905. package/scripts/aosp/llama-cpp-patches/polarquant/README.md +37 -0
  906. package/scripts/aosp/llama-cpp-patches/qjl/README.md +37 -0
  907. package/scripts/aosp/seccomp-shim/sigsys-handler-arm64.c +169 -0
  908. package/scripts/aosp/seccomp-shim/sigsys-handler-riscv64.c +217 -0
  909. package/scripts/aosp/smoke-cuttlefish.mjs +34 -4
  910. package/scripts/aosp/stage-default-models.mjs +18 -18
  911. package/scripts/aosp/variant-config-schema.ts +2 -2
  912. package/scripts/assert-required-bundled-packages.test.ts +534 -0
  913. package/scripts/audit-apple-store-sandbox.mjs +146 -0
  914. package/scripts/audit-live-test-surface.mjs +5 -2
  915. package/scripts/build-capacitor-app.mjs +21 -0
  916. package/scripts/build-flatpak.mjs +5 -5
  917. package/scripts/build-helpers/arm64-simd.mjs +72 -0
  918. package/scripts/build-helpers/omnivoice-merged.mjs +87 -0
  919. package/scripts/build-helpers/verify-fused-symbols.mjs +567 -0
  920. package/scripts/build-image.sh +1 -1
  921. package/scripts/build-llama-cpp-mtp.mjs +487 -0
  922. package/scripts/build-native-plugins.mjs +230 -18
  923. package/scripts/build-patched-electrobun-cli.mjs +68 -10
  924. package/scripts/build-win.mjs +1 -1
  925. package/scripts/bun-riscv64/Dockerfile +418 -0
  926. package/scripts/bun-riscv64/README.md +316 -0
  927. package/scripts/bun-riscv64/build.sh +469 -0
  928. package/scripts/bun-riscv64/bun-patches/0001-config-add-riscv64-arch.patch +74 -0
  929. package/scripts/bun-riscv64/bun-patches/0002-flags-add-riscv64-march-mabi.patch +16 -0
  930. package/scripts/bun-riscv64/bun-patches/0003-zig-add-riscv64-target-triple-and-cpu.patch +26 -0
  931. package/scripts/bun-riscv64/bun-patches/0004-webkit-force-local-mode-on-riscv64.patch +33 -0
  932. package/scripts/bun-riscv64/bun-patches/0005-tinycc-disable-on-riscv64.patch +16 -0
  933. package/scripts/bun-riscv64/bun-patches/0006-build-add-riscv64-cli-validation.patch +15 -0
  934. package/scripts/bun-riscv64/bun-patches/0007-deps-per-dep-riscv64-checks.patch +24 -0
  935. package/scripts/bun-riscv64/bun-patches/0008-source-stabilize-riscv64-musl-build.patch +226 -0
  936. package/scripts/bun-riscv64/bun-patches/0009-disable-wasm-streaming-hooks-for-c-loop.patch +162 -0
  937. package/scripts/bun-riscv64/bun-patches/0010-disable-inspector-profiler-for-riscv64-c-loop.patch +80 -0
  938. package/scripts/bun-riscv64/bun-patches/0011-process-arch-add-riscv64.patch +23 -0
  939. package/scripts/bun-riscv64/bun-patches/0012-cpu-features-add-riscv64-fallback.patch +13 -0
  940. package/scripts/bun-riscv64/bun-patches/0013-disable-console-inspector-hooks-for-riscv64-c-loop.patch +43 -0
  941. package/scripts/bun-riscv64/bun-patches/0014-disable-custom-inspector-dispatchers-on-riscv64.patch +127 -0
  942. package/scripts/bun-riscv64/bun-patches/0015-disable-jsc-profiler-builtins-on-riscv64.patch +75 -0
  943. package/scripts/bun-riscv64/bun-patches/0016-node-vm-disable-jit-cached-data-on-riscv64-c-loop.patch +96 -0
  944. package/scripts/bun-riscv64/bun-patches/0017-disable-performance-domjit-signature-on-riscv64-c-loop.patch +34 -0
  945. package/scripts/bun-riscv64/bun-patches/0018-fix-serialized-script-identifier-big-endian-path.patch +19 -0
  946. package/scripts/bun-riscv64/bun-patches/0019-add-wtf-timer-fire-bridge-for-c-loop.patch +24 -0
  947. package/scripts/bun-riscv64/bun-patches/0020-run-riscv64-smoke-test-under-qemu.patch +13 -0
  948. package/scripts/bun-riscv64/bun-patches/0021-fix-riscv64-linux-open-flags.patch +25 -0
  949. package/scripts/bun-riscv64/bun-patches/0022-zlib-riscv64-generic-kernels.patch +25 -0
  950. package/scripts/bun-riscv64/bun-patches/README.md +127 -0
  951. package/scripts/bun-riscv64/bun-version.json +202 -0
  952. package/scripts/bun-riscv64/run-build.sh +162 -0
  953. package/scripts/bun-riscv64/rust-core/0001-riscv64-rust-core-port.patch +868 -0
  954. package/scripts/bun-riscv64/rust-core/0002-second-wave-riscv64-source-gaps.patch +130 -0
  955. package/scripts/bun-riscv64/rust-core/0003-third-wave-riscv64-crash-handler-gaps.patch +78 -0
  956. package/scripts/bun-riscv64/rust-core/0004-rust-target-cpu-riscv64.patch +39 -0
  957. package/scripts/bun-riscv64/rust-core/0005-fifth-wave-riscv64-source-gaps.patch +96 -0
  958. package/scripts/bun-riscv64/rust-core/0006-cpp-wasm-and-inspector-guards-riscv64.patch +91 -0
  959. package/scripts/bun-riscv64/rust-core/0007-bun-alloc-max-align-t-riscv64.patch +36 -0
  960. package/scripts/bun-riscv64/rust-core/0008-workspace-lints-warn-not-deny-riscv64.patch +75 -0
  961. package/scripts/bun-riscv64/rust-core/0009-zigglobalobject-wasm-streaming-guards-riscv64.patch +109 -0
  962. package/scripts/bun-riscv64/rust-core/0010-tcc-externs-stub-on-riscv64.patch +62 -0
  963. package/scripts/bun-riscv64/rust-core/0011-clippy-ptr-cast-lints-warn-riscv64.patch +61 -0
  964. package/scripts/bun-riscv64/rust-core/README.md +80 -0
  965. package/scripts/bun-riscv64/rust-core/webkit-patches/0003-disable-dfg-ftl-on-riscv64.patch +60 -0
  966. package/scripts/bun-riscv64/rust-core/webkit-patches/0004-riscv64-do-not-force-wasm-in-c-loop.patch +31 -0
  967. package/scripts/bun-riscv64/rust-core/webkit-patches/0005-domjit-effect-allow-no-dfg-c-loop.patch +40 -0
  968. package/scripts/bun-riscv64/rust-core/webkit-patches/0006-disable-usewasm-when-webassembly-compiled-out.patch +33 -0
  969. package/scripts/bun-riscv64/rust-core/webkit-patches/0007-restore-dropped-includes-and-llint-fwd-decl.patch +31 -0
  970. package/scripts/bun-riscv64/validate.sh +264 -0
  971. package/scripts/bun-riscv64/webkit-patches/0001-cherry-pick-llint-riscv64.recipe +155 -0
  972. package/scripts/bun-riscv64/webkit-patches/0002-cherry-pick-baseline-jit-riscv64.recipe +40 -0
  973. package/scripts/bun-riscv64/webkit-patches/0003-disable-dfg-ftl-on-riscv64.patch +60 -0
  974. package/scripts/bun-riscv64/webkit-patches/0004-riscv64-do-not-force-wasm-in-c-loop.patch +31 -0
  975. package/scripts/bun-riscv64/webkit-patches/0005-domjit-effect-allow-no-dfg-c-loop.patch +40 -0
  976. package/scripts/bun-riscv64/webkit-patches/0006-disable-usewasm-when-webassembly-compiled-out.patch +33 -0
  977. package/scripts/bun-riscv64/webkit-patches/0007-restore-dropped-includes-and-llint-fwd-decl.patch +72 -0
  978. package/scripts/bun-riscv64/webkit-patches/README.md +146 -0
  979. package/scripts/check-homepage-public-readiness.mjs +353 -0
  980. package/scripts/check-homepage-release-data.mjs +110 -0
  981. package/scripts/check-i18n.mjs +2 -1
  982. package/scripts/check-real-local-chat.ts +147 -0
  983. package/scripts/check-real-local-provisioning.ts +104 -0
  984. package/scripts/check-real-local-reset.ts +249 -0
  985. package/scripts/check-sms-gateway-completion-audit.mjs +428 -0
  986. package/scripts/check-sms-gateway-readiness.mjs +266 -0
  987. package/scripts/clean-repo.mjs +5 -5
  988. package/scripts/codesign-mas.mjs +222 -16
  989. package/scripts/collect-docker-runtime-deps.mjs +229 -0
  990. package/scripts/continue-sms-gateway-work.mjs +121 -0
  991. package/scripts/copy-runtime-node-modules.ts +903 -195
  992. package/scripts/deploy-cloud-api-production-gateway.mjs +52 -0
  993. package/scripts/desktop-build.mjs +655 -101
  994. package/scripts/dev-platform.mjs +346 -102
  995. package/scripts/dev-startup-smoke.mjs +248 -0
  996. package/scripts/dev-ui.mjs +418 -176
  997. package/scripts/disable-local-eliza-workspace.mjs +35 -0
  998. package/scripts/docker-ci-smoke.sh +298 -96
  999. package/scripts/docker-entrypoint.sh +62 -1
  1000. package/scripts/docker-entrypoint.test.ts +283 -0
  1001. package/scripts/ensure-avatars.mjs +2 -2
  1002. package/scripts/ensure-electrobun-core.mjs +1 -1
  1003. package/scripts/ensure-generated-core-proto-js.mjs +1 -1
  1004. package/scripts/ensure-type-package-aliases.mjs +62 -5
  1005. package/scripts/ensure-vision-deps.mjs +20 -1
  1006. package/scripts/entry.ts +1 -1
  1007. package/scripts/ffi-stub/Makefile +64 -0
  1008. package/scripts/ffi-stub/README.md +391 -0
  1009. package/scripts/ffi-stub/asr-ffi-smoke.ts +139 -0
  1010. package/scripts/ffi-stub/ffi-stub.c +539 -0
  1011. package/scripts/ffi-stub/ffi.h +538 -0
  1012. package/scripts/ffi-stub/libelizainference_stub.so +0 -0
  1013. package/scripts/ffi-stub/tts-stream-ffi-smoke.ts +349 -0
  1014. package/scripts/generate-first-run-voicelines.mjs +194 -0
  1015. package/scripts/generate-plugin-index.js +4 -3
  1016. package/scripts/generate-static-asset-manifest.mjs +1 -1
  1017. package/scripts/i18n-dynamic-keys.json +5 -5
  1018. package/scripts/init-submodules.mjs +2 -2
  1019. package/scripts/install-android-sms-gateway.md +177 -0
  1020. package/scripts/install-android-sms-gateway.mjs +1088 -0
  1021. package/scripts/ios-xcframework/README.md +74 -72
  1022. package/scripts/ios-xcframework/build-xcframework.mjs +204 -43
  1023. package/scripts/ios-xcframework/run-physical-device-smoke.mjs +1943 -0
  1024. package/scripts/ios-xcframework/runtime-symbol-shim.c +450 -0
  1025. package/scripts/kernel-patches/cpu-polar-kernels.mjs +441 -0
  1026. package/scripts/kernel-patches/cpu-simd-kernels.mjs +253 -0
  1027. package/scripts/kernel-patches/cpu-thread-parallelism.mjs +368 -0
  1028. package/scripts/kernel-patches/cuda-kernels.mjs +117 -0
  1029. package/scripts/kernel-patches/metal-kernels.mjs +1698 -109
  1030. package/scripts/kernel-patches/server-omnivoice-route.mjs +718 -0
  1031. package/scripts/kernel-patches/server-structured-output.mjs +279 -0
  1032. package/scripts/kernel-patches/vulkan-dispatch-log.mjs +166 -0
  1033. package/scripts/kernel-patches/vulkan-dispatch-log.test.mjs +50 -0
  1034. package/scripts/kernel-patches/vulkan-dispatch-patches/01-vulkan-shaders-gen.patch +30 -16
  1035. package/scripts/kernel-patches/vulkan-dispatch-patches/02-ggml-vulkan-pipelines.patch +75 -30
  1036. package/scripts/kernel-patches/vulkan-kernels.mjs +800 -49
  1037. package/scripts/lib/agent-source-watcher.mjs +174 -0
  1038. package/scripts/lib/agent-source-watcher.test.mjs +184 -0
  1039. package/scripts/lib/api-supervisor.mjs +78 -9
  1040. package/scripts/lib/api-supervisor.test.mjs +121 -0
  1041. package/scripts/lib/app-dir.mjs +2 -16
  1042. package/scripts/lib/apple-entitlement-audit.mjs +655 -0
  1043. package/scripts/lib/apple-entitlement-audit.test.mjs +144 -0
  1044. package/scripts/lib/bun-version-guard.mjs +13 -13
  1045. package/scripts/lib/capacitor-plugin-build-needed.mjs +4 -3
  1046. package/scripts/lib/capacitor-plugin-names.mjs +30 -14
  1047. package/scripts/lib/desktop-preflight.mjs +9 -5
  1048. package/scripts/lib/desktop-startup-embedding-warmup-policy.mjs +51 -0
  1049. package/scripts/lib/desktop-startup-embedding-warmup-policy.test.mjs +55 -0
  1050. package/scripts/lib/duet-bridge.d.mts +63 -0
  1051. package/scripts/lib/duet-bridge.mjs +193 -0
  1052. package/scripts/lib/node-path-env.mjs +4 -2
  1053. package/scripts/lib/orchestrator-desktop-dev-banner.mjs +12 -3
  1054. package/scripts/lib/patch-bun-exports.mjs +90 -27
  1055. package/scripts/lib/patch-bun-exports.test.mjs +79 -0
  1056. package/scripts/lib/renderer-build-action.mjs +35 -0
  1057. package/scripts/lib/renderer-build-action.test.mjs +70 -0
  1058. package/scripts/lib/stage-android-agent.mjs +748 -99
  1059. package/scripts/lib/sync-eliza-env-aliases.mjs +3 -25
  1060. package/scripts/lib/ui-smoke-stub-decision.mjs +33 -0
  1061. package/scripts/lib/ui-smoke-stub-decision.test.mjs +46 -0
  1062. package/scripts/lib/vite-renderer-dist-stale.mjs +5 -0
  1063. package/scripts/lib/voice-latency-report.mjs +154 -0
  1064. package/scripts/lifeops-prompt-benchmark.ts +21 -12
  1065. package/scripts/link-docker-local-app-packages.mjs +89 -36
  1066. package/scripts/local-stt-bench.ts +192 -0
  1067. package/scripts/maintain-cloud-api-production-gateway.mjs +54 -0
  1068. package/scripts/mas-smoke.mjs +459 -0
  1069. package/scripts/mas-smoke.test.mjs +220 -0
  1070. package/scripts/mobile-auth-simulator-smoke.mjs +0 -1
  1071. package/scripts/normalize-eliza-capture.ts +97 -0
  1072. package/scripts/omnivoice-fuse/prepare.mjs +2543 -23
  1073. package/scripts/pack-upstreams.mjs +65 -5
  1074. package/scripts/package-electrobun-linux.mjs +303 -0
  1075. package/scripts/patch-deps.mjs +5 -3
  1076. package/scripts/patches/llama-mobile-kokoro-tts.patch +480 -0
  1077. package/scripts/playwright-ui-live-stack.ts +194 -49
  1078. package/scripts/playwright-ui-smoke-api-stub.mjs +3501 -109
  1079. package/scripts/pre-review-local.mjs +2 -2
  1080. package/scripts/prepare-ios-cocoapods.sh +41 -3
  1081. package/scripts/release-check.ts +180 -84
  1082. package/scripts/release-workflow-drift.test.ts +57 -0
  1083. package/scripts/relink-workspace-packages-to-dist.mjs +21 -4
  1084. package/scripts/rt.mjs +16 -1
  1085. package/scripts/run-biome-check.mjs +1 -1
  1086. package/scripts/run-coding-agent-e2e.mjs +3 -3
  1087. package/scripts/run-eliza-app-core-script.mjs +34 -0
  1088. package/scripts/run-local-plugin-live-smoke.mjs +71 -2
  1089. package/scripts/run-mobile-build-android-app-actions.test.mjs +426 -0
  1090. package/scripts/run-mobile-build.mjs +4757 -607
  1091. package/scripts/run-node-runtime.mjs +184 -7
  1092. package/scripts/run-node-runtime.test.mjs +167 -0
  1093. package/scripts/run-node-tsx.mjs +80 -33
  1094. package/scripts/run-node.mjs +41 -1
  1095. package/scripts/run-production-build.mjs +34 -27
  1096. package/scripts/run-release-check.mjs +19 -0
  1097. package/scripts/run-release-contract-suite.mjs +107 -14
  1098. package/scripts/run-ui-smoke-playwright-suite.mjs +0 -2
  1099. package/scripts/runtime-package-manifest.ts +21 -3
  1100. package/scripts/setup-upstreams.mjs +42 -1
  1101. package/scripts/sms-gateway-status.mjs +194 -0
  1102. package/scripts/stage-android-agent.test.mjs +97 -0
  1103. package/scripts/stage-elizavoice-lib.mjs +203 -0
  1104. package/scripts/startup-integration-script-drift.test.ts +82 -4
  1105. package/scripts/streaming-pipeline-bench.ts +543 -0
  1106. package/scripts/sync-homepage-porkbun-dns.mjs +262 -0
  1107. package/scripts/test-sms-gateway-software.mjs +100 -0
  1108. package/scripts/type-audit.mjs +1 -1
  1109. package/scripts/validate-bluebubbles-outbound.mjs +293 -0
  1110. package/scripts/validate-cdn-assets.mjs +15 -7
  1111. package/scripts/validate-regression-matrix.mjs +109 -8
  1112. package/scripts/verify-android-sms-gateway-e2e.mjs +362 -0
  1113. package/scripts/verify-bluebubbles-gateway-e2e.mjs +191 -0
  1114. package/scripts/verify-bluebubbles-inbound-readiness.mjs +88 -0
  1115. package/scripts/verify-cloud-api-production-deploy.mjs +87 -0
  1116. package/scripts/verify-cloud-sms-onboarding-flow.mjs +336 -0
  1117. package/scripts/voice/freeze-voice.mjs +521 -0
  1118. package/scripts/voice-attribution-smoke.ts +538 -0
  1119. package/scripts/voice-create-profile.mjs +379 -0
  1120. package/scripts/voice-duet.mjs +1355 -0
  1121. package/scripts/voice-e2e-hardware.ts +871 -0
  1122. package/scripts/voice-interactive.mjs +1750 -0
  1123. package/scripts/voice-latency-report.mjs +96 -0
  1124. package/scripts/voice-latency-report.test.ts +176 -0
  1125. package/scripts/voice-preset/build-default-voice-preset.mjs +249 -0
  1126. package/scripts/voice-preset/build-onboarding-voice.mjs +281 -0
  1127. package/scripts/watch-sms-gateway-readiness.mjs +303 -0
  1128. package/scripts/write-homepage-release-data.mjs +458 -26
  1129. package/security/agent-vault-id.d.ts +1 -1
  1130. package/security/agent-vault-id.js +1 -1
  1131. package/security/hydrate-wallet-keys-from-platform-store.d.ts.map +1 -1
  1132. package/security/hydrate-wallet-keys-from-platform-store.js +23 -14
  1133. package/security/platform-secure-store-node.d.ts +2 -2
  1134. package/security/platform-secure-store-node.js +3 -3
  1135. package/security/wallet-os-store-actions.d.ts +0 -9
  1136. package/security/wallet-os-store-actions.d.ts.map +1 -1
  1137. package/security/wallet-os-store-actions.js +3 -10
  1138. package/services/account-pool.d.ts +23 -14
  1139. package/services/account-pool.d.ts.map +1 -1
  1140. package/services/account-pool.js +86 -24
  1141. package/services/account-usage.d.ts.map +1 -1
  1142. package/services/account-usage.js +2 -5
  1143. package/services/ambient-audio/consent.d.ts +9 -0
  1144. package/services/ambient-audio/consent.d.ts.map +1 -0
  1145. package/services/ambient-audio/consent.js +28 -0
  1146. package/services/ambient-audio/index.d.ts +7 -0
  1147. package/services/ambient-audio/index.d.ts.map +1 -0
  1148. package/services/ambient-audio/index.js +4 -0
  1149. package/services/ambient-audio/replay-buffer.d.ts +14 -0
  1150. package/services/ambient-audio/replay-buffer.d.ts.map +1 -0
  1151. package/services/ambient-audio/replay-buffer.js +66 -0
  1152. package/services/ambient-audio/response-gate.d.ts +3 -0
  1153. package/services/ambient-audio/response-gate.d.ts.map +1 -0
  1154. package/services/ambient-audio/response-gate.js +33 -0
  1155. package/services/ambient-audio/service.d.ts +22 -0
  1156. package/services/ambient-audio/service.d.ts.map +1 -0
  1157. package/services/ambient-audio/service.js +47 -0
  1158. package/services/ambient-audio/types.d.ts +42 -0
  1159. package/services/ambient-audio/types.d.ts.map +1 -0
  1160. package/services/app-updates/update-policy.d.ts +64 -0
  1161. package/services/app-updates/update-policy.d.ts.map +1 -0
  1162. package/services/app-updates/update-policy.js +228 -0
  1163. package/services/auth-store.d.ts +37 -1
  1164. package/services/auth-store.d.ts.map +1 -1
  1165. package/services/auth-store.js +59 -26
  1166. package/services/cloud-jwks-store.d.ts +3 -3
  1167. package/services/cloud-jwks-store.d.ts.map +1 -1
  1168. package/services/cloud-jwks-store.js +5 -8
  1169. package/services/coding-account-bridge.d.ts +71 -0
  1170. package/services/coding-account-bridge.d.ts.map +1 -0
  1171. package/services/coding-account-bridge.js +267 -0
  1172. package/services/connector-target-catalog.d.ts +10 -3
  1173. package/services/connector-target-catalog.d.ts.map +1 -1
  1174. package/services/connector-target-catalog.js +7 -4
  1175. package/services/credential-tunnel-service.d.ts +66 -0
  1176. package/services/credential-tunnel-service.d.ts.map +1 -0
  1177. package/services/credential-tunnel-service.js +227 -0
  1178. package/services/github-credentials.d.ts +1 -1
  1179. package/services/github-credentials.js +1 -1
  1180. package/services/inference-abort.d.ts +47 -0
  1181. package/services/inference-abort.d.ts.map +1 -0
  1182. package/services/inference-abort.js +76 -0
  1183. package/services/persistence.d.ts +2 -3
  1184. package/services/persistence.d.ts.map +1 -1
  1185. package/services/persistence.js +2 -3
  1186. package/services/phrase-chunked-tts.d.ts +136 -0
  1187. package/services/phrase-chunked-tts.d.ts.map +1 -0
  1188. package/services/phrase-chunked-tts.js +208 -0
  1189. package/services/sandbox-registry.d.ts +78 -0
  1190. package/services/sandbox-registry.d.ts.map +1 -0
  1191. package/services/sandbox-registry.js +323 -0
  1192. package/services/secrets-manager-installer.d.ts +8 -1
  1193. package/services/secrets-manager-installer.d.ts.map +1 -1
  1194. package/services/secrets-manager-installer.js +27 -2
  1195. package/services/sensitive-requests/cloud-link-adapter.d.ts +15 -0
  1196. package/services/sensitive-requests/cloud-link-adapter.d.ts.map +1 -0
  1197. package/services/sensitive-requests/cloud-link-adapter.js +73 -0
  1198. package/services/sensitive-requests/index.d.ts +27 -0
  1199. package/services/sensitive-requests/index.d.ts.map +1 -0
  1200. package/services/sensitive-requests/index.js +51 -0
  1201. package/services/sensitive-requests/instruct-dm-only-adapter.d.ts +14 -0
  1202. package/services/sensitive-requests/instruct-dm-only-adapter.d.ts.map +1 -0
  1203. package/services/sensitive-requests/instruct-dm-only-adapter.js +22 -0
  1204. package/services/sensitive-requests/owner-app-inline-adapter.d.ts +3 -0
  1205. package/services/sensitive-requests/owner-app-inline-adapter.d.ts.map +1 -0
  1206. package/services/sensitive-requests/owner-app-inline-adapter.js +146 -0
  1207. package/services/sensitive-requests/owner-app-oauth-adapter.d.ts +3 -0
  1208. package/services/sensitive-requests/owner-app-oauth-adapter.d.ts.map +1 -0
  1209. package/services/sensitive-requests/owner-app-oauth-adapter.js +156 -0
  1210. package/services/sensitive-requests/public-link-adapter.d.ts +14 -0
  1211. package/services/sensitive-requests/public-link-adapter.d.ts.map +1 -0
  1212. package/services/sensitive-requests/public-link-adapter.js +86 -0
  1213. package/services/sensitive-requests/tunnel-link-adapter.d.ts +17 -0
  1214. package/services/sensitive-requests/tunnel-link-adapter.d.ts.map +1 -0
  1215. package/services/sensitive-requests/tunnel-link-adapter.js +38 -0
  1216. package/services/steward-credentials.d.ts +1 -1
  1217. package/services/steward-credentials.d.ts.map +1 -1
  1218. package/services/steward-credentials.js +10 -6
  1219. package/services/steward-sidecar/health-check.d.ts.map +1 -1
  1220. package/services/steward-sidecar/health-check.js +4 -3
  1221. package/services/steward-sidecar/process-management.d.ts +1 -1
  1222. package/services/steward-sidecar/process-management.d.ts.map +1 -1
  1223. package/services/steward-sidecar/process-management.js +9 -3
  1224. package/services/steward-sidecar/types.d.ts +1 -1
  1225. package/services/steward-sidecar/types.d.ts.map +1 -1
  1226. package/services/steward-sidecar/wallet-setup.d.ts.map +1 -1
  1227. package/services/steward-sidecar/wallet-setup.js +8 -7
  1228. package/services/steward-sidecar.d.ts +2 -2
  1229. package/services/steward-sidecar.d.ts.map +1 -1
  1230. package/services/steward-sidecar.js +27 -19
  1231. package/services/task-host-capabilities.d.ts +60 -0
  1232. package/services/task-host-capabilities.d.ts.map +1 -0
  1233. package/services/task-host-capabilities.js +122 -0
  1234. package/services/tool-call-cache/index.d.ts +2 -2
  1235. package/services/tool-call-cache/index.d.ts.map +1 -1
  1236. package/services/tool-call-cache/index.js +1 -1
  1237. package/services/trigger-event-bridge.js +1 -1
  1238. package/services/tunnel-to-mobile/index.d.ts +2 -0
  1239. package/services/tunnel-to-mobile/index.d.ts.map +1 -0
  1240. package/services/tunnel-to-mobile/index.js +1 -0
  1241. package/services/tunnel-to-mobile/tunnel-to-mobile-client.d.ts +105 -0
  1242. package/services/tunnel-to-mobile/tunnel-to-mobile-client.d.ts.map +1 -0
  1243. package/services/tunnel-to-mobile/tunnel-to-mobile-client.js +190 -0
  1244. package/services/vault-bootstrap.d.ts.map +1 -1
  1245. package/services/vault-bootstrap.js +48 -21
  1246. package/services/vault-mirror.d.ts +1 -1
  1247. package/services/vault-mirror.d.ts.map +1 -1
  1248. package/services/vault-mirror.js +29 -6
  1249. package/services/voice-profiles/diarization-pipeline.d.ts +6 -0
  1250. package/services/voice-profiles/diarization-pipeline.d.ts.map +1 -0
  1251. package/services/voice-profiles/diarization-pipeline.js +20 -0
  1252. package/services/voice-profiles/index.d.ts +12 -0
  1253. package/services/voice-profiles/index.d.ts.map +1 -0
  1254. package/services/voice-profiles/index.js +5 -0
  1255. package/services/voice-profiles/nickname-evaluator.d.ts +14 -0
  1256. package/services/voice-profiles/nickname-evaluator.d.ts.map +1 -0
  1257. package/services/voice-profiles/nickname-evaluator.js +46 -0
  1258. package/services/voice-profiles/owner-confidence.d.ts +10 -0
  1259. package/services/voice-profiles/owner-confidence.d.ts.map +1 -0
  1260. package/services/voice-profiles/owner-confidence.js +38 -0
  1261. package/services/voice-profiles/private-challenge.d.ts +20 -0
  1262. package/services/voice-profiles/private-challenge.d.ts.map +1 -0
  1263. package/services/voice-profiles/private-challenge.js +44 -0
  1264. package/services/voice-profiles/store.d.ts +21 -0
  1265. package/services/voice-profiles/store.d.ts.map +1 -0
  1266. package/services/voice-profiles/store.js +50 -0
  1267. package/services/voice-profiles/types.d.ts +38 -0
  1268. package/services/voice-profiles/types.d.ts.map +1 -0
  1269. package/services/voice-profiles/types.js +1 -0
  1270. package/styles/electrobun-mac-window-drag.css +4 -4
  1271. package/test/helpers/__tests__/live-agent-test.smoke.test.ts +43 -70
  1272. package/test/helpers/browser-mocks.ts +2 -2
  1273. package/test/helpers/conditional-tests.ts +2 -2
  1274. package/test/helpers/i18n.ts +1 -1
  1275. package/test/helpers/live-agent-test.ts +537 -551
  1276. package/test/helpers/live-provider.test.ts +4 -4
  1277. package/test/helpers/live-provider.ts +41 -7
  1278. package/test/helpers/live-runtime-server.ts +4 -4
  1279. package/test/helpers/pglite-runtime.ts +1 -1
  1280. package/test/helpers/real-runtime.ts +54 -15
  1281. package/test/helpers/trajectory-harness.ts +11 -7
  1282. package/test/scripts/start-eliza-live.ts +9 -0
  1283. package/test/scripts/test-parallel.mjs +1 -1
  1284. package/test/scripts/test-root-unit.mjs +6 -7
  1285. package/ui-compat.d.ts +13 -2
  1286. package/ui-compat.d.ts.map +1 -1
  1287. package/ui-compat.js +19 -3
  1288. package/api/auth-pairing-compat-routes.d.ts +0 -17
  1289. package/api/auth-pairing-compat-routes.d.ts.map +0 -1
  1290. package/api/auth-pairing-compat-routes.js +0 -301
  1291. package/api/local-inference-compat-routes.d.ts +0 -16
  1292. package/api/local-inference-compat-routes.d.ts.map +0 -1
  1293. package/api/local-inference-compat-routes.js +0 -617
  1294. package/api/onboarding-compat-routes.d.ts +0 -4
  1295. package/api/onboarding-compat-routes.d.ts.map +0 -1
  1296. package/api/onboarding-compat-routes.js +0 -207
  1297. package/api/plugins-compat-routes.d.ts +0 -103
  1298. package/api/plugins-compat-routes.d.ts.map +0 -1
  1299. package/api/plugins-compat-routes.js +0 -1181
  1300. package/api/server-onboarding-compat.d.ts +0 -31
  1301. package/api/server-onboarding-compat.d.ts.map +0 -1
  1302. package/api/server-onboarding-compat.js +0 -283
  1303. package/benchmark/cua-routes.d.ts +0 -10
  1304. package/benchmark/cua-routes.d.ts.map +0 -1
  1305. package/benchmark/cua-routes.js +0 -179
  1306. package/benchmark/mock-plugin-base.d.ts +0 -9
  1307. package/benchmark/mock-plugin-base.d.ts.map +0 -1
  1308. package/benchmark/mock-plugin-base.js +0 -325
  1309. package/cli/parse-duration.d.ts +0 -5
  1310. package/cli/parse-duration.d.ts.map +0 -1
  1311. package/cli/parse-duration.js +0 -27
  1312. package/patches/llama-cpp-capacitor@0.1.5.patch +0 -2387
  1313. package/platform/agent-browser-stub.d.ts +0 -27
  1314. package/platform/agent-browser-stub.d.ts.map +0 -1
  1315. package/platform/agent-browser-stub.js +0 -16
  1316. package/platforms/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java +0 -26
  1317. package/platforms/android/app/src/main/res/drawable/ic_launcher_background.xml +0 -170
  1318. package/platforms/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +0 -34
  1319. package/platforms/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java +0 -18
  1320. package/platforms/electrobun/assets/appIcon.iconset/icon_512x512@2x.png +0 -0
  1321. package/platforms/electrobun/assets/appIcon.png +0 -0
  1322. package/platforms/electrobun/scripts/build-whisper-universal.sh +0 -137
  1323. package/platforms/electrobun/scripts/build-whisper.sh +0 -95
  1324. package/platforms/electrobun/src/libMacWindowEffects.dylib +0 -0
  1325. package/platforms/electrobun/src/native/whisper.ts +0 -280
  1326. package/platforms/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png +0 -0
  1327. package/platforms/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png +0 -0
  1328. package/platforms/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png +0 -0
  1329. package/registry/generate-apps.d.ts +0 -2
  1330. package/registry/generate-apps.d.ts.map +0 -1
  1331. package/registry/generate-apps.js +0 -338
  1332. package/registry/generate.d.ts +0 -2
  1333. package/registry/generate.d.ts.map +0 -1
  1334. package/registry/generate.js +0 -506
  1335. package/runtime/embedding-manager-support.d.ts +0 -77
  1336. package/runtime/embedding-manager-support.d.ts.map +0 -1
  1337. package/runtime/embedding-manager-support.js +0 -309
  1338. package/runtime/embedding-presets.d.ts +0 -5
  1339. package/runtime/embedding-presets.d.ts.map +0 -1
  1340. package/runtime/embedding-presets.js +0 -47
  1341. package/runtime/embedding-warmup-policy.d.ts +0 -13
  1342. package/runtime/embedding-warmup-policy.d.ts.map +0 -1
  1343. package/runtime/embedding-warmup-policy.js +0 -33
  1344. package/runtime/ensure-local-inference-handler.d.ts +0 -25
  1345. package/runtime/ensure-local-inference-handler.d.ts.map +0 -1
  1346. package/runtime/ensure-local-inference-handler.js +0 -389
  1347. package/runtime/mobile-local-inference-gate.d.ts +0 -21
  1348. package/runtime/mobile-local-inference-gate.d.ts.map +0 -1
  1349. package/runtime/mobile-local-inference-gate.js +0 -24
  1350. package/scripts/aosp/avd-test.mjs +0 -403
  1351. package/scripts/aosp/boot-validate.mjs +0 -536
  1352. package/scripts/aosp/build-aosp.mjs +0 -448
  1353. package/scripts/aosp/build-bootanimation.mjs +0 -178
  1354. package/scripts/aosp/capture-screens.mjs +0 -325
  1355. package/scripts/aosp/e2e-validate.mjs +0 -225
  1356. package/scripts/aosp/lint-init-rc.mjs +0 -258
  1357. package/scripts/aosp/llama-shim/eliza_llama_shim.c +0 -276
  1358. package/scripts/aosp/sim.mjs +0 -277
  1359. package/scripts/aosp/sync-to-aosp.mjs +0 -134
  1360. package/scripts/aosp/validate.mjs +0 -1273
  1361. package/scripts/build-llama-cpp-dflash.mjs +0 -1866
  1362. package/scripts/generate-onboarding-voicelines.mjs +0 -194
  1363. package/scripts/generated/static-asset-manifest.json +0 -4
  1364. package/scripts/normalize-parallax-capture.ts +0 -97
  1365. package/scripts/omnivoice-fuse/Makefile +0 -44
  1366. package/scripts/omnivoice-fuse/README.md +0 -266
  1367. package/scripts/omnivoice-fuse/cmake-graft.mjs +0 -180
  1368. package/scripts/omnivoice-fuse/ffi-stub.c +0 -222
  1369. package/scripts/omnivoice-fuse/ffi.h +0 -158
  1370. package/scripts/omnivoice-fuse/libelizainference_stub.dylib +0 -0
  1371. package/scripts/omnivoice-fuse/verify-symbols.mjs +0 -138
  1372. package/security/cloud-secret-store.d.ts +0 -34
  1373. package/security/cloud-secret-store.d.ts.map +0 -1
  1374. package/security/cloud-secret-store.js +0 -65
  1375. package/security/export-guard.d.ts +0 -34
  1376. package/security/export-guard.d.ts.map +0 -1
  1377. package/security/export-guard.js +0 -127
  1378. package/services/local-inference/__stress__/cache-stress-helpers.d.ts +0 -76
  1379. package/services/local-inference/__stress__/cache-stress-helpers.d.ts.map +0 -1
  1380. package/services/local-inference/__stress__/cache-stress-helpers.js +0 -238
  1381. package/services/local-inference/active-model.d.ts +0 -180
  1382. package/services/local-inference/active-model.d.ts.map +0 -1
  1383. package/services/local-inference/active-model.js +0 -362
  1384. package/services/local-inference/assignments.d.ts +0 -58
  1385. package/services/local-inference/assignments.d.ts.map +0 -1
  1386. package/services/local-inference/assignments.js +0 -179
  1387. package/services/local-inference/backend.d.ts +0 -200
  1388. package/services/local-inference/backend.d.ts.map +0 -1
  1389. package/services/local-inference/backend.js +0 -242
  1390. package/services/local-inference/bundled-models.d.ts +0 -34
  1391. package/services/local-inference/bundled-models.d.ts.map +0 -1
  1392. package/services/local-inference/bundled-models.js +0 -104
  1393. package/services/local-inference/cache-bridge.d.ts +0 -184
  1394. package/services/local-inference/cache-bridge.d.ts.map +0 -1
  1395. package/services/local-inference/cache-bridge.js +0 -333
  1396. package/services/local-inference/catalog.d.ts +0 -57
  1397. package/services/local-inference/catalog.d.ts.map +0 -1
  1398. package/services/local-inference/catalog.js +0 -262
  1399. package/services/local-inference/conversation-registry.d.ts +0 -122
  1400. package/services/local-inference/conversation-registry.d.ts.map +0 -1
  1401. package/services/local-inference/conversation-registry.js +0 -182
  1402. package/services/local-inference/device-bridge.d.ts +0 -139
  1403. package/services/local-inference/device-bridge.d.ts.map +0 -1
  1404. package/services/local-inference/device-bridge.js +0 -774
  1405. package/services/local-inference/dflash-doctor.d.ts +0 -27
  1406. package/services/local-inference/dflash-doctor.d.ts.map +0 -1
  1407. package/services/local-inference/dflash-doctor.js +0 -149
  1408. package/services/local-inference/dflash-server.d.ts +0 -248
  1409. package/services/local-inference/dflash-server.d.ts.map +0 -1
  1410. package/services/local-inference/dflash-server.js +0 -1076
  1411. package/services/local-inference/downloader.d.ts +0 -48
  1412. package/services/local-inference/downloader.d.ts.map +0 -1
  1413. package/services/local-inference/downloader.js +0 -688
  1414. package/services/local-inference/engine.d.ts +0 -282
  1415. package/services/local-inference/engine.d.ts.map +0 -1
  1416. package/services/local-inference/engine.js +0 -743
  1417. package/services/local-inference/external-scanner.d.ts +0 -17
  1418. package/services/local-inference/external-scanner.d.ts.map +0 -1
  1419. package/services/local-inference/external-scanner.js +0 -261
  1420. package/services/local-inference/handler-registry.d.ts +0 -72
  1421. package/services/local-inference/handler-registry.d.ts.map +0 -1
  1422. package/services/local-inference/handler-registry.js +0 -159
  1423. package/services/local-inference/hardware.d.ts +0 -26
  1424. package/services/local-inference/hardware.d.ts.map +0 -1
  1425. package/services/local-inference/hardware.js +0 -139
  1426. package/services/local-inference/hf-search.d.ts +0 -19
  1427. package/services/local-inference/hf-search.d.ts.map +0 -1
  1428. package/services/local-inference/hf-search.js +0 -169
  1429. package/services/local-inference/index.d.ts +0 -10
  1430. package/services/local-inference/index.d.ts.map +0 -1
  1431. package/services/local-inference/index.js +0 -7
  1432. package/services/local-inference/llama-server-metrics.d.ts +0 -108
  1433. package/services/local-inference/llama-server-metrics.d.ts.map +0 -1
  1434. package/services/local-inference/llama-server-metrics.js +0 -175
  1435. package/services/local-inference/manifest/index.d.ts +0 -4
  1436. package/services/local-inference/manifest/index.d.ts.map +0 -1
  1437. package/services/local-inference/manifest/index.js +0 -5
  1438. package/services/local-inference/manifest/schema.d.ts +0 -419
  1439. package/services/local-inference/manifest/schema.d.ts.map +0 -1
  1440. package/services/local-inference/manifest/schema.js +0 -227
  1441. package/services/local-inference/manifest/types.d.ts +0 -23
  1442. package/services/local-inference/manifest/types.d.ts.map +0 -1
  1443. package/services/local-inference/manifest/types.js +0 -5
  1444. package/services/local-inference/manifest/validator.d.ts +0 -43
  1445. package/services/local-inference/manifest/validator.d.ts.map +0 -1
  1446. package/services/local-inference/manifest/validator.js +0 -180
  1447. package/services/local-inference/paths.d.ts +0 -8
  1448. package/services/local-inference/paths.d.ts.map +0 -1
  1449. package/services/local-inference/paths.js +0 -7
  1450. package/services/local-inference/providers.d.ts +0 -61
  1451. package/services/local-inference/providers.d.ts.map +0 -1
  1452. package/services/local-inference/providers.js +0 -334
  1453. package/services/local-inference/ram-budget.d.ts +0 -57
  1454. package/services/local-inference/ram-budget.d.ts.map +0 -1
  1455. package/services/local-inference/ram-budget.js +0 -107
  1456. package/services/local-inference/readiness.d.ts +0 -9
  1457. package/services/local-inference/readiness.d.ts.map +0 -1
  1458. package/services/local-inference/readiness.js +0 -153
  1459. package/services/local-inference/recommendation.d.ts +0 -62
  1460. package/services/local-inference/recommendation.d.ts.map +0 -1
  1461. package/services/local-inference/recommendation.js +0 -309
  1462. package/services/local-inference/registry.d.ts +0 -35
  1463. package/services/local-inference/registry.d.ts.map +0 -1
  1464. package/services/local-inference/registry.js +0 -117
  1465. package/services/local-inference/router-handler.d.ts +0 -51
  1466. package/services/local-inference/router-handler.d.ts.map +0 -1
  1467. package/services/local-inference/router-handler.js +0 -165
  1468. package/services/local-inference/routing-policy.d.ts +0 -55
  1469. package/services/local-inference/routing-policy.d.ts.map +0 -1
  1470. package/services/local-inference/routing-policy.js +0 -195
  1471. package/services/local-inference/routing-preferences.d.ts +0 -8
  1472. package/services/local-inference/routing-preferences.d.ts.map +0 -1
  1473. package/services/local-inference/routing-preferences.js +0 -7
  1474. package/services/local-inference/service.d.ts +0 -88
  1475. package/services/local-inference/service.d.ts.map +0 -1
  1476. package/services/local-inference/service.js +0 -210
  1477. package/services/local-inference/session-pool.d.ts +0 -72
  1478. package/services/local-inference/session-pool.d.ts.map +0 -1
  1479. package/services/local-inference/session-pool.js +0 -125
  1480. package/services/local-inference/types.d.ts +0 -309
  1481. package/services/local-inference/types.d.ts.map +0 -1
  1482. package/services/local-inference/types.js +0 -23
  1483. package/services/local-inference/verify.d.ts +0 -8
  1484. package/services/local-inference/verify.d.ts.map +0 -1
  1485. package/services/local-inference/verify.js +0 -7
  1486. package/services/local-inference/voice/barge-in.d.ts +0 -15
  1487. package/services/local-inference/voice/barge-in.d.ts.map +0 -1
  1488. package/services/local-inference/voice/barge-in.js +0 -20
  1489. package/services/local-inference/voice/engine-bridge.d.ts +0 -256
  1490. package/services/local-inference/voice/engine-bridge.d.ts.map +0 -1
  1491. package/services/local-inference/voice/engine-bridge.js +0 -398
  1492. package/services/local-inference/voice/ffi-bindings.d.ts +0 -114
  1493. package/services/local-inference/voice/ffi-bindings.d.ts.map +0 -1
  1494. package/services/local-inference/voice/ffi-bindings.js +0 -281
  1495. package/services/local-inference/voice/index.d.ts +0 -51
  1496. package/services/local-inference/voice/index.d.ts.map +0 -1
  1497. package/services/local-inference/voice/index.js +0 -50
  1498. package/services/local-inference/voice/lifecycle.d.ts +0 -135
  1499. package/services/local-inference/voice/lifecycle.d.ts.map +0 -1
  1500. package/services/local-inference/voice/lifecycle.js +0 -189
  1501. package/services/local-inference/voice/phoneme-tokenizer.d.ts +0 -58
  1502. package/services/local-inference/voice/phoneme-tokenizer.d.ts.map +0 -1
  1503. package/services/local-inference/voice/phoneme-tokenizer.js +0 -53
  1504. package/services/local-inference/voice/phrase-cache.d.ts +0 -24
  1505. package/services/local-inference/voice/phrase-cache.d.ts.map +0 -1
  1506. package/services/local-inference/voice/phrase-cache.js +0 -32
  1507. package/services/local-inference/voice/phrase-chunker.d.ts +0 -20
  1508. package/services/local-inference/voice/phrase-chunker.d.ts.map +0 -1
  1509. package/services/local-inference/voice/phrase-chunker.js +0 -85
  1510. package/services/local-inference/voice/ring-buffer.d.ts +0 -40
  1511. package/services/local-inference/voice/ring-buffer.d.ts.map +0 -1
  1512. package/services/local-inference/voice/ring-buffer.js +0 -85
  1513. package/services/local-inference/voice/rollback-queue.d.ts +0 -24
  1514. package/services/local-inference/voice/rollback-queue.d.ts.map +0 -1
  1515. package/services/local-inference/voice/rollback-queue.js +0 -49
  1516. package/services/local-inference/voice/scheduler.d.ts +0 -47
  1517. package/services/local-inference/voice/scheduler.d.ts.map +0 -1
  1518. package/services/local-inference/voice/scheduler.js +0 -123
  1519. package/services/local-inference/voice/shared-resources.d.ts +0 -119
  1520. package/services/local-inference/voice/shared-resources.d.ts.map +0 -1
  1521. package/services/local-inference/voice/shared-resources.js +0 -83
  1522. package/services/local-inference/voice/speaker-preset-cache.d.ts +0 -28
  1523. package/services/local-inference/voice/speaker-preset-cache.d.ts.map +0 -1
  1524. package/services/local-inference/voice/speaker-preset-cache.js +0 -44
  1525. package/services/local-inference/voice/types.d.ts +0 -80
  1526. package/services/local-inference/voice/types.d.ts.map +0 -1
  1527. package/services/local-inference/voice/voice-preset-format.d.ts +0 -56
  1528. package/services/local-inference/voice/voice-preset-format.d.ts.map +0 -1
  1529. package/services/local-inference/voice/voice-preset-format.js +0 -184
  1530. package/services/plugin-installer.d.ts +0 -22
  1531. package/services/plugin-installer.d.ts.map +0 -1
  1532. package/services/plugin-installer.js +0 -41
  1533. package/test/scripts/task-agent-live-smoke.ts +0 -1335
  1534. /package/services/{local-inference/voice → ambient-audio}/types.js +0 -0
@@ -17,11 +17,10 @@
17
17
  * remote -- it simply connects to `http://localhost:{port}`.
18
18
  *
19
19
  * **Port policy (WHY):** we resolve a **free** loopback desktop API port from
20
- * `ELIZA_API_PORT`, `ELIZA_API_PORT`, or `ELIZA_PORT` (see
21
- * `findFirstAvailableLoopbackPort`) instead of SIGKILL-ing listeners by
22
- * default, so two desktop apps can run side by side. Optional
23
- * `ELIZA_AGENT_RECLAIM_STALE_PORT=1` (legacy: `ELIZA_AGENT_RECLAIM_STALE_PORT`)
24
- * restores lsof-based reclaim for single-instance dev.
20
+ * `ELIZA_API_PORT` or `ELIZA_PORT` (see `findFirstAvailableLoopbackPort`)
21
+ * instead of SIGKILL-ing listeners by default, so two desktop apps can run
22
+ * side by side. Optional `ELIZA_AGENT_RECLAIM_STALE_PORT=1` restores
23
+ * lsof-based reclaim for single-instance dev.
25
24
  */
26
25
 
27
26
  import crypto from "node:crypto";
@@ -29,65 +28,82 @@ import fs from "node:fs";
29
28
  import os from "node:os";
30
29
  import path from "node:path";
31
30
  import {
32
- resolveApiToken,
33
- resolveDesktopApiPort,
34
- resolveDisableAutoApiToken,
35
- setApiToken,
31
+ resolveApiToken,
32
+ resolveDesktopApiPort,
33
+ resolveDisableAutoApiToken,
34
+ setApiToken,
36
35
  } from "@elizaos/shared";
37
36
  import { Utils } from "electrobun/bun";
38
37
  import { resolveDesktopRuntimeMode } from "../api-base";
39
38
  import { getBrandConfig } from "../brand-config";
40
39
  import { DEFAULT_API_PORT } from "../constants";
40
+ import {
41
+ acquireDatabaseStartupLock,
42
+ applyDatabaseResolutionToEnv,
43
+ backupPgliteDirectory,
44
+ classifyDatabaseError,
45
+ createDatabaseSnapshot,
46
+ createUnknownDatabaseSnapshot,
47
+ type DatabaseSnapshot,
48
+ type DatabaseStartupLock,
49
+ ensurePgliteDataDir,
50
+ redactDatabaseTarget,
51
+ resetPgliteDirectory,
52
+ resolveDatabaseMode,
53
+ updateDatabaseSnapshotStatus,
54
+ } from "../database";
41
55
  import { logger } from "../logger";
42
56
  import { recordStartupPhase, resolveStartupBundlePath } from "../startup-trace";
43
57
  import type { SendToWebview } from "../types.js";
44
58
  import { findFirstAvailableLoopbackPort } from "./loopback-port";
59
+ import { applyBundledWhisperEnv } from "./whisper-env";
45
60
 
46
61
  // ---------------------------------------------------------------------------
47
62
  // Types
48
63
  // ---------------------------------------------------------------------------
49
64
 
50
65
  interface AgentStatus {
51
- state: "not_started" | "starting" | "running" | "stopped" | "error";
52
- agentName: string | null;
53
- port: number | null;
54
- startedAt: number | null;
55
- error: string | null;
66
+ state: "not_started" | "starting" | "running" | "stopped" | "error";
67
+ agentName: string | null;
68
+ port: number | null;
69
+ startedAt: number | null;
70
+ error: string | null;
56
71
  }
57
72
 
58
73
  export interface StartupDiagnosticsSnapshot {
59
- state: AgentStatus["state"];
60
- phase: string;
61
- updatedAt: string;
62
- lastError: string | null;
63
- agentName: string | null;
64
- port: number | null;
65
- startedAt: number | null;
66
- platform: string;
67
- arch: string;
68
- configDir: string;
69
- logPath: string;
70
- statusPath: string;
74
+ state: AgentStatus["state"];
75
+ phase: string;
76
+ updatedAt: string;
77
+ lastError: string | null;
78
+ agentName: string | null;
79
+ port: number | null;
80
+ startedAt: number | null;
81
+ platform: string;
82
+ arch: string;
83
+ configDir: string;
84
+ logPath: string;
85
+ statusPath: string;
86
+ database: DatabaseSnapshot;
71
87
  }
72
88
 
73
89
  export interface BugReportBundleResult {
74
- directory: string;
75
- reportMarkdownPath: string;
76
- reportJsonPath: string;
77
- startupLogPath: string | null;
78
- startupStatusPath: string | null;
90
+ directory: string;
91
+ reportMarkdownPath: string;
92
+ reportJsonPath: string;
93
+ startupLogPath: string | null;
94
+ startupStatusPath: string | null;
79
95
  }
80
96
 
81
97
  import type {
82
- ExistingElizaInstallInfo,
83
- ExistingElizaInstallSource,
84
- StateDirMigrationResult,
98
+ ExistingElizaInstallInfo,
99
+ ExistingElizaInstallSource,
100
+ StateDirMigrationResult,
85
101
  } from "../rpc-schema";
86
102
 
87
103
  export type {
88
- ExistingElizaInstallInfo,
89
- ExistingElizaInstallSource,
90
- StateDirMigrationResult,
104
+ ExistingElizaInstallInfo,
105
+ ExistingElizaInstallSource,
106
+ StateDirMigrationResult,
91
107
  };
92
108
 
93
109
  // Subprocess type from Bun.spawn
@@ -104,283 +120,408 @@ const WINDOWS_ABS_PATH_RE = /^[A-Za-z]:[\\/]/;
104
120
  const ELIZA_CONFIG_FILENAME = "eliza.json";
105
121
 
106
122
  export function getHealthPollTimeoutMs(
107
- env: NodeJS.ProcessEnv = process.env,
108
- platform: string = process.platform,
123
+ env: NodeJS.ProcessEnv = process.env,
124
+ platform: string = process.platform,
109
125
  ): number {
110
- const raw = env.ELIZA_AGENT_HEALTH_TIMEOUT_MS?.trim();
111
- if (raw) {
112
- const parsed = Number.parseInt(raw, 10);
113
- if (Number.isFinite(parsed) && parsed > 0) {
114
- return parsed;
115
- }
116
- }
117
-
118
- // Windows packaged first-run startup can include PGLite initialization plus
119
- // a GGUF embedding model download before /api/health comes online.
120
- return platform === "win32" ? 240_000 : 120_000;
126
+ const raw = env.ELIZA_AGENT_HEALTH_TIMEOUT_MS?.trim();
127
+ if (raw) {
128
+ const parsed = Number.parseInt(raw, 10);
129
+ if (Number.isFinite(parsed) && parsed > 0) {
130
+ return parsed;
131
+ }
132
+ }
133
+
134
+ // Windows packaged first-run startup can include PGLite initialization plus
135
+ // a GGUF embedding model download before /api/health comes online.
136
+ return platform === "win32" ? 240_000 : 120_000;
121
137
  }
122
138
 
123
139
  function isPosixAbsolutePath(value: string): boolean {
124
- return value.startsWith("/") && !WINDOWS_ABS_PATH_RE.test(value);
140
+ return value.startsWith("/") && !WINDOWS_ABS_PATH_RE.test(value);
125
141
  }
126
142
 
127
143
  function resolvePortablePath(value: string): string {
128
- if (isPosixAbsolutePath(value) || WINDOWS_ABS_PATH_RE.test(value)) {
129
- return value;
130
- }
131
- return path.resolve(value);
144
+ if (isPosixAbsolutePath(value) || WINDOWS_ABS_PATH_RE.test(value)) {
145
+ return value;
146
+ }
147
+ return path.resolve(value);
132
148
  }
133
149
 
134
150
  function dirnamePortable(value: string): string {
135
- return isPosixAbsolutePath(value)
136
- ? path.posix.dirname(value)
137
- : path.dirname(value);
151
+ return isPosixAbsolutePath(value)
152
+ ? path.posix.dirname(value)
153
+ : path.dirname(value);
138
154
  }
139
155
 
140
156
  function joinPortable(base: string, ...parts: string[]): string {
141
- return isPosixAbsolutePath(base)
142
- ? path.posix.join(base, ...parts)
143
- : path.join(base, ...parts);
157
+ return isPosixAbsolutePath(base)
158
+ ? path.posix.join(base, ...parts)
159
+ : path.join(base, ...parts);
144
160
  }
145
161
 
146
162
  function resolveRelativePortable(base: string, relativePath: string): string {
147
- return isPosixAbsolutePath(base)
148
- ? path.posix.resolve(base, relativePath)
149
- : path.resolve(base, relativePath);
163
+ return isPosixAbsolutePath(base)
164
+ ? path.posix.resolve(base, relativePath)
165
+ : path.resolve(base, relativePath);
150
166
  }
151
167
 
152
168
  function getDefaultModuleDir(): string {
153
- return import.meta.dir ?? path.join(process.cwd(), "src");
169
+ return import.meta.dir;
154
170
  }
155
171
 
156
172
  function normalizeEnvPath(value: string | undefined): string | null {
157
- const trimmed = value?.trim();
158
- return trimmed ? resolvePortablePath(trimmed) : null;
173
+ const trimmed = value?.trim();
174
+ return trimmed ? resolvePortablePath(trimmed) : null;
159
175
  }
160
176
 
161
177
  function isStoreBuildVariant(env: NodeJS.ProcessEnv = process.env): boolean {
162
- const raw =
163
- env.MILADY_BUILD_VARIANT?.trim() || env.ELIZA_BUILD_VARIANT?.trim();
164
- return raw?.toLowerCase() === "store";
178
+ const raw = env.ELIZA_BUILD_VARIANT?.trim();
179
+ return raw?.toLowerCase() === "store";
180
+ }
181
+
182
+ function resolveBrandAwareNamespace(
183
+ envNamespace: string | undefined,
184
+ brandNamespace = getBrandConfig().namespace || "eliza",
185
+ ): string {
186
+ const trimmed = envNamespace?.trim();
187
+ if (!trimmed) return brandNamespace;
188
+ if (trimmed === "eliza" && brandNamespace !== "eliza") return brandNamespace;
189
+ return trimmed;
165
190
  }
166
191
 
167
192
  function resolveStateNamespace(env: NodeJS.ProcessEnv = process.env): string {
168
- return env.ELIZA_NAMESPACE?.trim() || getBrandConfig().namespace || "eliza";
193
+ return resolveBrandAwareNamespace(env.ELIZA_NAMESPACE);
194
+ }
195
+
196
+ export function resolveDesktopChildNamespace(
197
+ env: Record<string, string | undefined>,
198
+ brandNamespace?: string,
199
+ ): string {
200
+ return resolveBrandAwareNamespace(env.ELIZA_NAMESPACE, brandNamespace);
169
201
  }
170
202
 
171
203
  function resolveExplicitStateDir(env: NodeJS.ProcessEnv): string | null {
172
- return (
173
- normalizeEnvPath(env.MILADY_STATE_DIR) ??
174
- normalizeEnvPath(env.ELIZA_STATE_DIR)
175
- );
204
+ return normalizeEnvPath(env.ELIZA_STATE_DIR);
205
+ }
206
+
207
+ function isTruthyDesktopEnv(value: string | undefined): boolean {
208
+ const normalized = value?.trim().toLowerCase();
209
+ return normalized === "1" || normalized === "true" || normalized === "yes";
210
+ }
211
+
212
+ export function applyPackagedStartupEmbeddingWarmupPolicy(
213
+ childEnv: Record<string, string>,
214
+ packagedRuntime: boolean,
215
+ ): void {
216
+ if (!packagedRuntime) {
217
+ return;
218
+ }
219
+
220
+ const explicitSkip = childEnv.ELIZA_SKIP_LOCAL_EMBEDDING_WARMUP?.trim();
221
+ if (explicitSkip) {
222
+ childEnv.ELIZA_SKIP_LOCAL_EMBEDDING_WARMUP = explicitSkip;
223
+ return;
224
+ }
225
+
226
+ if (
227
+ isTruthyDesktopEnv(childEnv.ELIZA_ENABLE_STARTUP_LOCAL_EMBEDDING_WARMUP)
228
+ ) {
229
+ return;
230
+ }
231
+
232
+ childEnv.ELIZA_SKIP_LOCAL_EMBEDDING_WARMUP = "1";
233
+ }
234
+
235
+ /**
236
+ * Default the desktop-spawned agent to deferring the post-ready boot tail so
237
+ * `/api/health` flips `ready:true` (and the renderer reaches first paint /
238
+ * usable chat) before app-route plugins, training hooks, sensitive-request
239
+ * adapters, the trigger bridge, the connector catalog, and voice warmup finish.
240
+ *
241
+ * The trade-off is a brief window after "ready" where feature routes registered
242
+ * by app-route plugins (e.g. lifeops/steward/training) can 404 until the
243
+ * background tail completes — acceptable on desktop where first paint latency is
244
+ * far more visible than a sub-second feature-route gap.
245
+ *
246
+ * Only sets the default when `ELIZA_DEFER_APP_ROUTES` is unset, so an explicit
247
+ * `0`/`1` from the user or a test harness always wins. The production CLI
248
+ * `serve` path (not spawned here) is untouched and keeps the awaited-inline tail.
249
+ */
250
+ export function applyDesktopDeferAppRoutesPolicy(
251
+ childEnv: Record<string, string>,
252
+ ): void {
253
+ if (childEnv.ELIZA_DEFER_APP_ROUTES?.trim()) {
254
+ return;
255
+ }
256
+ childEnv.ELIZA_DEFER_APP_ROUTES = "1";
257
+ }
258
+
259
+ export function prependDesktopChildPathDirectory(
260
+ childEnv: Record<string, string | undefined>,
261
+ directory: string,
262
+ ): boolean {
263
+ const existingPathKey =
264
+ childEnv.PATH !== undefined
265
+ ? "PATH"
266
+ : childEnv.Path !== undefined
267
+ ? "Path"
268
+ : "PATH";
269
+ const existingPath = childEnv[existingPathKey]?.trim();
270
+ if (!existingPath) {
271
+ childEnv[existingPathKey] = directory;
272
+ return true;
273
+ }
274
+ if (existingPath.split(path.delimiter).includes(directory)) {
275
+ return false;
276
+ }
277
+ childEnv[existingPathKey] = `${directory}${path.delimiter}${existingPath}`;
278
+ return true;
176
279
  }
177
280
 
178
281
  function resolveStoreUserDataStateDir(): string {
179
- const userData = Utils.paths.userData || resolveConfigDir();
180
- return path.join(userData, "state");
282
+ const userData = Utils.paths.userData || resolveConfigDir();
283
+ return path.join(userData, "state");
284
+ }
285
+
286
+ function resolveXdgStateHome(opts?: {
287
+ env?: NodeJS.ProcessEnv;
288
+ homedir?: string;
289
+ }): string {
290
+ const env = opts?.env ?? process.env;
291
+ const explicit = normalizeEnvPath(env.XDG_STATE_HOME);
292
+ if (explicit) return explicit;
293
+ return joinPortable(opts?.homedir ?? os.homedir(), ".local", "state");
294
+ }
295
+
296
+ function resolveDefaultDesktopStateDir(opts?: {
297
+ env?: NodeJS.ProcessEnv;
298
+ homedir?: string;
299
+ }): string {
300
+ const env = opts?.env ?? process.env;
301
+ return joinPortable(resolveXdgStateHome(opts), resolveStateNamespace(env));
302
+ }
303
+
304
+ function resolveLegacyDotStateDir(opts?: {
305
+ env?: NodeJS.ProcessEnv;
306
+ homedir?: string;
307
+ }): string {
308
+ return joinPortable(
309
+ opts?.homedir ?? os.homedir(),
310
+ `.${resolveStateNamespace(opts?.env ?? process.env)}`,
311
+ );
181
312
  }
182
313
 
183
314
  export function resolveDesktopChildStateDir(opts?: {
184
- env?: NodeJS.ProcessEnv;
185
- homedir?: string;
315
+ env?: NodeJS.ProcessEnv;
316
+ homedir?: string;
186
317
  }): string {
187
- const env = opts?.env ?? process.env;
188
- const explicit = resolveExplicitStateDir(env);
189
- if (explicit) return explicit;
190
- if (isStoreBuildVariant(env)) return resolveStoreUserDataStateDir();
191
- return joinPortable(
192
- opts?.homedir ?? os.homedir(),
193
- `.${resolveStateNamespace(env)}`,
194
- );
318
+ const env = opts?.env ?? process.env;
319
+ const explicit = resolveExplicitStateDir(env);
320
+ if (explicit) return explicit;
321
+ if (isStoreBuildVariant(env)) return resolveStoreUserDataStateDir();
322
+ return resolveDefaultDesktopStateDir(opts);
195
323
  }
196
324
 
197
325
  function applyDesktopChildStateEnv(childEnv: Record<string, string>): void {
198
- if (!isStoreBuildVariant(childEnv as NodeJS.ProcessEnv)) return;
199
- const stateDir = resolveDesktopChildStateDir({
200
- env: childEnv as NodeJS.ProcessEnv,
201
- });
202
- fs.mkdirSync(stateDir, { recursive: true });
203
- childEnv.MILADY_STATE_DIR = stateDir;
204
- childEnv.ELIZA_STATE_DIR = stateDir;
326
+ const stateDir = resolveDesktopChildStateDir({
327
+ env: childEnv as NodeJS.ProcessEnv,
328
+ });
329
+ fs.mkdirSync(stateDir, { recursive: true });
330
+ childEnv.ELIZA_STATE_DIR = stateDir;
331
+ }
332
+
333
+ export function applyWindowsNativeInferenceDefaults(
334
+ childEnv: Record<string, string>,
335
+ platform: NodeJS.Platform = process.platform,
336
+ ): void {
337
+ if (platform !== "win32") return;
338
+
339
+ // node-llama-cpp crashes Bun on Windows during packaged startup.
340
+ // Disable local embeddings until upstream fix lands.
341
+ childEnv.ELIZA_DISABLE_LOCAL_EMBEDDINGS = "1";
342
+
343
+ // The fused elizaOS llama.cpp / OmniVoice runtime can trip GGML's
344
+ // uncaught-exception backtrace guard inside packaged Bun unless this is set
345
+ // before any native GGML library is loaded.
346
+ if (!childEnv.GGML_NO_BACKTRACE?.trim()) {
347
+ childEnv.GGML_NO_BACKTRACE = "1";
348
+ }
205
349
  }
206
350
 
207
351
  function listStateEntries(stateDir: string): string[] {
208
- try {
209
- return fs
210
- .readdirSync(stateDir)
211
- .filter(
212
- (entry) => entry !== "." && entry !== ".." && entry !== ".DS_Store",
213
- );
214
- } catch {
215
- return [];
216
- }
352
+ try {
353
+ return fs
354
+ .readdirSync(stateDir)
355
+ .filter(
356
+ (entry) => entry !== "." && entry !== ".." && entry !== ".DS_Store",
357
+ );
358
+ } catch {
359
+ return [];
360
+ }
217
361
  }
218
362
 
219
363
  function buildExistingElizaInstallCandidates(opts?: {
220
- env?: NodeJS.ProcessEnv;
221
- homedir?: string;
364
+ env?: NodeJS.ProcessEnv;
365
+ homedir?: string;
222
366
  }): Array<{
223
- source: ExistingElizaInstallSource;
224
- stateDir: string;
225
- configPath: string;
367
+ source: ExistingElizaInstallSource;
368
+ stateDir: string;
369
+ configPath: string;
226
370
  }> {
227
- const env = opts?.env ?? process.env;
228
- const homedir = opts?.homedir ?? os.homedir();
229
- const configPathFromEnv =
230
- normalizeEnvPath(env.MILADY_CONFIG_PATH) ??
231
- normalizeEnvPath(env.ELIZA_CONFIG_PATH);
232
- const stateDirFromEnv = resolveExplicitStateDir(env);
233
- const defaultStateDir = joinPortable(
234
- homedir,
235
- `.${resolveStateNamespace(env)}`,
236
- );
237
-
238
- const candidates = [
239
- configPathFromEnv
240
- ? {
241
- source: "config-path-env" as const,
242
- stateDir: dirnamePortable(configPathFromEnv),
243
- configPath: configPathFromEnv,
244
- }
245
- : null,
246
- stateDirFromEnv
247
- ? {
248
- source: "state-dir-env" as const,
249
- stateDir: stateDirFromEnv,
250
- configPath: joinPortable(stateDirFromEnv, ELIZA_CONFIG_FILENAME),
251
- }
252
- : null,
253
- {
254
- source: "default-state-dir" as const,
255
- stateDir: defaultStateDir,
256
- configPath: joinPortable(defaultStateDir, ELIZA_CONFIG_FILENAME),
257
- },
258
- ].filter((candidate): candidate is NonNullable<typeof candidate> =>
259
- Boolean(candidate),
260
- );
261
-
262
- return candidates.filter(
263
- (candidate, index, all) =>
264
- all.findIndex(
265
- (other) =>
266
- other.stateDir === candidate.stateDir &&
267
- other.configPath === candidate.configPath,
268
- ) === index,
269
- );
371
+ const env = opts?.env ?? process.env;
372
+ const homedir = opts?.homedir ?? os.homedir();
373
+ const configPathFromEnv = normalizeEnvPath(env.ELIZA_CONFIG_PATH);
374
+ const stateDirFromEnv = resolveExplicitStateDir(env);
375
+ const defaultStateDir = resolveDefaultDesktopStateDir({ env, homedir });
376
+ const legacyStateDir = resolveLegacyDotStateDir({ env, homedir });
377
+
378
+ const candidates = [
379
+ configPathFromEnv
380
+ ? {
381
+ source: "config-path-env" as const,
382
+ stateDir: dirnamePortable(configPathFromEnv),
383
+ configPath: configPathFromEnv,
384
+ }
385
+ : null,
386
+ stateDirFromEnv
387
+ ? {
388
+ source: "state-dir-env" as const,
389
+ stateDir: stateDirFromEnv,
390
+ configPath: joinPortable(stateDirFromEnv, ELIZA_CONFIG_FILENAME),
391
+ }
392
+ : null,
393
+ {
394
+ source: "default-state-dir" as const,
395
+ stateDir: defaultStateDir,
396
+ configPath: joinPortable(defaultStateDir, ELIZA_CONFIG_FILENAME),
397
+ },
398
+ legacyStateDir !== defaultStateDir
399
+ ? {
400
+ source: "legacy-dot-state-dir" as const,
401
+ stateDir: legacyStateDir,
402
+ configPath: joinPortable(legacyStateDir, ELIZA_CONFIG_FILENAME),
403
+ }
404
+ : null,
405
+ ].filter((candidate): candidate is NonNullable<typeof candidate> =>
406
+ Boolean(candidate),
407
+ );
408
+
409
+ return candidates.filter(
410
+ (candidate, index, all) =>
411
+ all.findIndex(
412
+ (other) =>
413
+ other.stateDir === candidate.stateDir &&
414
+ other.configPath === candidate.configPath,
415
+ ) === index,
416
+ );
270
417
  }
271
418
 
272
419
  export function inspectExistingElizaInstall(opts?: {
273
- env?: NodeJS.ProcessEnv;
274
- homedir?: string;
420
+ env?: NodeJS.ProcessEnv;
421
+ homedir?: string;
275
422
  }): ExistingElizaInstallInfo {
276
- const candidates = buildExistingElizaInstallCandidates(opts);
277
-
278
- for (const candidate of candidates) {
279
- const configExists = fs.existsSync(candidate.configPath);
280
- const stateDirExists = fs.existsSync(candidate.stateDir);
281
- const hasStateEntries =
282
- stateDirExists && listStateEntries(candidate.stateDir).length > 0;
283
-
284
- if (configExists || hasStateEntries) {
285
- return {
286
- detected: true,
287
- stateDir: candidate.stateDir,
288
- configPath: candidate.configPath,
289
- configExists,
290
- stateDirExists,
291
- hasStateEntries,
292
- source: candidate.source,
293
- };
294
- }
295
- }
296
-
297
- const fallback = candidates[0] ?? {
298
- source: "default-state-dir" as const,
299
- stateDir: joinPortable(
300
- opts?.homedir ?? os.homedir(),
301
- `.${resolveStateNamespace(opts?.env ?? process.env)}`,
302
- ),
303
- configPath: joinPortable(
304
- joinPortable(
305
- opts?.homedir ?? os.homedir(),
306
- `.${resolveStateNamespace(opts?.env ?? process.env)}`,
307
- ),
308
- ELIZA_CONFIG_FILENAME,
309
- ),
310
- };
311
-
312
- return {
313
- detected: false,
314
- stateDir: fallback.stateDir,
315
- configPath: fallback.configPath,
316
- configExists: false,
317
- stateDirExists: fs.existsSync(fallback.stateDir),
318
- hasStateEntries: false,
319
- source: fallback.source,
320
- };
423
+ const candidates = buildExistingElizaInstallCandidates(opts);
424
+
425
+ for (const candidate of candidates) {
426
+ const configExists = fs.existsSync(candidate.configPath);
427
+ const stateDirExists = fs.existsSync(candidate.stateDir);
428
+ const hasStateEntries =
429
+ stateDirExists && listStateEntries(candidate.stateDir).length > 0;
430
+
431
+ if (configExists || hasStateEntries) {
432
+ return {
433
+ detected: true,
434
+ stateDir: candidate.stateDir,
435
+ configPath: candidate.configPath,
436
+ configExists,
437
+ stateDirExists,
438
+ hasStateEntries,
439
+ source: candidate.source,
440
+ };
441
+ }
442
+ }
443
+
444
+ const fallback = candidates[0] ?? {
445
+ source: "default-state-dir" as const,
446
+ stateDir: resolveDefaultDesktopStateDir(opts),
447
+ configPath: joinPortable(
448
+ resolveDefaultDesktopStateDir(opts),
449
+ ELIZA_CONFIG_FILENAME,
450
+ ),
451
+ };
452
+
453
+ return {
454
+ detected: false,
455
+ stateDir: fallback.stateDir,
456
+ configPath: fallback.configPath,
457
+ configExists: false,
458
+ stateDirExists: fs.existsSync(fallback.stateDir),
459
+ hasStateEntries: false,
460
+ source: fallback.source,
461
+ };
321
462
  }
322
463
 
323
464
  export function migrateDesktopStateDirFromPath(
324
- fromPath: string,
325
- opts?: { env?: NodeJS.ProcessEnv },
465
+ fromPath: string,
466
+ opts?: { env?: NodeJS.ProcessEnv },
326
467
  ): StateDirMigrationResult {
327
- const source = resolvePortablePath(fromPath);
328
- const target = resolveDesktopChildStateDir({ env: opts?.env ?? process.env });
329
-
330
- if (source === target) {
331
- return {
332
- ok: true,
333
- migrated: false,
334
- fromPath: source,
335
- toPath: target,
336
- skippedReason: "same-path",
337
- };
338
- }
339
-
340
- try {
341
- const stat = fs.statSync(source);
342
- if (!stat.isDirectory()) {
343
- return {
344
- ok: true,
345
- migrated: false,
346
- fromPath: source,
347
- toPath: target,
348
- skippedReason: "source-not-directory",
349
- };
350
- }
351
- } catch {
352
- return {
353
- ok: true,
354
- migrated: false,
355
- fromPath: source,
356
- toPath: target,
357
- skippedReason: "source-missing",
358
- };
359
- }
360
-
361
- try {
362
- fs.mkdirSync(target, { recursive: true });
363
- fs.cpSync(source, target, {
364
- recursive: true,
365
- force: false,
366
- errorOnExist: false,
367
- dereference: false,
368
- });
369
- return {
370
- ok: true,
371
- migrated: true,
372
- fromPath: source,
373
- toPath: target,
374
- };
375
- } catch (err) {
376
- return {
377
- ok: false,
378
- migrated: false,
379
- fromPath: source,
380
- toPath: target,
381
- error: err instanceof Error ? err.message : String(err),
382
- };
383
- }
468
+ const source = resolvePortablePath(fromPath);
469
+ const target = resolveDesktopChildStateDir({ env: opts?.env ?? process.env });
470
+
471
+ if (source === target) {
472
+ return {
473
+ ok: true,
474
+ migrated: false,
475
+ fromPath: source,
476
+ toPath: target,
477
+ skippedReason: "same-path",
478
+ };
479
+ }
480
+
481
+ try {
482
+ const stat = fs.statSync(source);
483
+ if (!stat.isDirectory()) {
484
+ return {
485
+ ok: true,
486
+ migrated: false,
487
+ fromPath: source,
488
+ toPath: target,
489
+ skippedReason: "source-not-directory",
490
+ };
491
+ }
492
+ } catch {
493
+ return {
494
+ ok: true,
495
+ migrated: false,
496
+ fromPath: source,
497
+ toPath: target,
498
+ skippedReason: "source-missing",
499
+ };
500
+ }
501
+
502
+ try {
503
+ fs.mkdirSync(target, { recursive: true });
504
+ fs.cpSync(source, target, {
505
+ recursive: true,
506
+ force: false,
507
+ errorOnExist: false,
508
+ dereference: false,
509
+ });
510
+ return {
511
+ ok: true,
512
+ migrated: true,
513
+ fromPath: source,
514
+ toPath: target,
515
+ };
516
+ } catch (err) {
517
+ return {
518
+ ok: false,
519
+ migrated: false,
520
+ fromPath: source,
521
+ toPath: target,
522
+ error: err instanceof Error ? err.message : String(err),
523
+ };
524
+ }
384
525
  }
385
526
 
386
527
  // ---------------------------------------------------------------------------
@@ -396,268 +537,269 @@ export function migrateDesktopStateDirFromPath(
396
537
  * to mock process globals.
397
538
  */
398
539
  export function resolveConfigDir(opts?: {
399
- platform?: string;
400
- appdata?: string;
401
- homedir?: string;
540
+ platform?: string;
541
+ appdata?: string;
542
+ homedir?: string;
402
543
  }): string {
403
- const platform = opts?.platform ?? process.platform;
404
- const homedir = opts?.homedir ?? os.homedir();
405
- const dirName = getBrandConfig().configDirName;
406
- if (platform === "win32") {
407
- const roaming =
408
- opts?.appdata ??
409
- process.env.APPDATA ??
410
- joinPortable(homedir, "AppData", "Roaming");
411
- return joinPortable(roaming, dirName);
412
- }
413
- return joinPortable(homedir, ".config", dirName);
544
+ const platform = opts?.platform ?? process.platform;
545
+ const homedir = opts?.homedir ?? os.homedir();
546
+ const dirName = getBrandConfig().configDirName;
547
+ if (platform === "win32") {
548
+ const roaming =
549
+ opts?.appdata ??
550
+ process.env.APPDATA ??
551
+ joinPortable(homedir, "AppData", "Roaming");
552
+ return joinPortable(roaming, dirName);
553
+ }
554
+ return joinPortable(homedir, ".config", dirName);
414
555
  }
415
556
 
416
557
  export function ensureDesktopApiToken(
417
- env: NodeJS.ProcessEnv = process.env,
558
+ env: NodeJS.ProcessEnv = process.env,
418
559
  ): string {
419
- const existingToken = resolveApiToken(env);
420
- if (existingToken) {
421
- setApiToken(env, existingToken);
422
- return existingToken;
423
- }
424
-
425
- if (resolveDisableAutoApiToken(env)) {
426
- return "";
427
- }
428
-
429
- const generated = crypto.randomBytes(16).toString("hex");
430
- setApiToken(env, generated);
431
- return generated;
560
+ const existingToken = resolveApiToken(env);
561
+ if (existingToken) {
562
+ setApiToken(env, existingToken);
563
+ return existingToken;
564
+ }
565
+
566
+ if (resolveDisableAutoApiToken(env)) {
567
+ return "";
568
+ }
569
+
570
+ const generated = crypto.randomBytes(16).toString("hex");
571
+ setApiToken(env, generated);
572
+ return generated;
432
573
  }
433
574
 
434
575
  export function configureDesktopLocalApiAuth(
435
- env: NodeJS.ProcessEnv = process.env,
576
+ env: NodeJS.ProcessEnv = process.env,
436
577
  ): string {
437
- const token = ensureDesktopApiToken(env);
438
- env.ELIZA_PAIRING_DISABLED = "1";
439
- return token;
578
+ const token = ensureDesktopApiToken(env);
579
+ env.ELIZA_PAIRING_DISABLED = "1";
580
+ return token;
440
581
  }
441
582
 
442
583
  function getDesktopApiToken(
443
- env: NodeJS.ProcessEnv = process.env,
584
+ env: NodeJS.ProcessEnv = process.env,
444
585
  ): string | null {
445
- return resolveApiToken(env);
586
+ return resolveApiToken(env);
446
587
  }
447
588
 
448
589
  function getDesktopApiHeaders(
449
- env: NodeJS.ProcessEnv = process.env,
590
+ env: NodeJS.ProcessEnv = process.env,
450
591
  ): Record<string, string> | undefined {
451
- const token = getDesktopApiToken(env);
452
- if (!token) return undefined;
453
- return {
454
- Authorization: `Bearer ${token}`,
455
- "X-Api-Key": token,
456
- "X-Api-Token": token,
457
- };
592
+ const token = getDesktopApiToken(env);
593
+ if (!token) return undefined;
594
+ return {
595
+ Authorization: `Bearer ${token}`,
596
+ "X-Api-Key": token,
597
+ "X-Api-Token": token,
598
+ };
458
599
  }
459
600
 
460
601
  let diagnosticLogPath: string | null = null;
461
602
  let startupStatusPath: string | null = null;
462
603
 
463
604
  export function getDiagnosticLogPath(): string {
464
- if (diagnosticLogPath !== null) return diagnosticLogPath;
465
- try {
466
- const configDir = resolveConfigDir();
467
- if (!fs.existsSync(configDir)) {
468
- fs.mkdirSync(configDir, { recursive: true });
469
- }
470
- diagnosticLogPath = path.join(
471
- configDir,
472
- getBrandConfig().startupLogFileName,
473
- );
474
- } catch {
475
- // Fallback to temp dir
476
- diagnosticLogPath = path.join(
477
- os.tmpdir(),
478
- getBrandConfig().startupLogFileName,
479
- );
480
- }
481
- return diagnosticLogPath;
605
+ if (diagnosticLogPath !== null) return diagnosticLogPath;
606
+ try {
607
+ const configDir = resolveConfigDir();
608
+ if (!fs.existsSync(configDir)) {
609
+ fs.mkdirSync(configDir, { recursive: true });
610
+ }
611
+ diagnosticLogPath = path.join(
612
+ configDir,
613
+ getBrandConfig().startupLogFileName,
614
+ );
615
+ } catch {
616
+ // Fallback to temp dir
617
+ diagnosticLogPath = path.join(
618
+ os.tmpdir(),
619
+ getBrandConfig().startupLogFileName,
620
+ );
621
+ }
622
+ return diagnosticLogPath;
482
623
  }
483
624
 
484
625
  export function getStartupStatusPath(): string {
485
- if (startupStatusPath !== null) return startupStatusPath;
486
- try {
487
- const configDir = resolveConfigDir();
488
- if (!fs.existsSync(configDir)) {
489
- fs.mkdirSync(configDir, { recursive: true });
490
- }
491
- startupStatusPath = path.join(configDir, "startup-status.json");
492
- } catch {
493
- startupStatusPath = path.join(os.tmpdir(), "startup-status.json");
494
- }
495
- return startupStatusPath;
626
+ if (startupStatusPath !== null) return startupStatusPath;
627
+ try {
628
+ const configDir = resolveConfigDir();
629
+ if (!fs.existsSync(configDir)) {
630
+ fs.mkdirSync(configDir, { recursive: true });
631
+ }
632
+ startupStatusPath = path.join(configDir, "startup-status.json");
633
+ } catch {
634
+ startupStatusPath = path.join(os.tmpdir(), "startup-status.json");
635
+ }
636
+ return startupStatusPath;
496
637
  }
497
638
 
498
639
  export function diagnosticLog(message: string): void {
499
- const timestamp = new Date().toISOString();
500
- const line = `[${timestamp}] ${message}\n`;
501
- console.log(message);
502
- try {
503
- const logPath = getDiagnosticLogPath();
504
- fs.appendFileSync(logPath, line);
505
- } catch {
506
- // Ignore write errors
507
- }
640
+ const timestamp = new Date().toISOString();
641
+ const line = `[${timestamp}] ${message}\n`;
642
+ console.log(message);
643
+ try {
644
+ const logPath = getDiagnosticLogPath();
645
+ fs.appendFileSync(logPath, line);
646
+ } catch {
647
+ // Ignore write errors
648
+ }
508
649
  }
509
650
 
510
651
  /** One-line, truncated error string safe for UI (status.error). */
511
652
  function shortError(err: unknown, maxLen = 280): string {
512
- const raw =
513
- err instanceof Error
514
- ? err.message || (err.stack ?? String(err))
515
- : String(err);
516
- const oneLine = raw.replace(/\s+/g, " ").trim();
517
- if (oneLine.length <= maxLen) return oneLine;
518
- return `${oneLine.slice(0, maxLen)}... (see logs for full details)`;
653
+ const raw =
654
+ err instanceof Error
655
+ ? err.message || (err.stack ?? String(err))
656
+ : String(err);
657
+ const oneLine = raw.replace(/\s+/g, " ").trim();
658
+ if (oneLine.length <= maxLen) return oneLine;
659
+ return `${oneLine.slice(0, maxLen)}... (see logs for full details)`;
519
660
  }
520
661
 
521
662
  export function redactSensitiveDiagnostics(input: string): string {
522
- return input
523
- .replace(
524
- /(authorization\s*[:=]\s*bearer\s+)([a-z0-9._-]+)/gi,
525
- "$1[REDACTED]",
526
- )
527
- .replace(
528
- /((?:x-api-key|x-api-token|api[_-]?key|bearer[_-]?token|access[_-]?token|secret|password)\s*[:=]\s*)([^\s]+)/gi,
529
- "$1[REDACTED]",
530
- );
663
+ return input
664
+ .replace(
665
+ /(authorization\s*[:=]\s*bearer\s+)([a-z0-9._-]+)/gi,
666
+ "$1[REDACTED]",
667
+ )
668
+ .replace(
669
+ /((?:x-api-key|x-api-token|api[_-]?key|bearer[_-]?token|access[_-]?token|secret|password)\s*[:=]\s*)([^\s]+)/gi,
670
+ "$1[REDACTED]",
671
+ );
531
672
  }
532
673
 
533
674
  function readFileTail(filePath: string, maxChars = 16_000): string {
534
- try {
535
- const content = fs.readFileSync(filePath, "utf8");
536
- return redactSensitiveDiagnostics(content.slice(-maxChars));
537
- } catch {
538
- return "";
539
- }
675
+ try {
676
+ const content = fs.readFileSync(filePath, "utf8");
677
+ return redactSensitiveDiagnostics(content.slice(-maxChars));
678
+ } catch {
679
+ return "";
680
+ }
540
681
  }
541
682
 
542
683
  function writeStartupDiagnosticsSnapshot(
543
- snapshot: StartupDiagnosticsSnapshot,
684
+ snapshot: StartupDiagnosticsSnapshot,
544
685
  ): void {
545
- try {
546
- fs.writeFileSync(
547
- getStartupStatusPath(),
548
- `${JSON.stringify(snapshot, null, 2)}\n`,
549
- "utf8",
550
- );
551
- } catch {
552
- // Ignore write errors
553
- }
686
+ try {
687
+ fs.writeFileSync(
688
+ getStartupStatusPath(),
689
+ `${JSON.stringify(snapshot, null, 2)}\n`,
690
+ "utf8",
691
+ );
692
+ } catch {
693
+ // Ignore write errors
694
+ }
554
695
  }
555
696
 
556
697
  export function getStartupDiagnosticsSnapshot(): StartupDiagnosticsSnapshot {
557
- let parsed: Partial<StartupDiagnosticsSnapshot> | null = null;
558
- try {
559
- parsed = JSON.parse(
560
- fs.readFileSync(getStartupStatusPath(), "utf8"),
561
- ) as Partial<StartupDiagnosticsSnapshot> | null;
562
- } catch {
563
- parsed = null;
564
- }
565
-
566
- return {
567
- state: parsed?.state ?? "not_started",
568
- phase: parsed?.phase ?? "unknown",
569
- updatedAt: parsed?.updatedAt ?? new Date().toISOString(),
570
- lastError: parsed?.lastError ?? null,
571
- agentName: parsed?.agentName ?? null,
572
- port: parsed?.port ?? null,
573
- startedAt: parsed?.startedAt ?? null,
574
- platform: parsed?.platform ?? process.platform,
575
- arch: parsed?.arch ?? process.arch,
576
- configDir: parsed?.configDir ?? resolveConfigDir(),
577
- logPath: parsed?.logPath ?? getDiagnosticLogPath(),
578
- statusPath: parsed?.statusPath ?? getStartupStatusPath(),
579
- };
698
+ let parsed: Partial<StartupDiagnosticsSnapshot> | null = null;
699
+ try {
700
+ parsed = JSON.parse(
701
+ fs.readFileSync(getStartupStatusPath(), "utf8"),
702
+ ) as Partial<StartupDiagnosticsSnapshot> | null;
703
+ } catch {
704
+ parsed = null;
705
+ }
706
+
707
+ return {
708
+ state: parsed?.state ?? "not_started",
709
+ phase: parsed?.phase ?? "unknown",
710
+ updatedAt: parsed?.updatedAt ?? new Date().toISOString(),
711
+ lastError: parsed?.lastError ?? null,
712
+ agentName: parsed?.agentName ?? null,
713
+ port: parsed?.port ?? null,
714
+ startedAt: parsed?.startedAt ?? null,
715
+ platform: parsed?.platform ?? process.platform,
716
+ arch: parsed?.arch ?? process.arch,
717
+ configDir: parsed?.configDir ?? resolveConfigDir(),
718
+ logPath: parsed?.logPath ?? getDiagnosticLogPath(),
719
+ statusPath: parsed?.statusPath ?? getStartupStatusPath(),
720
+ database: parsed?.database ?? createUnknownDatabaseSnapshot(),
721
+ };
580
722
  }
581
723
 
582
724
  export function getStartupDiagnosticLogTail(maxChars = 16_000): string {
583
- return readFileTail(getDiagnosticLogPath(), maxChars);
725
+ return readFileTail(getDiagnosticLogPath(), maxChars);
584
726
  }
585
727
 
586
728
  function sanitizeBugReportPrefix(prefix: string | undefined): string {
587
- const trimmed = prefix?.trim();
588
- if (!trimmed) return "bug-report";
589
-
590
- const sanitized = trimmed
591
- .replace(/[\\/]+/g, "-")
592
- .replace(/\.\.+/g, "-")
593
- .replace(/[^a-zA-Z0-9._-]+/g, "-")
594
- .replace(/-+/g, "-")
595
- .replace(/^[._-]+|[._-]+$/g, "")
596
- .slice(0, 64);
597
-
598
- return sanitized || "bug-report";
729
+ const trimmed = prefix?.trim();
730
+ if (!trimmed) return "bug-report";
731
+
732
+ const sanitized = trimmed
733
+ .replace(/[\\/]+/g, "-")
734
+ .replace(/\.\.+/g, "-")
735
+ .replace(/[^a-zA-Z0-9._-]+/g, "-")
736
+ .replace(/-+/g, "-")
737
+ .replace(/^[._-]+|[._-]+$/g, "")
738
+ .slice(0, 64);
739
+
740
+ return sanitized || "bug-report";
599
741
  }
600
742
  export function createBugReportBundle(options: {
601
- reportMarkdown: string;
602
- reportJson: Record<string, unknown>;
603
- prefix?: string;
743
+ reportMarkdown: string;
744
+ reportJson: Record<string, unknown>;
745
+ prefix?: string;
604
746
  }): BugReportBundleResult {
605
- const configDir = resolveConfigDir();
606
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
607
- const prefix = sanitizeBugReportPrefix(options.prefix);
608
- const directory = path.join(
609
- configDir,
610
- "bug-reports",
611
- `${prefix}-${timestamp}`,
612
- );
613
- const reportMarkdownPath = path.join(directory, "report.md");
614
- const reportJsonPath = path.join(directory, "report.json");
615
- const logPath = getDiagnosticLogPath();
616
- const statusPath = getStartupStatusPath();
617
- const startupLogTarget = path.join(
618
- directory,
619
- getBrandConfig().startupLogFileName,
620
- );
621
- const startupStatusTarget = path.join(directory, "startup-status.json");
622
- const startupDiagnostics = getStartupDiagnosticsSnapshot();
623
- const includeLogTail =
624
- typeof options.reportJson.attachLogs === "boolean"
625
- ? options.reportJson.attachLogs
626
- : true;
627
- const startupLogTail = includeLogTail ? getStartupDiagnosticLogTail() : "";
628
- const normalizedReportJson = {
629
- ...options.reportJson,
630
- startupDiagnostics,
631
- startupLogTail,
632
- };
633
-
634
- fs.mkdirSync(directory, { recursive: true });
635
- fs.writeFileSync(reportMarkdownPath, options.reportMarkdown, "utf8");
636
- fs.writeFileSync(
637
- reportJsonPath,
638
- `${JSON.stringify(normalizedReportJson, null, 2)}\n`,
639
- "utf8",
640
- );
641
-
642
- let copiedLogPath: string | null = null;
643
- let copiedStatusPath: string | null = null;
644
-
645
- if (fs.existsSync(logPath)) {
646
- fs.copyFileSync(logPath, startupLogTarget);
647
- copiedLogPath = startupLogTarget;
648
- }
649
- if (fs.existsSync(statusPath)) {
650
- fs.copyFileSync(statusPath, startupStatusTarget);
651
- copiedStatusPath = startupStatusTarget;
652
- }
653
-
654
- return {
655
- directory,
656
- reportMarkdownPath,
657
- reportJsonPath,
658
- startupLogPath: copiedLogPath,
659
- startupStatusPath: copiedStatusPath,
660
- };
747
+ const configDir = resolveConfigDir();
748
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
749
+ const prefix = sanitizeBugReportPrefix(options.prefix);
750
+ const directory = path.join(
751
+ configDir,
752
+ "bug-reports",
753
+ `${prefix}-${timestamp}`,
754
+ );
755
+ const reportMarkdownPath = path.join(directory, "report.md");
756
+ const reportJsonPath = path.join(directory, "report.json");
757
+ const logPath = getDiagnosticLogPath();
758
+ const statusPath = getStartupStatusPath();
759
+ const startupLogTarget = path.join(
760
+ directory,
761
+ getBrandConfig().startupLogFileName,
762
+ );
763
+ const startupStatusTarget = path.join(directory, "startup-status.json");
764
+ const startupDiagnostics = getStartupDiagnosticsSnapshot();
765
+ const includeLogTail =
766
+ typeof options.reportJson.attachLogs === "boolean"
767
+ ? options.reportJson.attachLogs
768
+ : true;
769
+ const startupLogTail = includeLogTail ? getStartupDiagnosticLogTail() : "";
770
+ const normalizedReportJson = {
771
+ ...options.reportJson,
772
+ startupDiagnostics,
773
+ startupLogTail,
774
+ };
775
+
776
+ fs.mkdirSync(directory, { recursive: true });
777
+ fs.writeFileSync(reportMarkdownPath, options.reportMarkdown, "utf8");
778
+ fs.writeFileSync(
779
+ reportJsonPath,
780
+ `${JSON.stringify(normalizedReportJson, null, 2)}\n`,
781
+ "utf8",
782
+ );
783
+
784
+ let copiedLogPath: string | null = null;
785
+ let copiedStatusPath: string | null = null;
786
+
787
+ if (fs.existsSync(logPath)) {
788
+ fs.copyFileSync(logPath, startupLogTarget);
789
+ copiedLogPath = startupLogTarget;
790
+ }
791
+ if (fs.existsSync(statusPath)) {
792
+ fs.copyFileSync(statusPath, startupStatusTarget);
793
+ copiedStatusPath = startupStatusTarget;
794
+ }
795
+
796
+ return {
797
+ directory,
798
+ reportMarkdownPath,
799
+ reportJsonPath,
800
+ startupLogPath: copiedLogPath,
801
+ startupStatusPath: copiedStatusPath,
802
+ };
661
803
  }
662
804
 
663
805
  // ---------------------------------------------------------------------------
@@ -672,255 +814,260 @@ export function createBugReportBundle(options: {
672
814
  * 2. Walk up from import.meta.dir to find the runtime dist dir as a sibling
673
815
  */
674
816
  export function getRuntimeDistFallbackCandidates(
675
- moduleDir: string = getDefaultModuleDir(),
676
- execPath: string = process.execPath,
817
+ moduleDir: string = getDefaultModuleDir(),
818
+ execPath: string = process.execPath,
677
819
  ): string[] {
678
- const execDir = execPath ? dirnamePortable(execPath) : moduleDir;
679
- const distDir = getBrandConfig().runtimeDistDirName;
680
-
681
- return [
682
- // macOS: inside .app bundle (Contents/Resources/app/<dist>)
683
- resolveRelativePortable(execDir, `../Resources/app/${distDir}`),
684
- // Windows NSIS/portable: resources/app/<dist> next to exe
685
- resolveRelativePortable(execDir, `resources/app/${distDir}`),
686
- resolveRelativePortable(execDir, `../resources/app/${distDir}`),
687
- resolveRelativePortable(moduleDir, `app/${distDir}`),
688
- resolveRelativePortable(moduleDir, `../${distDir}`),
689
- resolveRelativePortable(moduleDir, `../app/${distDir}`),
690
- resolveRelativePortable(moduleDir, `../../../${distDir}`),
691
- // Legacy eliza-dist fallback for existing packaged builds
692
- resolveRelativePortable(execDir, "../Resources/app/eliza-dist"),
693
- resolveRelativePortable(execDir, "resources/app/eliza-dist"),
694
- resolveRelativePortable(moduleDir, "../eliza-dist"),
695
- resolveRelativePortable(moduleDir, "../../../eliza-dist"),
696
- ].filter((candidate, index, all) => all.indexOf(candidate) === index);
820
+ const execDir = execPath ? dirnamePortable(execPath) : moduleDir;
821
+ const distDir = getBrandConfig().runtimeDistDirName;
822
+
823
+ return [
824
+ // macOS: inside .app bundle (Contents/Resources/app/<dist>)
825
+ resolveRelativePortable(execDir, `../Resources/app/${distDir}`),
826
+ // Windows NSIS/portable: resources/app/<dist> next to exe
827
+ resolveRelativePortable(execDir, `resources/app/${distDir}`),
828
+ resolveRelativePortable(execDir, `../resources/app/${distDir}`),
829
+ resolveRelativePortable(moduleDir, `app/${distDir}`),
830
+ resolveRelativePortable(moduleDir, `../${distDir}`),
831
+ resolveRelativePortable(moduleDir, `../app/${distDir}`),
832
+ resolveRelativePortable(moduleDir, `../../../${distDir}`),
833
+ // Legacy eliza-dist fallback for existing packaged builds
834
+ resolveRelativePortable(execDir, "../Resources/app/eliza-dist"),
835
+ resolveRelativePortable(execDir, "resources/app/eliza-dist"),
836
+ resolveRelativePortable(moduleDir, "../eliza-dist"),
837
+ resolveRelativePortable(moduleDir, "../../../eliza-dist"),
838
+ ].filter((candidate, index, all) => all.indexOf(candidate) === index);
697
839
  }
698
840
 
699
841
  export function isPackagedDesktopRuntime(
700
- moduleDir: string = getDefaultModuleDir(),
701
- execPath: string = process.execPath,
842
+ moduleDir: string = getDefaultModuleDir(),
843
+ execPath: string = process.execPath,
702
844
  ): boolean {
703
- const normalizedModuleDir = moduleDir.replaceAll("\\", "/");
704
- const normalizedExecPath = execPath.replaceAll("\\", "/").toLowerCase();
705
- const looksLikePackagedExec =
706
- normalizedExecPath.includes(".app/contents/") ||
707
- normalizedExecPath.includes("/self-extraction/") ||
708
- normalizedExecPath.endsWith("/launcher") ||
709
- normalizedExecPath.endsWith("/launcher.exe");
710
- if (process.env.ELIZA_DIST_PATH?.trim() && !looksLikePackagedExec) {
711
- return false;
712
- }
713
- if (!normalizedModuleDir.includes("/src/")) {
714
- return true;
715
- }
716
-
717
- return looksLikePackagedExec;
845
+ const normalizedModuleDir = moduleDir.replaceAll("\\", "/");
846
+ const normalizedExecPath = execPath.replaceAll("\\", "/").toLowerCase();
847
+ const looksLikePackagedExec =
848
+ normalizedExecPath.includes(".app/contents/") ||
849
+ normalizedExecPath.includes("/self-extraction/") ||
850
+ normalizedExecPath.endsWith("/launcher") ||
851
+ normalizedExecPath.endsWith("/launcher.exe");
852
+ if (process.env.ELIZA_DIST_PATH?.trim() && !looksLikePackagedExec) {
853
+ return false;
854
+ }
855
+ if (!normalizedModuleDir.includes("/src/")) {
856
+ return true;
857
+ }
858
+
859
+ return looksLikePackagedExec;
718
860
  }
719
861
 
720
862
  export function resolveBunExecutablePath(opts?: {
721
- execPath?: string;
722
- moduleDir?: string;
723
- platform?: string;
863
+ execPath?: string;
864
+ moduleDir?: string;
865
+ platform?: string;
724
866
  }): string {
725
- const execPath = opts?.execPath ?? process.execPath;
726
- const moduleDir = opts?.moduleDir ?? getDefaultModuleDir();
727
- const platform = opts?.platform ?? process.platform;
728
- const packagedRuntime = isPackagedDesktopRuntime(moduleDir, execPath);
729
- const looksLikeMacBundleExec = execPath.includes(".app/Contents/MacOS/");
730
- const executableName =
731
- platform === "win32" && !looksLikeMacBundleExec ? "bun.exe" : "bun";
732
- const execDir = execPath ? dirnamePortable(execPath) : "";
733
- const packagedCandidates = [
734
- execPath,
735
- execDir ? joinPortable(execDir, executableName) : "",
736
- execDir
737
- ? resolveRelativePortable(
738
- execDir,
739
- `../Resources/app/bun/${executableName}`,
740
- )
741
- : "",
742
- execDir
743
- ? resolveRelativePortable(
744
- execDir,
745
- `../Resources/app/bun/bin/${executableName}`,
746
- )
747
- : "",
748
- moduleDir ? joinPortable(moduleDir, executableName) : "",
749
- moduleDir ? joinPortable(moduleDir, "bin", executableName) : "",
750
- moduleDir
751
- ? resolveRelativePortable(moduleDir, `../bun/${executableName}`)
752
- : "",
753
- moduleDir
754
- ? resolveRelativePortable(moduleDir, `../bun/bin/${executableName}`)
755
- : "",
756
- ].filter(Boolean);
757
-
758
- for (const candidate of packagedCandidates) {
759
- if (!fs.existsSync(candidate)) continue;
760
- if (
761
- path.basename(candidate).toLowerCase() === executableName.toLowerCase()
762
- ) {
763
- return candidate;
764
- }
765
- }
766
-
767
- if (packagedRuntime) {
768
- return (
769
- packagedCandidates.find(
770
- (candidate) =>
771
- path.basename(candidate).toLowerCase() ===
772
- executableName.toLowerCase(),
773
- ) ?? executableName
774
- );
775
- }
776
-
777
- const _candidates = [
778
- execPath,
779
- execDir ? joinPortable(execDir, executableName) : "",
780
- ].filter(Boolean);
781
-
782
- const bunGlobal = Bun as { which?: (binary: string) => string | null };
783
- const whichCandidate =
784
- typeof bunGlobal.which === "function" ? bunGlobal.which("bun") : null;
785
- if (whichCandidate) return whichCandidate;
786
-
787
- // Windows: bun is not always on PATH; check well-known install locations.
788
- if (process.platform === "win32") {
789
- const localAppData =
790
- process.env.LOCALAPPDATA ??
791
- joinPortable(os.homedir(), "AppData", "Local");
792
- const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
793
- const winCandidates = [
794
- joinPortable(localAppData, "bun", "bun.exe"),
795
- joinPortable(programFiles, "bun", "bun.exe"),
796
- joinPortable(os.homedir(), ".bun", "bin", "bun.exe"),
797
- ];
798
- for (const candidate of winCandidates) {
799
- if (fs.existsSync(candidate)) return candidate;
800
- }
801
- }
802
-
803
- return "bun";
867
+ const execPath = opts?.execPath ?? process.execPath;
868
+ const moduleDir = opts?.moduleDir ?? getDefaultModuleDir();
869
+ const platform = opts?.platform ?? process.platform;
870
+ const packagedRuntime = isPackagedDesktopRuntime(moduleDir, execPath);
871
+ const looksLikeMacBundleExec = execPath.includes(".app/Contents/MacOS/");
872
+ const executableName =
873
+ platform === "win32" && !looksLikeMacBundleExec ? "bun.exe" : "bun";
874
+ const execDir = execPath ? dirnamePortable(execPath) : "";
875
+ const packagedCandidates = [
876
+ execPath,
877
+ execDir ? joinPortable(execDir, executableName) : "",
878
+ execDir
879
+ ? resolveRelativePortable(
880
+ execDir,
881
+ `../Resources/app/bun/${executableName}`,
882
+ )
883
+ : "",
884
+ execDir
885
+ ? resolveRelativePortable(
886
+ execDir,
887
+ `../Resources/app/bun/bin/${executableName}`,
888
+ )
889
+ : "",
890
+ moduleDir ? joinPortable(moduleDir, executableName) : "",
891
+ moduleDir ? joinPortable(moduleDir, "bin", executableName) : "",
892
+ moduleDir
893
+ ? resolveRelativePortable(moduleDir, `../bun/${executableName}`)
894
+ : "",
895
+ moduleDir
896
+ ? resolveRelativePortable(moduleDir, `../bun/bin/${executableName}`)
897
+ : "",
898
+ ].filter(Boolean);
899
+
900
+ for (const candidate of packagedCandidates) {
901
+ if (!fs.existsSync(candidate)) continue;
902
+ if (
903
+ path.basename(candidate).toLowerCase() === executableName.toLowerCase()
904
+ ) {
905
+ return candidate;
906
+ }
907
+ }
908
+
909
+ if (packagedRuntime) {
910
+ return (
911
+ packagedCandidates.find(
912
+ (candidate) =>
913
+ path.basename(candidate).toLowerCase() ===
914
+ executableName.toLowerCase(),
915
+ ) ?? executableName
916
+ );
917
+ }
918
+
919
+ const _candidates = [
920
+ execPath,
921
+ execDir ? joinPortable(execDir, executableName) : "",
922
+ ].filter(Boolean);
923
+
924
+ const bunGlobal = Bun as { which?: (binary: string) => string | null };
925
+ const whichCandidate =
926
+ typeof bunGlobal.which === "function" ? bunGlobal.which("bun") : null;
927
+ if (whichCandidate) return whichCandidate;
928
+
929
+ // Windows: bun is not always on PATH; check well-known install locations.
930
+ if (process.platform === "win32") {
931
+ const localAppData =
932
+ process.env.LOCALAPPDATA ??
933
+ joinPortable(os.homedir(), "AppData", "Local");
934
+ const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
935
+ const winCandidates = [
936
+ joinPortable(localAppData, "bun", "bun.exe"),
937
+ joinPortable(programFiles, "bun", "bun.exe"),
938
+ joinPortable(os.homedir(), ".bun", "bin", "bun.exe"),
939
+ ];
940
+ for (const candidate of winCandidates) {
941
+ if (fs.existsSync(candidate)) return candidate;
942
+ }
943
+ }
944
+
945
+ return "bun";
804
946
  }
805
947
 
806
948
  export function resolveRuntimeDistPath(opts?: {
807
- env?: NodeJS.ProcessEnv;
808
- moduleDir?: string;
809
- execPath?: string;
949
+ env?: NodeJS.ProcessEnv;
950
+ moduleDir?: string;
951
+ execPath?: string;
810
952
  }): string {
811
- const env = opts?.env ?? process.env;
812
- const moduleDir = opts?.moduleDir ?? getDefaultModuleDir();
813
- const execPath = opts?.execPath ?? process.execPath;
814
- const packagedRuntime = isPackagedDesktopRuntime(moduleDir, execPath);
815
- const distDir = getBrandConfig().runtimeDistDirName;
816
- const fallbackCandidates = getRuntimeDistFallbackCandidates(
817
- moduleDir,
818
- execPath,
819
- );
820
-
821
- if (packagedRuntime) {
822
- for (const candidate of fallbackCandidates) {
823
- if (fs.existsSync(candidate)) {
824
- return candidate;
825
- }
826
- }
827
- const fallback = fallbackCandidates[0];
828
- diagnosticLog(
829
- `[Agent] Could not find packaged runtime dist; using fallback: ${fallback}`,
830
- );
831
- return fallback;
832
- }
833
-
834
- // 1. Env override
835
- const envPath = env.ELIZA_DIST_PATH;
836
- if (envPath) {
837
- const resolved = resolvePortablePath(envPath);
838
- if (fs.existsSync(resolved)) {
839
- return resolved;
840
- }
841
- diagnosticLog(
842
- `[Agent] ELIZA_DIST_PATH set but does not exist: ${resolved}`,
843
- );
844
- }
845
-
846
- // 2. Walk up from import.meta.dir looking for runtime dist or dev dist
847
- let dir = moduleDir;
848
- const maxDepth = 15;
849
- for (let i = 0; i < maxDepth; i++) {
850
- // Packaged: runtime dist sibling
851
- const runtimeDist = joinPortable(dir, distDir);
852
- if (fs.existsSync(runtimeDist)) {
853
- return runtimeDist;
854
- }
855
- // Legacy eliza-dist sibling (existing packaged builds)
856
- const legacyDist = joinPortable(dir, "eliza-dist");
857
- if (fs.existsSync(legacyDist)) {
858
- return legacyDist;
859
- }
860
- // Dev monorepo: dist/ sibling containing the canonical CLI entrypoint
861
- const devDist = joinPortable(dir, "dist");
862
- if (fs.existsSync(joinPortable(devDist, "entry.js"))) {
863
- return devDist;
864
- }
865
- const parent = dirnamePortable(dir);
866
- if (parent === dir) break; // reached filesystem root
867
- dir = parent;
868
- }
869
-
870
- // 3. Packaged/dev fallbacks derived from the launcher path and module dir.
871
- for (const candidate of fallbackCandidates) {
872
- if (fs.existsSync(candidate)) {
873
- diagnosticLog(
874
- `[Agent] Could not find runtime dist by walking up; using fallback: ${candidate}`,
875
- );
876
- return candidate;
877
- }
878
- }
879
-
880
- const fallback = fallbackCandidates[0];
881
- diagnosticLog(
882
- `[Agent] Could not find runtime dist by walking up; using fallback: ${fallback}`,
883
- );
884
- return fallback;
953
+ const env = opts?.env ?? process.env;
954
+ const moduleDir = opts?.moduleDir ?? getDefaultModuleDir();
955
+ const execPath = opts?.execPath ?? process.execPath;
956
+ const packagedRuntime = isPackagedDesktopRuntime(moduleDir, execPath);
957
+ const distDir = getBrandConfig().runtimeDistDirName;
958
+ const fallbackCandidates = getRuntimeDistFallbackCandidates(
959
+ moduleDir,
960
+ execPath,
961
+ );
962
+
963
+ if (packagedRuntime) {
964
+ for (const candidate of fallbackCandidates) {
965
+ if (fs.existsSync(candidate)) {
966
+ return candidate;
967
+ }
968
+ }
969
+ const fallback = fallbackCandidates[0];
970
+ diagnosticLog(
971
+ `[Agent] Could not find packaged runtime dist; using fallback: ${fallback}`,
972
+ );
973
+ return fallback;
974
+ }
975
+
976
+ // 1. Env override
977
+ const envPath = env.ELIZA_DIST_PATH;
978
+ if (envPath) {
979
+ const resolved = resolvePortablePath(envPath);
980
+ if (fs.existsSync(resolved)) {
981
+ return resolved;
982
+ }
983
+ diagnosticLog(
984
+ `[Agent] ELIZA_DIST_PATH set but does not exist: ${resolved}`,
985
+ );
986
+ }
987
+
988
+ // 2. Walk up from import.meta.dir looking for runtime dist or dev dist
989
+ let dir = moduleDir;
990
+ const maxDepth = 15;
991
+ for (let i = 0; i < maxDepth; i++) {
992
+ // Packaged: runtime dist sibling
993
+ const runtimeDist = joinPortable(dir, distDir);
994
+ if (fs.existsSync(runtimeDist)) {
995
+ return runtimeDist;
996
+ }
997
+ // Legacy eliza-dist sibling (existing packaged builds)
998
+ const legacyDist = joinPortable(dir, "eliza-dist");
999
+ if (fs.existsSync(legacyDist)) {
1000
+ return legacyDist;
1001
+ }
1002
+ // Dev monorepo: dist/ sibling containing the canonical CLI entrypoint
1003
+ const devDist = joinPortable(dir, "dist");
1004
+ if (fs.existsSync(joinPortable(devDist, "entry.js"))) {
1005
+ return devDist;
1006
+ }
1007
+ const parent = dirnamePortable(dir);
1008
+ if (parent === dir) break; // reached filesystem root
1009
+ dir = parent;
1010
+ }
1011
+
1012
+ // 3. Packaged/dev fallbacks derived from the launcher path and module dir.
1013
+ for (const candidate of fallbackCandidates) {
1014
+ if (fs.existsSync(candidate)) {
1015
+ diagnosticLog(
1016
+ `[Agent] Could not find runtime dist by walking up; using fallback: ${candidate}`,
1017
+ );
1018
+ return candidate;
1019
+ }
1020
+ }
1021
+
1022
+ const fallback = fallbackCandidates[0];
1023
+ diagnosticLog(
1024
+ `[Agent] Could not find runtime dist by walking up; using fallback: ${fallback}`,
1025
+ );
1026
+ return fallback;
885
1027
  }
886
1028
 
887
1029
  export function buildChildNodePaths(
888
- runtimeDistPath: string,
889
- opts?: { packagedRuntime?: boolean },
1030
+ runtimeDistPath: string,
1031
+ opts?: { packagedRuntime?: boolean },
890
1032
  ): string[] {
891
- const nodePaths = new Set<string>();
892
- const distModules = joinPortable(runtimeDistPath, "node_modules");
893
- if (fs.existsSync(distModules)) {
894
- nodePaths.add(distModules);
895
- }
896
-
897
- if (opts?.packagedRuntime) {
898
- return [...nodePaths];
899
- }
900
-
901
- let searchDir = runtimeDistPath;
902
- while (searchDir !== dirnamePortable(searchDir)) {
903
- const candidate = joinPortable(searchDir, "node_modules");
904
- if (fs.existsSync(candidate) && candidate !== distModules) {
905
- nodePaths.add(candidate);
906
- break;
907
- }
908
- searchDir = dirnamePortable(searchDir);
909
- }
910
-
911
- return [...nodePaths];
1033
+ const nodePaths = new Set<string>();
1034
+ const distModules = joinPortable(runtimeDistPath, "node_modules");
1035
+ if (fs.existsSync(distModules)) {
1036
+ nodePaths.add(distModules);
1037
+ }
1038
+
1039
+ if (opts?.packagedRuntime) {
1040
+ return [...nodePaths];
1041
+ }
1042
+
1043
+ let searchDir = runtimeDistPath;
1044
+ while (searchDir !== dirnamePortable(searchDir)) {
1045
+ const candidate = joinPortable(searchDir, "node_modules");
1046
+ if (fs.existsSync(candidate) && candidate !== distModules) {
1047
+ nodePaths.add(candidate);
1048
+ break;
1049
+ }
1050
+ searchDir = dirnamePortable(searchDir);
1051
+ }
1052
+
1053
+ return [...nodePaths];
912
1054
  }
913
1055
 
914
- function resolveRuntimeEntryPath(runtimeDistPath: string): string | null {
915
- const candidates = [joinPortable(runtimeDistPath, "entry.js")];
916
-
917
- for (const candidate of candidates) {
918
- if (fs.existsSync(candidate)) {
919
- return candidate;
920
- }
921
- }
922
-
923
- return null;
1056
+ export function resolveRuntimeEntryPath(
1057
+ runtimeDistPath: string,
1058
+ ): string | null {
1059
+ const candidates = [
1060
+ joinPortable(runtimeDistPath, "entry.js"),
1061
+ joinPortable(runtimeDistPath, "runtime", "entry.js"),
1062
+ ];
1063
+
1064
+ for (const candidate of candidates) {
1065
+ if (fs.existsSync(candidate)) {
1066
+ return candidate;
1067
+ }
1068
+ }
1069
+
1070
+ return null;
924
1071
  }
925
1072
 
926
1073
  // ---------------------------------------------------------------------------
@@ -928,52 +1075,97 @@ function resolveRuntimeEntryPath(runtimeDistPath: string): string | null {
928
1075
  // ---------------------------------------------------------------------------
929
1076
 
930
1077
  async function waitForHealthy(
931
- getPort: () => number,
932
- timeoutMs: number = getHealthPollTimeoutMs(),
933
- childProcess?: BunSubprocess | null,
1078
+ getPort: () => number,
1079
+ timeoutMs: number = getHealthPollTimeoutMs(),
1080
+ childProcess?: BunSubprocess | null,
1081
+ ): Promise<boolean> {
1082
+ const deadline = Date.now() + timeoutMs;
1083
+ const headers = getDesktopApiHeaders();
1084
+
1085
+ while (Date.now() < deadline) {
1086
+ // Bail early if the child process has already exited
1087
+ if (childProcess && childProcess.exitCode !== null) {
1088
+ return false;
1089
+ }
1090
+
1091
+ const port = getPort();
1092
+ const url = `http://127.0.0.1:${port}/api/health`;
1093
+ try {
1094
+ const response = await fetch(url, {
1095
+ headers,
1096
+ signal: AbortSignal.timeout(2_000),
1097
+ });
1098
+ if (response.ok) {
1099
+ const health = (await response.json().catch(() => null)) as {
1100
+ ready?: boolean;
1101
+ agentState?: string;
1102
+ startup?: { phase?: string };
1103
+ } | null;
1104
+ if (!health) {
1105
+ return true;
1106
+ }
1107
+ if (typeof health.ready === "boolean") {
1108
+ if (health.ready) {
1109
+ return true;
1110
+ }
1111
+ } else if (
1112
+ health.agentState !== "starting" &&
1113
+ health.agentState !== "restarting"
1114
+ ) {
1115
+ return true;
1116
+ }
1117
+ }
1118
+ if (await isStartupStatusReachable(port, headers)) {
1119
+ return true;
1120
+ }
1121
+ } catch {
1122
+ if (await isStartupStatusReachable(port, headers)) {
1123
+ return true;
1124
+ }
1125
+ }
1126
+ await Bun.sleep(HEALTH_POLL_INTERVAL_MS);
1127
+ }
1128
+ return false;
1129
+ }
1130
+
1131
+ function isRecord(value: unknown): value is Record<string, unknown> {
1132
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1133
+ }
1134
+
1135
+ function isNonFatalStartupStatus(value: unknown): boolean {
1136
+ if (!isRecord(value)) return false;
1137
+ const startup = value.startup;
1138
+ if (!isRecord(startup)) return false;
1139
+ const phase = startup.phase;
1140
+ if (
1141
+ phase === "fatal" ||
1142
+ phase === "startup_failed" ||
1143
+ phase === "runtime_entry_missing"
1144
+ ) {
1145
+ return false;
1146
+ }
1147
+ return (
1148
+ typeof phase === "string" ||
1149
+ typeof startup.embeddingPhase === "string" ||
1150
+ typeof startup.embeddingDetail === "string"
1151
+ );
1152
+ }
1153
+
1154
+ async function isStartupStatusReachable(
1155
+ port: number,
1156
+ headers: Record<string, string> | undefined,
934
1157
  ): Promise<boolean> {
935
- const deadline = Date.now() + timeoutMs;
936
- const headers = getDesktopApiHeaders();
937
-
938
- while (Date.now() < deadline) {
939
- // Bail early if the child process has already exited
940
- if (childProcess && childProcess.exitCode !== null) {
941
- return false;
942
- }
943
-
944
- const port = getPort();
945
- const url = `http://127.0.0.1:${port}/api/health`;
946
- try {
947
- const response = await fetch(url, {
948
- headers,
949
- signal: AbortSignal.timeout(2_000),
950
- });
951
- if (response.ok) {
952
- const health = (await response.json().catch(() => null)) as {
953
- ready?: boolean;
954
- agentState?: string;
955
- startup?: { phase?: string };
956
- } | null;
957
- if (!health) {
958
- return true;
959
- }
960
- if (typeof health.ready === "boolean") {
961
- if (health.ready) {
962
- return true;
963
- }
964
- } else if (
965
- health.agentState !== "starting" &&
966
- health.agentState !== "restarting"
967
- ) {
968
- return true;
969
- }
970
- }
971
- } catch {
972
- // Server not ready yet
973
- }
974
- await Bun.sleep(HEALTH_POLL_INTERVAL_MS);
975
- }
976
- return false;
1158
+ try {
1159
+ const response = await fetch(`http://127.0.0.1:${port}/api/status`, {
1160
+ headers,
1161
+ signal: AbortSignal.timeout(2_000),
1162
+ });
1163
+ const body = await response.json().catch(() => null);
1164
+ if (response.ok) return true;
1165
+ return isNonFatalStartupStatus(body);
1166
+ } catch {
1167
+ return false;
1168
+ }
977
1169
  }
978
1170
 
979
1171
  // ---------------------------------------------------------------------------
@@ -981,171 +1173,154 @@ async function waitForHealthy(
981
1173
  // ---------------------------------------------------------------------------
982
1174
 
983
1175
  async function watchStdoutForReady(
984
- stream: ReadableStream<Uint8Array>,
985
- onLine: (line: string) => void,
986
- signal: AbortSignal,
1176
+ stream: ReadableStream<Uint8Array>,
1177
+ onLine: (line: string) => void,
1178
+ signal: AbortSignal,
987
1179
  ): Promise<void> {
988
- const decoder = new TextDecoder();
989
- let buffer = "";
990
-
991
- try {
992
- const reader = stream.getReader();
993
- while (!signal.aborted) {
994
- const { done, value } = await reader.read();
995
- if (done) break;
996
-
997
- buffer += decoder.decode(value, { stream: true });
998
- const lines = buffer.split("\n");
999
- buffer = lines.pop() ?? "";
1000
-
1001
- for (const line of lines) {
1002
- if (line.trim()) {
1003
- onLine(line);
1004
- }
1005
- }
1006
- }
1007
- // Flush remaining buffer
1008
- if (buffer.trim()) {
1009
- onLine(buffer);
1010
- }
1011
- reader.releaseLock();
1012
- } catch (err) {
1013
- if (!signal.aborted) {
1014
- diagnosticLog(
1015
- `[Agent] stdout watcher error: ${err instanceof Error ? err.message : String(err)}`,
1016
- );
1017
- }
1018
- }
1180
+ const decoder = new TextDecoder();
1181
+ let buffer = "";
1182
+
1183
+ try {
1184
+ const reader = stream.getReader();
1185
+ while (!signal.aborted) {
1186
+ const { done, value } = await reader.read();
1187
+ if (done) break;
1188
+
1189
+ buffer += decoder.decode(value, { stream: true });
1190
+ const lines = buffer.split("\n");
1191
+ buffer = lines.pop() ?? "";
1192
+
1193
+ for (const line of lines) {
1194
+ if (line.trim()) {
1195
+ onLine(line);
1196
+ }
1197
+ }
1198
+ }
1199
+ // Flush remaining buffer
1200
+ if (buffer.trim()) {
1201
+ onLine(buffer);
1202
+ }
1203
+ reader.releaseLock();
1204
+ } catch (err) {
1205
+ if (!signal.aborted) {
1206
+ diagnosticLog(
1207
+ `[Agent] stdout watcher error: ${err instanceof Error ? err.message : String(err)}`,
1208
+ );
1209
+ }
1210
+ }
1019
1211
  }
1020
1212
 
1021
1213
  async function drainStderrToLog(
1022
- stream: ReadableStream<Uint8Array>,
1023
- signal: AbortSignal,
1024
- onLine?: (line: string) => void,
1214
+ stream: ReadableStream<Uint8Array>,
1215
+ signal: AbortSignal,
1216
+ onLine?: (line: string) => void,
1025
1217
  ): Promise<void> {
1026
- const decoder = new TextDecoder();
1027
- let buffer = "";
1028
-
1029
- try {
1030
- const reader = stream.getReader();
1031
- while (!signal.aborted) {
1032
- const { done, value } = await reader.read();
1033
- if (done) break;
1034
-
1035
- buffer += decoder.decode(value, { stream: true });
1036
- const lines = buffer.split("\n");
1037
- buffer = lines.pop() ?? "";
1038
-
1039
- for (const line of lines) {
1040
- if (line.trim()) {
1041
- diagnosticLog(`[Agent][stderr] ${line}`);
1042
- onLine?.(line);
1043
- }
1044
- }
1045
- }
1046
- if (buffer.trim()) {
1047
- diagnosticLog(`[Agent][stderr] ${buffer}`);
1048
- onLine?.(buffer);
1049
- }
1050
- reader.releaseLock();
1051
- } catch (err) {
1052
- if (!signal.aborted) {
1053
- diagnosticLog(
1054
- `[Agent] stderr drain error: ${err instanceof Error ? err.message : String(err)}`,
1055
- );
1056
- }
1057
- }
1218
+ const decoder = new TextDecoder();
1219
+ let buffer = "";
1220
+
1221
+ try {
1222
+ const reader = stream.getReader();
1223
+ while (!signal.aborted) {
1224
+ const { done, value } = await reader.read();
1225
+ if (done) break;
1226
+
1227
+ buffer += decoder.decode(value, { stream: true });
1228
+ const lines = buffer.split("\n");
1229
+ buffer = lines.pop() ?? "";
1230
+
1231
+ for (const line of lines) {
1232
+ if (line.trim()) {
1233
+ diagnosticLog(`[Agent][stderr] ${line}`);
1234
+ onLine?.(line);
1235
+ }
1236
+ }
1237
+ }
1238
+ if (buffer.trim()) {
1239
+ diagnosticLog(`[Agent][stderr] ${buffer}`);
1240
+ onLine?.(buffer);
1241
+ }
1242
+ reader.releaseLock();
1243
+ } catch (err) {
1244
+ if (!signal.aborted) {
1245
+ diagnosticLog(
1246
+ `[Agent] stderr drain error: ${err instanceof Error ? err.message : String(err)}`,
1247
+ );
1248
+ }
1249
+ }
1058
1250
  }
1059
1251
 
1060
1252
  const PGLITE_LOCK_RE =
1061
- /pglite data dir is already in use|database is locked|lock file already exists/i;
1253
+ /pglite data dir is already in use|database is locked|lock file already exists/i;
1062
1254
  const PGLITE_RECOVERY_RE =
1063
- /failed query:\s*(?:create schema if not exists|create table if not exists life_)|aborted\(\)\. build with -sassertions|database disk image is malformed|file is not a database|malformed database schema|checksum mismatch|checkpoint failed|wal file/i;
1255
+ /failed query:\s*(?:create schema if not exists|create table if not exists life_)|aborted\(\)\. build with -sassertions|database disk image is malformed|file is not a database|malformed database schema|checksum mismatch|checkpoint failed|wal file/i;
1064
1256
 
1065
1257
  function shouldAutoRecoverPgliteFailure(line: string): boolean {
1066
- if (PGLITE_LOCK_RE.test(line)) {
1067
- return false;
1068
- }
1069
-
1070
- return (
1071
- PGLITE_RECOVERY_RE.test(line) ||
1072
- (/corrupt/i.test(line) && /pglite|sqlite/i.test(line))
1073
- );
1258
+ if (PGLITE_LOCK_RE.test(line)) {
1259
+ return false;
1260
+ }
1261
+
1262
+ return (
1263
+ PGLITE_RECOVERY_RE.test(line) ||
1264
+ (/corrupt/i.test(line) && /pglite|sqlite/i.test(line))
1265
+ );
1074
1266
  }
1075
1267
 
1076
1268
  /**
1077
1269
  * Opt-in: kill processes listening on `port` (lsof + SIGKILL). Default off so a
1078
1270
  * second desktop instance can coexist on the same machine when ports differ.
1079
- * Set ELIZA_AGENT_RECLAIM_STALE_PORT=1 (legacy: ELIZA_AGENT_RECLAIM_STALE_PORT)
1080
- * to restore the old “take over default port behavior.
1271
+ * Set ELIZA_AGENT_RECLAIM_STALE_PORT=1 to restore the old "take over default
1272
+ * port" behavior.
1081
1273
  */
1082
1274
  async function maybeReclaimPortWithSigkill(port: number): Promise<void> {
1083
- const raw = process.env.ELIZA_AGENT_RECLAIM_STALE_PORT?.trim().toLowerCase();
1084
- if (raw !== "1" && raw !== "true" && raw !== "yes") {
1085
- return;
1086
- }
1087
- try {
1088
- const lsofResult = Bun.spawnSync(["lsof", "-ti", `tcp:${port}`]);
1089
- const pids = new TextDecoder()
1090
- .decode(lsofResult.stdout)
1091
- .trim()
1092
- .split("\n")
1093
- .filter(Boolean);
1094
- for (const pid of pids) {
1095
- const numPid = parseInt(pid, 10);
1096
- if (!Number.isNaN(numPid) && numPid !== process.pid) {
1097
- diagnosticLog(
1098
- `[Agent] Reclaim: killing process ${numPid} on port ${port} (ELIZA_AGENT_RECLAIM_STALE_PORT)`,
1099
- );
1100
- try {
1101
- process.kill(numPid, "SIGKILL");
1102
- } catch {
1103
- // Process may have already exited
1104
- }
1105
- }
1106
- }
1107
- if (pids.length > 0) {
1108
- await new Promise((r) => setTimeout(r, 500));
1109
- }
1110
- } catch {
1111
- // lsof missing — ignore
1112
- }
1113
- }
1114
-
1115
- function resolvePgliteDataDir(): string {
1116
- return joinPortable(
1117
- os.homedir(),
1118
- `.${getBrandConfig().namespace}`,
1119
- "workspace",
1120
- ".eliza",
1121
- ".elizadb",
1122
- );
1275
+ const raw = process.env.ELIZA_AGENT_RECLAIM_STALE_PORT?.trim().toLowerCase();
1276
+ if (raw !== "1" && raw !== "true" && raw !== "yes") {
1277
+ return;
1278
+ }
1279
+ try {
1280
+ const lsofResult = Bun.spawnSync(["lsof", "-ti", `tcp:${port}`]);
1281
+ const pids = new TextDecoder()
1282
+ .decode(lsofResult.stdout)
1283
+ .trim()
1284
+ .split("\n")
1285
+ .filter(Boolean);
1286
+ for (const pid of pids) {
1287
+ const numPid = parseInt(pid, 10);
1288
+ if (!Number.isNaN(numPid) && numPid !== process.pid) {
1289
+ diagnosticLog(
1290
+ `[Agent] Reclaim: killing process ${numPid} on port ${port} (ELIZA_AGENT_RECLAIM_STALE_PORT)`,
1291
+ );
1292
+ try {
1293
+ process.kill(numPid, "SIGKILL");
1294
+ } catch {
1295
+ // Process may have already exited
1296
+ }
1297
+ }
1298
+ }
1299
+ if (pids.length > 0) {
1300
+ await new Promise((r) => setTimeout(r, 500));
1301
+ }
1302
+ } catch {
1303
+ // lsof missing — ignore
1304
+ }
1123
1305
  }
1124
1306
 
1125
- /**
1126
- * Removes only the PGLite database folder (agent memory / conversations).
1127
- * GGUF embedding weights live under `MODELS_DIR` / `~/.eliza/models` by default — never deleted here.
1128
- */
1129
- function deletePgliteDataDir(): void {
1130
- const dir = resolvePgliteDataDir();
1131
- if (path.basename(dir) !== ".elizadb") {
1132
- diagnosticLog(
1133
- `[Agent] deletePgliteDataDir: refused basename must be .elizadb, got: ${dir}`,
1134
- );
1135
- return;
1136
- }
1137
- try {
1138
- if (fs.existsSync(dir)) {
1139
- fs.rmSync(dir, { recursive: true, force: true });
1140
- diagnosticLog(
1141
- `[Agent] Deleted PGLite data dir (GGUF model cache elsewhere): ${dir}`,
1142
- );
1143
- }
1144
- } catch (err) {
1145
- diagnosticLog(
1146
- `[Agent] Failed to delete PGLite data dir: ${err instanceof Error ? err.message : String(err)}`,
1147
- );
1148
- }
1307
+ function resolveDatabaseAppStateDir(
1308
+ env: NodeJS.ProcessEnv = process.env,
1309
+ ): string {
1310
+ const stateDir = resolveDesktopChildStateDir({ env });
1311
+ fs.mkdirSync(stateDir, { recursive: true });
1312
+ return stateDir;
1313
+ }
1314
+
1315
+ function resolveManagedPgliteDataDir(): string | null {
1316
+ const resolution = resolveDatabaseMode({
1317
+ env: process.env as Record<string, string | undefined>,
1318
+ packagedDesktop: isPackagedDesktopRuntime(),
1319
+ appStateDir: resolveDatabaseAppStateDir(process.env),
1320
+ });
1321
+ return resolution.mode === "pglite-persistent"
1322
+ ? (resolution.pgliteDataDir ?? null)
1323
+ : null;
1149
1324
  }
1150
1325
 
1151
1326
  // ---------------------------------------------------------------------------
@@ -1153,800 +1328,1065 @@ function deletePgliteDataDir(): void {
1153
1328
  // ---------------------------------------------------------------------------
1154
1329
 
1155
1330
  export class AgentManager {
1156
- private sendToWebview: SendToWebview | null = null;
1157
- private readonly statusListeners = new Set<
1158
- (status: Readonly<AgentStatus>) => void
1159
- >();
1160
- private status: AgentStatus = {
1161
- state: "not_started",
1162
- agentName: null,
1163
- port: null,
1164
- startedAt: null,
1165
- error: null,
1166
- };
1167
- private childProcess: BunSubprocess | null = null;
1168
- private stdioAbortController: AbortController | null = null;
1169
- private hasPgliteError = false;
1170
- private pgliteRecoveryDone = false;
1171
- private startupPhase = "not_started";
1172
-
1173
- constructor() {
1174
- this.persistStartupDiagnostics();
1175
- }
1176
-
1177
- setSendToWebview(fn: SendToWebview): void {
1178
- this.sendToWebview = fn;
1179
- }
1180
-
1181
- onStatusChange(
1182
- listener: (status: Readonly<AgentStatus>) => void,
1183
- ): () => void {
1184
- this.statusListeners.add(listener);
1185
- return () => {
1186
- this.statusListeners.delete(listener);
1187
- };
1188
- }
1189
-
1190
- /** Start the agent runtime as a child process. Idempotent. */
1191
- async start(): Promise<AgentStatus> {
1192
- recordStartupPhase("agent_start_entered", {
1193
- pid: process.pid,
1194
- exec_path: process.execPath,
1195
- bundle_path: resolveStartupBundlePath(process.execPath),
1196
- });
1197
- this.setStartupPhase("start_requested");
1198
- recordStartupPhase("agent_start_entered", {
1199
- pid: process.pid,
1200
- exec_path: process.execPath,
1201
- bundle_path: resolveStartupBundlePath(process.execPath),
1202
- });
1203
- diagnosticLog(
1204
- `[Agent] start() called, current state: ${this.status.state}`,
1205
- );
1206
- diagnosticLog(`[Agent] Diagnostic log file: ${getDiagnosticLogPath()}`);
1207
-
1208
- if (this.status.state === "running" || this.status.state === "starting") {
1209
- return this.status;
1210
- }
1211
-
1212
- const runtimeMode = resolveDesktopRuntimeMode(
1213
- process.env as Record<string, string | undefined>,
1214
- );
1215
- if (runtimeMode.mode !== "local") {
1216
- const reason =
1217
- runtimeMode.mode === "external"
1218
- ? `Embedded desktop runtime is disabled because ${runtimeMode.externalApi.source} points at ${runtimeMode.externalApi.base}.`
1219
- : "Embedded desktop runtime is disabled by ELIZA_DESKTOP_SKIP_EMBEDDED_AGENT=1.";
1220
- diagnosticLog(`[Agent] ${reason}`);
1221
- this.setStartupPhase("startup_disabled", reason);
1222
- throw new Error(reason);
1223
- }
1224
-
1225
- let packagedRuntime: boolean;
1226
- let apiPort: number;
1227
- let preferredPort: number;
1228
- try {
1229
- configureDesktopLocalApiAuth();
1230
- packagedRuntime = isPackagedDesktopRuntime();
1231
-
1232
- // Reset per-startup flags
1233
- this.pgliteRecoveryDone = false;
1234
-
1235
- // Clean up any stale process before starting
1236
- if (this.childProcess) {
1237
- await this.killChildProcess();
1238
- }
1239
-
1240
- preferredPort = resolveDesktopApiPort(process.env) || DEFAULT_API_PORT;
1241
- diagnosticLog(
1242
- `[Agent] Preferred port: ${preferredPort} (packaged: ${packagedRuntime})`,
1243
- );
1244
- if (!packagedRuntime) {
1245
- await maybeReclaimPortWithSigkill(preferredPort);
1246
- }
1247
- apiPort = await findFirstAvailableLoopbackPort(preferredPort);
1248
- } catch (err) {
1249
- const msg =
1250
- err instanceof Error ? err.message : "Failed during pre-startup";
1251
- diagnosticLog(`[Agent] ${msg}`);
1252
- this.status = {
1253
- state: "error",
1254
- agentName: null,
1255
- port: null,
1256
- startedAt: null,
1257
- error: msg,
1258
- };
1259
- recordStartupPhase("fatal", {
1260
- port: null,
1261
- error: msg,
1262
- });
1263
- this.setStartupPhase("port_allocation_failed", msg);
1264
- this.emitStatus();
1265
- return this.status;
1266
- }
1267
- if (apiPort !== preferredPort) {
1268
- diagnosticLog(
1269
- `[Agent] Port ${preferredPort} busy — using ${apiPort} for embedded API (set ELIZA_AGENT_RECLAIM_STALE_PORT=1 to try reclaiming the preferred port first)`,
1270
- );
1271
- }
1272
- recordStartupPhase("port_selected", {
1273
- port: apiPort,
1274
- });
1275
-
1276
- this.status = {
1277
- state: "starting",
1278
- agentName: null,
1279
- port: null,
1280
- startedAt: null,
1281
- error: null,
1282
- };
1283
- this.setStartupPhase("starting_runtime");
1284
- this.emitStatus();
1285
-
1286
- try {
1287
- // Resolve the bundled runtime dist path.
1288
- this.setStartupPhase("resolving_runtime");
1289
- const runtimeDistPath = resolveRuntimeDistPath();
1290
- diagnosticLog(`[Agent] Resolved runtime dist: ${runtimeDistPath}`);
1291
-
1292
- // Packaged builds can expose the runnable entry either at the dist root
1293
- // or under runtime/. Prefer the root file but accept both layouts.
1294
- const runtimeEntryPath = resolveRuntimeEntryPath(runtimeDistPath);
1295
- if (!runtimeEntryPath) {
1296
- const distExists = fs.existsSync(runtimeDistPath);
1297
- let contents = "<directory missing>";
1298
- if (distExists) {
1299
- try {
1300
- contents = fs.readdirSync(runtimeDistPath).join(", ");
1301
- } catch {
1302
- contents = "<unreadable>";
1303
- }
1304
- }
1305
- const errMsg = `No runnable runtime entry found in ${runtimeDistPath} (checked entry.js; dist exists: ${distExists}, contents: ${contents})`;
1306
- diagnosticLog(`[Agent] ${errMsg}`);
1307
- this.status = {
1308
- state: "error",
1309
- agentName: null,
1310
- port: null,
1311
- startedAt: null,
1312
- error: errMsg,
1313
- };
1314
- recordStartupPhase("fatal", {
1315
- port: apiPort,
1316
- error: errMsg,
1317
- });
1318
- this.setStartupPhase("runtime_entry_missing", errMsg);
1319
- recordStartupPhase("fatal", {
1320
- port: apiPort,
1321
- error: errMsg,
1322
- });
1323
- this.emitStatus();
1324
- return this.status;
1325
- }
1326
-
1327
- diagnosticLog(`[Agent] runtime entry: exists (${runtimeEntryPath})`);
1328
- recordStartupPhase("runtime_path_resolved", {
1329
- port: apiPort,
1330
- });
1331
-
1332
- diagnosticLog(`[Agent] Starting child process on port ${apiPort}...`);
1333
- this.setStartupPhase("spawning_runtime");
1334
-
1335
- // Build NODE_PATH so the child can find node_modules
1336
- const nodePaths = buildChildNodePaths(runtimeDistPath, {
1337
- packagedRuntime,
1338
- });
1339
- if (packagedRuntime && nodePaths.length === 0) {
1340
- const errMsg =
1341
- `Packaged runtime is missing bundle-local node_modules under ${runtimeDistPath}; ` +
1342
- "refusing to inherit the parent NODE_PATH";
1343
- diagnosticLog(`[Agent] ${errMsg}`);
1344
- this.status = {
1345
- state: "error",
1346
- agentName: null,
1347
- port: apiPort,
1348
- startedAt: null,
1349
- error: errMsg,
1350
- };
1351
- recordStartupPhase("fatal", {
1352
- port: apiPort,
1353
- error: errMsg,
1354
- });
1355
- this.emitStatus();
1356
- return this.status;
1357
- }
1358
-
1359
- const childEnv: Record<string, string> = {
1360
- ...(process.env as Record<string, string>),
1361
- ELIZA_API_PORT: String(apiPort),
1362
- ELIZA_PORT: String(apiPort),
1363
- };
1364
- childEnv.ELIZA_NAMESPACE =
1365
- childEnv.ELIZA_NAMESPACE?.trim() || getBrandConfig().namespace;
1366
- childEnv.ELIZA_NAMESPACE =
1367
- childEnv.ELIZA_NAMESPACE?.trim() || childEnv.ELIZA_NAMESPACE;
1368
- applyDesktopChildStateEnv(childEnv);
1369
- delete childEnv.ELIZA_PORT;
1370
- delete childEnv.NODE_PATH;
1371
-
1372
- // node-llama-cpp crashes Bun on Windows during packaged startup.
1373
- // Disable local embeddings until upstream fix lands.
1374
- if (process.platform === "win32") {
1375
- childEnv.ELIZA_DISABLE_LOCAL_EMBEDDINGS = "1";
1376
- }
1377
-
1378
- // Propagate PGlite data dir from parent env so CI/smoke test overrides
1379
- // (e.g. a short Windows path avoiding MAX_PATH issues) reach the runtime.
1380
- if (process.env.PGLITE_DATA_DIR) {
1381
- childEnv.PGLITE_DATA_DIR = process.env.PGLITE_DATA_DIR;
1382
- }
1383
-
1384
- if (nodePaths.length > 0) {
1385
- childEnv.NODE_PATH = nodePaths.join(path.delimiter);
1386
- diagnosticLog(`[Agent] Child NODE_PATH: ${childEnv.NODE_PATH}`);
1387
- }
1388
-
1389
- const bunExecutable = resolveBunExecutablePath();
1390
- diagnosticLog(`[Agent] Using Bun executable: ${bunExecutable}`);
1391
- diagnosticLog(
1392
- `[Agent] Bun exists on disk: ${fs.existsSync(bunExecutable)}`,
1393
- );
1394
-
1395
- // Ensure bun's directory is on PATH so child_process.exec calls
1396
- // (e.g. plugin-manager running `bun add ...`) can find it.
1397
- const bunDir = path.dirname(bunExecutable);
1398
- const existingPath = childEnv.PATH ?? "";
1399
- if (!existingPath.split(path.delimiter).includes(bunDir)) {
1400
- childEnv.PATH = bunDir + path.delimiter + existingPath;
1401
- diagnosticLog(`[Agent] Prepended bun dir to child PATH: ${bunDir}`);
1402
- }
1403
-
1404
- // Spawn the child process
1405
- const spawnTime = Date.now();
1406
- const proc = Bun.spawn(
1407
- [bunExecutable, "run", runtimeEntryPath, "start"],
1408
- {
1409
- cwd: runtimeDistPath,
1410
- env: childEnv,
1411
- stdout: "pipe",
1412
- stderr: "pipe",
1413
- },
1414
- );
1415
-
1416
- this.childProcess = proc;
1417
- diagnosticLog(
1418
- `[Agent] Child spawned pid=${proc.pid} elapsed=${Date.now() - spawnTime}ms`,
1419
- );
1420
- recordStartupPhase("child_spawned", {
1421
- port: apiPort,
1422
- child_pid: proc.pid,
1423
- });
1424
-
1425
- // Set up abort controller for stdio watchers
1426
- this.stdioAbortController = new AbortController();
1427
- const { signal } = this.stdioAbortController;
1428
-
1429
- // Surface the port immediately while waiting for ready
1430
- this.status = {
1431
- ...this.status,
1432
- port: apiPort,
1433
- };
1434
- this.emitStatus();
1435
-
1436
- // Track whether we detected the "listening" message from stdout
1437
- let detectedListening = false;
1438
-
1439
- // Watch stdout for "listening on port" or similar ready messages
1440
- if (proc.stdout) {
1441
- watchStdoutForReady(
1442
- proc.stdout,
1443
- (line: string) => {
1444
- diagnosticLog(`[Agent][stdout] ${line}`);
1445
- const lower = line.toLowerCase();
1446
- // Parse dynamic port from "[eliza-api] Listening on http://host:PORT"
1447
- const portMatch = line.match(
1448
- /Listening on https?:\/\/[^:]+:(\d+)/i,
1449
- );
1450
- if (portMatch) {
1451
- const parsedPort = parseInt(portMatch[1], 10);
1452
- if (!Number.isNaN(parsedPort) && parsedPort > 0) {
1453
- if (parsedPort !== apiPort) {
1454
- diagnosticLog(
1455
- `[Agent] Server bound to dynamic port ${parsedPort} (requested ${apiPort})`,
1456
- );
1457
- apiPort = parsedPort;
1458
- }
1459
- detectedListening = true;
1460
- }
1461
- } else if (
1462
- lower.includes("listening on port") ||
1463
- lower.includes("server started") ||
1464
- lower.includes("ready on")
1465
- ) {
1466
- detectedListening = true;
1467
- }
1468
- // Update status port so callers see the actual bound port
1469
- this.status = { ...this.status, port: apiPort };
1470
- this.emitStatus();
1471
- },
1472
- signal,
1473
- ).catch(() => {
1474
- // Stream ended or aborted -- expected on shutdown
1475
- });
1476
- }
1477
-
1478
- // Drain stderr to diagnostic log; detect PGLite migration failures
1479
- this.hasPgliteError = false;
1480
- if (proc.stderr) {
1481
- drainStderrToLog(proc.stderr, signal, (line) => {
1482
- if (shouldAutoRecoverPgliteFailure(line)) {
1483
- this.hasPgliteError = true;
1484
- }
1485
- }).catch(() => {
1486
- // Stream ended or aborted -- expected on shutdown
1487
- });
1488
- }
1489
-
1490
- // Monitor child process exit
1491
- this.monitorChildExit(proc);
1492
-
1493
- // Wait for the health endpoint to respond
1494
- // Use a getter so the health check follows dynamic port reassignment from stdout
1495
- diagnosticLog(
1496
- `[Agent] Waiting for health endpoint at http://127.0.0.1:${apiPort}/api/health ...`,
1497
- );
1498
- this.setStartupPhase("waiting_for_health");
1499
- const healthPollTimeoutMs = getHealthPollTimeoutMs();
1500
- const healthy = await waitForHealthy(
1501
- () => apiPort,
1502
- healthPollTimeoutMs,
1503
- proc,
1504
- );
1505
-
1506
- if (!healthy) {
1507
- // Check if process already exited
1508
- if (proc.exitCode !== null) {
1509
- const errMsg = `Child process exited with code ${proc.exitCode} before becoming healthy`;
1510
- diagnosticLog(`[Agent] ${errMsg}`);
1511
- this.childProcess = null;
1512
- this.status = {
1513
- state: "error",
1514
- agentName: null,
1515
- port: apiPort,
1516
- startedAt: null,
1517
- error: errMsg,
1518
- };
1519
- recordStartupPhase("fatal", {
1520
- port: apiPort,
1521
- child_pid: proc.pid,
1522
- error: errMsg,
1523
- exit_code: proc.exitCode,
1524
- });
1525
- this.setStartupPhase("startup_failed", errMsg);
1526
- recordStartupPhase("fatal", {
1527
- port: apiPort,
1528
- child_pid: proc.pid,
1529
- error: errMsg,
1530
- exit_code: proc.exitCode,
1531
- });
1532
- this.emitStatus();
1533
- return this.status;
1534
- }
1535
-
1536
- const errMsg = detectedListening
1537
- ? "Server reported listening but health check timed out"
1538
- : `Health check timed out after ${healthPollTimeoutMs}ms`;
1539
- diagnosticLog(`[Agent] ${errMsg}`);
1540
- this.status = {
1541
- state: "error",
1542
- agentName: null,
1543
- port: apiPort,
1544
- startedAt: null,
1545
- error: errMsg,
1546
- };
1547
- recordStartupPhase("fatal", {
1548
- port: apiPort,
1549
- child_pid: proc.pid,
1550
- error: errMsg,
1551
- });
1552
- this.setStartupPhase("startup_failed", errMsg);
1553
- recordStartupPhase("fatal", {
1554
- port: apiPort,
1555
- child_pid: proc.pid,
1556
- error: errMsg,
1557
- });
1558
- this.emitStatus();
1559
- return this.status;
1560
- }
1561
- recordStartupPhase("health_ready", {
1562
- port: apiPort,
1563
- child_pid: proc.pid,
1564
- });
1565
-
1566
- this.setStartupPhase("fetching_agent_metadata");
1567
- const startedAt = Date.now();
1568
- const startupMs = startedAt - spawnTime;
1569
-
1570
- this.status = {
1571
- state: "running",
1572
- agentName: getBrandConfig().appName,
1573
- port: apiPort,
1574
- startedAt,
1575
- error: null,
1576
- };
1577
- this.setStartupPhase("ready", null);
1578
- this.emitStatus();
1579
- diagnosticLog(
1580
- `[Agent] Runtime ready -- port: ${apiPort}, pid: ${proc.pid}, startup_ms: ${startupMs}`,
1581
- );
1582
- recordStartupPhase("runtime_ready", {
1583
- port: apiPort,
1584
- child_pid: proc.pid,
1585
- });
1586
- void this.refreshAgentMetadata(proc, apiPort, startupMs);
1587
- return this.status;
1588
- } catch (err) {
1589
- const errMsg =
1590
- err instanceof Error ? err.stack || err.message : String(err);
1591
- diagnosticLog(`[Agent] Failed to start: ${errMsg}`);
1592
- recordStartupPhase("fatal", {
1593
- port: this.status.port,
1594
- error: errMsg,
1595
- });
1596
-
1597
- // Clean up child if it was spawned
1598
- if (this.childProcess) {
1599
- await this.killChildProcess();
1600
- }
1601
-
1602
- this.status = {
1603
- state: "error",
1604
- agentName: null,
1605
- port: this.status.port, // preserve port if set
1606
- startedAt: null,
1607
- error: shortError(err),
1608
- };
1609
- this.setStartupPhase("startup_failed", shortError(err));
1610
- this.emitStatus();
1611
- return this.status;
1612
- }
1613
- }
1614
-
1615
- /** Stop the agent runtime. */
1616
- async stop(): Promise<void> {
1617
- if (this.status.state !== "running" && this.status.state !== "starting") {
1618
- return;
1619
- }
1620
-
1621
- diagnosticLog("[Agent] Stopping...");
1622
- this.setStartupPhase("stopping");
1623
-
1624
- // Abort stdio watchers
1625
- if (this.stdioAbortController) {
1626
- this.stdioAbortController.abort();
1627
- this.stdioAbortController = null;
1628
- }
1629
-
1630
- await this.killChildProcess();
1631
-
1632
- this.status = {
1633
- state: "stopped",
1634
- agentName: this.status.agentName,
1635
- port: null,
1636
- startedAt: null,
1637
- error: null,
1638
- };
1639
- this.setStartupPhase("stopped", null);
1640
- this.emitStatus();
1641
- diagnosticLog("[Agent] Runtime stopped");
1642
- }
1643
-
1644
- /**
1645
- * Restart the agent runtime -- stops the current instance and starts a
1646
- * fresh one, picking up config/plugin changes.
1647
- */
1648
- async restart(): Promise<AgentStatus> {
1649
- diagnosticLog("[Agent] Restart requested -- stopping current runtime...");
1650
- this.setStartupPhase("restart_requested");
1651
- await this.stop();
1652
- diagnosticLog("[Agent] Restarting...");
1653
- return this.start();
1654
- }
1655
-
1656
- /**
1657
- * Used after `POST /api/agent/reset`: stop the child, delete local PGLite
1658
- * (conversations / agent memory under `~/.${getBrandConfig().namespace}/workspace/.eliza/.elizadb`),
1659
- * then start fresh. Does not remove downloaded **GGUF** models (`MODELS_DIR`,
1660
- * default ~/.eliza/models), env-backed wallet keys, or eliza.json (the API
1661
- * reset already rewrote config on disk).
1662
- *
1663
- * When `ELIZA_DESKTOP_API_BASE` points at an external dev API (e.g. :31337),
1664
- * the embedded child is never used — this is a no-op so the renderer can
1665
- * bounce the real API via `POST /api/agent/restart` instead.
1666
- */
1667
- async restartClearingLocalDb(): Promise<AgentStatus> {
1668
- const runtimeMode = resolveDesktopRuntimeMode(
1669
- process.env as Record<string, string | undefined>,
1670
- );
1671
- if (runtimeMode.mode !== "local") {
1672
- diagnosticLog(
1673
- `[Agent] restartClearingLocalDb skipped — mode=${runtimeMode.mode} externalBase=${runtimeMode.externalApi.base ?? "n/a"} source=${runtimeMode.externalApi.source ?? "n/a"} (renderer uses POST /api/agent/restart)`,
1674
- );
1675
- return this.getStatus();
1676
- }
1677
-
1678
- diagnosticLog(
1679
- `[Agent] restartClearingLocalDb: local mode — stop → rm PGLite (${resolvePgliteDataDir()}) → start`,
1680
- );
1681
- await this.stop();
1682
- this.hasPgliteError = false;
1683
- this.pgliteRecoveryDone = false;
1684
- deletePgliteDataDir();
1685
- const next = await this.start();
1686
- diagnosticLog(
1687
- `[Agent] restartClearingLocalDb: start() finished state=${next.state} port=${next.port ?? "null"}`,
1688
- );
1689
- return next;
1690
- }
1691
-
1692
- getStatus(): AgentStatus {
1693
- return { ...this.status };
1694
- }
1695
-
1696
- inspectExistingInstall(): ExistingElizaInstallInfo {
1697
- return inspectExistingElizaInstall();
1698
- }
1699
-
1700
- migrateStateDir(params: { fromPath: string }): StateDirMigrationResult {
1701
- return migrateDesktopStateDirFromPath(params.fromPath);
1702
- }
1703
-
1704
- getPort(): number | null {
1705
- return this.status.port;
1706
- }
1707
-
1708
- /** Clean up on app quit. */
1709
- async dispose(): Promise<void> {
1710
- if (this.stdioAbortController) {
1711
- this.stdioAbortController.abort();
1712
- this.stdioAbortController = null;
1713
- }
1714
- try {
1715
- await this.killChildProcess();
1716
- } catch (err) {
1717
- logger.warn(
1718
- `[Agent] dispose error: ${err instanceof Error ? err.message : String(err)}`,
1719
- );
1720
- }
1721
- }
1722
-
1723
- // -----------------------------------------------------------------------
1724
- // Private helpers
1725
- // -----------------------------------------------------------------------
1726
-
1727
- private emitStatus(): void {
1728
- this.persistStartupDiagnostics();
1729
- if (this.sendToWebview) {
1730
- this.sendToWebview("agentStatusUpdate", this.status);
1731
- }
1732
- const statusSnapshot = { ...this.status };
1733
- for (const listener of this.statusListeners) {
1734
- try {
1735
- listener(statusSnapshot);
1736
- } catch (err) {
1737
- logger.warn(
1738
- `[Agent] status listener failed: ${err instanceof Error ? err.message : String(err)}`,
1739
- );
1740
- }
1741
- }
1742
- }
1743
-
1744
- private async refreshAgentMetadata(
1745
- proc: BunSubprocess,
1746
- port: number,
1747
- startupMs: number,
1748
- ): Promise<void> {
1749
- const agentName = await this.fetchAgentName(port);
1750
- if (
1751
- this.childProcess !== proc ||
1752
- this.status.state !== "running" ||
1753
- this.status.port !== port
1754
- ) {
1755
- return;
1756
- }
1757
-
1758
- if (this.status.agentName !== agentName) {
1759
- this.status = {
1760
- ...this.status,
1761
- agentName,
1762
- };
1763
- this.emitStatus();
1764
- }
1765
-
1766
- diagnosticLog(
1767
- `[Agent] Runtime started -- agent: ${agentName}, port: ${port}, pid: ${proc.pid}, startup_ms: ${startupMs}`,
1768
- );
1769
- recordStartupPhase("metadata_ready", {
1770
- port,
1771
- child_pid: proc.pid,
1772
- });
1773
- }
1774
- private setStartupPhase(phase: string, lastError?: string | null): void {
1775
- this.startupPhase = phase;
1776
- this.persistStartupDiagnostics(lastError);
1777
- }
1778
-
1779
- private persistStartupDiagnostics(lastError?: string | null): void {
1780
- writeStartupDiagnosticsSnapshot({
1781
- state: this.status.state,
1782
- phase: this.startupPhase,
1783
- updatedAt: new Date().toISOString(),
1784
- lastError: lastError ?? this.status.error,
1785
- agentName: this.status.agentName,
1786
- port: this.status.port,
1787
- startedAt: this.status.startedAt,
1788
- platform: process.platform,
1789
- arch: process.arch,
1790
- configDir: resolveConfigDir(),
1791
- logPath: getDiagnosticLogPath(),
1792
- statusPath: getStartupStatusPath(),
1793
- });
1794
- }
1795
-
1796
- /**
1797
- * Monitor the child process for unexpected exits and update status.
1798
- */
1799
- private monitorChildExit(proc: BunSubprocess): void {
1800
- // Bun.spawn provides an `exited` promise that resolves when the process exits
1801
- proc.exited
1802
- .then((exitCode: number) => {
1803
- // Only update status if this is still our active child process
1804
- if (this.childProcess !== proc) return;
1805
-
1806
- const wasRunning = this.status.state === "running";
1807
- const wasStarting = this.status.state === "starting";
1808
-
1809
- if (wasRunning || wasStarting) {
1810
- diagnosticLog(
1811
- `[Agent] Child process exited unexpectedly with code ${exitCode} (pid: ${proc.pid})`,
1812
- );
1813
- recordStartupPhase("fatal", {
1814
- port: this.status.port,
1815
- child_pid: proc.pid,
1816
- error: `Process exited unexpectedly with code ${exitCode}`,
1817
- exit_code: exitCode,
1818
- });
1819
- this.childProcess = null;
1820
-
1821
- // Auto-recover from PGLite migration failures by deleting the DB
1822
- // and spawning a fresh process (new process = fresh WASM state).
1823
- if (this.hasPgliteError && !this.pgliteRecoveryDone) {
1824
- this.pgliteRecoveryDone = true;
1825
- diagnosticLog(
1826
- "[Agent] PGLite migration error detected — deleting DB and retrying with fresh process",
1827
- );
1828
- deletePgliteDataDir();
1829
- this.status = {
1830
- state: "not_started",
1831
- agentName: null,
1832
- port: null,
1833
- startedAt: null,
1834
- error: null,
1835
- };
1836
- this.setStartupPhase("recovering_pglite");
1837
- // Delay slightly so OS releases file handles before respawn
1838
- setTimeout(() => void this.start(), 500);
1839
- return;
1840
- }
1841
-
1842
- this.status = {
1843
- state: "error",
1844
- agentName: this.status.agentName,
1845
- port: this.status.port,
1846
- startedAt: null,
1847
- error: `Process exited unexpectedly with code ${exitCode}`,
1848
- };
1849
- this.setStartupPhase(
1850
- "process_exited_unexpectedly",
1851
- `Process exited unexpectedly with code ${exitCode}`,
1852
- );
1853
- this.emitStatus();
1854
- } else {
1855
- // Expected exit (we called stop)
1856
- this.childProcess = null;
1857
- }
1858
- })
1859
- .catch((err: unknown) => {
1860
- if (this.childProcess !== proc) return;
1861
- diagnosticLog(
1862
- `[Agent] Child process exited with error: ${err instanceof Error ? err.message : String(err)}`,
1863
- );
1864
- recordStartupPhase("fatal", {
1865
- port: this.status.port,
1866
- child_pid: proc.pid,
1867
- error: err instanceof Error ? err.message : String(err),
1868
- });
1869
- this.childProcess = null;
1870
- if (
1871
- this.status.state === "running" ||
1872
- this.status.state === "starting"
1873
- ) {
1874
- this.status = {
1875
- state: "error",
1876
- agentName: this.status.agentName,
1877
- port: this.status.port,
1878
- startedAt: null,
1879
- error: shortError(err),
1880
- };
1881
- this.setStartupPhase("process_exit_error", shortError(err));
1882
- this.emitStatus();
1883
- }
1884
- });
1885
- }
1886
-
1887
- /**
1888
- * Kill the child process gracefully with SIGTERM, escalating to SIGKILL
1889
- * after a timeout.
1890
- */
1891
- private async killChildProcess(): Promise<void> {
1892
- const proc = this.childProcess;
1893
- if (!proc) return;
1894
-
1895
- this.childProcess = null;
1896
-
1897
- // Already exited
1898
- if (proc.exitCode !== null) return;
1899
-
1900
- diagnosticLog(`[Agent] Sending SIGTERM to pid ${proc.pid}`);
1901
- proc.kill("SIGTERM");
1902
-
1903
- // Wait for graceful shutdown or timeout
1904
- const exited = await Promise.race([
1905
- proc.exited.then(() => true as const),
1906
- Bun.sleep(SIGTERM_GRACE_MS).then(() => false as const),
1907
- ]);
1908
-
1909
- if (!exited) {
1910
- diagnosticLog(
1911
- `[Agent] Process did not exit within ${SIGTERM_GRACE_MS}ms, sending SIGKILL`,
1912
- );
1913
- try {
1914
- proc.kill("SIGKILL");
1915
- } catch {
1916
- // Process may have already exited between check and kill
1917
- }
1918
- // Wait briefly for SIGKILL to take effect
1919
- await Promise.race([proc.exited.catch(() => {}), Bun.sleep(1_000)]);
1920
- }
1921
-
1922
- diagnosticLog("[Agent] Child process terminated");
1923
- }
1924
-
1925
- /**
1926
- * Attempt to fetch the agent name from the running API server.
1927
- * Falls back to the configured desktop app name if the endpoint is unavailable.
1928
- */
1929
- private async fetchAgentName(port: number): Promise<string> {
1930
- try {
1931
- const headers = getDesktopApiHeaders();
1932
- const response = await fetch(`http://127.0.0.1:${port}/api/agents`, {
1933
- headers,
1934
- signal: AbortSignal.timeout(AGENT_NAME_FETCH_TIMEOUT_MS),
1935
- });
1936
- if (response.ok) {
1937
- const data = (await response.json()) as
1938
- | { agents?: Array<{ name?: string }> }
1939
- | Array<{ name?: string }>;
1940
- const agents = Array.isArray(data) ? data : data.agents;
1941
- if (agents && agents.length > 0 && agents[0].name) {
1942
- return agents[0].name;
1943
- }
1944
- }
1945
- } catch {
1946
- diagnosticLog("[Agent] Could not fetch agent name, using default");
1947
- }
1948
- return getBrandConfig().appName;
1949
- }
1331
+ private sendToWebview: SendToWebview | null = null;
1332
+ private readonly statusListeners = new Set<
1333
+ (status: Readonly<AgentStatus>) => void
1334
+ >();
1335
+ private status: AgentStatus = {
1336
+ state: "not_started",
1337
+ agentName: null,
1338
+ port: null,
1339
+ startedAt: null,
1340
+ error: null,
1341
+ };
1342
+ private childProcess: BunSubprocess | null = null;
1343
+ private stdioAbortController: AbortController | null = null;
1344
+ private hasPgliteError = false;
1345
+ private pgliteRecoveryDone = false;
1346
+ private startupPhase = "not_started";
1347
+ private databaseSnapshot: DatabaseSnapshot = createUnknownDatabaseSnapshot();
1348
+ private databaseStartupLock: DatabaseStartupLock | null = null;
1349
+
1350
+ constructor() {
1351
+ this.persistStartupDiagnostics();
1352
+ }
1353
+
1354
+ setSendToWebview(fn: SendToWebview): void {
1355
+ this.sendToWebview = fn;
1356
+ }
1357
+
1358
+ onStatusChange(
1359
+ listener: (status: Readonly<AgentStatus>) => void,
1360
+ ): () => void {
1361
+ this.statusListeners.add(listener);
1362
+ return () => {
1363
+ this.statusListeners.delete(listener);
1364
+ };
1365
+ }
1366
+
1367
+ /** Start the agent runtime as a child process. Idempotent. */
1368
+ async start(): Promise<AgentStatus> {
1369
+ recordStartupPhase("agent_start_entered", {
1370
+ pid: process.pid,
1371
+ exec_path: process.execPath,
1372
+ bundle_path: resolveStartupBundlePath(process.execPath),
1373
+ });
1374
+ this.setStartupPhase("start_requested");
1375
+ recordStartupPhase("agent_start_entered", {
1376
+ pid: process.pid,
1377
+ exec_path: process.execPath,
1378
+ bundle_path: resolveStartupBundlePath(process.execPath),
1379
+ });
1380
+ diagnosticLog(
1381
+ `[Agent] start() called, current state: ${this.status.state}`,
1382
+ );
1383
+ diagnosticLog(`[Agent] Diagnostic log file: ${getDiagnosticLogPath()}`);
1384
+
1385
+ if (this.status.state === "running" || this.status.state === "starting") {
1386
+ return this.status;
1387
+ }
1388
+
1389
+ const runtimeMode = resolveDesktopRuntimeMode(
1390
+ process.env as Record<string, string | undefined>,
1391
+ );
1392
+ if (runtimeMode.mode !== "local") {
1393
+ const reason =
1394
+ runtimeMode.mode === "external"
1395
+ ? `Embedded desktop runtime is disabled because ${runtimeMode.externalApi.source} points at ${runtimeMode.externalApi.base}.`
1396
+ : "Embedded desktop runtime is disabled by ELIZA_DESKTOP_SKIP_EMBEDDED_AGENT=1.";
1397
+ diagnosticLog(`[Agent] ${reason}`);
1398
+ this.setStartupPhase("startup_disabled", reason);
1399
+ throw new Error(reason);
1400
+ }
1401
+
1402
+ let packagedRuntime: boolean;
1403
+ let apiPort: number;
1404
+ let preferredPort: number;
1405
+ try {
1406
+ configureDesktopLocalApiAuth();
1407
+ packagedRuntime = isPackagedDesktopRuntime();
1408
+
1409
+ // Reset per-startup flags
1410
+ this.pgliteRecoveryDone = false;
1411
+
1412
+ // Clean up any stale process before starting
1413
+ if (this.childProcess) {
1414
+ await this.killChildProcess();
1415
+ }
1416
+
1417
+ preferredPort = resolveDesktopApiPort(process.env) || DEFAULT_API_PORT;
1418
+ diagnosticLog(
1419
+ `[Agent] Preferred port: ${preferredPort} (packaged: ${packagedRuntime})`,
1420
+ );
1421
+ if (!packagedRuntime) {
1422
+ await maybeReclaimPortWithSigkill(preferredPort);
1423
+ }
1424
+ apiPort = await findFirstAvailableLoopbackPort(preferredPort);
1425
+ } catch (err) {
1426
+ const msg =
1427
+ err instanceof Error ? err.message : "Failed during pre-startup";
1428
+ diagnosticLog(`[Agent] ${msg}`);
1429
+ this.status = {
1430
+ state: "error",
1431
+ agentName: null,
1432
+ port: null,
1433
+ startedAt: null,
1434
+ error: msg,
1435
+ };
1436
+ recordStartupPhase("fatal", {
1437
+ port: null,
1438
+ error: msg,
1439
+ });
1440
+ this.setStartupPhase("port_allocation_failed", msg);
1441
+ this.emitStatus();
1442
+ return this.status;
1443
+ }
1444
+ if (apiPort !== preferredPort) {
1445
+ diagnosticLog(
1446
+ `[Agent] Port ${preferredPort} busy — using ${apiPort} for embedded API (set ELIZA_AGENT_RECLAIM_STALE_PORT=1 to try reclaiming the preferred port first)`,
1447
+ );
1448
+ }
1449
+ recordStartupPhase("port_selected", {
1450
+ port: apiPort,
1451
+ });
1452
+
1453
+ this.status = {
1454
+ state: "starting",
1455
+ agentName: null,
1456
+ port: null,
1457
+ startedAt: null,
1458
+ error: null,
1459
+ };
1460
+ this.setStartupPhase("starting_runtime");
1461
+ this.emitStatus();
1462
+
1463
+ try {
1464
+ // Resolve the bundled runtime dist path.
1465
+ this.setStartupPhase("resolving_runtime");
1466
+ const runtimeDistPath = resolveRuntimeDistPath();
1467
+ diagnosticLog(`[Agent] Resolved runtime dist: ${runtimeDistPath}`);
1468
+
1469
+ // Packaged builds can expose the runnable entry either at the dist root
1470
+ // or under runtime/. Prefer the root file but accept both layouts.
1471
+ const runtimeEntryPath = resolveRuntimeEntryPath(runtimeDistPath);
1472
+ if (!runtimeEntryPath) {
1473
+ const distExists = fs.existsSync(runtimeDistPath);
1474
+ let contents = "<directory missing>";
1475
+ if (distExists) {
1476
+ try {
1477
+ contents = fs.readdirSync(runtimeDistPath).join(", ");
1478
+ } catch {
1479
+ contents = "<unreadable>";
1480
+ }
1481
+ }
1482
+ const errMsg = `No runnable runtime entry found in ${runtimeDistPath} (checked entry.js; dist exists: ${distExists}, contents: ${contents})`;
1483
+ diagnosticLog(`[Agent] ${errMsg}`);
1484
+ this.status = {
1485
+ state: "error",
1486
+ agentName: null,
1487
+ port: null,
1488
+ startedAt: null,
1489
+ error: errMsg,
1490
+ };
1491
+ recordStartupPhase("fatal", {
1492
+ port: apiPort,
1493
+ error: errMsg,
1494
+ });
1495
+ this.setStartupPhase("runtime_entry_missing", errMsg);
1496
+ recordStartupPhase("fatal", {
1497
+ port: apiPort,
1498
+ error: errMsg,
1499
+ });
1500
+ this.emitStatus();
1501
+ return this.status;
1502
+ }
1503
+
1504
+ diagnosticLog(`[Agent] runtime entry: exists (${runtimeEntryPath})`);
1505
+ recordStartupPhase("runtime_path_resolved", {
1506
+ port: apiPort,
1507
+ });
1508
+
1509
+ diagnosticLog(`[Agent] Starting child process on port ${apiPort}...`);
1510
+ this.setStartupPhase("spawning_runtime");
1511
+
1512
+ // Build NODE_PATH so the child can find node_modules
1513
+ const nodePaths = buildChildNodePaths(runtimeDistPath, {
1514
+ packagedRuntime,
1515
+ });
1516
+ if (packagedRuntime && nodePaths.length === 0) {
1517
+ const errMsg =
1518
+ `Packaged runtime is missing bundle-local node_modules under ${runtimeDistPath}; ` +
1519
+ "refusing to inherit the parent NODE_PATH";
1520
+ diagnosticLog(`[Agent] ${errMsg}`);
1521
+ this.status = {
1522
+ state: "error",
1523
+ agentName: null,
1524
+ port: apiPort,
1525
+ startedAt: null,
1526
+ error: errMsg,
1527
+ };
1528
+ recordStartupPhase("fatal", {
1529
+ port: apiPort,
1530
+ error: errMsg,
1531
+ });
1532
+ this.emitStatus();
1533
+ return this.status;
1534
+ }
1535
+
1536
+ const childEnv: Record<string, string> = {
1537
+ ...(process.env as Record<string, string>),
1538
+ ELIZA_API_PORT: String(apiPort),
1539
+ ELIZA_PORT: String(apiPort),
1540
+ };
1541
+ childEnv.ELIZA_NAMESPACE = resolveDesktopChildNamespace(childEnv);
1542
+ applyDesktopChildStateEnv(childEnv);
1543
+ delete childEnv.ELIZA_PORT;
1544
+ delete childEnv.NODE_PATH;
1545
+
1546
+ const databaseResolution = resolveDatabaseMode({
1547
+ env: childEnv,
1548
+ packagedDesktop: packagedRuntime,
1549
+ appStateDir: childEnv.ELIZA_STATE_DIR,
1550
+ cwd: runtimeDistPath,
1551
+ });
1552
+ applyDatabaseResolutionToEnv(childEnv, databaseResolution);
1553
+ const bundledWhisper = applyBundledWhisperEnv(childEnv, runtimeDistPath);
1554
+ if (bundledWhisper) {
1555
+ diagnosticLog(
1556
+ `[Agent] Bundled Whisper ASR: ${bundledWhisper.libraryPath}`,
1557
+ );
1558
+ }
1559
+ const effectiveTarget =
1560
+ databaseResolution.mode === "postgres"
1561
+ ? redactDatabaseTarget(databaseResolution.postgresUrl)
1562
+ : (databaseResolution.pgliteDataDir ?? null);
1563
+ this.databaseSnapshot = createDatabaseSnapshot({
1564
+ mode: databaseResolution.mode,
1565
+ status: "resolving",
1566
+ postgresUrlSet: databaseResolution.mode === "postgres",
1567
+ databaseUrlMapped: databaseResolution.databaseUrlMapped,
1568
+ pgliteDataDir: databaseResolution.pgliteDataDir ?? null,
1569
+ effectiveTarget,
1570
+ warnings: databaseResolution.warnings,
1571
+ });
1572
+ this.persistStartupDiagnostics();
1573
+ diagnosticLog(
1574
+ `[Agent] Database mode: ${databaseResolution.mode} source=${databaseResolution.source} target=${effectiveTarget ?? "runtime-default"}`,
1575
+ );
1576
+ recordStartupPhase("database_mode_resolved", {
1577
+ port: apiPort,
1578
+ });
1579
+ if (
1580
+ databaseResolution.mode === "pglite-persistent" &&
1581
+ databaseResolution.pgliteDataDir
1582
+ ) {
1583
+ try {
1584
+ ensurePgliteDataDir(databaseResolution.pgliteDataDir);
1585
+ const lockResult = acquireDatabaseStartupLock(
1586
+ databaseResolution.pgliteDataDir,
1587
+ );
1588
+ if (!lockResult.ok) {
1589
+ const errMsg = lockResult.error;
1590
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
1591
+ this.databaseSnapshot,
1592
+ "locked",
1593
+ {
1594
+ error: errMsg,
1595
+ lock: lockResult.snapshot,
1596
+ },
1597
+ );
1598
+ this.persistStartupDiagnostics(errMsg);
1599
+ this.status = {
1600
+ state: "error",
1601
+ agentName: null,
1602
+ port: apiPort,
1603
+ startedAt: null,
1604
+ error: errMsg,
1605
+ };
1606
+ this.emitStatus();
1607
+ return this.status;
1608
+ }
1609
+ this.databaseStartupLock = lockResult.lock;
1610
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
1611
+ this.databaseSnapshot,
1612
+ "starting",
1613
+ {
1614
+ lock: lockResult.lock.snapshot,
1615
+ },
1616
+ );
1617
+ this.persistStartupDiagnostics();
1618
+ } catch (error) {
1619
+ const message =
1620
+ error instanceof Error ? error.message : String(error);
1621
+ const status = classifyDatabaseError(message);
1622
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
1623
+ this.databaseSnapshot,
1624
+ status,
1625
+ {
1626
+ error: message,
1627
+ },
1628
+ );
1629
+ this.persistStartupDiagnostics(message);
1630
+ this.status = {
1631
+ state: "error",
1632
+ agentName: null,
1633
+ port: apiPort,
1634
+ startedAt: null,
1635
+ error: message,
1636
+ };
1637
+ this.emitStatus();
1638
+ return this.status;
1639
+ }
1640
+ } else if (
1641
+ databaseResolution.mode === "postgres" ||
1642
+ databaseResolution.mode === "pglite-memory"
1643
+ ) {
1644
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
1645
+ this.databaseSnapshot,
1646
+ "starting",
1647
+ );
1648
+ this.persistStartupDiagnostics();
1649
+ }
1650
+
1651
+ applyWindowsNativeInferenceDefaults(childEnv);
1652
+ applyPackagedStartupEmbeddingWarmupPolicy(childEnv, packagedRuntime);
1653
+ applyDesktopDeferAppRoutesPolicy(childEnv);
1654
+
1655
+ if (nodePaths.length > 0) {
1656
+ childEnv.NODE_PATH = nodePaths.join(path.delimiter);
1657
+ diagnosticLog(`[Agent] Child NODE_PATH: ${childEnv.NODE_PATH}`);
1658
+ }
1659
+
1660
+ const bunExecutable = resolveBunExecutablePath();
1661
+ diagnosticLog(`[Agent] Using Bun executable: ${bunExecutable}`);
1662
+ diagnosticLog(
1663
+ `[Agent] Bun exists on disk: ${fs.existsSync(bunExecutable)}`,
1664
+ );
1665
+
1666
+ // Ensure bun's directory is on PATH so child_process.exec calls
1667
+ // (e.g. plugin-manager running `bun add ...`) can find it.
1668
+ const bunDir = path.dirname(bunExecutable);
1669
+ if (prependDesktopChildPathDirectory(childEnv, bunDir)) {
1670
+ diagnosticLog(`[Agent] Prepended bun dir to child PATH: ${bunDir}`);
1671
+ }
1672
+
1673
+ // Spawn the child process
1674
+ const spawnTime = Date.now();
1675
+ const proc = Bun.spawn(
1676
+ [bunExecutable, "run", runtimeEntryPath, "start"],
1677
+ {
1678
+ cwd: runtimeDistPath,
1679
+ env: childEnv,
1680
+ stdout: "pipe",
1681
+ stderr: "pipe",
1682
+ },
1683
+ );
1684
+
1685
+ this.childProcess = proc;
1686
+ diagnosticLog(
1687
+ `[Agent] Child spawned pid=${proc.pid} elapsed=${Date.now() - spawnTime}ms`,
1688
+ );
1689
+ recordStartupPhase("child_spawned", {
1690
+ port: apiPort,
1691
+ child_pid: proc.pid,
1692
+ });
1693
+
1694
+ // Set up abort controller for stdio watchers
1695
+ this.stdioAbortController = new AbortController();
1696
+ const { signal } = this.stdioAbortController;
1697
+
1698
+ // Surface the port immediately while waiting for ready
1699
+ this.status = {
1700
+ ...this.status,
1701
+ port: apiPort,
1702
+ };
1703
+ this.emitStatus();
1704
+
1705
+ // Track whether we detected the "listening" message from stdout
1706
+ let detectedListening = false;
1707
+
1708
+ // Watch stdout for "listening on port" or similar ready messages
1709
+ if (proc.stdout) {
1710
+ watchStdoutForReady(
1711
+ proc.stdout,
1712
+ (line: string) => {
1713
+ diagnosticLog(`[Agent][stdout] ${line}`);
1714
+ const lower = line.toLowerCase();
1715
+ // Parse dynamic port from "[eliza-api] Listening on http://host:PORT"
1716
+ const portMatch = line.match(
1717
+ /Listening on https?:\/\/[^:]+:(\d+)/i,
1718
+ );
1719
+ if (portMatch) {
1720
+ const parsedPort = parseInt(portMatch[1], 10);
1721
+ if (!Number.isNaN(parsedPort) && parsedPort > 0) {
1722
+ if (parsedPort !== apiPort) {
1723
+ diagnosticLog(
1724
+ `[Agent] Server bound to dynamic port ${parsedPort} (requested ${apiPort})`,
1725
+ );
1726
+ apiPort = parsedPort;
1727
+ }
1728
+ detectedListening = true;
1729
+ }
1730
+ } else if (
1731
+ lower.includes("listening on port") ||
1732
+ lower.includes("server started") ||
1733
+ lower.includes("ready on")
1734
+ ) {
1735
+ detectedListening = true;
1736
+ }
1737
+ // Update status port so callers see the actual bound port
1738
+ this.status = { ...this.status, port: apiPort };
1739
+ this.emitStatus();
1740
+ },
1741
+ signal,
1742
+ ).catch(() => {
1743
+ // Stream ended or aborted -- expected on shutdown
1744
+ });
1745
+ }
1746
+
1747
+ // Drain stderr to diagnostic log; detect PGLite migration failures
1748
+ this.hasPgliteError = false;
1749
+ if (proc.stderr) {
1750
+ drainStderrToLog(proc.stderr, signal, (line) => {
1751
+ this.updateDatabaseSnapshotFromRuntimeLog(line);
1752
+ if (shouldAutoRecoverPgliteFailure(line)) {
1753
+ this.hasPgliteError = true;
1754
+ }
1755
+ }).catch(() => {
1756
+ // Stream ended or aborted -- expected on shutdown
1757
+ });
1758
+ }
1759
+
1760
+ // Monitor child process exit
1761
+ this.monitorChildExit(proc);
1762
+
1763
+ // Wait for the health endpoint to respond
1764
+ // Use a getter so the health check follows dynamic port reassignment from stdout
1765
+ diagnosticLog(
1766
+ `[Agent] Waiting for health endpoint at http://127.0.0.1:${apiPort}/api/health ...`,
1767
+ );
1768
+ this.setStartupPhase("waiting_for_health");
1769
+ const healthPollTimeoutMs = getHealthPollTimeoutMs();
1770
+ const healthy = await waitForHealthy(
1771
+ () => apiPort,
1772
+ healthPollTimeoutMs,
1773
+ proc,
1774
+ );
1775
+
1776
+ if (!healthy) {
1777
+ // Check if process already exited
1778
+ if (proc.exitCode !== null) {
1779
+ const errMsg = `Child process exited with code ${proc.exitCode} before becoming healthy`;
1780
+ diagnosticLog(`[Agent] ${errMsg}`);
1781
+ this.childProcess = null;
1782
+ this.status = {
1783
+ state: "error",
1784
+ agentName: null,
1785
+ port: apiPort,
1786
+ startedAt: null,
1787
+ error: errMsg,
1788
+ };
1789
+ recordStartupPhase("fatal", {
1790
+ port: apiPort,
1791
+ child_pid: proc.pid,
1792
+ error: errMsg,
1793
+ exit_code: proc.exitCode,
1794
+ });
1795
+ this.setStartupPhase("startup_failed", errMsg);
1796
+ recordStartupPhase("fatal", {
1797
+ port: apiPort,
1798
+ child_pid: proc.pid,
1799
+ error: errMsg,
1800
+ exit_code: proc.exitCode,
1801
+ });
1802
+ this.releaseDatabaseStartupLock();
1803
+ this.emitStatus();
1804
+ return this.status;
1805
+ }
1806
+
1807
+ const errMsg = detectedListening
1808
+ ? "Server reported listening but health check timed out"
1809
+ : `Health check timed out after ${healthPollTimeoutMs}ms`;
1810
+ diagnosticLog(`[Agent] ${errMsg}`);
1811
+ this.status = {
1812
+ state: "error",
1813
+ agentName: null,
1814
+ port: apiPort,
1815
+ startedAt: null,
1816
+ error: errMsg,
1817
+ };
1818
+ recordStartupPhase("fatal", {
1819
+ port: apiPort,
1820
+ child_pid: proc.pid,
1821
+ error: errMsg,
1822
+ });
1823
+ this.setStartupPhase("startup_failed", errMsg);
1824
+ recordStartupPhase("fatal", {
1825
+ port: apiPort,
1826
+ child_pid: proc.pid,
1827
+ error: errMsg,
1828
+ });
1829
+ this.releaseDatabaseStartupLock();
1830
+ this.emitStatus();
1831
+ return this.status;
1832
+ }
1833
+ recordStartupPhase("health_ready", {
1834
+ port: apiPort,
1835
+ child_pid: proc.pid,
1836
+ });
1837
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
1838
+ this.databaseSnapshot,
1839
+ "ready",
1840
+ {
1841
+ migrationStatus:
1842
+ this.databaseSnapshot.migrationStatus?.failed === true
1843
+ ? this.databaseSnapshot.migrationStatus
1844
+ : {
1845
+ running: false,
1846
+ completed: true,
1847
+ failed: false,
1848
+ },
1849
+ lock: {
1850
+ held: false,
1851
+ },
1852
+ },
1853
+ );
1854
+ this.releaseDatabaseStartupLock();
1855
+
1856
+ this.setStartupPhase("fetching_agent_metadata");
1857
+ const startedAt = Date.now();
1858
+ const startupMs = startedAt - spawnTime;
1859
+
1860
+ this.status = {
1861
+ state: "running",
1862
+ agentName: getBrandConfig().appName,
1863
+ port: apiPort,
1864
+ startedAt,
1865
+ error: null,
1866
+ };
1867
+ this.setStartupPhase("ready", null);
1868
+ this.emitStatus();
1869
+ diagnosticLog(
1870
+ `[Agent] Runtime ready -- port: ${apiPort}, pid: ${proc.pid}, startup_ms: ${startupMs}`,
1871
+ );
1872
+ recordStartupPhase("runtime_ready", {
1873
+ port: apiPort,
1874
+ child_pid: proc.pid,
1875
+ });
1876
+ void this.refreshAgentMetadata(proc, apiPort, startupMs);
1877
+ return this.status;
1878
+ } catch (err) {
1879
+ const errMsg =
1880
+ err instanceof Error ? err.stack || err.message : String(err);
1881
+ diagnosticLog(`[Agent] Failed to start: ${errMsg}`);
1882
+ recordStartupPhase("fatal", {
1883
+ port: this.status.port,
1884
+ error: errMsg,
1885
+ });
1886
+
1887
+ // Clean up child if it was spawned
1888
+ if (this.childProcess) {
1889
+ await this.killChildProcess();
1890
+ }
1891
+ this.releaseDatabaseStartupLock();
1892
+
1893
+ this.status = {
1894
+ state: "error",
1895
+ agentName: null,
1896
+ port: this.status.port, // preserve port if set
1897
+ startedAt: null,
1898
+ error: shortError(err),
1899
+ };
1900
+ this.setStartupPhase("startup_failed", shortError(err));
1901
+ this.emitStatus();
1902
+ return this.status;
1903
+ }
1904
+ }
1905
+
1906
+ /** Stop the agent runtime. */
1907
+ async stop(): Promise<void> {
1908
+ if (this.status.state !== "running" && this.status.state !== "starting") {
1909
+ return;
1910
+ }
1911
+
1912
+ diagnosticLog("[Agent] Stopping...");
1913
+ this.setStartupPhase("stopping");
1914
+
1915
+ // Abort stdio watchers
1916
+ if (this.stdioAbortController) {
1917
+ this.stdioAbortController.abort();
1918
+ this.stdioAbortController = null;
1919
+ }
1920
+
1921
+ await this.killChildProcess();
1922
+ this.releaseDatabaseStartupLock();
1923
+
1924
+ this.status = {
1925
+ state: "stopped",
1926
+ agentName: this.status.agentName,
1927
+ port: null,
1928
+ startedAt: null,
1929
+ error: null,
1930
+ };
1931
+ this.setStartupPhase("stopped", null);
1932
+ this.emitStatus();
1933
+ diagnosticLog("[Agent] Runtime stopped");
1934
+ }
1935
+
1936
+ /**
1937
+ * Restart the agent runtime -- stops the current instance and starts a
1938
+ * fresh one, picking up config/plugin changes.
1939
+ */
1940
+ async restart(): Promise<AgentStatus> {
1941
+ diagnosticLog("[Agent] Restart requested -- stopping current runtime...");
1942
+ this.setStartupPhase("restart_requested");
1943
+ await this.stop();
1944
+ diagnosticLog("[Agent] Restarting...");
1945
+ return this.start();
1946
+ }
1947
+
1948
+ /**
1949
+ * Used after `POST /api/agent/reset`: stop the child, delete local PGLite
1950
+ * (conversations / agent memory under the active state-dir workspace),
1951
+ * then start fresh. Does not remove downloaded **GGUF** models (`MODELS_DIR`,
1952
+ * env-backed wallet keys, or eliza.json (the API reset already rewrote
1953
+ * config on disk).
1954
+ *
1955
+ * When `ELIZA_DESKTOP_API_BASE` points at an external dev API (e.g. :31337),
1956
+ * the embedded child is never used — this is a no-op so the renderer can
1957
+ * bounce the real API via `POST /api/agent/restart` instead.
1958
+ */
1959
+ async restartClearingLocalDb(): Promise<AgentStatus> {
1960
+ const runtimeMode = resolveDesktopRuntimeMode(
1961
+ process.env as Record<string, string | undefined>,
1962
+ );
1963
+ if (runtimeMode.mode !== "local") {
1964
+ diagnosticLog(
1965
+ `[Agent] restartClearingLocalDb skipped — mode=${runtimeMode.mode} externalBase=${runtimeMode.externalApi.base ?? "n/a"} source=${runtimeMode.externalApi.source ?? "n/a"} (renderer uses POST /api/agent/restart)`,
1966
+ );
1967
+ return this.getStatus();
1968
+ }
1969
+
1970
+ const dataDir = resolveManagedPgliteDataDir();
1971
+ if (!dataDir) {
1972
+ const message =
1973
+ "Local PGlite reset is unavailable for the active database mode.";
1974
+ diagnosticLog(`[Agent] restartClearingLocalDb skipped — ${message}`);
1975
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
1976
+ this.databaseSnapshot,
1977
+ "error",
1978
+ { error: message },
1979
+ );
1980
+ return this.getStatus();
1981
+ }
1982
+
1983
+ diagnosticLog(
1984
+ `[Agent] restartClearingLocalDb: local mode — stop → backup/reset PGLite (${dataDir}) → start`,
1985
+ );
1986
+ await this.stop();
1987
+ this.hasPgliteError = false;
1988
+ this.pgliteRecoveryDone = false;
1989
+ const reset = resetPgliteDirectory(dataDir);
1990
+ diagnosticLog(
1991
+ `[Agent] PGLite backup/reset completed backup=${reset.backup.backupDir ?? "none"} removed=${reset.removed}`,
1992
+ );
1993
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
1994
+ this.databaseSnapshot,
1995
+ "starting",
1996
+ { error: null },
1997
+ );
1998
+ const next = await this.start();
1999
+ diagnosticLog(
2000
+ `[Agent] restartClearingLocalDb: start() finished state=${next.state} port=${next.port ?? "null"}`,
2001
+ );
2002
+ return next;
2003
+ }
2004
+
2005
+ getStatus(): AgentStatus {
2006
+ return { ...this.status };
2007
+ }
2008
+
2009
+ getDatabaseSnapshot(): DatabaseSnapshot {
2010
+ return this.databaseSnapshot;
2011
+ }
2012
+
2013
+ previewDatabaseRecovery(): {
2014
+ snapshot: DatabaseSnapshot;
2015
+ actions: DatabaseSnapshot["recoveryActions"];
2016
+ } {
2017
+ return {
2018
+ snapshot: this.databaseSnapshot,
2019
+ actions: this.databaseSnapshot.recoveryActions,
2020
+ };
2021
+ }
2022
+
2023
+ backupPgliteDatabase(): ReturnType<typeof backupPgliteDirectory> {
2024
+ const dataDir =
2025
+ this.databaseSnapshot.pgliteDataDir ?? resolveManagedPgliteDataDir();
2026
+ if (!dataDir) {
2027
+ throw new Error("No persistent PGlite data directory is active.");
2028
+ }
2029
+ const result = backupPgliteDirectory(dataDir);
2030
+ diagnosticLog(
2031
+ `[Agent] PGLite backup created: ${result.backupDir ?? "none"} reason=${result.reason ?? "created"}`,
2032
+ );
2033
+ return result;
2034
+ }
2035
+
2036
+ async resetPgliteDatabase(params?: {
2037
+ restart?: boolean;
2038
+ }): Promise<
2039
+ ReturnType<typeof resetPgliteDirectory> & { restarted: boolean }
2040
+ > {
2041
+ const dataDir =
2042
+ this.databaseSnapshot.pgliteDataDir ?? resolveManagedPgliteDataDir();
2043
+ if (!dataDir) {
2044
+ throw new Error("No persistent PGlite data directory is active.");
2045
+ }
2046
+ await this.stop();
2047
+ const result = resetPgliteDirectory(dataDir);
2048
+ diagnosticLog(
2049
+ `[Agent] PGLite reset completed backup=${result.backup.backupDir ?? "none"} removed=${result.removed}`,
2050
+ );
2051
+ if (params?.restart === true) {
2052
+ await this.start();
2053
+ return { ...result, restarted: true };
2054
+ }
2055
+ return { ...result, restarted: false };
2056
+ }
2057
+
2058
+ inspectExistingInstall(): ExistingElizaInstallInfo {
2059
+ return inspectExistingElizaInstall();
2060
+ }
2061
+
2062
+ migrateStateDir(params: { fromPath: string }): StateDirMigrationResult {
2063
+ return migrateDesktopStateDirFromPath(params.fromPath);
2064
+ }
2065
+
2066
+ getPort(): number | null {
2067
+ return this.status.port;
2068
+ }
2069
+
2070
+ /** Clean up on app quit. */
2071
+ async dispose(): Promise<void> {
2072
+ if (this.stdioAbortController) {
2073
+ this.stdioAbortController.abort();
2074
+ this.stdioAbortController = null;
2075
+ }
2076
+ try {
2077
+ await this.killChildProcess();
2078
+ this.releaseDatabaseStartupLock();
2079
+ } catch (err) {
2080
+ logger.warn(
2081
+ `[Agent] dispose error: ${err instanceof Error ? err.message : String(err)}`,
2082
+ );
2083
+ }
2084
+ }
2085
+
2086
+ // -----------------------------------------------------------------------
2087
+ // Private helpers
2088
+ // -----------------------------------------------------------------------
2089
+
2090
+ private emitStatus(): void {
2091
+ this.persistStartupDiagnostics();
2092
+ if (this.sendToWebview) {
2093
+ this.sendToWebview("agentStatusUpdate", this.status);
2094
+ }
2095
+ const statusSnapshot = { ...this.status };
2096
+ for (const listener of this.statusListeners) {
2097
+ try {
2098
+ listener(statusSnapshot);
2099
+ } catch (err) {
2100
+ logger.warn(
2101
+ `[Agent] status listener failed: ${err instanceof Error ? err.message : String(err)}`,
2102
+ );
2103
+ }
2104
+ }
2105
+ }
2106
+
2107
+ private async refreshAgentMetadata(
2108
+ proc: BunSubprocess,
2109
+ port: number,
2110
+ startupMs: number,
2111
+ ): Promise<void> {
2112
+ const agentName = await this.fetchAgentName(port);
2113
+ if (
2114
+ this.childProcess !== proc ||
2115
+ this.status.state !== "running" ||
2116
+ this.status.port !== port
2117
+ ) {
2118
+ return;
2119
+ }
2120
+
2121
+ if (this.status.agentName !== agentName) {
2122
+ this.status = {
2123
+ ...this.status,
2124
+ agentName,
2125
+ };
2126
+ this.emitStatus();
2127
+ }
2128
+
2129
+ diagnosticLog(
2130
+ `[Agent] Runtime started -- agent: ${agentName}, port: ${port}, pid: ${proc.pid}, startup_ms: ${startupMs}`,
2131
+ );
2132
+ recordStartupPhase("metadata_ready", {
2133
+ port,
2134
+ child_pid: proc.pid,
2135
+ });
2136
+ }
2137
+ private setStartupPhase(phase: string, lastError?: string | null): void {
2138
+ this.startupPhase = phase;
2139
+ this.persistStartupDiagnostics(lastError);
2140
+ }
2141
+
2142
+ private persistStartupDiagnostics(lastError?: string | null): void {
2143
+ writeStartupDiagnosticsSnapshot({
2144
+ state: this.status.state,
2145
+ phase: this.startupPhase,
2146
+ updatedAt: new Date().toISOString(),
2147
+ lastError: lastError ?? this.status.error,
2148
+ agentName: this.status.agentName,
2149
+ port: this.status.port,
2150
+ startedAt: this.status.startedAt,
2151
+ platform: process.platform,
2152
+ arch: process.arch,
2153
+ configDir: resolveConfigDir(),
2154
+ logPath: getDiagnosticLogPath(),
2155
+ statusPath: getStartupStatusPath(),
2156
+ database: this.databaseSnapshot,
2157
+ });
2158
+ }
2159
+
2160
+ private releaseDatabaseStartupLock(): void {
2161
+ if (!this.databaseStartupLock) return;
2162
+ this.databaseStartupLock.release();
2163
+ this.databaseStartupLock = null;
2164
+ }
2165
+
2166
+ private updateDatabaseSnapshotFromRuntimeLog(line: string): void {
2167
+ const lower = line.toLowerCase();
2168
+ if (lower.includes("starting migrations")) {
2169
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
2170
+ this.databaseSnapshot,
2171
+ "migrating",
2172
+ {
2173
+ migrationStatus: {
2174
+ running: true,
2175
+ completed: false,
2176
+ failed: false,
2177
+ },
2178
+ },
2179
+ );
2180
+ this.persistStartupDiagnostics();
2181
+ recordStartupPhase("database_migration_started", {
2182
+ port: this.status.port,
2183
+ });
2184
+ return;
2185
+ }
2186
+ if (lower.includes("all migrations completed successfully")) {
2187
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
2188
+ this.databaseSnapshot,
2189
+ "starting",
2190
+ {
2191
+ migrationStatus: {
2192
+ running: false,
2193
+ completed: true,
2194
+ failed: false,
2195
+ },
2196
+ },
2197
+ );
2198
+ this.persistStartupDiagnostics();
2199
+ recordStartupPhase("database_migration_completed", {
2200
+ port: this.status.port,
2201
+ });
2202
+ return;
2203
+ }
2204
+ if (
2205
+ lower.includes("migration failed") ||
2206
+ lower.includes("migration(s) failed")
2207
+ ) {
2208
+ const pluginMatch = line.match(/pluginName[":=\s]+["']?([^"',\s}]+)/);
2209
+ const error = redactSensitiveDiagnostics(line);
2210
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
2211
+ this.databaseSnapshot,
2212
+ "migration-failed",
2213
+ {
2214
+ error,
2215
+ migrationStatus: {
2216
+ running: false,
2217
+ completed: false,
2218
+ failed: true,
2219
+ failedPlugin: pluginMatch?.[1],
2220
+ error,
2221
+ },
2222
+ },
2223
+ );
2224
+ this.persistStartupDiagnostics(error);
2225
+ recordStartupPhase("database_migration_failed", {
2226
+ port: this.status.port,
2227
+ error,
2228
+ });
2229
+ return;
2230
+ }
2231
+ const status = classifyDatabaseError(line);
2232
+ if (status === "error") return;
2233
+ const error = redactSensitiveDiagnostics(line);
2234
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
2235
+ this.databaseSnapshot,
2236
+ status,
2237
+ { error },
2238
+ );
2239
+ this.persistStartupDiagnostics(error);
2240
+ }
2241
+
2242
+ /**
2243
+ * Monitor the child process for unexpected exits and update status.
2244
+ */
2245
+ private monitorChildExit(proc: BunSubprocess): void {
2246
+ // Bun.spawn provides an `exited` promise that resolves when the process exits
2247
+ proc.exited
2248
+ .then((exitCode: number) => {
2249
+ // Only update status if this is still our active child process
2250
+ if (this.childProcess !== proc) return;
2251
+
2252
+ const wasRunning = this.status.state === "running";
2253
+ const wasStarting = this.status.state === "starting";
2254
+
2255
+ if (wasRunning || wasStarting) {
2256
+ diagnosticLog(
2257
+ `[Agent] Child process exited unexpectedly with code ${exitCode} (pid: ${proc.pid})`,
2258
+ );
2259
+ recordStartupPhase("fatal", {
2260
+ port: this.status.port,
2261
+ child_pid: proc.pid,
2262
+ error: `Process exited unexpectedly with code ${exitCode}`,
2263
+ exit_code: exitCode,
2264
+ });
2265
+ this.childProcess = null;
2266
+
2267
+ if (this.hasPgliteError && !this.pgliteRecoveryDone) {
2268
+ this.pgliteRecoveryDone = true;
2269
+ const error =
2270
+ "PGLite startup or migration failed. Use database recovery to backup/reset local data or switch to Postgres.";
2271
+ diagnosticLog(`[Agent] ${error}`);
2272
+ this.databaseSnapshot = updateDatabaseSnapshotStatus(
2273
+ this.databaseSnapshot,
2274
+ classifyDatabaseError(error),
2275
+ { error },
2276
+ );
2277
+ }
2278
+
2279
+ this.status = {
2280
+ state: "error",
2281
+ agentName: this.status.agentName,
2282
+ port: this.status.port,
2283
+ startedAt: null,
2284
+ error: `Process exited unexpectedly with code ${exitCode}`,
2285
+ };
2286
+ this.setStartupPhase(
2287
+ "process_exited_unexpectedly",
2288
+ `Process exited unexpectedly with code ${exitCode}`,
2289
+ );
2290
+ this.releaseDatabaseStartupLock();
2291
+ this.emitStatus();
2292
+ } else {
2293
+ // Expected exit (we called stop)
2294
+ this.childProcess = null;
2295
+ this.releaseDatabaseStartupLock();
2296
+ }
2297
+ })
2298
+ .catch((err: unknown) => {
2299
+ if (this.childProcess !== proc) return;
2300
+ diagnosticLog(
2301
+ `[Agent] Child process exited with error: ${err instanceof Error ? err.message : String(err)}`,
2302
+ );
2303
+ recordStartupPhase("fatal", {
2304
+ port: this.status.port,
2305
+ child_pid: proc.pid,
2306
+ error: err instanceof Error ? err.message : String(err),
2307
+ });
2308
+ this.childProcess = null;
2309
+ this.releaseDatabaseStartupLock();
2310
+ if (
2311
+ this.status.state === "running" ||
2312
+ this.status.state === "starting"
2313
+ ) {
2314
+ this.status = {
2315
+ state: "error",
2316
+ agentName: this.status.agentName,
2317
+ port: this.status.port,
2318
+ startedAt: null,
2319
+ error: shortError(err),
2320
+ };
2321
+ this.setStartupPhase("process_exit_error", shortError(err));
2322
+ this.emitStatus();
2323
+ }
2324
+ });
2325
+ }
2326
+
2327
+ /**
2328
+ * Kill the child process gracefully with SIGTERM, escalating to SIGKILL
2329
+ * after a timeout.
2330
+ */
2331
+ private async killChildProcess(): Promise<void> {
2332
+ const proc = this.childProcess;
2333
+ if (!proc) return;
2334
+
2335
+ this.childProcess = null;
2336
+
2337
+ // Already exited
2338
+ if (proc.exitCode !== null) return;
2339
+
2340
+ diagnosticLog(`[Agent] Sending SIGTERM to pid ${proc.pid}`);
2341
+ proc.kill("SIGTERM");
2342
+
2343
+ // Wait for graceful shutdown or timeout
2344
+ const exited = await Promise.race([
2345
+ proc.exited.then(() => true as const),
2346
+ Bun.sleep(SIGTERM_GRACE_MS).then(() => false as const),
2347
+ ]);
2348
+
2349
+ if (!exited) {
2350
+ diagnosticLog(
2351
+ `[Agent] Process did not exit within ${SIGTERM_GRACE_MS}ms, sending SIGKILL`,
2352
+ );
2353
+ try {
2354
+ proc.kill("SIGKILL");
2355
+ } catch {
2356
+ // Process may have already exited between check and kill
2357
+ }
2358
+ // Wait briefly for SIGKILL to take effect
2359
+ await Promise.race([proc.exited.catch(() => {}), Bun.sleep(1_000)]);
2360
+ }
2361
+
2362
+ diagnosticLog("[Agent] Child process terminated");
2363
+ }
2364
+
2365
+ /**
2366
+ * Attempt to fetch the agent name from the running API server.
2367
+ * Falls back to the configured desktop app name if the endpoint is unavailable.
2368
+ */
2369
+ private async fetchAgentName(port: number): Promise<string> {
2370
+ try {
2371
+ const headers = getDesktopApiHeaders();
2372
+ const response = await fetch(`http://127.0.0.1:${port}/api/agents`, {
2373
+ headers,
2374
+ signal: AbortSignal.timeout(AGENT_NAME_FETCH_TIMEOUT_MS),
2375
+ });
2376
+ if (response.ok) {
2377
+ const data = (await response.json()) as
2378
+ | { agents?: Array<{ name?: string }> }
2379
+ | Array<{ name?: string }>;
2380
+ const agents = Array.isArray(data) ? data : data.agents;
2381
+ if (agents && agents.length > 0 && agents[0].name) {
2382
+ return agents[0].name;
2383
+ }
2384
+ }
2385
+ } catch {
2386
+ diagnosticLog("[Agent] Could not fetch agent name, using default");
2387
+ }
2388
+ return getBrandConfig().appName;
2389
+ }
1950
2390
  }
1951
2391
 
1952
2392
  // ---------------------------------------------------------------------------
@@ -1956,8 +2396,8 @@ export class AgentManager {
1956
2396
  let agentManager: AgentManager | null = null;
1957
2397
 
1958
2398
  export function getAgentManager(): AgentManager {
1959
- if (!agentManager) {
1960
- agentManager = new AgentManager();
1961
- }
1962
- return agentManager;
2399
+ if (!agentManager) {
2400
+ agentManager = new AgentManager();
2401
+ }
2402
+ return agentManager;
1963
2403
  }