Skip to content

fix(acp): exit help and EOF cleanly#111091

Merged
steipete merged 1 commit into
mainfrom
claude/fix-acp-cli-exit-hang
Jul 19, 2026
Merged

fix(acp): exit help and EOF cleanly#111091
steipete merged 1 commit into
mainfrom
claude/fix-acp-cli-exit-hang

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

Two acp exit hangs. (1) openclaw acp --help and openclaw acp client --help printed their help and then never exited (>8s / >18s, needed killing) — every other command tree's --help exits cleanly. (2) The ACP bridge (acp … --require-existing) did not exit on stdin EOF while waiting for the Gateway. Found by the R7 QA campaign.

Why This Change Was Made

  • The help hang: importing the acp command module eagerly pulled in the ACP client/server runtime (which opens a handle), so even --help — which never runs the command — kept the process alive.
  • The EOF hang: the startup EOF monitor left stdin paused and only did read(0), but Node doesn't emit end until buffered data is consumed, so a client that wrote an initialize/request frame and then closed was never detected.

User Impact

  • acp --help / acp client --help now exit in <0.5s (rc 0) — the ACP runtime is imported lazily inside the action handler, so help/registration doesn't load it. No [INEFFECTIVE_DYNAMIC_IMPORT].
  • The bridge now detects stdin closure losslessly: it reads/buffers pre-handshake input while watching for EOF, so both a zero-byte disconnect AND a disconnect after a real ACP frame exit cleanly if the Gateway never arrives — without dropping the client's frames when the Gateway does connect.

Evidence

  • Exit proof: acp --help 0.48s, acp client --help 0.47s (rc 0).
  • Tests: process-exit tests for both help commands and the non-empty-disconnect EOF case, plus ACP startup/shutdown/lifecycle units — 39/39 focused (incl. src/acp/translator.lifecycle.test.ts); happy-path assertion confirms buffered frames reach the SDK reader.
  • Autoreview (codex gpt-5.6-sol, xhigh): clean — "patch is correct (0.88)".

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes size: M maintainer Maintainer-authored PR labels Jul 19, 2026
@steipete steipete self-assigned this Jul 19, 2026
@steipete
steipete force-pushed the claude/fix-acp-cli-exit-hang branch from 5f50fd7 to 7df9907 Compare July 19, 2026 00:59
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jul 19, 2026
@clawsweeper

clawsweeper Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 18, 2026, 9:37 PM ET / July 19, 2026, 01:37 UTC.

Summary
The branch lazy-loads ACP client/server runtime from CLI action handlers and tees stdin during ACP Gateway startup so help commands exit and pre-handshake EOF is observed without losing buffered frames.

PR surface: Source +81, Tests +360. Total +441 across 4 files.

Reproducibility: no. high-confidence live reproduction was available in the supplied evidence. The changed paths and added process/startup tests make the reported help-hang and pre-Gateway EOF paths source-reproducible with medium confidence.

Review metrics: none identified.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Attach redacted real-run evidence for both help exits and the non-empty EOF case.
  • Show a successful Gateway-ready run that consumes a frame buffered before readiness.
  • Confirm or cover the intended behavior above the 1 MiB pre-Gateway buffer limit.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body asserts timings and focused tests but provides no inspectable redacted terminal output, recording, runtime log, or linked artifact demonstrating the repaired help and EOF paths after the fix; add redacted evidence and update the PR body, then request @clawsweeper re-review if a fresh review does not start automatically.

Risk before merge

  • [P1] The new tee-based startup path governs whether buffered ACP input is delivered or the bridge exits; until inspectable runtime evidence is supplied, message-delivery and termination behavior remain a merge-relevant uncertainty.
  • [P1] The hard 1 MiB pre-Gateway input limit creates a deliberate failure path while Gateway readiness is pending; maintainers should confirm that limit matches the intended ACP startup contract.

Maintainer options:

  1. Add observed ACP path proof (recommended)
    Before merge, attach redacted terminal or live-output evidence for clean help exit, EOF after a non-empty ACP frame without a Gateway, and buffered-frame delivery after Gateway readiness.
  2. Confirm the startup buffer boundary
    Document or add focused coverage for the accepted behavior when pre-Gateway ACP input exceeds the new 1 MiB limit.

Next step before merge

  • [P1] This protected maintainer-labeled PR needs maintainer confirmation of the new ACP startup buffer boundary and contributor-supplied real behavior proof before merge.

Maintainer decision needed

  • Question: Is rejecting ACP stdin after 1 MiB of pre-Gateway buffering the intended bridge contract, including for clients that send a valid early request before Gateway readiness?
  • Rationale: The branch adds a new explicit failure threshold to preserve bounded startup buffering, but the supplied context does not establish an existing ACP size contract or maintainer decision for that threshold.
  • Likely owner: steipete — The supplied context identifies steipete as the current author and assignee for the ACP startup change.
  • Options:
    • Accept the bounded startup contract (recommended): Keep the 1 MiB limit after confirming that early ACP input is expected to remain below it and document or test the intended failure behavior.
    • Use a different bounded strategy: Adjust the buffering approach or threshold if valid ACP startup traffic can exceed 1 MiB before the Gateway becomes ready.

