@elizaos/app-core 2.0.3-beta.6 → 2.0.3-beta.7

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 (36) hide show
  1. package/package.json +37 -36
  2. package/platforms/electrobun/package.json +10 -10
  3. package/platforms/electrobun/remotes/fs/README.md +0 -1
  4. package/platforms/electrobun/remotes/fs/package.json +0 -1
  5. package/platforms/electrobun/remotes/git/README.md +1 -2
  6. package/platforms/electrobun/remotes/git/package.json +0 -1
  7. package/platforms/electrobun/remotes/local-model/README.md +0 -1
  8. package/platforms/electrobun/remotes/local-model/package.json +0 -1
  9. package/platforms/electrobun/remotes/pty/README.md +1 -2
  10. package/platforms/electrobun/remotes/pty/package.json +0 -1
  11. package/platforms/electrobun/remotes/runtime/README.md +1 -5
  12. package/platforms/electrobun/remotes/runtime/package.json +0 -1
  13. package/platforms/electrobun/remotes/surface/README.md +1 -2
  14. package/platforms/electrobun/remotes/surface/package.json +0 -1
  15. package/platforms/electrobun/src/api-base.ts +11 -2
  16. package/platforms/electrobun/src/bridge/electrobun-direct-rpc.ts +15 -1
  17. package/platforms/electrobun/src/index.ts +25 -28
  18. package/platforms/electrobun/src/lifecycle/api-base-owner.test.ts +67 -5
  19. package/platforms/electrobun/src/lifecycle/api-base-owner.ts +36 -6
  20. package/platforms/electrobun/src/native/desktop.ts +1 -1
  21. package/platforms/electrobun/src/onboarding-overlay-window.ts +7 -8
  22. package/platforms/electrobun/src/preload.js +1 -1
  23. package/platforms/electrobun/src/rpc-schema.ts +5 -1
  24. package/runtime/voice-warmup.d.ts.map +1 -1
  25. package/runtime/voice-warmup.js +8 -2
  26. package/scripts/build-image.sh +5 -2
  27. package/scripts/bun-riscv64/build.sh +12 -6
  28. package/scripts/bun-riscv64/run-build.sh +10 -1
  29. package/scripts/dev-platform.mjs +19 -10
  30. package/scripts/ios-xcframework/README.md +15 -9
  31. package/scripts/ios-xcframework/run-physical-device-smoke.mjs +5 -3
  32. package/scripts/playwright-ui-live-stack.ts +32 -8
  33. package/platforms/electrobun/src/desktop-pill-config.test.ts +0 -27
  34. package/platforms/electrobun/src/desktop-pill-config.ts +0 -40
  35. package/platforms/electrobun/src/pill-window.test.ts +0 -91
  36. package/platforms/electrobun/src/pill-window.ts +0 -99
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/app-core",
3
- "version": "2.0.3-beta.6",
3
+ "version": "2.0.3-beta.7",
4
4
  "description": "Shared application core for elizaOS white-label agent apps.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -155,22 +155,22 @@
155
155
  "three": "^0.184.0"
156
156
  },
157
157
  "optionalDependencies": {
158
- "@elizaos/capacitor-appblocker": "2.0.3-beta.6",
159
- "@elizaos/capacitor-bun-runtime": "2.0.3-beta.6",
160
- "@elizaos/capacitor-camera": "2.0.3-beta.6",
161
- "@elizaos/capacitor-canvas": "2.0.3-beta.6",
162
- "@elizaos/capacitor-contacts": "2.0.3-beta.6",
163
- "@elizaos/capacitor-gateway": "2.0.3-beta.6",
164
- "@elizaos/capacitor-location": "2.0.3-beta.6",
165
- "@elizaos/capacitor-messages": "2.0.3-beta.6",
166
- "@elizaos/capacitor-mobile-agent-bridge": "2.0.3-beta.6",
167
- "@elizaos/capacitor-mobile-signals": "2.0.3-beta.6",
168
- "@elizaos/capacitor-phone": "2.0.3-beta.6",
169
- "@elizaos/capacitor-screencapture": "2.0.3-beta.6",
170
- "@elizaos/capacitor-swabble": "2.0.3-beta.6",
171
- "@elizaos/capacitor-system": "2.0.3-beta.6",
172
- "@elizaos/capacitor-talkmode": "2.0.3-beta.6",
173
- "@elizaos/capacitor-websiteblocker": "2.0.3-beta.6",
158
+ "@elizaos/capacitor-appblocker": "2.0.3-beta.7",
159
+ "@elizaos/capacitor-bun-runtime": "2.0.3-beta.7",
160
+ "@elizaos/capacitor-camera": "2.0.3-beta.7",
161
+ "@elizaos/capacitor-canvas": "2.0.3-beta.7",
162
+ "@elizaos/capacitor-contacts": "2.0.3-beta.7",
163
+ "@elizaos/capacitor-gateway": "2.0.3-beta.7",
164
+ "@elizaos/capacitor-location": "2.0.3-beta.7",
165
+ "@elizaos/capacitor-messages": "2.0.3-beta.7",
166
+ "@elizaos/capacitor-mobile-agent-bridge": "2.0.3-beta.7",
167
+ "@elizaos/capacitor-mobile-signals": "2.0.3-beta.7",
168
+ "@elizaos/capacitor-phone": "2.0.3-beta.7",
169
+ "@elizaos/capacitor-screencapture": "2.0.3-beta.7",
170
+ "@elizaos/capacitor-swabble": "2.0.3-beta.7",
171
+ "@elizaos/capacitor-system": "2.0.3-beta.7",
172
+ "@elizaos/capacitor-talkmode": "2.0.3-beta.7",
173
+ "@elizaos/capacitor-websiteblocker": "2.0.3-beta.7",
174
174
  "sharp": "^0.34.5"
175
175
  },
