- Add new skills: bugfix, feat-dev with structured workflows - Update existing skills: docs-audit-and-refresh, docs-update-from-diff, e2e-testing, qwen-code-claw, structured-debugging, terminal-capture - Update test-engineer agent with clearer constraints and formatting - Update qc commands: bugfix, code-review, commit, create-issue, create-pr - Reorganize .gitignore to keep qwen configs near top - Expand AGENTS.md with development commands, feature/bugfix workflows, project directories table, and code review guidelines Co-authored-by: 愚远 <zhenxing.tzx@alibaba-inc.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2.6 KiB
Worked example: headless run prints empty stdout in zsh TTY
A short qwen-code case to illustrate two failure modes from SKILL.md:
reproduction contradiction is data, and instrument the data flow, not just
the code path.
The bug
User: npm run dev -- -p "..." in zsh prints nothing. Process exits clean,
~/.qwen/logs shows the model returned proper text. Stdout was empty.
Cause: JsonOutputAdapter.emitResult wrote resultMessage.result without a
trailing \n. zsh's PROMPT_SP (powerlevel10k, agnoster, …) detects the
missing newline and emits \r\033[K before drawing the next prompt, erasing the
line. Pipe-captured stdout has no PROMPT_SP, so the bug is invisible there.
Fix: append \n to the write.
What made the case instructive
Every reproduction attempt from a debugging environment that captures stdout
(Cursor's Shell tool, out=$(...), tee, file redirect) passed. 14/14
success against the user's 0/N. Same SHA, same machine, same command. The only
variable was: pipe stdout vs TTY stdout.
That contradiction was the entire investigation. Once it was named, the fix was one line.
Lessons mapped to SKILL.md
-
Reproduction contradiction is data, not user error. When your run succeeds and the user's fails on identical state, the difference between the two environments is where the bug lives. Catalogue what differs (TTY vs pipe, terminal emulator, shell, locale, env vars, prior state) before forming any hypothesis. Reframing the user's report ("they must be on stale code") burns rounds and credibility.
-
Ask the one disambiguating question first. "Does it hang or exit cleanly?" would have falsified the most tempting wrong hypothesis here (the recently-fixed drain-loop hang) on turn one. For any "no output" report, that question is free and prunes half the hypothesis space.
-
Instrument the data flow, not just the code path. Tracing whether
writewas called showed the happy path firing every time and resolved nothing. The breakthrough was logging the return value ofprocess.stdout.writetogether withprocess.stdout.isTTY. Code-path traces tell you what ran; data traces tell you what it ran on. -
Pipe ≠ TTY. A passing pipe-captured run does not prove a TTY user sees the same output. Shell prompts can post-process trailing-newline- less writes; terminals can swallow control sequences; pipes do neither. When debugging interactive-shell symptoms, get evidence from the user's actual terminal at least once.
Reference
Fix commit: qwen-code feadf052f — fix(cli): append newline to text-mode emitResult so zsh PROMPT_SP doesn't erase the line