@elizaos/app-core 2.0.0-beta.1 → 2.0.0-beta.2

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 (43) hide show
  1. package/package.json +2 -2
  2. package/platforms/electrobun/native/macos/window-effects.mm +103 -0
  3. package/platforms/electrobun/package.json +9 -0
  4. package/platforms/electrobun/src/__stubs__/bun-ffi.ts +16 -0
  5. package/platforms/electrobun/src/libMacWindowEffects.dylib +0 -0
  6. package/platforms/electrobun/src/native/agent.ts +74 -3
  7. package/platforms/electrobun/src/native/desktop.ts +39 -6
  8. package/platforms/electrobun/src/native/mac-window-effects.ts +61 -1
  9. package/platforms/electrobun/src/native/permissions-shared.ts +3 -2
  10. package/platforms/electrobun/src/native/permissions.ts +11 -6
  11. package/platforms/electrobun/src/rpc-handlers.ts +7 -0
  12. package/platforms/electrobun/src/rpc-schema.ts +39 -4
  13. package/platforms/electrobun/src/runtime-permissions.ts +7 -1
  14. package/runtime/ensure-local-inference-handler.d.ts +1 -0
  15. package/runtime/ensure-local-inference-handler.d.ts.map +1 -1
  16. package/runtime/ensure-local-inference-handler.js +9 -0
  17. package/runtime/mode/remote-forwarder.d.ts.map +1 -1
  18. package/runtime/mode/remote-forwarder.js +1 -1
  19. package/runtime/mode/runtime-mode.d.ts +20 -2
  20. package/runtime/mode/runtime-mode.d.ts.map +1 -1
  21. package/runtime/mode/runtime-mode.js +69 -1
  22. package/scripts/aosp/stage-default-models.mjs +2 -2
  23. package/scripts/build-llama-cpp-dflash.mjs +75 -40
  24. package/scripts/kernel-patches/metal-kernels.mjs +357 -337
  25. package/scripts/lib/read-app-identity.mjs +5 -1
  26. package/services/local-inference/catalog.d.ts +2 -1
  27. package/services/local-inference/catalog.d.ts.map +1 -1
  28. package/services/local-inference/catalog.js +131 -12
  29. package/services/local-inference/downloader.d.ts +2 -0
  30. package/services/local-inference/downloader.d.ts.map +1 -1
  31. package/services/local-inference/downloader.js +300 -1
  32. package/services/local-inference/manifest/validator.d.ts.map +1 -1
  33. package/services/local-inference/manifest/validator.js +48 -0
  34. package/services/local-inference/providers.d.ts +1 -1
  35. package/services/local-inference/providers.js +6 -6
  36. package/services/local-inference/registry.d.ts.map +1 -1
  37. package/services/local-inference/registry.js +10 -1
  38. package/services/local-inference/types.d.ts +6 -0
  39. package/services/local-inference/types.d.ts.map +1 -1
  40. package/test/helpers/real-runtime.ts +21 -20
  41. package/platforms/electrobun/src/native/permissions-darwin.ts +0 -342
  42. package/platforms/electrobun/src/native/permissions-linux.ts +0 -34
  43. package/platforms/electrobun/src/native/permissions-win32.ts +0 -56
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/app-core",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.2",
4
4
  "description": "Shared application core for elizaOS white-label agent apps.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -50,7 +50,7 @@
50
50
  "@capacitor/preferences": "^8.0.1",
51
51
  "@capacitor/push-notifications": "^8.0.0",
52
52
  "@clack/prompts": "^1.0.0",
53
- "@elizaos/agent": "2.0.0-beta.1",
53
+ "@elizaos/agent": "2.0.0-beta.2",
54
54
  "@elizaos/capacitor-llama": "2.0.0-beta.1",
55
55
  "@elizaos/core": "2.0.0-beta.1",
56
56
  "@elizaos/plugin-anthropic": "2.0.0-beta.1",
@@ -3,6 +3,8 @@
3
3
  #import <AVFoundation/AVFoundation.h>
