qwen-code/packages/cli
ChiGao 90052f25ae
fix(cli): prevent silent VP-mode crash by adding uncaughtException handler and error visibility (#8088)
* fix(cli): prevent silent VP-mode crash by adding uncaughtException handler and error visibility

VP (alternate-screen) mode swallows all error output: uncaught exceptions
write their stack trace to stderr which lands on the alternate screen
buffer, then gets discarded when teardown switches back to the primary
buffer. The user sees a silent exit with no error message and nothing in
the debug log.

Root cause: no `uncaughtException` handler existed anywhere in the CLI.
PR #7406's ErrorBoundary and unhandledRejection handler only cover React
render errors and promise rejections — synchronous exceptions bypass both.

Changes:
- Add `setupUncaughtExceptionHandler()` with sync debug-log write,
  alternate-screen exit before stderr output, and clean process.exit(1)
- Add `consumeLastRenderError()` to ErrorBoundary for VP main-screen echo
  after unmount leaves the alternate screen
- Remove SIGTERM/SIGINT handlers from kittyProtocolDetector.ts that
  raced with the main signal handlers (#7779)
- Add SIGHUP handler alongside SIGTERM/SIGINT (#7781)
- Guard ThinkBody's MarkdownDisplay with per-item ErrorBoundary so
  partial markdown during thought streaming degrades to plain text

Related: #7971 #7972 #7779 #7781

* fix(cli): consolidate uncaughtException handler into a single listener (#8088)

The VP-crash handler added a second uncaughtException listener that conflicted with the pre-existing one in runCliEntryPoint: the first listener's process.exit(1) ran before the second, leaving the visibility feature inert for real errors, and the new listener lacked the PTY-race guard, crashing the session on benign teardown errors. Replace the startup handler with one session-aware listener (PTY guard, isTTY-guarded alternate-screen leave, writeStderrLineSafe), sanitize the inline render-error fallback, gate the exit-time render-error echo on onError, and cover SIGHUP exit code.

* fix(cli): harden uncaughtException handler and scope render-error echo (#8088)

* fix(cli): address review feedback on VP crash handler (#8088)

- Close over Config instead of sessionId string so the uncaughtException
  handler reads the current session ID at crash time
- Create debug log directory before appending so the write succeeds on
  fresh installs where ~/.qwen/debug/ does not yet exist
- Sanitize error stack with sanitizeTerminalText before writing to stderr
  to prevent ANSI injection on the persistent main buffer
- Add onError debug logging to the ThinkBody ErrorBoundary
- Gate the '(logged to debug file)' hint on isDebugLogFileEnabled() so
  the message is accurate when debug file logging is disabled

* fix(cli): move uncaught-exception helpers to a leaf module (#8088)

gemini.tsx statically imported handleUncaughtException and
isExpectedPtyRaceError from cli.ts, the esbuild entry point. gemini.tsx
is only ever loaded lazily, so that import formed an entry<->lazy cycle;
with splitting enabled esbuild hoisted the entry body into a shared chunk
and left dist/cli.js as a re-export stub. The bootstrap guard at the
bottom of cli.ts then never ran and the bundled CLI exited 0 silently.

Move the helpers (and the private getErrnoCode) into a new leaf module,
utils/uncaught-exception-handler.ts, imported by both cli.ts and
gemini.tsx. cli.ts re-exports them so existing importers (cli.test.ts)
are unaffected, and the handler reuses the shared writeStderrLine from
stdioHelpers.ts. The uncaughtException behavior itself is unchanged.

---------

Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
2026-07-31 08:39:55 +00:00
..
src fix(cli): prevent silent VP-mode crash by adding uncaughtException handler and error visibility (#8088) 2026-07-31 08:39:55 +00:00
.gitignore feat(core): add opt-in built-in web_search backed by the DashScope Responses API (#7215) 2026-07-21 10:59:36 +00:00
index.ts fix(cli): add bootstrap fast paths (#6188) 2026-07-02 22:28:11 +00:00
package.json chore(release): v0.21.2 (#8200) 2026-07-31 05:22:46 +00:00
test-setup.ts feat(serve): persist dynamic workspace registrations (#6716) 2026-07-11 16:49:40 +00:00
tsconfig.json feat(channels): add GitLab polling channel adapter (#7862) 2026-07-29 14:28:31 +00:00
vitest.config.ts feat(core): tag UserPromptSubmit hook context and record display provenance (#7956) 2026-07-30 11:45:23 +00:00