176
176
  "dependencies": {
@@ -184,24 +184,25 @@
184
184
  "@capacitor/preferences": "^8.0.1",
185
185
  "@capacitor/push-notifications": "^8.0.0",
186
186
  "@clack/prompts": "^1.0.0",
187
- "@elizaos/core": "2.0.3-beta.6",
188
- "@elizaos/plugin-anthropic": "2.0.3-beta.6",
189
- "@elizaos/plugin-browser": "2.0.3-beta.6",
190
- "@elizaos/plugin-edge-tts": "2.0.3-beta.6",
191
- "@elizaos/plugin-elizacloud": "2.0.3-beta.6",
192
- "@elizaos/plugin-groq": "2.0.3-beta.6",
193
- "@elizaos/plugin-health": "2.0.3-beta.6",
194
- "@elizaos/plugin-local-inference": "2.0.3-beta.6",
195
- "@elizaos/plugin-openai": "2.0.3-beta.6",
196
- "@elizaos/plugin-registry": "2.0.3-beta.6",
197
- "@elizaos/plugin-sql": "2.0.3-beta.6",
198
- "@elizaos/plugin-wechat": "2.0.3-beta.6",
199
- "@elizaos/plugin-workflow": "2.0.3-beta.6",
200
- "@elizaos/registry": "2.0.3-beta.6",
201
- "@elizaos/shared": "2.0.3-beta.6",
202
- "@elizaos/skills": "2.0.3-beta.6",
203
- "@elizaos/ui": "2.0.3-beta.6",
204
- "@elizaos/vault": "2.0.3-beta.6",
187
+ "@elizaos/agent": "2.0.3-beta.7",
188
+ "@elizaos/core": "2.0.3-beta.7",
189
+ "@elizaos/plugin-anthropic": "2.0.3-beta.7",
190
+ "@elizaos/plugin-browser": "2.0.3-beta.7",
191
+ "@elizaos/plugin-edge-tts": "2.0.3-beta.7",
192
+ "@elizaos/plugin-elizacloud": "2.0.3-beta.7",
193
+ "@elizaos/plugin-groq": "2.0.3-beta.7",
194
+ "@elizaos/plugin-health": "2.0.3-beta.7",
195
+ "@elizaos/plugin-local-inference": "2.0.3-beta.7",
196
+ "@elizaos/plugin-openai": "2.0.3-beta.7",
197
+ "@elizaos/plugin-registry": "2.0.3-beta.7",
198
+ "@elizaos/plugin-sql": "2.0.3-beta.7",
199
+ "@elizaos/plugin-wechat": "2.0.3-beta.7",
200
+ "@elizaos/plugin-workflow": "2.0.3-beta.7",
201
+ "@elizaos/registry": "2.0.3-beta.7",
202
+ "@elizaos/shared": "2.0.3-beta.7",
203
+ "@elizaos/skills": "2.0.3-beta.7",
204
+ "@elizaos/ui": "2.0.3-beta.7",
205
+ "@elizaos/vault": "2.0.3-beta.7",
205
206
  "@node-rs/argon2": "^2.0.2",
206
207
  "@upstash/redis": "^1.37.0",
207
208
  "chalk": "^5.3.0",
@@ -222,5 +223,5 @@
222
223
  },
223
224
  "module": "./index.js",
224
225
  "types": "./index.d.ts",