Security
Cleared: The supplied diff changes internal CLI and ACP stream control flow plus tests, with no new dependency, secret, workflow, permission, artifact-download, or package-resolution surface.

Review details

Best possible solution:

Keep the lazy imports, then provide redacted terminal or live-output proof covering both help commands, EOF after a real ACP frame with no Gateway, and successful delivery of buffered input when the Gateway becomes ready; confirm the bounded-buffer failure contract before merge.

Do we have a high-confidence way to reproduce the issue?

No high-confidence live reproduction was available in the supplied evidence. The changed paths and added process/startup tests make the reported help-hang and pre-Gateway EOF paths source-reproducible with medium confidence.

Is this the best way to solve the issue?

Unclear. Lazy-loading runtime imports is a narrow fix for help-process handles, and teeing stdin addresses EOF observability, but the new bounded buffering contract needs maintainer confirmation and observed end-to-end proof.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against b51e3d02c75b.

Label changes

Label justifications:

  • P1: The reported hangs block ACP CLI help and can leave an ACP bridge waiting indefinitely during active workflows.
  • merge-risk: 🚨 message-delivery: The PR changes how ACP stdin bytes are buffered and handed to the SDK before Gateway readiness.
  • merge-risk: 🚨 availability: The PR changes termination behavior for help commands and ACP startup when stdin closes or buffered input reaches its limit.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body asserts timings and focused tests but provides no inspectable redacted terminal output, recording, runtime log, or linked artifact demonstrating the repaired help and EOF paths after the fix; add redacted evidence and update the PR body, then request @clawsweeper re-review if a fresh review does not start automatically.
Evidence reviewed

PR surface:

Source +81, Tests +360. Total +441 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 88 7 +81
Tests 2 362 2 +360
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 450 9 +441

What I checked:

  • CLI runtime loading change: The PR moves ACP server and client imports into Commander action handlers, so help registration no longer imports runtime transports. (src/cli/acp-cli.ts:35, 6027466b48be)
  • ACP EOF handling change: The new startup monitor tees stdin, drains one branch to observe EOF, and retains the other branch for the eventual SDK reader; it also introduces a 1 MiB pre-Gateway input limit. (src/acp/server.ts:33, 6027466b48be)
  • Focused regression coverage: The branch adds process-oriented ACP CLI exit coverage and extends ACP startup tests for non-empty disconnect and buffered input handling. (src/cli/acp-cli-exit.process.test.ts:1, 6027466b48be)
  • Real behavior proof remains uninspectable: The PR body reports sub-second help exits and focused test counts, but it contains no attached terminal output, recording, redacted log, or linked artifact showing the repaired help and EOF paths after the latest head update. (6027466b48be)

Likely related people:

  • steipete: The supplied PR context identifies steipete as both the sole commit author for the ACP change and the assignee; no independent current-main feature-history owner could be established from the available read-only inspection context. (role: current ACP change author and assignee; confidence: low; commits: 6027466b48be; files: src/acp/server.ts, src/cli/acp-cli.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (2 earlier review cycles)
  • reviewed 2026-07-19T01:03:21.796Z sha 7df9907 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-19T01:24:03.147Z sha d38a9b8 :: needs real behavior proof before merge. :: none

@steipete
steipete force-pushed the claude/fix-acp-cli-exit-hang branch from 7df9907 to d38a9b8 Compare July 19, 2026 01:21
@steipete
steipete force-pushed the claude/fix-acp-cli-exit-hang branch from d38a9b8 to 6027466 Compare July 19, 2026 01:34
@steipete
steipete merged commit 7e1aca9 into main Jul 19, 2026
117 checks passed
@steipete
steipete deleted the claude/fix-acp-cli-exit-hang branch July 19, 2026 01:41
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6027466b48

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/acp/server.ts
if (!gatewayConnected) {
void shutdown();
}
}, shutdown);

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 Badge Propagate startup input failures

When stdin raises a read error or pre-hello data crosses the new 1 MiB limit, startupInput.ended rejects, but passing shutdown directly as the rejection callback converts that rejection into successful cleanup. Because shutdown also resolves gatewayReady, serveAcpGateway then returns normally and Commander exits with status 0 without reporting the constructed error. Preserve cleanup while rethrowing the original failure so invalid or failed input produces a diagnostic and nonzero exit.

Useful? React with 👍 / 👎.

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

Labels

cli CLI command changes maintainer Maintainer-authored PR merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: M status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant