@elizaos/app-core 2.0.0-beta.2 → 2.0.11-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-bridge.d.ts +27 -0
- package/agent-bridge.d.ts.map +1 -0
- package/agent-bridge.js +26 -0
- package/api/__tests__/sandbox-test-helpers.js +1 -1
- package/api/auth/audit.js +1 -1
- package/api/auth/auth-context.js +1 -1
- package/api/auth/bootstrap-token.js +2 -2
- package/api/auth/index.d.ts +9 -10
- package/api/auth/index.d.ts.map +1 -1
- package/api/auth/index.js +9 -10
- package/api/auth/passwords.js +2 -2
- package/api/auth/sensitive-rate-limit.d.ts +1 -4
- package/api/auth/sensitive-rate-limit.d.ts.map +1 -1
- package/api/auth/sensitive-rate-limit.js +6 -6
- package/api/auth/sessions.js +2 -2
- package/api/auth-bootstrap-routes.d.ts +6 -13
- package/api/auth-bootstrap-routes.d.ts.map +1 -1
- package/api/auth-bootstrap-routes.js +14 -27
- package/api/auth-pairing-routes.d.ts +17 -0
- package/api/auth-pairing-routes.d.ts.map +1 -0
- package/api/auth-pairing-routes.js +300 -0
- package/api/auth-session-routes.d.ts.map +1 -1
- package/api/auth-session-routes.js +36 -15
- package/api/auth.d.ts +12 -19
- package/api/auth.d.ts.map +1 -1
- package/api/auth.js +32 -27
- package/api/automations-compat-routes.d.ts.map +1 -1
- package/api/automations-compat-routes.js +5 -5
- package/api/background-tasks-routes.d.ts +4 -0
- package/api/background-tasks-routes.d.ts.map +1 -0
- package/api/background-tasks-routes.js +63 -0
- package/api/catalog-routes.js +3 -3
- package/api/cloud-pair-route.d.ts +26 -0
- package/api/cloud-pair-route.d.ts.map +1 -0
- package/api/cloud-pair-route.js +222 -0
- package/api/cloud-voice-routes.d.ts +52 -0
- package/api/cloud-voice-routes.d.ts.map +1 -0
- package/api/cloud-voice-routes.js +50 -0
- package/api/compat-route-shared.d.ts +2 -2
- package/api/compat-route-shared.d.ts.map +1 -1
- package/api/compat-route-shared.js +11 -7
- package/api/credential-resolver.d.ts +2 -2
- package/api/credential-resolver.d.ts.map +1 -1
- package/api/credential-resolver.js +8 -2
- package/api/database-rows-compat-routes.d.ts.map +1 -1
- package/api/database-rows-compat-routes.js +69 -31
- package/api/dev-boot-history.d.ts +26 -0
- package/api/dev-boot-history.d.ts.map +1 -0
- package/api/dev-boot-history.js +69 -0
- package/api/dev-compat-routes.d.ts +5 -0
- package/api/dev-compat-routes.d.ts.map +1 -1
- package/api/dev-compat-routes.js +127 -4
- package/api/dev-console-log.d.ts +2 -2
- package/api/dev-console-log.d.ts.map +1 -1
- package/api/dev-console-log.js +8 -5
- package/api/dev-route-catalog.d.ts +58 -0
- package/api/dev-route-catalog.d.ts.map +1 -0
- package/api/dev-route-catalog.js +447 -0
- package/api/dev-stack.d.ts.map +1 -1
- package/api/dev-stack.js +6 -9
- package/api/first-run-routes.d.ts +4 -0
- package/api/first-run-routes.d.ts.map +1 -0
- package/api/first-run-routes.js +208 -0
- package/api/first-run-tts-route.d.ts +19 -0
- package/api/first-run-tts-route.d.ts.map +1 -0
- package/api/first-run-tts-route.js +59 -0
- package/api/internal-routes.d.ts +23 -0
- package/api/internal-routes.d.ts.map +1 -0
- package/api/internal-routes.js +203 -0
- package/api/ios-local-agent-transport.d.ts +36 -0
- package/api/ios-local-agent-transport.d.ts.map +1 -0
- package/api/ios-local-agent-transport.js +566 -0
- package/api/onboarding-voice-lines.d.ts +23 -0
- package/api/onboarding-voice-lines.d.ts.map +1 -0
- package/api/onboarding-voice-lines.js +8 -0
- package/api/perf-instrument.d.ts +43 -0
- package/api/perf-instrument.d.ts.map +1 -0
- package/api/perf-instrument.js +113 -0
- package/api/response.d.ts.map +1 -1
- package/api/response.js +14 -14
- package/api/runtime-mode-routes.d.ts.map +1 -1
- package/api/runtime-mode-routes.js +2 -2
- package/api/secrets-inventory-routes.js +2 -2
- package/api/secrets-manager-routes.d.ts +1 -1
- package/api/secrets-manager-routes.d.ts.map +1 -1
- package/api/secrets-manager-routes.js +9 -10
- package/api/sensitive-request-routes.d.ts.map +1 -1
- package/api/sensitive-request-routes.js +5 -5
- package/api/sensitive-request-store.d.ts +12 -3
- package/api/sensitive-request-store.d.ts.map +1 -1
- package/api/server-cors.d.ts.map +1 -1
- package/api/server-cors.js +13 -2
- package/api/server-first-run-helpers.d.ts +26 -0
- package/api/server-first-run-helpers.d.ts.map +1 -0
- package/api/server-first-run-helpers.js +271 -0
- package/api/server-security.js +1 -1
- package/api/server-startup.d.ts.map +1 -1
- package/api/server-startup.js +3 -4
- package/api/server-wallet-trade.js +1 -1
- package/api/server.d.ts +4 -4
- package/api/server.d.ts.map +1 -1
- package/api/server.js +222 -88
- package/api/setup-contract.d.ts +63 -0
- package/api/setup-contract.d.ts.map +1 -0
- package/api/setup-contract.js +39 -0
- package/api/training-benchmarks.d.ts +97 -0
- package/api/training-benchmarks.d.ts.map +1 -0
- package/api/training-benchmarks.js +307 -0
- package/api/workbench-compat-routes.js +2 -2
- package/benchmark/cerebras-autowire.d.ts +28 -0
- package/benchmark/cerebras-autowire.d.ts.map +1 -0
- package/benchmark/cerebras-autowire.js +62 -0
- package/benchmark/lifeops-bench-handler.d.ts +36 -0
- package/benchmark/lifeops-bench-handler.d.ts.map +1 -1
- package/benchmark/lifeops-bench-handler.js +63 -1
- package/benchmark/lifeops-fake-backend.d.ts +39 -0
- package/benchmark/lifeops-fake-backend.d.ts.map +1 -1
- package/benchmark/lifeops-fake-backend.js +993 -21
- package/benchmark/mock-plugin.d.ts.map +1 -1
- package/benchmark/mock-plugin.js +0 -24
- package/benchmark/plugin.d.ts +2 -1
- package/benchmark/plugin.d.ts.map +1 -1
- package/benchmark/plugin.js +989 -68
- package/benchmark/replay-capture.d.ts +2 -2
- package/benchmark/replay-capture.d.ts.map +1 -1
- package/benchmark/replay-capture.js +3 -3
- package/benchmark/server-utils.d.ts +162 -9
- package/benchmark/server-utils.d.ts.map +1 -1
- package/benchmark/server-utils.js +625 -62
- package/benchmark/server.d.ts.map +1 -1
- package/benchmark/server.js +1962 -118
- package/boot-profile.d.ts +3 -0
- package/boot-profile.d.ts.map +1 -0
- package/boot-profile.js +30 -0
- package/browser.d.ts +23 -1
- package/browser.d.ts.map +1 -1
- package/browser.js +20 -1
- package/cli/argv.js +1 -1
- package/cli/banner.js +1 -1
- package/cli/command-format.js +2 -2
- package/cli/doctor/checks.d.ts.map +1 -1
- package/cli/doctor/checks.js +6 -6
- package/cli/plugins-cli.d.ts.map +1 -1
- package/cli/plugins-cli.js +77 -32
- package/cli/profile.d.ts.map +1 -1
- package/cli/profile.js +5 -4
- package/cli/program/build-program.js +4 -4
- package/cli/program/command-registry.d.ts.map +1 -1
- package/cli/program/command-registry.js +13 -11
- package/cli/program/help.js +5 -5
- package/cli/program/preaction.js +5 -5
- package/cli/program/register.auth.d.ts.map +1 -1
- package/cli/program/register.auth.js +6 -12
- package/cli/program/register.capability-router.d.ts +29 -0
- package/cli/program/register.capability-router.d.ts.map +1 -0
- package/cli/program/register.capability-router.js +568 -0
- package/cli/program/register.config.js +1 -1
- package/cli/program/register.configure.d.ts.map +1 -1
- package/cli/program/register.configure.js +1 -1
- package/cli/program/register.dashboard.d.ts.map +1 -1
- package/cli/program/register.dashboard.js +6 -7
- package/cli/program/register.db.d.ts.map +1 -1
- package/cli/program/register.db.js +3 -4
- package/cli/program/register.doctor.js +7 -7
- package/cli/program/register.setup.d.ts.map +1 -1
- package/cli/program/register.setup.js +14 -10
- package/cli/program/register.start.d.ts.map +1 -1
- package/cli/program/register.start.js +5 -3
- package/cli/program/register.subclis.js +3 -3
- package/cli/program/register.update.d.ts +6 -0
- package/cli/program/register.update.d.ts.map +1 -1
- package/cli/program/register.update.js +58 -6
- package/cli/program.js +1 -1
- package/cli/run-main.js +4 -4
- package/config/app-config.d.ts +2 -0
- package/config/app-config.d.ts.map +1 -0
- package/config/app-config.js +1 -0
- package/connectors/capacitor-jsc.d.ts.map +1 -1
- package/connectors/capacitor-jsc.js +16 -10
- package/connectors/capacitor-quickjs.d.ts.map +1 -1
- package/connectors/capacitor-quickjs.js +18 -13
- package/connectors/capacitor-sqlite.d.ts.map +1 -1
- package/connectors/capacitor-sqlite.js +27 -12
- package/dispatch/approval-queue.d.ts +37 -0
- package/dispatch/approval-queue.d.ts.map +1 -0
- package/dispatch/approval-queue.js +25 -0
- package/dispatch/channel-registry.d.ts +30 -0
- package/dispatch/channel-registry.d.ts.map +1 -0
- package/dispatch/channel-registry.js +22 -0
- package/dispatch/connector-registry.d.ts +39 -0
- package/dispatch/connector-registry.d.ts.map +1 -0
- package/dispatch/connector-registry.js +24 -0
- package/dispatch/index.d.ts +14 -0
- package/dispatch/index.d.ts.map +1 -0
- package/dispatch/index.js +13 -0
- package/dispatch/send-policy.d.ts +36 -0
- package/dispatch/send-policy.d.ts.map +1 -0
- package/dispatch/send-policy.js +16 -0
- package/entry.js +28 -11
- package/first-run/first-run-config.d.ts +55 -0
- package/first-run/first-run-config.d.ts.map +1 -0
- package/first-run/first-run-config.js +178 -0
- package/first-run/runtime-target.d.ts +4 -0
- package/first-run/runtime-target.d.ts.map +1 -0
- package/first-run/runtime-target.js +13 -0
- package/index.d.ts +16 -3
- package/index.d.ts.map +1 -1
- package/index.js +57 -33
- package/package.json +159 -50
- package/packaging/debian/apt-repo-config/README.md +18 -0
- package/packaging/debian/apt-repo-config/conf/distributions +11 -0
- package/packaging/flatpak/README.md +26 -16
- package/packaging/flatpak/ai.elizaos.App.metainfo.xml +17 -12
- package/packaging/flatpak/ai.elizaos.App.store.yml +5 -5
- package/packaging/flatpak/ai.elizaos.App.yml +10 -24
- package/packaging/flatpak/elizaos-app-wrapper.store.sh +2 -2
- package/packaging/flatpak/generate-sources.sh +74 -0
- package/packaging/flatpak/node-sources.json +7930 -0
- package/packaging/inno/build-inno.ps1 +34 -9
- package/packaging/msix/AppxManifest.store.xml +1 -1
- package/packaging/msix/README.md +39 -19
- package/packaging/msix/build-msix.ps1 +44 -14
- package/packaging/snap/snapcraft.yaml +22 -21
- package/packaging/test-packaging.sh +2 -2
- package/permissions/types.d.ts +1 -1
- package/permissions/types.js +1 -1
- package/platform/elizaos-agent-browser-stub.d.ts +144 -0
- package/platform/elizaos-agent-browser-stub.d.ts.map +1 -0
- package/platform/elizaos-agent-browser-stub.js +158 -0
- package/platform/elizaos-plugin-elizacloud-browser-stub.d.ts +34 -0
- package/platform/elizaos-plugin-elizacloud-browser-stub.d.ts.map +1 -0
- package/platform/elizaos-plugin-elizacloud-browser-stub.js +51 -0
- package/platform/empty-node-module.d.ts +148 -0
- package/platform/empty-node-module.d.ts.map +1 -1
- package/platform/empty-node-module.js +140 -3
- package/platform/ios-runtime-backends.d.ts +83 -0
- package/platform/ios-runtime-backends.d.ts.map +1 -0
- package/platform/ios-runtime-backends.js +133 -0
- package/platform/ios-runtime-bridge.d.ts +15 -0
- package/platform/ios-runtime-bridge.d.ts.map +1 -0
- package/platform/ios-runtime-bridge.js +527 -0
- package/platform/native-library-policy.d.ts +23 -0
- package/platform/native-library-policy.d.ts.map +1 -0
- package/platform/native-library-policy.js +112 -0
- package/platform/native-plugin-entrypoints.d.ts +19 -0
- package/platform/native-plugin-entrypoints.d.ts.map +1 -0
- package/platform/native-plugin-entrypoints.js +29 -0
- package/platforms/android/README.md +68 -10
- package/platforms/android/app/build.gradle +268 -3
- package/platforms/android/app/capacitor.build.gradle +18 -1
- package/platforms/android/app/proguard-rules.pro +17 -2
- package/platforms/android/app/src/androidTest/java/ai/elizaos/app/ElizaOsInstrumentedTest.java +1 -1
- package/platforms/android/app/src/main/AndroidManifest.xml +334 -17
- package/platforms/android/app/src/main/assets/runners/eliza-tasks.js +177 -0
- package/platforms/android/app/src/main/elizavoice-jni/CMakeLists.txt +75 -0
- package/platforms/android/app/src/main/elizavoice-jni/elizavoice-jni.cpp +1045 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/AgentPlugin.java +111 -171
- package/platforms/android/app/src/main/java/ai/elizaos/app/AndroidVirtualizationBridge.java +284 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/BatteryOptimizationPlugin.java +95 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAccessibilityService.java +55 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAgentService.java +1198 -141
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAndroidSystemBridge.java +83 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAssistActivity.java +50 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaBootReceiver.java +90 -8
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaBrowserActivity.java +2 -2
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaCalendarActivity.java +1 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaCameraActivity.java +1 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaClockActivity.java +2 -2
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaContactsActivity.java +1 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaDialActivity.java +1 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaInCallService.java +1 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaMmsReceiver.java +1 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaNativeBridge.java +22 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaNotificationListenerService.java +45 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaQuickActionsWidgetProvider.java +68 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaShareActivity.java +132 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaSmsComposeActivity.java +1 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaSmsGatewayService.java +268 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaSmsReceiver.java +12 -1
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaTasksWorker.java +194 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoiceCaptureService.java +198 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoiceNative.java +160 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoicePlugin.java +450 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoiceTileService.java +39 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaWorkScheduler.java +60 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/GatewayConnectionService.java +53 -19
- package/platforms/android/app/src/main/java/ai/elizaos/app/MainActivity.java +160 -33
- package/platforms/android/app/src/main/java/ai/elizaos/app/ResourceProbePlugin.java +169 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/VoiceCapturePlugin.java +119 -0
- package/platforms/android/app/src/main/res/drawable/eliza_widget_background.xml +10 -0
- package/platforms/android/app/src/main/res/drawable/eliza_widget_button_background.xml +13 -0
- package/platforms/android/app/src/main/res/drawable/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-land-hdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-land-mdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-land-xhdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-land-xxhdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-land-xxxhdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-port-hdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-port-mdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-port-xhdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-port-xxhdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/drawable-port-xxxhdpi/splash.png +0 -0
- package/platforms/android/app/src/main/res/layout/eliza_quick_actions_widget.xml +86 -0
- package/platforms/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +2 -1
- package/platforms/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +2 -1
- package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png +0 -0
- package/platforms/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/platforms/android/app/src/main/res/values/android_app_actions.xml +48 -0
- package/platforms/android/app/src/main/res/values/colors.xml +8 -0
- package/platforms/android/app/src/main/res/values/ic_launcher_background.xml +2 -2
- package/platforms/android/app/src/main/res/values/strings.xml +2 -2
- package/platforms/android/app/src/main/res/values/styles.xml +25 -1
- package/platforms/android/app/src/main/res/xml/eliza_accessibility_service.xml +9 -0
- package/platforms/android/app/src/main/res/xml/eliza_quick_actions_widget.xml +13 -0
- package/platforms/android/app/src/main/res/xml/shortcuts.xml +121 -0
- package/platforms/android/build.gradle +2 -2
- package/platforms/android/capacitor-cordova-android-plugins/build.gradle +9 -3
- package/platforms/android/capacitor-cordova-android-plugins/cordova.variables.gradle +6 -2
- package/platforms/android/capacitor-cordova-android-plugins/src/main/AndroidManifest.xml +7 -2
- package/platforms/android/capacitor-cordova-android-plugins/src/main/java/.gitkeep +0 -1
- package/platforms/android/capacitor.settings.gradle +66 -16
- package/platforms/android/gradle.properties +1 -0
- package/platforms/android/update-manifest/generate-manifest.mjs +97 -0
- package/platforms/android/update-manifest/schema.json +26 -0
- package/platforms/apple-store-entitlements.reviewed.json +155 -0
- package/platforms/electrobun/.generated/brand-config.json +3 -2
- package/platforms/electrobun/LICENSE +21 -0
- package/platforms/electrobun/README.md +15 -1
- package/platforms/electrobun/assets/appIcon.icns +0 -0
- package/platforms/electrobun/assets/appIcon.ico +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_128x128.png +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_128x128@2x.png +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_16x16.png +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_16x16@2x.png +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_256x256.png +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_256x256@2x.png +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_32x32.png +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_32x32@2x.png +0 -0
- package/platforms/electrobun/assets/appIcon.iconset/icon_512x512.png +0 -0
- package/platforms/electrobun/assets/brand-config.json +6 -6
- package/platforms/electrobun/biome.json +9 -9
- package/platforms/electrobun/docs/capability-collapse-matrix.json +318 -0
- package/platforms/electrobun/docs/capability-collapse-matrix.md +129 -0
- package/platforms/electrobun/docs/capability-routing.md +86 -0
- package/platforms/electrobun/docs/convergence-audit.json +3505 -0
- package/platforms/electrobun/docs/convergence-audit.md +694 -0
- package/platforms/electrobun/docs/database-boot-policy.md +90 -0
- package/platforms/electrobun/docs/riscv64-port.md +175 -0
- package/platforms/electrobun/docs/startup-first-run-cleanup.md +18 -0
- package/platforms/electrobun/docs/trace-first-annotations.md +52 -0
- package/platforms/electrobun/docs/ui-boundary-audit.json +580 -0
- package/platforms/electrobun/docs/ui-boundary-audit.md +257 -0
- package/platforms/electrobun/electrobun.config.ts +592 -364
- package/platforms/electrobun/entitlements/JUSTIFICATIONS.md +141 -0
- package/platforms/electrobun/entitlements/README.md +34 -6
- package/platforms/electrobun/entitlements/mas-bun.entitlements +15 -0
- package/platforms/electrobun/entitlements/mas.entitlements +6 -4
- package/platforms/electrobun/native/macos/window-effects.mm +1522 -0
- package/platforms/electrobun/package.json +18 -12
- package/platforms/electrobun/remotes/fs/README.md +70 -0
- package/platforms/electrobun/remotes/fs/electrobun.config.ts +38 -0
- package/platforms/electrobun/remotes/fs/package.json +12 -0
- package/platforms/electrobun/remotes/fs/plugin.json +25 -0
- package/platforms/electrobun/remotes/fs/src/bun/errors.ts +57 -0
- package/platforms/electrobun/remotes/fs/src/bun/file-limits.ts +50 -0
- package/platforms/electrobun/remotes/fs/src/bun/fs-service.ts +389 -0
- package/platforms/electrobun/remotes/fs/src/bun/path-guard.ts +270 -0
- package/platforms/electrobun/remotes/fs/src/bun/protocol.ts +149 -0
- package/platforms/electrobun/remotes/fs/src/bun/worker.ts +174 -0
- package/platforms/electrobun/remotes/fs/src/dev/phase5-smoke.ts +171 -0
- package/platforms/electrobun/remotes/fs/src/web/index.html +8 -0
- package/platforms/electrobun/remotes/git/README.md +75 -0
- package/platforms/electrobun/remotes/git/electrobun.config.ts +44 -0
- package/platforms/electrobun/remotes/git/package.json +12 -0
- package/platforms/electrobun/remotes/git/plugin.json +31 -0
- package/platforms/electrobun/remotes/git/src/bun/errors.ts +69 -0
- package/platforms/electrobun/remotes/git/src/bun/git-command.ts +156 -0
- package/platforms/electrobun/remotes/git/src/bun/git-service.ts +446 -0
- package/platforms/electrobun/remotes/git/src/bun/operation-history.ts +124 -0
- package/platforms/electrobun/remotes/git/src/bun/protocol.ts +252 -0
- package/platforms/electrobun/remotes/git/src/bun/worker.ts +316 -0
- package/platforms/electrobun/remotes/git/src/dev/phase7-smoke.ts +141 -0
- package/platforms/electrobun/remotes/git/src/web/index.html +8 -0
- package/platforms/electrobun/remotes/local-model/README.md +138 -0
- package/platforms/electrobun/remotes/local-model/electrobun.config.ts +46 -0
- package/platforms/electrobun/remotes/local-model/package.json +12 -0
- package/platforms/electrobun/remotes/local-model/plugin.json +33 -0
- package/platforms/electrobun/remotes/local-model/src/bun/download-state.ts +115 -0
- package/platforms/electrobun/remotes/local-model/src/bun/eliza1-catalog.ts +425 -0
- package/platforms/electrobun/remotes/local-model/src/bun/errors.ts +74 -0
- package/platforms/electrobun/remotes/local-model/src/bun/hf-eliza1-client.ts +169 -0
- package/platforms/electrobun/remotes/local-model/src/bun/local-inference-api-client.ts +245 -0
- package/platforms/electrobun/remotes/local-model/src/bun/model-service.ts +490 -0
- package/platforms/electrobun/remotes/local-model/src/bun/protocol.ts +301 -0
- package/platforms/electrobun/remotes/local-model/src/bun/worker.ts +248 -0
- package/platforms/electrobun/remotes/local-model/src/dev/phase8-smoke.ts +117 -0
- package/platforms/electrobun/remotes/local-model/src/web/index.html +13 -0
- package/platforms/electrobun/remotes/pty/README.md +65 -0
- package/platforms/electrobun/remotes/pty/electrobun.config.ts +47 -0
- package/platforms/electrobun/remotes/pty/package.json +12 -0
- package/platforms/electrobun/remotes/pty/plugin.json +34 -0
- package/platforms/electrobun/remotes/pty/src/bun/errors.ts +57 -0
- package/platforms/electrobun/remotes/pty/src/bun/output-buffer.ts +127 -0
- package/platforms/electrobun/remotes/pty/src/bun/protocol.ts +192 -0
- package/platforms/electrobun/remotes/pty/src/bun/pty-service.ts +562 -0
- package/platforms/electrobun/remotes/pty/src/bun/worker.ts +218 -0
- package/platforms/electrobun/remotes/pty/src/dev/phase6-smoke.ts +127 -0
- package/platforms/electrobun/remotes/pty/src/web/index.html +8 -0
- package/platforms/electrobun/remotes/runtime/README.md +370 -0
- package/platforms/electrobun/remotes/runtime/electrobun.config.ts +48 -0
- package/platforms/electrobun/remotes/runtime/package.json +14 -0
- package/platforms/electrobun/remotes/runtime/plugin.json +30 -0
- package/platforms/electrobun/remotes/runtime/src/bun/api-client.ts +620 -0
- package/platforms/electrobun/remotes/runtime/src/bun/errors.ts +45 -0
- package/platforms/electrobun/remotes/runtime/src/bun/log-buffer.ts +33 -0
- package/platforms/electrobun/remotes/runtime/src/bun/protocol.ts +366 -0
- package/platforms/electrobun/remotes/runtime/src/bun/route-discovery.ts +419 -0
- package/platforms/electrobun/remotes/runtime/src/bun/runtime-manager.ts +423 -0
- package/platforms/electrobun/remotes/runtime/src/bun/sse-parser.ts +99 -0
- package/platforms/electrobun/remotes/runtime/src/bun/stream-manager.ts +887 -0
- package/platforms/electrobun/remotes/runtime/src/bun/worker.ts +1231 -0
- package/platforms/electrobun/remotes/runtime/src/dev/phase1-smoke.ts +34 -0
- package/platforms/electrobun/remotes/runtime/src/dev/phase2-smoke.ts +86 -0
- package/platforms/electrobun/remotes/runtime/src/dev/phase3-smoke.ts +141 -0
- package/platforms/electrobun/remotes/runtime/src/web/index.css +187 -0
- package/platforms/electrobun/remotes/runtime/src/web/index.html +76 -0
- package/platforms/electrobun/remotes/runtime/src/web/index.ts +192 -0
- package/platforms/electrobun/remotes/surface/README.md +201 -0
- package/platforms/electrobun/remotes/surface/electrobun.config.ts +38 -0
- package/platforms/electrobun/remotes/surface/package.json +12 -0
- package/platforms/electrobun/remotes/surface/plugin.json +28 -0
- package/platforms/electrobun/remotes/surface/src/bun/worker.ts +132 -0
- package/platforms/electrobun/remotes/surface/src/dev/phase4-smoke.ts +566 -0
- package/platforms/electrobun/remotes/surface/src/protocol/event-types.ts +84 -0
- package/platforms/electrobun/remotes/surface/src/protocol/runtime-client.ts +673 -0
- package/platforms/electrobun/remotes/surface/src/web/app.ts +595 -0
- package/platforms/electrobun/remotes/surface/src/web/index.css +460 -0
- package/platforms/electrobun/remotes/surface/src/web/index.html +466 -0
- package/platforms/electrobun/remotes/surface/src/web/index.ts +5 -0
- package/platforms/electrobun/remotes/surface/src/web/render.ts +455 -0
- package/platforms/electrobun/remotes/surface/src/web/state.ts +427 -0
- package/platforms/electrobun/scripts/build-macos-effects.sh +4 -0
- package/platforms/electrobun/scripts/ensure-build-folder.ts +28 -0
- package/platforms/electrobun/scripts/ensure-whisper-gguf.sh +55 -0
- package/platforms/electrobun/scripts/ensure-whisper-model.sh +22 -80
- package/platforms/electrobun/scripts/generate-convergence-audit.ts +1203 -0
- package/platforms/electrobun/scripts/local-adhoc-sign-macos.ts +159 -159
- package/platforms/electrobun/scripts/postwrap-diagnostics.ts +424 -339
- package/platforms/electrobun/scripts/postwrap-sign-runtime-macos.ts +302 -271
- package/platforms/electrobun/scripts/smoke-test-windows.ps1 +17 -16
- package/platforms/electrobun/scripts/smoke-test.sh +5 -7
- package/platforms/electrobun/scripts/sync-web-assets.mjs +13 -13
- package/platforms/electrobun/scripts/verify-rpc-handlers.ts +109 -110
- package/platforms/electrobun/scripts/verify-windows-installer-proof.ps1 +3 -8
- package/platforms/electrobun/src/__stubs__/bun-ffi.ts +31 -31
- package/platforms/electrobun/src/__stubs__/electrobun-bun.ts +1 -1
- package/platforms/electrobun/src/agent-ready-state.ts +8 -8
- package/platforms/electrobun/src/agent-reset-from-main.test.ts +162 -0
- package/platforms/electrobun/src/agent-reset-from-main.ts +62 -62
- package/platforms/electrobun/src/agent-status-rpc.test.ts +95 -0
- package/platforms/electrobun/src/agent-status-rpc.ts +156 -0
- package/platforms/electrobun/src/api-base.test.ts +247 -0
- package/platforms/electrobun/src/api-base.ts +202 -93
- package/platforms/electrobun/src/application-menu-action-registry.ts +9 -9
- package/platforms/electrobun/src/application-menu.ts +348 -348
- package/platforms/electrobun/src/background-notice.ts +36 -36
- package/platforms/electrobun/src/boot-progress.test.ts +188 -0
- package/platforms/electrobun/src/boot-progress.ts +111 -0
- package/platforms/electrobun/src/brand-config.test.ts +39 -0
- package/platforms/electrobun/src/brand-config.ts +141 -129
- package/platforms/electrobun/src/bridge/browser-tabs-renderer-registry.ts +28 -28
- package/platforms/electrobun/src/bridge/electrobun-boot-config.ts +42 -0
- package/platforms/electrobun/src/bridge/electrobun-crypto-ready.ts +120 -0
- package/platforms/electrobun/src/bridge/electrobun-direct-rpc.ts +342 -357
- package/platforms/electrobun/src/bridge/electrobun-stub.ts +13 -13
- package/platforms/electrobun/src/browser-workspace-bridge-server.ts +285 -243
- package/platforms/electrobun/src/cloud-auth-window.ts +136 -136
- package/platforms/electrobun/src/cloud-disconnect-from-main.ts +90 -90
- package/platforms/electrobun/src/config-and-auth-rpc.test.ts +256 -0
- package/platforms/electrobun/src/config-and-auth-rpc.ts +302 -0
- package/platforms/electrobun/src/conversations-and-character-rpc.test.ts +185 -0
- package/platforms/electrobun/src/conversations-and-character-rpc.ts +131 -0
- package/platforms/electrobun/src/dashboard-rpc.test.ts +200 -0
- package/platforms/electrobun/src/dashboard-rpc.ts +344 -0
- package/platforms/electrobun/src/database/database-lock.ts +141 -0
- package/platforms/electrobun/src/database/database-mode.ts +149 -0
- package/platforms/electrobun/src/database/database-recovery.ts +72 -0
- package/platforms/electrobun/src/database/database-snapshot.ts +190 -0
- package/platforms/electrobun/src/database/database.test.ts +196 -0
- package/platforms/electrobun/src/database/index.ts +5 -0
- package/platforms/electrobun/src/database/pglite-paths.ts +100 -0
- package/platforms/electrobun/src/desktop-deep-link-events.test.ts +30 -0
- package/platforms/electrobun/src/desktop-deep-link-events.ts +17 -0
- package/platforms/electrobun/src/desktop-http-request.test.ts +73 -73
- package/platforms/electrobun/src/desktop-http-request.ts +85 -85
- package/platforms/electrobun/src/desktop-pill-config.test.ts +27 -0
- package/platforms/electrobun/src/desktop-pill-config.ts +40 -0
- package/platforms/electrobun/src/desktop-test-bridge-server.ts +204 -204
- package/platforms/electrobun/src/desktop-tray-config.test.ts +87 -0
- package/platforms/electrobun/src/desktop-tray-config.ts +84 -0
- package/platforms/electrobun/src/devtools-layout.ts +41 -41
- package/platforms/electrobun/src/diagnostic-format.test.ts +71 -0
- package/platforms/electrobun/src/diagnostic-format.ts +75 -36
- package/platforms/electrobun/src/dynamic-view-rpc-schema.test.ts +37 -0
- package/platforms/electrobun/src/dynamic-views/README.md +44 -0
- package/platforms/electrobun/src/dynamic-views/demo/agent-run-trace.html +135 -0
- package/platforms/electrobun/src/dynamic-views/errors.ts +29 -0
- package/platforms/electrobun/src/dynamic-views/host.test.ts +353 -0
- package/platforms/electrobun/src/dynamic-views/host.ts +332 -0
- package/platforms/electrobun/src/dynamic-views/index.ts +57 -0
- package/platforms/electrobun/src/dynamic-views/kiosk-canvas.ts +89 -0
- package/platforms/electrobun/src/dynamic-views/registry.test.ts +139 -0
- package/platforms/electrobun/src/dynamic-views/registry.ts +196 -0
- package/platforms/electrobun/src/dynamic-views/session-manager.test.ts +355 -0
- package/platforms/electrobun/src/dynamic-views/session-manager.ts +348 -0
- package/platforms/electrobun/src/dynamic-views/types.ts +105 -0
- package/platforms/electrobun/src/electrobun-boot-config.test.ts +50 -0
- package/platforms/electrobun/src/electrobun-config.test.ts +62 -0
- package/platforms/electrobun/src/electrobun-crypto-ready.test.ts +65 -0
- package/platforms/electrobun/src/electrobun-window-options.ts +25 -0
- package/platforms/electrobun/src/extension-rpc.test.ts +88 -0
- package/platforms/electrobun/src/extension-rpc.ts +102 -0
- package/platforms/electrobun/src/fatal-shutdown.test.ts +10 -10
- package/platforms/electrobun/src/fatal-shutdown.ts +1 -1
- package/platforms/electrobun/src/first-party-remotes.test.ts +169 -0
- package/platforms/electrobun/src/first-party-remotes.ts +297 -0
- package/platforms/electrobun/src/first-run-rpc.test.ts +192 -0
- package/platforms/electrobun/src/first-run-rpc.ts +146 -0
- package/platforms/electrobun/src/floating-chat-window.ts +181 -181
- package/platforms/electrobun/src/inbox-rpc.test.ts +123 -0
- package/platforms/electrobun/src/inbox-rpc.ts +158 -0
- package/platforms/electrobun/src/index.ts +2555 -2096
- package/platforms/electrobun/src/kiosk-mode.ts +50 -0
- package/platforms/electrobun/src/launch/index.ts +4 -0
- package/platforms/electrobun/src/launch/launch-dynamic-view.ts +37 -0
- package/platforms/electrobun/src/launch/launch-orchestrator.test.ts +224 -0
- package/platforms/electrobun/src/launch/launch-orchestrator.ts +456 -0
- package/platforms/electrobun/src/launch/launch-store.test.ts +97 -0
- package/platforms/electrobun/src/launch/launch-store.ts +134 -0
- package/platforms/electrobun/src/launch/types.ts +103 -0
- package/platforms/electrobun/src/launch/views/launch-diagnostics.html +205 -0
- package/platforms/electrobun/src/lifecycle/agent-ready-publish.test.ts +50 -0
- package/platforms/electrobun/src/lifecycle/agent-ready-publish.ts +27 -0
- package/platforms/electrobun/src/lifecycle/api-base-owner.ts +42 -31
- package/platforms/electrobun/src/lifecycle/desktop-session-prime.ts +44 -44
- package/platforms/electrobun/src/logger.ts +14 -14
- package/platforms/electrobun/src/main-window-runtime.ts +83 -83
- package/platforms/electrobun/src/main-window-session.test.ts +109 -0
- package/platforms/electrobun/src/main-window-session.ts +87 -51
- package/platforms/electrobun/src/menu-reset-from-main.ts +158 -158
- package/platforms/electrobun/src/native/agent-env.test.ts +52 -0
- package/platforms/electrobun/src/native/agent-runtime-layout.test.ts +42 -0
- package/platforms/electrobun/src/native/agent-state-dir.test.ts +91 -0
- package/platforms/electrobun/src/native/agent.ts +2122 -1682
- package/platforms/electrobun/src/native/auth-bridge.test.ts +67 -0
- package/platforms/electrobun/src/native/auth-bridge.ts +464 -360
- package/platforms/electrobun/src/native/browser-workspace.ts +723 -471
- package/platforms/electrobun/src/native/camera.ts +50 -50
- package/platforms/electrobun/src/native/canvas.ts +444 -445
- package/platforms/electrobun/src/native/credentials.ts +673 -616
- package/platforms/electrobun/src/native/desktop-window.test.ts +300 -0
- package/platforms/electrobun/src/native/desktop.ts +2196 -2156
- package/platforms/electrobun/src/native/editor-bridge.ts +201 -201
- package/platforms/electrobun/src/native/file-watcher.ts +154 -154
- package/platforms/electrobun/src/native/gateway.ts +179 -180
- package/platforms/electrobun/src/native/gpu-window.ts +256 -256
- package/platforms/electrobun/src/native/index.ts +76 -74
- package/platforms/electrobun/src/native/location.test.ts +44 -0
- package/platforms/electrobun/src/native/location.ts +90 -80
- package/platforms/electrobun/src/native/loopback-port.ts +60 -60
- package/platforms/electrobun/src/native/mac-window-effects.ts +166 -104
- package/platforms/electrobun/src/native/music-player.ts +38 -38
- package/platforms/electrobun/src/native/permissions-shared.ts +249 -150
- package/platforms/electrobun/src/native/permissions.ts +301 -208
- package/platforms/electrobun/src/native/power-state.ts +129 -129
- package/platforms/electrobun/src/native/remote-plugin-host.test.ts +1394 -0
- package/platforms/electrobun/src/native/remote-plugin-host.ts +1531 -0
- package/platforms/electrobun/src/native/screencapture.ts +667 -573
- package/platforms/electrobun/src/native/steward.ts +207 -204
- package/platforms/electrobun/src/native/swabble.ts +68 -324
- package/platforms/electrobun/src/native/talkmode.ts +253 -422
- package/platforms/electrobun/src/native/webgpu-browser-support.test.ts +18 -0
- package/platforms/electrobun/src/native/webgpu-browser-support.ts +165 -147
- package/platforms/electrobun/src/native/whisper-env.test.ts +71 -0
- package/platforms/electrobun/src/native/whisper-env.ts +68 -0
- package/platforms/electrobun/src/native-onboarding.ts +270 -0
- package/platforms/electrobun/src/onboarding-overlay-window.ts +141 -0
- package/platforms/electrobun/src/persisted-deployment.ts +91 -0
- package/platforms/electrobun/src/pill-window.test.ts +91 -0
- package/platforms/electrobun/src/pill-window.ts +99 -0
- package/platforms/electrobun/src/preload-validation.ts +44 -44
- package/platforms/electrobun/src/preload.js +1 -1
- package/platforms/electrobun/src/print-electrobun-dev-settings-banner.ts +120 -120
- package/platforms/electrobun/src/renderer-api-proxy.test.ts +73 -0
- package/platforms/electrobun/src/renderer-api-proxy.ts +86 -0
- package/platforms/electrobun/src/renderer-static.test.ts +53 -0
- package/platforms/electrobun/src/renderer-static.ts +144 -57
- package/platforms/electrobun/src/rpc-handler-slices.ts +121 -0
- package/platforms/electrobun/src/rpc-handlers.test.ts +267 -0
- package/platforms/electrobun/src/rpc-handlers.ts +1306 -913
- package/platforms/electrobun/src/rpc-parse-utils.ts +57 -0
- package/platforms/electrobun/src/rpc-port-resolver.test.ts +45 -0
- package/platforms/electrobun/src/rpc-port-resolver.ts +31 -0
- package/platforms/electrobun/src/rpc-schema.ts +2556 -1619
- package/platforms/electrobun/src/runtime-layout.ts +105 -105
- package/platforms/electrobun/src/runtime-permissions.ts +95 -95
- package/platforms/electrobun/src/runtime-rpc.test.ts +126 -0
- package/platforms/electrobun/src/runtime-rpc.ts +237 -0
- package/platforms/electrobun/src/screenshot-dev-server.ts +87 -87
- package/platforms/electrobun/src/settings-mutations-rpc.test.ts +193 -0
- package/platforms/electrobun/src/settings-mutations-rpc.ts +220 -0
- package/platforms/electrobun/src/startup-trace.ts +274 -270
- package/platforms/electrobun/src/subscription-rpc.test.ts +89 -0
- package/platforms/electrobun/src/subscription-rpc.ts +192 -0
- package/platforms/electrobun/src/surface-windows.test.ts +355 -0
- package/platforms/electrobun/src/surface-windows.ts +410 -410
- package/platforms/electrobun/src/trace/README.md +73 -0
- package/platforms/electrobun/src/trace/errors.ts +21 -0
- package/platforms/electrobun/src/trace/index.ts +40 -0
- package/platforms/electrobun/src/trace/trace-dynamic-view.ts +40 -0
- package/platforms/electrobun/src/trace/trace-host-requests.ts +473 -0
- package/platforms/electrobun/src/trace/trace-service.test.ts +186 -0
- package/platforms/electrobun/src/trace/trace-service.ts +324 -0
- package/platforms/electrobun/src/trace/trace-store.test.ts +141 -0
- package/platforms/electrobun/src/trace/trace-store.ts +551 -0
- package/platforms/electrobun/src/trace/types.ts +250 -0
- package/platforms/electrobun/src/trace/views/agent-run-trace.html +311 -0
- package/platforms/electrobun/src/types/web-speech.d.ts +28 -28
- package/platforms/electrobun/src/types.ts +5 -5
- package/platforms/electrobun/src/update-availability.test.ts +72 -0
- package/platforms/electrobun/src/update-availability.ts +90 -0
- package/platforms/electrobun/src/update-rpc.test.ts +83 -0
- package/platforms/electrobun/src/update-rpc.ts +123 -0
- package/platforms/electrobun/src/voice/README.md +184 -0
- package/platforms/electrobun/src/voice/errors.ts +42 -0
- package/platforms/electrobun/src/voice/index.ts +78 -0
- package/platforms/electrobun/src/voice/types.ts +316 -0
- package/platforms/electrobun/src/voice/voice-host-requests.ts +259 -0
- package/platforms/electrobun/src/voice/voice-latency-budget.test.ts +66 -0
- package/platforms/electrobun/src/voice/voice-latency-budget.ts +243 -0
- package/platforms/electrobun/src/voice/voice-live-validation.test.ts +352 -0
- package/platforms/electrobun/src/voice/voice-live-validation.ts +838 -0
- package/platforms/electrobun/src/voice/voice-pipeline.ts +250 -0
- package/platforms/electrobun/src/voice/voice-playback-adapter.ts +31 -0
- package/platforms/electrobun/src/voice/voice-runtime-adapter.test.ts +213 -0
- package/platforms/electrobun/src/voice/voice-runtime-adapter.ts +686 -0
- package/platforms/electrobun/src/voice/voice-service.test.ts +561 -0
- package/platforms/electrobun/src/voice/voice-service.ts +1027 -0
- package/platforms/electrobun/src/voice/voice-stream-coordinator.test.ts +115 -0
- package/platforms/electrobun/src/voice/voice-stream-coordinator.ts +270 -0
- package/platforms/electrobun/src/voice/voice-trace.ts +97 -0
- package/platforms/electrobun/src/voice/voice-tts-chunker.test.ts +91 -0
- package/platforms/electrobun/src/voice/voice-tts-chunker.ts +194 -0
- package/platforms/electrobun/src/windows-cef-profile.ts +88 -88
- package/platforms/electrobun/tsconfig.json +73 -13
- package/platforms/electrobun/update-channels.json +22 -0
- package/platforms/electrobun/vitest.electrobun.config.ts +72 -42
- package/platforms/ios/App/App/App.entitlements +4 -0
- package/platforms/ios/App/App/AppDelegate.swift +80 -18
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ios-marketing-1024.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20@1x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-20x20@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29@1x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-29x29@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40@1x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-40x40@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76@1x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-76x76@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-ipad-83_5x83_5@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-20x20@3x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-29x29@3x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-40x40@3x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@2x.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iphone-60x60@3x.png +0 -0
- package/platforms/ios/App/App/Base.lproj/LaunchScreen.storyboard +1 -4
- package/platforms/ios/App/App/ComputerUseBridge.swift +589 -0
- package/platforms/ios/App/App/DeviceActivityMonitorExtension/DeviceActivityMonitorExtension.entitlements +12 -0
- package/platforms/ios/App/App/DeviceActivityMonitorExtension/DeviceActivityMonitorExtension.swift +34 -0
- package/platforms/ios/App/App/DeviceActivityMonitorExtension/Info.plist +29 -0
- package/platforms/ios/App/App/DeviceActivityReportExtension/DeviceActivityReportExtension.entitlements +12 -0
- package/platforms/ios/App/App/DeviceActivityReportExtension/DeviceActivityReportExtension.swift +53 -0
- package/platforms/ios/App/App/DeviceActivityReportExtension/Info.plist +27 -0
- package/platforms/ios/App/App/ElizaAppIntents.swift +183 -0
- package/platforms/ios/App/App/ElizaIntentPlugin.swift +342 -5
- package/platforms/ios/App/App/Info.plist +17 -1
- package/platforms/ios/App/App/runners/eliza-tasks.js +177 -0
- package/platforms/ios/App/App.xcodeproj/project.pbxproj +262 -6
- package/platforms/ios/App/BroadcastExtension/SampleHandler.swift +100 -0
- package/platforms/ios/App/Podfile +5 -0
- package/platforms/ios/App/Podfile.lock +83 -59
- package/register-runtime-hooks.js +11 -5
- package/registry/app-registry.d.ts +14 -0
- package/registry/app-registry.d.ts.map +1 -0
- package/registry/app-registry.js +29 -0
- package/registry/entries/apps/app-polymarket.json +31 -0
- package/registry/entries/apps/clawville.json +27 -0
- package/registry/entries/apps/companion.json +28 -0
- package/registry/entries/apps/database-viewer.json +27 -0
- package/registry/entries/apps/defense-of-the-agents.json +27 -0
- package/registry/entries/apps/documents.json +30 -0
- package/registry/entries/apps/feed.json +27 -0
- package/registry/entries/apps/hyperliquid.json +31 -0
- package/registry/entries/apps/log-viewer.json +27 -0
- package/registry/entries/apps/memory-viewer.json +27 -0
- package/registry/entries/apps/model-tester.json +31 -0
- package/registry/entries/apps/plugin-viewer.json +27 -0
- package/registry/entries/apps/relationship-viewer.json +27 -0
- package/registry/entries/apps/runtime-debugger.json +27 -0
- package/registry/entries/apps/shopify.json +31 -0
- package/registry/entries/apps/skills-viewer.json +27 -0
- package/registry/entries/apps/steward.json +31 -0
- package/registry/entries/apps/training.json +54 -0
- package/registry/entries/apps/trajectory-viewer.json +27 -0
- package/registry/entries/apps/vincent.json +31 -0
- package/registry/entries/connectors/bluebubbles.json +99 -0
- package/registry/entries/connectors/bluesky.json +173 -0
- package/registry/entries/connectors/discord.json +119 -0
- package/registry/entries/connectors/farcaster.json +174 -0
- package/registry/entries/connectors/feishu.json +79 -0
- package/registry/entries/connectors/google-chat.json +120 -0
- package/registry/entries/connectors/google.json +82 -0
- package/registry/entries/connectors/imessage.json +96 -0
- package/registry/entries/connectors/instagram.json +64 -0
- package/registry/entries/connectors/line.json +86 -0
- package/registry/entries/connectors/matrix.json +94 -0
- package/registry/entries/connectors/mattermost.json +110 -0
- package/registry/entries/connectors/msteams.json +104 -0
- package/registry/entries/connectors/nextcloud-talk.json +104 -0
- package/registry/entries/connectors/nostr.json +70 -0
- package/registry/entries/connectors/signal.json +81 -0
- package/registry/entries/connectors/slack.json +102 -0
- package/registry/entries/connectors/telegram.json +71 -0
- package/registry/entries/connectors/tlon.json +94 -0
- package/registry/entries/connectors/twitch.json +110 -0
- package/registry/entries/connectors/whatsapp.json +113 -0
- package/registry/entries/connectors/x.json +231 -0
- package/registry/entries/connectors/zalo.json +112 -0
- package/registry/entries/connectors/zalouser.json +122 -0
- package/registry/entries/plugins/agent-orchestrator.json +33 -0
- package/registry/entries/plugins/agent-skills.json +72 -0
- package/registry/entries/plugins/anthropic.json +73 -0
- package/registry/entries/plugins/app-control.json +23 -0
- package/registry/entries/plugins/auto-trader.json +203 -0
- package/registry/entries/plugins/background-runner.json +26 -0
- package/registry/entries/plugins/blooio.json +102 -0
- package/registry/entries/plugins/browser.json +75 -0
- package/registry/entries/plugins/cli.json +40 -0
- package/registry/entries/plugins/clipboard.json +44 -0
- package/registry/entries/plugins/coding-tools.json +71 -0
- package/registry/entries/plugins/commands.json +63 -0
- package/registry/entries/plugins/computeruse.json +74 -0
- package/registry/entries/plugins/copilot-proxy.json +93 -0
- package/registry/entries/plugins/directives.json +63 -0
- package/registry/entries/plugins/edge-tts.json +97 -0
- package/registry/entries/plugins/elevenlabs.json +169 -0
- package/registry/entries/plugins/elizacloud.json +208 -0
- package/registry/entries/plugins/evm.json +134 -0
- package/registry/entries/plugins/experience.json +34 -0
- package/registry/entries/plugins/facewear.json +131 -0
- package/registry/entries/plugins/form.json +26 -0
- package/registry/entries/plugins/github.json +93 -0
- package/registry/entries/plugins/gmail-watch.json +25 -0
- package/registry/entries/plugins/goals.json +77 -0
- package/registry/entries/plugins/google-genai.json +106 -0
- package/registry/entries/plugins/groq.json +93 -0
- package/registry/entries/plugins/hedera.json +48 -0
- package/registry/entries/plugins/inmemorydb.json +25 -0
- package/registry/entries/plugins/linear.json +51 -0
- package/registry/entries/plugins/local-inference.json +142 -0
- package/registry/entries/plugins/local-storage.json +36 -0
- package/registry/entries/plugins/localdb.json +25 -0
- package/registry/entries/plugins/mcp.json +44 -0
- package/registry/entries/plugins/memory.json +124 -0
- package/registry/entries/plugins/minecraft.json +79 -0
- package/registry/entries/plugins/moltbook.json +83 -0
- package/registry/entries/plugins/music.json +155 -0
- package/registry/entries/plugins/mysticism.json +48 -0
- package/registry/entries/plugins/nearai.json +82 -0
- package/registry/entries/plugins/ngrok.json +69 -0
- package/registry/entries/plugins/ollama.json +96 -0
- package/registry/entries/plugins/openai.json +189 -0
- package/registry/entries/plugins/openrouter.json +188 -0
- package/registry/entries/plugins/pdf.json +26 -0
- package/registry/entries/plugins/plugin-manager.json +23 -0
- package/registry/entries/plugins/prose.json +48 -0
- package/registry/entries/plugins/rlm.json +26 -0
- package/registry/entries/plugins/roblox.json +88 -0
- package/registry/entries/plugins/rss.json +64 -0
- package/registry/entries/plugins/s3-storage.json +91 -0
- package/registry/entries/plugins/scheduling.json +35 -0
- package/registry/entries/plugins/shell.json +94 -0
- package/registry/entries/plugins/social-alpha.json +72 -0
- package/registry/entries/plugins/tailscale.json +81 -0
- package/registry/entries/plugins/tee.json +53 -0
- package/registry/entries/plugins/todos.json +26 -0
- package/registry/entries/plugins/trajectory-logger.json +33 -0
- package/registry/entries/plugins/trust.json +39 -0
- package/registry/entries/plugins/tts.json +71 -0
- package/registry/entries/plugins/tunnel.json +45 -0
- package/registry/entries/plugins/twilio.json +168 -0
- package/registry/entries/plugins/vercel-ai-gateway.json +128 -0
- package/registry/entries/plugins/video.json +23 -0
- package/registry/entries/plugins/vision.json +43 -0
- package/registry/entries/plugins/webhooks.json +23 -0
- package/registry/entries/plugins/workflow.json +25 -0
- package/registry/entries/plugins/xai.json +75 -0
- package/registry/index.d.ts +2 -1
- package/registry/index.d.ts.map +1 -1
- package/registry/index.js +46 -12
- package/registry/loader.d.ts +2 -1
- package/registry/loader.d.ts.map +1 -1
- package/registry/loader.js +49 -2
- package/registry/schema.d.ts +244 -34
- package/registry/schema.d.ts.map +1 -1
- package/registry/schema.js +36 -0
- package/runtime/android-avf-microdroid-bridge.d.ts +29 -0
- package/runtime/android-avf-microdroid-bridge.d.ts.map +1 -0
- package/runtime/android-avf-microdroid-bridge.js +149 -0
- package/runtime/api-dev-settings-banner.d.ts.map +1 -1
- package/runtime/api-dev-settings-banner.js +5 -13
- package/runtime/app-core-runtime-hooks.d.ts +21 -0
- package/runtime/app-core-runtime-hooks.d.ts.map +1 -0
- package/runtime/app-core-runtime-hooks.js +10 -0
- package/runtime/autonomy-policy.d.ts +2 -0
- package/runtime/autonomy-policy.d.ts.map +1 -0
- package/runtime/autonomy-policy.js +4 -0
- package/runtime/desktop/AppWindowRenderer.d.ts +17 -0
- package/runtime/desktop/AppWindowRenderer.d.ts.map +1 -0
- package/runtime/desktop/AppWindowRenderer.js +360 -0
- package/runtime/desktop/DesktopSurfaceNavigationRuntime.d.ts +2 -0
- package/runtime/desktop/DesktopSurfaceNavigationRuntime.d.ts.map +1 -0
- package/runtime/desktop/DesktopSurfaceNavigationRuntime.js +41 -0
- package/runtime/desktop/DesktopTrayRuntime.d.ts +2 -0
- package/runtime/desktop/DesktopTrayRuntime.d.ts.map +1 -0
- package/runtime/desktop/DesktopTrayRuntime.js +174 -0
- package/runtime/desktop/DetachedShellRoot.d.ts +10 -0
- package/runtime/desktop/DetachedShellRoot.d.ts.map +1 -0
- package/runtime/desktop/DetachedShellRoot.js +111 -0
- package/runtime/desktop/index.d.ts +6 -0
- package/runtime/desktop/index.d.ts.map +1 -0
- package/runtime/desktop/index.js +5 -0
- package/runtime/desktop/tray-menu.d.ts +20 -0
- package/runtime/desktop/tray-menu.d.ts.map +1 -0
- package/runtime/desktop/tray-menu.js +143 -0
- package/runtime/dev-server.d.ts +1 -1
- package/runtime/dev-server.d.ts.map +1 -1
- package/runtime/dev-server.js +93 -17
- package/runtime/eliza.d.ts +75 -1
- package/runtime/eliza.d.ts.map +1 -1
- package/runtime/eliza.js +596 -122
- package/runtime/ensure-text-to-speech-handler.d.ts.map +1 -1
- package/runtime/ensure-text-to-speech-handler.js +10 -3
- package/runtime/mobile-safe-runtime.d.ts +181 -2
- package/runtime/mobile-safe-runtime.d.ts.map +1 -1
- package/runtime/mobile-safe-runtime.js +1019 -12
- package/runtime/mode/remote-forwarder.d.ts.map +1 -1
- package/runtime/mode/remote-forwarder.js +2 -2
- package/runtime/mode/route-mode-guard.d.ts +1 -2
- package/runtime/mode/route-mode-guard.d.ts.map +1 -1
- package/runtime/mode/route-mode-guard.js +4 -5
- package/runtime/mode/route-mode-matrix.d.ts.map +1 -1
- package/runtime/mode/route-mode-matrix.js +14 -1
- package/runtime/mode/runtime-mode.d.ts +1 -1
- package/runtime/mode/runtime-mode.d.ts.map +1 -1
- package/runtime/mode/runtime-mode.js +15 -4
- package/runtime/runtime-bootstrap-policy.d.ts.map +1 -1
- package/runtime/runtime-bootstrap-policy.js +14 -2
- package/runtime/telegram-standalone-handler.d.ts.map +1 -1
- package/runtime/telegram-standalone-handler.js +10 -9
- package/runtime/tts-cache-wiring.d.ts +29 -0
- package/runtime/tts-cache-wiring.d.ts.map +1 -0
- package/runtime/tts-cache-wiring.js +114 -0
- package/runtime/voice-warmup.d.ts +81 -0
- package/runtime/voice-warmup.d.ts.map +1 -0
- package/runtime/voice-warmup.js +111 -0
- package/scripts/android-sms-gateway-template.test.mjs +1014 -0
- package/scripts/aosp/README.md +19 -15
- package/scripts/aosp/compile-libllama.mjs +1344 -248
- package/scripts/aosp/compile-shim.mjs +47 -18
- package/scripts/aosp/deploy-pixel.mjs +405 -0
- package/scripts/aosp/lib/load-variant-config.mjs +3 -3
- package/scripts/aosp/llama-cpp-patches/README.md +8 -8
- package/scripts/aosp/llama-cpp-patches/apply-patches.mjs +23 -6
- package/scripts/aosp/llama-cpp-patches/polarquant/README.md +37 -0
- package/scripts/aosp/llama-cpp-patches/qjl/README.md +37 -0
- package/scripts/aosp/seccomp-shim/sigsys-handler-arm64.c +169 -0
- package/scripts/aosp/seccomp-shim/sigsys-handler-riscv64.c +217 -0
- package/scripts/aosp/smoke-cuttlefish.mjs +34 -4
- package/scripts/aosp/stage-default-models.mjs +18 -18
- package/scripts/aosp/variant-config-schema.ts +2 -2
- package/scripts/assert-required-bundled-packages.test.ts +534 -0
- package/scripts/audit-apple-store-sandbox.mjs +146 -0
- package/scripts/audit-live-test-surface.mjs +5 -2
- package/scripts/build-capacitor-app.mjs +21 -0
- package/scripts/build-flatpak.mjs +5 -5
- package/scripts/build-helpers/arm64-simd.mjs +72 -0
- package/scripts/build-helpers/omnivoice-merged.mjs +87 -0
- package/scripts/build-helpers/verify-fused-symbols.mjs +567 -0
- package/scripts/build-image.sh +1 -1
- package/scripts/build-llama-cpp-mtp.mjs +487 -0
- package/scripts/build-native-plugins.mjs +230 -18
- package/scripts/build-patched-electrobun-cli.mjs +68 -10
- package/scripts/build-win.mjs +1 -1
- package/scripts/bun-riscv64/Dockerfile +418 -0
- package/scripts/bun-riscv64/README.md +316 -0
- package/scripts/bun-riscv64/build.sh +469 -0
- package/scripts/bun-riscv64/bun-patches/0001-config-add-riscv64-arch.patch +74 -0
- package/scripts/bun-riscv64/bun-patches/0002-flags-add-riscv64-march-mabi.patch +16 -0
- package/scripts/bun-riscv64/bun-patches/0003-zig-add-riscv64-target-triple-and-cpu.patch +26 -0
- package/scripts/bun-riscv64/bun-patches/0004-webkit-force-local-mode-on-riscv64.patch +33 -0
- package/scripts/bun-riscv64/bun-patches/0005-tinycc-disable-on-riscv64.patch +16 -0
- package/scripts/bun-riscv64/bun-patches/0006-build-add-riscv64-cli-validation.patch +15 -0
- package/scripts/bun-riscv64/bun-patches/0007-deps-per-dep-riscv64-checks.patch +24 -0
- package/scripts/bun-riscv64/bun-patches/0008-source-stabilize-riscv64-musl-build.patch +226 -0
- package/scripts/bun-riscv64/bun-patches/0009-disable-wasm-streaming-hooks-for-c-loop.patch +162 -0
- package/scripts/bun-riscv64/bun-patches/0010-disable-inspector-profiler-for-riscv64-c-loop.patch +80 -0
- package/scripts/bun-riscv64/bun-patches/0011-process-arch-add-riscv64.patch +23 -0
- package/scripts/bun-riscv64/bun-patches/0012-cpu-features-add-riscv64-fallback.patch +13 -0
- package/scripts/bun-riscv64/bun-patches/0013-disable-console-inspector-hooks-for-riscv64-c-loop.patch +43 -0
- package/scripts/bun-riscv64/bun-patches/0014-disable-custom-inspector-dispatchers-on-riscv64.patch +127 -0
- package/scripts/bun-riscv64/bun-patches/0015-disable-jsc-profiler-builtins-on-riscv64.patch +75 -0
- package/scripts/bun-riscv64/bun-patches/0016-node-vm-disable-jit-cached-data-on-riscv64-c-loop.patch +96 -0
- package/scripts/bun-riscv64/bun-patches/0017-disable-performance-domjit-signature-on-riscv64-c-loop.patch +34 -0
- package/scripts/bun-riscv64/bun-patches/0018-fix-serialized-script-identifier-big-endian-path.patch +19 -0
- package/scripts/bun-riscv64/bun-patches/0019-add-wtf-timer-fire-bridge-for-c-loop.patch +24 -0
- package/scripts/bun-riscv64/bun-patches/0020-run-riscv64-smoke-test-under-qemu.patch +13 -0
- package/scripts/bun-riscv64/bun-patches/0021-fix-riscv64-linux-open-flags.patch +25 -0
- package/scripts/bun-riscv64/bun-patches/0022-zlib-riscv64-generic-kernels.patch +25 -0
- package/scripts/bun-riscv64/bun-patches/README.md +127 -0
- package/scripts/bun-riscv64/bun-version.json +202 -0
- package/scripts/bun-riscv64/run-build.sh +162 -0
- package/scripts/bun-riscv64/rust-core/0001-riscv64-rust-core-port.patch +868 -0
- package/scripts/bun-riscv64/rust-core/0002-second-wave-riscv64-source-gaps.patch +130 -0
- package/scripts/bun-riscv64/rust-core/0003-third-wave-riscv64-crash-handler-gaps.patch +78 -0
- package/scripts/bun-riscv64/rust-core/0004-rust-target-cpu-riscv64.patch +39 -0
- package/scripts/bun-riscv64/rust-core/0005-fifth-wave-riscv64-source-gaps.patch +96 -0
- package/scripts/bun-riscv64/rust-core/0006-cpp-wasm-and-inspector-guards-riscv64.patch +91 -0
- package/scripts/bun-riscv64/rust-core/0007-bun-alloc-max-align-t-riscv64.patch +36 -0
- package/scripts/bun-riscv64/rust-core/0008-workspace-lints-warn-not-deny-riscv64.patch +75 -0
- package/scripts/bun-riscv64/rust-core/0009-zigglobalobject-wasm-streaming-guards-riscv64.patch +109 -0
- package/scripts/bun-riscv64/rust-core/0010-tcc-externs-stub-on-riscv64.patch +62 -0
- package/scripts/bun-riscv64/rust-core/0011-clippy-ptr-cast-lints-warn-riscv64.patch +61 -0
- package/scripts/bun-riscv64/rust-core/README.md +80 -0
- package/scripts/bun-riscv64/rust-core/webkit-patches/0003-disable-dfg-ftl-on-riscv64.patch +60 -0
- package/scripts/bun-riscv64/rust-core/webkit-patches/0004-riscv64-do-not-force-wasm-in-c-loop.patch +31 -0
- package/scripts/bun-riscv64/rust-core/webkit-patches/0005-domjit-effect-allow-no-dfg-c-loop.patch +40 -0
- package/scripts/bun-riscv64/rust-core/webkit-patches/0006-disable-usewasm-when-webassembly-compiled-out.patch +33 -0
- package/scripts/bun-riscv64/rust-core/webkit-patches/0007-restore-dropped-includes-and-llint-fwd-decl.patch +31 -0
- package/scripts/bun-riscv64/validate.sh +264 -0
- package/scripts/bun-riscv64/webkit-patches/0001-cherry-pick-llint-riscv64.recipe +155 -0
- package/scripts/bun-riscv64/webkit-patches/0002-cherry-pick-baseline-jit-riscv64.recipe +40 -0
- package/scripts/bun-riscv64/webkit-patches/0003-disable-dfg-ftl-on-riscv64.patch +60 -0
- package/scripts/bun-riscv64/webkit-patches/0004-riscv64-do-not-force-wasm-in-c-loop.patch +31 -0
- package/scripts/bun-riscv64/webkit-patches/0005-domjit-effect-allow-no-dfg-c-loop.patch +40 -0
- package/scripts/bun-riscv64/webkit-patches/0006-disable-usewasm-when-webassembly-compiled-out.patch +33 -0
- package/scripts/bun-riscv64/webkit-patches/0007-restore-dropped-includes-and-llint-fwd-decl.patch +72 -0
- package/scripts/bun-riscv64/webkit-patches/README.md +146 -0
- package/scripts/check-homepage-public-readiness.mjs +353 -0
- package/scripts/check-homepage-release-data.mjs +110 -0
- package/scripts/check-i18n.mjs +2 -1
- package/scripts/check-real-local-chat.ts +147 -0
- package/scripts/check-real-local-provisioning.ts +104 -0
- package/scripts/check-real-local-reset.ts +249 -0
- package/scripts/check-sms-gateway-completion-audit.mjs +428 -0
- package/scripts/check-sms-gateway-readiness.mjs +266 -0
- package/scripts/clean-repo.mjs +5 -5
- package/scripts/codesign-mas.mjs +222 -16
- package/scripts/collect-docker-runtime-deps.mjs +229 -0
- package/scripts/continue-sms-gateway-work.mjs +121 -0
- package/scripts/copy-runtime-node-modules.ts +903 -195
- package/scripts/deploy-cloud-api-production-gateway.mjs +52 -0
- package/scripts/desktop-build.mjs +655 -101
- package/scripts/dev-platform.mjs +346 -102
- package/scripts/dev-startup-smoke.mjs +248 -0
- package/scripts/dev-ui.mjs +418 -176
- package/scripts/disable-local-eliza-workspace.mjs +35 -0
- package/scripts/docker-ci-smoke.sh +298 -96
- package/scripts/docker-entrypoint.sh +62 -1
- package/scripts/docker-entrypoint.test.ts +283 -0
- package/scripts/ensure-avatars.mjs +2 -2
- package/scripts/ensure-electrobun-core.mjs +1 -1
- package/scripts/ensure-generated-core-proto-js.mjs +1 -1
- package/scripts/ensure-type-package-aliases.mjs +62 -5
- package/scripts/ensure-vision-deps.mjs +20 -1
- package/scripts/entry.ts +1 -1
- package/scripts/ffi-stub/Makefile +64 -0
- package/scripts/ffi-stub/README.md +391 -0
- package/scripts/ffi-stub/asr-ffi-smoke.ts +139 -0
- package/scripts/ffi-stub/ffi-stub.c +539 -0
- package/scripts/ffi-stub/ffi.h +538 -0
- package/scripts/ffi-stub/libelizainference_stub.so +0 -0
- package/scripts/ffi-stub/tts-stream-ffi-smoke.ts +349 -0
- package/scripts/generate-first-run-voicelines.mjs +194 -0
- package/scripts/generate-plugin-index.js +4 -3
- package/scripts/generate-static-asset-manifest.mjs +1 -1
- package/scripts/i18n-dynamic-keys.json +5 -5
- package/scripts/init-submodules.mjs +2 -2
- package/scripts/install-android-sms-gateway.md +177 -0
- package/scripts/install-android-sms-gateway.mjs +1088 -0
- package/scripts/ios-xcframework/README.md +74 -72
- package/scripts/ios-xcframework/build-xcframework.mjs +204 -43
- package/scripts/ios-xcframework/run-physical-device-smoke.mjs +1943 -0
- package/scripts/ios-xcframework/runtime-symbol-shim.c +450 -0
- package/scripts/kernel-patches/cpu-polar-kernels.mjs +441 -0
- package/scripts/kernel-patches/cpu-simd-kernels.mjs +253 -0
- package/scripts/kernel-patches/cpu-thread-parallelism.mjs +368 -0
- package/scripts/kernel-patches/cuda-kernels.mjs +117 -0
- package/scripts/kernel-patches/metal-kernels.mjs +1698 -109
- package/scripts/kernel-patches/server-omnivoice-route.mjs +718 -0
- package/scripts/kernel-patches/server-structured-output.mjs +279 -0
- package/scripts/kernel-patches/vulkan-dispatch-log.mjs +166 -0
- package/scripts/kernel-patches/vulkan-dispatch-log.test.mjs +50 -0
- package/scripts/kernel-patches/vulkan-dispatch-patches/01-vulkan-shaders-gen.patch +30 -16
- package/scripts/kernel-patches/vulkan-dispatch-patches/02-ggml-vulkan-pipelines.patch +75 -30
- package/scripts/kernel-patches/vulkan-kernels.mjs +800 -49
- package/scripts/lib/agent-source-watcher.mjs +174 -0
- package/scripts/lib/agent-source-watcher.test.mjs +184 -0
- package/scripts/lib/api-supervisor.mjs +78 -9
- package/scripts/lib/api-supervisor.test.mjs +121 -0
- package/scripts/lib/app-dir.mjs +2 -16
- package/scripts/lib/apple-entitlement-audit.mjs +655 -0
- package/scripts/lib/apple-entitlement-audit.test.mjs +144 -0
- package/scripts/lib/bun-version-guard.mjs +13 -13
- package/scripts/lib/capacitor-plugin-build-needed.mjs +4 -3
- package/scripts/lib/capacitor-plugin-names.mjs +30 -14
- package/scripts/lib/desktop-preflight.mjs +9 -5
- package/scripts/lib/desktop-startup-embedding-warmup-policy.mjs +51 -0
- package/scripts/lib/desktop-startup-embedding-warmup-policy.test.mjs +55 -0
- package/scripts/lib/duet-bridge.d.mts +63 -0
- package/scripts/lib/duet-bridge.mjs +193 -0
- package/scripts/lib/node-path-env.mjs +4 -2
- package/scripts/lib/orchestrator-desktop-dev-banner.mjs +12 -3
- package/scripts/lib/patch-bun-exports.mjs +90 -27
- package/scripts/lib/patch-bun-exports.test.mjs +79 -0
- package/scripts/lib/renderer-build-action.mjs +35 -0
- package/scripts/lib/renderer-build-action.test.mjs +70 -0
- package/scripts/lib/stage-android-agent.mjs +748 -99
- package/scripts/lib/sync-eliza-env-aliases.mjs +3 -25
- package/scripts/lib/ui-smoke-stub-decision.mjs +33 -0
- package/scripts/lib/ui-smoke-stub-decision.test.mjs +46 -0
- package/scripts/lib/vite-renderer-dist-stale.mjs +5 -0
- package/scripts/lib/voice-latency-report.mjs +154 -0
- package/scripts/lifeops-prompt-benchmark.ts +21 -12
- package/scripts/link-docker-local-app-packages.mjs +89 -36
- package/scripts/local-stt-bench.ts +192 -0
- package/scripts/maintain-cloud-api-production-gateway.mjs +54 -0
- package/scripts/mas-smoke.mjs +459 -0
- package/scripts/mas-smoke.test.mjs +220 -0
- package/scripts/mobile-auth-simulator-smoke.mjs +0 -1
- package/scripts/normalize-eliza-capture.ts +97 -0
- package/scripts/omnivoice-fuse/prepare.mjs +2543 -23
- package/scripts/pack-upstreams.mjs +65 -5
- package/scripts/package-electrobun-linux.mjs +303 -0
- package/scripts/patch-deps.mjs +5 -3
- package/scripts/patches/llama-mobile-kokoro-tts.patch +480 -0
- package/scripts/playwright-ui-live-stack.ts +194 -49
- package/scripts/playwright-ui-smoke-api-stub.mjs +3501 -109
- package/scripts/pre-review-local.mjs +2 -2
- package/scripts/prepare-ios-cocoapods.sh +41 -3
- package/scripts/release-check.ts +180 -84
- package/scripts/release-workflow-drift.test.ts +57 -0
- package/scripts/relink-workspace-packages-to-dist.mjs +21 -4
- package/scripts/rt.mjs +16 -1
- package/scripts/run-biome-check.mjs +1 -1
- package/scripts/run-coding-agent-e2e.mjs +3 -3
- package/scripts/run-eliza-app-core-script.mjs +34 -0
- package/scripts/run-local-plugin-live-smoke.mjs +71 -2
- package/scripts/run-mobile-build-android-app-actions.test.mjs +426 -0
- package/scripts/run-mobile-build.mjs +4757 -607
- package/scripts/run-node-runtime.mjs +184 -7
- package/scripts/run-node-runtime.test.mjs +167 -0
- package/scripts/run-node-tsx.mjs +80 -33
- package/scripts/run-node.mjs +41 -1
- package/scripts/run-production-build.mjs +34 -27
- package/scripts/run-release-check.mjs +19 -0
- package/scripts/run-release-contract-suite.mjs +107 -14
- package/scripts/run-ui-smoke-playwright-suite.mjs +0 -2
- package/scripts/runtime-package-manifest.ts +21 -3
- package/scripts/setup-upstreams.mjs +42 -1
- package/scripts/sms-gateway-status.mjs +194 -0
- package/scripts/stage-android-agent.test.mjs +97 -0
- package/scripts/stage-elizavoice-lib.mjs +203 -0
- package/scripts/startup-integration-script-drift.test.ts +82 -4
- package/scripts/streaming-pipeline-bench.ts +543 -0
- package/scripts/sync-homepage-porkbun-dns.mjs +262 -0
- package/scripts/test-sms-gateway-software.mjs +100 -0
- package/scripts/type-audit.mjs +1 -1
- package/scripts/validate-bluebubbles-outbound.mjs +293 -0
- package/scripts/validate-cdn-assets.mjs +15 -7
- package/scripts/validate-regression-matrix.mjs +109 -8
- package/scripts/verify-android-sms-gateway-e2e.mjs +362 -0
- package/scripts/verify-bluebubbles-gateway-e2e.mjs +191 -0
- package/scripts/verify-bluebubbles-inbound-readiness.mjs +88 -0
- package/scripts/verify-cloud-api-production-deploy.mjs +87 -0
- package/scripts/verify-cloud-sms-onboarding-flow.mjs +336 -0
- package/scripts/voice/freeze-voice.mjs +521 -0
- package/scripts/voice-attribution-smoke.ts +538 -0
- package/scripts/voice-create-profile.mjs +379 -0
- package/scripts/voice-duet.mjs +1355 -0
- package/scripts/voice-e2e-hardware.ts +871 -0
- package/scripts/voice-interactive.mjs +1750 -0
- package/scripts/voice-latency-report.mjs +96 -0
- package/scripts/voice-latency-report.test.ts +176 -0
- package/scripts/voice-preset/build-default-voice-preset.mjs +249 -0
- package/scripts/voice-preset/build-onboarding-voice.mjs +281 -0
- package/scripts/watch-sms-gateway-readiness.mjs +303 -0
- package/scripts/write-homepage-release-data.mjs +458 -26
- package/security/agent-vault-id.d.ts +1 -1
- package/security/agent-vault-id.js +1 -1
- package/security/hydrate-wallet-keys-from-platform-store.d.ts.map +1 -1
- package/security/hydrate-wallet-keys-from-platform-store.js +23 -14
- package/security/platform-secure-store-node.d.ts +2 -2
- package/security/platform-secure-store-node.js +3 -3
- package/security/wallet-os-store-actions.d.ts +0 -9
- package/security/wallet-os-store-actions.d.ts.map +1 -1
- package/security/wallet-os-store-actions.js +3 -10
- package/services/account-pool.d.ts +23 -14
- package/services/account-pool.d.ts.map +1 -1
- package/services/account-pool.js +86 -24
- package/services/account-usage.d.ts.map +1 -1
- package/services/account-usage.js +2 -5
- package/services/ambient-audio/consent.d.ts +9 -0
- package/services/ambient-audio/consent.d.ts.map +1 -0
- package/services/ambient-audio/consent.js +28 -0
- package/services/ambient-audio/index.d.ts +7 -0
- package/services/ambient-audio/index.d.ts.map +1 -0
- package/services/ambient-audio/index.js +4 -0
- package/services/ambient-audio/replay-buffer.d.ts +14 -0
- package/services/ambient-audio/replay-buffer.d.ts.map +1 -0
- package/services/ambient-audio/replay-buffer.js +66 -0
- package/services/ambient-audio/response-gate.d.ts +3 -0
- package/services/ambient-audio/response-gate.d.ts.map +1 -0
- package/services/ambient-audio/response-gate.js +33 -0
- package/services/ambient-audio/service.d.ts +22 -0
- package/services/ambient-audio/service.d.ts.map +1 -0
- package/services/ambient-audio/service.js +47 -0
- package/services/ambient-audio/types.d.ts +42 -0
- package/services/ambient-audio/types.d.ts.map +1 -0
- package/services/app-updates/update-policy.d.ts +64 -0
- package/services/app-updates/update-policy.d.ts.map +1 -0
- package/services/app-updates/update-policy.js +228 -0
- package/services/auth-store.d.ts +37 -1
- package/services/auth-store.d.ts.map +1 -1
- package/services/auth-store.js +59 -26
- package/services/cloud-jwks-store.d.ts +3 -3
- package/services/cloud-jwks-store.d.ts.map +1 -1
- package/services/cloud-jwks-store.js +5 -8
- package/services/coding-account-bridge.d.ts +71 -0
- package/services/coding-account-bridge.d.ts.map +1 -0
- package/services/coding-account-bridge.js +267 -0
- package/services/connector-target-catalog.d.ts +10 -3
- package/services/connector-target-catalog.d.ts.map +1 -1
- package/services/connector-target-catalog.js +7 -4
- package/services/credential-tunnel-service.d.ts +66 -0
- package/services/credential-tunnel-service.d.ts.map +1 -0
- package/services/credential-tunnel-service.js +227 -0
- package/services/github-credentials.d.ts +1 -1
- package/services/github-credentials.js +1 -1
- package/services/inference-abort.d.ts +47 -0
- package/services/inference-abort.d.ts.map +1 -0
- package/services/inference-abort.js +76 -0
- package/services/persistence.d.ts +2 -3
- package/services/persistence.d.ts.map +1 -1
- package/services/persistence.js +2 -3
- package/services/phrase-chunked-tts.d.ts +136 -0
- package/services/phrase-chunked-tts.d.ts.map +1 -0
- package/services/phrase-chunked-tts.js +208 -0
- package/services/sandbox-registry.d.ts +78 -0
- package/services/sandbox-registry.d.ts.map +1 -0
- package/services/sandbox-registry.js +323 -0
- package/services/secrets-manager-installer.d.ts +8 -1
- package/services/secrets-manager-installer.d.ts.map +1 -1
- package/services/secrets-manager-installer.js +27 -2
- package/services/sensitive-requests/cloud-link-adapter.d.ts +15 -0
- package/services/sensitive-requests/cloud-link-adapter.d.ts.map +1 -0
- package/services/sensitive-requests/cloud-link-adapter.js +73 -0
- package/services/sensitive-requests/index.d.ts +27 -0
- package/services/sensitive-requests/index.d.ts.map +1 -0
- package/services/sensitive-requests/index.js +51 -0
- package/services/sensitive-requests/instruct-dm-only-adapter.d.ts +14 -0
- package/services/sensitive-requests/instruct-dm-only-adapter.d.ts.map +1 -0
- package/services/sensitive-requests/instruct-dm-only-adapter.js +22 -0
- package/services/sensitive-requests/owner-app-inline-adapter.d.ts +3 -0
- package/services/sensitive-requests/owner-app-inline-adapter.d.ts.map +1 -0
- package/services/sensitive-requests/owner-app-inline-adapter.js +146 -0
- package/services/sensitive-requests/owner-app-oauth-adapter.d.ts +3 -0
- package/services/sensitive-requests/owner-app-oauth-adapter.d.ts.map +1 -0
- package/services/sensitive-requests/owner-app-oauth-adapter.js +156 -0
- package/services/sensitive-requests/public-link-adapter.d.ts +14 -0
- package/services/sensitive-requests/public-link-adapter.d.ts.map +1 -0
- package/services/sensitive-requests/public-link-adapter.js +86 -0
- package/services/sensitive-requests/tunnel-link-adapter.d.ts +17 -0
- package/services/sensitive-requests/tunnel-link-adapter.d.ts.map +1 -0
- package/services/sensitive-requests/tunnel-link-adapter.js +38 -0
- package/services/steward-credentials.d.ts +1 -1
- package/services/steward-credentials.d.ts.map +1 -1
- package/services/steward-credentials.js +10 -6
- package/services/steward-sidecar/health-check.d.ts.map +1 -1
- package/services/steward-sidecar/health-check.js +4 -3
- package/services/steward-sidecar/process-management.d.ts +1 -1
- package/services/steward-sidecar/process-management.d.ts.map +1 -1
- package/services/steward-sidecar/process-management.js +9 -3
- package/services/steward-sidecar/types.d.ts +1 -1
- package/services/steward-sidecar/types.d.ts.map +1 -1
- package/services/steward-sidecar/wallet-setup.d.ts.map +1 -1
- package/services/steward-sidecar/wallet-setup.js +8 -7
- package/services/steward-sidecar.d.ts +2 -2
- package/services/steward-sidecar.d.ts.map +1 -1
- package/services/steward-sidecar.js +27 -19
- package/services/task-host-capabilities.d.ts +60 -0
- package/services/task-host-capabilities.d.ts.map +1 -0
- package/services/task-host-capabilities.js +122 -0
- package/services/tool-call-cache/index.d.ts +2 -2
- package/services/tool-call-cache/index.d.ts.map +1 -1
- package/services/tool-call-cache/index.js +1 -1
- package/services/trigger-event-bridge.js +1 -1
- package/services/tunnel-to-mobile/index.d.ts +2 -0
- package/services/tunnel-to-mobile/index.d.ts.map +1 -0
- package/services/tunnel-to-mobile/index.js +1 -0
- package/services/tunnel-to-mobile/tunnel-to-mobile-client.d.ts +105 -0
- package/services/tunnel-to-mobile/tunnel-to-mobile-client.d.ts.map +1 -0
- package/services/tunnel-to-mobile/tunnel-to-mobile-client.js +190 -0
- package/services/vault-bootstrap.d.ts.map +1 -1
- package/services/vault-bootstrap.js +48 -21
- package/services/vault-mirror.d.ts +1 -1
- package/services/vault-mirror.d.ts.map +1 -1
- package/services/vault-mirror.js +29 -6
- package/services/voice-profiles/diarization-pipeline.d.ts +6 -0
- package/services/voice-profiles/diarization-pipeline.d.ts.map +1 -0
- package/services/voice-profiles/diarization-pipeline.js +20 -0
- package/services/voice-profiles/index.d.ts +12 -0
- package/services/voice-profiles/index.d.ts.map +1 -0
- package/services/voice-profiles/index.js +5 -0
- package/services/voice-profiles/nickname-evaluator.d.ts +14 -0
- package/services/voice-profiles/nickname-evaluator.d.ts.map +1 -0
- package/services/voice-profiles/nickname-evaluator.js +46 -0
- package/services/voice-profiles/owner-confidence.d.ts +10 -0
- package/services/voice-profiles/owner-confidence.d.ts.map +1 -0
- package/services/voice-profiles/owner-confidence.js +38 -0
- package/services/voice-profiles/private-challenge.d.ts +20 -0
- package/services/voice-profiles/private-challenge.d.ts.map +1 -0
- package/services/voice-profiles/private-challenge.js +44 -0
- package/services/voice-profiles/store.d.ts +21 -0
- package/services/voice-profiles/store.d.ts.map +1 -0
- package/services/voice-profiles/store.js +50 -0
- package/services/voice-profiles/types.d.ts +38 -0
- package/services/voice-profiles/types.d.ts.map +1 -0
- package/services/voice-profiles/types.js +1 -0
- package/styles/electrobun-mac-window-drag.css +4 -4
- package/test/helpers/__tests__/live-agent-test.smoke.test.ts +43 -70
- package/test/helpers/browser-mocks.ts +2 -2
- package/test/helpers/conditional-tests.ts +2 -2
- package/test/helpers/i18n.ts +1 -1
- package/test/helpers/live-agent-test.ts +537 -551
- package/test/helpers/live-provider.test.ts +4 -4
- package/test/helpers/live-provider.ts +41 -7
- package/test/helpers/live-runtime-server.ts +4 -4
- package/test/helpers/pglite-runtime.ts +1 -1
- package/test/helpers/real-runtime.ts +54 -15
- package/test/helpers/trajectory-harness.ts +11 -7
- package/test/scripts/start-eliza-live.ts +9 -0
- package/test/scripts/test-parallel.mjs +1 -1
- package/test/scripts/test-root-unit.mjs +6 -7
- package/ui-compat.d.ts +13 -2
- package/ui-compat.d.ts.map +1 -1
- package/ui-compat.js +19 -3
- package/api/auth-pairing-compat-routes.d.ts +0 -17
- package/api/auth-pairing-compat-routes.d.ts.map +0 -1
- package/api/auth-pairing-compat-routes.js +0 -301
- package/api/local-inference-compat-routes.d.ts +0 -16
- package/api/local-inference-compat-routes.d.ts.map +0 -1
- package/api/local-inference-compat-routes.js +0 -617
- package/api/onboarding-compat-routes.d.ts +0 -4
- package/api/onboarding-compat-routes.d.ts.map +0 -1
- package/api/onboarding-compat-routes.js +0 -207
- package/api/plugins-compat-routes.d.ts +0 -103
- package/api/plugins-compat-routes.d.ts.map +0 -1
- package/api/plugins-compat-routes.js +0 -1181
- package/api/server-onboarding-compat.d.ts +0 -31
- package/api/server-onboarding-compat.d.ts.map +0 -1
- package/api/server-onboarding-compat.js +0 -283
- package/benchmark/cua-routes.d.ts +0 -10
- package/benchmark/cua-routes.d.ts.map +0 -1
- package/benchmark/cua-routes.js +0 -179
- package/benchmark/mock-plugin-base.d.ts +0 -9
- package/benchmark/mock-plugin-base.d.ts.map +0 -1
- package/benchmark/mock-plugin-base.js +0 -325
- package/cli/parse-duration.d.ts +0 -5
- package/cli/parse-duration.d.ts.map +0 -1
- package/cli/parse-duration.js +0 -27
- package/patches/llama-cpp-capacitor@0.1.5.patch +0 -2387
- package/platform/agent-browser-stub.d.ts +0 -27
- package/platform/agent-browser-stub.d.ts.map +0 -1
- package/platform/agent-browser-stub.js +0 -16
- package/platforms/android/app/src/androidTest/java/com/getcapacitor/myapp/ExampleInstrumentedTest.java +0 -26
- package/platforms/android/app/src/main/res/drawable/ic_launcher_background.xml +0 -170
- package/platforms/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +0 -34
- package/platforms/android/app/src/test/java/com/getcapacitor/myapp/ExampleUnitTest.java +0 -18
- package/platforms/electrobun/assets/appIcon.iconset/icon_512x512@2x.png +0 -0
- package/platforms/electrobun/assets/appIcon.png +0 -0
- package/platforms/electrobun/scripts/build-whisper-universal.sh +0 -137
- package/platforms/electrobun/scripts/build-whisper.sh +0 -95
- package/platforms/electrobun/src/libMacWindowEffects.dylib +0 -0
- package/platforms/electrobun/src/native/whisper.ts +0 -280
- package/platforms/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png +0 -0
- package/platforms/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png +0 -0
- package/registry/generate-apps.d.ts +0 -2
- package/registry/generate-apps.d.ts.map +0 -1
- package/registry/generate-apps.js +0 -338
- package/registry/generate.d.ts +0 -2
- package/registry/generate.d.ts.map +0 -1
- package/registry/generate.js +0 -506
- package/runtime/embedding-manager-support.d.ts +0 -77
- package/runtime/embedding-manager-support.d.ts.map +0 -1
- package/runtime/embedding-manager-support.js +0 -309
- package/runtime/embedding-presets.d.ts +0 -5
- package/runtime/embedding-presets.d.ts.map +0 -1
- package/runtime/embedding-presets.js +0 -47
- package/runtime/embedding-warmup-policy.d.ts +0 -13
- package/runtime/embedding-warmup-policy.d.ts.map +0 -1
- package/runtime/embedding-warmup-policy.js +0 -33
- package/runtime/ensure-local-inference-handler.d.ts +0 -25
- package/runtime/ensure-local-inference-handler.d.ts.map +0 -1
- package/runtime/ensure-local-inference-handler.js +0 -389
- package/runtime/mobile-local-inference-gate.d.ts +0 -21
- package/runtime/mobile-local-inference-gate.d.ts.map +0 -1
- package/runtime/mobile-local-inference-gate.js +0 -24
- package/scripts/aosp/avd-test.mjs +0 -403
- package/scripts/aosp/boot-validate.mjs +0 -536
- package/scripts/aosp/build-aosp.mjs +0 -448
- package/scripts/aosp/build-bootanimation.mjs +0 -178
- package/scripts/aosp/capture-screens.mjs +0 -325
- package/scripts/aosp/e2e-validate.mjs +0 -225
- package/scripts/aosp/lint-init-rc.mjs +0 -258
- package/scripts/aosp/llama-shim/eliza_llama_shim.c +0 -276
- package/scripts/aosp/sim.mjs +0 -277
- package/scripts/aosp/sync-to-aosp.mjs +0 -134
- package/scripts/aosp/validate.mjs +0 -1273
- package/scripts/build-llama-cpp-dflash.mjs +0 -1866
- package/scripts/generate-onboarding-voicelines.mjs +0 -194
- package/scripts/generated/static-asset-manifest.json +0 -4
- package/scripts/normalize-parallax-capture.ts +0 -97
- package/scripts/omnivoice-fuse/Makefile +0 -44
- package/scripts/omnivoice-fuse/README.md +0 -266
- package/scripts/omnivoice-fuse/cmake-graft.mjs +0 -180
- package/scripts/omnivoice-fuse/ffi-stub.c +0 -222
- package/scripts/omnivoice-fuse/ffi.h +0 -158
- package/scripts/omnivoice-fuse/libelizainference_stub.dylib +0 -0
- package/scripts/omnivoice-fuse/verify-symbols.mjs +0 -138
- package/security/cloud-secret-store.d.ts +0 -34
- package/security/cloud-secret-store.d.ts.map +0 -1
- package/security/cloud-secret-store.js +0 -65
- package/security/export-guard.d.ts +0 -34
- package/security/export-guard.d.ts.map +0 -1
- package/security/export-guard.js +0 -127
- package/services/local-inference/__stress__/cache-stress-helpers.d.ts +0 -76
- package/services/local-inference/__stress__/cache-stress-helpers.d.ts.map +0 -1
- package/services/local-inference/__stress__/cache-stress-helpers.js +0 -238
- package/services/local-inference/active-model.d.ts +0 -180
- package/services/local-inference/active-model.d.ts.map +0 -1
- package/services/local-inference/active-model.js +0 -362
- package/services/local-inference/assignments.d.ts +0 -58
- package/services/local-inference/assignments.d.ts.map +0 -1
- package/services/local-inference/assignments.js +0 -179
- package/services/local-inference/backend.d.ts +0 -200
- package/services/local-inference/backend.d.ts.map +0 -1
- package/services/local-inference/backend.js +0 -242
- package/services/local-inference/bundled-models.d.ts +0 -34
- package/services/local-inference/bundled-models.d.ts.map +0 -1
- package/services/local-inference/bundled-models.js +0 -104
- package/services/local-inference/cache-bridge.d.ts +0 -184
- package/services/local-inference/cache-bridge.d.ts.map +0 -1
- package/services/local-inference/cache-bridge.js +0 -333
- package/services/local-inference/catalog.d.ts +0 -57
- package/services/local-inference/catalog.d.ts.map +0 -1
- package/services/local-inference/catalog.js +0 -262
- package/services/local-inference/conversation-registry.d.ts +0 -122
- package/services/local-inference/conversation-registry.d.ts.map +0 -1
- package/services/local-inference/conversation-registry.js +0 -182
- package/services/local-inference/device-bridge.d.ts +0 -139
- package/services/local-inference/device-bridge.d.ts.map +0 -1
- package/services/local-inference/device-bridge.js +0 -774
- package/services/local-inference/dflash-doctor.d.ts +0 -27
- package/services/local-inference/dflash-doctor.d.ts.map +0 -1
- package/services/local-inference/dflash-doctor.js +0 -149
- package/services/local-inference/dflash-server.d.ts +0 -248
- package/services/local-inference/dflash-server.d.ts.map +0 -1
- package/services/local-inference/dflash-server.js +0 -1076
- package/services/local-inference/downloader.d.ts +0 -48
- package/services/local-inference/downloader.d.ts.map +0 -1
- package/services/local-inference/downloader.js +0 -688
- package/services/local-inference/engine.d.ts +0 -282
- package/services/local-inference/engine.d.ts.map +0 -1
- package/services/local-inference/engine.js +0 -743
- package/services/local-inference/external-scanner.d.ts +0 -17
- package/services/local-inference/external-scanner.d.ts.map +0 -1
- package/services/local-inference/external-scanner.js +0 -261
- package/services/local-inference/handler-registry.d.ts +0 -72
- package/services/local-inference/handler-registry.d.ts.map +0 -1
- package/services/local-inference/handler-registry.js +0 -159
- package/services/local-inference/hardware.d.ts +0 -26
- package/services/local-inference/hardware.d.ts.map +0 -1
- package/services/local-inference/hardware.js +0 -139
- package/services/local-inference/hf-search.d.ts +0 -19
- package/services/local-inference/hf-search.d.ts.map +0 -1
- package/services/local-inference/hf-search.js +0 -169
- package/services/local-inference/index.d.ts +0 -10
- package/services/local-inference/index.d.ts.map +0 -1
- package/services/local-inference/index.js +0 -7
- package/services/local-inference/llama-server-metrics.d.ts +0 -108
- package/services/local-inference/llama-server-metrics.d.ts.map +0 -1
- package/services/local-inference/llama-server-metrics.js +0 -175
- package/services/local-inference/manifest/index.d.ts +0 -4
- package/services/local-inference/manifest/index.d.ts.map +0 -1
- package/services/local-inference/manifest/index.js +0 -5
- package/services/local-inference/manifest/schema.d.ts +0 -419
- package/services/local-inference/manifest/schema.d.ts.map +0 -1
- package/services/local-inference/manifest/schema.js +0 -227
- package/services/local-inference/manifest/types.d.ts +0 -23
- package/services/local-inference/manifest/types.d.ts.map +0 -1
- package/services/local-inference/manifest/types.js +0 -5
- package/services/local-inference/manifest/validator.d.ts +0 -43
- package/services/local-inference/manifest/validator.d.ts.map +0 -1
- package/services/local-inference/manifest/validator.js +0 -180
- package/services/local-inference/paths.d.ts +0 -8
- package/services/local-inference/paths.d.ts.map +0 -1
- package/services/local-inference/paths.js +0 -7
- package/services/local-inference/providers.d.ts +0 -61
- package/services/local-inference/providers.d.ts.map +0 -1
- package/services/local-inference/providers.js +0 -334
- package/services/local-inference/ram-budget.d.ts +0 -57
- package/services/local-inference/ram-budget.d.ts.map +0 -1
- package/services/local-inference/ram-budget.js +0 -107
- package/services/local-inference/readiness.d.ts +0 -9
- package/services/local-inference/readiness.d.ts.map +0 -1
- package/services/local-inference/readiness.js +0 -153
- package/services/local-inference/recommendation.d.ts +0 -62
- package/services/local-inference/recommendation.d.ts.map +0 -1
- package/services/local-inference/recommendation.js +0 -309
- package/services/local-inference/registry.d.ts +0 -35
- package/services/local-inference/registry.d.ts.map +0 -1
- package/services/local-inference/registry.js +0 -117
- package/services/local-inference/router-handler.d.ts +0 -51
- package/services/local-inference/router-handler.d.ts.map +0 -1
- package/services/local-inference/router-handler.js +0 -165
- package/services/local-inference/routing-policy.d.ts +0 -55
- package/services/local-inference/routing-policy.d.ts.map +0 -1
- package/services/local-inference/routing-policy.js +0 -195
- package/services/local-inference/routing-preferences.d.ts +0 -8
- package/services/local-inference/routing-preferences.d.ts.map +0 -1
- package/services/local-inference/routing-preferences.js +0 -7
- package/services/local-inference/service.d.ts +0 -88
- package/services/local-inference/service.d.ts.map +0 -1
- package/services/local-inference/service.js +0 -210
- package/services/local-inference/session-pool.d.ts +0 -72
- package/services/local-inference/session-pool.d.ts.map +0 -1
- package/services/local-inference/session-pool.js +0 -125
- package/services/local-inference/types.d.ts +0 -309
- package/services/local-inference/types.d.ts.map +0 -1
- package/services/local-inference/types.js +0 -23
- package/services/local-inference/verify.d.ts +0 -8
- package/services/local-inference/verify.d.ts.map +0 -1
- package/services/local-inference/verify.js +0 -7
- package/services/local-inference/voice/barge-in.d.ts +0 -15
- package/services/local-inference/voice/barge-in.d.ts.map +0 -1
- package/services/local-inference/voice/barge-in.js +0 -20
- package/services/local-inference/voice/engine-bridge.d.ts +0 -256
- package/services/local-inference/voice/engine-bridge.d.ts.map +0 -1
- package/services/local-inference/voice/engine-bridge.js +0 -398
- package/services/local-inference/voice/ffi-bindings.d.ts +0 -114
- package/services/local-inference/voice/ffi-bindings.d.ts.map +0 -1
- package/services/local-inference/voice/ffi-bindings.js +0 -281
- package/services/local-inference/voice/index.d.ts +0 -51
- package/services/local-inference/voice/index.d.ts.map +0 -1
- package/services/local-inference/voice/index.js +0 -50
- package/services/local-inference/voice/lifecycle.d.ts +0 -135
- package/services/local-inference/voice/lifecycle.d.ts.map +0 -1
- package/services/local-inference/voice/lifecycle.js +0 -189
- package/services/local-inference/voice/phoneme-tokenizer.d.ts +0 -58
- package/services/local-inference/voice/phoneme-tokenizer.d.ts.map +0 -1
- package/services/local-inference/voice/phoneme-tokenizer.js +0 -53
- package/services/local-inference/voice/phrase-cache.d.ts +0 -24
- package/services/local-inference/voice/phrase-cache.d.ts.map +0 -1
- package/services/local-inference/voice/phrase-cache.js +0 -32
- package/services/local-inference/voice/phrase-chunker.d.ts +0 -20
- package/services/local-inference/voice/phrase-chunker.d.ts.map +0 -1
- package/services/local-inference/voice/phrase-chunker.js +0 -85
- package/services/local-inference/voice/ring-buffer.d.ts +0 -40
- package/services/local-inference/voice/ring-buffer.d.ts.map +0 -1
- package/services/local-inference/voice/ring-buffer.js +0 -85
- package/services/local-inference/voice/rollback-queue.d.ts +0 -24
- package/services/local-inference/voice/rollback-queue.d.ts.map +0 -1
- package/services/local-inference/voice/rollback-queue.js +0 -49
- package/services/local-inference/voice/scheduler.d.ts +0 -47
- package/services/local-inference/voice/scheduler.d.ts.map +0 -1
- package/services/local-inference/voice/scheduler.js +0 -123
- package/services/local-inference/voice/shared-resources.d.ts +0 -119
- package/services/local-inference/voice/shared-resources.d.ts.map +0 -1
- package/services/local-inference/voice/shared-resources.js +0 -83
- package/services/local-inference/voice/speaker-preset-cache.d.ts +0 -28
- package/services/local-inference/voice/speaker-preset-cache.d.ts.map +0 -1
- package/services/local-inference/voice/speaker-preset-cache.js +0 -44
- package/services/local-inference/voice/types.d.ts +0 -80
- package/services/local-inference/voice/types.d.ts.map +0 -1
- package/services/local-inference/voice/voice-preset-format.d.ts +0 -56
- package/services/local-inference/voice/voice-preset-format.d.ts.map +0 -1
- package/services/local-inference/voice/voice-preset-format.js +0 -184
- package/services/plugin-installer.d.ts +0 -22
- package/services/plugin-installer.d.ts.map +0 -1
- package/services/plugin-installer.js +0 -41
- package/test/scripts/task-agent-live-smoke.ts +0 -1335
- /package/services/{local-inference/voice → ambient-audio}/types.js +0 -0
|
@@ -3,96 +3,130 @@ import { createServer as createNetServer } from "node:net";
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { resolveApiToken, resolveDesktopApiPort } from "@elizaos/shared";
|
|
6
|
+
import type { BrowserWindow } from "electrobun/bun";
|
|
6
7
|
import Electrobun, {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
webgpu,
|
|
8
|
+
ApplicationMenu,
|
|
9
|
+
BrowserView,
|
|
10
|
+
BuildConfig,
|
|
11
|
+
Updater,
|
|
12
|
+
Utils,
|
|
13
|
+
WGPU,
|
|
14
|
+
webgpu,
|
|
15
15
|
} from "electrobun/bun";
|
|
16
16
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
resolveDesktopRuntimeModeWithDeployment,
|
|
18
|
+
resolveInitialApiBase,
|
|
19
|
+
resolveRendererFacingApiBase,
|
|
20
20
|
} from "./api-base";
|
|
21
21
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
parseSettingsWindowAction,
|
|
22
|
+
buildApplicationMenu,
|
|
23
|
+
findAppMenuEntryBySlug,
|
|
24
|
+
parseSettingsWindowAction,
|
|
26
25
|
} from "./application-menu";
|
|
27
26
|
import { setApplicationMenuActionHandler } from "./application-menu-action-registry";
|
|
28
27
|
import { showBackgroundNoticeOnce } from "./background-notice";
|
|
29
28
|
import { getBrandConfig } from "./brand-config";
|
|
30
29
|
import { startBrowserWorkspaceBridgeServer } from "./browser-workspace-bridge-server";
|
|
31
30
|
import { readNavigationEventUrl } from "./cloud-auth-window";
|
|
31
|
+
import { readOpenUrlEventUrl } from "./desktop-deep-link-events";
|
|
32
|
+
import { shouldCreateDesktopPill } from "./desktop-pill-config";
|
|
32
33
|
import { startDesktopTestBridgeServer } from "./desktop-test-bridge-server";
|
|
34
|
+
import {
|
|
35
|
+
shouldCreateDesktopTray,
|
|
36
|
+
shouldStartOnboardingOverlay,
|
|
37
|
+
shouldStartTrayFirst,
|
|
38
|
+
} from "./desktop-tray-config";
|
|
33
39
|
import { scheduleDevtoolsLayoutRefresh } from "./devtools-layout";
|
|
40
|
+
import { createElectrobunBrowserWindow } from "./electrobun-window-options";
|
|
41
|
+
import { seedFirstPartyRemotePluginsForStartup } from "./first-party-remotes";
|
|
34
42
|
import { getFloatingChatManager } from "./floating-chat-window";
|
|
43
|
+
import { appendKioskShellModeParam, isKioskShellMode } from "./kiosk-mode";
|
|
44
|
+
import { publishAgentApiBase } from "./lifecycle/agent-ready-publish";
|
|
35
45
|
import * as apiBaseOwner from "./lifecycle/api-base-owner";
|
|
36
46
|
import {
|
|
37
|
-
|
|
38
|
-
|
|
47
|
+
markDesktopSessionStale,
|
|
48
|
+
primeDesktopSessionAuth,
|
|
39
49
|
} from "./lifecycle/desktop-session-prime";
|
|
40
50
|
import { logger } from "./logger";
|
|
41
51
|
import {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
resolveBootstrapShellRenderer,
|
|
53
|
+
resolveBootstrapViewRenderer,
|
|
54
|
+
resolveMainWindowPartition,
|
|
55
|
+
shouldForceMainWindowCef,
|
|
56
|
+
shouldUseIsolatedMainView,
|
|
46
57
|
} from "./main-window-session";
|
|
47
58
|
import {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
59
|
+
buildMainMenuResetApiCandidates,
|
|
60
|
+
pickReachableMenuResetApiBase,
|
|
61
|
+
runMainMenuResetAfterApiBaseResolved,
|
|
51
62
|
} from "./menu-reset-from-main";
|
|
52
63
|
import {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
configureDesktopLocalApiAuth,
|
|
65
|
+
getAgentManager,
|
|
66
|
+
getDiagnosticLogPath,
|
|
67
|
+
getHealthPollTimeoutMs,
|
|
68
|
+
getStartupDiagnosticLogTail,
|
|
69
|
+
getStartupDiagnosticsSnapshot,
|
|
70
|
+
getStartupStatusPath,
|
|
59
71
|
} from "./native/agent";
|
|
60
72
|
import { getDesktopManager } from "./native/desktop";
|
|
61
73
|
import { disposeNativeModules, initializeNativeModules } from "./native/index";
|
|
62
74
|
import {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
enableVibrancy,
|
|
76
|
+
ensureShadow,
|
|
77
|
+
setNativeDragRegion,
|
|
78
|
+
setTrafficLightsPosition,
|
|
67
79
|
} from "./native/mac-window-effects";
|
|
68
80
|
import { getPermissionManager } from "./native/permissions";
|
|
81
|
+
import { getRemotePluginHost } from "./native/remote-plugin-host";
|
|
69
82
|
import { checkWebGpuSupport } from "./native/webgpu-browser-support";
|
|
83
|
+
import {
|
|
84
|
+
submitOnboardingFirstRun,
|
|
85
|
+
waitForApiReady,
|
|
86
|
+
waitForOnboardingNotificationChoice,
|
|
87
|
+
} from "./native-onboarding";
|
|
88
|
+
import {
|
|
89
|
+
closeOnboardingOverlayWindow,
|
|
90
|
+
createOnboardingOverlayWindow,
|
|
91
|
+
getOnboardingOverlayWindow,
|
|
92
|
+
} from "./onboarding-overlay-window";
|
|
93
|
+
import { getPersistedDeployment } from "./persisted-deployment";
|
|
94
|
+
import { createPillWindow, getPillWindow } from "./pill-window";
|
|
70
95
|
import { printElectrobunDevSettingsBanner } from "./print-electrobun-dev-settings-banner";
|
|
71
|
-
import { resolveRendererAsset } from "./renderer-static";
|
|
72
96
|
import {
|
|
73
|
-
|
|
74
|
-
|
|
97
|
+
createRendererApiProxyRequestInit,
|
|
98
|
+
isRendererApiProxyPath,
|
|
99
|
+
resolveRendererProxyIdleTimeoutSeconds,
|
|
100
|
+
} from "./renderer-api-proxy";
|
|
101
|
+
import {
|
|
102
|
+
getRendererAssetContentType,
|
|
103
|
+
resolveRendererAsset,
|
|
104
|
+
resolveRendererAssetByteRange,
|
|
105
|
+
} from "./renderer-static";
|
|
106
|
+
import {
|
|
107
|
+
buildBunRpcHandlers,
|
|
108
|
+
wireBrowserWorkspaceCaller,
|
|
75
109
|
} from "./rpc-handlers";
|
|
76
110
|
import type { ElizaDesktopRPCSchema } from "./rpc-schema";
|
|
77
111
|
import {
|
|
78
|
-
|
|
79
|
-
|
|
112
|
+
readResolvedPreloadScript,
|
|
113
|
+
resolveRendererAssetDir,
|
|
80
114
|
} from "./runtime-layout";
|
|
81
115
|
import { mergeRuntimePermissionStates } from "./runtime-permissions";
|
|
82
116
|
import { startScreenshotDevServer } from "./screenshot-dev-server";
|
|
83
117
|
import { recordStartupPhase, resolveStartupBundlePath } from "./startup-trace";
|
|
84
118
|
import {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
119
|
+
type BoundsStore,
|
|
120
|
+
isDetachedSurface,
|
|
121
|
+
type ManagedWindowFrame,
|
|
122
|
+
type ManagedWindowLike,
|
|
123
|
+
SurfaceWindowManager,
|
|
90
124
|
} from "./surface-windows";
|
|
91
125
|
import type { SendToWebview } from "./types.js";
|
|
92
126
|
import {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
127
|
+
resolveDesktopBundleVersion,
|
|
128
|
+
shouldResetWindowsCefProfile,
|
|
129
|
+
shouldWriteWindowsCefProfileMarker,
|
|
96
130
|
} from "./windows-cef-profile";
|
|
97
131
|
|
|
98
132
|
const BRAND = getBrandConfig();
|
|
@@ -101,88 +135,102 @@ const STARTUP_CRASH_REPORT_FILE = "startup-crash-report-latest.md";
|
|
|
101
135
|
const STARTUP_CRASH_PROMPT_MARKER_FILE = "startup-crash-last-prompted.txt";
|
|
102
136
|
|
|
103
137
|
import {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
138
|
+
isAgentReady,
|
|
139
|
+
onAgentReadyChange,
|
|
140
|
+
setAgentReady,
|
|
107
141
|
} from "./agent-ready-state";
|
|
108
142
|
import {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
143
|
+
clearCurrentMainWindow,
|
|
144
|
+
setCurrentMainWindow,
|
|
145
|
+
updateCurrentMainWindowEffectsState,
|
|
112
146
|
} from "./main-window-runtime";
|
|
113
147
|
import {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
148
|
+
isStewardLocalEnabled,
|
|
149
|
+
onStewardStatusChange,
|
|
150
|
+
resetSteward,
|
|
151
|
+
restartSteward,
|
|
152
|
+
setStewardSendToWebview,
|
|
153
|
+
startSteward,
|
|
154
|
+
stopSteward,
|
|
121
155
|
} from "./native/steward";
|
|
122
156
|
|
|
123
157
|
function resolveDesktopAppIconPath(): string {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
158
|
+
return path.join(
|
|
159
|
+
import.meta.dir,
|
|
160
|
+
process.platform === "win32"
|
|
161
|
+
? "../assets/appIcon.ico"
|
|
162
|
+
: "../assets/appIcon.png",
|
|
163
|
+
);
|
|
130
164
|
}
|
|
131
165
|
|
|
132
166
|
function shouldUseBrowserDevtoolsFallback(): boolean {
|
|
133
|
-
|
|
167
|
+
return false;
|
|
134
168
|
}
|
|
135
169
|
|
|
136
170
|
function setupApplicationMenu(): void {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
171
|
+
const isMac = process.platform === "darwin";
|
|
172
|
+
const menu = buildApplicationMenu({
|
|
173
|
+
isMac,
|
|
174
|
+
browserEnabled: false,
|
|
175
|
+
detachedWindows: surfaceWindowManager?.listWindows() ?? [],
|
|
176
|
+
agentReady: isAgentReady(),
|
|
177
|
+
});
|
|
178
|
+
ApplicationMenu.setApplicationMenu(
|
|
179
|
+
menu as Parameters<typeof ApplicationMenu.setApplicationMenu>[0],
|
|
180
|
+
);
|
|
147
181
|
}
|
|
148
182
|
|
|
149
183
|
onAgentReadyChange(() => setupApplicationMenu());
|
|
150
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Resolve the desktop runtime mode, consulting both the env vars and the
|
|
187
|
+
* persisted deployment target (`eliza.json` `deploymentTarget.runtime`). A
|
|
188
|
+
* topology-3 (cloud-hosted) agent target with a renderer-ready cloud agent
|
|
189
|
+
* base resolves to `external` so the embedded agent is skipped; topology 1
|
|
190
|
+
* (local agent → cloud inference) and topology 2 (all-local) keep `local`.
|
|
191
|
+
*/
|
|
192
|
+
function resolveDesktopRuntime(): ReturnType<
|
|
193
|
+
typeof resolveDesktopRuntimeModeWithDeployment
|
|
194
|
+
> {
|
|
195
|
+
return resolveDesktopRuntimeModeWithDeployment(
|
|
196
|
+
process.env as Record<string, string | undefined>,
|
|
197
|
+
getPersistedDeployment(),
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
151
201
|
function summarizeDesktopActionError(error: unknown, fallback: string): string {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
202
|
+
const message = error instanceof Error ? error.message : fallback;
|
|
203
|
+
const trimmed = message.trim();
|
|
204
|
+
if (!trimmed) return fallback;
|
|
205
|
+
return trimmed.length > 80 ? `${trimmed.slice(0, 77)}...` : trimmed;
|
|
156
206
|
}
|
|
157
207
|
|
|
158
208
|
function buildApiRequestHeaders(contentType?: string): Record<string, string> {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
return headers;
|
|
209
|
+
const headers: Record<string, string> = {
|
|
210
|
+
Accept: "application/json",
|
|
211
|
+
};
|
|
212
|
+
if (contentType) {
|
|
213
|
+
headers["Content-Type"] = contentType;
|
|
214
|
+
}
|
|
215
|
+
let apiToken = resolveApiToken(process.env);
|
|
216
|
+
if (!apiToken) {
|
|
217
|
+
const rt = resolveDesktopRuntime();
|
|
218
|
+
if (rt.mode === "local") {
|
|
219
|
+
apiToken = configureDesktopLocalApiAuth().trim();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (apiToken) {
|
|
223
|
+
headers.Authorization = `Bearer ${apiToken}`;
|
|
224
|
+
}
|
|
225
|
+
return headers;
|
|
178
226
|
}
|
|
179
227
|
|
|
180
228
|
function resolveLoopbackApiBase(): string | null {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
229
|
+
const port = getAgentManager().getStatus().port;
|
|
230
|
+
if (typeof port === "number" && port > 0) {
|
|
231
|
+
return `http://127.0.0.1:${port}`;
|
|
232
|
+
}
|
|
233
|
+
return resolveInitialApiBase(process.env);
|
|
186
234
|
}
|
|
187
235
|
|
|
188
236
|
/**
|
|
@@ -194,28 +242,28 @@ function resolveLoopbackApiBase(): string | null {
|
|
|
194
242
|
* port, menu Reset must not blindly POST to the dead env URL.
|
|
195
243
|
*/
|
|
196
244
|
async function resolveReachableApiBaseForMainReset(): Promise<string | null> {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
245
|
+
const candidates = buildMainMenuResetApiCandidates({
|
|
246
|
+
embeddedPort: getAgentManager().getStatus().port,
|
|
247
|
+
configuredBase: resolveInitialApiBase(process.env),
|
|
248
|
+
});
|
|
249
|
+
if (candidates.length === 0) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
const base = await pickReachableMenuResetApiBase({
|
|
253
|
+
candidates,
|
|
254
|
+
fetchImpl: fetch,
|
|
255
|
+
buildHeaders: buildApiRequestHeaders,
|
|
256
|
+
});
|
|
257
|
+
if (base) {
|
|
258
|
+
logger.info(
|
|
259
|
+
`[Main][reset] Using reachable API base ${base} (tried: ${candidates.join(", ")})`,
|
|
260
|
+
);
|
|
261
|
+
} else {
|
|
262
|
+
logger.warn(
|
|
263
|
+
`[Main][reset] No reachable API base among candidates (tried: ${candidates.join(", ")})`,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
return base;
|
|
219
267
|
}
|
|
220
268
|
|
|
221
269
|
/**
|
|
@@ -230,112 +278,110 @@ async function resolveReachableApiBaseForMainReset(): Promise<string | null> {
|
|
|
230
278
|
* @see `docs/apps/desktop-main-process-reset.md`
|
|
231
279
|
*/
|
|
232
280
|
async function resetTheAppFromApplicationMenu(): Promise<void> {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
});
|
|
338
|
-
}
|
|
281
|
+
logger.info(
|
|
282
|
+
`[Main][reset] App menu: Reset ${BRAND.appName} — confirm + POST /api/agent/reset + restart (main process)`,
|
|
283
|
+
);
|
|
284
|
+
await getDesktopManager()
|
|
285
|
+
.showWindow()
|
|
286
|
+
.catch((err: unknown) => {
|
|
287
|
+
logger.warn(
|
|
288
|
+
`[Main][reset] showWindow failed (continuing): ${err instanceof Error ? err.message : String(err)}`,
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const autoConfirm =
|
|
293
|
+
process.env.ELIZA_DESKTOP_TEST_AUTO_CONFIRM_DIALOGS === "1" ||
|
|
294
|
+
process.env.ELIZA_DESKTOP_TEST_AUTO_CONFIRM_RESET === "1";
|
|
295
|
+
const response = autoConfirm
|
|
296
|
+
? 0
|
|
297
|
+
: await Utils.showMessageBox({
|
|
298
|
+
type: "warning",
|
|
299
|
+
title: "Reset Agent",
|
|
300
|
+
message:
|
|
301
|
+
"This will reset the agent: config, cloud keys, and local agent database (conversations / memory).",
|
|
302
|
+
detail:
|
|
303
|
+
"Downloaded GGUF embedding models are kept. You will return to first-run runtime setup.",
|
|
304
|
+
buttons: ["Reset", "Cancel"],
|
|
305
|
+
defaultId: 0,
|
|
306
|
+
cancelId: 1,
|
|
307
|
+
}).then((box) =>
|
|
308
|
+
box && typeof box === "object" && "response" in box
|
|
309
|
+
? (box as { response: number }).response
|
|
310
|
+
: typeof box === "number"
|
|
311
|
+
? box
|
|
312
|
+
: 1,
|
|
313
|
+
);
|
|
314
|
+
if (response !== 0) {
|
|
315
|
+
logger.info("[Main][reset] User cancelled native confirm");
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const apiBase = await resolveReachableApiBaseForMainReset();
|
|
320
|
+
if (!apiBase) {
|
|
321
|
+
Utils.showNotification({
|
|
322
|
+
title: "Reset Failed",
|
|
323
|
+
body: `Could not reach the ${BRAND.appName} API (tried embedded port and ELIZA_DESKTOP_API_BASE / defaults). Start the agent or dev server, or fix your API base env.`,
|
|
324
|
+
});
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
const runtimeMode = resolveDesktopRuntime();
|
|
330
|
+
|
|
331
|
+
await runMainMenuResetAfterApiBaseResolved({
|
|
332
|
+
apiBase,
|
|
333
|
+
fetchImpl: fetch,
|
|
334
|
+
buildHeaders: buildApiRequestHeaders,
|
|
335
|
+
useEmbeddedRestart: runtimeMode.mode === "local",
|
|
336
|
+
restartEmbeddedClearingLocalDb: async () => {
|
|
337
|
+
const status = await getAgentManager().restartClearingLocalDb();
|
|
338
|
+
return { port: status.port ?? undefined };
|
|
339
|
+
},
|
|
340
|
+
pushEmbeddedApiBaseToRenderer: (port, apiToken) => {
|
|
341
|
+
if (currentWindow) {
|
|
342
|
+
const base = port
|
|
343
|
+
? resolveRendererFacingApiBase(
|
|
344
|
+
process.env as Record<string, string | undefined>,
|
|
345
|
+
port,
|
|
346
|
+
)
|
|
347
|
+
: (resolveLoopbackApiBase() ??
|
|
348
|
+
resolveInitialApiBase(
|
|
349
|
+
process.env as Record<string, string | undefined>,
|
|
350
|
+
) ??
|
|
351
|
+
apiBase);
|
|
352
|
+
if (base) {
|
|
353
|
+
apiBaseOwner.notifyChange(currentWindow, base, apiToken);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
getLocalApiAuthToken: () => configureDesktopLocalApiAuth(),
|
|
358
|
+
postExternalAgentRestart: async () => {
|
|
359
|
+
try {
|
|
360
|
+
await fetch(`${apiBase}/api/agent/restart`, {
|
|
361
|
+
method: "POST",
|
|
362
|
+
headers: buildApiRequestHeaders(),
|
|
363
|
+
});
|
|
364
|
+
} catch {
|
|
365
|
+
/* 409 / race while restarting — poll below */
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
resolveApiBaseForStatusPoll: () => resolveLoopbackApiBase() ?? apiBase,
|
|
369
|
+
sendMenuResetAppliedToRenderer: (payload) => {
|
|
370
|
+
sendToActiveRenderer("desktopTrayMenuClick", payload);
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
logger.info(
|
|
374
|
+
"[Main][reset] Pushed menu-reset-app-applied to renderer with /api/status snapshot",
|
|
375
|
+
);
|
|
376
|
+
} catch (err) {
|
|
377
|
+
logger.error(
|
|
378
|
+
`[Main][reset] Main-process reset failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
379
|
+
);
|
|
380
|
+
Utils.showNotification({
|
|
381
|
+
title: "Reset Failed",
|
|
382
|
+
body: summarizeDesktopActionError(err, "Reset failed"),
|
|
383
|
+
});
|
|
384
|
+
}
|
|
339
385
|
}
|
|
340
386
|
|
|
341
387
|
const MAC_TRAFFIC_LIGHTS_X = 14;
|
|
@@ -355,75 +401,75 @@ const MAC_NATIVE_DRAG_REGION_HEIGHT = 38;
|
|
|
355
401
|
* view stays above WKWebView.
|
|
356
402
|
*/
|
|
357
403
|
function applyMacOSWindowEffects(win: BrowserWindow): void {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
404
|
+
if (process.platform !== "darwin") return;
|
|
405
|
+
|
|
406
|
+
const ptr = (win as { ptr?: unknown }).ptr;
|
|
407
|
+
if (!ptr) {
|
|
408
|
+
logger.warn("[MacEffects] win.ptr unavailable — skipping native effects");
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const vibrancyEnabled = enableVibrancy(
|
|
413
|
+
ptr as Parameters<typeof enableVibrancy>[0],
|
|
414
|
+
);
|
|
415
|
+
const shadowEnabled = ensureShadow(ptr as Parameters<typeof ensureShadow>[0]);
|
|
416
|
+
updateCurrentMainWindowEffectsState({
|
|
417
|
+
vibrancyEnabled,
|
|
418
|
+
shadowEnabled,
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
const alignButtons = () =>
|
|
422
|
+
setTrafficLightsPosition(
|
|
423
|
+
ptr as Parameters<typeof setTrafficLightsPosition>[0],
|
|
424
|
+
MAC_TRAFFIC_LIGHTS_X,
|
|
425
|
+
MAC_TRAFFIC_LIGHTS_Y,
|
|
426
|
+
);
|
|
427
|
+
const alignDragRegion = () =>
|
|
428
|
+
setNativeDragRegion(
|
|
429
|
+
ptr as Parameters<typeof setNativeDragRegion>[0],
|
|
430
|
+
MAC_NATIVE_DRAG_REGION_X,
|
|
431
|
+
MAC_NATIVE_DRAG_REGION_HEIGHT,
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
const alignChrome = () => {
|
|
435
|
+
alignButtons();
|
|
436
|
+
alignDragRegion();
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
alignChrome();
|
|
440
|
+
setTimeout(alignChrome, 120);
|
|
441
|
+
const chromeRefreshTimer = setInterval(alignChrome, 1000);
|
|
442
|
+
|
|
443
|
+
win.on("resize", alignChrome);
|
|
444
|
+
win.on("focus", alignChrome);
|
|
445
|
+
win.on("blur", () => {
|
|
446
|
+
alignChrome();
|
|
447
|
+
setTimeout(alignChrome, 80);
|
|
448
|
+
setTimeout(alignChrome, 240);
|
|
449
|
+
setTimeout(alignChrome, 700);
|
|
450
|
+
});
|
|
451
|
+
// Display (NSScreen) changes without a resize edge case — depth uses window.screen.
|
|
452
|
+
win.on("move", alignChrome);
|
|
453
|
+
win.on("close", () => clearInterval(chromeRefreshTimer));
|
|
454
|
+
|
|
455
|
+
// WKWebView is often inserted or reordered after first layout; restack native
|
|
456
|
+
// views so drag/resize strips stay hit-testable above the page.
|
|
457
|
+
try {
|
|
458
|
+
win.webview.on("dom-ready", () => {
|
|
459
|
+
alignChrome();
|
|
460
|
+
setTimeout(alignChrome, 50);
|
|
461
|
+
setTimeout(alignChrome, 300);
|
|
462
|
+
});
|
|
463
|
+
} catch {
|
|
464
|
+
// webview may not accept listeners yet in some embed paths
|
|
465
|
+
}
|
|
420
466
|
}
|
|
421
467
|
|
|
422
468
|
interface WindowState {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
469
|
+
x: number;
|
|
470
|
+
y: number;
|
|
471
|
+
width: number;
|
|
472
|
+
height: number;
|
|
427
473
|
}
|
|
428
474
|
|
|
429
475
|
/**
|
|
@@ -434,10 +480,10 @@ interface WindowState {
|
|
|
434
480
|
* systems where maximize() hasn't registered yet.
|
|
435
481
|
*/
|
|
436
482
|
const DEFAULT_WINDOW_STATE: WindowState = {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
483
|
+
x: 60,
|
|
484
|
+
y: 60,
|
|
485
|
+
width: 1440,
|
|
486
|
+
height: 900,
|
|
441
487
|
};
|
|
442
488
|
|
|
443
489
|
/**
|
|
@@ -449,58 +495,58 @@ const DEFAULT_WINDOW_STATE: WindowState = {
|
|
|
449
495
|
const MAXIMIZE_ON_LAUNCH_SENTINEL = 1;
|
|
450
496
|
|
|
451
497
|
interface PersistedWindowState extends WindowState {
|
|
452
|
-
|
|
453
|
-
|
|
498
|
+
/** When truthy, call win.maximize() right after creation. */
|
|
499
|
+
shouldMaximize?: number;
|
|
454
500
|
}
|
|
455
501
|
|
|
456
502
|
function loadWindowState(statePath: string): PersistedWindowState {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
503
|
+
try {
|
|
504
|
+
if (fs.existsSync(statePath)) {
|
|
505
|
+
const data = JSON.parse(fs.readFileSync(statePath, "utf8"));
|
|
506
|
+
if (typeof data.width === "number" && typeof data.height === "number") {
|
|
507
|
+
const state = { ...DEFAULT_WINDOW_STATE, ...data };
|
|
508
|
+
// Discard state saved while the window was minimized. On Windows,
|
|
509
|
+
// minimized windows report position (-32000, -32000) and a tiny
|
|
510
|
+
// size, which makes the window invisible on next launch.
|
|
511
|
+
if (state.width < 200 || state.height < 200 || state.x < -16000) {
|
|
512
|
+
return {
|
|
513
|
+
...DEFAULT_WINDOW_STATE,
|
|
514
|
+
shouldMaximize: MAXIMIZE_ON_LAUNCH_SENTINEL,
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
return state;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
} catch {}
|
|
521
|
+
// No saved state → first launch. Open at the default 1440×900 window
|
|
522
|
+
// size (centered-ish near top-left) instead of maximizing. Maximizing on
|
|
523
|
+
// first launch buries the welcome content in a vast empty workspace and
|
|
524
|
+
// gives a "this is overwhelming" impression. The user can always
|
|
525
|
+
// maximize themselves; subsequent launches restore their last size.
|
|
526
|
+
return { ...DEFAULT_WINDOW_STATE };
|
|
481
527
|
}
|
|
482
528
|
|
|
483
529
|
let saveTimer: ReturnType<typeof setTimeout> | null = null;
|
|
484
530
|
|
|
485
531
|
function scheduleStateSave(statePath: string, win: BrowserWindow): void {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
532
|
+
if (saveTimer) clearTimeout(saveTimer);
|
|
533
|
+
saveTimer = setTimeout(() => {
|
|
534
|
+
try {
|
|
535
|
+
const { x, y } = win.getPosition();
|
|
536
|
+
const { width, height } = win.getSize();
|
|
537
|
+
// Skip saving when the window is minimized — Windows reports
|
|
538
|
+
// position (-32000, -32000) and a collapsed size, which would make
|
|
539
|
+
// the window invisible on next launch.
|
|
540
|
+
if (width < 200 || height < 200 || x < -16000) return;
|
|
541
|
+
const dir = path.dirname(statePath);
|
|
542
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
543
|
+
fs.writeFileSync(
|
|
544
|
+
statePath,
|
|
545
|
+
JSON.stringify({ x, y, width, height }),
|
|
546
|
+
"utf8",
|
|
547
|
+
);
|
|
548
|
+
} catch {}
|
|
549
|
+
}, 500);
|
|
504
550
|
}
|
|
505
551
|
|
|
506
552
|
/**
|
|
@@ -512,69 +558,69 @@ function scheduleStateSave(statePath: string, win: BrowserWindow): void {
|
|
|
512
558
|
* Mixing them would couple unrelated lifecycles.
|
|
513
559
|
*/
|
|
514
560
|
function createAppWindowBoundsStore(): BoundsStore {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
561
|
+
const storePath = path.join(Utils.paths.userData, "app-window-bounds.json");
|
|
562
|
+
type Blob = Record<string, ManagedWindowFrame>;
|
|
563
|
+
let cache: Blob | null = null;
|
|
564
|
+
|
|
565
|
+
function isFrame(value: unknown): value is ManagedWindowFrame {
|
|
566
|
+
if (!value || typeof value !== "object") return false;
|
|
567
|
+
const f = value as Record<string, unknown>;
|
|
568
|
+
return (
|
|
569
|
+
typeof f.x === "number" &&
|
|
570
|
+
typeof f.y === "number" &&
|
|
571
|
+
typeof f.width === "number" &&
|
|
572
|
+
typeof f.height === "number" &&
|
|
573
|
+
f.width >= 200 &&
|
|
574
|
+
f.height >= 200 &&
|
|
575
|
+
f.x > -16000 &&
|
|
576
|
+
f.y > -16000
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
function readCache(): Blob {
|
|
581
|
+
if (cache) return cache;
|
|
582
|
+
try {
|
|
583
|
+
if (fs.existsSync(storePath)) {
|
|
584
|
+
const raw = JSON.parse(fs.readFileSync(storePath, "utf8")) as unknown;
|
|
585
|
+
if (raw && typeof raw === "object") {
|
|
586
|
+
const next: Blob = {};
|
|
587
|
+
for (const [slug, frame] of Object.entries(raw)) {
|
|
588
|
+
if (isFrame(frame)) next[slug] = frame;
|
|
589
|
+
}
|
|
590
|
+
cache = next;
|
|
591
|
+
return next;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
} catch {
|
|
595
|
+
/* ignore — corrupt or missing file just yields empty cache */
|
|
596
|
+
}
|
|
597
|
+
cache = {};
|
|
598
|
+
return cache;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function writeCache(): void {
|
|
602
|
+
if (!cache) return;
|
|
603
|
+
try {
|
|
604
|
+
const dir = path.dirname(storePath);
|
|
605
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
606
|
+
fs.writeFileSync(storePath, JSON.stringify(cache), "utf8");
|
|
607
|
+
} catch {
|
|
608
|
+
/* ignore — bounds save must never break the window */
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
return {
|
|
613
|
+
load: (slug) => {
|
|
614
|
+
const blob = readCache();
|
|
615
|
+
return blob[slug] ?? null;
|
|
616
|
+
},
|
|
617
|
+
save: (slug, frame) => {
|
|
618
|
+
if (!isFrame(frame)) return;
|
|
619
|
+
const blob = readCache();
|
|
620
|
+
blob[slug] = frame;
|
|
621
|
+
writeCache();
|
|
622
|
+
},
|
|
623
|
+
};
|
|
578
624
|
}
|
|
579
625
|
|
|
580
626
|
let currentWindow: BrowserWindow | null = null;
|
|
@@ -585,8 +631,19 @@ let backgroundWindowPromise: Promise<void> | null = null;
|
|
|
585
631
|
let isQuitting = false;
|
|
586
632
|
|
|
587
633
|
function requestAppQuit(): void {
|
|
588
|
-
|
|
589
|
-
|
|
634
|
+
isQuitting = true;
|
|
635
|
+
Utils.quit();
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* True for packaged desktop builds, false for the in-repo dev runtime.
|
|
640
|
+
* The compiled bundle no longer runs out of a `/src/` directory, so its
|
|
641
|
+
* absence is the dev/prod signal already used by loadTheAppEnvFilesForMain.
|
|
642
|
+
* Normalize Windows separators first so dev paths containing `\src\` are not
|
|
643
|
+
* misclassified as packaged (which would make dev builds fatal on Windows).
|
|
644
|
+
*/
|
|
645
|
+
function isPackagedDesktopBuild(): boolean {
|
|
646
|
+
return !import.meta.dir.replaceAll("\\", "/").includes("/src/");
|
|
590
647
|
}
|
|
591
648
|
|
|
592
649
|
const cleanupFns: Array<() => void | Promise<void>> = [];
|
|
@@ -594,54 +651,54 @@ let lastFocusedWindow: ManagedWindowLike | null = null;
|
|
|
594
651
|
const macOpenedDevtoolsWindowIds = new Set<number>();
|
|
595
652
|
|
|
596
653
|
async function openBrowserDevtoolsFallback(
|
|
597
|
-
|
|
654
|
+
targetWindow: ManagedWindowLike | BrowserWindow | null,
|
|
598
655
|
): Promise<void> {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
656
|
+
const currentUrl = (
|
|
657
|
+
targetWindow?.webview as { url?: string | null } | undefined
|
|
658
|
+
)?.url;
|
|
659
|
+
const url = currentUrl?.trim() || (await resolveRendererUrl());
|
|
660
|
+
|
|
661
|
+
if (!/^https?:\/\//i.test(url)) {
|
|
662
|
+
Utils.showNotification({
|
|
663
|
+
title: "Developer Tools Unavailable",
|
|
664
|
+
body: "Native macOS Electrobun devtools are disabled, and the renderer URL is not browser-openable.",
|
|
665
|
+
});
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
Utils.openExternal(url);
|
|
670
|
+
Utils.showNotification({
|
|
671
|
+
title: "Opened Renderer in Browser",
|
|
672
|
+
body: "Native macOS Electrobun devtools are disabled due to a WKWebView crash/layout bug. Use browser devtools instead.",
|
|
673
|
+
});
|
|
617
674
|
}
|
|
618
675
|
|
|
619
676
|
function sendToActiveRenderer(message: string, payload?: unknown): void {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
677
|
+
currentSendToWebview?.(message, payload);
|
|
678
|
+
if (!currentSendToWebview) {
|
|
679
|
+
const level =
|
|
680
|
+
message === "desktopTrayMenuClick" ? console.warn : console.debug;
|
|
681
|
+
level.call(
|
|
682
|
+
console,
|
|
683
|
+
"[Main] Dropped renderer message (no window):",
|
|
684
|
+
message,
|
|
685
|
+
);
|
|
686
|
+
}
|
|
630
687
|
}
|
|
631
688
|
|
|
632
689
|
function sendManagedWindowsChanged(): void {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
690
|
+
sendToActiveRenderer("desktopManagedWindowsChanged", {
|
|
691
|
+
windows: surfaceWindowManager?.listWindows() ?? [],
|
|
692
|
+
});
|
|
636
693
|
}
|
|
637
694
|
|
|
638
695
|
function shouldRestoreWindowBeforeMenuAction(
|
|
639
|
-
|
|
696
|
+
action: string | undefined,
|
|
640
697
|
): boolean {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
698
|
+
if (!action || action.startsWith("focus-window:")) {
|
|
699
|
+
return false;
|
|
700
|
+
}
|
|
701
|
+
return action !== "quit";
|
|
645
702
|
}
|
|
646
703
|
|
|
647
704
|
/**
|
|
@@ -650,632 +707,800 @@ function shouldRestoreWindowBeforeMenuAction(
|
|
|
650
707
|
* Returns the base URL e.g. "http://localhost:5174".
|
|
651
708
|
*/
|
|
652
709
|
async function startRendererServer(): Promise<string> {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
710
|
+
const rendererDir = resolveRendererAssetDir(import.meta.dir);
|
|
711
|
+
if (!fs.existsSync(rendererDir)) {
|
|
712
|
+
logger.warn("[Renderer] renderer dir not found:", rendererDir);
|
|
713
|
+
return "";
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Find a free port starting at 5174 (5173 reserved for Vite dev)
|
|
717
|
+
const getPort = (start: number): Promise<number> =>
|
|
718
|
+
new Promise((resolve) => {
|
|
719
|
+
const srv = createNetServer();
|
|
720
|
+
srv.listen(start, "127.0.0.1", () => {
|
|
721
|
+
const { port } = srv.address() as { port: number };
|
|
722
|
+
srv.close(() => resolve(port));
|
|
723
|
+
});
|
|
724
|
+
srv.on("error", () => resolve(getPort(start + 1)));
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
const port = await getPort(5174);
|
|
728
|
+
|
|
729
|
+
// Seed the api-base-owner singleton with the initial value so the
|
|
730
|
+
// HTML-inject path and the RPC push path both read the same source of
|
|
731
|
+
// truth. Without this seeding, the static server would inject one value
|
|
732
|
+
// into HTML before the renderer mounts and the RPC bridge would push a
|
|
733
|
+
// different value moments later — the renderer racing two answers is
|
|
734
|
+
// what produced the port-shift disconnect documented in MASTER.md §0.
|
|
735
|
+
const initialRuntime = resolveDesktopRuntime();
|
|
736
|
+
// External mode (env-forced OR a cloud-hosted deployment target) seeds the
|
|
737
|
+
// resolved external base directly; local mode keeps the loopback agent port.
|
|
738
|
+
const initialApiBase =
|
|
739
|
+
initialRuntime.mode === "external" && initialRuntime.externalApi.base
|
|
740
|
+
? initialRuntime.externalApi.base
|
|
741
|
+
: resolveInitialApiBase(
|
|
742
|
+
process.env as Record<string, string | undefined>,
|
|
743
|
+
);
|
|
744
|
+
const initialApiToken =
|
|
745
|
+
initialRuntime.mode === "local"
|
|
746
|
+
? configureDesktopLocalApiAuth()
|
|
747
|
+
: (resolveApiToken(process.env) ?? "");
|
|
748
|
+
apiBaseOwner.setCurrent(initialApiBase, initialApiToken);
|
|
749
|
+
|
|
750
|
+
const resolveRendererCacheControl = (
|
|
751
|
+
pathname: string,
|
|
752
|
+
mimeExt: string,
|
|
753
|
+
): string => {
|
|
754
|
+
if (pathname.startsWith("/assets/")) {
|
|
755
|
+
return "public, max-age=31536000, immutable";
|
|
756
|
+
}
|
|
757
|
+
if (
|
|
758
|
+
mimeExt === ".vrm" ||
|
|
759
|
+
pathname.endsWith(".vrm.gz") ||
|
|
760
|
+
pathname.startsWith("/vrms/previews/") ||
|
|
761
|
+
pathname.startsWith("/vrms/backgrounds/") ||
|
|
762
|
+
[
|
|
763
|
+
".png",
|
|
764
|
+
".jpg",
|
|
765
|
+
".jpeg",
|
|
766
|
+
".gif",
|
|
767
|
+
".webp",
|
|
768
|
+
".avif",
|
|
769
|
+
".svg",
|
|
770
|
+
".mp3",
|
|
771
|
+
".wav",
|
|
772
|
+
".ogg",
|
|
773
|
+
".m4a",
|
|
774
|
+
".aac",
|
|
775
|
+
".flac",
|
|
776
|
+
".mp4",
|
|
777
|
+
".webm",
|
|
778
|
+
".glb",
|
|
779
|
+
".gltf",
|
|
780
|
+
".vrm",
|
|
781
|
+
".woff",
|
|
782
|
+
".woff2",
|
|
783
|
+
".ttf",
|
|
784
|
+
".otf",
|
|
785
|
+
].includes(mimeExt)
|
|
786
|
+
) {
|
|
787
|
+
return "public, max-age=86400";
|
|
788
|
+
}
|
|
789
|
+
return "public, max-age=0, must-revalidate";
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
const rendererProxyIdleTimeoutSeconds =
|
|
793
|
+
resolveRendererProxyIdleTimeoutSeconds(process.env);
|
|
794
|
+
|
|
795
|
+
Bun.serve({
|
|
796
|
+
port,
|
|
797
|
+
hostname: "127.0.0.1",
|
|
798
|
+
// The renderer fetches long-lived chat/SSE endpoints through this
|
|
799
|
+
// same-origin proxy. Bun's default 10s idle timeout cuts those streams
|
|
800
|
+
// while local inference is still pre-filling; keep it aligned with the
|
|
801
|
+
// API server's long request budget, capped to Bun.serve's accepted range.
|
|
802
|
+
idleTimeout: rendererProxyIdleTimeoutSeconds,
|
|
803
|
+
async fetch(req) {
|
|
804
|
+
const url = new URL(req.url);
|
|
805
|
+
const pathname = url.pathname;
|
|
806
|
+
|
|
807
|
+
// Proxy /api/*, /ws, /music-player to the agent port. Mirrors the Vite
|
|
808
|
+
// dev-server proxy in apps/app/vite.config.ts so the renderer can rely
|
|
809
|
+
// on same-origin /api fetches whether it's loaded via Vite (watch mode)
|
|
810
|
+
// or this static server (non-watch dev:desktop). Without this, every
|
|
811
|
+
// /api/* call returned SPA HTML and Settings sat on "Loading…" forever.
|
|
812
|
+
const apiBase = apiBaseOwner.getCurrent().base ?? initialApiBase;
|
|
813
|
+
if (apiBase && isRendererApiProxyPath(pathname)) {
|
|
814
|
+
const target = new URL(pathname + url.search, apiBase);
|
|
815
|
+
try {
|
|
816
|
+
const upstreamRequest = createRendererApiProxyRequestInit(
|
|
817
|
+
req,
|
|
818
|
+
target,
|
|
819
|
+
);
|
|
820
|
+
const upstream = await fetch(target, upstreamRequest);
|
|
821
|
+
return new Response(upstream.body, {
|
|
822
|
+
status: upstream.status,
|
|
823
|
+
statusText: upstream.statusText,
|
|
824
|
+
headers: upstream.headers,
|
|
825
|
+
});
|
|
826
|
+
} catch (err) {
|
|
827
|
+
return new Response(
|
|
828
|
+
JSON.stringify({
|
|
829
|
+
error: "API server unavailable",
|
|
830
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
831
|
+
}),
|
|
832
|
+
{
|
|
833
|
+
status: 502,
|
|
834
|
+
headers: { "Content-Type": "application/json" },
|
|
835
|
+
},
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
const { filePath, isGzipped, mimeExt } = resolveRendererAsset({
|
|
841
|
+
rendererDir,
|
|
842
|
+
urlPath: pathname,
|
|
843
|
+
existsSync: fs.existsSync,
|
|
844
|
+
statSync: fs.statSync,
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
try {
|
|
848
|
+
const content = fs.readFileSync(filePath);
|
|
849
|
+
// Inject API base into HTML responses
|
|
850
|
+
if (mimeExt === ".html" || filePath.endsWith("index.html")) {
|
|
851
|
+
const html = apiBaseOwner.injectIntoHtml(content.toString("utf8"));
|
|
852
|
+
return new Response(html, {
|
|
853
|
+
headers: {
|
|
854
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
855
|
+
"Access-Control-Allow-Origin": "*",
|
|
856
|
+
"Cache-Control": "public, max-age=0, must-revalidate",
|
|
857
|
+
},
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
const headers: Record<string, string> = {
|
|
862
|
+
"Content-Type": getRendererAssetContentType(mimeExt),
|
|
863
|
+
"Access-Control-Allow-Origin": "*",
|
|
864
|
+
"Cache-Control": resolveRendererCacheControl(pathname, mimeExt),
|
|
865
|
+
"Accept-Ranges": "bytes",
|
|
866
|
+
"Content-Length": String(content.byteLength),
|
|
867
|
+
};
|
|
868
|
+
|
|
869
|
+
if (isGzipped) {
|
|
870
|
+
headers["Content-Encoding"] = "gzip";
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
const byteRange = isGzipped
|
|
874
|
+
? null
|
|
875
|
+
: resolveRendererAssetByteRange(
|
|
876
|
+
req.headers.get("range"),
|
|
877
|
+
content.byteLength,
|
|
878
|
+
);
|
|
879
|
+
if (byteRange) {
|
|
880
|
+
const body = content.subarray(byteRange.start, byteRange.end + 1);
|
|
881
|
+
headers["Content-Length"] = String(body.byteLength);
|
|
882
|
+
headers["Content-Range"] =
|
|
883
|
+
`bytes ${byteRange.start}-${byteRange.end}/${content.byteLength}`;
|
|
884
|
+
return new Response(body, {
|
|
885
|
+
status: 206,
|
|
886
|
+
headers,
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
return new Response(content, { headers });
|
|
891
|
+
} catch {
|
|
892
|
+
return new Response("Not found", { status: 404 });
|
|
893
|
+
}
|
|
894
|
+
},
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
console.log(`[Renderer] Static server on http://127.0.0.1:${port}`);
|
|
898
|
+
return `http://127.0.0.1:${port}`;
|
|
828
899
|
}
|
|
829
900
|
|
|
830
901
|
async function resolveRendererUrl(): Promise<string> {
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
902
|
+
// Prefer ELIZA_RENDERER_URL / VITE_DEV_SERVER_URL when set (e.g. dev-platform.mjs watch mode).
|
|
903
|
+
// Why: Vite HMR only works against the dev server; serving pre-built dist from this static
|
|
904
|
+
// server would force a full rebuild for every UI change.
|
|
905
|
+
let rendererUrl =
|
|
906
|
+
process.env.ELIZA_RENDERER_URL ?? process.env.VITE_DEV_SERVER_URL ?? "";
|
|
907
|
+
|
|
908
|
+
if (!rendererUrl) {
|
|
909
|
+
rendererUrlPromise ??= startRendererServer();
|
|
910
|
+
rendererUrl = await rendererUrlPromise;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
if (!rendererUrl) {
|
|
914
|
+
// Last resort: file:// (may have CORS issues with crossorigin module scripts)
|
|
915
|
+
rendererUrl = `file://${path.join(resolveRendererAssetDir(import.meta.dir), "index.html")}`;
|
|
916
|
+
logger.warn(
|
|
917
|
+
"[Main] Falling back to file:// renderer URL — CORS issues possible",
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
return rendererUrl;
|
|
851
922
|
}
|
|
852
923
|
|
|
853
924
|
async function createMainWindow(rpc: ElizaDesktopRpc): Promise<BrowserWindow> {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
925
|
+
const kiosk = isKioskShellMode();
|
|
926
|
+
const rendererUrl = kiosk
|
|
927
|
+
? appendKioskShellModeParam(await resolveRendererUrl())
|
|
928
|
+
: await resolveRendererUrl();
|
|
929
|
+
const buildInfo = await BuildConfig.get();
|
|
930
|
+
const mainWindowPartition = resolveMainWindowPartition(process.env, {
|
|
931
|
+
platform: process.platform,
|
|
932
|
+
buildInfo,
|
|
933
|
+
});
|
|
934
|
+
if (mainWindowPartition) {
|
|
935
|
+
logger.info(`[Main] Using main window partition ${mainWindowPartition}`);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
const statePath = path.join(Utils.paths.userData, "window-state.json");
|
|
939
|
+
const state = loadWindowState(statePath);
|
|
940
|
+
|
|
941
|
+
let preload: string;
|
|
942
|
+
try {
|
|
943
|
+
preload = readResolvedPreloadScript(import.meta.dir);
|
|
944
|
+
} catch (err) {
|
|
945
|
+
// A missing/stale/empty preload means the main window has no API bridge —
|
|
946
|
+
// the renderer boots into a white screen. In packaged builds that is a
|
|
947
|
+
// fatal misbuild, so surface it (the error already names `build:preload`)
|
|
948
|
+
// instead of silently shipping a broken window. Keep the soft fallback in
|
|
949
|
+
// the dev runtime so an unbuilt preload doesn't block iterating on the UI.
|
|
950
|
+
if (isPackagedDesktopBuild()) {
|
|
951
|
+
throw err;
|
|
952
|
+
}
|
|
953
|
+
logger.error(
|
|
954
|
+
`[Main] Failed to read preload script (dev fallback): ${err instanceof Error ? err.message : String(err)}`,
|
|
955
|
+
);
|
|
956
|
+
preload = "// preload unavailable";
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const windowFrame = {
|
|
960
|
+
width: state.width,
|
|
961
|
+
height: state.height,
|
|
962
|
+
x: state.x,
|
|
963
|
+
y: state.y,
|
|
964
|
+
};
|
|
965
|
+
const titleBarStyle = kiosk
|
|
966
|
+
? "hidden"
|
|
967
|
+
: process.platform === "darwin"
|
|
968
|
+
? "hiddenInset"
|
|
969
|
+
: "default";
|
|
970
|
+
const transparent = !kiosk && process.platform === "darwin";
|
|
971
|
+
const forceMainWindowCef = shouldForceMainWindowCef(
|
|
972
|
+
process.env,
|
|
973
|
+
process.platform,
|
|
974
|
+
);
|
|
975
|
+
const canUseCefView = buildInfo.availableRenderers.includes("cef");
|
|
976
|
+
const useIsolatedMainView = shouldUseIsolatedMainView({
|
|
977
|
+
platform: process.platform,
|
|
978
|
+
mainWindowPartition,
|
|
979
|
+
forceMainWindowCef,
|
|
980
|
+
buildInfo,
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
if (forceMainWindowCef && !canUseCefView) {
|
|
984
|
+
logger.warn(
|
|
985
|
+
"[Main] ELIZA_DESKTOP_FORCE_CEF=1 requested, but this Electrobun build does not bundle the CEF renderer. Falling back to the native renderer.",
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
let win: BrowserWindow;
|
|
990
|
+
if (useIsolatedMainView) {
|
|
991
|
+
// Shell window with the empty default webview. The actual content
|
|
992
|
+
// (and therefore the RPC channel) is hosted on the separate mainView
|
|
993
|
+
// BrowserView constructed below — that's what we attach `rpc` to.
|
|
994
|
+
win = createElectrobunBrowserWindow({
|
|
995
|
+
title: BRAND.appName,
|
|
996
|
+
icon: resolveDesktopAppIconPath(),
|
|
997
|
+
url: null,
|
|
998
|
+
preload: null,
|
|
999
|
+
frame: windowFrame,
|
|
1000
|
+
renderer: resolveBootstrapShellRenderer(buildInfo),
|
|
1001
|
+
titleBarStyle,
|
|
1002
|
+
transparent,
|
|
1003
|
+
});
|
|
1004
|
+
win.webview.remove();
|
|
1005
|
+
const mainView = new BrowserView({
|
|
1006
|
+
url: rendererUrl,
|
|
1007
|
+
preload,
|
|
1008
|
+
renderer: forceMainWindowCef
|
|
1009
|
+
? "cef"
|
|
1010
|
+
: resolveBootstrapViewRenderer(buildInfo),
|
|
1011
|
+
partition: mainWindowPartition,
|
|
1012
|
+
frame: {
|
|
1013
|
+
x: 0,
|
|
1014
|
+
y: 0,
|
|
1015
|
+
width: state.width,
|
|
1016
|
+
height: state.height,
|
|
1017
|
+
},
|
|
1018
|
+
windowId: win.id,
|
|
1019
|
+
rpc,
|
|
1020
|
+
});
|
|
1021
|
+
win.webviewId = mainView.id;
|
|
1022
|
+
if (forceMainWindowCef) {
|
|
1023
|
+
logger.info(
|
|
1024
|
+
`[Main] Using CEF main-window workaround with persistent partition ${mainWindowPartition}`,
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
} else {
|
|
1028
|
+
win = createElectrobunBrowserWindow({
|
|
1029
|
+
title: BRAND.appName,
|
|
1030
|
+
icon: resolveDesktopAppIconPath(),
|
|
1031
|
+
url: rendererUrl,
|
|
1032
|
+
preload,
|
|
1033
|
+
frame: windowFrame,
|
|
1034
|
+
titleBarStyle,
|
|
1035
|
+
transparent,
|
|
1036
|
+
rpc,
|
|
1037
|
+
...(mainWindowPartition ? { partition: mainWindowPartition } : {}),
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// Kiosk mode: the app IS the GUI. Go fullscreen and skip the bounds
|
|
1042
|
+
// persistence + maximize ergonomics — the window is fixed fullscreen and
|
|
1043
|
+
// must never restore to a smaller frame.
|
|
1044
|
+
if (kiosk) {
|
|
1045
|
+
try {
|
|
1046
|
+
win.setFullScreen(true);
|
|
1047
|
+
} catch (err) {
|
|
1048
|
+
logger.warn(
|
|
1049
|
+
`[main-window] kiosk setFullScreen() failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
return win;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
applyMacOSWindowEffects(win);
|
|
1056
|
+
win.on("resize", () => scheduleStateSave(statePath, win));
|
|
1057
|
+
win.on("move", () => scheduleStateSave(statePath, win));
|
|
1058
|
+
|
|
1059
|
+
// First-launch ergonomics: when there's no saved state (or the
|
|
1060
|
+
// saved state was garbage and we're falling back to defaults), open
|
|
1061
|
+
// the window maximized so the user gets a full workspace instead of
|
|
1062
|
+
// a 1440x900 rectangle in the corner they have to resize by hand.
|
|
1063
|
+
// Subsequent launches skip this because loadWindowState returns the
|
|
1064
|
+
// real persisted dimensions without the shouldMaximize sentinel.
|
|
1065
|
+
if (state.shouldMaximize === MAXIMIZE_ON_LAUNCH_SENTINEL) {
|
|
1066
|
+
try {
|
|
1067
|
+
(win as typeof win & { maximize?: () => void }).maximize?.();
|
|
1068
|
+
} catch (err) {
|
|
1069
|
+
// Non-fatal — if maximize() isn't available on this electrobun
|
|
1070
|
+
// build, the window still opens at the default dimensions.
|
|
1071
|
+
logger.warn(
|
|
1072
|
+
`[main-window] maximize() failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
return win;
|
|
973
1078
|
}
|
|
974
1079
|
|
|
975
1080
|
function attachMainWindow(
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1081
|
+
win: BrowserWindow,
|
|
1082
|
+
rpc: ElizaDesktopRpc,
|
|
1083
|
+
sendToWebview: SendToWebview,
|
|
979
1084
|
): BrowserWindow {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1085
|
+
wireMainWindowAfterCreate(win, rpc, sendToWebview);
|
|
1086
|
+
currentWindow = win;
|
|
1087
|
+
currentSendToWebview = sendToWebview;
|
|
1088
|
+
setCurrentMainWindow(win, {
|
|
1089
|
+
titleBarStyle: process.platform === "darwin" ? "hiddenInset" : "default",
|
|
1090
|
+
transparent: process.platform === "darwin",
|
|
1091
|
+
});
|
|
1092
|
+
trackFocusedWindow(win);
|
|
1093
|
+
// Reveal the Dock icon in tray-first mode whenever a main window is attached,
|
|
1094
|
+
// regardless of how it was opened (boot, tray "Show Window", Dock reopen, or
|
|
1095
|
+
// a direct restoreWindow() from a deep link that bypasses showWindow()).
|
|
1096
|
+
getDesktopManager().markMainWindowShown();
|
|
1097
|
+
|
|
1098
|
+
win.webview.on("dom-ready", () => {
|
|
1099
|
+
injectApiBase(win);
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
// Prevent the main webview from navigating to external URLs.
|
|
1103
|
+
// The renderer is always served from localhost — any other navigation
|
|
1104
|
+
// (e.g. from a compromised plugin) should open in the default browser.
|
|
1105
|
+
win.webview.on("will-navigate", (event: unknown) => {
|
|
1106
|
+
const e = event as {
|
|
1107
|
+
url?: string;
|
|
1108
|
+
data?: { detail?: string };
|
|
1109
|
+
preventDefault?: () => void;
|
|
1110
|
+
};
|
|
1111
|
+
const url = readNavigationEventUrl(e);
|
|
1112
|
+
try {
|
|
1113
|
+
const parsed = new URL(url);
|
|
1114
|
+
const isAllowed =
|
|
1115
|
+
parsed.protocol === "file:" ||
|
|
1116
|
+
parsed.hostname === "localhost" ||
|
|
1117
|
+
parsed.hostname === "127.0.0.1" ||
|
|
1118
|
+
parsed.protocol === "views:";
|
|
1119
|
+
if (!isAllowed) {
|
|
1120
|
+
e.preventDefault?.();
|
|
1121
|
+
void import("electrobun/bun")
|
|
1122
|
+
.then(({ Utils }) => {
|
|
1123
|
+
try {
|
|
1124
|
+
Utils.openExternal(url);
|
|
1125
|
+
} catch {
|
|
1126
|
+
// Ignore external open failures during navigation blocking.
|
|
1127
|
+
}
|
|
1128
|
+
})
|
|
1129
|
+
.catch(() => {});
|
|
1130
|
+
}
|
|
1131
|
+
} catch {
|
|
1132
|
+
// Unparseable URL — block it.
|
|
1133
|
+
e.preventDefault?.();
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
win.on("close", (event: unknown) => {
|
|
1138
|
+
// Kiosk mode: the app is the entire GUI under a single-window compositor.
|
|
1139
|
+
// The window must never close — block every close request and keep it up.
|
|
1140
|
+
if (isKioskShellMode() && !isQuitting) {
|
|
1141
|
+
const closeEvent = event as { preventDefault?: () => void } | undefined;
|
|
1142
|
+
closeEvent?.preventDefault?.();
|
|
1143
|
+
logger.info("[Main] Kiosk window close blocked — staying fullscreen");
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// On Linux with no tray configured, minimizing-to-tray (or running in the
|
|
1148
|
+
// background) strands an invisible process: there is no dock reopen like
|
|
1149
|
+
// macOS and no StatusNotifier item to restore from. Quit cleanly in that
|
|
1150
|
+
// case so closing the last window can't leave the agent unreachable. The
|
|
1151
|
+
// tray decision is read from the environment up front — not from a flag set
|
|
1152
|
+
// after createTray() resolves — so closing during startup, before the tray
|
|
1153
|
+
// icon appears, doesn't spuriously quit. macOS/Windows and the
|
|
1154
|
+
// Linux-with-tray path keep their existing behavior.
|
|
1155
|
+
if (
|
|
1156
|
+
!isQuitting &&
|
|
1157
|
+
process.platform === "linux" &&
|
|
1158
|
+
!shouldCreateDesktopTray(process.env)
|
|
1159
|
+
) {
|
|
1160
|
+
logger.info(
|
|
1161
|
+
"[Main] Window close on Linux with no tray — quitting (no surface to restore from)",
|
|
1162
|
+
);
|
|
1163
|
+
requestAppQuit();
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
if (!isQuitting && process.env.ELIZAOS_CLOSE_MINIMIZES_TO_TRAY !== "0") {
|
|
1168
|
+
const closeEvent = event as { preventDefault?: () => void } | undefined;
|
|
1169
|
+
if (typeof closeEvent?.preventDefault === "function") {
|
|
1170
|
+
closeEvent.preventDefault();
|
|
1171
|
+
void getDesktopManager()
|
|
1172
|
+
.hideWindow()
|
|
1173
|
+
.catch((err: unknown) => {
|
|
1174
|
+
logger.warn(
|
|
1175
|
+
`[Main] Failed to minimize window on close: ${err instanceof Error ? err.message : String(err)}`,
|
|
1176
|
+
);
|
|
1177
|
+
});
|
|
1178
|
+
logger.info("[Main] Window close requested - minimized to tray");
|
|
1179
|
+
showBackgroundRunNoticeOnce();
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
logger.info(
|
|
1183
|
+
"[Main] Window close requested - agent continues in background",
|
|
1184
|
+
);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
if (currentWindow?.id === win.id) {
|
|
1188
|
+
currentWindow = null;
|
|
1189
|
+
currentSendToWebview = null;
|
|
1190
|
+
}
|
|
1191
|
+
clearCurrentMainWindow(win);
|
|
1192
|
+
getDesktopManager().clearMainWindow(win);
|
|
1193
|
+
|
|
1194
|
+
if (!isQuitting) {
|
|
1195
|
+
void ensureBackgroundWindow();
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
1198
|
+
|
|
1199
|
+
return win;
|
|
1042
1200
|
}
|
|
1043
1201
|
|
|
1044
1202
|
async function ensureBackgroundWindow(): Promise<void> {
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1203
|
+
if (isQuitting || currentWindow) {
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// Don't recreate the window — just keep the process alive in the
|
|
1208
|
+
// background (exitOnLastWindowClosed is false in electrobun.config.ts).
|
|
1209
|
+
// The dock icon click fires the "reopen" event which restores the window.
|
|
1210
|
+
logger.info("[Main] Window closed — agent continues in background");
|
|
1211
|
+
showBackgroundRunNoticeOnce();
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Create — or focus, if already open — the transparent onboarding overlay
|
|
1216
|
+
* window and wire its API base. Shared by the first-run boot branch and the
|
|
1217
|
+
* dock-reopen path so the overlay (not the dashboard) is always the surface
|
|
1218
|
+
* shown while onboarding is the active first-run mode.
|
|
1219
|
+
*/
|
|
1220
|
+
async function openOnboardingOverlayWindow(): Promise<BrowserWindow> {
|
|
1221
|
+
const existing = getOnboardingOverlayWindow();
|
|
1222
|
+
if (existing) {
|
|
1223
|
+
try {
|
|
1224
|
+
existing.focus();
|
|
1225
|
+
} catch {
|
|
1226
|
+
// focus may be unavailable on this platform
|
|
1227
|
+
}
|
|
1228
|
+
return existing;
|
|
1229
|
+
}
|
|
1230
|
+
const { rpc } = createDesktopRpc("onboarding-overlay");
|
|
1231
|
+
const rendererUrl = await resolveRendererUrl();
|
|
1232
|
+
let preload = "";
|
|
1233
|
+
try {
|
|
1234
|
+
preload = readResolvedPreloadScript(import.meta.dir);
|
|
1235
|
+
} catch {
|
|
1236
|
+
// Dev fallback — an unbuilt preload should not block the overlay.
|
|
1237
|
+
}
|
|
1238
|
+
const win = createOnboardingOverlayWindow({ rendererUrl, preload, rpc });
|
|
1239
|
+
win.webview.on("dom-ready", () => {
|
|
1240
|
+
injectApiBase(win);
|
|
1241
|
+
});
|
|
1242
|
+
|
|
1243
|
+
// When the overlay closes (renderer calls window.close() after the first-run
|
|
1244
|
+
// API completes), transition to the main dashboard window. Without this the
|
|
1245
|
+
// overlay disappears but no dashboard appears.
|
|
1246
|
+
win.on("close", () => {
|
|
1247
|
+
logger.info(
|
|
1248
|
+
"[Main] Onboarding overlay closed — creating main dashboard window",
|
|
1249
|
+
);
|
|
1250
|
+
void (async () => {
|
|
1251
|
+
try {
|
|
1252
|
+
const { rpc: mainRpc, sendToWebview: mainSendToWebview } =
|
|
1253
|
+
createDesktopRpc("main");
|
|
1254
|
+
attachMainWindow(
|
|
1255
|
+
await createMainWindow(mainRpc),
|
|
1256
|
+
mainRpc,
|
|
1257
|
+
mainSendToWebview,
|
|
1258
|
+
);
|
|
1259
|
+
} catch (err) {
|
|
1260
|
+
logger.error(
|
|
1261
|
+
`[Main] Failed to create dashboard after overlay close: ${err instanceof Error ? err.message : String(err)}`,
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
})();
|
|
1265
|
+
});
|
|
1266
|
+
|
|
1267
|
+
return win;
|
|
1054
1268
|
}
|
|
1055
1269
|
|
|
1056
1270
|
/** Restore or recreate the main window (called on dock icon click). */
|
|
1057
1271
|
async function restoreWindow(): Promise<void> {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1272
|
+
if (currentWindow) {
|
|
1273
|
+
try {
|
|
1274
|
+
currentWindow.unminimize();
|
|
1275
|
+
currentWindow.focus();
|
|
1276
|
+
} catch {
|
|
1277
|
+
// unminimize/focus may not be available
|
|
1278
|
+
}
|
|
1279
|
+
// Re-reveal the Dock icon for an already-open window (tray-first only).
|
|
1280
|
+
getDesktopManager().markMainWindowShown();
|
|
1281
|
+
return;
|
|
1282
|
+
}
|
|
1283
|
+
// Onboarding-overlay mode: the correct first-run surface is the transparent
|
|
1284
|
+
// overlay card, NOT the opaque dashboard. Re-show (or recreate) the overlay
|
|
1285
|
+
// instead of building a main window. Once onboarding completes and a
|
|
1286
|
+
// dashboard is attached, `currentWindow` is set and the branch above wins.
|
|
1287
|
+
if (shouldStartOnboardingOverlay()) {
|
|
1288
|
+
await openOnboardingOverlayWindow();
|
|
1289
|
+
logger.info("[Main] Reopened onboarding overlay (dock reopen)");
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (backgroundWindowPromise) {
|
|
1293
|
+
await backgroundWindowPromise;
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
backgroundWindowPromise = (async () => {
|
|
1297
|
+
const { rpc, sendToWebview } = createDesktopRpc("main");
|
|
1298
|
+
const win = attachMainWindow(
|
|
1299
|
+
await createMainWindow(rpc),
|
|
1300
|
+
rpc,
|
|
1301
|
+
sendToWebview,
|
|
1302
|
+
);
|
|
1303
|
+
injectApiBase(win);
|
|
1304
|
+
logger.info("[Main] Restored window from dock click");
|
|
1305
|
+
})().finally(() => {
|
|
1306
|
+
backgroundWindowPromise = null;
|
|
1307
|
+
});
|
|
1308
|
+
await backgroundWindowPromise;
|
|
1084
1309
|
}
|
|
1085
1310
|
|
|
1086
1311
|
function showBackgroundRunNoticeOnce(): void {
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1312
|
+
try {
|
|
1313
|
+
showBackgroundNoticeOnce({
|
|
1314
|
+
fileSystem: fs,
|
|
1315
|
+
userDataDir: Utils.paths.userData,
|
|
1316
|
+
showNotification: (options) => {
|
|
1317
|
+
Utils.showNotification(options);
|
|
1318
|
+
},
|
|
1319
|
+
});
|
|
1320
|
+
} catch (error) {
|
|
1321
|
+
logger.warn(
|
|
1322
|
+
`[Main] Failed to persist background notice marker: ${error instanceof Error ? error.message : String(error)}`,
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1100
1325
|
}
|
|
1101
1326
|
|
|
1102
1327
|
async function createSettingsWindow(tabHint?: string): Promise<void> {
|
|
1103
|
-
|
|
1104
|
-
|
|
1328
|
+
if (!surfaceWindowManager) return;
|
|
1329
|
+
await surfaceWindowManager.openSettingsWindow(tabHint);
|
|
1105
1330
|
}
|
|
1106
1331
|
|
|
1107
1332
|
async function showMainSurface(surface: string): Promise<void> {
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1333
|
+
if (!currentWindow) {
|
|
1334
|
+
await restoreWindow();
|
|
1335
|
+
}
|
|
1336
|
+
void getDesktopManager().showWindow();
|
|
1337
|
+
sendToActiveRenderer("desktopTrayMenuClick", {
|
|
1338
|
+
itemId: `show-main:${surface}`,
|
|
1339
|
+
});
|
|
1115
1340
|
}
|
|
1116
1341
|
|
|
1117
1342
|
function resolveDefaultDialogPath(): string {
|
|
1118
|
-
|
|
1119
|
-
|
|
1343
|
+
const downloadsPath = path.join(os.homedir(), "Downloads");
|
|
1344
|
+
return fs.existsSync(downloadsPath) ? downloadsPath : os.homedir();
|
|
1120
1345
|
}
|
|
1121
1346
|
|
|
1122
1347
|
async function exportConfigFromMenu(): Promise<void> {
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1348
|
+
const apiBase = resolveLoopbackApiBase();
|
|
1349
|
+
if (!apiBase) {
|
|
1350
|
+
Utils.showNotification({
|
|
1351
|
+
title: "Config Export Failed",
|
|
1352
|
+
body: "Agent unavailable",
|
|
1353
|
+
});
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
try {
|
|
1358
|
+
const response = await fetch(`${apiBase}/api/config`, {
|
|
1359
|
+
headers: buildApiRequestHeaders(),
|
|
1360
|
+
});
|
|
1361
|
+
if (!response.ok) {
|
|
1362
|
+
throw new Error(`Config fetch failed (${response.status})`);
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
const config = await response.json();
|
|
1366
|
+
const dialog = await getDesktopManager().showSaveDialog({
|
|
1367
|
+
defaultPath: resolveDefaultDialogPath(),
|
|
1368
|
+
allowedFileTypes: "json",
|
|
1369
|
+
});
|
|
1370
|
+
if (dialog.canceled || dialog.filePaths.length === 0) {
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
const outputPath = path.join(dialog.filePaths[0], CONFIG_EXPORT_FILE_NAME);
|
|
1375
|
+
fs.writeFileSync(
|
|
1376
|
+
outputPath,
|
|
1377
|
+
`${JSON.stringify(config, null, 2)}\n`,
|
|
1378
|
+
"utf8",
|
|
1379
|
+
);
|
|
1380
|
+
|
|
1381
|
+
Utils.showNotification({
|
|
1382
|
+
title: "Config Exported",
|
|
1383
|
+
body: `Saved to ${outputPath}`,
|
|
1384
|
+
});
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
Utils.showNotification({
|
|
1387
|
+
title: "Config Export Failed",
|
|
1388
|
+
body: summarizeDesktopActionError(error, "Config export failed"),
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1166
1391
|
}
|
|
1167
1392
|
|
|
1168
1393
|
async function importConfigFromMenu(): Promise<void> {
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1394
|
+
const apiBase = resolveLoopbackApiBase();
|
|
1395
|
+
if (!apiBase) {
|
|
1396
|
+
Utils.showNotification({
|
|
1397
|
+
title: "Config Import Failed",
|
|
1398
|
+
body: "Agent unavailable",
|
|
1399
|
+
});
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
try {
|
|
1404
|
+
const dialog = await getDesktopManager().showOpenDialog({
|
|
1405
|
+
defaultPath: resolveDefaultDialogPath(),
|
|
1406
|
+
allowedFileTypes: "json",
|
|
1407
|
+
canChooseFiles: true,
|
|
1408
|
+
canChooseDirectory: false,
|
|
1409
|
+
allowsMultipleSelection: false,
|
|
1410
|
+
});
|
|
1411
|
+
if (dialog.canceled || dialog.filePaths.length === 0) {
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
const inputPath = dialog.filePaths[0];
|
|
1416
|
+
const rawConfig = fs.readFileSync(inputPath, "utf8");
|
|
1417
|
+
const parsedConfig = JSON.parse(rawConfig) as unknown;
|
|
1418
|
+
if (
|
|
1419
|
+
typeof parsedConfig !== "object" ||
|
|
1420
|
+
parsedConfig === null ||
|
|
1421
|
+
Array.isArray(parsedConfig)
|
|
1422
|
+
) {
|
|
1423
|
+
throw new Error("Config file must contain a JSON object");
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
const response = await fetch(`${apiBase}/api/config`, {
|
|
1427
|
+
method: "PUT",
|
|
1428
|
+
headers: buildApiRequestHeaders("application/json"),
|
|
1429
|
+
body: JSON.stringify(parsedConfig),
|
|
1430
|
+
});
|
|
1431
|
+
if (!response.ok) {
|
|
1432
|
+
throw new Error(`Config import failed (${response.status})`);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
Utils.showNotification({
|
|
1436
|
+
title: "Config Imported",
|
|
1437
|
+
body: `Loaded ${path.basename(inputPath)}`,
|
|
1438
|
+
});
|
|
1439
|
+
} catch (error) {
|
|
1440
|
+
Utils.showNotification({
|
|
1441
|
+
title: "Config Import Failed",
|
|
1442
|
+
body: summarizeDesktopActionError(error, "Config import failed"),
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1220
1445
|
}
|
|
1221
1446
|
|
|
1222
1447
|
function trackFocusedWindow(window: ManagedWindowLike): void {
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1448
|
+
lastFocusedWindow = window;
|
|
1449
|
+
window.on("focus", () => {
|
|
1450
|
+
lastFocusedWindow = window;
|
|
1451
|
+
const windowId = (window as { id?: number }).id;
|
|
1452
|
+
if (
|
|
1453
|
+
process.platform === "darwin" &&
|
|
1454
|
+
typeof windowId === "number" &&
|
|
1455
|
+
macOpenedDevtoolsWindowIds.has(windowId)
|
|
1456
|
+
) {
|
|
1457
|
+
scheduleDevtoolsLayoutRefresh(
|
|
1458
|
+
window as Parameters<typeof scheduleDevtoolsLayoutRefresh>[0],
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
});
|
|
1462
|
+
window.on("close", () => {
|
|
1463
|
+
const windowId = (window as { id?: number }).id;
|
|
1464
|
+
if (typeof windowId === "number") {
|
|
1465
|
+
macOpenedDevtoolsWindowIds.delete(windowId);
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1243
1468
|
}
|
|
1244
1469
|
|
|
1245
1470
|
function toggleFocusedWindowDevTools(): void {
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1471
|
+
const targetWindow = lastFocusedWindow ?? currentWindow;
|
|
1472
|
+
const webview = targetWindow?.webview as
|
|
1473
|
+
| {
|
|
1474
|
+
toggleDevTools?: () => void;
|
|
1475
|
+
openDevTools?: () => void;
|
|
1476
|
+
}
|
|
1477
|
+
| undefined;
|
|
1478
|
+
|
|
1479
|
+
if (shouldUseBrowserDevtoolsFallback()) {
|
|
1480
|
+
void openBrowserDevtoolsFallback(targetWindow);
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
if (typeof webview?.toggleDevTools === "function") {
|
|
1485
|
+
webview.toggleDevTools();
|
|
1486
|
+
scheduleDevtoolsLayoutRefresh(
|
|
1487
|
+
targetWindow as Parameters<typeof scheduleDevtoolsLayoutRefresh>[0],
|
|
1488
|
+
);
|
|
1489
|
+
return;
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
if (typeof webview?.openDevTools === "function") {
|
|
1493
|
+
webview.openDevTools();
|
|
1494
|
+
scheduleDevtoolsLayoutRefresh(
|
|
1495
|
+
targetWindow as Parameters<typeof scheduleDevtoolsLayoutRefresh>[0],
|
|
1496
|
+
);
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
Utils.showNotification({
|
|
1501
|
+
title: "Developer Tools Unavailable",
|
|
1502
|
+
body: "The focused window does not expose Electrobun devtools controls.",
|
|
1503
|
+
});
|
|
1279
1504
|
}
|
|
1280
1505
|
|
|
1281
1506
|
/**
|
|
@@ -1284,7 +1509,7 @@ function toggleFocusedWindowDevTools(): void {
|
|
|
1284
1509
|
* and `send` proxies.
|
|
1285
1510
|
*/
|
|
1286
1511
|
type ElizaDesktopRpc = ReturnType<
|
|
1287
|
-
|
|
1512
|
+
typeof BrowserView.defineRPC<ElizaDesktopRPCSchema>
|
|
1288
1513
|
>;
|
|
1289
1514
|
|
|
1290
1515
|
/**
|
|
@@ -1315,49 +1540,51 @@ const MAX_RPC_REQUEST_TIME_MS = 600_000;
|
|
|
1315
1540
|
* main / settings / surface windows are distinguishable.
|
|
1316
1541
|
*/
|
|
1317
1542
|
function createDesktopRpc(label: string): {
|
|
1318
|
-
|
|
1319
|
-
|
|
1543
|
+
rpc: ElizaDesktopRpc;
|
|
1544
|
+
sendToWebview: SendToWebview;
|
|
1320
1545
|
} {
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1546
|
+
let rpc: ElizaDesktopRpc | undefined;
|
|
1547
|
+
|
|
1548
|
+
const sendToWebview: SendToWebview = (message, payload) => {
|
|
1549
|
+
if (!rpc) {
|
|
1550
|
+
logger.warn(
|
|
1551
|
+
`[sendToWebview:${label}] RPC not yet initialised; dropping message: ${message}`,
|
|
1552
|
+
);
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
try {
|
|
1556
|
+
// `rpc.send` is a Proxy<sendFn> from defineElectrobunRPC: both
|
|
1557
|
+
// `rpc.send(message, payload)` and `rpc.send.<message>(payload)`
|
|
1558
|
+
// dispatch through the same underlying sendFn. Cast to a plain
|
|
1559
|
+
// function signature to call it dynamically by name without the
|
|
1560
|
+
// schema-typed overloads narrowing the message string.
|
|
1561
|
+
(rpc.send as unknown as (m: string, p?: unknown) => void)(
|
|
1562
|
+
message,
|
|
1563
|
+
payload ?? null,
|
|
1564
|
+
);
|
|
1565
|
+
} catch (err) {
|
|
1566
|
+
logger.warn(
|
|
1567
|
+
`[sendToWebview:${label}] send(${message}) failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1571
|
+
|
|
1572
|
+
type BunRpcRequestsHandlers = NonNullable<
|
|
1573
|
+
Parameters<
|
|
1574
|
+
typeof BrowserView.defineRPC<ElizaDesktopRPCSchema>
|
|
1575
|
+
>[0]["handlers"]
|
|
1576
|
+
>["requests"];
|
|
1577
|
+
|
|
1578
|
+
rpc = BrowserView.defineRPC<ElizaDesktopRPCSchema>({
|
|
1579
|
+
maxRequestTime: MAX_RPC_REQUEST_TIME_MS,
|
|
1580
|
+
handlers: {
|
|
1581
|
+
requests: buildBunRpcHandlers({
|
|
1582
|
+
sendToWebview,
|
|
1583
|
+
}) as BunRpcRequestsHandlers,
|
|
1584
|
+
},
|
|
1585
|
+
});
|
|
1586
|
+
|
|
1587
|
+
return { rpc, sendToWebview };
|
|
1361
1588
|
}
|
|
1362
1589
|
|
|
1363
1590
|
/**
|
|
@@ -1375,15 +1602,15 @@ function createDesktopRpc(label: string): {
|
|
|
1375
1602
|
* - steward sidecar's send-to-webview is wired
|
|
1376
1603
|
*/
|
|
1377
1604
|
function wireMainWindowAfterCreate(
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1605
|
+
win: BrowserWindow,
|
|
1606
|
+
rpc: ElizaDesktopRpc,
|
|
1607
|
+
sendToWebview: SendToWebview,
|
|
1381
1608
|
): void {
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1609
|
+
initializeNativeModules(win, sendToWebview);
|
|
1610
|
+
setStewardSendToWebview(sendToWebview);
|
|
1611
|
+
wireBrowserWorkspaceCaller({
|
|
1612
|
+
request: rpc.request as unknown as RpcRequestProxy,
|
|
1613
|
+
});
|
|
1387
1614
|
}
|
|
1388
1615
|
|
|
1389
1616
|
/**
|
|
@@ -1396,47 +1623,80 @@ function wireMainWindowAfterCreate(
|
|
|
1396
1623
|
* settings windows don't need most of the wiring.
|
|
1397
1624
|
*/
|
|
1398
1625
|
function wireSettingsRpcAfterCreate(rpc: ElizaDesktopRpc): void {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1626
|
+
wireBrowserWorkspaceCaller({
|
|
1627
|
+
request: rpc.request as unknown as RpcRequestProxy,
|
|
1628
|
+
});
|
|
1402
1629
|
}
|
|
1403
1630
|
|
|
1404
1631
|
function injectApiBase(win: BrowserWindow): void {
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1632
|
+
const runtimeResolution = resolveDesktopRuntime();
|
|
1633
|
+
|
|
1634
|
+
if (runtimeResolution.externalApi.invalidSources.length > 0) {
|
|
1635
|
+
logger.warn(
|
|
1636
|
+
`[Main] Invalid API base env vars: ${runtimeResolution.externalApi.invalidSources.join(", ")}`,
|
|
1637
|
+
);
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
if (
|
|
1641
|
+
runtimeResolution.mode === "external" &&
|
|
1642
|
+
runtimeResolution.externalApi.base
|
|
1643
|
+
) {
|
|
1644
|
+
apiBaseOwner.notifyChange(
|
|
1645
|
+
win,
|
|
1646
|
+
runtimeResolution.externalApi.base,
|
|
1647
|
+
resolveApiToken(process.env) ?? "",
|
|
1648
|
+
);
|
|
1649
|
+
setAgentReady(true);
|
|
1650
|
+
return;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
const agent = getAgentManager();
|
|
1654
|
+
const port = agent.getPort() ?? resolveDesktopApiPort(process.env);
|
|
1655
|
+
const apiToken = configureDesktopLocalApiAuth();
|
|
1656
|
+
apiBaseOwner.notifyChange(
|
|
1657
|
+
win,
|
|
1658
|
+
resolveRendererFacingApiBase(
|
|
1659
|
+
process.env as Record<string, string | undefined>,
|
|
1660
|
+
port,
|
|
1661
|
+
),
|
|
1662
|
+
apiToken,
|
|
1663
|
+
);
|
|
1664
|
+
setAgentReady(true);
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
function injectApiBaseIntoOpenRendererWindows(): void {
|
|
1668
|
+
if (currentWindow) {
|
|
1669
|
+
injectApiBase(currentWindow);
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
const pillWindow = getPillWindow();
|
|
1673
|
+
if (pillWindow && pillWindow !== currentWindow) {
|
|
1674
|
+
injectApiBase(pillWindow);
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
surfaceWindowManager?.forEachWindow((w) => {
|
|
1678
|
+
injectApiBase(w as BrowserWindow);
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
/**
|
|
1683
|
+
* Snapshot of every currently-open renderer window the agent API base should
|
|
1684
|
+
* be pushed to. Mirrors the window set in injectApiBaseIntoOpenRendererWindows.
|
|
1685
|
+
* Returns an empty array when no window exists yet (headless boot).
|
|
1686
|
+
*/
|
|
1687
|
+
function collectOpenRendererWindows(): BrowserWindow[] {
|
|
1688
|
+
const windows: BrowserWindow[] = [];
|
|
1689
|
+
if (currentWindow) {
|
|
1690
|
+
windows.push(currentWindow);
|
|
1691
|
+
}
|
|
1692
|
+
const pillWindow = getPillWindow();
|
|
1693
|
+
if (pillWindow && pillWindow !== currentWindow) {
|
|
1694
|
+
windows.push(pillWindow);
|
|
1695
|
+
}
|
|
1696
|
+
surfaceWindowManager?.forEachWindow((w) => {
|
|
1697
|
+
windows.push(w as BrowserWindow);
|
|
1698
|
+
});
|
|
1699
|
+
return windows;
|
|
1440
1700
|
}
|
|
1441
1701
|
|
|
1442
1702
|
/**
|
|
@@ -1444,332 +1704,394 @@ function injectApiBase(win: BrowserWindow): void {
|
|
|
1444
1704
|
* PermissionsSection shows correct statuses and capability toggles unlock.
|
|
1445
1705
|
*/
|
|
1446
1706
|
async function syncPermissionsToRestApi(
|
|
1447
|
-
|
|
1448
|
-
|
|
1707
|
+
port: number,
|
|
1708
|
+
startup = false,
|
|
1449
1709
|
): Promise<void> {
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1710
|
+
try {
|
|
1711
|
+
const permissions = await mergeRuntimePermissionStates(
|
|
1712
|
+
port,
|
|
1713
|
+
await getPermissionManager().checkAllPermissions(),
|
|
1714
|
+
);
|
|
1715
|
+
await fetch(`http://127.0.0.1:${port}/api/permissions/state`, {
|
|
1716
|
+
method: "PUT",
|
|
1717
|
+
headers: { "Content-Type": "application/json" },
|
|
1718
|
+
body: JSON.stringify({ permissions, startup }),
|
|
1719
|
+
});
|
|
1720
|
+
} catch (err) {
|
|
1721
|
+
logger.warn(
|
|
1722
|
+
`[Main] Permission sync failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1465
1725
|
}
|
|
1466
1726
|
|
|
1467
|
-
async function _startAgent(
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1727
|
+
async function _startAgent(): Promise<void> {
|
|
1728
|
+
const runtimeResolution = resolveDesktopRuntime();
|
|
1729
|
+
|
|
1730
|
+
if (runtimeResolution.mode !== "local") {
|
|
1731
|
+
logger.info(
|
|
1732
|
+
`[Main] Skipping embedded agent startup (${runtimeResolution.mode} mode)`,
|
|
1733
|
+
);
|
|
1734
|
+
injectApiBaseIntoOpenRendererWindows();
|
|
1735
|
+
return;
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
recordStartupPhase("autostart_requested", {
|
|
1739
|
+
pid: process.pid,
|
|
1740
|
+
exec_path: process.execPath,
|
|
1741
|
+
bundle_path: resolveStartupBundlePath(process.execPath),
|
|
1742
|
+
});
|
|
1743
|
+
|
|
1744
|
+
try {
|
|
1745
|
+
const remotePluginHost = getRemotePluginHost();
|
|
1746
|
+
remotePluginHost.startWorker("eliza.runtime");
|
|
1747
|
+
await remotePluginHost.invokeWorker({
|
|
1748
|
+
id: "eliza.runtime",
|
|
1749
|
+
method: "runtime.start",
|
|
1750
|
+
timeoutMs: getHealthPollTimeoutMs() + 5_000,
|
|
1751
|
+
});
|
|
1752
|
+
const status = getAgentManager().getStatus();
|
|
1753
|
+
|
|
1754
|
+
if (status.state === "running" && status.port) {
|
|
1755
|
+
const apiBase = `http://127.0.0.1:${status.port}`;
|
|
1756
|
+
const rendererBase = resolveRendererFacingApiBase(
|
|
1757
|
+
process.env as Record<string, string | undefined>,
|
|
1758
|
+
status.port,
|
|
1759
|
+
);
|
|
1760
|
+
// Mint or reload the loopback desktop session and install the
|
|
1761
|
+
// session+csrf cookies on the webview's cookie jar BEFORE we tell the
|
|
1762
|
+
// renderer to start hitting /api. This is the desktop trust path: if
|
|
1763
|
+
// the bridge succeeds, the renderer skips the login UI; if it fails,
|
|
1764
|
+
// the renderer behaves like a remote browser (password-required).
|
|
1765
|
+
await primeDesktopSessionAuth(apiBase, rendererBase);
|
|
1766
|
+
const apiToken = resolveApiToken(process.env) ?? "";
|
|
1767
|
+
// Set the source-of-truth API base FIRST (correct even with zero open
|
|
1768
|
+
// windows), then push to every open window.
|
|
1769
|
+
publishAgentApiBase(rendererBase, apiToken, collectOpenRendererWindows());
|
|
1770
|
+
setAgentReady(true);
|
|
1771
|
+
// Sync real OS permission states to the REST API so the renderer
|
|
1772
|
+
// can display them and capability toggles can unlock.
|
|
1773
|
+
// Pass startup=true so the backend skips scheduling a restart for
|
|
1774
|
+
// capabilities that are being auto-enabled for the first time.
|
|
1775
|
+
syncPermissionsToRestApi(status.port, true);
|
|
1776
|
+
}
|
|
1777
|
+
} catch (err) {
|
|
1778
|
+
logger.error(
|
|
1779
|
+
`[Main] Agent start failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1780
|
+
);
|
|
1781
|
+
}
|
|
1516
1782
|
}
|
|
1517
1783
|
|
|
1518
1784
|
async function setupUpdater(): Promise<void> {
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1785
|
+
const runUpdateCheck = async (notifyOnNoUpdate = false): Promise<void> => {
|
|
1786
|
+
try {
|
|
1787
|
+
const updaterState = await getDesktopManager().getUpdaterState();
|
|
1788
|
+
if (!updaterState.canAutoUpdate) {
|
|
1789
|
+
if (updaterState.autoUpdateDisabledReason) {
|
|
1790
|
+
logger.info(
|
|
1791
|
+
`[Updater] Skipping auto-update check: ${updaterState.autoUpdateDisabledReason}`,
|
|
1792
|
+
);
|
|
1793
|
+
if (notifyOnNoUpdate) {
|
|
1794
|
+
Utils.showNotification({
|
|
1795
|
+
title: "Updates Unavailable",
|
|
1796
|
+
body: updaterState.autoUpdateDisabledReason,
|
|
1797
|
+
});
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
return;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
const updateResult = await Updater.checkForUpdate();
|
|
1804
|
+
if (updateResult.updateAvailable) {
|
|
1805
|
+
Updater.downloadUpdate().catch((err: unknown) => {
|
|
1806
|
+
logger.warn(
|
|
1807
|
+
`[Updater] Download failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1808
|
+
);
|
|
1809
|
+
});
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
if (notifyOnNoUpdate) {
|
|
1814
|
+
Utils.showNotification({
|
|
1815
|
+
title: `${BRAND.appName} Up To Date`,
|
|
1816
|
+
body: "You already have the latest release installed.",
|
|
1817
|
+
});
|
|
1818
|
+
}
|
|
1819
|
+
} catch (err) {
|
|
1820
|
+
logger.warn(
|
|
1821
|
+
`[Updater] Update check failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1822
|
+
);
|
|
1823
|
+
if (notifyOnNoUpdate) {
|
|
1824
|
+
Utils.showNotification({
|
|
1825
|
+
title: "Update Check Failed",
|
|
1826
|
+
body: `${BRAND.appName} could not reach the update server.`,
|
|
1827
|
+
});
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
try {
|
|
1833
|
+
// Subscribe to update status changes so we can notify the renderer
|
|
1834
|
+
// at the right lifecycle points.
|
|
1835
|
+
Updater.onStatusChange((entry: { status: string; message?: string }) => {
|
|
1836
|
+
if (entry.status === "update-available") {
|
|
1837
|
+
// checkForUpdate found a new version — notify renderer
|
|
1838
|
+
const info = Updater.updateInfo();
|
|
1839
|
+
sendToActiveRenderer("desktopUpdateAvailable", {
|
|
1840
|
+
version: info.version,
|
|
1841
|
+
});
|
|
1842
|
+
} else if (entry.status === "download-complete") {
|
|
1843
|
+
// downloadUpdate finished — update is ready to apply
|
|
1844
|
+
const info = Updater.updateInfo();
|
|
1845
|
+
sendToActiveRenderer("desktopUpdateReady", { version: info.version });
|
|
1846
|
+
Utils.showNotification({
|
|
1847
|
+
title: `${BRAND.appName} Update Ready`,
|
|
1848
|
+
body: `Version ${info.version} is ready. Restart to apply.`,
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
});
|
|
1852
|
+
|
|
1853
|
+
const triggerManualUpdateCheck = () => {
|
|
1854
|
+
Utils.showNotification({
|
|
1855
|
+
title: "Checking for Updates",
|
|
1856
|
+
body: `${BRAND.appName} is checking for a newer release.`,
|
|
1857
|
+
});
|
|
1858
|
+
void runUpdateCheck(true);
|
|
1859
|
+
};
|
|
1860
|
+
|
|
1861
|
+
const handleUpdateAndConfigMenuAction = async (
|
|
1862
|
+
action: string | undefined,
|
|
1863
|
+
): Promise<boolean> => {
|
|
1864
|
+
if (action === "check-for-updates") {
|
|
1865
|
+
triggerManualUpdateCheck();
|
|
1866
|
+
return true;
|
|
1867
|
+
}
|
|
1868
|
+
if (action === "open-about") {
|
|
1869
|
+
const updaterState = await getDesktopManager().getUpdaterState();
|
|
1870
|
+
const version = updaterState.currentVersion || "unknown";
|
|
1871
|
+
Utils.showNotification({
|
|
1872
|
+
title: `About ${BRAND.appName}`,
|
|
1873
|
+
body: `Version ${version} (${process.platform}/${process.arch})`,
|
|
1874
|
+
});
|
|
1875
|
+
void createSettingsWindow("updates");
|
|
1876
|
+
return true;
|
|
1877
|
+
}
|
|
1878
|
+
if (action === "export-config") {
|
|
1879
|
+
void exportConfigFromMenu();
|
|
1880
|
+
return true;
|
|
1881
|
+
}
|
|
1882
|
+
if (action === "import-config") {
|
|
1883
|
+
void importConfigFromMenu();
|
|
1884
|
+
return true;
|
|
1885
|
+
}
|
|
1886
|
+
return false;
|
|
1887
|
+
};
|
|
1888
|
+
|
|
1889
|
+
const handleMainWindowMenuAction = (
|
|
1890
|
+
action: string | undefined,
|
|
1891
|
+
): boolean => {
|
|
1892
|
+
if (action === "toggle-devtools") {
|
|
1893
|
+
toggleFocusedWindowDevTools();
|
|
1894
|
+
return true;
|
|
1895
|
+
}
|
|
1896
|
+
if (action === "focus-main-window") {
|
|
1897
|
+
void getDesktopManager().focusWindow();
|
|
1898
|
+
return true;
|
|
1899
|
+
}
|
|
1900
|
+
if (action === "hide-main-window") {
|
|
1901
|
+
void getDesktopManager().hideWindow();
|
|
1902
|
+
return true;
|
|
1903
|
+
}
|
|
1904
|
+
if (action === "maximize-main-window") {
|
|
1905
|
+
void getDesktopManager().maximizeWindow();
|
|
1906
|
+
return true;
|
|
1907
|
+
}
|
|
1908
|
+
if (action === "restore-main-window") {
|
|
1909
|
+
void getDesktopManager().unmaximizeWindow();
|
|
1910
|
+
return true;
|
|
1911
|
+
}
|
|
1912
|
+
if (action === "show") {
|
|
1913
|
+
void getDesktopManager().showWindow();
|
|
1914
|
+
return true;
|
|
1915
|
+
}
|
|
1916
|
+
return false;
|
|
1917
|
+
};
|
|
1918
|
+
|
|
1919
|
+
const handleSettingsMenuAction = (action: string | undefined): boolean => {
|
|
1920
|
+
if (action === "open-secrets-manager") {
|
|
1921
|
+
void restoreWindow();
|
|
1922
|
+
sendToActiveRenderer("openSecretsManager", {});
|
|
1923
|
+
return true;
|
|
1924
|
+
}
|
|
1925
|
+
if (action === "open-settings" || action?.startsWith("open-settings-")) {
|
|
1926
|
+
void createSettingsWindow(parseSettingsWindowAction(action));
|
|
1927
|
+
return true;
|
|
1928
|
+
}
|
|
1929
|
+
return false;
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1932
|
+
const handleSurfaceMenuAction = (action: string | undefined): boolean => {
|
|
1933
|
+
if (action?.startsWith("new-window:")) {
|
|
1934
|
+
const surface = action.slice("new-window:".length);
|
|
1935
|
+
if (surfaceWindowManager && isDetachedSurface(surface)) {
|
|
1936
|
+
void surfaceWindowManager.openSurfaceWindow(surface);
|
|
1937
|
+
}
|
|
1938
|
+
return true;
|
|
1939
|
+
}
|
|
1940
|
+
if (action?.startsWith("focus-window:")) {
|
|
1941
|
+
const windowId = action.slice("focus-window:".length);
|
|
1942
|
+
surfaceWindowManager?.focusWindow(windowId);
|
|
1943
|
+
return true;
|
|
1944
|
+
}
|
|
1945
|
+
if (action?.startsWith("show-main:")) {
|
|
1946
|
+
showMainSurface(action.slice("show-main:".length));
|
|
1947
|
+
return true;
|
|
1948
|
+
}
|
|
1949
|
+
return false;
|
|
1950
|
+
};
|
|
1951
|
+
|
|
1952
|
+
const handleStewardMenuAction = (action: string | undefined): boolean => {
|
|
1953
|
+
if (action === "restart-steward" && isStewardLocalEnabled()) {
|
|
1954
|
+
restartSteward().catch((err: unknown) => {
|
|
1955
|
+
logger.error(
|
|
1956
|
+
`[Main] Steward restart failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1957
|
+
);
|
|
1958
|
+
Utils.showNotification({
|
|
1959
|
+
title: "Steward Restart Failed",
|
|
1960
|
+
body: err instanceof Error ? err.message : "Unknown error",
|
|
1961
|
+
});
|
|
1962
|
+
});
|
|
1963
|
+
return true;
|
|
1964
|
+
}
|
|
1965
|
+
if (action === "reset-steward" && isStewardLocalEnabled()) {
|
|
1966
|
+
resetSteward().catch((err: unknown) => {
|
|
1967
|
+
logger.error(
|
|
1968
|
+
`[Main] Steward reset failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1969
|
+
);
|
|
1970
|
+
Utils.showNotification({
|
|
1971
|
+
title: "Steward Reset Failed",
|
|
1972
|
+
body: err instanceof Error ? err.message : "Unknown error",
|
|
1973
|
+
});
|
|
1974
|
+
});
|
|
1975
|
+
return true;
|
|
1976
|
+
}
|
|
1977
|
+
return false;
|
|
1978
|
+
};
|
|
1979
|
+
|
|
1980
|
+
const handleAppEntryMenuAction = (action: string | undefined): boolean => {
|
|
1981
|
+
if (!action?.startsWith("apps:") && !action?.startsWith("tray-app-")) {
|
|
1982
|
+
return false;
|
|
1983
|
+
}
|
|
1984
|
+
const slug = action.startsWith("apps:")
|
|
1985
|
+
? action.slice("apps:".length)
|
|
1986
|
+
: action.slice("tray-app-".length);
|
|
1987
|
+
const entry = findAppMenuEntryBySlug(slug);
|
|
1988
|
+
if (!entry) return true;
|
|
1989
|
+
if (entry.hasDetailsPage) {
|
|
1990
|
+
void restoreWindow();
|
|
1991
|
+
sendToActiveRenderer("desktopAppDetailsRequested", {
|
|
1992
|
+
slug: entry.slug,
|
|
1993
|
+
});
|
|
1994
|
+
return true;
|
|
1995
|
+
}
|
|
1996
|
+
void getDesktopManager().openAppWindow({
|
|
1997
|
+
slug: entry.slug,
|
|
1998
|
+
title: entry.displayName,
|
|
1999
|
+
path: entry.windowPath,
|
|
2000
|
+
alwaysOnTop: false,
|
|
2001
|
+
});
|
|
2002
|
+
return true;
|
|
2003
|
+
};
|
|
2004
|
+
|
|
2005
|
+
const handleRuntimeMenuAction = (action: string | undefined): boolean => {
|
|
2006
|
+
if (action === "relaunch") {
|
|
2007
|
+
void getDesktopManager().relaunch();
|
|
2008
|
+
return true;
|
|
2009
|
+
}
|
|
2010
|
+
if (action === "reset-app") {
|
|
2011
|
+
void resetTheAppFromApplicationMenu();
|
|
2012
|
+
return true;
|
|
2013
|
+
}
|
|
2014
|
+
if (action === "desktop-notify") {
|
|
2015
|
+
void getDesktopManager().showNotification({
|
|
2016
|
+
title: `${BRAND.appName} Desktop`,
|
|
2017
|
+
body: `${BRAND.appName} native application menu actions are wired and responding.`,
|
|
2018
|
+
urgency: "normal",
|
|
2019
|
+
});
|
|
2020
|
+
return true;
|
|
2021
|
+
}
|
|
2022
|
+
if (action === "restart-agent") {
|
|
2023
|
+
getAgentManager()
|
|
2024
|
+
.restart()
|
|
2025
|
+
.catch((err: unknown) => {
|
|
2026
|
+
logger.error(
|
|
2027
|
+
`[Main] Agent restart failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2028
|
+
);
|
|
2029
|
+
});
|
|
2030
|
+
return true;
|
|
2031
|
+
}
|
|
2032
|
+
if (action === "quit") {
|
|
2033
|
+
void getDesktopManager().quit();
|
|
2034
|
+
return true;
|
|
2035
|
+
}
|
|
2036
|
+
if (action?.startsWith("navigate-")) {
|
|
2037
|
+
void getDesktopManager().showWindow();
|
|
2038
|
+
sendToActiveRenderer("desktopTrayMenuClick", { itemId: action });
|
|
2039
|
+
return true;
|
|
2040
|
+
}
|
|
2041
|
+
return false;
|
|
2042
|
+
};
|
|
2043
|
+
|
|
2044
|
+
const handleApplicationMenuAction = async (
|
|
2045
|
+
action: string | undefined,
|
|
2046
|
+
): Promise<void> => {
|
|
2047
|
+
if (!currentWindow && shouldRestoreWindowBeforeMenuAction(action)) {
|
|
2048
|
+
await restoreWindow();
|
|
2049
|
+
}
|
|
2050
|
+
if (await handleUpdateAndConfigMenuAction(action)) return;
|
|
2051
|
+
if (handleMainWindowMenuAction(action)) return;
|
|
2052
|
+
if (handleSettingsMenuAction(action)) return;
|
|
2053
|
+
if (handleSurfaceMenuAction(action)) return;
|
|
2054
|
+
if (handleStewardMenuAction(action)) return;
|
|
2055
|
+
if (handleAppEntryMenuAction(action)) return;
|
|
2056
|
+
handleRuntimeMenuAction(action);
|
|
2057
|
+
};
|
|
2058
|
+
|
|
2059
|
+
setApplicationMenuActionHandler(handleApplicationMenuAction);
|
|
2060
|
+
|
|
2061
|
+
Electrobun.events.on(
|
|
2062
|
+
"application-menu-clicked",
|
|
2063
|
+
(e: { data?: { action?: string } }) => {
|
|
2064
|
+
void handleApplicationMenuAction(e.data?.action);
|
|
2065
|
+
},
|
|
2066
|
+
);
|
|
2067
|
+
|
|
2068
|
+
// Route tray app entries (`tray-app-<slug>`) into the same handler as the
|
|
2069
|
+
// OS menu bar. WHY: the desktop manager forwards every tray click to the
|
|
2070
|
+
// renderer, but spawning native windows must happen on the bun side.
|
|
2071
|
+
Electrobun.events.on(
|
|
2072
|
+
"tray-clicked",
|
|
2073
|
+
(e: { data?: { action?: string } }) => {
|
|
2074
|
+
const action = e.data?.action;
|
|
2075
|
+
if (typeof action === "string" && action.startsWith("tray-app-")) {
|
|
2076
|
+
void handleApplicationMenuAction(action);
|
|
2077
|
+
}
|
|
2078
|
+
},
|
|
2079
|
+
);
|
|
2080
|
+
|
|
2081
|
+
Electrobun.events.on("context-menu-clicked", (action: string) => {
|
|
2082
|
+
if (action === "check-for-updates") {
|
|
2083
|
+
triggerManualUpdateCheck();
|
|
2084
|
+
} else if (action === "relaunch") {
|
|
2085
|
+
void getDesktopManager().relaunch();
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
|
|
2089
|
+
await runUpdateCheck(false);
|
|
2090
|
+
} catch (err) {
|
|
2091
|
+
logger.warn(
|
|
2092
|
+
`[Updater] Update check failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2093
|
+
);
|
|
2094
|
+
}
|
|
1773
2095
|
}
|
|
1774
2096
|
|
|
1775
2097
|
/**
|
|
@@ -1782,126 +2104,146 @@ async function setupUpdater(): Promise<void> {
|
|
|
1782
2104
|
* `urlSchemes`, sourced from `ELIZA_URL_SCHEME`) — this handler does not
|
|
1783
2105
|
* care which scheme is used; it only routes by host + pathname.
|
|
1784
2106
|
*/
|
|
1785
|
-
function handleDeepLink(url: string): void {
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
2107
|
+
async function handleDeepLink(url: string): Promise<void> {
|
|
2108
|
+
let parsed: URL;
|
|
2109
|
+
try {
|
|
2110
|
+
parsed = new URL(url);
|
|
2111
|
+
} catch {
|
|
2112
|
+
await forwardDeepLinkToRenderer(url);
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// `<scheme>://apps/<slug>` → URL parses host="apps", pathname="/<slug>"
|
|
2117
|
+
if (parsed.host === "apps") {
|
|
2118
|
+
const slug = parsed.pathname
|
|
2119
|
+
.replace(/^\/+/, "")
|
|
2120
|
+
.replace(/[?#].*$/, "")
|
|
2121
|
+
.split("/")[0];
|
|
2122
|
+
if (slug) {
|
|
2123
|
+
const entry = findAppMenuEntryBySlug(slug);
|
|
2124
|
+
if (entry) {
|
|
2125
|
+
// Mirror the menu/tray handler: apps with a details page get a config
|
|
2126
|
+
// review screen instead of a direct window so deep links and clicks
|
|
2127
|
+
// produce identical UX.
|
|
2128
|
+
if (entry.hasDetailsPage) {
|
|
2129
|
+
void restoreWindow();
|
|
2130
|
+
sendToActiveRenderer("desktopAppDetailsRequested", {
|
|
2131
|
+
slug: entry.slug,
|
|
2132
|
+
});
|
|
2133
|
+
} else {
|
|
2134
|
+
void getDesktopManager().openAppWindow({
|
|
2135
|
+
slug: entry.slug,
|
|
2136
|
+
title: entry.displayName,
|
|
2137
|
+
path: entry.windowPath,
|
|
2138
|
+
alwaysOnTop: false,
|
|
2139
|
+
});
|
|
2140
|
+
}
|
|
2141
|
+
return;
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
await forwardDeepLinkToRenderer(url);
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
async function forwardDeepLinkToRenderer(url: string): Promise<void> {
|
|
2150
|
+
await restoreWindow();
|
|
2151
|
+
// Assistant/Siri/Shortcuts links deliberately stay renderer-owned. LifeOps
|
|
2152
|
+
// requests must go through the normal chat/runtime planner, which persists
|
|
2153
|
+
// ScheduledTask records instead of creating native macOS-only state.
|
|
2154
|
+
sendToActiveRenderer("shareTargetReceived", { url });
|
|
1825
2155
|
}
|
|
1826
2156
|
|
|
1827
2157
|
function setupDeepLinks(): void {
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
2158
|
+
Electrobun.events.on("open-url", (event: unknown) => {
|
|
2159
|
+
const url = readOpenUrlEventUrl(event);
|
|
2160
|
+
if (!url) {
|
|
2161
|
+
logger.warn("[Main] Ignoring open-url event without a URL payload");
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
void handleDeepLink(url);
|
|
2165
|
+
});
|
|
1831
2166
|
}
|
|
1832
2167
|
|
|
1833
2168
|
function setupDockReopen(): void {
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
2169
|
+
Electrobun.events.on("reopen", () => {
|
|
2170
|
+
void restoreWindow();
|
|
2171
|
+
});
|
|
1837
2172
|
}
|
|
1838
2173
|
|
|
1839
2174
|
async function runShutdownCleanup(reason: string): Promise<void> {
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
2175
|
+
logger.info(`[Main] App quitting (${reason}), disposing native modules...`);
|
|
2176
|
+
isQuitting = true;
|
|
2177
|
+
sendToActiveRenderer("desktopShutdownStarted", { reason });
|
|
2178
|
+
for (const cleanupFn of cleanupFns) {
|
|
2179
|
+
await Promise.resolve(cleanupFn());
|
|
2180
|
+
}
|
|
2181
|
+
await disposeNativeModules();
|
|
1847
2182
|
}
|
|
1848
2183
|
|
|
1849
2184
|
function setupShutdown(): void {
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
2185
|
+
Electrobun.events.on("before-quit", () => {
|
|
2186
|
+
void runShutdownCleanup("before-quit");
|
|
2187
|
+
});
|
|
1853
2188
|
}
|
|
1854
2189
|
|
|
1855
2190
|
/**
|
|
1856
|
-
* Load repo-root and
|
|
2191
|
+
* Load repo-root and state-dir `.env` into `process.env` (non-destructive) so the
|
|
1857
2192
|
* main process can send the same `ELIZA_API_TOKEN` as `dev-server.ts` when
|
|
1858
2193
|
* calling loopback APIs (app menu reset, export, etc.). The dev API child
|
|
1859
2194
|
* already loads dotenv; Electrobun did not until this ran.
|
|
1860
2195
|
*
|
|
1861
2196
|
* Packaged desktop builds must not load these files. On machines that also
|
|
1862
|
-
* have
|
|
2197
|
+
* have an app/Eliza dev checkout, the state-dir `.env` can contain
|
|
1863
2198
|
* ELIZA_DESKTOP_API_BASE and related overrides that switch the packaged app
|
|
1864
2199
|
* into external mode and make launcher startup appear dead.
|
|
1865
2200
|
*/
|
|
1866
2201
|
async function loadTheAppEnvFilesForMain(): Promise<void> {
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
2202
|
+
const normalizedModuleDir = import.meta.dir.replaceAll("\\", "/");
|
|
2203
|
+
const isPackagedBuild = !normalizedModuleDir.includes("/src/");
|
|
2204
|
+
if (isPackagedBuild) {
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
try {
|
|
2209
|
+
const { config } = await import("dotenv");
|
|
2210
|
+
const repoRootGuess = path.resolve(
|
|
2211
|
+
normalizedModuleDir,
|
|
2212
|
+
"..",
|
|
2213
|
+
"..",
|
|
2214
|
+
"..",
|
|
2215
|
+
"..",
|
|
2216
|
+
);
|
|
2217
|
+
const namespace = process.env.ELIZA_NAMESPACE?.trim() || BRAND.namespace;
|
|
2218
|
+
const xdgStateHome = process.env.XDG_STATE_HOME?.trim();
|
|
2219
|
+
const stateHome = xdgStateHome
|
|
2220
|
+
? path.isAbsolute(xdgStateHome)
|
|
2221
|
+
? xdgStateHome
|
|
2222
|
+
: path.join(os.homedir(), xdgStateHome)
|
|
2223
|
+
: path.join(os.homedir(), ".local", "state");
|
|
2224
|
+
for (const envPath of [
|
|
2225
|
+
path.join(repoRootGuess, ".env"),
|
|
2226
|
+
path.join(stateHome, namespace, ".env"),
|
|
2227
|
+
]) {
|
|
2228
|
+
if (fs.existsSync(envPath)) {
|
|
2229
|
+
config({ path: envPath, override: false });
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
} catch {
|
|
2233
|
+
/* dotenv may be unavailable in minimal installs */
|
|
2234
|
+
}
|
|
1893
2235
|
}
|
|
1894
2236
|
|
|
1895
2237
|
function initializeBundledWebGPU(): void {
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
2238
|
+
if (!WGPU.native.available) {
|
|
2239
|
+
logger.info(
|
|
2240
|
+
"[WebGPU] Native Dawn runtime not bundled for this run; renderer-side WebGPU remains available through the webview/browser path.",
|
|
2241
|
+
);
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
|
|
2245
|
+
webgpu.install();
|
|
2246
|
+
logger.info(`[WebGPU] Native Dawn runtime ready at ${WGPU.native.path}`);
|
|
1905
2247
|
}
|
|
1906
2248
|
|
|
1907
2249
|
/**
|
|
@@ -1914,595 +2256,712 @@ function initializeBundledWebGPU(): void {
|
|
|
1914
2256
|
* On macOS 26+ with native renderer, WebGPU is expected via WKWebView.
|
|
1915
2257
|
* On Linux/Windows with CEF, upstream Electrobun flag support is still needed.
|
|
1916
2258
|
*/
|
|
1917
|
-
function checkWebGpuBrowserSupport(): void {
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
2259
|
+
function checkWebGpuBrowserSupport(rendererType: "native" | "cef"): void {
|
|
2260
|
+
const status = checkWebGpuSupport(rendererType);
|
|
2261
|
+
if (status.available) {
|
|
2262
|
+
logger.info(`[WebGPU Browser] ${status.reason}`);
|
|
2263
|
+
} else {
|
|
2264
|
+
logger.warn(`[WebGPU Browser] ${status.reason}`);
|
|
2265
|
+
if (status.chromeBetaPath) {
|
|
2266
|
+
logger.info(
|
|
2267
|
+
`[WebGPU Browser] Chrome Beta found at: ${status.chromeBetaPath}`,
|
|
2268
|
+
);
|
|
2269
|
+
} else if (status.downloadUrl) {
|
|
2270
|
+
logger.info(
|
|
2271
|
+
`[WebGPU Browser] Download Chrome Beta: ${status.downloadUrl}`,
|
|
2272
|
+
);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
// Push status to renderer after a short delay to allow window creation.
|
|
2277
|
+
setTimeout(() => {
|
|
2278
|
+
sendToActiveRenderer("webgpu:browserStatus", status);
|
|
2279
|
+
}, 2000);
|
|
1938
2280
|
}
|
|
1939
2281
|
|
|
1940
2282
|
async function main(): Promise<void> {
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2283
|
+
recordStartupPhase("main_start", {
|
|
2284
|
+
pid: process.pid,
|
|
2285
|
+
exec_path: process.execPath,
|
|
2286
|
+
bundle_path: resolveStartupBundlePath(process.execPath),
|
|
2287
|
+
});
|
|
2288
|
+
await loadTheAppEnvFilesForMain();
|
|
2289
|
+
recordStartupPhase("env_loaded", {
|
|
2290
|
+
pid: process.pid,
|
|
2291
|
+
});
|
|
2292
|
+
// Start the static renderer server in parallel with the rest of pre-window
|
|
2293
|
+
// work — first paint needs the renderer URL, so kicking it off now overlaps
|
|
2294
|
+
// the server bind/port-scan with crash-prompt checks, WebGPU init, and bridge
|
|
2295
|
+
// startup below. resolveRendererUrl() is idempotent (memoises this promise),
|
|
2296
|
+
// so later callers reuse it. Errors surface when the promise is awaited.
|
|
2297
|
+
void resolveRendererUrl();
|
|
2298
|
+
console.log(`[Main] Starting ${BRAND.appName} (Electrobun)`);
|
|
2299
|
+
const normalizedModuleDir = import.meta.dir.replaceAll("\\", "/");
|
|
2300
|
+
const runtimeResolution = resolveDesktopRuntime();
|
|
2301
|
+
// Structured startup environment block — visible in CI logs and eliza-startup.log
|
|
2302
|
+
console.log(
|
|
2303
|
+
`[Env] platform=${process.platform} arch=${process.arch} bun=${Bun.version} ` +
|
|
2304
|
+
`execPath=${process.execPath} cwd=${process.cwd()} moduleDir=${import.meta.dir} ` +
|
|
2305
|
+
`packaged=${!normalizedModuleDir.includes("/src/")} argv=${process.argv.slice(1).join(" ")}`,
|
|
2306
|
+
);
|
|
2307
|
+
console.log(
|
|
2308
|
+
`[Env] desktopRuntimeMode=${runtimeResolution.mode} externalApi=${runtimeResolution.externalApi.base ?? "none"}`,
|
|
2309
|
+
);
|
|
2310
|
+
|
|
2311
|
+
printElectrobunDevSettingsBanner(
|
|
2312
|
+
process.env as Record<string, string | undefined>,
|
|
2313
|
+
);
|
|
2314
|
+
|
|
2315
|
+
// Don't block first paint on the crash-recovery prompt. The common path is a
|
|
2316
|
+
// couple of stat reads that early-return; the only blocking case is a modal
|
|
2317
|
+
// shown after a *prior* launch crashed, which can safely overlap the window.
|
|
2318
|
+
void maybePromptStartupCrashReport()
|
|
2319
|
+
.then(() => {
|
|
2320
|
+
recordStartupPhase("crash_prompt_checked", {
|
|
2321
|
+
pid: process.pid,
|
|
2322
|
+
});
|
|
2323
|
+
})
|
|
2324
|
+
.catch((err) => {
|
|
2325
|
+
logger.warn(
|
|
2326
|
+
`[Main] Startup crash prompt failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2327
|
+
);
|
|
2328
|
+
});
|
|
2329
|
+
// On Windows (CEF renderer), clear stale CEF profile data when the app
|
|
2330
|
+
// version changes. A leftover Partitions/default profile from a previous
|
|
2331
|
+
// install causes "Cannot create profile at path" errors that cascade into
|
|
2332
|
+
// GPU process crashes, rendering the UI unusable. Clearing the CEF cache
|
|
2333
|
+
// is safe — it only contains browser session state (cookies, caches,
|
|
2334
|
+
// LevelDB stores) that CEF recreates on next launch.
|
|
2335
|
+
if (process.platform === "win32") {
|
|
2336
|
+
try {
|
|
2337
|
+
const cefDir = path.join(Utils.paths.userData, "CEF");
|
|
2338
|
+
const cefVersionMarker = path.join(
|
|
2339
|
+
cefDir,
|
|
2340
|
+
BRAND.cefVersionMarkerFileName,
|
|
2341
|
+
);
|
|
2342
|
+
const currentVersion =
|
|
2343
|
+
resolveDesktopBundleVersion(import.meta.dir) ?? "unknown";
|
|
2344
|
+
let previousVersion: string | null = null;
|
|
2345
|
+
try {
|
|
2346
|
+
previousVersion = fs.readFileSync(cefVersionMarker, "utf-8").trim();
|
|
2347
|
+
} catch {
|
|
2348
|
+
// No marker — first run or pre-fix install.
|
|
2349
|
+
}
|
|
2350
|
+
if (
|
|
2351
|
+
shouldResetWindowsCefProfile({
|
|
2352
|
+
currentVersion,
|
|
2353
|
+
previousVersion,
|
|
2354
|
+
cefDirExists: fs.existsSync(cefDir),
|
|
2355
|
+
})
|
|
2356
|
+
) {
|
|
2357
|
+
logger.info(
|
|
2358
|
+
`[Main] CEF version mismatch (${previousVersion ?? "none"} → ${currentVersion}), clearing stale CEF profile`,
|
|
2359
|
+
);
|
|
2360
|
+
// Remove everything except the version marker we're about to write.
|
|
2361
|
+
for (const entry of fs.readdirSync(cefDir)) {
|
|
2362
|
+
if (entry === BRAND.cefVersionMarkerFileName) continue;
|
|
2363
|
+
const entryPath = path.join(cefDir, entry);
|
|
2364
|
+
try {
|
|
2365
|
+
fs.rmSync(entryPath, { recursive: true, force: true });
|
|
2366
|
+
} catch (err) {
|
|
2367
|
+
logger.warn(
|
|
2368
|
+
`[Main] Could not remove ${entryPath}: ${err instanceof Error ? err.message : String(err)}`,
|
|
2369
|
+
);
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
// Write/update version marker so we don't clear again on next launch.
|
|
2374
|
+
if (shouldWriteWindowsCefProfileMarker(currentVersion)) {
|
|
2375
|
+
fs.mkdirSync(cefDir, { recursive: true });
|
|
2376
|
+
fs.writeFileSync(cefVersionMarker, currentVersion);
|
|
2377
|
+
}
|
|
2378
|
+
} catch (err) {
|
|
2379
|
+
logger.warn(
|
|
2380
|
+
`[Main] CEF profile cleanup failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`,
|
|
2381
|
+
);
|
|
2382
|
+
}
|
|
2383
|
+
}
|
|
2384
|
+
|
|
2385
|
+
initializeBundledWebGPU();
|
|
2386
|
+
recordStartupPhase("webgpu_initialized", {
|
|
2387
|
+
pid: process.pid,
|
|
2388
|
+
});
|
|
2389
|
+
const buildInfo = await BuildConfig.get();
|
|
2390
|
+
checkWebGpuBrowserSupport(buildInfo.defaultRenderer);
|
|
2391
|
+
cleanupFns.length = 0;
|
|
2392
|
+
// Start the browser-workspace bridge without blocking first paint. The
|
|
2393
|
+
// renderer reaches it lazily (browser-workspace RPC), so it does not need to
|
|
2394
|
+
// be listening before the window opens. Register a cleanup that awaits the
|
|
2395
|
+
// resolved stop fn so shutdown still tears it down.
|
|
2396
|
+
const browserWorkspaceBridgeStop = startBrowserWorkspaceBridgeServer()
|
|
2397
|
+
.then((stop) => {
|
|
2398
|
+
recordStartupPhase("browser_workspace_bridge_ready", {
|
|
2399
|
+
pid: process.pid,
|
|
2400
|
+
});
|
|
2401
|
+
return stop;
|
|
2402
|
+
})
|
|
2403
|
+
.catch((err) => {
|
|
2404
|
+
logger.warn(
|
|
2405
|
+
`[Main] Browser-workspace bridge startup failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2406
|
+
);
|
|
2407
|
+
return undefined;
|
|
2408
|
+
});
|
|
2409
|
+
cleanupFns.push(async () => {
|
|
2410
|
+
const stop = await browserWorkspaceBridgeStop;
|
|
2411
|
+
await stop?.();
|
|
2412
|
+
});
|
|
2413
|
+
const stopDesktopTestBridgeServer = await startDesktopTestBridgeServer();
|
|
2414
|
+
recordStartupPhase("desktop_test_bridge_ready", {
|
|
2415
|
+
pid: process.pid,
|
|
2416
|
+
});
|
|
2417
|
+
if (stopDesktopTestBridgeServer) {
|
|
2418
|
+
cleanupFns.push(stopDesktopTestBridgeServer);
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
// WHY push API base on every status tick with a port: embedded startup can
|
|
2422
|
+
// settle on a different loopback port than env/static HTML (allocation + stdout).
|
|
2423
|
+
// Detached surfaces must not keep a stale __ELIZA_API_BASE__ while the main
|
|
2424
|
+
// window was already updated—menu reset, chat, and settings each own a webview.
|
|
2425
|
+
cleanupFns.push(
|
|
2426
|
+
getAgentManager().onStatusChange((status) => {
|
|
2427
|
+
if (status.port) {
|
|
2428
|
+
// The agent rebound to a different loopback port (or recovered from a
|
|
2429
|
+
// crash) — the cookies we installed during _startAgent were scoped to
|
|
2430
|
+
// the old origin. Re-prime so every renderer's next /api request stays
|
|
2431
|
+
// authenticated, including the OS-level pill window.
|
|
2432
|
+
markDesktopSessionStale();
|
|
2433
|
+
const apiBase = `http://127.0.0.1:${status.port}`;
|
|
2434
|
+
const rendererBase = resolveRendererFacingApiBase(
|
|
2435
|
+
process.env as Record<string, string | undefined>,
|
|
2436
|
+
status.port,
|
|
2437
|
+
);
|
|
2438
|
+
void primeDesktopSessionAuth(apiBase, rendererBase);
|
|
2439
|
+
injectApiBaseIntoOpenRendererWindows();
|
|
2440
|
+
}
|
|
2441
|
+
}),
|
|
2442
|
+
);
|
|
2443
|
+
|
|
2444
|
+
// Create window first — on Windows (CEF) the UI message loop must be
|
|
2445
|
+
// running before any synchronous FFI calls like setApplicationMenu().
|
|
2446
|
+
// Calling setupApplicationMenu() before createMainWindow() deadlocks.
|
|
2447
|
+
const onboardingOverlay = shouldStartOnboardingOverlay();
|
|
2448
|
+
const trayFirst = shouldStartTrayFirst();
|
|
2449
|
+
let mainWin: BrowserWindow | null = null;
|
|
2450
|
+
if (onboardingOverlay) {
|
|
2451
|
+
// First-run onboarding (macOS, opt-in): post a native macOS notification
|
|
2452
|
+
// with action buttons ("Local On-Device", "Local Cloud AI", "Eliza Cloud").
|
|
2453
|
+
// The user's choice is polled via FFI. Once selected, we wait for the
|
|
2454
|
+
// embedded API server to be ready, POST the first-run config, then open
|
|
2455
|
+
// the dashboard. Falls back to the overlay window on FFI failure.
|
|
2456
|
+
logger.info("[Main] Onboarding — posting native macOS notification");
|
|
2457
|
+
recordStartupPhase("creating_window", { pid: process.pid });
|
|
2458
|
+
|
|
2459
|
+
// Run notification flow async — don't block the event loop.
|
|
2460
|
+
// Once the user picks and the API is ready, we create the dashboard.
|
|
2461
|
+
void (async () => {
|
|
2462
|
+
try {
|
|
2463
|
+
const choice = await waitForOnboardingNotificationChoice();
|
|
2464
|
+
if (!choice) {
|
|
2465
|
+
// FFI failed or unsupported — fall back to overlay window.
|
|
2466
|
+
logger.warn(
|
|
2467
|
+
"[Main] Native notification unavailable — falling back to overlay",
|
|
2468
|
+
);
|
|
2469
|
+
await openOnboardingOverlayWindow();
|
|
2470
|
+
return;
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
// Wait for the embedded API server to be ready before submitting.
|
|
2474
|
+
// The agent manager may not have started yet, so poll until
|
|
2475
|
+
// resolveLoopbackApiBase() returns a valid URL.
|
|
2476
|
+
let apiBase: string | null = null;
|
|
2477
|
+
const apiBaseDeadline = Date.now() + 120_000;
|
|
2478
|
+
while (Date.now() < apiBaseDeadline) {
|
|
2479
|
+
apiBase = resolveLoopbackApiBase();
|
|
2480
|
+
if (apiBase) break;
|
|
2481
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
2482
|
+
}
|
|
2483
|
+
if (!apiBase) {
|
|
2484
|
+
logger.error(
|
|
2485
|
+
"[Main] Cannot resolve API base after 120s — falling back to overlay",
|
|
2486
|
+
);
|
|
2487
|
+
await openOnboardingOverlayWindow();
|
|
2488
|
+
return;
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
logger.info(
|
|
2492
|
+
`[Main] Notification choice received — waiting for API at ${apiBase}`,
|
|
2493
|
+
);
|
|
2494
|
+
const apiReady = await waitForApiReady(apiBase, 120_000);
|
|
2495
|
+
if (!apiReady) {
|
|
2496
|
+
logger.error(
|
|
2497
|
+
"[Main] API server not ready after 120s — falling back to overlay",
|
|
2498
|
+
);
|
|
2499
|
+
await openOnboardingOverlayWindow();
|
|
2500
|
+
return;
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
// Submit first-run config to the API.
|
|
2504
|
+
const submitted = await submitOnboardingFirstRun(apiBase, choice);
|
|
2505
|
+
if (!submitted) {
|
|
2506
|
+
logger.error(
|
|
2507
|
+
"[Main] First-run submission failed — falling back to overlay",
|
|
2508
|
+
);
|
|
2509
|
+
await openOnboardingOverlayWindow();
|
|
2510
|
+
return;
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
// First-run complete — close the overlay and let its close handler
|
|
2514
|
+
// create the dashboard (single handoff point). The win.on("close")
|
|
2515
|
+
// handler wired in openOnboardingOverlayWindow() transitions to the
|
|
2516
|
+
// main dashboard window, so we just need to trigger it.
|
|
2517
|
+
logger.info(
|
|
2518
|
+
"[Main] First-run complete — closing overlay to transition to dashboard",
|
|
2519
|
+
);
|
|
2520
|
+
closeOnboardingOverlayWindow();
|
|
2521
|
+
} catch (err) {
|
|
2522
|
+
logger.error(
|
|
2523
|
+
`[Main] Native onboarding failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2524
|
+
);
|
|
2525
|
+
await openOnboardingOverlayWindow();
|
|
2526
|
+
}
|
|
2527
|
+
})();
|
|
2528
|
+
|
|
2529
|
+
recordStartupPhase("window_ready", {
|
|
2530
|
+
pid: process.pid,
|
|
2531
|
+
});
|
|
2532
|
+
} else if (trayFirst) {
|
|
2533
|
+
// Tray-first (macOS, opt-in): no window at launch. The tray icon is the
|
|
2534
|
+
// only surface; the main window is created lazily via restoreWindow() /
|
|
2535
|
+
// DesktopManager.showWindow() on tray "Show Window", Dock reopen, or a
|
|
2536
|
+
// deep link. setTrayFirstMode hides the Dock icon until a window is shown.
|
|
2537
|
+
logger.info("[Main] Tray-first startup — deferring main window creation");
|
|
2538
|
+
getDesktopManager().setTrayFirstMode(true);
|
|
2539
|
+
recordStartupPhase("window_ready", {
|
|
2540
|
+
pid: process.pid,
|
|
2541
|
+
});
|
|
2542
|
+
} else {
|
|
2543
|
+
recordStartupPhase("creating_window", {
|
|
2544
|
+
pid: process.pid,
|
|
2545
|
+
});
|
|
2546
|
+
const { rpc: mainRpc, sendToWebview: mainSendToWebview } =
|
|
2547
|
+
createDesktopRpc("main");
|
|
2548
|
+
mainWin = attachMainWindow(
|
|
2549
|
+
await createMainWindow(mainRpc),
|
|
2550
|
+
mainRpc,
|
|
2551
|
+
mainSendToWebview,
|
|
2552
|
+
);
|
|
2553
|
+
recordStartupPhase("window_ready", {
|
|
2554
|
+
pid: process.pid,
|
|
2555
|
+
});
|
|
2556
|
+
}
|
|
2557
|
+
seedFirstPartyRemotePluginsForStartup();
|
|
2558
|
+
|
|
2559
|
+
// Configure the floating chat manager now that the renderer URL is resolved.
|
|
2560
|
+
// This must run after createMainWindow() so rendererUrlPromise is already set.
|
|
2561
|
+
void resolveRendererUrl().then((url) => {
|
|
2562
|
+
let preload = "";
|
|
2563
|
+
try {
|
|
2564
|
+
preload = readResolvedPreloadScript(import.meta.dir);
|
|
2565
|
+
} catch {
|
|
2566
|
+
/* non-fatal */
|
|
2567
|
+
}
|
|
2568
|
+
getFloatingChatManager().configure(url, preload);
|
|
2569
|
+
// In kiosk mode the chat pill lives in-canvas on the KioskShell, so we
|
|
2570
|
+
// never spawn the separate native pill toplevel. Outside kiosk, the pill
|
|
2571
|
+
// loads the same renderer in chat-overlay shell mode so the assistant
|
|
2572
|
+
// lives in its own OS-level window instead of inside the app.
|
|
2573
|
+
if (!isKioskShellMode() && shouldCreateDesktopPill()) {
|
|
2574
|
+
try {
|
|
2575
|
+
createPillWindow({ rendererUrl: url, preload });
|
|
2576
|
+
} catch (err) {
|
|
2577
|
+
logger.warn(
|
|
2578
|
+
`[Main] Failed to spawn pill window: ${err instanceof Error ? err.message : String(err)}`,
|
|
2579
|
+
);
|
|
2580
|
+
}
|
|
2581
|
+
}
|
|
2582
|
+
});
|
|
2583
|
+
|
|
2584
|
+
// Per-window RPC tracking: surface windows each get their own typed
|
|
2585
|
+
// RPC built up front via createDesktopRpc, baked into the BrowserWindow
|
|
2586
|
+
// constructor, then "wired" post-hoc by wireSettingsRpcAfterCreate.
|
|
2587
|
+
const surfaceRpcs = new WeakMap<ManagedWindowLike, ElizaDesktopRpc>();
|
|
2588
|
+
|
|
2589
|
+
surfaceWindowManager = new SurfaceWindowManager({
|
|
2590
|
+
createWindow: (options) => {
|
|
2591
|
+
const { rpc } = createDesktopRpc("surface");
|
|
2592
|
+
const window = createElectrobunBrowserWindow({
|
|
2593
|
+
...options,
|
|
2594
|
+
rpc,
|
|
2595
|
+
}) as BrowserWindow & ManagedWindowLike;
|
|
2596
|
+
surfaceRpcs.set(window, rpc);
|
|
2597
|
+
return window;
|
|
2598
|
+
},
|
|
2599
|
+
resolveRendererUrl,
|
|
2600
|
+
readPreload: () => readResolvedPreloadScript(import.meta.dir),
|
|
2601
|
+
wireRpc: (window) => {
|
|
2602
|
+
const rpc = surfaceRpcs.get(window);
|
|
2603
|
+
if (!rpc) {
|
|
2604
|
+
logger.warn(
|
|
2605
|
+
"[surface-windows] wireRpc called for window with no tracked rpc; skipping browser-workspace caller setup",
|
|
2606
|
+
);
|
|
2607
|
+
return;
|
|
2608
|
+
}
|
|
2609
|
+
wireSettingsRpcAfterCreate(rpc);
|
|
2610
|
+
},
|
|
2611
|
+
injectApiBase: (window) =>
|
|
2612
|
+
injectApiBase(window as BrowserWindow & ManagedWindowLike),
|
|
2613
|
+
onWindowFocused: (window) => {
|
|
2614
|
+
lastFocusedWindow = window;
|
|
2615
|
+
},
|
|
2616
|
+
onRegistryChanged: () => {
|
|
2617
|
+
sendManagedWindowsChanged();
|
|
2618
|
+
setupApplicationMenu();
|
|
2619
|
+
},
|
|
2620
|
+
boundsStore: createAppWindowBoundsStore(),
|
|
2621
|
+
});
|
|
2622
|
+
// Set up app menu after the window (and its message loop) exists.
|
|
2623
|
+
setupApplicationMenu();
|
|
2624
|
+
const stopScreenshotDevServer = startScreenshotDevServer();
|
|
2625
|
+
if (stopScreenshotDevServer) {
|
|
2626
|
+
cleanupFns.push(stopScreenshotDevServer);
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
// Wire detached window callbacks so menus and RPC can open them.
|
|
2630
|
+
getDesktopManager().setOpenSettingsCallback((tabHint) => {
|
|
2631
|
+
void createSettingsWindow(tabHint);
|
|
2632
|
+
});
|
|
2633
|
+
getDesktopManager().setRestoreMainWindowCallback(() => restoreWindow());
|
|
2634
|
+
getDesktopManager().setRequestQuitCallback(() => {
|
|
2635
|
+
requestAppQuit();
|
|
2636
|
+
});
|
|
2637
|
+
getDesktopManager().setOpenSurfaceWindowCallback(
|
|
2638
|
+
(surface, browse, alwaysOnTop) => {
|
|
2639
|
+
if (!surfaceWindowManager) {
|
|
2640
|
+
throw new Error("Surface window manager is not ready.");
|
|
2641
|
+
}
|
|
2642
|
+
return surfaceWindowManager.openSurfaceWindow(
|
|
2643
|
+
surface,
|
|
2644
|
+
browse,
|
|
2645
|
+
alwaysOnTop === true,
|
|
2646
|
+
);
|
|
2647
|
+
},
|
|
2648
|
+
);
|
|
2649
|
+
getDesktopManager().setOpenAppWindowCallback((options) => {
|
|
2650
|
+
if (!surfaceWindowManager) {
|
|
2651
|
+
throw new Error("Surface window manager is not ready.");
|
|
2652
|
+
}
|
|
2653
|
+
return surfaceWindowManager.openAppWindow(options);
|
|
2654
|
+
});
|
|
2655
|
+
getDesktopManager().setManagedWindowAlwaysOnTopCallback((id, flag) => {
|
|
2656
|
+
return surfaceWindowManager?.setWindowAlwaysOnTop(id, flag) ?? false;
|
|
2657
|
+
});
|
|
2658
|
+
|
|
2659
|
+
// If launched with --hidden (e.g. auto-launch with openAsHidden), minimize immediately.
|
|
2660
|
+
// In tray-first mode there is no window yet (mainWin is null) — nothing to minimize.
|
|
2661
|
+
if (mainWin && process.argv.includes("--hidden")) {
|
|
2662
|
+
try {
|
|
2663
|
+
mainWin.minimize();
|
|
2664
|
+
} catch (err) {
|
|
2665
|
+
logger.warn(
|
|
2666
|
+
`[Main] Failed to minimize window on --hidden startup: ${err instanceof Error ? err.message : String(err)}`,
|
|
2667
|
+
);
|
|
2668
|
+
}
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
setupDeepLinks();
|
|
2672
|
+
setupDockReopen();
|
|
2673
|
+
|
|
2674
|
+
const desktop = getDesktopManager();
|
|
2675
|
+
if (shouldCreateDesktopTray(process.env)) {
|
|
2676
|
+
try {
|
|
2677
|
+
// Tray is created here so the icon appears at startup, but the menu is
|
|
2678
|
+
// owned by the renderer (DesktopTrayRuntime + main.tsx → Desktop.setTrayMenu).
|
|
2679
|
+
// That keeps a single source of truth for tray items and their handlers.
|
|
2680
|
+
await desktop.createTray({
|
|
2681
|
+
icon: resolveDesktopAppIconPath(),
|
|
2682
|
+
tooltip: BRAND.appName,
|
|
2683
|
+
title: BRAND.appName,
|
|
2684
|
+
});
|
|
2685
|
+
} catch (err) {
|
|
2686
|
+
logger.warn(
|
|
2687
|
+
`[Main] Tray creation failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2688
|
+
);
|
|
2689
|
+
}
|
|
2690
|
+
} else {
|
|
2691
|
+
logger.info("[Main] Desktop tray disabled by environment");
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
// ── Steward sidecar startup (must happen BEFORE agent) ────────────
|
|
2695
|
+
// When STEWARD_LOCAL=true, start the steward sidecar first so it can
|
|
2696
|
+
// set STEWARD_API_URL / STEWARD_AGENT_TOKEN env vars. The the app agent's
|
|
2697
|
+
// steward-bridge.ts reads these on boot to discover local steward.
|
|
2698
|
+
if (isStewardLocalEnabled()) {
|
|
2699
|
+
logger.info("[Main] STEWARD_LOCAL=true — starting steward sidecar...");
|
|
2700
|
+
cleanupFns.push(() => stopSteward());
|
|
2701
|
+
|
|
2702
|
+
// Listen for steward status changes and push to renderer
|
|
2703
|
+
cleanupFns.push(
|
|
2704
|
+
onStewardStatusChange((status) => {
|
|
2705
|
+
sendToActiveRenderer("stewardStatusUpdate", status);
|
|
2706
|
+
}),
|
|
2707
|
+
);
|
|
2708
|
+
|
|
2709
|
+
try {
|
|
2710
|
+
const stewardResult = await startSteward();
|
|
2711
|
+
if (stewardResult.state === "running") {
|
|
2712
|
+
logger.info(
|
|
2713
|
+
`[Main] Steward sidecar ready on port ${stewardResult.port}, wallet: ${stewardResult.walletAddress ?? "pending"}`,
|
|
2714
|
+
);
|
|
2715
|
+
} else {
|
|
2716
|
+
logger.warn(
|
|
2717
|
+
`[Main] Steward sidecar in state "${stewardResult.state}": ${stewardResult.error ?? "unknown"}`,
|
|
2718
|
+
);
|
|
2719
|
+
sendToActiveRenderer("stewardStartupFailed", {
|
|
2720
|
+
error: stewardResult.error ?? "Steward failed to start",
|
|
2721
|
+
canRetry: true,
|
|
2722
|
+
});
|
|
2723
|
+
}
|
|
2724
|
+
} catch (err) {
|
|
2725
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
2726
|
+
logger.error(`[Main] Steward sidecar startup failed: ${error}`);
|
|
2727
|
+
sendToActiveRenderer("stewardStartupFailed", {
|
|
2728
|
+
error,
|
|
2729
|
+
canRetry: true,
|
|
2730
|
+
});
|
|
2731
|
+
// Don't block agent startup — steward is optional
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
// Agent startup: in external mode, push the API base via the
|
|
2736
|
+
// api-base-owner (the agent is already running externally). In local
|
|
2737
|
+
// mode, start the embedded agent first — apiBaseOwner.injectIntoHtml()
|
|
2738
|
+
// already set the initial window.__ELIZA_API_BASE__ from the seed value
|
|
2739
|
+
// in main(), but _startAgent will push the actual port once the agent
|
|
2740
|
+
// reports it.
|
|
2741
|
+
const rt = resolveDesktopRuntime();
|
|
2742
|
+
if (rt.mode === "external") {
|
|
2743
|
+
injectApiBaseIntoOpenRendererWindows();
|
|
2744
|
+
} else if (rt.mode === "local") {
|
|
2745
|
+
logger.info("[Main] Starting embedded agent (local mode).");
|
|
2746
|
+
_startAgent().catch((err) => {
|
|
2747
|
+
logger.error(
|
|
2748
|
+
`[Main] Agent auto-start failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2749
|
+
);
|
|
2750
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
2751
|
+
sendToActiveRenderer("agentStartupFailed", { error });
|
|
2752
|
+
console.error(`title: "${BRAND.appName} startup failed"`);
|
|
2753
|
+
});
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
void setupUpdater();
|
|
2757
|
+
cleanupFns.push(() => getAgentManager().stop());
|
|
2758
|
+
setupShutdown();
|
|
2300
2759
|
}
|
|
2301
2760
|
|
|
2302
2761
|
function resolveStartupCrashReportPath(): string {
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2762
|
+
return path.join(
|
|
2763
|
+
path.dirname(getDiagnosticLogPath()),
|
|
2764
|
+
STARTUP_CRASH_REPORT_FILE,
|
|
2765
|
+
);
|
|
2307
2766
|
}
|
|
2308
2767
|
|
|
2309
2768
|
function resolveStartupCrashPromptMarkerPath(): string {
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2769
|
+
return path.join(
|
|
2770
|
+
path.dirname(getDiagnosticLogPath()),
|
|
2771
|
+
STARTUP_CRASH_PROMPT_MARKER_FILE,
|
|
2772
|
+
);
|
|
2314
2773
|
}
|
|
2315
2774
|
|
|
2316
2775
|
function buildStartupCrashDiscordReport(options: {
|
|
2317
|
-
|
|
2318
|
-
|
|
2776
|
+
source: "startup-recovery" | "fatal-startup";
|
|
2777
|
+
error: string | null;
|
|
2319
2778
|
}): string {
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2779
|
+
const diagnostics = getStartupDiagnosticsSnapshot();
|
|
2780
|
+
const startupLogTail = getStartupDiagnosticLogTail(8_000).trim();
|
|
2781
|
+
const appVersion = process.env.npm_package_version?.trim() || "unknown";
|
|
2782
|
+
const appRuntime = `electrobun/${Bun.version}`;
|
|
2783
|
+
const reportLines = [
|
|
2784
|
+
`${BRAND.appName} startup crash report`,
|
|
2785
|
+
"",
|
|
2786
|
+
"Share this report in Discord and ping @iono.",
|
|
2787
|
+
"",
|
|
2788
|
+
`Source: ${options.source}`,
|
|
2789
|
+
`Timestamp: ${new Date().toISOString()}`,
|
|
2790
|
+
`App Version: ${appVersion}`,
|
|
2791
|
+
`Runtime: ${appRuntime}`,
|
|
2792
|
+
`Platform: ${process.platform} ${process.arch}`,
|
|
2793
|
+
`State: ${diagnostics.state}`,
|
|
2794
|
+
`Phase: ${diagnostics.phase}`,
|
|
2795
|
+
`Last Error: ${options.error ?? diagnostics.lastError ?? "unknown"}`,
|
|
2796
|
+
`Updated At: ${diagnostics.updatedAt}`,
|
|
2797
|
+
`Log Path: ${diagnostics.logPath}`,
|
|
2798
|
+
`Status Path: ${diagnostics.statusPath}`,
|
|
2799
|
+
"",
|
|
2800
|
+
startupLogTail ? "Startup Log Tail:" : "Startup Log Tail: unavailable",
|
|
2801
|
+
];
|
|
2802
|
+
|
|
2803
|
+
if (startupLogTail) {
|
|
2804
|
+
reportLines.push("```");
|
|
2805
|
+
reportLines.push(startupLogTail);
|
|
2806
|
+
reportLines.push("```");
|
|
2807
|
+
}
|
|
2808
|
+
return `${reportLines.join("\n")}\n`;
|
|
2350
2809
|
}
|
|
2351
2810
|
|
|
2352
2811
|
function persistStartupCrashReport(options: {
|
|
2353
|
-
|
|
2354
|
-
|
|
2812
|
+
source: "startup-recovery" | "fatal-startup";
|
|
2813
|
+
error: string | null;
|
|
2355
2814
|
}): { report: string; reportPath: string } {
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2815
|
+
const report = buildStartupCrashDiscordReport(options);
|
|
2816
|
+
const primaryReportPath = resolveStartupCrashReportPath();
|
|
2817
|
+
const fallbackReportPath = path.join(os.tmpdir(), STARTUP_CRASH_REPORT_FILE);
|
|
2818
|
+
let reportPath = primaryReportPath;
|
|
2819
|
+
try {
|
|
2820
|
+
fs.mkdirSync(path.dirname(primaryReportPath), { recursive: true });
|
|
2821
|
+
fs.writeFileSync(primaryReportPath, report, "utf8");
|
|
2822
|
+
} catch (err) {
|
|
2823
|
+
logger.warn(
|
|
2824
|
+
`[Main] Failed to write startup crash report: ${err instanceof Error ? err.message : String(err)}`,
|
|
2825
|
+
);
|
|
2826
|
+
try {
|
|
2827
|
+
fs.mkdirSync(path.dirname(fallbackReportPath), { recursive: true });
|
|
2828
|
+
fs.writeFileSync(fallbackReportPath, report, "utf8");
|
|
2829
|
+
reportPath = fallbackReportPath;
|
|
2830
|
+
} catch (fallbackErr) {
|
|
2831
|
+
logger.warn(
|
|
2832
|
+
`[Main] Failed to write fallback startup crash report: ${fallbackErr instanceof Error ? fallbackErr.message : String(fallbackErr)}`,
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
return { report, reportPath };
|
|
2378
2837
|
}
|
|
2379
2838
|
|
|
2380
2839
|
function wasStartupCrashAlreadyPrompted(updatedAt: string): boolean {
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2840
|
+
try {
|
|
2841
|
+
const markerPath = resolveStartupCrashPromptMarkerPath();
|
|
2842
|
+
return fs.readFileSync(markerPath, "utf8").trim() === updatedAt;
|
|
2843
|
+
} catch {
|
|
2844
|
+
return false;
|
|
2845
|
+
}
|
|
2387
2846
|
}
|
|
2388
2847
|
|
|
2389
2848
|
function markStartupCrashPrompted(updatedAt: string): void {
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2849
|
+
try {
|
|
2850
|
+
fs.writeFileSync(resolveStartupCrashPromptMarkerPath(), updatedAt, "utf8");
|
|
2851
|
+
} catch {}
|
|
2393
2852
|
}
|
|
2394
2853
|
|
|
2395
2854
|
async function maybePromptStartupCrashReport(): Promise<void> {
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2855
|
+
if (
|
|
2856
|
+
process.env.ELIZA_DESKTOP_SKIP_STARTUP_CRASH_PROMPT === "1" ||
|
|
2857
|
+
process.env.ELIZA_DESKTOP_TEST_AUTO_CONFIRM_DIALOGS === "1"
|
|
2858
|
+
) {
|
|
2859
|
+
return;
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2862
|
+
const diagnostics = getStartupDiagnosticsSnapshot();
|
|
2863
|
+
const looksLikeStartupFailure =
|
|
2864
|
+
diagnostics.state === "error" &&
|
|
2865
|
+
diagnostics.phase !== "ready" &&
|
|
2866
|
+
diagnostics.phase !== "stopped";
|
|
2867
|
+
if (!looksLikeStartupFailure) {
|
|
2868
|
+
return;
|
|
2869
|
+
}
|
|
2870
|
+
if (wasStartupCrashAlreadyPrompted(diagnostics.updatedAt)) {
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
const { report, reportPath } = persistStartupCrashReport({
|
|
2875
|
+
source: "startup-recovery",
|
|
2876
|
+
error: diagnostics.lastError,
|
|
2877
|
+
});
|
|
2878
|
+
markStartupCrashPrompted(diagnostics.updatedAt);
|
|
2879
|
+
|
|
2880
|
+
const dialog = await Utils.showMessageBox({
|
|
2881
|
+
type: "warning",
|
|
2882
|
+
title: `${BRAND.appName} recovered after a startup failure`,
|
|
2883
|
+
message:
|
|
2884
|
+
"The previous launch failed. A crash report is ready to share with support.",
|
|
2885
|
+
detail:
|
|
2886
|
+
"Choose Copy Report, paste into Discord, and ping @iono. You can also open logs.",
|
|
2887
|
+
buttons: ["Copy Report", "Open Logs Folder", "Continue"],
|
|
2888
|
+
defaultId: 0,
|
|
2889
|
+
cancelId: 2,
|
|
2890
|
+
});
|
|
2891
|
+
const response =
|
|
2892
|
+
dialog && typeof dialog === "object" && "response" in dialog
|
|
2893
|
+
? (dialog as { response: number }).response
|
|
2894
|
+
: typeof dialog === "number"
|
|
2895
|
+
? dialog
|
|
2896
|
+
: 2;
|
|
2897
|
+
|
|
2898
|
+
if (response === 0) {
|
|
2899
|
+
try {
|
|
2900
|
+
Utils.clipboardWriteText(report);
|
|
2901
|
+
Utils.showNotification({
|
|
2902
|
+
title: "Crash report copied",
|
|
2903
|
+
body: "Paste in Discord and ping @iono.",
|
|
2904
|
+
});
|
|
2905
|
+
} catch (err) {
|
|
2906
|
+
logger.warn(
|
|
2907
|
+
`[Main] Failed to copy startup crash report: ${err instanceof Error ? err.message : String(err)}`,
|
|
2908
|
+
);
|
|
2909
|
+
}
|
|
2910
|
+
} else if (response === 1) {
|
|
2911
|
+
try {
|
|
2912
|
+
Utils.openPath(path.dirname(reportPath));
|
|
2913
|
+
} catch (err) {
|
|
2914
|
+
logger.warn(
|
|
2915
|
+
`[Main] Failed to open startup logs folder: ${err instanceof Error ? err.message : String(err)}`,
|
|
2916
|
+
);
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2460
2919
|
}
|
|
2461
2920
|
|
|
2462
2921
|
main().catch((err) => {
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2922
|
+
const msg = `[Main] Fatal error during startup: ${err?.stack ?? err}`;
|
|
2923
|
+
console.error(msg);
|
|
2924
|
+
recordStartupPhase("fatal", {
|
|
2925
|
+
pid: process.pid,
|
|
2926
|
+
exec_path: process.execPath,
|
|
2927
|
+
bundle_path: resolveStartupBundlePath(process.execPath),
|
|
2928
|
+
error: err instanceof Error ? err.stack || err.message : String(err),
|
|
2929
|
+
});
|
|
2930
|
+
persistStartupCrashReport({
|
|
2931
|
+
source: "fatal-startup",
|
|
2932
|
+
error: msg,
|
|
2933
|
+
});
|
|
2934
|
+
recordStartupPhase("fatal", {
|
|
2935
|
+
pid: process.pid,
|
|
2936
|
+
exec_path: process.execPath,
|
|
2937
|
+
bundle_path: resolveStartupBundlePath(process.execPath),
|
|
2938
|
+
error: err instanceof Error ? err.stack || err.message : String(err),
|
|
2939
|
+
});
|
|
2940
|
+
// Write to startup log so it's visible even without a console
|
|
2941
|
+
try {
|
|
2942
|
+
const logPath = getDiagnosticLogPath();
|
|
2943
|
+
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
2944
|
+
fs.appendFileSync(logPath, `[${new Date().toISOString()}] ${msg}\n`);
|
|
2945
|
+
fs.writeFileSync(
|
|
2946
|
+
getStartupStatusPath(),
|
|
2947
|
+
`${JSON.stringify(
|
|
2948
|
+
{
|
|
2949
|
+
state: "error",
|
|
2950
|
+
phase: "fatal_startup",
|
|
2951
|
+
updatedAt: new Date().toISOString(),
|
|
2952
|
+
lastError: msg,
|
|
2953
|
+
platform: process.platform,
|
|
2954
|
+
arch: process.arch,
|
|
2955
|
+
logPath,
|
|
2956
|
+
statusPath: getStartupStatusPath(),
|
|
2957
|
+
},
|
|
2958
|
+
null,
|
|
2959
|
+
2,
|
|
2960
|
+
)}\n`,
|
|
2961
|
+
"utf8",
|
|
2962
|
+
);
|
|
2963
|
+
} catch {}
|
|
2964
|
+
void runShutdownCleanup("fatal-startup").finally(shutdownAfterFatalError);
|
|
2506
2965
|
});
|
|
2507
2966
|
|
|
2508
2967
|
import { shutdownAfterFatalError } from "./fatal-shutdown";
|