4
4
  #import <Availability.h>
5
5
  #import <CoreGraphics/CoreGraphics.h>
6
+ #include <stdlib.h>
7
+ #include <string.h>
6
8
 
7
9
  static NSString *const kElectrobunVibrancyViewIdentifier =
8
10
  @"ElectrobunVibrancyView";
@@ -17,6 +19,32 @@ static NSString *const kElectrobunNativeDragRightEdgeIdentifier =
17
19
  static NSString *const kElizaInactiveTrafficLightsOverlayIdentifier =
18
20
  @"ElizaInactiveTrafficLightsOverlay";
19
21
 
22
+ static NSMutableArray<NSURL *> *elizaSecurityScopedUrls(void) {
23
+ static NSMutableArray<NSURL *> *urls = nil;
24
+ static dispatch_once_t onceToken;
25
+ dispatch_once(&onceToken, ^{
26
+ urls = [[NSMutableArray alloc] init];
27
+ });
28
+ return urls;
29
+ }
30
+
31
+ static char *elizaCopyCString(NSString *value) {
32
+ if (value == nil) {
33
+ return nullptr;
34
+ }
35
+ const char *utf8 = [value UTF8String];
36
+ if (utf8 == nullptr) {
37
+ return nullptr;
38
+ }
39
+ size_t len = strlen(utf8);
40
+ char *out = (char *)malloc(len + 1);
41
+ if (out == nullptr) {
42
+ return nullptr;
43
+ }
44
+ memcpy(out, utf8, len + 1);
45
+ return out;
46
+ }
47
+
20
48
  /** Transparent strip for moving the window. WKWebView does not honor
21
49
  * -webkit-app-region reliably on system WebKit; this view is stacked
22
50
  * NSWindowAbove the web view so safe empty/title zones hit AppKit first.
@@ -584,6 +612,81 @@ extern "C" void requestMicrophonePermission(void) {
584
612
  }];
585
613
  }
586
614
 
615
+ extern "C" void freeNativeCString(char *value) {
616
+ if (value != nullptr) {
617
+ free(value);
618
+ }
619
+ }
620
+
621
+ extern "C" char *createSecurityScopedBookmark(const char *path) {
622
+ @autoreleasepool {
623
+ if (path == nullptr || path[0] == '\0') {
624
+ return nullptr;
625
+ }
626
+ NSString *pathString = [NSString stringWithUTF8String:path];
627
+ if (pathString == nil) {
628
+ return nullptr;
629
+ }
630
+ NSURL *url = [NSURL fileURLWithPath:pathString isDirectory:YES];
631
+ if (url == nil) {
632
+ return nullptr;
633
+ }
634
+ NSError *error = nil;
635
+ NSData *bookmark = [url
636
+ bookmarkDataWithOptions:NSURLBookmarkCreationWithSecurityScope
637
+ includingResourceValuesForKeys:nil
638
+ relativeToURL:nil
639
+ error:&error];
640
+ if (bookmark == nil || error != nil) {
641
+ return nullptr;
642
+ }
643
+ return elizaCopyCString([bookmark base64EncodedStringWithOptions:0]);
644
+ }
645
+ }
646
+
647
+ extern "C" char *startAccessingSecurityScopedBookmark(const char *base64) {
648
+ @autoreleasepool {
649
+ if (base64 == nullptr || base64[0] == '\0') {
650
+ return nullptr;
651
+ }
652
+ NSString *base64String = [NSString stringWithUTF8String:base64];
653
+ if (base64String == nil) {
654
+ return nullptr;
655
+ }
656
+ NSData *bookmark = [[NSData alloc]
657
+ initWithBase64EncodedString:base64String
658
+ options:NSDataBase64DecodingIgnoreUnknownCharacters];
659
+ if (bookmark == nil) {
660
+ return nullptr;
661
+ }
662
+ BOOL stale = NO;
663
+ NSError *error = nil;
664
+ NSURL *url = [NSURL URLByResolvingBookmarkData:bookmark
665
+ options:NSURLBookmarkResolutionWithSecurityScope
666
+ relativeToURL:nil
667
+ bookmarkDataIsStale:&stale
668
+ error:&error];
669
+ if (url == nil || error != nil) {
670
+ return nullptr;
671
+ }
672
+ if (![url startAccessingSecurityScopedResource]) {
673
+ return nullptr;
674
+ }
675
+ [elizaSecurityScopedUrls() addObject:url];
676
+ return elizaCopyCString([url path]);
677
+ }
678
+ }
679
+
680
+ extern "C" void stopAccessingSecurityScopedBookmarks(void) {
681
+ @autoreleasepool {
682
+ NSMutableArray<NSURL *> *urls = elizaSecurityScopedUrls();
683
+ for (NSURL *url in urls) {
684
+ [url stopAccessingSecurityScopedResource];
685
+ }
686
+ [urls removeAllObjects];
687
+ }
688
+ }
689
+
587
690
  extern "C" bool enableWindowVibrancy(void *windowPtr) {
588
691
  if (windowPtr == nullptr) {
589
692
  return false;
@@ -2,6 +2,15 @@
2
2
  "name": "@elizaos/electrobun",
3
3
  "version": "2.0.0-beta.1",
4
4
  "type": "module",
5
+ "files": [
6
+ "assets",
7
+ "entitlements",
8
+ "scripts",
9
+ "src",
10
+ "electrobun.config.ts",
11
+ "README.md",
12
+ "tsconfig.json"
13
+ ],
5
14
  "scripts": {
6
15
  "dev": "bun run build:preload && PATH=\"$PWD/scripts/bin:$PATH\" bunx electrobun dev",
7
16
  "build": "bun run build:preload && ELECTROBUN_SKIP_CODESIGN=1 PATH=\"$PWD/scripts/bin:$PATH\" bunx electrobun build",
@@ -10,10 +10,26 @@ export const FFIType = {
10
10
  f64: 2,
11
11
  i32: 3,
12
12
  cstring: 4,
13
+ void: 5,
13
14
  } as const;
14
15
 
15
16
  export type Pointer = number;
16
17
 
18
+ export class CString {
19
+ private readonly value: unknown;
20
+ constructor(ptr: unknown) {
21
+ this.value = ptr;
22
+ }
23
+ toString(): string {
24
+ void this.value;
25
+ return "";
26
+ }
27
+ }
28
+
29
+ export function ptr(_value: ArrayBufferView): Pointer {
30
+ return 0;
31
+ }
32
+
17
33
  export function dlopen(
18
34
  _path: string,
19
35
  _symbols: Record<string, unknown>,
@@ -28,13 +28,13 @@ import crypto from "node:crypto";
28
28
  import fs from "node:fs";
29
29
  import os from "node:os";
30
30
  import path from "node:path";
31
- import { Utils } from "electrobun/bun";
32
31
  import {
33
32
  resolveApiToken,
34
33
  resolveDesktopApiPort,
35
34
  resolveDisableAutoApiToken,
36
35
  setApiToken,
37
36
  } from "@elizaos/shared";
37
+ import { Utils } from "electrobun/bun";
38
38
  import { resolveDesktopRuntimeMode } from "../api-base";
39
39
  import { getBrandConfig } from "../brand-config";
40
40
  import { DEFAULT_API_PORT } from "../constants";
@@ -159,7 +159,8 @@ function normalizeEnvPath(value: string | undefined): string | null {
159
159
  }
160
160
 
161
161
  function isStoreBuildVariant(env: NodeJS.ProcessEnv = process.env): boolean {
162
- const raw = env.MILADY_BUILD_VARIANT?.trim() || env.ELIZA_BUILD_VARIANT?.trim();
162
+ const raw =
163
+ env.MILADY_BUILD_VARIANT?.trim() || env.ELIZA_BUILD_VARIANT?.trim();
163
164
  return raw?.toLowerCase() === "store";
164
165
  }
165
166
 
@@ -229,7 +230,10 @@ function buildExistingElizaInstallCandidates(opts?: {
229
230
  normalizeEnvPath(env.MILADY_CONFIG_PATH) ??
230
231
  normalizeEnvPath(env.ELIZA_CONFIG_PATH);
231
232
  const stateDirFromEnv = resolveExplicitStateDir(env);
232
- const defaultStateDir = joinPortable(homedir, `.${resolveStateNamespace(env)}`);
233
+ const defaultStateDir = joinPortable(
234
+ homedir,
235
+ `.${resolveStateNamespace(env)}`,
236
+ );
233
237
 
234
238
  const candidates = [
235
239
  configPathFromEnv
@@ -316,6 +320,69 @@ export function inspectExistingElizaInstall(opts?: {
316
320
  };
317
321
  }
318
322
 
323
+ export function migrateDesktopStateDirFromPath(
324
+ fromPath: string,
325
+ opts?: { env?: NodeJS.ProcessEnv },
326
+ ): 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
+ }
384
+ }
385
+
319
386
  // ---------------------------------------------------------------------------
320
387
  // Diagnostic logging
321
388
  // ---------------------------------------------------------------------------
@@ -1630,6 +1697,10 @@ export class AgentManager {
1630
1697
  return inspectExistingElizaInstall();
1631
1698
  }
1632
1699
 
1700
+ migrateStateDir(params: { fromPath: string }): StateDirMigrationResult {
1701
+ return migrateDesktopStateDirFromPath(params.fromPath);
1702
+ }
1703
+
1633
1704
  getPort(): number | null {
1634
1705
  return this.status.port;
1635
1706
  }
@@ -71,10 +71,13 @@ import {
71
71
  getStartupDiagnosticsSnapshot,
72
72
  } from "./agent";
73
73
  import {
74
+ createSecurityScopedBookmark,
74
75
  isAppActive,
75
76
  isKeyWindow,
76
77
  makeKeyAndOrderFront,
77
78
  orderOut,
79
+ startAccessingSecurityScopedBookmark,
80
+ stopAccessingSecurityScopedBookmarks,
78
81
  } from "./mac-window-effects";
79
82
  import {
80
83
  linuxSysfsOnBattery,
@@ -2018,11 +2021,8 @@ X-GNOME-Autostart-enabled=true
2018
2021
  *
2019
2022
  * The `bookmark` field is the OS-specific persistence handle: on macOS, a
2020
2023
  * base64 NSURLBookmarkCreationOptions.WithSecurityScope blob the caller
2021
- * stores and re-resolves on next launch. Bookmark creation requires a
2022
- * native bridge that this build does not yet ship, so we currently return
2023
- * `bookmark: null` and rely on the picker re-prompt at next launch when
2024
- * the path no longer resolves under the sandbox. TODO: wire into the
2025
- * `native/` module's NSURL bookmark API to make grants persistent.
2024
+ * stores and re-resolves on next launch. Non-macOS platforms return null
2025
+ * because portals / AppContainer do not use NSURL bookmarks.
2026
2026
  */
