Interactive PTY: compound commands silently produce no output (WASI EFAULT), and shell diagnostics never reach the terminal
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 52/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 静か
- 技術スタック
- javascript, rust, shell, wasm
調査の方向性
まず crates/execution/assets/runners/wasi-module.js の _fdWrite から始め、特に _writeUint32 と synthetic-pipe のパスを確認してから、crates/CLAUDE.md にある WASM ホストプロセスブリッジのガイダンスを読んでください。AGENTOS_WASM_WASI_DEBUG=1 を有効にし、#1746 で追加された Brush のインタラクティブ PTY スイートを使用してください。複合コマンドの出力と brush の診断情報が EFAULT なしでターミナルに届けば完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
Under an interactive PTY (terminal.open() → brush), compound commands produce no output and no error. The same constructs work through exec() and through sh -c inside the same PTY, so this is specific to brush's interactive path, not to pipelines.
Two symptoms, likely one root cause — both are writes from the interactive shell that never reach the terminal:
- Compound commands (
;,&&,|,( ), backticks) print nothing. Redirecting stderr shows the real failure is WASI errno 21 (EFAULT) on a write. - brush's own diagnostics never reach the PTY at all, so an unknown command silently returns to the prompt instead of printing
command not found.
Symptom 2 is what makes symptom 1 invisible: the shell is reporting an error, it just goes nowhere.
Reproduction
import { AgentOs } from "@rivet-dev/agentos-core";
import common from "@agentos-software/common";
const vm = await AgentOs.create({ software: [common] });
const shell = await vm.terminal.open({ cols: 80, rows: 24 });
const id = shell.shellId;
let buf = "";
vm.onShellData(id, (e) => { buf += Buffer.from(e?.data ?? e).toString("utf8"); });
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
await sleep(1500);
for (const c of [
"echo one", // OK
"echo b; echo c", // FAIL - no output
"echo d && echo e", // FAIL
"echo a | cat", // FAIL
"(echo sub)", // FAIL
"echo `echo backtick`", // FAIL
"echo 'semi;colon'", // OK - quoted, so it is one simple command
"sh -c 'echo b; echo c'", // OK - same PTY, non-interactive brush
"nosuchcmd", // FAIL - no "command not found"
]) {
buf = "";
await vm.terminal.write(id, c + "\n");
await sleep(3000);
console.log(JSON.stringify(c), "=>", JSON.stringify(buf.replace(/\r/g, "")));
}
Observed:
| command | interactive PTY | exec() |
|---|---|---|
echo one |
one |
ok |
uname -a |
correct output | ok |
echo 'semi;colon' |
semi;colon |
ok |
sh -c 'echo a | cat' |
a |
ok |
sh -c 'echo b; echo c' |
b c |
ok |
echo b; echo c |
nothing | ok |
echo d && echo e |
nothing | ok |
echo a | cat |
nothing | ok |
(echo sub) |
nothing | ok |
nosuchcmd |
nothing (no error) | prints error |
Note echo here is a brush builtin, so the failing case involves no external command at all.
The hidden error
Redirecting stderr to a file makes both failures visible:
$ nosuchcmd 2>/tmp/e1
$ cat /tmp/e1
error: command not found: nosuchcmd
$ echo b; echo c 2>/tmp/e2
$ cat /tmp/e2
error: echo: i/o error: Bad address (os error 21)
Under wasm32-wasip1, errno 21 is EFAULT (WASI numbering, not Linux's EISDIR), so "Bad address" and the code agree. brush parsed and executed the list correctly — the write to stdout failed.
Ruled out
- Pipelines /
;themselves —exec("ls /opt/agentos/bin | head -5")returns correct output. - The kernel PTY, fd wiring, job control —
sh -c 'echo a | cat'works inside the failing interactive shell. - stderr routing generally — a child's stderr does reach the terminal (
sh -c 'echo to-stderr 1>&2'renders). Only the interactive shell's own stderr is lost. TERM— identical failure withTERM=xterm-256colorandTERM=dumb.- The terminal client — reproduced entirely server-side via
vm.terminal.write(), no browser involved.
Where to look
_fdWrite in crates/execution/assets/runners/wasi-module.js:1404 returns EFAULT only via _writeUint32 (:413) — _mapFsError (:811) defaults to EIO, not EFAULT. So the failing path is the nwritten pointer write, or a synthetic-pipe branch, rather than a generic fs error.
crates/CLAUDE.md already documents this failure mode in the WASM host-process bridge:
child_process.pollreturningECHILDafter anexitevent's trailing-drain pass is terminal, not a new fault … post-exit drain loops must stop onECHILDinstead of converting a successful pipeline intoWASI_ERRNO_FAULT.
Debug logging: AGENTOS_WASM_WASI_DEBUG=1 enables [agentos-wasi] traces from that runner.
Per software/CLAUDE.md ("fix portability one layer down, in the sysroot … patch the real upstream tool only as a fallback"), the fix likely belongs in the WASI/fd layer rather than in brush.
Related
- #1881 — adjacent but different: kernel-stub command resolution inside subshells via
exec, whereecho hi | head -n 1still works. Shares the "silent failure / misleading exit code" theme. - #1657 — other brush redirection divergences (
>>,< file). - #1746 — merged; restored interactive shell correctness and added a real Brush interactive PTY suite, which is the natural harness for a regression test here.
- 主要言語
- Rust
- スター
- 4.8k
- フォーク
- 272
- 平均マージ
- 13時間 24分
- マージ済み PR(30日)
- 49
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
rivet-dev/agentos のほかの issue
-
難易度 3/5 半日 初心者へのやさしさ 32/100
rivet-dev/agentos#2020 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Inline JavaScript resolves dynamic import() from / instead of the working directory対応中かも @mittal-parth が 34 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
rivet-dev/agentos#1973 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 52/100
メンテナーはふだん 1 日以内に返信
-
Guest-execution slot counter has no near-threshold warning対応中かも @SparshSunilNaik が 56 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
rivet-dev/agentos の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
farion1231/cc-switch#8829 ·
メンテナーはふだん 1 日以内に返信
-
Validate CI command vectors before indexing Cargo subcommands対応中かも @amandeavor が今日担当しました。 オープンbug ci good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 92/100
longbridge/gpui-kit#3677 ·
メンテナーはふだん 1 日以内に返信
-
E-pr-welcome
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
seanmonstar/reqwest#3121 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 68/100
ilya-zlobintsev/LACT#1235 ·
メンテナーはふだん 1 日以内に返信