225
- "gitHead": "990dc996172b3e0fb525a75052a5ac28a4cd4de5"
226
+ "gitHead": "61094f10458d11055c75b3dd0bae374e3f66bac5"
226
227
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/electrobun",
3
- "version": "2.0.3-beta.6",
3
+ "version": "2.0.3-beta.7",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "assets",
@@ -25,14 +25,14 @@
25
25
  "build:native-effects": "bash scripts/build-macos-effects.sh"
26
26
  },
27
27
  "dependencies": {
28
- "@elizaos/agent": "2.0.3-beta.6",
29
- "@elizaos/app-core": "2.0.3-beta.6",
30
- "@elizaos/plugin-browser": "2.0.3-beta.6",
31
- "@elizaos/plugin-capacitor-bridge": "2.0.3-beta.6",
32
- "@elizaos/plugin-registry": "2.0.3-beta.6",
33
- "@elizaos/plugin-remote-manifest": "2.0.3-beta.6",
34
- "@elizaos/plugin-streaming": "2.0.3-beta.6",
35
- "@elizaos/shared": "2.0.3-beta.6",
28
+ "@elizaos/agent": "2.0.3-beta.7",
29
+ "@elizaos/app-core": "2.0.3-beta.7",
30
+ "@elizaos/plugin-browser": "2.0.3-beta.7",
31
+ "@elizaos/plugin-capacitor-bridge": "2.0.3-beta.7",
32
+ "@elizaos/plugin-registry": "2.0.3-beta.7",
33
+ "@elizaos/plugin-remote-manifest": "2.0.3-beta.7",
34
+ "@elizaos/plugin-streaming": "2.0.3-beta.7",
35
+ "@elizaos/shared": "2.0.3-beta.7",
36
36
  "bonjour-service": "1.4.2",
37
37
  "electrobun": "^1.18.1"
38
38
  },
@@ -46,5 +46,5 @@
46
46
  "publishConfig": {
47
47
  "access": "public"
48
48
  },
49
- "gitHead": "990dc996172b3e0fb525a75052a5ac28a4cd4de5"
49
+ "gitHead": "61094f10458d11055c75b3dd0bae374e3f66bac5"
50
50
  }
@@ -61,7 +61,6 @@ Environment overrides:
61
61
  ## Commands
62
62
 
63
63
  ```sh
64
- bun run --cwd elizalaunch/remotes/fs build
65
64
  bun run --cwd elizalaunch/remotes/fs smoke
66
65
  bun run --cwd elizalaunch/remotes/fs smoke:phase5
67
66
  bun run --cwd elizalaunch/remotes/fs typecheck
@@ -4,7 +4,6 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "bun build src/bun/worker.ts src/dev/phase5-smoke.ts --outdir dist --target bun",
8
7
  "smoke": "bun run src/dev/phase5-smoke.ts",
9
8
  "smoke:phase5": "bun run src/dev/phase5-smoke.ts",
10
9
  "typecheck": "tsc --ignoreConfig --noEmit --target ES2022 --module ESNext --moduleResolution Bundler --lib ES2022,DOM --types bun-types --allowImportingTsExtensions src/bun/protocol.ts src/bun/errors.ts src/bun/file-limits.ts src/bun/path-guard.ts src/bun/fs-service.ts src/bun/worker.ts src/dev/phase5-smoke.ts"
@@ -57,11 +57,10 @@ Each operation includes:
57
57
  - `ELIZA_GIT_COMMAND_TIMEOUT_MS` defaults to `120000`
58
58
  - `ELIZA_GIT_MAX_OPERATIONS` defaults to `200`
59
59
 
60
- ## Build And Smoke
60
+ ## Typecheck And Smoke
61
61
 
62
62
  ```sh
63
63
  bun run --cwd elizalaunch/remotes/git typecheck
64
- bun run --cwd elizalaunch/remotes/git build
65
64
  bun run --cwd elizalaunch/remotes/git smoke
66
65
  bun run --cwd elizalaunch/remotes/git smoke:phase7
67
66
  ```
@@ -4,7 +4,6 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "bun build src/bun/worker.ts src/dev/phase7-smoke.ts --outdir dist --target bun",
8
7
  "smoke": "bun run src/dev/phase7-smoke.ts",
9
8
  "smoke:phase7": "bun run src/dev/phase7-smoke.ts",
10
9
  "typecheck": "tsc --ignoreConfig --noEmit --target ES2022 --module ESNext --moduleResolution Bundler --lib ES2022,DOM --types bun-types --allowImportingTsExtensions src/bun/protocol.ts src/bun/errors.ts src/bun/operation-history.ts src/bun/git-command.ts src/bun/git-service.ts src/bun/worker.ts src/dev/phase7-smoke.ts"
@@ -94,7 +94,6 @@ The current route file does not expose direct local generation or direct embeddi
94
94
 
95
95
  ```sh
