The previous version (1.1.0) has a native-level bug on macOS where each
PTY spawn leaks one /dev/ptmx file descriptor that is never closed. Over
a long session with hundreds of shell commands, this exhausts the
system-wide PTY pool (kern.tty.ptmx_max = 511), breaking other programs
like tmux and new terminal windows.
Root cause: microsoft/node-pty#882
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Previously, only shell scripts (.sh) had .claude -> .qwen path replacement.
Markdown files (.md) like cancel-ralph.md and help.md were missing this
conversion, causing incorrect paths like .claude/ralph-loop.local.md.
Now performVariableReplacement also replaces .claude directory references
in markdown files using the same regex pattern as shell scripts.
Root cause: PR #1835 accidentally overwrote PR #1912's correct telemetry
isolation during a merge conflict resolution. This restores the original
guard logic so subagent GeminiChat instances (which don't receive a
telemetryService param) no longer write to the global uiTelemetryService.
- Remove unused uiTelemetryService import from geminiChat.ts
- Guard telemetry calls with this.telemetryService checks
- Add test verifying subagent isolation
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
When the WASM files cannot be found (e.g. symlinked CLI whose vendor path
probe still fails, or any other I/O error), isShellCommandReadOnlyAST and
initParser previously left the agent in a permanently broken state:
- initParser() returned a rejected promise stored in initPromise, so every
subsequent call returned the same rejection immediately
- isShellCommandReadOnlyAST() propagated the error to its caller, which
caused the shell tool to throw and left the agent 'thinking forever'
Changes:
- Import isShellCommandReadOnly from shellReadOnlyChecker.js
- Track parserInitFailed: boolean flag on the parser singleton
- initParser(): on any init error, set parserInitFailed=true and reset
initPromise=null (preventing permanent hang on the rejected promise)
- isShellCommandReadOnlyAST(): check parserInitFailed before attempting
AST parse; wrap the AST path in try/catch so any unexpected runtime
error also falls through to the regex checker
- _resetParser(): also resets parserInitFailed so tests can re-initialise
- Export _setParserFailedForTesting() to allow unit tests to exercise the
fallback path without breaking actual WASM loading
Tests added:
- Fallback suite: verifies that when the parser is marked as failed, all
isShellCommandReadOnlyAST calls delegate to isShellCommandReadOnly and
that _resetParser() restores normal AST operation
- Consistency suite: 40+ commands from shellReadOnlyChecker.test.ts run
through BOTH implementations; every case must agree. Known intentional
divergences (pure assignment, process substitution, control flow,
function definitions) are documented explicitly - all happen to agree
on the same boolean result, confirming the two implementations are
behaviourally consistent across the tested corpus
Fixes#2758
The previous fix used fs.realpathSync(fileURLToPath(import.meta.url)) to
resolve symlinks before computing the WASM path. This works in the common
case (/usr/bin/qwen → /usr/lib/node_modules/.../cli.js), but silently falls
back to the unresolved symlink path when:
- realpathSync throws (ENOENT, EACCES, ELOOP, or other OS-level errors)
- Node.js has already resolved import.meta.url to the real path on some
platforms (making realpathSync a no-op and the first candidate correct),
but the vendor files are still not found at that location
The new approach for the bundle case (inSrcUtils = false) collects up to four
candidate directories:
1. path.dirname(fileURLToPath(import.meta.url)) — already resolved on
Node.js 18+ on most platforms
2. path.dirname(realpathSync(import.meta.url)) — symlink-resolved fallback
3. path.dirname(process.argv[1]) — entry point as invoked
4. path.dirname(realpathSync(process.argv[1])) — resolved entry point
It then calls fs.existsSync on each candidate path for the requested .wasm
file and returns the first one that actually exists, rather than trusting
that a single path computation is correct. If none exist we fall back to
the first candidate so the caller still gets a deterministic ENOENT (instead
of silently using a wrong path).
Fixes#2758
- Strip trailing orphaned funcCall (force=true) before split point calculation,
so normal compression logic runs cleanly on the remaining history instead of
requiring ad-hoc special-casing
- Remove redundant lastToolCompletionSplitPoint machinery: after fixing the
i+2 index bug, lastSplitPoint already subsumes it, making Math.max redundant
- Add MIN_COMPRESSION_FRACTION constant (0.05) to guard against futile API
calls when historyToCompress is too small relative to total history
- Add tests for orphaned funcCall handling (force=true compresses, force=false NOOP)
- Add test for MIN_COMPRESSION_FRACTION guard
Fixes#2647
The skill instructed agents to write temp files via `cat > file <<'EOF'`
in run_shell_command, which contradicts the repo's tool guidance
("Use write_file, NOT echo >/cat <<EOF"). Resolve the contradiction by:
1. Adding write_file to allowedTools in SKILL.md frontmatter
2. Replacing shell heredoc file writes with write_file tool calls
3. Keeping -F body=@file and --body-file for shell-safe gh api/pr usage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Review content may contain double quotes, $VAR, backticks, etc. that
break double-quoted shell arguments or trigger run_shell_command security
rejection. Replace direct string interpolation with a two-step approach:
1. Write body to temp file via quoted heredoc (<<'BODYEOF') which
prevents ALL shell expansion
2. Reference file with -F body=@/tmp/pr-comment.txt in gh api calls
and --body-file in gh pr review calls
Also update Step 5 to clean up all temp files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add explicit `-f start_side="RIGHT"` to the multi-line gh api comment
example. GitHub API docs indicate start_side may be required for ranged
comments. Adding it explicitly is low-cost and eliminates ambiguity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes for 7 issues raised in PR review:
1. [Critical] Extract exclusion criteria into shared "Exclusion Criteria"
section, referenced by both Step 2 and Step 2.5 to prevent drift
2. [Suggestion] Specify exact token matching for --comment flag parsing
(not substring match, ignore --commentary etc.)
3. [Suggestion] Replace `git rev-parse HEAD` with `gh pr view --json
headRefOid` to get correct remote PR HEAD SHA
4. [Suggestion] Use heredoc to construct comment body with real newlines
instead of broken \n escape in -f flag
5. [Nice to have] Add batch limit of 10 for parallel verification agents
6. [Nice to have] Add error handling: skip Step 4 if gh commands fail
7. [Suggestion] Issue #4 (endpoint) deferred — current approach documented
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add LineEnding type and detectLineEnding() function to fileSystemService
- Detect and record line ending format in readTextFile _meta
- Honor lineEnding from _meta in writeTextFile to restore original format
- Update edit.ts and write-file.ts to pass lineEnding through _meta
- Add comprehensive unit tests for line ending detection and preservation
Fixes: #2704
- Remove project-level qwen-settings-config skill and its references/
- Create bundled qc-helper skill at packages/core/src/skills/bundled/
that references docs/users/ for answering usage/config questions
- Update copy_bundle_assets.js to copy docs/users/ into dist/bundled/qc-helper/docs/
- Update dev.js to create symlink for dev mode docs access
- Add bundled docs directory verification in prepare-package.js
- Revert doc-update skills (docs-audit-and-refresh, docs-update-from-diff)
to main branch versions