@elizaos/app-core 2.0.3-beta.5 → 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 (40) hide show
  1. package/package.json +37 -36
  2. package/platforms/electrobun/electrobun.config.ts +31 -1
  3. package/platforms/electrobun/package.json +10 -10
  4. package/platforms/electrobun/remotes/fs/README.md +0 -1
  5. package/platforms/electrobun/remotes/fs/package.json +0 -1
  6. package/platforms/electrobun/remotes/git/README.md +1 -2
  7. package/platforms/electrobun/remotes/git/package.json +0 -1
  8. package/platforms/electrobun/remotes/local-model/README.md +0 -1
  9. package/platforms/electrobun/remotes/local-model/package.json +0 -1
  10. package/platforms/electrobun/remotes/pty/README.md +1 -2
  11. package/platforms/electrobun/remotes/pty/package.json +0 -1
  12. package/platforms/electrobun/remotes/runtime/README.md +1 -5
  13. package/platforms/electrobun/remotes/runtime/package.json +0 -1
  14. package/platforms/electrobun/remotes/surface/README.md +1 -2
  15. package/platforms/electrobun/remotes/surface/package.json +0 -1
  16. package/platforms/electrobun/scripts/sync-web-assets.mjs +31 -2
  17. package/platforms/electrobun/src/api-base.ts +11 -2
  18. package/platforms/electrobun/src/bridge/electrobun-direct-rpc.ts +15 -1
  19. package/platforms/electrobun/src/index.ts +25 -28
  20. package/platforms/electrobun/src/lifecycle/api-base-owner.test.ts +67 -5
  21. package/platforms/electrobun/src/lifecycle/api-base-owner.ts +36 -6
  22. package/platforms/electrobun/src/native/desktop.ts +1 -1
  23. package/platforms/electrobun/src/onboarding-overlay-window.ts +7 -8
  24. package/platforms/electrobun/src/preload.js +1 -1
  25. package/platforms/electrobun/src/rpc-schema.ts +5 -1
  26. package/runtime/voice-warmup.d.ts.map +1 -1
  27. package/runtime/voice-warmup.js +8 -2
  28. package/scripts/benchmark-preflight.mjs +31 -2
  29. package/scripts/build-image.sh +5 -2
  30. package/scripts/bun-riscv64/build.sh +12 -6
  31. package/scripts/bun-riscv64/run-build.sh +10 -1
  32. package/scripts/dev-platform.mjs +19 -10
  33. package/scripts/ios-xcframework/README.md +15 -9
  34. package/scripts/ios-xcframework/run-physical-device-smoke.mjs +5 -3
  35. package/scripts/playwright-ui-live-stack.ts +32 -8
  36. package/scripts/run-mobile-build.mjs +11 -14
  37. package/platforms/electrobun/src/desktop-pill-config.test.ts +0 -27
  38. package/platforms/electrobun/src/desktop-pill-config.ts +0 -40
  39. package/platforms/electrobun/src/pill-window.test.ts +0 -91
  40. package/platforms/electrobun/src/pill-window.ts +0 -99