96
96
  bun run --cwd elizalaunch/remotes/local-model typecheck
97
- bun run --cwd elizalaunch/remotes/local-model build
98
97
  bun run --cwd elizalaunch/remotes/local-model smoke
99
98
  bun run --cwd elizalaunch/remotes/local-model smoke:phase8
100
99
  ```
@@ -4,7 +4,6 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "bun build src/bun/worker.ts src/dev/phase8-smoke.ts --outdir dist --target bun",
8
7
  "smoke": "bun run src/dev/phase8-smoke.ts",
9
8
  "smoke:phase8": "bun run src/dev/phase8-smoke.ts",
10
9
  "typecheck": "tsc --ignoreConfig --noEmit --target ES2022 --module ESNext --moduleResolution Bundler --lib ES2022,DOM --types bun-types --allowImportingTsExtensions src/bun/protocol.ts src/bun/errors.ts src/bun/eliza1-catalog.ts src/bun/hf-eliza1-client.ts src/bun/local-inference-api-client.ts src/bun/download-state.ts src/bun/model-service.ts src/bun/worker.ts src/dev/phase8-smoke.ts"
@@ -52,10 +52,9 @@ Output polling through `pty.session.output.tail` is sufficient for Phase 6 when
52
52
 
53
53
  Session environment inherits `process.env` and merges per-session env overrides.
54
54
 
55
- ## Build And Smoke
55
+ ## Smoke
56
56
 
57
57
  ```sh
58
- bun run --cwd elizalaunch/remotes/pty build
59
58
  bun run --cwd elizalaunch/remotes/pty smoke
60
59
  bun run --cwd elizalaunch/remotes/pty smoke:phase6
61
60
  ```
@@ -4,7 +4,6 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "bun build src/bun/worker.ts src/dev/phase6-smoke.ts --outdir dist --target bun",
8
7
  "smoke": "bun run src/dev/phase6-smoke.ts",
9
8
  "smoke:phase6": "bun run src/dev/phase6-smoke.ts",
10
9
  "typecheck": "tsc --ignoreConfig --noEmit --target ES2022 --module ESNext --moduleResolution Bundler --lib ES2022,DOM --types bun-types --allowImportingTsExtensions src/bun/protocol.ts src/bun/errors.ts src/bun/output-buffer.ts src/bun/pty-service.ts src/bun/worker.ts src/dev/phase6-smoke.ts"
@@ -206,11 +206,7 @@ Git:
206
206
 
207
207
  ## Run
208
208
 
209
- Build:
210
-
211
- ```sh
212
- bun run --cwd elizalaunch/remotes/runtime build
213
- ```
209
+ Remotes run from source (the runtime loads `src/bun/worker.ts` / `src/web/index.html` directly); there is no build step.
214
210
 
215
211
  Phase 1 smoke:
216
212
 
@@ -4,7 +4,6 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "bun build src/bun/worker.ts src/dev/phase1-smoke.ts src/dev/phase2-smoke.ts src/dev/phase3-smoke.ts --outdir dist --target bun",
8
7
  "smoke": "bun src/dev/phase1-smoke.ts",
9
8
  "smoke:phase1": "bun src/dev/phase1-smoke.ts",
10
9
  "smoke:phase2": "bun src/dev/phase2-smoke.ts",
@@ -106,10 +106,9 @@ It consumes:
106
106
  - `agent.message.stream.done`
107
107
  - `agent.message.stream.cancelled`
108
108
 
109
- ## Build and Smoke
109
+ ## Smoke
110
110
 
111
111
  ```sh
112
- bun run --cwd elizalaunch/remotes/surface build
113
112
  bun run --cwd elizalaunch/remotes/surface smoke
114
113
  bun run --cwd elizalaunch/remotes/surface smoke:phase4
