Skip to content

fix(terminal): auto-provision Linux sandbox before running commands - #2962

Closed
nicorudorlk22-gif wants to merge 2 commits into
Acode-Foundation:mainfrom
nicorudorlk22-gif:fix/terminal-sandbox-rebased
Closed

nicorudorlk22-gif wants to merge 2 commits into
Acode-Foundation:mainfrom
nicorudorlk22-gif:fix/terminal-sandbox-rebased

Conversation

@nicorudorlk22-gif

Copy link
Copy Markdown

What it does

Reopens the work from #2956 (closed before review) rebased onto the current main — both original commits cherry-picked cleanly, zero conflicts.

Problem: callers that invoke Terminal.startAxs() before the Alpine sandbox has ever been provisioned (core terminal UI on first run, or third-party plugins such as AI copilots that shell out to npm/node) hit a confusing "No such file or directory" on init-sandbox.sh and unknown node/npm versions, instead of the sandbox being set up.

Fix:

  1. startAxs() now guards: if the sandbox is not installed and the caller is not install() itself, it auto-provisions (install then continue) — or throws a clear, actionable error message via err_logger.
  2. A _provisioning flag prevents the internal startAxs(true, ...) call inside install() from re-entering install() and recursing forever.

Notes

biloca added 2 commits October 9, 2026 02:35
Ensures the Alpine sandbox is provisioned automatically before executing
terminal commands, so the built-in terminal works out of the box.
Adds a guard so the sandbox installation check no longer loops forever
when provisioning takes longer than expected.
@greptile-apps

greptile-apps Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium impact] Terminal plugin auto-provisions sandbox before running commands.

Fix competing installations before merging; simultaneous setup calls can delete files another install needs.

Findings

  1. P1 Setup calls delete shared files ▶
  2. P2 First-run setup runs twice ▶

Summary

Adds an installation check to startAxs() and a shared _provisioning flag to limit nested setup calls.

  • Concurrent setup calls can start competing installs and delete each other's files.
  • The normal first-run UI repeats the full installation.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A["UI calls Terminal.install()"] --> B["Extract sandbox"]
  B --> C["Call startAxs(true)"]
  C --> D[".configured missing; flag unset"]
  D --> E["Set flag; call install() again"]
  E --> F["Delete and rebuild sandbox"]
  F --> G["Call startAxs(true) with flag set"]
  G --> H["Configure sandbox and return"]
Loading

Reviews (1) · Last reviewed commit: "fix(terminal): prevent infinite loop dur..." · Reviewed by Greptile

// check, init-sandbox.sh does not exist yet and the caller sees a confusing
// "No such file or directory" + unknown node/npm versions instead of the
// sandbox being set up automatically.
if (!this._provisioning && !(await this.isInstalled())) {

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 Setup calls delete shared files

Two concurrent startAxs(true) calls can both read _provisioning as false before awaiting isInstalled(). Both then call install(). Each install deletes the same sandbox before extracting it, so one can remove files the other needs and make setup fail.

Store and share a pending installation promise before the first await, and keep the internal configuration call separate from outside callers.

this._provisioning = true;
let installed;
try {
installed = await this.install(logger, err_logger);

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 First-run setup runs twice

The normal first-run UI calls Terminal.install() directly, but install() never sets _provisioning. Its final startAxs(true) reaches this branch while .configured is still missing and starts another full install. The second install deletes the files just extracted, extracts them again, and repeats every download on F-Droid.

Set the guard for the whole install() call, or let its final configuration call bypass provisioning.

@RohitKushvaha01

Copy link
Copy Markdown
Member

Hello @nicorudorlk22-gif we will not accept any changes in terminal related stuff for some time due to ongoing migration

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

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants