mirror of
https://github.com/Heretek-AI/hermes-mobile.git
synced 2026-07-01 16:12:43 -04:00
892d778b08
Make the on-device Termux install flow actually work end-to-end. Three workstreams from plans/atomic-wondering-sunrise.md plus a validation patch: Workstream A — F-Droid deep-link from WelcomeScreen - The 'Install locally (Termux)' card no longer renders a dead disabled Continue button when Termux is missing. It now shows two stacked CTAs: primary 'Open F-Droid' (existing termux_install_action string, now actually used) deep-linking https://f-droid.org/packages/com.termux/, and secondary 'Or get it from GitHub Releases' (new string) for side-loaders deep-linking github.com/termux/termux-app/releases. - Reuses existing HermesApi.openExternal; no new IPC method needed. Workstream B — HermesInstaller backend-aware shell dispatch - runShell / runHermesDoctor / runPipInstall in HermesInstaller now branch on currentBackend() and dispatch to TermuxRunner on Termux, bundled.runPython on Bundled. Pre-fix, every stage shelled through bundled.runPython regardless of backend, so Termux installs failed immediately at stage 3 with 'Bundled Python not available'. Workstream C — RUN_COMMAND_PENDING_INTENT for real exit codes - New TermuxResultReceiver.kt: BroadcastReceiver + TermuxResultRegistry process-singleton. Atomic session IDs, ConcurrentHashMap of Continuations, PendingIntent.FLAG_MUTABLE result intent builder (FLAG_MUTABLE is required — Termux's RunCommandService adds the result bundle to the PendingIntent before broadcasting it back). - New TermuxRunner.runAndWait(command, cwd): suspend fn using suspendCancellableCoroutine (modeled on GatewayClient.request), attaches the result PendingIntent via the com.termux.RUN_COMMAND_PENDING_INTENT intent extra. Resolves with a BundledPythonRunner.PythonResult carrying the real exit code + truncated stdout/stderr (~100KB cap imposed by Termux). - HermesInstaller.runShellViaTermux switches from termux.run to termux.runAndWait. The 4 call sites (stages 3/4/5/8 in runStages, plus runHermesUpdate) already gate on exitCode != 0 and consume stderr/stdout, so they become correct automatically. - applyPatches rewritten as suspend: dispatches git apply via Termux using a bash heredoc to write the patch content to Termux's $PREFIX/tmp/ (our app's process can't write into Termux's sandbox). Drops the now-stale TODO(workstream-B-followup) comment. - AndroidManifest gets a <queries> block declaring Termux package visibility — without it, on API 30+, PackageManager.getPackageInfo returns NameNotFoundException even when Termux is installed and HermesInstaller falls through to the bundled-Python backend. Also adds com.termux.permission.RUN_COMMAND (user-granted in Android Settings -> App info -> Additional permissions). - TermuxProbe.isRunCommandResultSupported() helper checks Termux versionName >= 0.109 (the floor for RUN_COMMAND_PENDING_INTENT). - InstallScreen surfaces a TermuxPermissionNeededCard when an install stage fails with a Termux-specific error pattern (RUN_COMMAND, allow-external-apps, plugin_action_disabled — NOT the bare word 'permission' which pip prints routinely). The card has an 'Open App Settings' button using a new HermesApi.openAppSettings() helper that fires Settings.ACTION_APPLICATION_DETAILS_SETTINGS. - setup-android.sh gains a queries-merge step. Anchored on start-of-line for awk and probes android:name="com.termux" for detect-and-skip (so a future library's unrelated <queries> block doesn't silently skip the Termux merge). Validation patch — markerDir + Termux sandbox awareness (B1–B5) - An adversarial review found that HermesInstaller assumed every path it computes (hermesPython, hermesRepo, hermesVenv, the verified marker) lives somewhere our app can read. On Termux backend hermesHome resolves to /data/data/com.termux/files/home/.hermes which is OFF-LIMITS to our process. Pre-Workstream-C the install never succeeded on Termux so these checks were never exercised against real state; Workstream C made the install actually work, so the broken file-existence checks now blocked every user from ever reaching AppState.Main. - Fix: backend-aware markerDir at context.filesDir/hermes-markers/ on Termux (hermesHome on Bundled). New sentinels hermesVerifiedMarker / hermesRepoClonedMarker / hermesVenvCreatedMarker live there. Stages 3 & 4 write their marker on success and check the marker (not the file) for skip-on-rerun. checkInstall().installed/configured/hasApiKey collapse to 'verified marker exists' on Termux (the marker IS the success signal of a completed install). - Stage 4 switches from python3.11 to python on Termux — Termux's pkg install python ships the binary as 'python' symlinked to the current 3.x; the literal 'python3.11' was a Bundled-path assumption that happened to work on some Termux setups but not others. - getHermesVersion becomes suspend + backend-aware (Termux dispatches the importlib.metadata.version call via runAndWait); HermesApi cascades. Plan + research artifacts - plans/atomic-wondering-sunrise.md is the live source-of-truth plan/postmortem (3 shipped workstreams + validation section). - docs/python-bundling-alternatives.md captures the research that showed Termux + RESULT_INTENT is the right v1 path and that the originally-planned Chaquopy workstream isn't needed. Alpine minirootfs + proot is the recommended Tier 2 alternative for users without Termux, downloaded on first run (no APK bloat, no GPL contagion, F-Droid compatible). Build status - ./gradlew :app:assembleDebug green (arm64-v8a, armeabi-v7a, x86_64, universal APKs, ~20MB each). - script/check-kotlin-drift.sh green (59 Kotlin files in sync). - graphify graph rebuilt (1681 nodes, 2866 edges). Untested on device. Verification steps for happy path, permission-denied regression, and cancellation hygiene are in the plan's Workstream C verification section. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
69 lines
996 B
Plaintext
69 lines
996 B
Plaintext
# Project metadata
|
|
.claude/
|
|
CLAUDE.md
|
|
review/
|
|
|
|
# Dependencies
|
|
node_modules/
|
|
.pnpm-store/
|
|
|
|
# Build artifacts
|
|
dist/
|
|
build/
|
|
out/
|
|
*.tsbuildinfo
|
|
|
|
# Capacitor / Android
|
|
apps/mobile/android/.gradle/
|
|
apps/mobile/android/.idea/
|
|
apps/mobile/android/local.properties
|
|
apps/mobile/android/app/build/
|
|
apps/mobile/android/captures/
|
|
apps/mobile/android/app/release/
|
|
apps/mobile/android/app/debug/
|
|
apps/mobile/android/*.iml
|
|
apps/mobile/android/.cxx/
|
|
|
|
# iOS (not used in v1, scaffolded for future)
|
|
apps/mobile/ios/Pods/
|
|
apps/mobile/ios/build/
|
|
|
|
# Generated renderer
|
|
packages/renderer/dist/
|
|
|
|
# Keystore and signing material
|
|
*.jks
|
|
*.keystore
|
|
keystore.properties
|
|
android-runner/app/release.keystore
|
|
|
|
# Logs
|
|
*.log
|
|
npm-debug.log*
|
|
yarn-debug.log*
|
|
yarn-error.log*
|
|
|
|
# OS files
|
|
.DS_Store
|
|
Thumbs.db
|
|
|
|
# Editor
|
|
.vscode/*
|
|
!.vscode/extensions.json
|
|
.idea/
|
|
|
|
# Env
|
|
.env
|
|
.env.local
|
|
.env.*.local
|
|
|
|
# Python artifacts (vendored hermes-agent install)
|
|
__pycache__/
|
|
*.pyc
|
|
.pytest_cache/
|
|
.venv/
|
|
venv/
|
|
|
|
# Sensitive
|
|
.sentryclirc
|
|
graphify-out/ |