115
114
  ```
@@ -4,7 +4,6 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "bun build src/bun/worker.ts src/dev/phase4-smoke.ts --outdir dist --target bun && bun build src/web/index.ts --outdir dist/web --target browser",
8
7
  "smoke": "bun run src/dev/phase4-smoke.ts",
9
8
  "smoke:phase4": "bun run src/dev/phase4-smoke.ts",
10
9
  "typecheck": "tsc --ignoreConfig --noEmit --target ES2022 --module ESNext --moduleResolution Bundler --lib ES2022,DOM,DOM.Iterable --types bun-types --allowImportingTsExtensions src/protocol/event-types.ts src/protocol/runtime-client.ts src/web/state.ts src/web/render.ts src/web/app.ts src/web/index.ts src/bun/worker.ts src/dev/phase4-smoke.ts"
@@ -256,7 +256,11 @@ export function resolveRendererFacingApiBase(
256
256
  */
257
257
  type ApiBaseUpdateRpc = {
258
258
  send?: {
259
- apiBaseUpdate?: (payload: { base: string; token?: string }) => void;
259
+ apiBaseUpdate?: (payload: {
260
+ base: string;
261
+ token?: string;
262
+ externalApiBase?: string | null;
263
+ }) => void;
260
264
  };
261
265
  };
262
266
 
@@ -264,9 +268,14 @@ export function pushApiBaseToRenderer(
264
268
  win: { webview: { rpc?: unknown } },
265
269
  base: string,
266
270
  apiToken?: string,
271
+ externalApiBase?: string | null,
267
272
  ): void {
268
273
  const trimmedToken = apiToken?.trim();
269
- const payload = { base, token: trimmedToken || undefined };
274
+ const payload = {
275
+ base,
276
+ token: trimmedToken || undefined,
277
+ externalApiBase: externalApiBase ?? null,
278
+ };
270
279
  try {
271
280
  const rpcSend = (win.webview.rpc as ApiBaseUpdateRpc | undefined)?.send;
272
281
  rpcSend?.apiBaseUpdate?.(payload);
@@ -63,8 +63,21 @@ ensureElectrobunGlobal();
63
63
 
64
64
  function dispatchMessage(messageName: string, payload: unknown): void {
65
65
  if (messageName === "apiBaseUpdate") {
66
- const apiBaseUpdate = payload as { base: string; token?: string };
66
+ const apiBaseUpdate = payload as {
67
+ base: string;
68
+ token?: string;
69
+ externalApiBase?: string | null;
70
+ };
67
71
  window.__ELIZA_API_BASE__ = apiBaseUpdate.base;
72
+ if (
73
+ typeof apiBaseUpdate.externalApiBase === "string" &&
74
+ apiBaseUpdate.externalApiBase.trim()
75
+ ) {
76
+ window.__ELIZA_DESKTOP_EXTERNAL_API_BASE__ =
77
+ apiBaseUpdate.externalApiBase.trim();
78
+ } else {
79
+ Reflect.deleteProperty(window, "__ELIZA_DESKTOP_EXTERNAL_API_BASE__");
80
+ }
68
81
  if (apiBaseUpdate.token) {
69
82
  Object.defineProperty(window, "__ELIZA_API_TOKEN__", {
70
83
  value: apiBaseUpdate.token,
@@ -196,6 +209,7 @@ declare global {
196
209
  interface Window {
197
210
  __ELIZA_API_BASE__?: string;
198
211
  __ELIZA_API_TOKEN__: string;
212
+ __ELIZA_DESKTOP_EXTERNAL_API_BASE__?: string;
199
213
  __ELIZA_ELECTROBUN_RPC__?: typeof electrobunRpc;
200
214
  }
201
215
  }
@@ -34,7 +34,6 @@ import { getBrandConfig } from "./brand-config";
34
34
  import { startBrowserWorkspaceBridgeServer } from "./browser-workspace-bridge-server";
35
35
  import { readNavigationEventUrl } from "./cloud-auth-window";
36
36
  import { readOpenUrlEventUrl } from "./desktop-deep-link-events";
37
- import { shouldCreateDesktopPill } from "./desktop-pill-config";
38
37
  import { startDesktopTestBridgeServer } from "./desktop-test-bridge-server";
39
38
  import {
40
39
  shouldCreateDesktopTray,
@@ -96,7 +95,6 @@ import {
96
95
  getOnboardingOverlayWindow,
97
96
  } from "./onboarding-overlay-window";
98
97
  import { getPersistedDeployment } from "./persisted-deployment";
99
- import { createPillWindow, getPillWindow } from "./pill-window";
100
98
  import { printElectrobunDevSettingsBanner } from "./print-electrobun-dev-settings-banner";
101
99
  import {
102
100
  createRendererApiProxyRequestInit,
@@ -944,11 +942,32 @@ async function resolveRendererUrl(): Promise<string> {
944
942
  return rendererUrl;
945
943
  }
946
944
 
945
+ function appendApiBaseParam(rendererUrl: string, apiBase: string): string {
946
+ try {
947
+ const url = new URL(rendererUrl);
948
+ if (!url.searchParams.has("apiBase")) {
949
+ url.searchParams.set("apiBase", apiBase);
950
+ }
951
+ return url.toString();
952
+ } catch {
953
+ return rendererUrl;
954
+ }
955
+ }
956
+
957
+ async function resolveRendererUrlForCurrentRuntime(): Promise<string> {
958
+ const rendererUrl = await resolveRendererUrl();
959
+ const runtime = resolveDesktopRuntime();
960
+ if (runtime.mode === "external" && runtime.externalApi.base) {
961
+ return appendApiBaseParam(rendererUrl, runtime.externalApi.base);
962
+ }
963
+ return rendererUrl;
964
+ }
965
+
947
966
  async function createMainWindow(rpc: ElizaDesktopRpc): Promise<BrowserWindow> {
948
967
  const kiosk = isKioskShellMode();
949
968
  const rendererUrl = kiosk
950
- ? appendKioskShellModeParam(await resolveRendererUrl())
951
- : await resolveRendererUrl();
969
+ ? appendKioskShellModeParam(await resolveRendererUrlForCurrentRuntime())
970
+ : await resolveRendererUrlForCurrentRuntime();
952
971
  const buildInfo = await BuildConfig.get();
953
972
  const mainWindowPartition = resolveMainWindowPartition(process.env, {
954
973
  platform: process.platform,
@@ -1251,7 +1270,7 @@ async function openOnboardingOverlayWindow(): Promise<BrowserWindow> {
1251
1270
  return existing;
1252
1271
  }
1253
1272
  const { rpc } = createDesktopRpc("onboarding-overlay");
1254
- const rendererUrl = await resolveRendererUrl();
1273
+ const rendererUrl = await resolveRendererUrlForCurrentRuntime();
1255
1274
  let preload = "";
1256
1275
  try {
1257
1276
  preload = readResolvedPreloadScript(import.meta.dir);
@@ -1692,11 +1711,6 @@ function injectApiBaseIntoOpenRendererWindows(): void {
1692
1711
  injectApiBase(currentWindow);
1693
1712
  }
1694
1713
 
1695
- const pillWindow = getPillWindow();
1696
- if (pillWindow && pillWindow !== currentWindow) {
1697
- injectApiBase(pillWindow);
1698
- }
1699
-
1700
1714
  surfaceWindowManager?.forEachWindow((w) => {
1701
1715
  injectApiBase(w as BrowserWindow);
1702
1716
  });
@@ -1712,10 +1726,6 @@ function collectOpenRendererWindows(): BrowserWindow[] {
1712
1726
  if (currentWindow) {
1713
1727
  windows.push(currentWindow);
1714
1728
  }
1715
- const pillWindow = getPillWindow();
1716
- if (pillWindow && pillWindow !== currentWindow) {
1717
- windows.push(pillWindow);
1718
- }
1719
1729
  surfaceWindowManager?.forEachWindow((w) => {
1720
1730
  windows.push(w as BrowserWindow);
1721
1731
  });
@@ -2479,7 +2489,7 @@ async function main(): Promise<void> {
2479
2489
  // The agent rebound to a different loopback port (or recovered from a
2480
2490
  // crash) — the cookies we installed during _startAgent were scoped to
2481
2491
  // the old origin. Re-prime so every renderer's next /api request stays
2482
- // authenticated, including the OS-level pill window.
2492
+ // authenticated, including any open secondary renderer windows.
2483
2493
  markDesktopSessionStale();
2484
2494
  const apiBase = `http://127.0.0.1:${status.port}`;
