@elizaos/app-core 2.0.3-beta.2 → 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 +5 -5
- package/api/auth/audit.d.ts +1 -1
- package/api/auth/auth-context.d.ts +1 -1
- package/api/auth/bootstrap-token.d.ts +1 -1
- package/api/auth/sessions.d.ts +1 -1
- package/api/auth-bootstrap-routes.d.ts +1 -1
- package/api/auth-pairing-routes.d.ts +1 -1
- package/api/auth-pairing-routes.d.ts.map +1 -1
- package/api/auth-pairing-routes.js +2 -3
- package/api/auth-session-routes.d.ts +2 -2
- package/api/auth.d.ts +1 -1
- package/api/automations-compat-routes.d.ts +1 -1
- package/api/background-tasks-routes.d.ts +1 -1
- package/api/catalog-routes.d.ts +1 -1
- package/api/cloud-voice-routes.d.ts +1 -1
- package/api/compat-route-shared.d.ts +12 -5
- package/api/compat-route-shared.d.ts.map +1 -1
- package/api/compat-route-shared.js +22 -187
- package/api/database-rows-compat-routes.d.ts +1 -1
- package/api/dev-compat-routes.d.ts +1 -1
- package/api/dev-route-catalog.d.ts.map +1 -1
- package/api/dev-route-catalog.js +20 -0
- 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 +1 -1
- package/api/internal-routes.d.ts +1 -1
- package/api/runtime-mode-routes.d.ts +1 -1
- package/api/secrets-manager-routes.d.ts.map +1 -1
- package/api/sensitive-request-routes.d.ts +2 -2
- package/api/server-config-filter.d.ts.map +1 -1
- package/api/server-config-filter.js +0 -1
- package/api/server-first-run-helpers.d.ts.map +1 -1
- package/api/server-first-run-helpers.js +0 -3
- package/api/server.d.ts +8 -8
- package/api/server.d.ts.map +1 -1
- package/api/server.js +13 -59
- package/api/training-benchmarks.d.ts +1 -1
- package/api/training-benchmarks.d.ts.map +1 -1
- package/api/training-benchmarks.js +31 -9
- package/api/workbench-compat-routes.d.ts +1 -1
- package/benchmark/server-utils.d.ts +2 -2
- package/browser.d.ts +4 -4
- package/cli/plugins-cli.d.ts.map +1 -1
- package/cli/plugins-cli.js +5 -0
- 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 +187 -0
- package/cli/program/register.dashboard.d.ts.map +1 -1
- package/cli/program/register.dashboard.js +11 -1
- package/cli/program.d.ts +1 -1
- package/first-run/first-run-config.d.ts +1 -1
- package/index.d.ts +46 -47
- package/index.d.ts.map +1 -1
- package/index.js +3 -7
- package/package.json +42 -36
- package/packaging/PUBLISHING_GUIDE.md +20 -20
- package/platform/elizaos-agent-browser-stub.d.ts +0 -1
- package/platform/elizaos-agent-browser-stub.d.ts.map +1 -1
- package/platform/elizaos-agent-browser-stub.js +0 -1
- package/platform/ios-runtime-bridge.d.ts.map +1 -1
- package/platform/ios-runtime-bridge.js +0 -1
- package/platform/native-plugin-entrypoints.d.ts +2 -2
- package/platforms/android/app/build.gradle +30 -7
- package/platforms/android/app/src/main/elizavoice-jni/elizavoice-jni.cpp +179 -35
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaAgentService.java +60 -32
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaBionicInferenceServer.java +405 -65
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoiceNative.java +35 -0
- package/platforms/android/app/src/main/java/ai/elizaos/app/ElizaVoicePlugin.java +13 -6
- 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/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/colors.xml +5 -1
- package/platforms/android/app/src/main/res/values/ic_launcher_background.xml +1 -1
- package/platforms/android/app/src/main/res/values/styles.xml +4 -1
- package/platforms/electrobun/electrobun.config.ts +0 -1
- package/platforms/electrobun/native/macos/window-effects.mm +4 -0
- package/platforms/electrobun/package.json +11 -9
- package/platforms/electrobun/remotes/local-model/src/bun/eliza1-catalog.ts +1 -1
- package/platforms/electrobun/remotes/runtime/src/dev/phase2-smoke.ts +10 -5
- package/platforms/electrobun/remotes/runtime/src/dev/phase3-smoke.ts +11 -15
- package/platforms/electrobun/src/application-menu.ts +0 -7
- package/platforms/electrobun/src/desktop-http-request.test.ts +30 -1
- package/platforms/electrobun/src/desktop-http-request.ts +14 -2
- package/platforms/electrobun/src/desktop-test-bridge-server.ts +28 -0
- package/platforms/electrobun/src/fatal-shutdown.test.ts +3 -7
- package/platforms/electrobun/src/index.ts +64 -13
- package/platforms/electrobun/src/lifecycle/api-base-owner.test.ts +83 -0
- package/platforms/electrobun/src/lifecycle/api-base-owner.ts +37 -16
- package/platforms/electrobun/src/native/agent.ts +28 -17
- package/platforms/electrobun/src/native/credentials.ts +6 -1
- package/platforms/electrobun/src/native/desktop-window.test.ts +142 -26
- package/platforms/electrobun/src/native/desktop.ts +8 -4
- package/platforms/electrobun/src/native/index.ts +6 -0
- package/platforms/electrobun/src/native/remote-plugin-host.ts +18 -8
- package/platforms/electrobun/src/preload.js +1 -1
- package/platforms/electrobun/src/voice/voice-live-validation.test.ts +10 -5
- package/platforms/electrobun/src/voice/voice-runtime-adapter.ts +3 -2
- package/platforms/electrobun/src/voice/voice-service.test.ts +26 -0
- package/platforms/electrobun/src/voice/voice-service.ts +57 -17
- package/platforms/electrobun/tsconfig.json +17 -1
- package/platforms/ios/App/App/Base.lproj/LaunchScreen.storyboard +4 -6
- package/registry/index.d.ts +1 -6
- package/registry/index.d.ts.map +1 -1
- package/registry/index.js +9 -101
- package/runtime/android-avf-microdroid-bridge.d.ts +1 -1
- 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/index.d.ts +5 -5
- package/runtime/dev-server.js +11 -2
- package/runtime/eliza.d.ts.map +1 -1
- package/runtime/eliza.js +18 -8
- package/runtime/mode/route-mode-guard.d.ts +1 -1
- package/runtime/mode/route-mode-matrix.d.ts +1 -1
- package/runtime/voice-warmup.d.ts +4 -19
- package/runtime/voice-warmup.d.ts.map +1 -1
- package/runtime/voice-warmup.js +4 -14
- package/scripts/aosp/README.md +10 -1
- package/scripts/aosp/compile-libllama-zig-pin.test.mjs +147 -0
- package/scripts/aosp/compile-libllama.mjs +446 -59
- package/scripts/aosp/compile-libllama.test.mjs +133 -0
- package/scripts/aosp/compile-shim.mjs +21 -1
- package/scripts/aosp/deploy-pixel.mjs +1 -1
- package/scripts/aosp/stage-default-models.mjs +24 -31
- package/scripts/aosp/stage-default-models.test.mjs +23 -0
- package/scripts/assert-required-bundled-packages.test.ts +22 -1
- package/scripts/build-helpers/verify-fused-symbols.mjs +33 -0
- package/scripts/build-helpers/verify-fused-symbols.test.mjs +0 -0
- package/scripts/build-image.sh +1 -3
- package/scripts/build-llama-cpp-mtp.mjs +17 -16
- package/scripts/check-i18n.mjs +0 -1
- package/scripts/copy-runtime-node-modules.ts +147 -0
- package/scripts/desktop-build.mjs +317 -4
- package/scripts/docker-ci-smoke.sh +33 -8
- package/scripts/ensure-type-package-aliases.mjs +1 -1
- package/scripts/ios-xcframework/run-physical-device-smoke.mjs +1 -1
- package/scripts/lib/agent-source-watcher.mjs +0 -1
- 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/duet-bridge.mjs +1 -1
- package/scripts/lib/ios-plist-url-scheme.mjs +80 -0
- package/scripts/lib/mobile-build-decisions.mjs +97 -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 +13 -4
- 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/websocket-pending-queue.ts +92 -0
- package/scripts/link-docker-local-app-packages.mjs +6 -0
- package/scripts/playwright-ui-live-stack.ts +430 -144
- package/scripts/playwright-ui-smoke-api-stub.mjs +160 -168
- package/scripts/run-local-plugin-live-smoke.mjs +1 -6
- 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 +408 -86
- package/scripts/serve-real-local-agent.ts +72 -0
- package/scripts/stage-desktop-fused-lib.mjs +43 -14
- package/scripts/verify-ondevice-artifact.mjs +111 -0
- package/scripts/voice-attribution-smoke.ts +144 -38
- package/scripts/voice-duet.mjs +6 -6
- package/scripts/voice-e2e-hardware.ts +22 -16
- package/scripts/voice-interactive.mjs +16 -45
- package/security/agent-vault-id.d.ts +1 -1
- package/security/platform-secure-store-node.d.ts +1 -1
- package/services/ambient-audio/consent.d.ts +1 -1
- package/services/ambient-audio/index.d.ts +6 -6
- package/services/ambient-audio/replay-buffer.d.ts +1 -1
- package/services/ambient-audio/response-gate.d.ts +1 -1
- package/services/ambient-audio/service.d.ts +3 -3
- package/services/connector-target-catalog.d.ts +1 -1
- package/services/sensitive-requests/index.d.ts +6 -6
- package/services/steward-sidecar/wallet-setup.d.ts +1 -1
- package/services/steward-sidecar.d.ts +3 -3
- package/services/tunnel-to-mobile/index.d.ts +1 -1
- package/services/vault-bootstrap.d.ts.map +1 -1
- package/services/vault-bootstrap.js +14 -10
- package/services/voice-profiles/diarization-pipeline.d.ts +1 -1
- package/services/voice-profiles/index.d.ts +11 -11
- package/services/voice-profiles/owner-confidence.d.ts +1 -1
- package/services/voice-profiles/private-challenge.d.ts +1 -1
- package/services/voice-profiles/store.d.ts +1 -1
- package/test/helpers/live-provider.test.ts +91 -1
- package/test/helpers/live-provider.ts +195 -51
- 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 +1 -0
- package/ui-compat.d.ts.map +1 -1
- package/ui-compat.js +4 -0
- package/platforms/electrobun/docs/convergence-audit.json +0 -3505
- package/platforms/electrobun/docs/convergence-audit.md +0 -694
- package/platforms/electrobun/scripts/ensure-whisper-gguf.sh +0 -55
- package/platforms/electrobun/scripts/ensure-whisper-model.sh +0 -35
- package/platforms/electrobun/scripts/generate-convergence-audit.ts +0 -1203
- package/platforms/electrobun/src/native/whisper-env.test.ts +0 -71
- package/platforms/electrobun/src/native/whisper-env.ts +0 -68
- package/registry/app-registry.d.ts +0 -14
- package/registry/app-registry.d.ts.map +0 -1
- package/registry/app-registry.js +0 -29
- package/registry/entries/apps/app-polymarket.json +0 -31
- package/registry/entries/apps/clawville.json +0 -27
- package/registry/entries/apps/companion.json +0 -28
- package/registry/entries/apps/database-viewer.json +0 -27
- package/registry/entries/apps/defense-of-the-agents.json +0 -27
- package/registry/entries/apps/documents.json +0 -30
- package/registry/entries/apps/feed.json +0 -27
- package/registry/entries/apps/hyperliquid.json +0 -31
- package/registry/entries/apps/log-viewer.json +0 -27
- package/registry/entries/apps/memory-viewer.json +0 -27
- package/registry/entries/apps/model-tester.json +0 -31
- package/registry/entries/apps/plugin-viewer.json +0 -27
- package/registry/entries/apps/relationship-viewer.json +0 -27
- package/registry/entries/apps/runtime-debugger.json +0 -27
- package/registry/entries/apps/shopify.json +0 -31
- package/registry/entries/apps/skills-viewer.json +0 -27
- package/registry/entries/apps/steward.json +0 -31
- package/registry/entries/apps/training.json +0 -54
- package/registry/entries/apps/trajectory-viewer.json +0 -27
- package/registry/entries/apps/vincent.json +0 -31
- package/registry/entries/connectors/bluebubbles.json +0 -99
- package/registry/entries/connectors/bluesky.json +0 -173
- package/registry/entries/connectors/discord.json +0 -119
- package/registry/entries/connectors/farcaster.json +0 -174
- package/registry/entries/connectors/feishu.json +0 -79
- package/registry/entries/connectors/google-chat.json +0 -120
- package/registry/entries/connectors/google.json +0 -82
- package/registry/entries/connectors/imessage.json +0 -96
- package/registry/entries/connectors/instagram.json +0 -64
- package/registry/entries/connectors/line.json +0 -86
- package/registry/entries/connectors/matrix.json +0 -94
- package/registry/entries/connectors/mattermost.json +0 -110
- package/registry/entries/connectors/msteams.json +0 -104
- package/registry/entries/connectors/nextcloud-talk.json +0 -104
- package/registry/entries/connectors/nostr.json +0 -70
- package/registry/entries/connectors/signal.json +0 -81
- package/registry/entries/connectors/slack.json +0 -102
- package/registry/entries/connectors/telegram.json +0 -71
- package/registry/entries/connectors/tlon.json +0 -94
- package/registry/entries/connectors/twitch.json +0 -110
- package/registry/entries/connectors/whatsapp.json +0 -113
- package/registry/entries/connectors/x.json +0 -231
- package/registry/entries/connectors/zalo.json +0 -112
- package/registry/entries/connectors/zalouser.json +0 -122
- package/registry/entries/plugins/agent-orchestrator.json +0 -33
- package/registry/entries/plugins/agent-skills.json +0 -72
- package/registry/entries/plugins/anthropic.json +0 -73
- package/registry/entries/plugins/app-control.json +0 -23
- package/registry/entries/plugins/auto-trader.json +0 -203
- package/registry/entries/plugins/background-runner.json +0 -26
- package/registry/entries/plugins/blooio.json +0 -102
- package/registry/entries/plugins/browser.json +0 -75
- package/registry/entries/plugins/cli.json +0 -40
- package/registry/entries/plugins/clipboard.json +0 -44
- package/registry/entries/plugins/coding-tools.json +0 -71
- package/registry/entries/plugins/commands.json +0 -63
- package/registry/entries/plugins/computeruse.json +0 -74
- package/registry/entries/plugins/copilot-proxy.json +0 -93
- package/registry/entries/plugins/directives.json +0 -63
- package/registry/entries/plugins/edge-tts.json +0 -97
- package/registry/entries/plugins/elevenlabs.json +0 -169
- package/registry/entries/plugins/elizacloud.json +0 -208
- package/registry/entries/plugins/evm.json +0 -134
- package/registry/entries/plugins/experience.json +0 -34
- package/registry/entries/plugins/facewear.json +0 -131
- package/registry/entries/plugins/form.json +0 -26
- package/registry/entries/plugins/github.json +0 -93
- package/registry/entries/plugins/gmail-watch.json +0 -25
- package/registry/entries/plugins/goals.json +0 -77
- package/registry/entries/plugins/google-genai.json +0 -106
- package/registry/entries/plugins/groq.json +0 -93
- package/registry/entries/plugins/hedera.json +0 -48
- package/registry/entries/plugins/inmemorydb.json +0 -25
- package/registry/entries/plugins/linear.json +0 -51
- package/registry/entries/plugins/local-inference.json +0 -137
- package/registry/entries/plugins/local-storage.json +0 -36
- package/registry/entries/plugins/localdb.json +0 -25
- package/registry/entries/plugins/mcp.json +0 -44
- package/registry/entries/plugins/memory.json +0 -124
- package/registry/entries/plugins/minecraft.json +0 -79
- package/registry/entries/plugins/moltbook.json +0 -83
- package/registry/entries/plugins/music.json +0 -155
- package/registry/entries/plugins/mysticism.json +0 -48
- package/registry/entries/plugins/nearai.json +0 -82
- package/registry/entries/plugins/ngrok.json +0 -69
- package/registry/entries/plugins/ollama.json +0 -96
- package/registry/entries/plugins/openai.json +0 -189
- package/registry/entries/plugins/openrouter.json +0 -188
- package/registry/entries/plugins/pdf.json +0 -26
- package/registry/entries/plugins/plugin-manager.json +0 -23
- package/registry/entries/plugins/prose.json +0 -48
- package/registry/entries/plugins/rlm.json +0 -26
- package/registry/entries/plugins/roblox.json +0 -88
- package/registry/entries/plugins/rss.json +0 -64
- package/registry/entries/plugins/s3-storage.json +0 -91
- package/registry/entries/plugins/scheduling.json +0 -35
- package/registry/entries/plugins/shell.json +0 -94
- package/registry/entries/plugins/social-alpha.json +0 -72
- package/registry/entries/plugins/tailscale.json +0 -81
- package/registry/entries/plugins/tee.json +0 -53
- package/registry/entries/plugins/todos.json +0 -26
- package/registry/entries/plugins/trajectory-logger.json +0 -33
- package/registry/entries/plugins/trust.json +0 -39
- package/registry/entries/plugins/tts.json +0 -71
- package/registry/entries/plugins/tunnel.json +0 -45
- package/registry/entries/plugins/twilio.json +0 -168
- package/registry/entries/plugins/vercel-ai-gateway.json +0 -128
- package/registry/entries/plugins/video.json +0 -23
- package/registry/entries/plugins/vision.json +0 -43
- package/registry/entries/plugins/webhooks.json +0 -23
- package/registry/entries/plugins/workflow.json +0 -25
- package/registry/entries/plugins/xai.json +0 -75
- package/registry/loader.d.ts +0 -28
- package/registry/loader.d.ts.map +0 -1
- package/registry/loader.js +0 -158
- package/registry/schema.d.ts +0 -1199
- package/registry/schema.d.ts.map +0 -1
- package/registry/schema.js +0 -300
- package/scripts/patches/llama-mobile-kokoro-tts.patch +0 -480
- package/scripts/release-workflow-drift.test.ts +0 -57
- 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
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import {
|
|
2
|
+
import { existsSync, rmSync } from "node:fs";
|
|
3
|
+
import {
|
|
4
|
+
access,
|
|
5
|
+
cp,
|
|
6
|
+
mkdir,
|
|
7
|
+
mkdtemp,
|
|
8
|
+
readFile,
|
|
9
|
+
rm,
|
|
10
|
+
writeFile,
|
|
11
|
+
} from "node:fs/promises";
|
|
4
12
|
import {
|
|
5
13
|
createServer,
|
|
6
14
|
type IncomingMessage,
|
|
@@ -12,13 +20,22 @@ import path from "node:path";
|
|
|
12
20
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
13
21
|
import { WebSocket, WebSocketServer } from "ws";
|
|
14
22
|
import { buildFirstRunRuntimeConfig } from "../src/first-run/first-run-config.ts";
|
|
23
|
+
import { createLiveRuntimeChildEnv } from "../test/helpers/live-child-env.ts";
|
|
15
24
|
import {
|
|
16
25
|
getFirstRunProviderForLiveProvider,
|
|
17
|
-
|
|
26
|
+
selectLiveProviderAsync,
|
|
18
27
|
} from "../test/helpers/live-provider.ts";
|
|
19
28
|
import { resolveMainAppDir } from "./lib/app-dir.mjs";
|
|
20
29
|
import { shouldForceStubStack } from "./lib/ui-smoke-stub-decision.mjs";
|
|
21
30
|
import { viteRendererBuildNeeded } from "./lib/vite-renderer-dist-stale.mjs";
|
|
31
|
+
import {
|
|
32
|
+
clearPendingWebSocketQueue,
|
|
33
|
+
createPendingWebSocketQueueState,
|
|
34
|
+
DEFAULT_PENDING_WEBSOCKET_QUEUE_LIMITS,
|
|
35
|
+
drainPendingWebSocketQueue,
|
|
36
|
+
enqueuePendingWebSocketMessage,
|
|
37
|
+
type WebSocketSendData,
|
|
38
|
+
} from "./lib/websocket-pending-queue.ts";
|
|
22
39
|
|
|
23
40
|
const REPO_ROOT = path.resolve(import.meta.dirname, "..", "..", "..");
|
|
24
41
|
const APP_DIR = resolveMainAppDir(REPO_ROOT, "app");
|
|
@@ -36,12 +53,55 @@ const UI_SMOKE_STUB_SCRIPT = path.join(
|
|
|
36
53
|
const READY_TIMEOUT_MS = 180_000;
|
|
37
54
|
const API_PORT = Number(process.env.ELIZA_UI_SMOKE_API_PORT ?? "31337");
|
|
38
55
|
const UI_PORT = Number(process.env.ELIZA_UI_SMOKE_PORT ?? "2138");
|
|
39
|
-
const
|
|
56
|
+
const UI_SMOKE_RUN_ID = process.env.ELIZA_UI_SMOKE_RUN_ID?.trim() ?? "";
|
|
57
|
+
const LIVE_PROVIDER = await selectLiveProviderAsync();
|
|
40
58
|
// Precedence (force-stub > live opt-in > CI default) lives in one tested helper.
|
|
41
59
|
// The key behavior: ELIZA_UI_SMOKE_LIVE_STACK=1 overrides the CI-based stub force
|
|
42
60
|
// so a genuinely-real lane is possible (GitHub Actions always sets CI=true, which
|
|
43
61
|
// would otherwise re-force the stub even when a provider key was supplied).
|
|
44
62
|
const FORCE_STUB_STACK = shouldForceStubStack(process.env);
|
|
63
|
+
const LIVE_STACK_OPTIONAL_VIEW_PLUGIN_ENTRIES = [
|
|
64
|
+
"calendar",
|
|
65
|
+
"inbox",
|
|
66
|
+
"todos",
|
|
67
|
+
"wallet-ui",
|
|
68
|
+
] as const;
|
|
69
|
+
const LIVE_STACK_OPTIONAL_VIEW_PLUGIN_PACKAGES: ReadonlyArray<{
|
|
70
|
+
id: (typeof LIVE_STACK_OPTIONAL_VIEW_PLUGIN_ENTRIES)[number];
|
|
71
|
+
dir: string;
|
|
72
|
+
requiredBuildOutputs: readonly string[];
|
|
73
|
+
}> = [
|
|
74
|
+
{
|
|
75
|
+
id: "calendar",
|
|
76
|
+
dir: "plugin-calendar",
|
|
77
|
+
requiredBuildOutputs: [
|
|
78
|
+
"dist/index.js",
|
|
79
|
+
"dist/plugin.js",
|
|
80
|
+
"dist/views/bundle.js",
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: "inbox",
|
|
85
|
+
dir: "plugin-inbox",
|
|
86
|
+
requiredBuildOutputs: [
|
|
87
|
+
"dist/index.js",
|
|
88
|
+
"dist/plugin.js",
|
|
89
|
+
"dist/views/bundle.js",
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "todos",
|
|
94
|
+
dir: "plugin-todos",
|
|
95
|
+
requiredBuildOutputs: ["dist/index.js", "dist/views/bundle.js"],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: "wallet-ui",
|
|
99
|
+
dir: "plugin-wallet-ui",
|
|
100
|
+
requiredBuildOutputs: ["dist/index.js", "dist/views/bundle.js"],
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
const pendingStateDirs = new Set<string>();
|
|
104
|
+
const ownedStateDirs = new Set<string>();
|
|
45
105
|
|
|
46
106
|
type StartedStack = {
|
|
47
107
|
apiBase: string;
|
|
@@ -51,6 +111,45 @@ type StartedStack = {
|
|
|
51
111
|
uiServer: Server;
|
|
52
112
|
};
|
|
53
113
|
|
|
114
|
+
async function createStateDir(prefix: string): Promise<string> {
|
|
115
|
+
const stateDir = await mkdtemp(path.join(os.tmpdir(), prefix));
|
|
116
|
+
pendingStateDirs.add(stateDir);
|
|
117
|
+
if (UI_SMOKE_RUN_ID) {
|
|
118
|
+
await writeFile(
|
|
119
|
+
path.join(stateDir, ".eliza-ui-smoke-run-id"),
|
|
120
|
+
`${UI_SMOKE_RUN_ID}\n`,
|
|
121
|
+
"utf8",
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return stateDir;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function markStateDirOwnedByStack(stateDir: string): void {
|
|
128
|
+
pendingStateDirs.delete(stateDir);
|
|
129
|
+
ownedStateDirs.add(stateDir);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function cleanupPendingStateDirs(): Promise<void> {
|
|
133
|
+
const stateDirs = Array.from(pendingStateDirs);
|
|
134
|
+
pendingStateDirs.clear();
|
|
135
|
+
await Promise.all(
|
|
136
|
+
stateDirs.map((stateDir) => rm(stateDir, { force: true, recursive: true })),
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function cleanupKnownStateDirsSync(): void {
|
|
141
|
+
const stateDirs = new Set([...pendingStateDirs, ...ownedStateDirs]);
|
|
142
|
+
pendingStateDirs.clear();
|
|
143
|
+
ownedStateDirs.clear();
|
|
144
|
+
for (const stateDir of stateDirs) {
|
|
145
|
+
try {
|
|
146
|
+
rmSync(stateDir, { force: true, recursive: true });
|
|
147
|
+
} catch {
|
|
148
|
+
// Best effort during process teardown.
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
54
153
|
function resolveBunCommand(): string {
|
|
55
154
|
const bunFromEnv = process.env.BUN?.trim();
|
|
56
155
|
if (bunFromEnv && existsSync(bunFromEnv)) {
|
|
@@ -268,17 +367,15 @@ function relayWebSocket(args: {
|
|
|
268
367
|
: undefined,
|
|
269
368
|
});
|
|
270
369
|
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
isBinary: boolean;
|
|
274
|
-
}> = [];
|
|
370
|
+
const pendingClientQueue =
|
|
371
|
+
createPendingWebSocketQueueState<WebSocketSendData>();
|
|
275
372
|
|
|
276
|
-
const closeSocket = (socket: WebSocket) => {
|
|
373
|
+
const closeSocket = (socket: WebSocket, code?: number, reason?: string) => {
|
|
277
374
|
if (
|
|
278
375
|
socket.readyState === WebSocket.OPEN ||
|
|
279
376
|
socket.readyState === WebSocket.CONNECTING
|
|
280
377
|
) {
|
|
281
|
-
socket.close();
|
|
378
|
+
socket.close(code, reason);
|
|
282
379
|
}
|
|
283
380
|
};
|
|
284
381
|
|
|
@@ -288,12 +385,25 @@ function relayWebSocket(args: {
|
|
|
288
385
|
return;
|
|
289
386
|
}
|
|
290
387
|
if (upstreamSocket.readyState === WebSocket.CONNECTING) {
|
|
291
|
-
|
|
388
|
+
const accepted = enqueuePendingWebSocketMessage(
|
|
389
|
+
pendingClientQueue,
|
|
390
|
+
{ data, isBinary },
|
|
391
|
+
DEFAULT_PENDING_WEBSOCKET_QUEUE_LIMITS,
|
|
392
|
+
);
|
|
393
|
+
if (!accepted) {
|
|
394
|
+
clearPendingWebSocketQueue(pendingClientQueue);
|
|
395
|
+
closeSocket(
|
|
396
|
+
args.clientSocket,
|
|
397
|
+
1009,
|
|
398
|
+
"Pending websocket queue overflow",
|
|
399
|
+
);
|
|
400
|
+
closeSocket(upstreamSocket);
|
|
401
|
+
}
|
|
292
402
|
}
|
|
293
403
|
});
|
|
294
404
|
|
|
295
405
|
upstreamSocket.on("open", () => {
|
|
296
|
-
for (const message of
|
|
406
|
+
for (const message of drainPendingWebSocketQueue(pendingClientQueue)) {
|
|
297
407
|
upstreamSocket.send(message.data, { binary: message.isBinary });
|
|
298
408
|
}
|
|
299
409
|
});
|
|
@@ -306,16 +416,20 @@ function relayWebSocket(args: {
|
|
|
306
416
|
});
|
|
307
417
|
|
|
308
418
|
args.clientSocket.on("close", () => {
|
|
419
|
+
clearPendingWebSocketQueue(pendingClientQueue);
|
|
309
420
|
closeSocket(upstreamSocket);
|
|
310
421
|
});
|
|
311
422
|
upstreamSocket.on("close", () => {
|
|
423
|
+
clearPendingWebSocketQueue(pendingClientQueue);
|
|
312
424
|
closeSocket(args.clientSocket);
|
|
313
425
|
});
|
|
314
426
|
|
|
315
427
|
args.clientSocket.on("error", () => {
|
|
428
|
+
clearPendingWebSocketQueue(pendingClientQueue);
|
|
316
429
|
closeSocket(upstreamSocket);
|
|
317
430
|
});
|
|
318
431
|
upstreamSocket.on("error", () => {
|
|
432
|
+
clearPendingWebSocketQueue(pendingClientQueue);
|
|
319
433
|
closeSocket(args.clientSocket);
|
|
320
434
|
});
|
|
321
435
|
}
|
|
@@ -407,6 +521,29 @@ async function waitForChildExit(
|
|
|
407
521
|
});
|
|
408
522
|
}
|
|
409
523
|
|
|
524
|
+
async function closeUiServer(uiServer: Server | null): Promise<void> {
|
|
525
|
+
if (!uiServer) return;
|
|
526
|
+
try {
|
|
527
|
+
await new Promise<void>((resolve, reject) =>
|
|
528
|
+
uiServer.close((error) => (error ? reject(error) : resolve())),
|
|
529
|
+
);
|
|
530
|
+
} catch {
|
|
531
|
+
// Best effort during shutdown.
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
async function stopApiChild(
|
|
536
|
+
apiChild: ChildProcessWithoutNullStreams | null,
|
|
537
|
+
): Promise<void> {
|
|
538
|
+
if (!apiChild || apiChild.exitCode != null) return;
|
|
539
|
+
apiChild.kill("SIGTERM");
|
|
540
|
+
const exitedAfterTerm = await waitForChildExit(apiChild, 5_000);
|
|
541
|
+
if (!exitedAfterTerm && apiChild.exitCode == null) {
|
|
542
|
+
apiChild.kill("SIGKILL");
|
|
543
|
+
await waitForChildExit(apiChild, 5_000);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
410
547
|
async function fetchJson<T>(url: string): Promise<T> {
|
|
411
548
|
const response = await fetch(url);
|
|
412
549
|
if (!response.ok) {
|
|
@@ -465,6 +602,54 @@ async function waitForJsonPredicate<T>(
|
|
|
465
602
|
: new Error(`Timed out waiting for ${url}`);
|
|
466
603
|
}
|
|
467
604
|
|
|
605
|
+
function createProcessLogSignal(matchText: string): {
|
|
606
|
+
observe: (chunk: Buffer | string) => void;
|
|
607
|
+
wait: (timeoutMs: number, label: string) => Promise<void>;
|
|
608
|
+
} {
|
|
609
|
+
let matched = false;
|
|
610
|
+
let tail = "";
|
|
611
|
+
const waiters = new Set<() => void>();
|
|
612
|
+
|
|
613
|
+
return {
|
|
614
|
+
observe(chunk) {
|
|
615
|
+
if (matched) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
619
|
+
tail = `${tail}${text}`.slice(-Math.max(matchText.length * 2, 4096));
|
|
620
|
+
if (!tail.includes(matchText)) {
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
matched = true;
|
|
624
|
+
tail = "";
|
|
625
|
+
for (const resolve of waiters) {
|
|
626
|
+
resolve();
|
|
627
|
+
}
|
|
628
|
+
waiters.clear();
|
|
629
|
+
},
|
|
630
|
+
async wait(timeoutMs, label) {
|
|
631
|
+
if (matched) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
await new Promise<void>((resolve, reject) => {
|
|
635
|
+
const timeout = setTimeout(() => {
|
|
636
|
+
cleanup();
|
|
637
|
+
reject(new Error(`Timed out waiting for ${label}`));
|
|
638
|
+
}, timeoutMs);
|
|
639
|
+
const finish = () => {
|
|
640
|
+
cleanup();
|
|
641
|
+
resolve();
|
|
642
|
+
};
|
|
643
|
+
const cleanup = () => {
|
|
644
|
+
clearTimeout(timeout);
|
|
645
|
+
waiters.delete(finish);
|
|
646
|
+
};
|
|
647
|
+
waiters.add(finish);
|
|
648
|
+
});
|
|
649
|
+
},
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
|
|
468
653
|
async function ensureUiDistReady(): Promise<void> {
|
|
469
654
|
const distIndex = path.join(APP_DIST_DIR, "index.html");
|
|
470
655
|
let needsBuild = false;
|
|
@@ -605,56 +790,138 @@ async function submitFirstRun(apiBase: string): Promise<void> {
|
|
|
605
790
|
);
|
|
606
791
|
}
|
|
607
792
|
|
|
608
|
-
async function
|
|
609
|
-
|
|
610
|
-
|
|
793
|
+
async function seedLiveStackConfig(stateDir: string): Promise<void> {
|
|
794
|
+
await mkdir(stateDir, { recursive: true });
|
|
795
|
+
const configPath = path.join(stateDir, "eliza.json");
|
|
796
|
+
await writeFile(
|
|
797
|
+
configPath,
|
|
798
|
+
`${JSON.stringify(
|
|
799
|
+
{
|
|
800
|
+
logging: { level: "error" },
|
|
801
|
+
plugins: {
|
|
802
|
+
entries: Object.fromEntries(
|
|
803
|
+
LIVE_STACK_OPTIONAL_VIEW_PLUGIN_ENTRIES.map((pluginId) => [
|
|
804
|
+
pluginId,
|
|
805
|
+
{ enabled: true },
|
|
806
|
+
]),
|
|
807
|
+
),
|
|
808
|
+
},
|
|
809
|
+
},
|
|
810
|
+
null,
|
|
811
|
+
2,
|
|
812
|
+
)}\n`,
|
|
813
|
+
"utf8",
|
|
611
814
|
);
|
|
612
|
-
|
|
613
|
-
const apiBase = `http://127.0.0.1:${API_PORT}`;
|
|
614
|
-
const apiChild = spawn("node", [UI_SMOKE_STUB_SCRIPT], {
|
|
615
|
-
cwd: REPO_ROOT,
|
|
616
|
-
env: {
|
|
617
|
-
...process.env,
|
|
618
|
-
FORCE_COLOR: "0",
|
|
619
|
-
ELIZA_UI_SMOKE_API_PORT: String(API_PORT),
|
|
620
|
-
ELIZA_UI_SMOKE_STUB_IGNORE_SIGTERM: "1",
|
|
621
|
-
},
|
|
622
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
623
|
-
});
|
|
815
|
+
}
|
|
624
816
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
817
|
+
async function ensureLiveStackOptionalViewPluginsReady(): Promise<void> {
|
|
818
|
+
for (const plugin of LIVE_STACK_OPTIONAL_VIEW_PLUGIN_PACKAGES) {
|
|
819
|
+
const pluginDir = path.join(REPO_ROOT, "plugins", plugin.dir);
|
|
820
|
+
const outputPaths = plugin.requiredBuildOutputs.map((output) =>
|
|
821
|
+
path.join(pluginDir, output),
|
|
822
|
+
);
|
|
823
|
+
const missingOutputPaths: string[] = [];
|
|
824
|
+
for (const outputPath of outputPaths) {
|
|
825
|
+
try {
|
|
826
|
+
await access(outputPath);
|
|
827
|
+
} catch {
|
|
828
|
+
missingOutputPaths.push(outputPath);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
if (missingOutputPaths.length === 0) continue;
|
|
631
832
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
833
|
+
const logs: string[] = [];
|
|
834
|
+
const child = spawn(resolveBunCommand(), ["run", "build"], {
|
|
835
|
+
cwd: pluginDir,
|
|
836
|
+
env: {
|
|
837
|
+
...process.env,
|
|
838
|
+
FORCE_COLOR: "0",
|
|
839
|
+
},
|
|
840
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
841
|
+
});
|
|
842
|
+
child.stdout.on("data", (chunk) => logs.push(String(chunk)));
|
|
843
|
+
child.stderr.on("data", (chunk) => logs.push(String(chunk)));
|
|
643
844
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
845
|
+
const BUILD_TIMEOUT_MS = 300_000;
|
|
846
|
+
const exited = await waitForChildExit(child, BUILD_TIMEOUT_MS);
|
|
847
|
+
if (!exited) {
|
|
848
|
+
child.kill("SIGKILL");
|
|
849
|
+
throw new Error(
|
|
850
|
+
`Timed out building optional live-stack plugin ${plugin.id} after ${BUILD_TIMEOUT_MS}ms.\n${logs.join("").slice(-8_000)}`,
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
if (child.exitCode !== 0) {
|
|
854
|
+
throw new Error(
|
|
855
|
+
`Failed to build optional live-stack plugin ${plugin.id}.\n${logs.join("").slice(-8_000)}`,
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
for (const outputPath of outputPaths) {
|
|
859
|
+
await access(outputPath);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
650
863
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
864
|
+
async function startStubStack(): Promise<StartedStack> {
|
|
865
|
+
const stateDir = await createStateDir("eliza-ui-smoke-stub-");
|
|
866
|
+
let apiChild: ChildProcessWithoutNullStreams | null = null;
|
|
867
|
+
let uiServer: Server | null = null;
|
|
868
|
+
try {
|
|
869
|
+
const uiDistDir = await snapshotUiDist(stateDir);
|
|
870
|
+
const apiBase = `http://127.0.0.1:${API_PORT}`;
|
|
871
|
+
apiChild = spawn("node", [UI_SMOKE_STUB_SCRIPT], {
|
|
872
|
+
cwd: REPO_ROOT,
|
|
873
|
+
env: {
|
|
874
|
+
...process.env,
|
|
875
|
+
FORCE_COLOR: "0",
|
|
876
|
+
ELIZA_UI_SMOKE_API_PORT: String(API_PORT),
|
|
877
|
+
ELIZA_UI_SMOKE_STUB_IGNORE_SIGTERM: "1",
|
|
878
|
+
},
|
|
879
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
apiChild.stdout.on("data", (chunk) => {
|
|
883
|
+
process.stdout.write(`[ui-smoke][stub] ${chunk}`);
|
|
884
|
+
});
|
|
885
|
+
apiChild.stderr.on("data", (chunk) => {
|
|
886
|
+
process.stdout.write(`[ui-smoke][stub-err] ${chunk}`);
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
await waitForJson<{ complete: boolean }>(`${apiBase}/api/first-run/status`);
|
|
890
|
+
await waitForJsonPredicate<{ state?: string }>(
|
|
891
|
+
`${apiBase}/api/status`,
|
|
892
|
+
(status) => status.state === "running",
|
|
893
|
+
READY_TIMEOUT_MS,
|
|
894
|
+
);
|
|
895
|
+
await waitForJsonPredicate<{ session?: { kind?: string } }>(
|
|
896
|
+
`${apiBase}/api/auth/me`,
|
|
897
|
+
(me) => me.session?.kind === "local",
|
|
898
|
+
READY_TIMEOUT_MS,
|
|
899
|
+
);
|
|
900
|
+
|
|
901
|
+
uiServer = await startUiProxyServer({
|
|
902
|
+
apiBase,
|
|
903
|
+
port: UI_PORT,
|
|
904
|
+
uiDistDir,
|
|
905
|
+
});
|
|
906
|
+
process.env.ELIZA_API_PORT = String(API_PORT);
|
|
907
|
+
markStateDirOwnedByStack(stateDir);
|
|
908
|
+
const startedApiChild = apiChild;
|
|
909
|
+
const startedUiServer = uiServer;
|
|
910
|
+
|
|
911
|
+
return {
|
|
912
|
+
apiBase,
|
|
913
|
+
apiChild: startedApiChild,
|
|
914
|
+
stateDir,
|
|
915
|
+
uiBase: `http://127.0.0.1:${UI_PORT}`,
|
|
916
|
+
uiServer: startedUiServer,
|
|
917
|
+
};
|
|
918
|
+
} catch (error) {
|
|
919
|
+
await closeUiServer(uiServer);
|
|
920
|
+
await stopApiChild(apiChild);
|
|
921
|
+
await rm(stateDir, { force: true, recursive: true });
|
|
922
|
+
pendingStateDirs.delete(stateDir);
|
|
923
|
+
throw error;
|
|
924
|
+
}
|
|
658
925
|
}
|
|
659
926
|
|
|
660
927
|
async function startRealStack(): Promise<StartedStack> {
|
|
@@ -664,84 +931,112 @@ async function startRealStack(): Promise<StartedStack> {
|
|
|
664
931
|
return startStubStack();
|
|
665
932
|
}
|
|
666
933
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
);
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
934
|
+
await ensureLiveStackOptionalViewPluginsReady();
|
|
935
|
+
|
|
936
|
+
const stateDir = await createStateDir("eliza-ui-smoke-live-");
|
|
937
|
+
let apiChild: ChildProcessWithoutNullStreams | null = null;
|
|
938
|
+
let uiServer: Server | null = null;
|
|
939
|
+
try {
|
|
940
|
+
await seedLiveStackConfig(stateDir);
|
|
941
|
+
const uiDistDir = await snapshotUiDist(stateDir);
|
|
942
|
+
const apiBase = `http://127.0.0.1:${API_PORT}`;
|
|
943
|
+
const deferredBootComplete = createProcessLogSignal(
|
|
944
|
+
"[eliza-boot] deferred:complete",
|
|
945
|
+
);
|
|
946
|
+
apiChild = spawn(
|
|
947
|
+
"node",
|
|
948
|
+
[
|
|
949
|
+
path.join(REPO_ROOT, "packages/app-core/scripts/run-node-tsx.mjs"),
|
|
950
|
+
path.join(REPO_ROOT, "packages/app-core/src/runtime/eliza.ts"),
|
|
951
|
+
],
|
|
952
|
+
{
|
|
953
|
+
cwd: REPO_ROOT,
|
|
954
|
+
env: createLiveRuntimeChildEnv({
|
|
955
|
+
...(LIVE_PROVIDER?.env ?? {}),
|
|
956
|
+
ALLOW_NO_DATABASE: "",
|
|
957
|
+
FORCE_COLOR: "0",
|
|
958
|
+
ELIZA_API_PORT: String(API_PORT),
|
|
959
|
+
ELIZA_HOME_PORT: String(UI_PORT),
|
|
960
|
+
ELIZA_PORT: String(API_PORT),
|
|
961
|
+
ELIZA_STATE_DIR: stateDir,
|
|
962
|
+
}),
|
|
963
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
688
964
|
},
|
|
689
|
-
|
|
690
|
-
},
|
|
691
|
-
);
|
|
965
|
+
);
|
|
692
966
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
967
|
+
apiChild.stdout.on("data", (chunk) => {
|
|
968
|
+
deferredBootComplete.observe(chunk);
|
|
969
|
+
process.stdout.write(`[ui-smoke][api] ${chunk}`);
|
|
970
|
+
});
|
|
971
|
+
apiChild.stderr.on("data", (chunk) => {
|
|
972
|
+
deferredBootComplete.observe(chunk);
|
|
973
|
+
process.stdout.write(`[ui-smoke][api-err] ${chunk}`);
|
|
974
|
+
});
|
|
699
975
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
976
|
+
await waitForJson<{ complete: boolean }>(`${apiBase}/api/first-run/status`);
|
|
977
|
+
// Cloud-live mode (ELIZA_UI_SMOKE_CLOUD_LIVE=1) leaves first-run UNcompleted so
|
|
978
|
+
// the spec can drive the real cloud onboarding (login -> provision) through the
|
|
979
|
+
// UI against real Eliza Cloud. The default lane auto-completes a local first-run
|
|
980
|
+
// so chat/view specs land on a ready agent.
|
|
981
|
+
const skipAutoFirstRun = process.env.ELIZA_UI_SMOKE_CLOUD_LIVE === "1";
|
|
982
|
+
if (!skipAutoFirstRun) {
|
|
983
|
+
const onboardingStatus = await fetchJson<{ complete: boolean }>(
|
|
984
|
+
`${apiBase}/api/first-run/status`,
|
|
985
|
+
);
|
|
986
|
+
if (!onboardingStatus.complete) {
|
|
987
|
+
await submitFirstRun(apiBase);
|
|
988
|
+
}
|
|
713
989
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
990
|
+
await waitForJsonPredicate<{ complete: boolean }>(
|
|
991
|
+
`${apiBase}/api/first-run/status`,
|
|
992
|
+
(status) => status.complete === true,
|
|
993
|
+
READY_TIMEOUT_MS,
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
await waitForJsonPredicate<{ state?: string }>(
|
|
997
|
+
`${apiBase}/api/status`,
|
|
998
|
+
(status) => status.state === "running",
|
|
717
999
|
READY_TIMEOUT_MS,
|
|
718
1000
|
);
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
port: UI_PORT,
|
|
734
|
-
uiDistDir,
|
|
735
|
-
});
|
|
736
|
-
process.env.ELIZA_API_PORT = String(API_PORT);
|
|
1001
|
+
await waitForJsonPredicate<{ session?: { kind?: string } }>(
|
|
1002
|
+
`${apiBase}/api/auth/me`,
|
|
1003
|
+
(me) => me.session?.kind === "local",
|
|
1004
|
+
READY_TIMEOUT_MS,
|
|
1005
|
+
);
|
|
1006
|
+
if (!skipAutoFirstRun) {
|
|
1007
|
+
// App-control and plugin views are deferred capabilities. Treat the live
|
|
1008
|
+
// harness as ready only after those runtime plugins have had a chance to
|
|
1009
|
+
// register; otherwise chat-driven view switching can race boot.
|
|
1010
|
+
await deferredBootComplete.wait(
|
|
1011
|
+
READY_TIMEOUT_MS,
|
|
1012
|
+
"deferred runtime plugin registration",
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
737
1015
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
1016
|
+
uiServer = await startUiProxyServer({
|
|
1017
|
+
apiBase,
|
|
1018
|
+
port: UI_PORT,
|
|
1019
|
+
uiDistDir,
|
|
1020
|
+
});
|
|
1021
|
+
process.env.ELIZA_API_PORT = String(API_PORT);
|
|
1022
|
+
markStateDirOwnedByStack(stateDir);
|
|
1023
|
+
const startedApiChild = apiChild;
|
|
1024
|
+
const startedUiServer = uiServer;
|
|
1025
|
+
|
|
1026
|
+
return {
|
|
1027
|
+
apiBase,
|
|
1028
|
+
apiChild: startedApiChild,
|
|
1029
|
+
stateDir,
|
|
1030
|
+
uiBase: `http://127.0.0.1:${UI_PORT}`,
|
|
1031
|
+
uiServer: startedUiServer,
|
|
1032
|
+
};
|
|
1033
|
+
} catch (error) {
|
|
1034
|
+
await closeUiServer(uiServer);
|
|
1035
|
+
await stopApiChild(apiChild);
|
|
1036
|
+
await rm(stateDir, { force: true, recursive: true });
|
|
1037
|
+
pendingStateDirs.delete(stateDir);
|
|
1038
|
+
throw error;
|
|
1039
|
+
}
|
|
745
1040
|
}
|
|
746
1041
|
|
|
747
1042
|
async function stopRealStack(stack: StartedStack | null): Promise<void> {
|
|
@@ -749,35 +1044,25 @@ async function stopRealStack(stack: StartedStack | null): Promise<void> {
|
|
|
749
1044
|
return;
|
|
750
1045
|
}
|
|
751
1046
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
stack.uiServer.close((error) => (error ? reject(error) : resolve())),
|
|
755
|
-
);
|
|
756
|
-
} catch {
|
|
757
|
-
// Best effort during shutdown.
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
if (stack.apiChild.exitCode == null) {
|
|
761
|
-
stack.apiChild.kill("SIGTERM");
|
|
762
|
-
const exitedAfterTerm = await waitForChildExit(stack.apiChild, 5_000);
|
|
763
|
-
if (!exitedAfterTerm && stack.apiChild.exitCode == null) {
|
|
764
|
-
stack.apiChild.kill("SIGKILL");
|
|
765
|
-
await waitForChildExit(stack.apiChild, 5_000);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
1047
|
+
await closeUiServer(stack.uiServer);
|
|
1048
|
+
await stopApiChild(stack.apiChild);
|
|
768
1049
|
|
|
769
1050
|
await rm(stack.stateDir, { force: true, recursive: true });
|
|
1051
|
+
ownedStateDirs.delete(stack.stateDir);
|
|
770
1052
|
}
|
|
771
1053
|
|
|
772
1054
|
let stack: StartedStack | null = null;
|
|
773
1055
|
let shuttingDown = false;
|
|
774
1056
|
|
|
1057
|
+
process.once("exit", cleanupKnownStateDirsSync);
|
|
1058
|
+
|
|
775
1059
|
async function shutdown(exitCode: number): Promise<void> {
|
|
776
1060
|
if (shuttingDown) {
|
|
777
1061
|
return;
|
|
778
1062
|
}
|
|
779
1063
|
shuttingDown = true;
|
|
780
1064
|
await stopRealStack(stack);
|
|
1065
|
+
await cleanupPendingStateDirs();
|
|
781
1066
|
process.exit(exitCode);
|
|
782
1067
|
}
|
|
783
1068
|
|
|
@@ -808,5 +1093,6 @@ try {
|
|
|
808
1093
|
}`,
|
|
809
1094
|
);
|
|
810
1095
|
await stopRealStack(stack);
|
|
1096
|
+
await cleanupPendingStateDirs();
|
|
811
1097
|
process.exit(1);
|
|
812
1098
|
}
|