Bug type
Crash (process/app exits or hangs)
Beta release blocker
No
Summary
openclaw plugins uninstall <id> awaits the confirmation prompt through promptYesNo(). When stdin is closed (for example < /dev/null) and --force is not used, Node can exit with Detected unsettled top-level await and code 13 instead of returning a clear CLI error.
Steps to reproduce
- Use OpenClaw 2026.4.27 on Node 22.
- Ensure the target plugin id is managed by plugin config or install records.
- Run
pnpm openclaw plugins uninstall <id> < /dev/null.
- Observe the uninstall confirmation prompt starts.
- Observe Node exits with
Detected unsettled top-level await and exit code 13.
Expected behavior
The command should fail cleanly with exit code 1 and an actionable message, for example:
Error: plugins uninstall requires confirmation input. Re-run in an interactive TTY or pass --force.
Piped answers should continue to work:
echo "n" | openclaw plugins uninstall <id>
echo "y" | openclaw plugins uninstall <id>
Non-interactive automation can also use:
openclaw plugins uninstall <id> --force
Actual behavior
With closed stdin, the prompt await can remain unsettled and Node exits with code 13:
Uninstall plugin "<id>"? [y/N] Warning: Detected unsettled top-level await at file:///.../openclaw.mjs:233
if (await tryImport("./dist/entry.js")) {
^
ELIFECYCLE Command failed with exit code 13.
OpenClaw version
2026.4.27 source checkout
Operating system
Ubuntu/Linux
Install method
pnpm dev
Model
N/A
Provider / routing chain
N/A
Additional provider/model setup details
N/A. This is in the CLI prompt path before any provider/model call.
Logs, screenshots, and evidence
The OpenClaw code path is:
src/cli/plugins-cli.ts: plugins uninstall calls promptYesNo() when --force is not set.
src/cli/prompt.ts: promptYesNo() directly awaits readline.question() and does not handle readline close / EOF.
Minimal Node 22.22.1 reproduction of the dependency behavior:
timeout 10s node --input-type=module -e 'import readline from "node:readline/promises"; const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const answer = await rl.question("Question? "); console.log("answer", JSON.stringify(answer)); rl.close();' < /dev/null
Observed result:
exit=13
Question? Warning: Detected unsettled top-level await at file:///.../[eval1]:1
Impact and severity
Affected users/systems/channels: anyone running plugins uninstall from CI, scripts, detached shells, or other closed-stdin contexts without --force.
Severity: crash / DX bug. No data corruption observed because the crash happens before config writes.
Frequency: deterministic for the closed-stdin prompt case in the minimal Node/readline reproduction; OpenClaw reaches this prompt path when uninstalling a managed plugin without --force.
Consequence: automation receives exit 13 and an internal Node warning instead of a clear OpenClaw CLI error.
Additional information
Suggested fix: make promptYesNo() EOF-aware by racing readline.question() with readline close, while preserving piped y / n behavior. Then have plugins uninstall catch the closed-input case and exit 1 with a message that suggests --force.
Avoid a simple !process.stdin.isTTY gate because it would break currently working piped answers.
Suggested tests:
src/cli/prompt.test.ts: closed readline rejects or returns a distinct closed-input result instead of hanging.
src/cli/plugins-cli.uninstall.test.ts: closed confirmation exits 1, does not write config, and suggests --force.
- Existing
--force, cancel, and successful uninstall paths still pass.
Related: #73551 documents the separate stale-entry seed path that can make users try plugins uninstall as cleanup.
Bug type
Crash (process/app exits or hangs)
Beta release blocker
No
Summary
openclaw plugins uninstall <id>awaits the confirmation prompt throughpromptYesNo(). When stdin is closed (for example< /dev/null) and--forceis not used, Node can exit withDetected unsettled top-level awaitand code 13 instead of returning a clear CLI error.Steps to reproduce
pnpm openclaw plugins uninstall <id> < /dev/null.Detected unsettled top-level awaitand exit code 13.Expected behavior
The command should fail cleanly with exit code 1 and an actionable message, for example:
Piped answers should continue to work:
Non-interactive automation can also use:
Actual behavior
With closed stdin, the prompt await can remain unsettled and Node exits with code 13:
OpenClaw version
2026.4.27 source checkout
Operating system
Ubuntu/Linux
Install method
pnpm dev
Model
N/A
Provider / routing chain
N/A
Additional provider/model setup details
N/A. This is in the CLI prompt path before any provider/model call.
Logs, screenshots, and evidence
The OpenClaw code path is:
src/cli/plugins-cli.ts:plugins uninstallcallspromptYesNo()when--forceis not set.src/cli/prompt.ts:promptYesNo()directly awaitsreadline.question()and does not handle readlineclose/ EOF.Minimal Node 22.22.1 reproduction of the dependency behavior:
Observed result:
Impact and severity
Affected users/systems/channels: anyone running
plugins uninstallfrom CI, scripts, detached shells, or other closed-stdin contexts without--force.Severity: crash / DX bug. No data corruption observed because the crash happens before config writes.
Frequency: deterministic for the closed-stdin prompt case in the minimal Node/readline reproduction; OpenClaw reaches this prompt path when uninstalling a managed plugin without
--force.Consequence: automation receives exit 13 and an internal Node warning instead of a clear OpenClaw CLI error.
Additional information
Suggested fix: make
promptYesNo()EOF-aware by racingreadline.question()with readlineclose, while preserving pipedy/nbehavior. Then haveplugins uninstallcatch the closed-input case and exit 1 with a message that suggests--force.Avoid a simple
!process.stdin.isTTYgate because it would break currently working piped answers.Suggested tests:
src/cli/prompt.test.ts: closed readline rejects or returns a distinct closed-input result instead of hanging.src/cli/plugins-cli.uninstall.test.ts: closed confirmation exits 1, does not write config, and suggests--force.--force, cancel, and successful uninstall paths still pass.Related: #73551 documents the separate stale-entry seed path that can make users try
plugins uninstallas cleanup.