@@ -1469,7 +1469,7 @@ function mirrorCapacitorWebPayloadIntoAndroidDir() {
1469
1469
  fs.realpathSync(syncedAssets) === fs.realpathSync(targetAssets);
1470
1470
  if (hasSyncedPublic && !sameTree) {
1471
1471
  fs.mkdirSync(targetAssets, { recursive: true });
1472
- fs.rmSync(targetPublic, { recursive: true, force: true });
1472
+ rmRecursive(targetPublic);
1473
1473
  fs.cpSync(syncedPublic, targetPublic, { recursive: true });
1474
1474
  for (const cfg of ["capacitor.config.json", "capacitor.plugins.json"]) {
1475
1475
  const src = path.join(syncedAssets, cfg);
@@ -1508,10 +1508,7 @@ function mirrorCapacitorWebPayloadIntoAndroidDir() {
1508
1508
  fs.existsSync(targetAssets)
1509
1509
  ) {
1510
1510
  fs.mkdirSync(targetPublic, { recursive: true });
1511
- fs.rmSync(path.join(targetPublic, "assets"), {
1512
- recursive: true,
1513
- force: true,
1514
- });
1511
+ rmRecursive(path.join(targetPublic, "assets"));
1515
1512
  fs.cpSync(freshWeb, targetPublic, { recursive: true });
1516
1513
  console.log(
1517
1514
  `[mobile-build] Stale-web guard: overlaid fresh ${path.relative(repoRoot, freshWeb)} → ${path.relative(repoRoot, targetPublic)}`,
@@ -2536,7 +2533,7 @@ function removeStaleAndroidJavaSourceRoots(
2536
2533
  shouldRemoveAndroidJavaSourceRoot(candidate, dstJava, protectedRoots) &&
2537
2534
  fs.existsSync(candidate)
2538
2535
  ) {
2539
- fs.rmSync(candidate, { recursive: true, force: true });
2536
+ rmRecursive(candidate);
2540
2537
  }
2541
2538
  }
2542
2539
  }
@@ -3058,7 +3055,7 @@ function overlayAndroid({ includeAospRoleLaunchers = false } = {}) {
3058
3055
  protectedJavaRoots,
3059
3056
  )
3060
3057
  ) {
3061
- fs.rmSync(staleJava, { recursive: true, force: true });
3058
+ rmRecursive(staleJava);
3062
3059
  }
3063
3060
  }
3064
3061
  fs.mkdirSync(dstJava, { recursive: true });
@@ -3135,7 +3132,7 @@ function overlayAndroid({ includeAospRoleLaunchers = false } = {}) {
3135
3132
  path.resolve(srcJava) !== path.resolve(templateJava) &&
3136
3133
  path.resolve(srcJava) !== path.resolve(dstJava)
3137
3134
  ) {
3138
- fs.rmSync(srcJava, { recursive: true, force: true });
3135
+ rmRecursive(srcJava);
3139
3136
  }
3140
3137
  console.log("[mobile-build] Overlaid Android Java sources.");
3141
3138
  }
