Repository navigation
fix(cli): report an async command error as one line, not a stack trace - #1271
Conversation
The entry boundary reported only `NotInitializedError` as one line; every other error an async action threw escaped as an unhandled rejection, so Node printed it under a `cli.js:NNNN` header with the whole stack. `teamai session list` outside an initialized project showed exactly that. `reportCommandError` now reports whatever a command action throws: one line through `log.error`, `process.exitCode = 1`, and the stack through `log.debug`, which always appends to ~/.teamai/debug.log and prints on the console under --verbose. The per-command `reportNotInitialized` wrapper is unchanged; the boundary is what covers the commands that never wrapped themselves. Two help tests asserted that the entry rejects when `process.exit` is mocked. It reports that throw now, so they await the import and reset exitCode; the help text they check is already on stdout. In production commander calls the real `process.exit` for --help, so the boundary never sees it. Fixes Tencent#1270.
|
No findings in the specified diff. The PR description satisfies the testing requirement: it documents a post-build real-CLI run, including exit codes, stderr output, and verbose stack output. Deferring the full suite to CI is not blocking. Review was read-only; I did not run, build, or install anything from the PR. |
SaulMoro
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
@Smilewithoutfalling Approving. We built this head and main (d60e68f5) and ran both in an isolated HOME.
teamai session listoutside a project:mainexits 1 with Node'scli.jsheader and the full stack. This head exits 1 with one line on stderr,✖ No teamai project config found....teamai -v session listprints the same line, and the stack shows up as debug output.~/.teamai/debug.loggets the error and the stack with or without-v.teamai status,--versionand an unknown command behave the same as onmain.- The new e2e test passes on this head and fails 2/2 against
main's build.
[P3 nit] In src/__tests__/index-codebase-help.test.ts:23 and src/__tests__/index-import-help.test.ts:23, the old rejects.toThrow('process.exit(0)') also checked that --help reaches process.exit(0). The new form no longer checks it. Keeping the spy and adding expect(exitSpy).toHaveBeenCalledWith(0) would bring that back. Optional.
#1234, #1208 and #1191 also edit src/index.ts, but none of them touches the entry error handler.
Summary
The entry boundary reported only
NotInitializedErroras one line. Any other error an async action threw escaped as an unhandled rejection, so Node printed it under acli.js:NNNNheader with the whole stack (teamai session listoutside an initialized project, for example). The boundary now reports whatever a command action throws as one line on stderr and exits 1, and keeps the stack for--verboseand~/.teamai/debug.log.Type of Change
Test Plan
npx tsc --noEmitpassesnpm run lintpasses on the touched files (0 warnings, 0 errors)npx vitest runpasses on every entry test this touches; the full local suite is left to CI (it takes over 15 minutes on this host)npm run build, in a cold$HOME(see the record below)Real CLI
Before (main
d60e68f5, built the same way),teamai session listin an empty cwd:After:
~/.teamai/debug.logcarries both the[ERROR]line and the[DEBUG]stack in either mode.Unchanged:
status,env list,members list,tags liststill print one line and exit 1;--versionstill exits 0.The new
src/__tests__/e2e/cli-error-exit.test.tsfails on the build frommain(2 failed: the stack is in stderr, and--verboseprints nothing) and passes on this one.Suite note
The entry tests (
index-not-initialized,index-migration-trigger,index-codebase-help,index-import-help,cli-path,session-cmd) run as one batch. One of them fails on this Windows host, and it fails the same way with this change reverted:The test drives a
--cwd /run/dirfixture whose POSIX path does not resolve here, so it is not from this PR. The full suite is left to CI.Related Issues
Fixes #1270
Notes for Reviewers
--verbose. That is wherelog.debugalready writes (writeInfoLine), andlog.debugalso appends to~/.teamai/debug.logon every run, so support keeps the trace without a flag. I did not special-case a second destination for it.reportNotInitializedstays as it is.status,listandpushstill report inside their own action; the boundary is what covers the commands that never wrapped themselves, such assession list.index-codebase-help.test.tsandindex-import-help.test.tsmockprocess.exitto throw and asserted that the entry rejects with it (rejects.toThrow('process.exit(0)')). A boundary that reports every error now reports that throw instead, so they await the import and resetprocess.exitCode. The help text they check is already on stdout by then, and in production--help/--versionnever reach the boundary: commander calls the realprocess.exit.index-not-initialized.test.tsgained four cases forreportCommandErroritself: message and exit code without rejecting, the stack reachinglog.debug, an empty message falling back to the error name, and a thrown non-Errorvalue with no invented stack.teamai digestprintsFailed to generate digest: teamai is not initialized...and exits 0, so a script cannot tell it failed. Different cause, so I did not fold it in here.