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

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 (97) hide show
  1. package/api/i18n-locale-routes.d.ts +7 -0
  2. package/api/i18n-locale-routes.d.ts.map +1 -0
  3. package/api/i18n-locale-routes.js +58 -0
  4. package/api/ios-local-agent-transport.d.ts +3 -0
  5. package/api/ios-local-agent-transport.d.ts.map +1 -1
  6. package/api/ios-local-agent-transport.js +22 -1
  7. package/api/server.d.ts.map +1 -1
  8. package/api/server.js +5 -0
  9. package/benchmark/cerebras-autowire.d.ts.map +1 -1
  10. package/benchmark/cerebras-autowire.js +9 -2
  11. package/package.json +36 -36
  12. package/packaging/debian/rules +1 -1
  13. package/packaging/flatpak/generate-sources.sh +6 -1
  14. package/packaging/snap/snapcraft.yaml +15 -11
  15. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAgentService.java +2 -1
  16. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaNativeBridge.java +5 -0
  17. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaStartupTrace.java +28 -0
  18. package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoicePlugin.java +1 -1
  19. package/platforms/android/app/src/main/java/ai/elizaos/app/MainActivity.java +1 -0
  20. package/platforms/electrobun/electrobun.config.ts +31 -1
  21. package/platforms/electrobun/package.json +10 -10
  22. package/platforms/electrobun/remotes/local-model/README.md +2 -5
  23. package/platforms/electrobun/remotes/local-model/src/bun/eliza1-catalog.ts +0 -16
  24. package/platforms/electrobun/remotes/local-model/src/dev/phase8-smoke.ts +0 -2
  25. package/platforms/electrobun/scripts/smoke-test.sh +8 -2
  26. package/platforms/electrobun/scripts/stage-macos-release-artifacts.sh +8 -2
  27. package/platforms/electrobun/scripts/sync-web-assets.mjs +31 -2
  28. package/platforms/electrobun/src/bridge/electrobun-boot-config.ts +8 -0
  29. package/platforms/electrobun/src/bridge/electrobun-crypto-ready.ts +5 -1
  30. package/platforms/electrobun/src/bridge/electrobun-direct-rpc.ts +5 -11
  31. package/platforms/electrobun/src/preload.js +1 -1
  32. package/platforms/ios/App/App/Base.lproj/Main.storyboard +1 -1
  33. package/platforms/ios/App/App/ElizaBridgeViewController.swift +22 -0
  34. package/platforms/ios/App/App/ElizaStartupTrace.swift +12 -0
  35. package/platforms/ios/App/App.xcodeproj/project.pbxproj +8 -0
  36. package/runtime/eliza.d.ts.map +1 -1
  37. package/runtime/eliza.js +18 -0
  38. package/runtime/voice-warmup.d.ts +4 -4
  39. package/runtime/voice-warmup.d.ts.map +1 -1
  40. package/runtime/voice-warmup.js +4 -4
  41. package/scripts/aosp/compile-libllama.mjs +25 -5
  42. package/scripts/aosp/compile-libllama.test.mjs +17 -1
  43. package/scripts/assert-required-bundled-packages.test.ts +24 -2
  44. package/scripts/benchmark-preflight.mjs +31 -2
  45. package/scripts/build-bundled-agent-skills-artifact.mjs +32 -8
  46. package/scripts/build-bundled-orchestrator-artifact.mjs +34 -12
  47. package/scripts/build-llama-cpp-mtp.mjs +27 -3
  48. package/scripts/build-patched-electrobun-cli.mjs +30 -2
  49. package/scripts/bun-riscv64/bun-version.json +1 -1
  50. package/scripts/bun-riscv64/validate.sh +21 -8
  51. package/scripts/check-real-local-reset.ts +13 -1
  52. package/scripts/check-sms-gateway-completion-audit.mjs +96 -31
  53. package/scripts/check-sms-gateway-readiness.mjs +54 -17
  54. package/scripts/clean-repo.mjs +21 -3
  55. package/scripts/copy-runtime-node-modules.ts +68 -63
  56. package/scripts/desktop-build.mjs +46 -5
  57. package/scripts/dev-platform-no-install.test.mjs +19 -0
  58. package/scripts/dev-platform.mjs +6 -2
  59. package/scripts/disable-local-eliza-workspace.mjs +23 -1
  60. package/scripts/docker-ci-smoke.sh +6 -5
  61. package/scripts/ensure-avatars.mjs +18 -5
  62. package/scripts/ensure-bundled-workspaces.mjs +4 -15
  63. package/scripts/ensure-type-package-aliases.mjs +47 -3
  64. package/scripts/ffi-stub/Makefile +5 -2
  65. package/scripts/ios-xcframework/build-xcframework.mjs +22 -11
  66. package/scripts/ios-xcframework/run-physical-device-smoke.mjs +99 -6
  67. package/scripts/ios-xcframework/runtime-symbol-shim.c +560 -105
  68. package/scripts/lib/agent-source-watcher.test.mjs +24 -4
  69. package/scripts/lib/apple-entitlement-audit.test.mjs +19 -2
  70. package/scripts/lib/artifact-staleness.test.mts +18 -1
  71. package/scripts/lib/patch-bun-exports.mjs +20 -2
  72. package/scripts/lib/patch-bun-exports.test.mjs +108 -4
  73. package/scripts/lib/renderer-build-manifest.test.mts +18 -1
  74. package/scripts/lib/stage-android-agent.mjs +16 -3
  75. package/scripts/lib/verify-ondevice-artifact.test.mts +18 -1
  76. package/scripts/link-docker-local-app-packages.mjs +26 -1
  77. package/scripts/mas-smoke.test.mjs +25 -9
  78. package/scripts/omnivoice-fuse/prepare.mjs +27 -4
  79. package/scripts/package-electrobun-linux.mjs +22 -7
  80. package/scripts/patch-deps.mjs +18 -5
  81. package/scripts/playwright-ui-live-stack.ts +16 -3
  82. package/scripts/playwright-ui-smoke-api-stub.mjs +167 -2
  83. package/scripts/prepare-ios-cocoapods.sh +5 -1
  84. package/scripts/prune-cdn-local-assets.mjs +52 -5
  85. package/scripts/run-mobile-build-android-app-actions.test.mjs +19 -1
  86. package/scripts/run-mobile-build-mtp-staleness.test.mts +20 -4
  87. package/scripts/run-mobile-build.mjs +74 -16
  88. package/scripts/stage-android-agent.test.mjs +19 -1
  89. package/scripts/stage-desktop-fused-lib.mjs +26 -1
  90. package/scripts/sync-desktop-renderer.mjs +53 -12
  91. package/scripts/test-sms-gateway-software.mjs +20 -4
  92. package/cli/command-format.d.ts +0 -2
  93. package/cli/command-format.d.ts.map +0 -1
  94. package/cli/command-format.js +0 -20
  95. package/register-runtime-hooks.d.ts +0 -2
  96. package/register-runtime-hooks.d.ts.map +0 -1
  97. package/register-runtime-hooks.js +0 -19