2027
2027
  async pickWorkspaceFolder(options: {
2028
2028
  defaultPath?: string;
@@ -2038,7 +2038,40 @@ X-GNOME-Autostart-enabled=true
2038
2038
  if (canceled) {
2039
2039
  return { canceled: true, path: "", bookmark: null };
2040
2040
  }
2041
- return { canceled: false, path: filePaths[0], bookmark: null };
2041
+ const selectedPath = filePaths[0] ?? "";
2042
+ if (!selectedPath) {
2043
+ return { canceled: true, path: "", bookmark: null };
2044
+ }
2045
+ const bookmark =
2046
+ process.platform === "darwin"
2047
+ ? createSecurityScopedBookmark(selectedPath)
2048
+ : null;
2049
+ return { canceled: false, path: selectedPath, bookmark };
2050
+ }
2051
+
2052
+ resolveWorkspaceFolderBookmark(options: { bookmark: string }): {
2053
+ ok: boolean;
2054
+ path: string;
2055
+ stale?: boolean;
2056
+ error?: string;
2057
+ } {
2058
+ if (process.platform !== "darwin") {
2059
+ return { ok: true, path: "" };
2060
+ }
2061
+ const path = startAccessingSecurityScopedBookmark(options.bookmark);
2062
+ if (!path) {
2063
+ return {
2064
+ ok: false,
2065
+ path: "",
2066
+ error: "Unable to resolve security-scoped bookmark.",
2067
+ };
2068
+ }
2069
+ return { ok: true, path };
2070
+ }
2071
+
2072
+ releaseWorkspaceFolderBookmarks(): { ok: true } {
2073
+ stopAccessingSecurityScopedBookmarks();
2074
+ return { ok: true };
2042
2075
  }
2043
2076
 
2044
2077
  // MARK: - Helpers
@@ -1,4 +1,4 @@
1
- import { dlopen, FFIType, type Pointer } from "bun:ffi";
1
+ import { CString, dlopen, FFIType, type Pointer, ptr } from "bun:ffi";
2
2
  import { existsSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
 
@@ -16,6 +16,10 @@ type MacEffectsSymbols = {
16
16
  makeKeyAndOrderFrontWindow(ptr: Pointer): boolean;
17
17
  isAppActive(): boolean;
18
18
  isWindowKey(ptr: Pointer): boolean;
19
+ createSecurityScopedBookmark(path: Pointer): Pointer | null;
20
+ startAccessingSecurityScopedBookmark(bookmark: Pointer): Pointer | null;
21
+ stopAccessingSecurityScopedBookmarks(): void;
22
+ freeNativeCString(value: Pointer): void;
19
23
  };
20
24
 
21
25
  type LoadedMacEffectsLib = { symbols: MacEffectsSymbols; close(): void };
@@ -52,6 +56,19 @@ function loadLib(): MacEffectsLib {
52
56
  },
53
57
  isAppActive: { args: [], returns: FFIType.bool },
54
58
  isWindowKey: { args: [FFIType.ptr], returns: FFIType.bool },
59
+ createSecurityScopedBookmark: {
60
+ args: [FFIType.ptr],
61
+ returns: FFIType.ptr,
62
+ },
63
+ startAccessingSecurityScopedBookmark: {
64
+ args: [FFIType.ptr],
65
+ returns: FFIType.ptr,
66
+ },
67
+ stopAccessingSecurityScopedBookmarks: {
68
+ args: [],
69
+ returns: FFIType.void,
70
+ },
71
+ freeNativeCString: { args: [FFIType.ptr], returns: FFIType.void },
55
72
  }) as MacEffectsLib;
