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