2485
2495
  const rendererBase = resolveRendererFacingApiBase(
@@ -2617,19 +2627,6 @@ async function main(): Promise<void> {
2617
2627
  /* non-fatal */
2618
2628
  }
2619
2629
  getFloatingChatManager().configure(url, preload);
2620
- // In kiosk mode the chat pill lives in-canvas on the KioskShell, so we
2621
- // never spawn the separate native pill toplevel. Outside kiosk, the pill
2622
- // loads the same renderer in chat-overlay shell mode so the assistant
2623
- // lives in its own OS-level window instead of inside the app.
2624
- if (!isKioskShellMode() && shouldCreateDesktopPill()) {
2625
- try {
2626
- createPillWindow({ rendererUrl: url, preload });
2627
- } catch (err) {
2628
- logger.warn(
2629
- `[Main] Failed to spawn pill window: ${err instanceof Error ? err.message : String(err)}`,
2630
- );
2631
- }
2632
- }
2633
2630
  });
2634
2631
 
2635
2632
  // Per-window RPC tracking: surface windows each get their own typed
@@ -1,10 +1,23 @@
1
1
  import fs from "node:fs";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
- import { getCurrent, injectIntoHtml, setCurrent } from "./api-base-owner";
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
+ import {
6
+ getCurrent,
7
+ injectIntoHtml,
8
+ pushToWindow,
9
+ setCurrent,
10
+ } from "./api-base-owner";
6
11
 
