-
Notifications
You must be signed in to change notification settings - Fork 3k
fix(dws): include command output in failures #10279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |||||||||
| */ | ||||||||||
|
|
||||||||||
| import { execFile } from 'node:child_process'; | ||||||||||
| import { sanitizeLogText } from '@qwen-code/channel-base'; | ||||||||||
| import { dwsProcessEnvironment } from './dws-environment.js'; | ||||||||||
| import { | ||||||||||
| startDwsEventProcess, | ||||||||||
|
|
@@ -16,6 +17,8 @@ | |||||||||
| const DWS_PROCESS_FORCE_KILL_DELAY_MS = 5_000; | ||||||||||
| const MINIMUM_DWS_VERSION = [1, 0, 57] as const; | ||||||||||
| const DWS_MAX_OUTPUT_BYTES = 16 * 1024 * 1024; | ||||||||||
| const DWS_ERROR_OUTPUT_MAX_CHARS = 1000; | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] R1-1: The 1000-code-point detail budget exceeds every consumer cap in this package. All 15 — qwen3.8-max via Qwen Code /review (v0.22.2) |
||||||||||
| const ANSI_ESCAPE_SEQUENCE = /\u001b\[[0-?]*[ -/]*[@-~]/g; | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] This hand-rolled CSI-only regex duplicates stripping the repo already centralizes, and misses non-CSI sequences. OSC payloads — a window title import { stripVTControlCharacters } from 'node:util';
// ...
const details = sanitizeLogText(
stripVTControlCharacters(output),
DWS_ERROR_OUTPUT_MAX_CHARS,
).trim();The dws package depends only on channel-base, so — qwen3.8-max via Qwen Code /review (v0.22.2) |
||||||||||
| const MAX_MESSAGE_PAGES = 100; | ||||||||||
| const MAX_TODO_PAGES = 50; | ||||||||||
| const TODO_PAGE_SIZE = 20; | ||||||||||
|
|
@@ -187,6 +190,21 @@ | |||||||||
| : 'unknown'; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| function dwsCommandFailureMessage( | ||||||||||
| code: unknown, | ||||||||||
| stdout: unknown, | ||||||||||
| stderr: unknown, | ||||||||||
| ): string { | ||||||||||
| const base = `DWS command failed${code === undefined ? '' : ` (${String(code)})`}`; | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The
Suggested change
The SIGKILL test already stages — qwen3.8-max via Qwen Code /review (v0.22.2)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] R1-3: The
Suggested change
The SIGKILL test already stages — qwen3.8-max via Qwen Code /review (v0.22.2) |
||||||||||
| const output = String(stderr ?? '').trim() || String(stdout ?? '').trim(); | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The stdout-fallback and empty-output branches of this helper have no test. The added test exercises only non-empty stderr, and the pre-existing SIGKILL test that traverses the empty path asserts only — qwen3.8-max via Qwen Code /review (v0.22.2)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The stderr->stdout fallback selects on the pre-sanitize raw text, so control-only stderr suppresses a usable stdout detail. If — qwen3.8-max via Qwen Code /review (v0.22.2) |
||||||||||
| if (!output) return `${base}.`; | ||||||||||
| const details = sanitizeLogText( | ||||||||||
| output.replace(ANSI_ESCAPE_SEQUENCE, ''), | ||||||||||
| DWS_ERROR_OUTPUT_MAX_CHARS, | ||||||||||
| ).trim(); | ||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The entire output — up to the 16 MiB const window = output.slice(0, 2 * DWS_ERROR_OUTPUT_MAX_CHARS);
const details = sanitizeLogText(
window.replace(ANSI_ESCAPE_SEQUENCE, ''),
DWS_ERROR_OUTPUT_MAX_CHARS,
).trim();2000 UTF-16 units always contain the first 1000 code points, and a mid-CSI window cut stays safe because — qwen3.8-max via Qwen Code /review (v0.22.2)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The 1000-code-point cap is pinned by no test — the added test feeds only ~45 chars of stderr, and a repo-wide grep finds — qwen3.8-max via Qwen Code /review (v0.22.2) |
||||||||||
| return details ? `${base}: ${details}` : `${base}.`; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| function runDwsProcess( | ||||||||||
| executable: string, | ||||||||||
| args: string[], | ||||||||||
|
|
@@ -212,7 +230,7 @@ | |||||||||
| const outcome = classifyDwsCommandFailure(code); | ||||||||||
| reject( | ||||||||||
| new DwsCommandError( | ||||||||||
| `DWS command failed${code === undefined ? '' : ` (${String(code)})`}.`, | ||||||||||
| dwsCommandFailureMessage(code, stdout, stderr), | ||||||||||
| outcome, | ||||||||||
| ), | ||||||||||
| ); | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] The 1000-code-point detail budget exceeds every consumer cap in this package. All 15
error.messagelog sites indws-channel.tsre-cap withsanitizeLogText(..., 300)(logReactionFailureat 200), andChannelBase.lifecycleErrorcaps at 200 — so, including the ~24-charDWS command failed (N):prefix, at most ~276 chars of detail ever surface. Concretely: an ~800-char JSON error body on stderr is run through the ANSI regex andsanitizeLogTextat full cost to build a 1000-code-point detail, and then every site that logs it truncates the whole message to <=300 — ~70-80% of the prepared detail is discarded on every failure while the O(maxBuffer) processing cost is paid in full. The log excerpts in the linked issue are exactly these 300-capped sites. Consider aligning the budget with the consumer caps (e.g. 256, matching GithubAdapter's stderr-hint budget) and windowing the raw output before per-character work — or documenting that the extra budget is intentional for theErrorobject itself. If the budget changes, extenddws-client-process.test.tswith a stderr detail longer than the budget and assert the detail segment is capped — removing the cap must make that test red.— qwen3.8-max via Qwen Code /review (v0.22.2)