@@ -5166,7 +5163,7 @@ async function ensureIosLlamaCppVendoredFramework({
5166
5163
  await ensureMtpIosTarget(simulatorTarget);
5167
5164
 
5168
5165
  fs.mkdirSync(xcframeworksDir, { recursive: true });
5169
- fs.rmSync(xcframeworkDir, { recursive: true, force: true });
5166
+ rmRecursive(xcframeworkDir);
5170
5167
  await run("node", [
5171
5168
  IOS_XCFRAMEWORK_BUILD_SCRIPT,
5172
5169
  "--output",
@@ -5197,7 +5194,7 @@ async function ensureIosLlamaCppVendoredFramework({
5197
5194
  "ios",
5198
5195
  `.${path.basename(stale, ".framework")}-stock-archive`,
5199
5196
  );
5200
- fs.rmSync(archived, { recursive: true, force: true });
5197
+ rmRecursive(archived);
5201
5198
  fs.renameSync(stale, archived);
5202
5199
  console.log(
5203
5200
  `[mobile-build] Archived stock npm framework: ${stale} -> ${archived} ` +
@@ -5532,7 +5529,7 @@ function stageIosFullBunEngineForPodspec(framework) {
5532
5529
  console.log(
5533
5530
  `[mobile-build] staging external iOS full Bun engine for CocoaPods: ${resolved} -> ${defaultIosBunEngineXcframework}`,
5534
5531
  );
5535
- fs.rmSync(defaultIosBunEngineXcframework, { recursive: true, force: true });
5532
+ rmRecursive(defaultIosBunEngineXcframework);
5536
5533
  fs.mkdirSync(path.dirname(defaultIosBunEngineXcframework), {
5537
5534
  recursive: true,
5538
5535
  });
@@ -6117,7 +6114,7 @@ export function removeInactiveAndroidJavaSourceRoots(javaRoots, activeRoot) {
6117
6114
  if (resolved === active || seen.has(resolved)) continue;
6118
6115
  seen.add(resolved);
6119
6116
  if (!fs.existsSync(root)) continue;
6120
- fs.rmSync(root, { recursive: true, force: true });
6117
+ rmRecursive(root);
6121
6118
  removed += 1;
6122
6119
  }
6123
6120
  return removed;
@@ -6127,7 +6124,7 @@ function removeCloudNativeArtifacts() {
6127
6124
  const assetsRoot = path.join(androidDir, "app", "src", "main", "assets");
6128
6125
  const stagedAgentAssets = path.join(assetsRoot, "agent");
6129
6126
  if (fs.existsSync(stagedAgentAssets)) {
6130
- fs.rmSync(stagedAgentAssets, { recursive: true, force: true });
6127
+ rmRecursive(stagedAgentAssets);
6131
6128
  console.log(
6132
6129
  "[mobile-build] Removed staged on-device agent runtime under assets/agent/.",
6133
6130
  );
@@ -7478,7 +7475,7 @@ function writeAndroidSystemProvenance(apkPath) {
7478
7475
  );
7479
7476
  }
7480
7477
  } finally {
7481
- fs.rmSync(tmpDir, { recursive: true, force: true });
7478
+ rmRecursive(tmpDir);
7482
7479
  }
7483
7480
  }
7484
7481
 
@@ -1,27 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { shouldCreateDesktopPill } from "./desktop-pill-config";
3
-
4
- describe("desktop pill config", () => {
5
- it("creates a pill window by default (voice surface)", () => {
6
- expect(shouldCreateDesktopPill({})).toBe(true);
7
- });
8
-
9
- it("supports an explicit enable flag", () => {
10
- expect(shouldCreateDesktopPill({ ELIZA_DESKTOP_PILL: "1" })).toBe(true);
11
- expect(shouldCreateDesktopPill({ ELIZA_DESKTOP_PILL: "true" })).toBe(true);
12
- expect(shouldCreateDesktopPill({ ELIZA_DESKTOP_PILL: "yes" })).toBe(true);
13
- });
14
-
15
- it("supports explicit negative and disable flags", () => {
16
- expect(shouldCreateDesktopPill({ ELIZA_DESKTOP_PILL: "0" })).toBe(false);
17
- expect(shouldCreateDesktopPill({ ELIZA_DESKTOP_PILL: "false" })).toBe(
18
- false,
19
- );
20
- expect(
21
- shouldCreateDesktopPill({
22
- ELIZA_DESKTOP_PILL: "1",
23
- ELIZA_DESKTOP_DISABLE_PILL: "1",
24
- }),
25
- ).toBe(false);
26
- });
27
- });
@@ -1,40 +0,0 @@
1
- function parseTruthy(value: string | undefined): boolean {
2
- const normalized = value?.trim().toLowerCase();
3
- return normalized === "1" || normalized === "true" || normalized === "yes";
4
- }
5
-
6
- function parseFalsy(value: string | undefined): boolean {
7
- const normalized = value?.trim().toLowerCase();
8
- return normalized === "0" || normalized === "false" || normalized === "no";
9
- }
10
-
11
- /**
12
- * Whether the floating voice-pill window should be created at startup.
13
- *
14
- * BEHAVIOR CHANGE (PR #8175): the pill window is now **on by default**.
15
- * Previously `ELIZA_DESKTOP_PILL=1` was required to opt in; now all desktop
16
- * users see the pill unless they explicitly opt out.
17
- *
18
- * Migration for existing users who did not set `ELIZA_DESKTOP_PILL`:
19
- * - Before PR #8175: pill was hidden (opt-in OFF by default).
20
- * - After PR #8175: pill is shown (opt-out, ON by default).
21
- *
22
- * To restore the previous hidden behaviour set either:
23
- * ELIZA_DESKTOP_PILL=0 (standard off)
24
- * ELIZA_DESKTOP_DISABLE_PILL=1 (legacy kill-switch; still respected)
25
- */
26
- export function shouldCreateDesktopPill(
27
- env: NodeJS.ProcessEnv = process.env,
28
- ): boolean {
29
- if (parseTruthy(env.ELIZA_DESKTOP_DISABLE_PILL)) {
30
- return false;
31
- }
32
-
33
- if (parseFalsy(env.ELIZA_DESKTOP_PILL)) {
34
- return false;
35
- }
36
-
37
- // Default on: the pill window is the primary voice surface. Users can
38
- // suppress it with ELIZA_DESKTOP_PILL=0 or ELIZA_DESKTOP_DISABLE_PILL=1.
39
- return true;
40
- }
@@ -1,91 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from "vitest";
2
-
3
- const mocks = vi.hoisted(() => ({
4
- createWindow: vi.fn(),
5
- getPrimaryDisplay: vi.fn(),
6
- info: vi.fn(),
7
- warn: vi.fn(),
8
- }));
9
-
10
- vi.mock("electrobun/bun", () => ({
11
- BrowserWindow: class BrowserWindow {},
12
- Screen: {
13
- getPrimaryDisplay: mocks.getPrimaryDisplay,
14
- },
15
- }));
16
-
17
- vi.mock("./electrobun-window-options", () => ({
18
- createElectrobunBrowserWindow: mocks.createWindow,
19
- }));
20
-
21
- vi.mock("./logger", () => ({
22
- logger: {
23
- debug: vi.fn(),
24
- error: vi.fn(),
25
- info: mocks.info,
26
- success: vi.fn(),
27
- warn: mocks.warn,
28
- },
29
- }));
30
-
31
- describe("pill window", () => {
32
- beforeEach(() => {
33
- vi.resetModules();
34
- mocks.createWindow.mockReset();
35
- mocks.getPrimaryDisplay.mockReset();
36
- mocks.info.mockReset();
37
- mocks.warn.mockReset();
38
- });
39
-
40
- it("loads the OS pill into the live chat overlay shell route", async () => {
41
- const { buildPillRendererUrl } = await import("./pill-window");
42
-
43
- expect(buildPillRendererUrl("http://127.0.0.1:5174/home?old=1#hash")).toBe(
44
- "http://127.0.0.1:5174/home?shellMode=chat-overlay",
45
- );
46
- });
47
-
48
- it("creates a bottom-centered transparent always-on-top window", async () => {
49
- const closeHandlers: Array<() => void> = [];
50
- const setAlwaysOnTop = vi.fn();
51
- const windowMock = {
52
- on: vi.fn((event: string, handler: () => void) => {
53
- if (event === "close") closeHandlers.push(handler);
54
- }),
55
- setAlwaysOnTop,
56
- };
57
- mocks.createWindow.mockReturnValue(windowMock);
58
- mocks.getPrimaryDisplay.mockReturnValue({
59
- workArea: { x: 100, y: 50, width: 1600, height: 900 },
60
- });
61
-
62
- const { createPillWindow, getPillWindow } = await import("./pill-window");
63
- const win = createPillWindow({
64
- rendererUrl: "http://127.0.0.1:5174/",
65
- preload: "preload.js",
66
- });
67
-
68
- expect(win).toBe(windowMock);
69
- expect(mocks.createWindow).toHaveBeenCalledWith(
70
- expect.objectContaining({
71
- title: "Eliza Pill",
72
- url: "http://127.0.0.1:5174/?shellMode=chat-overlay",
73
- preload: "preload.js",
74
- titleBarStyle: "hidden",
75
- transparent: true,
76
- activate: false,
77
- frame: {
78
- x: 720,
79
- y: 654,
80
- width: 360,
81
- height: 280,
82
- },
83
- }),
84
- );
85
- expect(setAlwaysOnTop).toHaveBeenCalledWith(true);
86
- expect(getPillWindow()).toBe(windowMock);
87
-
88
- for (const handler of closeHandlers) handler();
89
- expect(getPillWindow()).toBeNull();
90
- });
91
- });
@@ -1,99 +0,0 @@
1
- /**
2
- * Pill overlay window for Electrobun.
3
- *
4
- * Spawns a single borderless, transparent, always-on-top BrowserWindow
5
- * docked to the bottom-center of the user's primary display. The window
6
- * loads the same renderer bundle as the main shell with
7
- * `?shellMode=chat-overlay`, which routes to the live assistant overlay shell.
8
- *
9
- * Lifecycle:
10
- * - Created once at app boot, alongside the main window.
11
- * - Closing the main window does NOT close the pill, and vice versa.
12
- * - Quitting the app closes both (handled by Electrobun's standard
13
- * `exitOnLastWindowClosed` behavior firing when both windows are gone,
14
- * or by the application's quit menu).
15
- *
16
- * This is the persistent chat-overlay pill — created at app boot when
17
- * shouldCreateDesktopPill() returns true (shellMode=chat-overlay). It is the
18
- * live production voice/chat surface the user sees every day, rendering the
19
- * ContinuousChatOverlay (NOT the old standalone VoicePill, which was removed).
20
- */
21
-
22
- import { type BrowserWindow, Screen } from "electrobun/bun";
23
- import { createElectrobunBrowserWindow } from "./electrobun-window-options";
24
- import { logger } from "./logger";
25
-
26
- const PILL_WIDTH = 360;
27
- const PILL_HEIGHT = 280;
28
- const PILL_BOTTOM_MARGIN = 16;
29
-
30
- interface PillWindowFrame {
31
- x: number;
32
- y: number;
33
- width: number;
34
- height: number;
35
- }
36
-
37
- function resolvePillFrame(): PillWindowFrame {
38
- const display = Screen.getPrimaryDisplay();
39
- const workArea = display.workArea;
40
- return {
41
- x: workArea.x + Math.round((workArea.width - PILL_WIDTH) / 2),
42
- y: workArea.y + workArea.height - PILL_HEIGHT - PILL_BOTTOM_MARGIN,
43
- width: PILL_WIDTH,
44
- height: PILL_HEIGHT,
45
- };
46
- }
47
-
48
- export function buildPillRendererUrl(rendererUrl: string): string {
49
- const url = new URL(rendererUrl);
50
- url.search = "?shellMode=chat-overlay";
51
- url.hash = "";
52
- return url.toString();
53
- }
54
-
55
- let pillWindow: BrowserWindow | null = null;
56
-
57
- export function createPillWindow(args: {
58
- rendererUrl: string;
59
- preload: string;
60
- }): BrowserWindow {
61
- if (pillWindow) {
62
- return pillWindow;
63
- }
64
-
65
- const frame = resolvePillFrame();
66
- const url = buildPillRendererUrl(args.rendererUrl);
67
-
68
- const win = createElectrobunBrowserWindow({
69
- title: "Eliza Pill",
70
- url,
71
- preload: args.preload,
72
- frame,
73
- titleBarStyle: "hidden",
74
- transparent: true,
75
- activate: false,
76
- });
77
-
78
- try {
79
- win.setAlwaysOnTop(true);
80
- } catch (err) {
81
- logger.warn(
82
- `[pill-window] setAlwaysOnTop failed: ${err instanceof Error ? err.message : String(err)}`,
83
- );
84
- }
85
-
86
- win.on("close", () => {
87
- pillWindow = null;
88
- });
89
-
90
- pillWindow = win;
91
- logger.info(
92
- `[pill-window] Spawned pill overlay at (${frame.x},${frame.y}) ${frame.width}x${frame.height}`,
93
- );
94
- return win;
95
- }
96
-
97
- export function getPillWindow(): BrowserWindow | null {
98
- return pillWindow;
99
- }