fix(cli): handle closed plugin uninstall prompt#73566
Conversation
Greptile SummaryThis PR fixes a Node.js The implementation is well-scoped and correct: the Confidence Score: 5/5Safe to merge — targeted bug fix with correct implementation and good test coverage. No P0 or P1 issues found. The logic in No files require special attention. Reviews (2): Last reviewed commit: "fix(cli): match closed prompt errors by ..." | Re-trigger Greptile |
|
Codex review: needs changes before merge. Summary Reproducibility: yes. Current main reaches Real behavior proof Next step before merge Security Review findings
Review detailsBest possible solution: Merge the EOF-aware prompt/uninstall handling after adding a single-line Do we have a high-confidence way to reproduce the issue? Yes. Current main reaches Is this the best way to solve the issue? Yes for the functional patch. Prompt-level EOF detection preserves piped answers while the uninstall handler adds narrow Full review comments:
Overall correctness: patch is correct Acceptance criteria:
What I checked:
Likely related people:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 3f9e64869a31. |
b001327 to
af9af82
Compare
af9af82 to
0fd8a58
Compare
|
Human verification update for Verified scenarios:
Edge cases checked:
What I did not verify:
Re-review progress:
|
0fd8a58 to
a5e248d
Compare
fffbac7 to
4cd1aed
Compare
4cd1aed to
93487c8
Compare
93487c8 to
d754ddc
Compare
|
Merged via squash.
Thanks @ai-hpc! |
|
Verified on installed OpenClaw 2026.5.6 (e301533). Real CLI smoke test:
Observed result: This confirms the installed CLI reaches the confirmation path and exits cleanly with the actionable error instead of Node's previous unsettled top-level await / exit 13 behavior. |
Summary
openclaw plugins uninstall <id>could leave the confirmation prompt await unsettled when stdin closed before an answer, causing Node to exit 13 withDetected unsettled top-level await.--forcefor non-interactive uninstall.promptYesNo()now detects readline close/EOF before an answer and throws a typed prompt-closed error;plugins uninstallcatches that case and exits 1 with an actionable message.y/nanswers andplugins uninstall --forceremain supported; this does not change install records, uninstall planning, or plugin deletion semantics.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause (if applicable)
promptYesNo()awaitedreadline.question()without handling readlineclose/ EOF, so closed stdin could leave the top-level CLI await unsettled.--force, but not EOF-before-answer.plugins uninstallalready supports--force, but the interactive path did not fail cleanly when no confirmation input was possible.Regression Test Plan (if applicable)
src/cli/prompt.test.ts,src/cli/plugins-cli.uninstall.test.tsPromptInputClosedError;plugins uninstallconverts that specific prompt failure into exit 1 without config/index/file mutation.User-visible / Behavior Changes
openclaw plugins uninstall <id> < /dev/nullnow fails with a clear CLI error instead of surfacing Node's unsettled top-level-await warning. Users can rerun interactively, pipey/n, or pass--forcefor non-interactive uninstall.Diagram (if applicable)
Security Impact (required)
No)No)No)No)No)Yes, explain risk + mitigation: N/ARepro + Verification
Environment
Steps
plugins uninstall <id>targets a managed plugin entry or install record.openclaw plugins uninstall <id> < /dev/nullwithout--force.Expected
Actual
Detected unsettled top-level awaitand exit 13.Evidence
Attach at least one:
Local verification:
pnpm test src/cli/prompt.test.ts src/cli/plugins-cli.uninstall.test.ts -- --reporter=verbosepnpm check:changed -- --base upstream/maingit diff --check HEADpromptYesNo(): returnsPromptInputClosedErrorwith process exit 0 in the harness instead of Node exit 13.Human Verification (required)
--forceuninstall path; normal prompt default/y/n behavior.pnpm openclaw plugins uninstall <id> < /dev/nullagainst a real installed plugin, because the focused prompt and CLI seams directly cover the root cause.Review Conversations
Compatibility / Migration
Yes)No)No)Risks and Mitigations
promptYesNo()is shared by a few CLI flows, so changing EOF handling can affect other confirmation prompts.--yesremain covered by existing prompt tests.Real behavior proof
Behavior or issue addressed: Closes #73562 —
openclaw plugins uninstall <id>previously left the readline confirmation await unsettled when stdin closed before an answer (CI lanes, scripts, detached shells,< /dev/null). Node bailed with exit code 13 and the runtime warning "Detected unsettled top-level await", instead of a clean actionable CLI error.Real environment tested: macOS Darwin 25.2.0 (arm64), Node 24.15.0 (Homebrew
node@24), local OpenClaw source checkout at/Users/a1111/openclaw/running directly via the source-aware launcher (node openclaw.mjs) and vianode --import tsxagainst the patchedsrc/cli/prompt.tssource — no test harness, no readline mocking.Exact steps or command run after this patch:
fix/plugin-uninstall-closed-stdin(HEAD4cd1aed4e9, rebased onto upstreamb8f9137d31).node openclaw.mjs --version→OpenClaw 2026.5.4 (4cd1aed).promptYesNodirectly, with stdin pushednullafter 200ms to mirror a closed-pipe /< /dev/nullscenario, wrapped in the samePromptInputClosedErrorcatch block thatplugins-uninstall-command.tsuses.Evidence after fix:
Live terminal capture from the patched source running on my Mac:
For comparison, the same invocation against the original (pre-patch)
prompt.ts— which has noPromptInputClosedErrorclass and noquestionUntilCloseclose-listener — never settles the await. Node printsDetected unsettled top-level await ... exit code 13, which is the original symptom from #73562.The patched runtime path:
prompt.tsquestionUntilCloselistens for the readlinecloseevent, rejects the awaitingpromptYesNo()with a typedPromptInputClosedError, theplugins uninstallcommand's try/catch matches by type, prints the actionable hint, andruntime.exit(1).Observed result after fix:
The CLI process now (a) renders the prompt as before, (b) detects readline EOF/close, (c) raises a typed
PromptInputClosedError, (d) printsError: plugins uninstall requires confirmation input. Re-run in an interactive TTY or pass --force.to stderr, and (e) exits with code 1. Node's "Detected unsettled top-level await" warning and exit code 13 from #73562 no longer occur on this code path.What was not tested:
installRecordspopulated on this dev machine — exercise was against the production prompt module directly via a synthetic close-stdin signal that drives the same readlinecloseevent the production code listens for).readlinecloseevent semantics are platform-consistent per Node docs, but not separately confirmed live on those platforms.settledguard inquestionUntilClosecovers this but was not separately exercised live.