@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
|
@@ -64,16 +64,38 @@ import {
|
|
|
64
64
|
resolveAppConfigPath,
|
|
65
65
|
} from "./aosp/lib/load-variant-config.mjs";
|
|
66
66
|
import { resolveMainAppDir } from "./lib/app-dir.mjs";
|
|
67
|
+
import { artifactStaleness } from "./lib/artifact-staleness.mjs";
|
|
67
68
|
import {
|
|
68
69
|
isCapacitorPlatformReady as isCapacitorPlatformReadyImpl,
|
|
69
70
|
resolvePlatformTemplateRoot as resolvePlatformTemplateRootImpl,
|
|
70
71
|
syncPlatformTemplateFiles as syncPlatformTemplateFilesImpl,
|
|
71
72
|
} from "./lib/capacitor-platform-templates.mjs";
|
|
73
|
+
import { ensurePlistUrlScheme } from "./lib/ios-plist-url-scheme.mjs";
|
|
74
|
+
import {
|
|
75
|
+
androidUsesAppDirFor,
|
|
76
|
+
MTP_FORK_SRC_CANDIDATES,
|
|
77
|
+
mtpForceRebuildRequested,
|
|
78
|
+
mtpSliceReuse,
|
|
79
|
+
} from "./lib/mobile-build-decisions.mjs";
|
|
80
|
+
import {
|
|
81
|
+
assertStagedRendererMatchesBuild,
|
|
82
|
+
overlayFreshRendererIntoPublic,
|
|
83
|
+
readRendererBuildManifest,
|
|
84
|
+
} from "./lib/renderer-build-manifest.mjs";
|
|
72
85
|
import { resolveRepoRootFromImportMeta } from "./lib/repo-root.mjs";
|
|
73
86
|
import {
|
|
74
87
|
RUNTIME_PROVENANCE_FILENAME,
|
|
75
88
|
stageAndroidAgentRuntime,
|
|
76
89
|
} from "./lib/stage-android-agent.mjs";
|
|
90
|
+
import { viteRendererBuildNeeded } from "./lib/vite-renderer-dist-stale.mjs";
|
|
91
|
+
|
|
92
|
+
export {
|
|
93
|
+
androidUsesAppDirFor,
|
|
94
|
+
MTP_FORK_SRC_CANDIDATES,
|
|
95
|
+
mtpBuilderRepoRoot,
|
|
96
|
+
mtpForceRebuildRequested,
|
|
97
|
+
mtpSliceReuse,
|
|
98
|
+
} from "./lib/mobile-build-decisions.mjs";
|
|
77
99
|
|
|
78
100
|
// ── Paths ───────────────────────────────────────────────────────────────
|
|
79
101
|
|
|
@@ -103,10 +125,11 @@ const iosDir = path.join(appDir, "ios", "App");
|
|
|
103
125
|
// treating app-core/platforms/android as a read-only template copied in by
|
|
104
126
|
// overlayAndroid/patchAndroidGradle/syncAndroidAppActionsResources. That keeps
|
|
105
127
|
// the two brands' Android builds fully separate.
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
128
|
+
const androidBuildAppId = readAppIdentity().appId;
|
|
129
|
+
const androidUsesAppDir = androidUsesAppDirFor(androidBuildAppId, process.env);
|
|
130
|
+
const androidDir = androidUsesAppDir
|
|
131
|
+
? path.join(appDir, "android")
|
|
132
|
+
: path.join(appCoreRoot, "platforms", "android");
|
|
110
133
|
const localArtifactsDir = path.join(elizaRepoRoot, ".eliza-local", "artifacts");
|
|
111
134
|
const androidSmsGatewayDebugApkArtifact = path.join(
|
|
112
135
|
localArtifactsDir,
|
|
@@ -291,8 +314,23 @@ function withMobileBuildNodeOptions(env = process.env) {
|
|
|
291
314
|
}
|
|
292
315
|
|
|
293
316
|
function run(command, args, { cwd, env = process.env } = {}) {
|
|
317
|
+
// Windows: gradlew is gradlew.bat, and Node cannot spawn `./gradlew` (ENOENT)
|
|
318
|
+
// nor a .bat/.cmd directly (EINVAL since CVE-2024-27980). Translate
|
|
319
|
+
// ./gradlew -> the sibling gradlew.bat (resolved against cwd) and run any
|
|
320
|
+
// .bat/.cmd through cmd.exe with args as separate argv (no shell:true).
|
|
321
|
+
let spawnCmd = command;
|
|
322
|
+
let spawnArgs = args;
|
|
323
|
+
if (process.platform === "win32") {
|
|
324
|
+
if (command === "./gradlew" || command === "gradlew") {
|
|
325
|
+
spawnCmd = path.join(cwd || process.cwd(), "gradlew.bat");
|
|
326
|
+
}
|
|
327
|
+
if (/.(?:bat|cmd)$/i.test(spawnCmd)) {
|
|
328
|
+
spawnArgs = ["/d", "/s", "/c", spawnCmd, ...args];
|
|
329
|
+
spawnCmd = process.env.ComSpec || "cmd.exe";
|
|
330
|
+
}
|
|
331
|
+
}
|
|
294
332
|
return new Promise((resolve, reject) => {
|
|
295
|
-
const child = spawn(
|
|
333
|
+
const child = spawn(spawnCmd, spawnArgs, { cwd, env, stdio: "inherit" });
|
|
296
334
|
child.on("exit", (code, signal) => {
|
|
297
335
|
if (signal) return reject(new Error(`${command} killed by ${signal}`));
|
|
298
336
|
if ((code ?? 1) !== 0)
|
|
@@ -386,6 +424,11 @@ function resolveAndroidSdkRoot() {
|
|
|
386
424
|
process.env.ANDROID_HOME,
|
|
387
425
|
path.join(os.homedir(), "Library", "Android", "sdk"),
|
|
388
426
|
path.join(os.homedir(), "Android", "Sdk"),
|
|
427
|
+
path.join(
|
|
428
|
+
process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local"),
|
|
429
|
+
"Android",
|
|
430
|
+
"Sdk",
|
|
431
|
+
),
|
|
389
432
|
]);
|
|
390
433
|
}
|
|
391
434
|
|
|
@@ -402,15 +445,66 @@ function resolveViteCli() {
|
|
|
402
445
|
return viteCli;
|
|
403
446
|
}
|
|
404
447
|
|
|
448
|
+
function javaMajorVersion(javaHome) {
|
|
449
|
+
if (!javaHome || !fs.existsSync(javaHome)) return null;
|
|
450
|
+
// `release` is the cheapest, most reliable source (no JVM spawn).
|
|
451
|
+
const releaseFile = path.join(javaHome, "release");
|
|
452
|
+
if (fs.existsSync(releaseFile)) {
|
|
453
|
+
const m = fs
|
|
454
|
+
.readFileSync(releaseFile, "utf8")
|
|
455
|
+
.match(/JAVA_VERSION="?(\d+)/);
|
|
456
|
+
if (m) return Number.parseInt(m[1], 10);
|
|
457
|
+
}
|
|
458
|
+
const javaBin = path.join(
|
|
459
|
+
javaHome,
|
|
460
|
+
"bin",
|
|
461
|
+
process.platform === "win32" ? "java.exe" : "java",
|
|
462
|
+
);
|
|
463
|
+
if (fs.existsSync(javaBin)) {
|
|
464
|
+
const r = spawnSync(javaBin, ["-version"], { encoding: "utf8" });
|
|
465
|
+
const m = `${r.stderr ?? ""}${r.stdout ?? ""}`.match(/version "?(\d+)/);
|
|
466
|
+
if (m) return Number.parseInt(m[1], 10);
|
|
467
|
+
}
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Auto-select a JDK >= 21 so a plain `build:android` "just works" with no
|
|
472
|
+
// JAVA_HOME juggling. JAVA_HOME is honored ONLY when it actually is >= 21;
|
|
473
|
+
// otherwise we fall through to the well-known JDK 21 install paths and finally
|
|
474
|
+
// scan /usr/lib/jvm. (AGP 9 + the Android toolchain require 21.)
|
|
405
475
|
function resolveJavaHome() {
|
|
406
|
-
|
|
476
|
+
const candidates = [
|
|
407
477
|
process.env.JAVA_HOME,
|
|
408
478
|
"/opt/homebrew/opt/openjdk@21",
|
|
409
479
|
"/usr/local/opt/openjdk@21",
|
|
410
480
|
"/usr/lib/jvm/temurin-21-jdk-amd64",
|
|
411
481
|
"/usr/lib/jvm/java-21-openjdk-amd64",
|
|
412
482
|
"/usr/lib/jvm/java-21-openjdk",
|
|
413
|
-
]
|
|
483
|
+
];
|
|
484
|
+
for (const candidate of candidates) {
|
|
485
|
+
if (candidate && (javaMajorVersion(candidate) ?? 0) >= 21) return candidate;
|
|
486
|
+
}
|
|
487
|
+
const jvmRoot = "/usr/lib/jvm";
|
|
488
|
+
if (fs.existsSync(jvmRoot)) {
|
|
489
|
+
for (const name of fs.readdirSync(jvmRoot)) {
|
|
490
|
+
const full = path.join(jvmRoot, name);
|
|
491
|
+
if ((javaMajorVersion(full) ?? 0) >= 21) return full;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (process.platform === "win32") {
|
|
495
|
+
const programFiles = process.env.ProgramFiles || "C:\\Program Files";
|
|
496
|
+
for (const vendor of ["Eclipse Adoptium", "Microsoft", "Java", "Zulu"]) {
|
|
497
|
+
const vendorRoot = path.join(programFiles, vendor);
|
|
498
|
+
if (!fs.existsSync(vendorRoot)) continue;
|
|
499
|
+
for (const name of fs.readdirSync(vendorRoot)) {
|
|
500
|
+
const full = path.join(vendorRoot, name);
|
|
501
|
+
if ((javaMajorVersion(full) ?? 0) >= 21) return full;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
// Nothing >= 21 found — return the first path that exists so the caller's
|
|
506
|
+
// "JDK 21 not found" error fires with a concrete (if wrong-version) hint.
|
|
507
|
+
return firstExisting(candidates);
|
|
414
508
|
}
|
|
415
509
|
|
|
416
510
|
function prependPath(env, entries) {
|
|
@@ -487,32 +581,6 @@ function insertBeforeRootPlistDictClose(content, insertion) {
|
|
|
487
581
|
return `${content.slice(0, fallbackIndex)}${insertion}${content.slice(fallbackIndex + "</dict>".length)}`;
|
|
488
582
|
}
|
|
489
583
|
|
|
490
|
-
function ensurePlistUrlScheme(content, urlScheme) {
|
|
491
|
-
const escapedScheme = escapeXmlText(urlScheme);
|
|
492
|
-
const urlTypesRe =
|
|
493
|
-
/(<key>CFBundleURLTypes<\/key>\s*<array>)([\s\S]*?)(\s*<\/array>)/;
|
|
494
|
-
const entry = `
|
|
495
|
-
<dict>
|
|
496
|
-
<key>CFBundleURLName</key>
|
|
497
|
-
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
498
|
-
<key>CFBundleURLSchemes</key>
|
|
499
|
-
<array>
|
|
500
|
-
<string>${escapedScheme}</string>
|
|
501
|
-
</array>
|
|
502
|
-
</dict>`;
|
|
503
|
-
const match = content.match(urlTypesRe);
|
|
504
|
-
if (!match) {
|
|
505
|
-
return insertBeforeRootPlistDictClose(
|
|
506
|
-
content,
|
|
507
|
-
`\t<key>CFBundleURLTypes</key>\n\t<array>${entry}\n\t</array>\n</dict>`,
|
|
508
|
-
);
|
|
509
|
-
}
|
|
510
|
-
if (match[2].includes(`<string>${escapedScheme}</string>`)) {
|
|
511
|
-
return content;
|
|
512
|
-
}
|
|
513
|
-
return content.replace(urlTypesRe, `$1${match[2]}${entry}$3`);
|
|
514
|
-
}
|
|
515
|
-
|
|
516
584
|
/**
|
|
517
585
|
* Resolve the real filesystem path to a node_modules package (follows bun
|
|
518
586
|
* symlinks). Returns a path relative to `relativeTo`.
|
|
@@ -912,14 +980,69 @@ export function resolveMobileBuildPolicy(platform) {
|
|
|
912
980
|
|
|
913
981
|
async function buildWeb(platform) {
|
|
914
982
|
if (process.env.ELIZA_MOBILE_SKIP_WEB_BUILD === "1") {
|
|
915
|
-
const
|
|
983
|
+
const distDir = path.join(appDir, "dist");
|
|
984
|
+
const indexPath = path.join(distDir, "index.html");
|
|
916
985
|
if (!fs.existsSync(indexPath)) {
|
|
917
986
|
throw new Error(
|
|
918
987
|
`[mobile-build] ELIZA_MOBILE_SKIP_WEB_BUILD=1 but ${indexPath} is missing.`,
|
|
919
988
|
);
|
|
920
989
|
}
|
|
990
|
+
// Never SILENTLY reuse a stale renderer (issue #9309). The skip flag is an
|
|
991
|
+
// explicit "reuse the existing dist" request, but it must still fail loudly
|
|
992
|
+
// when that dist is stale relative to sources or was built for a different
|
|
993
|
+
// variant/target than this build needs. A deliberate stale reuse can be
|
|
994
|
+
// forced with ELIZA_MOBILE_SKIP_WEB_BUILD_ALLOW_STALE=1.
|
|
995
|
+
const allowStale =
|
|
996
|
+
process.env.ELIZA_MOBILE_SKIP_WEB_BUILD_ALLOW_STALE === "1";
|
|
997
|
+
const policy = resolveMobileBuildPolicy(platform);
|
|
998
|
+
const expectedVariant =
|
|
999
|
+
process.env.ELIZA_BUILD_VARIANT || policy.buildVariant;
|
|
1000
|
+
const expectedTarget = policy.capacitorTarget;
|
|
1001
|
+
const manifest = readRendererBuildManifest(distDir);
|
|
1002
|
+
const problems = [];
|
|
1003
|
+
if (!manifest) {
|
|
1004
|
+
problems.push(
|
|
1005
|
+
`no ${path.join("dist", "eliza-renderer-build.json")} (renderer not built with the build-manifest plugin)`,
|
|
1006
|
+
);
|
|
1007
|
+
} else {
|
|
1008
|
+
if (
|
|
1009
|
+
expectedVariant &&
|
|
1010
|
+
manifest.variant != null &&
|
|
1011
|
+
manifest.variant !== expectedVariant
|
|
1012
|
+
) {
|
|
1013
|
+
problems.push(
|
|
1014
|
+
`dist built for variant '${manifest.variant}' but this build targets '${expectedVariant}'`,
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
if (
|
|
1018
|
+
expectedTarget &&
|
|
1019
|
+
manifest.capacitorTarget != null &&
|
|
1020
|
+
manifest.capacitorTarget !== expectedTarget
|
|
1021
|
+
) {
|
|
1022
|
+
problems.push(
|
|
1023
|
+
`dist built for capacitor target '${manifest.capacitorTarget}' but this build targets '${expectedTarget}'`,
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
if (viteRendererBuildNeeded(appDir, repoRoot)) {
|
|
1028
|
+
problems.push("dist is older than renderer sources (stale)");
|
|
1029
|
+
}
|
|
1030
|
+
if (problems.length > 0) {
|
|
1031
|
+
const detail = problems.map((p) => ` - ${p}`).join("\n");
|
|
1032
|
+
if (!allowStale) {
|
|
1033
|
+
throw new Error(
|
|
1034
|
+
`[mobile-build] ELIZA_MOBILE_SKIP_WEB_BUILD=1 refused — the existing web build is stale or mismatched:\n${detail}\n` +
|
|
1035
|
+
`Drop ELIZA_MOBILE_SKIP_WEB_BUILD to rebuild, or set ` +
|
|
1036
|
+
`ELIZA_MOBILE_SKIP_WEB_BUILD_ALLOW_STALE=1 to ship this dist anyway (NOT recommended).`,
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
1039
|
+
console.warn(
|
|
1040
|
+
`[mobile-build] ELIZA_MOBILE_SKIP_WEB_BUILD_ALLOW_STALE=1 — shipping a renderer flagged as stale/mismatched:\n${detail}`,
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
921
1043
|
console.log(
|
|
922
|
-
`[mobile-build] Reusing existing web build: ${path.relative(repoRoot,
|
|
1044
|
+
`[mobile-build] Reusing existing web build: ${path.relative(repoRoot, distDir)}` +
|
|
1045
|
+
(manifest ? ` (buildId=${manifest.buildId.slice(0, 12)})` : ""),
|
|
923
1046
|
);
|
|
924
1047
|
return;
|
|
925
1048
|
}
|
|
@@ -1098,6 +1221,23 @@ function stageIosAgentRuntime({
|
|
|
1098
1221
|
}
|
|
1099
1222
|
}
|
|
1100
1223
|
|
|
1224
|
+
// The agent bundle must be the freshly built one — never a stale leftover that
|
|
1225
|
+
// forces a manual hot-swap to get latest (issue #9309). buildIos rebuilds it
|
|
1226
|
+
// before staging, so this is a hard guarantee; fail loudly if it regressed.
|
|
1227
|
+
if (process.env.ELIZA_MOBILE_ALLOW_STALE_AGENT_BUNDLE !== "1") {
|
|
1228
|
+
const bundleStale = artifactStaleness(
|
|
1229
|
+
path.join(sourceDir, "agent-bundle.js"),
|
|
1230
|
+
{ sourceDirs: [path.join(packagesRoot, "agent", "src")] },
|
|
1231
|
+
);
|
|
1232
|
+
if (bundleStale.stale) {
|
|
1233
|
+
throw new Error(
|
|
1234
|
+
`[mobile-build] iOS agent bundle is stale (${bundleStale.reason}). ` +
|
|
1235
|
+
`Run \`bun run --cwd packages/agent build:ios-bun\` to rebuild, or set ` +
|
|
1236
|
+
`ELIZA_MOBILE_ALLOW_STALE_AGENT_BUNDLE=1 to stage it anyway (NOT recommended).`,
|
|
1237
|
+
);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1101
1241
|
const targetDir = path.join(iosDir, "App", "public", "agent");
|
|
1102
1242
|
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
1103
1243
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
@@ -1117,6 +1257,19 @@ function stageIosAgentRuntime({
|
|
|
1117
1257
|
for (const file of assetPlan.rootAssets) {
|
|
1118
1258
|
fs.copyFileSync(path.join(sourceDir, file), path.join(publicDir, file));
|
|
1119
1259
|
}
|
|
1260
|
+
// Verify the staged bundle is a faithful copy (catch a torn/partial copy that
|
|
1261
|
+
// would ship a corrupt agent runtime).
|
|
1262
|
+
if (assetPlan.agentAssets?.includes("agent-bundle.js")) {
|
|
1263
|
+
const sha = (p) =>
|
|
1264
|
+
crypto.createHash("sha256").update(fs.readFileSync(p)).digest("hex");
|
|
1265
|
+
const srcSha = sha(path.join(sourceDir, "agent-bundle.js"));
|
|
1266
|
+
const dstSha = sha(path.join(targetDir, "agent-bundle.js"));
|
|
1267
|
+
if (srcSha !== dstSha) {
|
|
1268
|
+
throw new Error(
|
|
1269
|
+
`[mobile-build] staged iOS agent-bundle.js hash ${dstSha} != source ${srcSha} — partial/corrupt copy.`,
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1120
1273
|
const stagedModelCount = stageIosBundledLocalModels(targetDir);
|
|
1121
1274
|
console.log(
|
|
1122
1275
|
`[mobile-build] Staged iOS Bun agent payload${appStoreBuild ? " (App Store allowlist)" : ""}: ${path.relative(repoRoot, targetDir)}${stagedModelCount > 0 ? ` with ${stagedModelCount} local model file(s)` : ""}`,
|
|
@@ -1303,7 +1456,85 @@ function mirrorCapacitorWebPayloadIntoAndroidDir() {
|
|
|
1303
1456
|
`[mobile-build] Stale-web guard: overlaid fresh ${path.relative(repoRoot, freshWeb)} → ${path.relative(repoRoot, targetPublic)}`,
|
|
1304
1457
|
);
|
|
1305
1458
|
}
|
|
1459
|
+
dropRetiredLlamaCppFromAndroidGradle();
|
|
1306
1460
|
reconcilePluginManifestWithGradle(targetAssets);
|
|
1461
|
+
// Verify the staged Android renderer is exactly the freshly built one. The
|
|
1462
|
+
// overlay above makes it so; this turns "should be fresh" into a hard,
|
|
1463
|
+
// build-failing guarantee (issue #9309).
|
|
1464
|
+
if (fs.existsSync(path.join(freshWeb, "index.html"))) {
|
|
1465
|
+
assertStagedRendererMatchesBuild(freshWeb, targetPublic, {
|
|
1466
|
+
label: "android",
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
/**
|
|
1472
|
+
* iOS stale-web guard — the iOS counterpart to
|
|
1473
|
+
* mirrorCapacitorWebPayloadIntoAndroidDir. `cap sync ios` (and a skipped sync)
|
|
1474
|
+
* have both been observed to leave a STALE `ios/App/App/public` — an old entry
|
|
1475
|
+
* hash shipping an ancient UI despite a fresh `dist`. The freshly vite-built
|
|
1476
|
+
* bundle is the source of truth, so overlay it unconditionally: clear the hashed
|
|
1477
|
+
* assets/ then copy dist over public. The on-device agent payload
|
|
1478
|
+
* (`public/agent`) and PGlite root extension assets staged by
|
|
1479
|
+
* stageIosAgentRuntime live OUTSIDE dist and survive — we only clear
|
|
1480
|
+
* `public/assets` and cpSync never deletes existing non-dist files. After the
|
|
1481
|
+
* overlay we assert the staged renderer matches the build so a stale/missing UI
|
|
1482
|
+
* FAILS THE BUILD instead of shipping (issue #9309).
|
|
1483
|
+
*/
|
|
1484
|
+
function mirrorCapacitorWebPayloadIntoIosDir() {
|
|
1485
|
+
const freshWeb = path.join(appDir, "dist");
|
|
1486
|
+
const targetPublic = path.join(iosDir, "App", "public");
|
|
1487
|
+
overlayFreshRendererIntoPublic(freshWeb, targetPublic, { label: "ios" });
|
|
1488
|
+
console.log(
|
|
1489
|
+
`[mobile-build] Stale-web guard: overlaid fresh ${path.relative(repoRoot, freshWeb)} → ${path.relative(repoRoot, targetPublic)}`,
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
/**
|
|
1494
|
+
* Remove the RETIRED llama-cpp-capacitor Android module from the gradle build
|
|
1495
|
+
* entirely — the `include ':llama-cpp-capacitor'` + project line in
|
|
1496
|
+
* capacitor.settings.gradle and the `implementation project(':llama-cpp-capacitor')`
|
|
1497
|
+
* in app/capacitor.build.gradle. `cap sync` re-adds these on every sync because
|
|
1498
|
+
* the package ships an android/ dir, but agent inference runs solely through the
|
|
1499
|
+
* fused libelizainference.so and nothing on Android loads this plugin's separate
|
|
1500
|
+
* libllama-cpp-arm64.so. Leaving the gradle project in only made gradle configure
|
|
1501
|
+
* its CMake — which built a no-op stub and used to require the
|
|
1502
|
+
* ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB opt-out. Dropping the project removes the
|
|
1503
|
+
* stub build outright (no flag needed). iOS is untouched: ios-local-agent-kernel
|
|
1504
|
+
* loads the package via a dynamic import, so the npm dependency stays.
|
|
1505
|
+
*
|
|
1506
|
+
* Opt back into the full second library (not the stub) with
|
|
1507
|
+
* ELIZA_ANDROID_INCLUDE_LLAMA_CPP_CAPACITOR=1. Idempotent.
|
|
1508
|
+
*/
|
|
1509
|
+
function dropRetiredLlamaCppFromAndroidGradle() {
|
|
1510
|
+
if (
|
|
1511
|
+
process.env.ELIZA_ANDROID_INCLUDE_LLAMA_CPP_CAPACITOR === "1" ||
|
|
1512
|
+
process.env.elizaIncludeLlamaCppCapacitor === "true"
|
|
1513
|
+
) {
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
const targets = [
|
|
1517
|
+
path.join(androidDir, "capacitor.settings.gradle"),
|
|
1518
|
+
path.join(androidDir, "app", "capacitor.build.gradle"),
|
|
1519
|
+
];
|
|
1520
|
+
let dropped = false;
|
|
1521
|
+
for (const target of targets) {
|
|
1522
|
+
if (!fs.existsSync(target)) continue;
|
|
1523
|
+
const before = fs.readFileSync(target, "utf8");
|
|
1524
|
+
const after = before
|
|
1525
|
+
.split("\n")
|
|
1526
|
+
.filter((line) => !line.includes("llama-cpp-capacitor"))
|
|
1527
|
+
.join("\n");
|
|
1528
|
+
if (after !== before) {
|
|
1529
|
+
fs.writeFileSync(target, after, "utf8");
|
|
1530
|
+
dropped = true;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
if (dropped) {
|
|
1534
|
+
console.log(
|
|
1535
|
+
"[mobile-build] Dropped retired llama-cpp-capacitor from the Android gradle build (no stub CMake; libelizainference is the sole in-process inference lib).",
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1307
1538
|
}
|
|
1308
1539
|
|
|
1309
1540
|
/**
|
|
@@ -1342,22 +1573,19 @@ function reconcilePluginManifestWithGradle(targetAssets) {
|
|
|
1342
1573
|
String(pkg ?? "")
|
|
1343
1574
|
.replace(/@/g, "")
|
|
1344
1575
|
.replace(/\//g, "-");
|
|
1345
|
-
//
|
|
1346
|
-
//
|
|
1347
|
-
//
|
|
1348
|
-
//
|
|
1349
|
-
//
|
|
1350
|
-
//
|
|
1351
|
-
//
|
|
1352
|
-
//
|
|
1353
|
-
//
|
|
1354
|
-
//
|
|
1355
|
-
// via bun:ffi) does NOT use this Capacitor plugin, so the device-bridge import
|
|
1356
|
-
// failing as a catchable "LlamaCpp plugin not implemented" JS error costs
|
|
1357
|
-
// nothing and keeps the JS↔native surface honest.
|
|
1576
|
+
// The llama-cpp-capacitor plugin is RETIRED on Android: agent inference runs
|
|
1577
|
+
// entirely through the single fused libelizainference.so, and nothing loads
|
|
1578
|
+
// this plugin's separate libllama-cpp-arm64.so (its JS adapter is retired).
|
|
1579
|
+
// dropRetiredLlamaCppFromAndroidGradle() (called above) removes its gradle
|
|
1580
|
+
// project outright, so its CMake never runs — there is no stub to register
|
|
1581
|
+
// and no ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB opt-out to set. We also drop it from
|
|
1582
|
+
// the plugins manifest here so the LlamaCpp class never auto-registers. The
|
|
1583
|
+
// device-bridge's optional LlamaCpp import resolves to a catchable "plugin not
|
|
1584
|
+
// implemented" JS error, which costs nothing. Opt the full second library back
|
|
1585
|
+
// in (gradle project + manifest) only with ELIZA_ANDROID_INCLUDE_LLAMA_CPP_CAPACITOR=1.
|
|
1358
1586
|
const stubLlamaCpp =
|
|
1359
|
-
process.env.
|
|
1360
|
-
process.env.
|
|
1587
|
+
process.env.ELIZA_ANDROID_INCLUDE_LLAMA_CPP_CAPACITOR !== "1" &&
|
|
1588
|
+
process.env.elizaIncludeLlamaCppCapacitor !== "true";
|
|
1361
1589
|
// Third-party Capacitor plugins that `cap sync` includes (they ship an
|
|
1362
1590
|
// android/ dir, so they ARE in capacitor.settings.gradle) but whose Kotlin
|
|
1363
1591
|
// plugin class never lands in the app dex on AGP 8.x: both rely on AGP's
|
|
@@ -1670,34 +1898,20 @@ export function injectNativeLibLegacyPackaging(content) {
|
|
|
1670
1898
|
*
|
|
1671
1899
|
* Fails local builds when no path is configured or the dir doesn't exist. The
|
|
1672
1900
|
* Android Capacitor JNI wrapper links against these MTP libraries and cannot
|
|
1673
|
-
* honestly support Eliza-1/
|
|
1674
|
-
*
|
|
1675
|
-
*
|
|
1901
|
+
* honestly support Eliza-1/Gemma 4 without them. Cloud builds skip the task.
|
|
1902
|
+
* A build with no fresh source dir falls back to the already-staged fused lib
|
|
1903
|
+
* set (the common dev case); only a genuinely missing arm64 lib is a hard error.
|
|
1676
1904
|
*
|
|
1677
1905
|
* Idempotent: re-runs are no-ops once the block is present.
|
|
1678
1906
|
*/
|
|
1679
1907
|
function ensureCopyForkLlamaLibGuards(content) {
|
|
1680
1908
|
if (!/\[copyForkLlamaLib\]/.test(content)) return content;
|
|
1681
|
-
|
|
1682
|
-
const
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
if (!hasCloudGuard) {
|
|
1688
|
-
guards +=
|
|
1689
|
-
` if (project.findProperty('elizaCloudBuild') == 'true') {\n` +
|
|
1690
|
-
` println "[copyForkLlamaLib] skipped for cloud build"\n` +
|
|
1691
|
-
` return\n` +
|
|
1692
|
-
` }\n`;
|
|
1693
|
-
}
|
|
1694
|
-
if (!hasExplicitSkipGuard) {
|
|
1695
|
-
guards +=
|
|
1696
|
-
` if (project.findProperty('elizaSkipForkLlamaLib') == 'true' || System.getenv('ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB') == '1') {\n` +
|
|
1697
|
-
` println "[copyForkLlamaLib] skipped by explicit native-lib opt-out"\n` +
|
|
1698
|
-
` return\n` +
|
|
1699
|
-
` }\n`;
|
|
1700
|
-
}
|
|
1909
|
+
if (/skipped for cloud build/.test(content)) return content;
|
|
1910
|
+
const guards =
|
|
1911
|
+
` if (project.findProperty('elizaCloudBuild') == 'true') {\n` +
|
|
1912
|
+
` println "[copyForkLlamaLib] skipped for cloud build"\n` +
|
|
1913
|
+
` return\n` +
|
|
1914
|
+
` }\n`;
|
|
1701
1915
|
return content.replace(
|
|
1702
1916
|
/(task copyForkLlamaLib\s*\{\s*\n\s*doLast\s*\{\s*\n)/,
|
|
1703
1917
|
`$1${guards}`,
|
|
@@ -1710,7 +1924,7 @@ export function injectCopyForkLlamaLibTask(content) {
|
|
|
1710
1924
|
}
|
|
1711
1925
|
const block =
|
|
1712
1926
|
`\n// Bundle the MTP Android llama.cpp stack into the APK so mobile\n` +
|
|
1713
|
-
`// gets Eliza-1/
|
|
1927
|
+
`// gets Eliza-1/Gemma 4 support across every supported Android ABI\n` +
|
|
1714
1928
|
`// (arm64-v8a, x86_64, riscv64). The arm64-v8a slice is mandatory for\n` +
|
|
1715
1929
|
`// local-agent capable builds; x86_64 and riscv64 ship when their\n` +
|
|
1716
1930
|
`// per-ABI artifacts exist (Wave 2 cross-compiles land them\n` +
|
|
@@ -1783,25 +1997,35 @@ export function injectCopyForkLlamaLibTask(content) {
|
|
|
1783
1997
|
` return null\n` +
|
|
1784
1998
|
`}\n` +
|
|
1785
1999
|
`\n` +
|
|
2000
|
+
`// NOTE: despite the legacy "ForkLlama" name, this stages the SINGLE canonical\n` +
|
|
2001
|
+
`// fused inference lib — libelizainference.so — with its own DT_NEEDED runtime\n` +
|
|
2002
|
+
`// siblings (libggml*, libllama.so, libllama-common.so, libmtmd.so, libomp.so),\n` +
|
|
2003
|
+
`// which ARE libelizainference's GPU/CPU backends, NOT a separate llama.cpp fork.\n` +
|
|
2004
|
+
`// There is no second inference library; do NOT delete this task or its siblings.\n` +
|
|
1786
2005
|
`task copyForkLlamaLib {\n` +
|
|
1787
2006
|
` doLast {\n` +
|
|
1788
2007
|
` if (project.findProperty('elizaCloudBuild') == 'true') {\n` +
|
|
1789
2008
|
` println "[copyForkLlamaLib] skipped for cloud build"\n` +
|
|
1790
2009
|
` return\n` +
|
|
1791
2010
|
` }\n` +
|
|
1792
|
-
` if (project.findProperty('elizaSkipForkLlamaLib') == 'true' || System.getenv('ELIZA_ANDROID_SKIP_FORK_LLAMA_LIB') == '1') {\n` +
|
|
1793
|
-
` println "[copyForkLlamaLib] skipped by explicit native-lib opt-out"\n` +
|
|
1794
|
-
` return\n` +
|
|
1795
|
-
` }\n` +
|
|
1796
2011
|
` boolean stagedArm64 = false\n` +
|
|
1797
2012
|
` int totalCopied = 0\n` +
|
|
1798
2013
|
` boolean stagedKernels = false\n` +
|
|
1799
2014
|
` project.ext.elizaForkLlamaAbis.each { abi ->\n` +
|
|
1800
2015
|
` def libDir = resolveForkLlamaLibDir(abi)\n` +
|
|
1801
2016
|
` if (!libDir) {\n` +
|
|
2017
|
+
` // No fresh source configured. If the fused lib set is already\n` +
|
|
2018
|
+
` // staged in jniLibs (a prior build, the common dev case), use it\n` +
|
|
2019
|
+
` // as-is so a plain build:android "just works" without any flag.\n` +
|
|
2020
|
+
` def alreadyStaged = new File(file("src/main/jniLibs/\${abi}"), 'libelizainference.so')\n` +
|
|
2021
|
+
` if (alreadyStaged.isFile()) {\n` +
|
|
2022
|
+
` logger.lifecycle("[copyForkLlamaLib] no source dir for \${abi}; libelizainference.so already staged in jniLibs — using the pre-staged fused lib set")\n` +
|
|
2023
|
+
` if (abi == 'arm64-v8a') stagedArm64 = true\n` +
|
|
2024
|
+
` return\n` +
|
|
2025
|
+
` }\n` +
|
|
1802
2026
|
` if (abi == 'arm64-v8a') {\n` +
|
|
1803
|
-
` // arm64-v8a is the mandatory baseline ABI; missing it is a hard error.\n` +
|
|
1804
|
-
` throw new GradleException("[copyForkLlamaLib] no
|
|
2027
|
+
` // arm64-v8a is the mandatory baseline ABI; missing it (and no pre-staged lib) is a hard error.\n` +
|
|
2028
|
+
` throw new GradleException("[copyForkLlamaLib] no fused inference lib for arm64-v8a (not configured, not pre-staged). Run packages/app-core/scripts/aosp/compile-libllama.mjs --target android-arm64-vulkan-fused (the Android cross-compiler; build-llama-cpp-mtp.mjs has no Android targets) or set -Peliza.mtp.android.libdir / ELIZA_MTP_ANDROID_LIBDIR.")\n` +
|
|
1805
2029
|
` }\n` +
|
|
1806
2030
|
` logger.lifecycle("[copyForkLlamaLib] no fork lib dir for ABI \${abi}; skipping")\n` +
|
|
1807
2031
|
` return\n` +
|
|
@@ -2540,7 +2764,20 @@ export function validateAndroidAppActionsXmlResource(
|
|
|
2540
2764
|
return failures;
|
|
2541
2765
|
}
|
|
2542
2766
|
|
|
2767
|
+
function assertSharedTreeOnlyForEliza(what) {
|
|
2768
|
+
if (
|
|
2769
|
+
APP.appId !== "ai.elizaos.app" &&
|
|
2770
|
+
path.resolve(androidDir) === path.resolve(platformsDir, "android")
|
|
2771
|
+
) {
|
|
2772
|
+
throw new Error(
|
|
2773
|
+
`[mobile-build] Refusing to ${what} for brand '${APP.appId}' in the shared elizaOS android tree (${androidDir}). ` +
|
|
2774
|
+
"Whitelabel builds must use apps/app/android (set ELIZA_ANDROID_USE_APP_DIR=1); the elizaOS build owns the shared tree.",
|
|
2775
|
+
);
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2543
2779
|
function syncAndroidAppActionsResources() {
|
|
2780
|
+
assertSharedTreeOnlyForEliza("patch app-actions resources");
|
|
2544
2781
|
const templateResDir = path.join(
|
|
2545
2782
|
platformsDir,
|
|
2546
2783
|
"android",
|
|
@@ -2690,6 +2927,7 @@ function restoreAndroidManifestFromPlatformTemplateIfMissing() {
|
|
|
2690
2927
|
}
|
|
2691
2928
|
|
|
2692
2929
|
function overlayAndroid({ includeAospRoleLaunchers = false } = {}) {
|
|
2930
|
+
assertSharedTreeOnlyForEliza("overlay Java sources");
|
|
2693
2931
|
const templateJavaRoot = path.join(
|
|
2694
2932
|
platformsDir,
|
|
2695
2933
|
"android",
|
|
@@ -2806,7 +3044,23 @@ function overlayAndroid({ includeAospRoleLaunchers = false } = {}) {
|
|
|
2806
3044
|
code = injectBrandUserAgentMarkers(code, APP.userAgentMarkers ?? []);
|
|
2807
3045
|
}
|
|
2808
3046
|
fs.writeFileSync(path.join(dstJava, file), code, "utf8");
|
|
2809
|
-
|
|
3047
|
+
// Rewrite the legacy-package copy's R/BuildConfig imports so any file left
|
|
3048
|
+
// behind in the old package still resolves — but ONLY when that copy lives
|
|
3049
|
+
// in THIS build's own android dir. NEVER write into the shared elizaOS
|
|
3050
|
+
// template tree (platforms/android): a whitelabel build
|
|
3051
|
+
// (ELIZA_ANDROID_USE_APP_DIR) reads that template READ-ONLY, and writing
|
|
3052
|
+
// the brand package back into it corrupts the elizaOS checkout's
|
|
3053
|
+
// ai/elizaos/app sources (the recurring "package ai.milady.app does not
|
|
3054
|
+
// exist" pollution that breaks the next elizaOS build). srcJava resolves
|
|
3055
|
+
// to templateJava for a whitelabel build, so this guard is what keeps the
|
|
3056
|
+
// two brands' source trees separate.
|
|
3057
|
+
const srcInOwnAndroidDir = path
|
|
3058
|
+
.resolve(src)
|
|
3059
|
+
.startsWith(`${path.resolve(androidDir)}${path.sep}`);
|
|
3060
|
+
if (
|
|
3061
|
+
srcInOwnAndroidDir &&
|
|
3062
|
+
path.resolve(src) !== path.resolve(path.join(dstJava, file))
|
|
3063
|
+
) {
|
|
2810
3064
|
const legacyCode = fs
|
|
2811
3065
|
.readFileSync(src, "utf8")
|
|
2812
3066
|
.replaceAll(
|
|
@@ -3699,7 +3953,14 @@ function shouldSkipIosPodInstall(env = process.env) {
|
|
|
3699
3953
|
return isTruthyEnv(env.ELIZA_IOS_SKIP_POD_INSTALL);
|
|
3700
3954
|
}
|
|
3701
3955
|
|
|
3702
|
-
|
|
3956
|
+
// An iOS build ships the on-device no-JIT Bun engine (and thus a real local
|
|
3957
|
+
// agent) when it is explicitly requested, OR when it is a store/App Store build
|
|
3958
|
+
// with the local runtime left enabled (the default). App Store builds are
|
|
3959
|
+
// cloud-hybrid: they keep the App Store-safe local runtime unless an operator
|
|
3960
|
+
// opts into a cloud-only thin client via ELIZA_IOS_APP_STORE_LOCAL_RUNTIME=0.
|
|
3961
|
+
// Exported so the release preflight + tests share one definition of "will the
|
|
3962
|
+
// shipped IPA actually contain a local agent runtime".
|
|
3963
|
+
export function shouldIncludeIosFullBunEngine(env = process.env) {
|
|
3703
3964
|
return (
|
|
3704
3965
|
isFullIosBunEngineRequested(env) ||
|
|
3705
3966
|
(isIosAppStoreBuild(env) && isIosAppStoreLocalRuntimeEnabled(env))
|
|
@@ -4061,6 +4322,7 @@ function patchInstalledLlamaCapacitorBuildGradle() {
|
|
|
4061
4322
|
}
|
|
4062
4323
|
|
|
4063
4324
|
function patchAndroidGradle() {
|
|
4325
|
+
assertSharedTreeOnlyForEliza("patch gradle identity");
|
|
4064
4326
|
patchAndroidGradleWrapperForReleaseCompat();
|
|
4065
4327
|
patchAndroidGradleProperties();
|
|
4066
4328
|
patchInstalledLlamaCapacitorBuildGradle();
|
|
@@ -4529,6 +4791,7 @@ async function generateIosBrandAssets() {
|
|
|
4529
4791
|
}
|
|
4530
4792
|
|
|
4531
4793
|
async function generateAndroidBrandAssets() {
|
|
4794
|
+
assertSharedTreeOnlyForEliza("write brand icons");
|
|
4532
4795
|
const resDir = path.join(androidDir, "app", "src", "main", "res");
|
|
4533
4796
|
if (!fs.existsSync(resDir)) return;
|
|
4534
4797
|
|
|
@@ -4729,17 +4992,55 @@ function mtpTargetOutDir(target) {
|
|
|
4729
4992
|
);
|
|
4730
4993
|
}
|
|
4731
4994
|
|
|
4995
|
+
function resolveMtpForkSrc() {
|
|
4996
|
+
for (const candidate of MTP_FORK_SRC_CANDIDATES) {
|
|
4997
|
+
if (fs.existsSync(path.join(candidate, "CMakeLists.txt"))) return candidate;
|
|
4998
|
+
}
|
|
4999
|
+
return null;
|
|
5000
|
+
}
|
|
5001
|
+
|
|
5002
|
+
/** `git describe --always --dirty` of the fork, or null when git/desc fails. */
|
|
5003
|
+
function currentMtpForkRevision(forkSrc) {
|
|
5004
|
+
if (!forkSrc) return null;
|
|
5005
|
+
const result = spawnSync(
|
|
5006
|
+
"git",
|
|
5007
|
+
["-C", forkSrc, "describe", "--always", "--dirty"],
|
|
5008
|
+
{ encoding: "utf8" },
|
|
5009
|
+
);
|
|
5010
|
+
if (result.status !== 0) return null;
|
|
5011
|
+
return result.stdout?.trim() || null;
|
|
5012
|
+
}
|
|
5013
|
+
|
|
4732
5014
|
async function ensureMtpIosTarget(target) {
|
|
4733
5015
|
const outDir = mtpTargetOutDir(target);
|
|
4734
5016
|
const capabilities = path.join(outDir, "CAPABILITIES.json");
|
|
4735
|
-
|
|
5017
|
+
const forkSrc = resolveMtpForkSrc();
|
|
5018
|
+
const reuse = mtpSliceReuse(
|
|
5019
|
+
capabilities,
|
|
5020
|
+
forkSrc,
|
|
5021
|
+
currentMtpForkRevision(forkSrc),
|
|
5022
|
+
);
|
|
5023
|
+
const forceRebuild = mtpForceRebuildRequested(reuse, process.env);
|
|
5024
|
+
if (!forceRebuild) {
|
|
4736
5025
|
console.log(
|
|
4737
|
-
`[mobile-build] Reusing
|
|
5026
|
+
`[mobile-build] Reusing fresh mtp artifact for ${target} at ${outDir}`,
|
|
4738
5027
|
);
|
|
4739
5028
|
return outDir;
|
|
4740
5029
|
}
|
|
4741
|
-
|
|
4742
|
-
|
|
5030
|
+
if (fs.existsSync(capabilities)) {
|
|
5031
|
+
console.log(
|
|
5032
|
+
`[mobile-build] Rebuilding mtp artifact for ${target} — ${process.env.ELIZA_IOS_REBUILD_MTP === "1" ? "ELIZA_IOS_REBUILD_MTP=1" : reuse.reason}`,
|
|
5033
|
+
);
|
|
5034
|
+
} else {
|
|
5035
|
+
console.log(`[mobile-build] Building mtp artifact for ${target}`);
|
|
5036
|
+
}
|
|
5037
|
+
// The child builder (build-llama-cpp-mtp.mjs) has its OWN presence-only reuse
|
|
5038
|
+
// gate keyed on ELIZA_MTP_FORCE_REBUILD. Without propagating it, the child
|
|
5039
|
+
// would see the stale CAPABILITIES.json and reuse it — turning this staleness
|
|
5040
|
+
// gate into a no-op. Force the child to actually rebuild (#9309).
|
|
5041
|
+
await run("node", [MTP_BUILD_SCRIPT, "--target", target], {
|
|
5042
|
+
env: { ...process.env, ELIZA_MTP_FORCE_REBUILD: "1" },
|
|
5043
|
+
});
|
|
4743
5044
|
if (!fs.existsSync(capabilities)) {
|
|
4744
5045
|
throw new Error(
|
|
4745
5046
|
`[mobile-build] mtp build for ${target} did not produce CAPABILITIES.json at ${capabilities}. ` +
|
|
@@ -7162,6 +7463,8 @@ async function buildAndroidSystem() {
|
|
|
7162
7463
|
androidDir,
|
|
7163
7464
|
spikeDir: androidAgentSpikeDir,
|
|
7164
7465
|
bunChannel: "canary",
|
|
7466
|
+
// Objective AOSP/chip image: riscv64 bun stays fail-closed (it ships it).
|
|
7467
|
+
objective: true,
|
|
7165
7468
|
});
|
|
7166
7469
|
auditAndroidSystemSource("pre-gradle");
|
|
7167
7470
|
|
|
@@ -7329,6 +7632,11 @@ async function buildIos({ local = false } = {}) {
|
|
|
7329
7632
|
} else {
|
|
7330
7633
|
await runCapacitor(["sync", "ios"]);
|
|
7331
7634
|
}
|
|
7635
|
+
// Overlay the freshly built renderer onto ios/App/App/public and assert it
|
|
7636
|
+
// matches the build — never ship a stale UI whether sync ran, was skipped, or
|
|
7637
|
+
// left old hashed assets behind (issue #9309). Runs before the post-sync agent
|
|
7638
|
+
// re-stage so the agent payload remains the final authority on public/agent.
|
|
7639
|
+
mirrorCapacitorWebPayloadIntoIosDir();
|
|
7332
7640
|
if (includesLocalAgentPayload) {
|
|
7333
7641
|
stageIosAgentRuntime({
|
|
7334
7642
|
appStoreBuild: isIosAppStoreBuild() && !local,
|
|
@@ -7445,6 +7753,20 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
7445
7753
|
} else {
|
|
7446
7754
|
prepareIosOverlay();
|
|
7447
7755
|
await generateIosBrandAssets();
|
|
7756
|
+
// The App Store release pipeline splits the build into `bun run build`
|
|
7757
|
+
// (web) + `cap:sync:ios` + this overlay + fastlane, so it never runs
|
|
7758
|
+
// buildIos()'s local-agent staging. When the build embeds the full Bun
|
|
7759
|
+
// engine, stage the agent runtime payload here (after cap sync, before
|
|
7760
|
+
// pod install / fastlane archive) so the shipped IPA actually contains the
|
|
7761
|
+
// agent the engine runs — without it the engine boots with nothing to
|
|
7762
|
+
// execute. The agent bundle must already be built (packages/agent
|
|
7763
|
+
// build:ios-bun); stageIosAgentRuntime throws with that hint if missing.
|
|
7764
|
+
if (shouldIncludeIosFullBunEngine()) {
|
|
7765
|
+
stageIosAgentRuntime({
|
|
7766
|
+
appStoreBuild: isIosAppStoreBuild(),
|
|
7767
|
+
includeFullBunEngine: true,
|
|
7768
|
+
});
|
|
7769
|
+
}
|
|
7448
7770
|
}
|
|
7449
7771
|
}
|
|
7450
7772
|
|