7
12
  const ENV_KEYS = [
13
+ "ELIZA_API_BASE",
14
+ "ELIZA_API_BASE_URL",
15
+ "ELIZA_DESKTOP_API_BASE",
16
+ "ELIZA_DESKTOP_CLOUD_AGENT_BASE",
17
+ "ELIZA_DESKTOP_CLOUD_ONLY",
18
+ "ELIZA_DESKTOP_RUNTIME_MODE",
19
+ "ELIZA_DESKTOP_SKIP_EMBEDDED_AGENT",
20
+ "ELIZA_DESKTOP_TEST_API_BASE",
8
21
  "ELIZA_STARTUP_SESSION_ID",
9
22
  "ELIZA_STARTUP_STATE_FILE",
10
23
  "ELIZA_STARTUP_EVENTS_FILE",
@@ -17,12 +30,10 @@ let tempHome: string | null = null;
17
30
  beforeEach(() => {
18
31
  for (const key of ENV_KEYS) {
19
32
  originalEnv.set(key, process.env[key]);
33
+ if (key !== "HOME") delete process.env[key];
20
34
  }
21
35
  tempHome = fs.mkdtempSync(path.join(os.tmpdir(), "eliza-api-base-owner-"));
22
36
  process.env.HOME = tempHome;
23
- delete process.env.ELIZA_STARTUP_SESSION_ID;
24
- delete process.env.ELIZA_STARTUP_STATE_FILE;
25
- delete process.env.ELIZA_STARTUP_EVENTS_FILE;
26
37
  setCurrent(null);
27
38
  });
28
39
 
@@ -80,4 +91,55 @@ describe("api-base-owner", () => {
80
91
  expect(injected).toContain('"__ELIZA_API_TOKEN__"');
81
92
  expect(injected).toContain("elizaos.app.boot-config");
82
93
  });
94
+
95
+ it("marks a non-loopback current API base as an external desktop API base", () => {
96
+ setCurrent("https://agent.example.com", "cloud-token");
97
+
98
+ const injected = injectIntoHtml("<html><head></head><body></body></html>");
99
+
100
+ expect(injected).toContain(
101
+ 'window.__ELIZA_API_BASE__="https://agent.example.com";',
102
+ );
103
+ expect(injected).toContain(
104
+ 'window.__ELIZA_DESKTOP_EXTERNAL_API_BASE__="https://agent.example.com";',
105
+ );
106
+ });
107
+
108
+ it("pushes the external desktop API base to already-open renderer windows", () => {
109
+ setCurrent("https://agent.example.com", "cloud-token");
110
+ const apiBaseUpdate = vi.fn();
111
+
112
+ pushToWindow({
113
+ webview: {
114
+ rpc: {
115
+ send: { apiBaseUpdate },
116
+ },
117
+ },
118
+ });
119
+
120
+ expect(apiBaseUpdate).toHaveBeenCalledWith({
121
+ base: "https://agent.example.com",
122
+ token: "cloud-token",
123
+ externalApiBase: "https://agent.example.com",
124
+ });
125
+ });
126
+
127
+ it("does not mark loopback API bases as external", () => {
128
+ setCurrent("http://127.0.0.1:31337", "dev-token");
129
+ const apiBaseUpdate = vi.fn();
130
+
131
+ pushToWindow({
132
+ webview: {
133
+ rpc: {
134
+ send: { apiBaseUpdate },
135
+ },
136
+ },
137
+ });
138
+
139
+ expect(apiBaseUpdate).toHaveBeenCalledWith({
140
+ base: "http://127.0.0.1:31337",
141
+ token: "dev-token",
142
+ externalApiBase: null,
143
+ });
144
+ });
83
145
  });
@@ -30,6 +30,7 @@
30
30
  */
31
31
 