@@ -7,7 +7,6 @@ import {
7
7
  mkdirSync,
8
8
  readdirSync,
9
9
  readFileSync,
10
- rmSync,
11
10
  statSync,
12
11
  writeFileSync,
13
12
  } from "node:fs";
@@ -25,6 +24,12 @@ const electrobunRoot = path.join(
25
24
  const buildRoot = path.join(electrobunRoot, "build");
26
25
  const artifactRoot = path.join(electrobunRoot, "artifacts");
27
26
  const iconPath = path.join(electrobunRoot, "assets/appIcon.png");
27
+ const cleanupHelperScript = path.join(
28
+ repoRoot,
29
+ "packages",
30
+ "scripts",
31
+ "rm-path-recursive.mjs",
32
+ );
28
33
 
29
34
  const args = new Map(
30
35
  process.argv.slice(2).map((arg) => {
@@ -75,6 +80,10 @@ function sh(command, commandArgs, options = {}) {
75
80
  });
76
81
  }
77
82
 
83
+ function removePathRecursive(targetPath) {
84
+ sh(process.execPath, [cleanupHelperScript, targetPath]);
85
+ }
86
+
78
87
  function latestBuildDir() {
79
88
  const explicit = args.get("build-dir");
80
89
  if (explicit) return path.resolve(repoRoot, explicit);
@@ -142,7 +151,7 @@ function writeDesktopFile(dest, execName = namespace) {
142
151
  }
143
152
 
144
153
  async function stagePackageRoot(buildDir, destRoot) {
145
- rmSync(destRoot, { recursive: true, force: true });
154
+ removePathRecursive(destRoot);
146
155
  mkdirSync(path.join(destRoot, optDir), { recursive: true });
147
156
  mkdirSync(path.join(destRoot, "usr/bin"), { recursive: true });
148
157
  mkdirSync(path.join(destRoot, "usr/share/applications"), { recursive: true });
@@ -199,9 +208,12 @@ async function buildDeb(buildDir) {
199
208
  "",
200
209
  ].join("\n"),
201
210
  );
202
- const out = path.join(artifactRoot, `${packageName}_${version}_${debArch}.deb`);
211
+ const out = path.join(
212
+ artifactRoot,
213
+ `${packageName}_${version}_${debArch}.deb`,
214
+ );
203
215
  sh("dpkg-deb", ["--build", root, out]);
204
- rmSync(root, { recursive: true, force: true });
216
+ removePathRecursive(root);
205
217
  return out;
206
218
  }
207
219
 
@@ -246,9 +258,12 @@ async function buildRpm(buildDir) {
246
258
  const rpmDir = path.join(top, "RPMS", rpmArch);
247
259
  const rpm = readdirSync(rpmDir).find((name) => name.endsWith(".rpm"));
248
260
  if (!rpm) throw new Error("rpmbuild did not produce an rpm");
249
- const out = path.join(artifactRoot, `${packageName}-${version}.${rpmArch}.rpm`);
261
+ const out = path.join(
262
+ artifactRoot,
263
+ `${packageName}-${version}.${rpmArch}.rpm`,
264
+ );
250
265
  copyFileSync(path.join(rpmDir, rpm), out);
251
- rmSync(top, { recursive: true, force: true });
266
+ removePathRecursive(top);
252
267
  return out;
253
268
  }
254
269
 
@@ -284,7 +299,7 @@ async function buildAppImage(buildDir) {
284
299
  sh(tool, [appDir, out], {
285
300
  env: { ...process.env, ARCH: rpmArch, APPIMAGE_EXTRACT_AND_RUN: "1" },
286
301
  });
287
- rmSync(appDir, { recursive: true, force: true });
302
+ removePathRecursive(appDir);
288
303
  return out;
289
304
  }
290
305
 
@@ -19,12 +19,12 @@
19
19
  * docs/retired-patches.md — do not add new memorial comments in this
20
20
  * file.
21
21
  */
22
+ import { execFileSync } from "node:child_process";
22
23
  import {
23
24
  existsSync,
24
25
  readdirSync,
25
26
  readFileSync,
26
27
  realpathSync,
27
- rmSync,
28
28
  symlinkSync,
29
29
  writeFileSync,
30
30
  } from "node:fs";
@@ -47,6 +47,19 @@ import { resolveRepoRootFromImportMeta } from "./lib/repo-root.mjs";
47
47
 
48
48
  const __dirname = dirname(fileURLToPath(import.meta.url));
49
49
  const root = resolveRepoRootFromImportMeta(import.meta.url);
50
+ const cleanupHelperScript = resolve(
51
+ root,
52
+ "packages",
53
+ "scripts",
54
+ "rm-path-recursive.mjs",
55
+ );
56
+
57
+ function removePathRecursive(targetPath) {
58
+ execFileSync(process.execPath, [cleanupHelperScript, targetPath], {
59
+ cwd: root,
60
+ stdio: "inherit",
61
+ });
62
+ }
50
63
 
51
64
  // ---------------------------------------------------------------------------
52
65
  // Bust stale Bun cache entries for @elizaos packages.
@@ -72,7 +85,7 @@ warnStaleBunCache(root);
72
85
  try {
73
86
  for (const entry of readdirSync(nmDir)) {
74
87
  if (entry.startsWith("@types+")) {
75
- rmSync(resolve(nmDir, entry), { recursive: true, force: true });
88
+ removePathRecursive(resolve(nmDir, entry));
76
89
  removedCount++;
77
90
  }
78
91
  }
@@ -280,7 +293,7 @@ function patchBaileysNestedSharpCopies() {
280
293
  for (const entry of readdirSync(bunCacheDir)) {
281
294
  if (!entry.startsWith("@whiskeysockets+baileys@")) continue;
282
295
  const nestedSharp = resolve(bunCacheDir, entry, "node_modules/sharp");
283
- rmSync(nestedSharp, { recursive: true, force: true });
296
+ removePathRecursive(nestedSharp);
284
297
  symlinkSync(rootSharpRealPath, nestedSharp, linkType);
285
298
  patched++;
286
299
  console.log(
@@ -336,7 +349,7 @@ function patchLegacySharpStoreAliases() {
336
349
  const staleRealPath = realpathSync(stalePath);
337
350
  if (staleRealPath === canonicalRealPath) continue;
338
351
 
339
- rmSync(stalePath, { recursive: true, force: true });
352
+ removePathRecursive(stalePath);
340
353
  symlinkSync(canonicalRealPath, stalePath, linkType);
341
354
  patched++;
342
355
  console.log(
@@ -417,7 +430,7 @@ for (const viteCacheDir of [
417
430
  resolve(root, "apps/app", "node_modules", ".vite"),
418
431
  ]) {
419
432
  if (!existsSync(viteCacheDir)) continue;
420
- rmSync(viteCacheDir, { recursive: true, force: true });
433
+ removePathRecursive(viteCacheDir);
421
434
  console.log(`[patch-deps] Cleared Vite optimize cache: ${viteCacheDir}`);
422
435
  }
423
436
 
@@ -1,5 +1,9 @@
1
- import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
2
- import { existsSync, rmSync } from "node:fs";
1
+ import {
2
+ type ChildProcessWithoutNullStreams,
3
+ execFileSync,
4
+ spawn,
5
+ } from "node:child_process";
6
+ import { existsSync } from "node:fs";
3
7
  import {
4
8
  access,
5
9
  cp,
@@ -38,6 +42,12 @@ import {
38
42
  } from "./lib/websocket-pending-queue.ts";
39
43
 
40
44
  const REPO_ROOT = path.resolve(import.meta.dirname, "..", "..", "..");
45
+ const CLEANUP_HELPER_SCRIPT = path.join(
46
+ REPO_ROOT,
47
+ "packages",
48
+ "scripts",
49
+ "rm-path-recursive.mjs",
50
+ );
41
51
  const APP_DIR = resolveMainAppDir(REPO_ROOT, "app");
42
52
  const APP_DIST_DIR = path.join(APP_DIR, "dist");
43
53
  const COMPANION_PUBLIC_DIR = path.join(
@@ -143,7 +153,10 @@ function cleanupKnownStateDirsSync(): void {
143
153
  ownedStateDirs.clear();
144
154
  for (const stateDir of stateDirs) {
145
155
  try {
146
- rmSync(stateDir, { force: true, recursive: true });
156
+ execFileSync(process.execPath, [CLEANUP_HELPER_SCRIPT, stateDir], {
157
+ cwd: REPO_ROOT,
158
+ stdio: "ignore",
159
+ });
147
160
  } catch {
148
161
  // Best effort during process teardown.
149
162
  }
@@ -8,6 +8,9 @@ const port = Number(process.env.ELIZA_UI_SMOKE_API_PORT || "31337");
8
8
  const repoRoot = path.resolve(new URL("../../..", import.meta.url).pathname);
9
9
  const SMOKE_GENERATED_AT = "2026-01-01T00:00:00.000Z";
10
10
  const DEMO_ORCHESTRATOR = process.env.ELIZA_UI_SMOKE_DEMO_ORCHESTRATOR === "1";
11
+ const HUMAN_CHAT_FIXTURES = process.env.ELIZA_UI_SMOKE_HUMAN_CHAT === "1";
12
+ const SMOKE_NOTIFICATIONS =
13
+ process.env.ELIZA_UI_SMOKE_NOTIFICATIONS === "1";
11
14
  let browserWorkspaceCounter = 0;
12
15
  let browserWorkspaceTabs = [];
13
16
  let lifeOpsAppEnabled = true;
@@ -116,6 +119,14 @@ const smokeViewDeclarations = [
116
119
  // `/documents` collides with the built-in "documents" tab (App.tsx findView
117
120
  // matches `/${tab}`), which would hijack the `/character/documents` route.
118
121
  ["calendar", "Calendar", "plugin-calendar", "/calendar", "CalendarView"],
122
+ ["notes", "Notes", "plugin-simple-views", "/notes", "NotesView"],
123
+ [
124
+ "simple-calendar",
125
+ "Simple Calendar",
126
+ "plugin-simple-views",
127
+ "/simple-calendar",
128
+ "SimpleCalendarView",
129
+ ],
119
130
  ["finances", "Finances", "plugin-finances", "/finances", "FinancesView"],
120
131
  ["focus", "Focus", "plugin-blocker", "/focus", "FocusView"],
121
132
  ["goals", "Goals", "plugin-goals", "/goals", "GoalsView"],
@@ -603,6 +614,53 @@ const stubMemoryBrowseResponse = {
603
614
  offset: 0,
604
615
  };
605
616
 
617
+ const simpleViewsState = {
618
+ notes: [
619
+ {
620
+ id: "note-ui-smoke",
621
+ title: "UI smoke note",
622
+ body: "Rendered from the optional simple views plugin.",
623
+ color: "yellow",
624
+ createdAt: "2026-06-25T00:00:00.000Z",
625
+ updatedAt: "2026-06-25T00:00:00.000Z",
626
+ },
627
+ ],
628
+ events: [
629
+ {
630
+ id: "event-ui-smoke",
631
+ title: "UI smoke calendar event",
632
+ date: "2026-06-25",
633
+ time: "09:00",
634
+ notes: "Rendered from the optional simple views plugin.",
635
+ color: "green",
636
+ createdAt: "2026-06-25T00:00:00.000Z",
637
+ },
638
+ ],
639
+ selectedDate: "2026-06-25",
640
+ };
641
+
642
+ const smokeNotifications = [
643
+ {
644
+ id: "smoke-notification-view-qa",
645
+ title: "View switching ready",
646
+ body: "Notes and Simple Calendar are registered for desktop QA.",
647
+ category: "workflow",
648
+ priority: "high",
649
+ source: "ui-smoke",
650
+ createdAt: Date.UTC(2026, 5, 25, 9, 0, 0),
651
+ deepLink: "/views",
652
+ },
653
+ {
654
+ id: "smoke-notification-cloud-chat",
655
+ title: "Cloud chat stub online",
656
+ body: "The smoke backend is serving deterministic chat responses.",
657
+ category: "status",
658
+ priority: "normal",
659
+ source: "ui-smoke",
660
+ createdAt: Date.UTC(2026, 5, 25, 8, 55, 0),
661
+ },
662
+ ];
663
+
606
664
  const emptyComputerUseApprovalSnapshot = {
607
665
  mode: "full_control",
608
666
  pendingCount: 0,
@@ -1171,6 +1229,12 @@ function normalizeAssistantInput(value) {
1171
1229
 
1172
1230
  function classifyAssistantAction(text) {
1173
1231
  const normalized = text.toLowerCase();
1232
+ if (/\b(note|notes|sticky)\b/.test(normalized)) {
1233
+ return { type: "navigate", target: "/notes" };
1234
+ }
1235
+ if (/\b(calendar|schedule|event|events)\b/.test(normalized)) {
1236
+ return { type: "navigate", target: "/simple-calendar" };
1237
+ }
1174
1238
  if (/\b(wallet|inventory|address|balance)\b/.test(normalized)) {
1175
1239
  return { type: "navigate", target: "/wallet" };
1176
1240
  }
@@ -1186,6 +1250,51 @@ function classifyAssistantAction(text) {
1186
1250
  return { type: "noop", target: null };
1187
1251
  }
1188
1252
 
1253
+ function navigationDetailForTarget(target) {
1254
+ switch (target) {
1255
+ case "/notes":
1256
+ return { viewId: "notes", viewPath: "/notes", viewLabel: "Notes" };
1257
+ case "/simple-calendar":
1258
+ return {
1259
+ viewId: "simple-calendar",
1260
+ viewPath: "/simple-calendar",
1261
+ viewLabel: "Simple Calendar",
1262
+ };
1263
+ case "/wallet":
1264
+ return { viewId: "wallet", viewPath: "/wallet", viewLabel: "Wallet" };
1265
+ case "/views":
1266
+ return { viewPath: "/views", viewLabel: "Springboard" };
1267
+ case "/settings":
1268
+ return {
1269
+ viewId: "settings",
1270
+ viewPath: "/settings",
1271
+ viewLabel: "Settings",
1272
+ };
1273
+ case "/chat":
1274
+ return { viewPath: "/chat", viewLabel: "Chat" };
1275
+ default:
1276
+ return typeof target === "string" && target.length > 0
1277
+ ? { viewPath: target }
1278
+ : null;
1279
+ }
1280
+ }
1281
+
1282
+ function maybeBroadcastAssistantNavigation(text) {
1283
+ if (!HUMAN_CHAT_FIXTURES) return;
1284
+ const action = classifyAssistantAction(text);
1285
+ if (action.type !== "navigate") return;
1286
+ const detail = navigationDetailForTarget(action.target);
1287
+ if (!detail) return;
1288
+ setTimeout(() => {
1289
+ broadcastWsEvent({
1290
+ type: "shell:navigate:view",
1291
+ viewType: "gui",
1292
+ alwaysOnTop: false,
1293
+ ...detail,
1294
+ });
1295
+ }, 50);
1296
+ }
1297
+
1189
1298
  function createDeterministicAssistantText({ body, conversationId, transport }) {
1190
1299
  const inputText = normalizeAssistantInput(body?.text ?? body?.message);
1191
1300
  if (inputText === SMOKE_VOICE_TRANSCRIPT) {
@@ -1202,6 +1311,21 @@ function createDeterministicAssistantText({ body, conversationId, transport }) {
1202
1311
  action: classifyAssistantAction(inputText),
1203
1312
  }).slice(0, -2)}`;
1204
1313
  }
1314
+ const action = classifyAssistantAction(inputText);
1315
+ if (HUMAN_CHAT_FIXTURES) {
1316
+ if (action.type === "navigate") {
1317
+ const label =
1318
+ action.target === "/simple-calendar"
1319
+ ? "Simple Calendar"
1320
+ : action.target === "/notes"
1321
+ ? "Notes"
1322
+ : action.target?.replace(/^\//, "") || "that view";
1323
+ return `Opening ${label}.`;
1324
+ }
1325
+ return inputText
1326
+ ? `I received "${inputText}".`
1327
+ : "I am ready when you are.";
1328
+ }
1205
1329
  const payload = {
1206
1330
  fixture: "ui-smoke-assistant-v1",
1207
1331
  registrySeam: "strict-fixture-registry",
@@ -1212,7 +1336,7 @@ function createDeterministicAssistantText({ body, conversationId, transport }) {
1212
1336
  length: inputText.length,
1213
1337
  hash: stableTextHash(inputText),
1214
1338
  },
1215
- action: classifyAssistantAction(inputText),
1339
+ action,
1216
1340
  };
1217
1341
  return JSON.stringify(payload);
1218
1342
  }
@@ -3177,7 +3301,13 @@ const server = http.createServer(async (req, res) => {
3177
3301
  }
3178
3302
 
3179
3303
  if (req.method === "GET" && url.pathname === "/api/notifications") {
3180
- sendJson(req, res, 200, { notifications: [], unreadCount: 0 });
3304
+ const notifications = SMOKE_NOTIFICATIONS ? smokeNotifications : [];
3305
+ sendJson(req, res, 200, {
3306
+ notifications,
3307
+ unreadCount: notifications.filter((notification) => {
3308
+ return !notification.readAt;
3309
+ }).length,
3310
+ });
3181
3311
  return;
3182
3312
  }
3183
3313
 
@@ -3659,6 +3789,7 @@ const server = http.createServer(async (req, res) => {
3659
3789
  writeSseEvent(res, { type: "token", text, fullText: text });
3660
3790
  writeSseEvent(res, { type: "done", fullText: text, agentName: "Eliza" });
3661
3791
  res.end();
3792
+ maybeBroadcastAssistantNavigation(body.text);
3662
3793
  return;
3663
3794
  }
3664
3795
 
@@ -3672,6 +3803,7 @@ const server = http.createServer(async (req, res) => {
3672
3803
  });
3673
3804
  appendStubMessage(conversationId, createStubMessage("assistant", text));
3674
3805
  sendJson(req, res, 200, { text, agentName: "Eliza" });
3806
+ maybeBroadcastAssistantNavigation(body.text);
3675
3807
  return;
3676
3808
  }
3677
3809
  }
@@ -4296,6 +4428,15 @@ const server = http.createServer(async (req, res) => {
4296
4428
  return;
4297
4429
  }
4298
4430
 
4431
+ if (req.method === "GET" && url.pathname === "/api/approvals") {
4432
+ // Mirror the canonical pending-actions route
4433
+ // (packages/agent/src/api/approval-routes.ts). With no approval service in
4434
+ // the smoke stub, the real route serves an empty pending list so the home
4435
+ // widget stays quiet and retries without logging a 501.
4436
+ sendJson(req, res, 200, { pending: [] });
4437
+ return;
4438
+ }
4439
+
4299
4440
  if (
4300
4441
  req.method === "GET" &&
4301
4442
  url.pathname === "/api/computer-use/approvals/stream"
@@ -5014,6 +5155,21 @@ const server = http.createServer(async (req, res) => {
5014
5155
  return;
5015
5156
  }
5016
5157
 
5158
+ if (req.method === "GET" && url.pathname === "/api/simple-views/state") {
5159
+ sendJson(req, res, 200, simpleViewsState);
5160
+ return;
5161
+ }
5162
+
5163
+ if (req.method === "POST" && url.pathname === "/api/simple-views/interact") {
5164
+ await drainRequest(req);
5165
+ sendJson(req, res, 200, {
5166
+ success: true,
5167
+ text: "OK",
5168
+ state: simpleViewsState,
5169
+ });
5170
+ return;
5171
+ }
5172
+
5017
5173
  if (
5018
5174
  req.method === "GET" &&
5019
5175
  url.pathname === "/api/__ui-smoke/unhandled-requests"
@@ -5182,6 +5338,15 @@ wsServer.on("connection", (ws) => {
5182
5338
  ws.on("message", () => {});
5183
5339
  });
5184
5340
 
5341
+ function broadcastWsEvent(payload) {
5342
+ const message = JSON.stringify(payload);
5343
+ for (const client of wsServer.clients) {
5344
+ if (client.readyState === 1) {
5345
+ client.send(message);
5346
+ }
5347
+ }
5348
+ }
5349
+
5185
5350
  server.listen(port, "127.0.0.1", () => {
5186
5351
  console.log(
5187
5352
  `[playwright-ui-smoke-api-stub] listening on http://127.0.0.1:${port}`,
@@ -1,6 +1,10 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
6
+ RM_PATH_RECURSIVE="${REPO_ROOT}/packages/scripts/rm-path-recursive.mjs"
7
+
4
8
  resolve_pod() {
5
9
  if command -v pod >/dev/null 2>&1; then
6
10
  return 0
@@ -57,7 +61,7 @@ fi
57
61
 
58
62
  if [ -e "${TRUNK_REPO_DIR}" ]; then
59
63
  echo "Removing partial CocoaPods trunk repo at ${TRUNK_REPO_DIR}"
60
- rm -rf "${TRUNK_REPO_DIR}"
64
+ node "${RM_PATH_RECURSIVE}" "${TRUNK_REPO_DIR}"
61
65
  fi
62
66
 
63
67
  echo "Adding CocoaPods trunk repo from ${TRUNK_REPO_URL}"
@@ -1,24 +1,71 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import { spawnSync } from "node:child_process";
3
4
  import fs from "node:fs";
4
5
  import path from "node:path";
5
- import { fileURLToPath } from "node:url";
6
+ import { resolveMainAppDir } from "./lib/app-dir.mjs";
7
+ import { resolveRepoRootFromImportMeta } from "./lib/repo-root.mjs";
6
8
  import { APP_DIST_BOOTSTRAP_ASSETS } from "./lib/static-asset-manifest.mjs";
7
9
 
8
- const here = path.dirname(fileURLToPath(import.meta.url));
9
- const repoRoot = path.resolve(here, "..");
10
- const appDir = path.join(repoRoot, "apps", "app");
10
+ const repoRoot = resolveRepoRootFromImportMeta(import.meta.url, {
11
+ fallbackToCwd: true,
12
+ });
13
+ const appDir = resolveMainAppDir(repoRoot, "app");
11
14
  const distDir = path.join(appDir, "dist");
12
15
  const publicDir = path.join(appDir, "public");
16
+ const cleanupHelperScript = resolveCleanupHelperScript();
13
17
  const heavyDirs = ["animations", "vrms", "worlds"];
14
18
 
15
19
  function exists(candidate) {
16
20
  return fs.existsSync(candidate);
17
21
  }
18
22
 
23
+ function resolveCleanupHelperScript() {
24
+ const candidates = [
25
+ path.join(repoRoot, "packages", "scripts", "rm-path-recursive.mjs"),
26
+ path.join(
27
+ repoRoot,
28
+ "eliza",
29
+ "packages",
30
+ "scripts",
31
+ "rm-path-recursive.mjs",
32
+ ),
33
+ ];
34
+ return candidates.find(exists) ?? candidates[0];
35
+ }
36
+
37
+ function removePathRecursive(targetPath) {
38
+ if (!exists(targetPath)) {
39
+ return;
40
+ }
41
+
42
+ const result = spawnSync(
43
+ "node",
44
+ [cleanupHelperScript, path.relative(repoRoot, targetPath)],
45
+ {
46
+ cwd: repoRoot,
47
+ encoding: "utf8",
48
+ stdio: "pipe",
49
+ },
50
+ );
51
+
52
+ if (result.error) {
53
+ throw result.error;
54
+ }
55
+ if (result.status !== 0) {
56
+ const output = [result.stdout, result.stderr]
57
+ .filter(Boolean)
58
+ .join("\n")
59
+ .trim();
60
+ throw new Error(
61
+ `cleanup helper failed for ${targetPath}${output ? `:\n${output}` : ""}`,
62
+ );
63
+ }
64
+ }
65
+
19
66
  function resetHeavyDirs() {
20
67
  for (const dir of heavyDirs) {
21
- fs.rmSync(path.join(distDir, dir), { recursive: true, force: true });
68
+ removePathRecursive(path.join(distDir, dir));
22
69
  }
23
70
  }
24
71
 
@@ -1,7 +1,9 @@
1
1
  import assert from "node:assert/strict";
2
+ import { execFileSync } from "node:child_process";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
5
  import test from "node:test";
6
+ import { fileURLToPath } from "node:url";
5
7
 
6
8
  import {
7
9
  ANDROID_APP_ACTION_CAPABILITIES,
@@ -16,6 +18,22 @@ import {
16
18
  validateAndroidAppActionsXmlResource,
17
19
  } from "./run-mobile-build.mjs";
18
20
 
21
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
22
+ const repoRoot = path.resolve(scriptDir, "..", "..", "..");
23
+ const cleanupHelperScript = path.join(
24
+ repoRoot,
25
+ "packages",
26
+ "scripts",
27
+ "rm-path-recursive.mjs",
28
+ );
29
+
30
+ function removePathRecursive(targetPath) {
31
+ execFileSync(process.execPath, [cleanupHelperScript, targetPath], {
32
+ cwd: repoRoot,
33
+ stdio: "inherit",
34
+ });
35
+ }
36
+
19
37
  function escapeRegExp(value) {
20
38
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
21
39
  }
@@ -86,7 +104,7 @@ test("Android cloud strip keeps only the active Java package root", () => {
86
104
  assert.equal(fs.existsSync(stale), false);
87
105
  assert.equal(fs.existsSync(legacy), false);
88
106
  } finally {
89
- fs.rmSync(tmp, { recursive: true, force: true });
107
+ removePathRecursive(tmp);
90
108
  }
91
109
  });
92
110
 
@@ -1,15 +1,16 @@
1
+ import { execFileSync } from "node:child_process";
1
2
  import fs from "node:fs";
2
3
  import os from "node:os";
3
4
  import path from "node:path";
4
5
  import { fileURLToPath } from "node:url";
5
6
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
-
7
7
  import {
8
8
  MTP_FORK_SRC_CANDIDATES,
9
9
  mtpBuilderRepoRoot,
10
10
  mtpForceRebuildRequested,
11
11
  mtpSliceReuse,
12
12
  } from "./lib/mobile-build-decisions.mjs";
13
+ import { resolveRepoRootFromImportMeta } from "./lib/repo-root.mjs";
13
14
 
14
15
  // Far-future mtimes keep these tests independent of the checkout's own file
15
16
  // timestamps (the worktree stamps every file at checkout time, including the
@@ -18,6 +19,21 @@ const FUTURE_ARTIFACT = new Date("2031-01-01T00:00:00Z").getTime();
18
19
  const OLDER_SOURCE = new Date("2030-01-01T00:00:00Z").getTime();
19
20
  const NEWER_SOURCE = new Date("2032-01-01T00:00:00Z").getTime();
20
21
 
22
+ const repoRoot = resolveRepoRootFromImportMeta(import.meta.url);
23
+ const cleanupHelperScript = path.join(
24
+ repoRoot,
25
+ "packages",
26
+ "scripts",
27
+ "rm-path-recursive.mjs",
28
+ );
29
+
30
+ function removePathRecursive(targetPath: string) {
31
+ execFileSync(process.execPath, [cleanupHelperScript, targetPath], {
32
+ cwd: repoRoot,
33
+ stdio: "inherit",
34
+ });
35
+ }
36
+
21
37
  let tmp: string;
22
38
 
23
39
  beforeEach(() => {
@@ -25,7 +41,7 @@ beforeEach(() => {
25
41
  });
26
42
 
27
43
  afterEach(() => {
28
- fs.rmSync(tmp, { recursive: true, force: true });
44
+ removePathRecursive(tmp);
29
45
  });
30
46
 
31
47
  function touch(file: string, mtimeMs: number) {
@@ -118,7 +134,7 @@ describe("mtpSliceReuse", () => {
118
134
  describe("MTP_FORK_SRC_CANDIDATES (no drift vs the builder)", () => {
119
135
  it("mirrors build-llama-cpp-mtp.mjs: the in-repo fork + the ios-deps fallback, and nothing divergent", () => {
120
136
  const here = path.dirname(fileURLToPath(import.meta.url));
121
- const repoRoot = path.resolve(here, "..", "..", "..");
137
+ const expectedRepoRoot = path.resolve(here, "..", "..", "..");
122
138
  const forkSuffix = path.join(
123
139
  "plugins",
124
140
  "plugin-local-inference",
@@ -133,7 +149,7 @@ describe("MTP_FORK_SRC_CANDIDATES (no drift vs the builder)", () => {
133
149
  "src",
134
150
  );
135
151
 
136
- expect(repoRoot).toBe(mtpBuilderRepoRoot);
152
+ expect(expectedRepoRoot).toBe(mtpBuilderRepoRoot);
137
153
  expect(MTP_FORK_SRC_CANDIDATES).toEqual(
138
154
  [
139
155
  process.env.ELIZA_MTP_LLAMA_CPP_SRC?.trim(),