56
73
  } catch (err) {
57
74
  console.warn("[MacEffects] Failed to load dylib:", err);
@@ -59,6 +76,25 @@ function loadLib(): MacEffectsLib {
59
76
  }
60
77
  }
61
78
 
79
+ function cStringBuffer(value: string): Buffer {
80
+ const bytes = Buffer.from(value, "utf8");
81
+ const buffer = Buffer.alloc(bytes.byteLength + 1);
82
+ bytes.copy(buffer);
83
+ return buffer;
84
+ }
85
+
86
+ function takeNativeString(
87
+ lib: LoadedMacEffectsLib,
88
+ value: Pointer | null,
89
+ ): string | null {
90
+ if (!value) return null;
91
+ try {
92
+ return new CString(value).toString();
93
+ } finally {
94
+ lib.symbols.freeNativeCString(value);
95
+ }
96
+ }
97
+
62
98
  function getLib(): LoadedMacEffectsLib | null {
63
99
  if (process.platform !== "darwin") return null;
64
100
  if (_lib === undefined) {
@@ -116,3 +152,27 @@ export function isAppActive(): boolean {
116
152
  export function isKeyWindow(ptr: Pointer): boolean {
117
153
  return getLib()?.symbols.isWindowKey(ptr) ?? false;
118
154
  }
155
+
156
+ export function createSecurityScopedBookmark(path: string): string | null {
157
+ const lib = getLib();
158
+ if (!lib || !path.trim()) return null;
159
+ const pathBuffer = cStringBuffer(path);
160
+ const result = lib.symbols.createSecurityScopedBookmark(ptr(pathBuffer));
161
+ return takeNativeString(lib, result);
162
+ }
163
+
164
+ export function startAccessingSecurityScopedBookmark(
165
+ bookmark: string,
166
+ ): string | null {
167
+ const lib = getLib();
168
+ if (!lib || !bookmark.trim()) return null;
169
+ const bookmarkBuffer = cStringBuffer(bookmark);
170
+ const result = lib.symbols.startAccessingSecurityScopedBookmark(
171
+ ptr(bookmarkBuffer),
172
+ );
173
+ return takeNativeString(lib, result);
174
+ }
175
+
176
+ export function stopAccessingSecurityScopedBookmarks(): void {
177
+ getLib()?.symbols.stopAccessingSecurityScopedBookmarks();
178
+ }
@@ -16,7 +16,7 @@ import type {
16
16
 
17
17
  export type SystemPermissionId = PermissionId;
18
18
 
19
- /** Local variant uses an index signature (the canonical contract uses explicit keys). */
19
+ /** Local variant keeps a loose index signature for legacy Electrobun RPC code. */
20
20
  export interface AllPermissionsState {
21
21
  [key: string]: PermissionState;
22
22
  }
@@ -133,7 +133,8 @@ export const SYSTEM_PERMISSIONS: SystemPermissionDefinition[] = [
133
133
  {
134
134
  id: "notifications",
135
135
  name: "Notifications",
136
- description: "Show system notifications for reminders and background results",
136
+ description:
137
+ "Show system notifications for reminders and background results",
137
138
  icon: "bell",
138
139
  platforms: ["darwin", "win32", "linux"],
139
140
  requiredForFeatures: ["notifications", "lifeops"],
@@ -5,9 +5,9 @@
5
5
  * Shared implementation ported forward to Electrobun; no runtime-specific APIs required.
6
6
  */
7
7
 
8
- import type { SendToWebview } from "../types.js";
9
8
  import { ALL_PROBERS } from "@elizaos/agent/services/permissions/probers/index";
10
9
  import { getMacPermissionDeepLink } from "@elizaos/shared";
10
+ import type { SendToWebview } from "../types.js";
11
11
  import type {
12
12
  AllPermissionsState,
13
13
  PermissionState,
@@ -82,7 +82,8 @@ async function openPermissionSettings(id: SystemPermissionId): Promise<void> {
82
82
  notifications: "notifications",
83
83
  };
84
84
  const panel = settingsMap[id];
85
- if (panel) await spawnDetached(["sh", "-lc", `gnome-control-center ${panel}`]);
85
+ if (panel)
86
+ await spawnDetached(["sh", "-lc", `gnome-control-center ${panel}`]);
86
87
  }
87
88
  }
88
89
 
@@ -177,10 +178,14 @@ export class PermissionManager {
177
178
  }
178
179
 
179
180
  if (id === "shell") {
180
- const state = buildPermissionState(id, this.shellEnabled ? "granted" : "denied", {
181
- canRequest: false,
182
- lastRequested: Date.now(),
183
- });
181
+ const state = buildPermissionState(
182
+ id,
183
+ this.shellEnabled ? "granted" : "denied",
184
+ {
185
+ canRequest: false,
186
+ lastRequested: Date.now(),
187
+ },
188
+ );
184
189
  this.cache.set(id, state);
185
190
  return state;
186
191
  }
@@ -244,6 +244,8 @@ export function buildBunRpcHandlers({
244
244
  },
245
245
  agentStatus: async () => agent.getStatus(),
246
246
  agentInspectExistingInstall: async () => agent.inspectExistingInstall(),
247
+ agentMigrateStateDir: async (params: { fromPath: string }) =>
248
+ agent.migrateStateDir(params),
247
249
  /** Renderer `fetch` after native dialogs can stall; main POST matches menu reset pattern. */
248
250
  agentPostReset: async (
249
251
  params?: { apiBase?: string; bearerToken?: string } | null,
@@ -640,6 +642,11 @@ export function buildBunRpcHandlers({
640
642
  desktopPickWorkspaceFolder: async (
641
643
  params: Parameters<typeof desktop.pickWorkspaceFolder>[0],
642
644
  ) => desktop.pickWorkspaceFolder(params),
645
+ desktopResolveWorkspaceFolderBookmark: async (
646
+ params: Parameters<typeof desktop.resolveWorkspaceFolderBookmark>[0],
647
+ ) => desktop.resolveWorkspaceFolderBookmark(params),
648
+ desktopReleaseWorkspaceFolderBookmarks: async () =>
649
+ desktop.releaseWorkspaceFolderBookmarks(),
643
650
 
644
651
  // ---- Gateway ----
645
652
  gatewayStartDiscovery: async (
@@ -40,6 +40,15 @@ export interface ExistingElizaInstallInfo {
40
40
  source: ExistingElizaInstallSource;
41
41
  }
42
42
 
43
+ export interface StateDirMigrationResult {
44
+ ok: boolean;
45
+ migrated: boolean;
46
+ fromPath: string;
47
+ toPath: string;
48
+ error?: string;
49
+ skippedReason?: "same-path" | "source-missing" | "source-not-directory";
50
+ }
51
+
43
52
  export interface TrayMenuItem {
44
53
  id: string;
45
54
  label?: string;
@@ -242,12 +251,14 @@ export interface DiscoveryResult {
242
251
 
243
252
  // -- Permissions --
244
253
  export type {
254
+ PermissionId,
245
255
  PermissionState,
246
256
  PermissionStatus,
247
- SystemPermissionId,
248
257
  } from "@elizaos/shared";
249
258
 
250
- import type { PermissionState, SystemPermissionId } from "@elizaos/shared";
259
+ import type { PermissionId, PermissionState } from "@elizaos/shared";
260
+
261
+ export type SystemPermissionId = PermissionId;
251
262
 
252
263
  /** Local variant uses an index signature (the canonical contract uses explicit keys). */
253
264
  export interface AllPermissionsState {
@@ -432,8 +443,8 @@ export interface FileDialogResult {
432
443
  * `path` — resolved absolute path (empty string when canceled).
433
444
  * `canceled` — user dismissed the dialog without choosing.
434
445
  * `bookmark` — opaque, OS-specific persistence handle (macOS security-scoped
435
- * bookmark base64; null on platforms that do not require it, or until the
436
- * native bookmark bridge ships). Callers must persist it verbatim.
446
+ * bookmark base64; null on platforms that do not require it). Callers must
447
+ * persist it verbatim.
437
448
  */
438
449
  export interface WorkspaceFolderPickResult {
439
450
  canceled: boolean;
@@ -441,6 +452,13 @@ export interface WorkspaceFolderPickResult {
441
452
  bookmark: string | null;
442
453
  }
443
454
 
455
+ export interface WorkspaceFolderBookmarkResolveResult {
456
+ ok: boolean;
457
+ path: string;
458
+ stale?: boolean;
459
+ error?: string;
460
+ }
461
+
444
462
  // -- Screen / Display --
445
463
  export interface DisplayBounds {
446
464
  x: number;
@@ -533,6 +551,10 @@ export type ElizaDesktopRPCSchema = {
533
551
  params: undefined;
534
552
  response: ExistingElizaInstallInfo;
535
553
  };
554
+ agentMigrateStateDir: {
555
+ params: { fromPath: string };
556
+ response: StateDirMigrationResult;
557
+ };
536
558
  agentPostReset: {
537
559
  params: { apiBase?: string; bearerToken?: string } | undefined | null;
538
560
  response: { ok: boolean; error?: string };
@@ -843,6 +865,14 @@ export type ElizaDesktopRPCSchema = {
843
865
  params: { defaultPath?: string; promptTitle?: string };
844
866
  response: WorkspaceFolderPickResult;
845
867
  };
868
+ desktopResolveWorkspaceFolderBookmark: {
869
+ params: { bookmark: string };
870
+ response: WorkspaceFolderBookmarkResolveResult;
871
+ };
872
+ desktopReleaseWorkspaceFolderBookmarks: {
873
+ params: undefined;
874
+ response: { ok: true };
875
+ };
846
876
 
847
877
  // ---- Gateway ----
848
878
  gatewayStartDiscovery: {
@@ -1507,6 +1537,7 @@ export const CHANNEL_TO_RPC_METHOD: Record<string, string> = {
1507
1537
  "agent:restartClearLocalDb": "agentRestartClearLocalDb",
1508
1538
  "agent:status": "agentStatus",
1509
1539
  "agent:inspectExistingInstall": "agentInspectExistingInstall",
1540
+ "agent:migrateStateDir": "agentMigrateStateDir",
1510
1541
  "agent:postReset": "agentPostReset",
1511
1542
  "agent:postCloudDisconnect": "agentPostCloudDisconnect",
1512
1543
  "agent:cloudDisconnectWithConfirm": "agentCloudDisconnectWithConfirm",
@@ -1614,6 +1645,10 @@ export const CHANNEL_TO_RPC_METHOD: Record<string, string> = {
1614
1645
  "desktop:showOpenDialog": "desktopShowOpenDialog",
1615
1646
  "desktop:showSaveDialog": "desktopShowSaveDialog",
1616
1647
  "desktop:pickWorkspaceFolder": "desktopPickWorkspaceFolder",
1648
+ "desktop:resolveWorkspaceFolderBookmark":
1649
+ "desktopResolveWorkspaceFolderBookmark",
1650
+ "desktop:releaseWorkspaceFolderBookmarks":
1651
+ "desktopReleaseWorkspaceFolderBookmarks",
1617
1652
 
1618
1653
  // Gateway
1619
1654
  "gateway:startDiscovery": "gatewayStartDiscovery",
@@ -6,7 +6,7 @@ import type {
6
6
  SystemPermissionId,
7
7
  } from "./native/permissions-shared";
8
8
 
9
- export const RUNTIME_PERMISSION_IDS = ["website-blocking", "location"] as const;
9
+ export const RUNTIME_PERMISSION_IDS = ["website-blocking"] as const;
10
10
 
11
11
  type RuntimePermissionId = (typeof RUNTIME_PERMISSION_IDS)[number];
12
12
  type RuntimePermissionOperation = "check" | "request" | "open-settings";
@@ -39,6 +39,12 @@ export function buildRuntimePermissionUnavailableState(
39
39
  status: "denied",
40
40
  lastChecked: Date.now(),
41
41
  canRequest: false,
42
+ platform:
43
+ process.platform === "darwin" ||
44
+ process.platform === "win32" ||
45
+ process.platform === "linux"
46
+ ? process.platform
47
+ : "linux",
42
48
  reason,
43
49
  };
44
50
  }
@@ -20,5 +20,6 @@
20
20
  * Parallels `ensure-text-to-speech-handler.ts` — same shape, same guards.
21
21
  */
22
22
  import { type AgentRuntime } from "@elizaos/core";
23
+ export declare function shouldRegisterLocalInferenceHandlers(mode: string): boolean;
23
24
  export declare function ensureLocalInferenceHandler(runtime: AgentRuntime): Promise<void>;
24
25
  //# sourceMappingURL=ensure-local-inference-handler.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ensure-local-inference-handler.d.ts","sourceRoot":"","sources":["../../../../../src/runtime/ensure-local-inference-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,KAAK,YAAY,EAMlB,MAAM,eAAe,CAAC;AAkWvB,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAuJf"}
1
+ {"version":3,"file":"ensure-local-inference-handler.d.ts","sourceRoot":"","sources":["../../../../../src/runtime/ensure-local-inference-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,KAAK,YAAY,EAMlB,MAAM,eAAe,CAAC;AAoEvB,wBAAgB,oCAAoC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1E;AAiSD,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CA+Jf"}