32
32
  import {
33
+ normalizeApiBase,
33
34
  pushApiBaseToRenderer,
34
35
  resolveDesktopRuntimeMode,
35
36
  resolveDesktopRuntimeModeSignal,
@@ -51,6 +52,31 @@ function resolveStartupTraceId(): string | null {
51
52
  return getStartupTraceConfig().sessionId;
52
53
  }
53
54
 
55
+ function resolveCurrentExternalApiBase(): string | null {
56
+ const runtime = resolveDesktopRuntimeMode(process.env);
57
+ if (runtime.mode === "external" && runtime.externalApi.base) {
58
+ return runtime.externalApi.base;
59
+ }
60
+ const currentBase = normalizeApiBase(current.base ?? undefined);
61
+ if (!currentBase) return null;
62
+ try {
63
+ const parsed = new URL(currentBase);
64
+ const hostname = parsed.hostname.toLowerCase();
65
+ if (
66
+ (parsed.protocol === "http:" || parsed.protocol === "https:") &&
67
+ hostname !== "localhost" &&
68
+ hostname !== "127.0.0.1" &&
69
+ hostname !== "::1" &&
70
+ hostname !== "[::1]"
71
+ ) {
72
+ return parsed.origin;
73
+ }
74
+ } catch {
75
+ return null;
76
+ }
77
+ return null;
78
+ }
79
+
54
80
  /**
55
81
  * Update the singleton with the latest known API base + token. Subsequent
56
82
  * `injectIntoHtml(...)` and `pushToWindow(...)` calls read this state.
@@ -107,11 +133,10 @@ export function injectIntoHtml(html: string): string {
107
133
  const runtimeModeInject = runtimeModeSignal
108
134
  ? `window.__ELIZA_DESKTOP_RUNTIME_MODE__=${safeJsonForHtml(runtimeModeSignal)};`
109
135
  : "";
110
- const runtime = resolveDesktopRuntimeMode(process.env);
111
- const externalApiBaseInject =
112
- runtime.mode === "external" && runtime.externalApi.base
113
- ? `window.__ELIZA_DESKTOP_EXTERNAL_API_BASE__=${safeJsonForHtml(runtime.externalApi.base)};`
114
- : "";
136
+ const externalApiBase = resolveCurrentExternalApiBase();
137
+ const externalApiBaseInject = externalApiBase
138
+ ? `window.__ELIZA_DESKTOP_EXTERNAL_API_BASE__=${safeJsonForHtml(externalApiBase)};`
139
+ : "";
115
140
  apiBaseInject = `window.__ELIZA_API_BASE__=${baseLiteral};${runtimeModeInject}${externalApiBaseInject}${tokenInject}${bootConfigInject}`;
116
141
  }
117
142
 
@@ -133,7 +158,12 @@ export function injectIntoHtml(html: string): string {
133
158
  */
134
159
  export function pushToWindow(win: { webview: { rpc?: unknown } }): void {
135
160
  if (!current.base) return;
136
- pushApiBaseToRenderer(win, current.base, current.token || undefined);
161
+ pushApiBaseToRenderer(
162
+ win,
163
+ current.base,
164
+ current.token || undefined,
165
+ resolveCurrentExternalApiBase(),
166
+ );
137
167
  }
138
168
 
139
169
  /**
@@ -2252,7 +2252,7 @@ X-GNOME-Autostart-enabled=true
2252
2252
  error instanceof Error ? error.message : error ? String(error) : null;
2253
2253
 
2254
2254
  try {
2255
- const localInfo = await Updater.getLocallocalInfo();
2255
+ const localInfo = await Updater.getLocalInfo();
2256
2256
  currentVersion = localInfo.version;
2257
2257
  currentHash = localInfo.hash;
2258
2258
  channel = localInfo.channel;
@@ -18,7 +18,8 @@
18
18
  * onboarding completes the overlay is closed and the normal dashboard window
19
19
  * opens.
20
20
  *
21
- * Modeled on pill-window.ts (the existing small borderless/transparent overlay).
21
+ * Uses the same small borderless/transparent-window constraints as the other
22
+ * focused native overlay surfaces.
22
23
  */
23
24
 
24
25
  import { type BrowserWindow, Screen } from "electrobun/bun";
@@ -51,11 +52,10 @@ export function createOnboardingOverlayWindow(args: {
51
52
  }
52
53
 
53
54
  // Use the full work area so the renderer can place UI elements anywhere on
54
- // screen — the onboarding card is pinned top-right via CSS, and the voice
55
- // pill is centered at the bottom. The window is transparent + passthrough,
56
- // so clicks on empty regions fall through to the desktop. The
57
- // makeKeyAndOrderFront call after dom-ready ensures the interactive elements
58
- // (buttons, pill) receive clicks.
55
+ // screen — the onboarding card is pinned top-right via CSS. The window is
56
+ // transparent + passthrough, so clicks on empty regions fall through to the
57
+ // desktop. The makeKeyAndOrderFront call after dom-ready ensures the
58
+ // interactive elements receive clicks.
59
59
  const workArea = Screen.getPrimaryDisplay().workArea;
60
60
  const frame = {
61
61
  x: workArea.x,
@@ -72,8 +72,7 @@ export function createOnboardingOverlayWindow(args: {
72
72
  frame,
73
73
  titleBarStyle: "hidden",
74
74
  transparent: true,
75
- // Match the pill window's proven-visible config. A small, borderless,
76
- // transparent window only showed reliably with activate:false — a
75
+ // A small, borderless, transparent window only showed reliably with activate:false — a
77
76
  // borderless NSWindow cannot become key, and activate:true left the small
78
77
  // window unshown (the full-screen variant happened to paint regardless).
79
78
  // No passthrough: the window is small, so clicks outside it already reach