Skip to content

feat: terminal fail safe#2144

Draft
RohitKushvaha01 wants to merge 1 commit into
Acode-Foundation:mainfrom
RohitKushvaha01:main
Draft

feat: terminal fail safe#2144
RohitKushvaha01 wants to merge 1 commit into
Acode-Foundation:mainfrom
RohitKushvaha01:main

Conversation

@RohitKushvaha01
Copy link
Copy Markdown
Member

@RohitKushvaha01 RohitKushvaha01 commented Jun 1, 2026

Closes #2084

@RohitKushvaha01 RohitKushvaha01 marked this pull request as draft June 1, 2026 10:39
@github-actions github-actions Bot added the translations Anything related to Translations Whether a Issue or PR label Jun 1, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 1, 2026

Greptile Summary

This PR adds a "failsafe mode" terminal setting that launches the axs server directly via the Android system linker, bypassing proot — intended for devices where proot is broken. To enable the failsafe path it also restructures init-alpine.sh to run one-time setup unconditionally and fall through to bash.

  • Failsafe path (Terminal.js): detects architecture, resolves the 32/64-bit linker, and runs axs -c \"sh -i\" without proot when the setting is on; the outer shell's PID ($$) is written to the pid file rather than axs's own PID, so stopAxs() kills the shell while axs is orphaned and continues holding the port.
  • init-alpine.sh refactor: removes the if [ \"$#\" -eq 0 ] branch that previously wrote the pid file and launched \"$PREFIX/axs\" -c \"bash --rcfile /initrc -i\"; the replacement ends with exec /bin/bash --rcfile /initrc, meaning the axs HTTP server is never started and no pid file is ever written in the normal (non-failsafe) flow.
  • i18n: 32 locale files gain the \"failsafe mode\" key but none (besides en-us) receive the \"info-failsafeMode\" description key; the restart toast in terminalSettings.js is also hardcoded in English.

Confidence Score: 2/5

The normal (non-failsafe) terminal path is broken: axs is never started and the pid file is never written, so every session open fails after a 10-second polling timeout.

The refactored init-alpine.sh removed the two lines that made the default terminal work — writing the pid and launching the axs HTTP server — replacing them with a bare exec /bin/bash that has no connection to the axs session infrastructure. Additionally, the failsafe mode's process-management model writes the wrong PID, leaving axs as an orphan after every terminal stop. These two issues together mean neither code path leaves the terminal in a reliably working state.

src/plugins/terminal/scripts/init-alpine.sh and src/plugins/terminal/www/Terminal.js (failsafe command block) need the most attention before merging.

Important Files Changed

Filename Overview
src/plugins/terminal/scripts/init-alpine.sh Restructured init logic for failsafe compatibility, but the normal (non-failsafe) path no longer starts the axs HTTP server or writes the pid file, breaking default terminal operation.
src/plugins/terminal/www/Terminal.js Adds failsafe mode that launches axs via the Android linker without proot; unquoted filesDir path and orphaned axs process on stopAxs() are concerns in the failsafe command.
src/components/terminal/terminal.js Correctly reads failsafeMode from settings and passes it to startAxs; change is minimal and correct.
src/components/terminal/terminalDefaults.js Adds failsafeMode: false default — straightforward and correct.
src/settings/terminalSettings.js Adds failsafeMode toggle to settings UI; toast message is hardcoded English and info-failsafeMode key is missing from non-English locales.
src/lang/en-us.json Adds both 'failsafe mode' and 'info-failsafeMode' keys; other locales only received 'failsafe mode'.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[createSession called] --> B{isAxsRunning?}
    B -- No --> C[startAxs called]
    C --> D{failsafeMode?}
    D -- Yes / Failsafe --> E["linker axs -c 'sh -i'\n(no proot)"]
    E --> F["echo $$(sh PID) > pid"]
    F --> G[axs HTTP server running]
    D -- No / Normal --> H[source init-sandbox.sh]
    H --> I["proot → init-alpine.sh"]
    I --> J["exec /bin/bash --rcfile /initrc\n(NEW: no axs, no pid written ⚠️)"]
    J --> K["isAxsRunning polls 10×\n→ always false ⚠️"]
    K --> L["Toast: Failed to start AXS\nfetch to localhost fails ⚠️"]
    B -- Yes --> M[POST /terminals]
    G --> M
    M --> N[Terminal session open]

    subgraph stopAxs
        O["kill -KILL (sh PID)"] --> P[sh dies]
        P --> Q["axs orphaned, still on port ⚠️"]
    end
Loading

Reviews (1): Last reviewed commit: "feat: terminal fail safe" | Re-trigger Greptile

Comment on lines +229 to +235
if [ "$1" = "--installing" ]; then
touch "$PREFIX/.configured"
exit 0
fi

# Fallback to bash if no command specified
exec /bin/bash --rcfile /initrc
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 axs server and pid file no longer started in normal mode

The old init-alpine.sh wrote echo "$$" > "$PREFIX/pid" and then launched "$PREFIX/axs" -c "bash --rcfile /initrc -i" in the no-args (normal terminal start) branch. The new code replaces both with exec /bin/bash --rcfile /initrc, which runs bash inside proot but never starts the axs HTTP server.

createSession() in terminal.js connects to http://localhost:{port}/terminals — which only works when axs is running. With no pid file, isAxsRunning() always returns false, so startAxs is called on every session open; the 10-second polling loop exhausts, a toast fires, and then the fetch to the axs endpoint fails. The terminal is effectively broken in the default (non-failsafe) mode after this change.

}).then(async (uuid) => {
await Executor.write(uuid, `source ${filesDir}/init-sandbox.sh ${installing ? "--installing" : ""}; exit`);
if (failsafeMode) {
await Executor.write(uuid, `chmod +x ${filesDir}/axs; echo $$ > ${filesDir}/pid; ${linker} ${filesDir}/axs -c "sh -i"; exit`);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Unquoted ${filesDir} will break on paths containing spaces. All three uses should be double-quoted within the shell string.

Suggested change
await Executor.write(uuid, `chmod +x ${filesDir}/axs; echo $$ > ${filesDir}/pid; ${linker} ${filesDir}/axs -c "sh -i"; exit`);
await Executor.write(uuid, `chmod +x "${filesDir}/axs"; echo $$ > "${filesDir}/pid"; ${linker} "${filesDir}/axs" -c "sh -i"; exit`);

Comment on lines +71 to +73
if (failsafeMode) {
await Executor.write(uuid, `chmod +x ${filesDir}/axs; echo $$ > ${filesDir}/pid; ${linker} ${filesDir}/axs -c "sh -i"; exit`);
} else {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Failsafe mode: axs process is orphaned when stopAxs() is called

echo $$ > ${filesDir}/pid stores the PID of the outer sh shell (started by Executor.start). stopAxs() then does kill -KILL $(cat $PREFIX/pid), which kills that outer shell. However, the ${linker} ${filesDir}/axs child process is not in the same process group and is not covered by --kill-on-exit (that flag is proot-specific). On Android/Linux, killing a parent with SIGKILL orphans its children — axs survives.

On the next createSession(), isAxsRunning() finds the old sh PID dead and returns false, triggering another startAxs. The new axs instance attempts to bind the same port while the old orphaned instance still holds it, causing the new start to fail silently. Users end up with leaked axs processes accumulating across terminal restarts.

Consider writing the axs PID directly — e.g., start axs in the background, capture $!, write that to the pid file, and wait for it — so stopAxs kills the process that actually owns the port.

Comment on lines +296 to +298
if (key === "failsafeMode") {
toast("Restart terminal to apply changes");
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Hardcoded English toast and missing info-failsafeMode in non-English locales

toast("Restart terminal to apply changes") is not passed through the strings i18n map, so non-English users see English text. A corresponding key (e.g., "restart terminal to apply changes") should be added to all locale files and referenced via strings[...] here.

Additionally, every non-English locale file in this PR only received the "failsafe mode" key; none received "info-failsafeMode". The setting's info field will render as undefined for all non-English users.

@UnschooledGamer
Copy link
Copy Markdown
Member

Wow, Mini Termux-like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

translations Anything related to Translations Whether a Issue or PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Terminal FailSafe mode

2 participants