feat: upstream backports — MCP reconnect, compress fixes, hooks cleanup, follow-up suggestions#2866
Closed
mabry1985 wants to merge 130 commits into
Closed
feat: upstream backports — MCP reconnect, compress fixes, hooks cleanup, follow-up suggestions#2866mabry1985 wants to merge 130 commits into
mabry1985 wants to merge 130 commits into
Conversation
Phase 1 – Prompt Cache Boundary
- Split getCoreSystemPrompt() return into StructuredSystemPrompt {staticPrefix, dynamicSuffix, full}
- Anthropic converter emits static prefix with cache_control: {type:'ephemeral'}, dynamic suffix without
- DashScope provider splits system message at boundary for OpenAI-compat caching
Phase 2 – Task Management System
- Replace TodoWriteTool with 6 task tools: task_create, task_get, task_list, task_update, task_stop, task_output
- New TaskStore service with CRUD, hierarchy, persistence to .qwen/runtime/tasks/{sessionId}.json
- Task interface: id, parentTaskId, title, description, status, priority, createdBy, createdAt, output
- Remove todoWrite.ts; update tool-names.ts, config.ts, prompts.ts, builtin-agents.ts
- ACP layer: task tools emit regular tool_call events (no special plan_update routing)
Phase 3 – Dream Memory Consolidation
- New MemoryConsolidationService with three-gate trigger (time/session-count/PID lock)
- Four-phase consolidation: orient → gather → consolidate (model side-query) → prune (200-line cap)
- Runs on session teardown; state at .qwen/runtime/memory-consolidation-state.json
- Configurable via memoryConsolidation settings: minSessionsBetween, minHoursBetween, maxMemoryLines
Phase 4 – Auto-Approval Classifier
- New AutoApproveClassifier: fast-path deny/allow patterns + model side-query for ambiguous cases
- Add ToolCallDecision.AUTO_ACCEPT enum value; wire into PermissionManager.evaluate()
- Settings: autoApproval.{model, maxPerSession, denyPatterns, allowPatterns}
Phase 5 – Verification Agent
- Add 'verify' read-only builtin agent (ReadFile, Grep, Glob, Shell, LS, LSP)
- Wire into Stop hook path: spawn verify subagent, block on passed: false with issues as stopReason
Phase 6 – Completion Checker
- New CompletionChecker heuristic service (no model call): checks unresolved shell errors,
edits-without-tests, mentioned-but-never-run tests, uncommitted changes in git workflows
- Wire into hookSystem.ts fireStopEvent() as synthetic blocking StopHookOutput
Phase 7 – Incremental Context Compaction
- Replace all-or-nothing compress() with incremental approach
- Protect fresh tail (10 messages), compress oldest chunk (20 messages) per call
- Mark compressed nodes with [COMPRESSED_CONTEXT] prefix
- Add getIncrementalCompressionPrompt() to prompts.ts
Also: disable import/no-internal-modules ESLint rule (pervasively violated throughout
the existing codebase; rule cannot be enforced without a full-codebase cleanup)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ports high-value agent engineering patterns from Claude Code's architecture into the Qwen Code fork. Full details in the squashed commit.
Phase 5 added 'verify' as a third builtin agent. Update test assertions that hardcoded the expected count (5→6) and name list to include 'verify'. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Phase 5 added 'verify' as a third builtin agent. Update compiled JS test assertions that hardcoded expected count (5→6) and name list. Also suppress pre-existing no-undef/console lint error in the compiled file. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- logger.test.ts/js: append process.pid to temp dir to prevent EACCES under parallel vitest workers sharing the same fixture path - packages/vendor/tree-sitter/: add tree-sitter.wasm + tree-sitter-bash.wasm for compiled .js test paths (levelsUp=3 targets packages/vendor/, not core/vendor/) - eslint.config.js: add Node globals block for packages/*/src/**/*.test.js with no-undef:off, no-console:off, and no-unused-vars caughtErrorsIgnorePattern Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…gnore Root cause: tsc emits .js/.d.ts files alongside .ts sources in src/, and vitest's default include picks up both. Every test ran twice, causing temp-dir races between the .ts and .js versions of the same test. - packages/core/vitest.config.ts: exclude *.test.js and *.spec.js so only TypeScript sources run (canonical) - packages/core/.gitignore: ignore src/**/*.js, *.d.ts, *.js.map to prevent future compiled output from accumulating untracked - Remove previously committed logger.test.js and subagent-manager.test.js (compiled duplicates; fixes belong in the .ts sources) Result: 190/190 test files pass, 4968 tests, 0 failures. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…r test - packages/cli/vitest.config.ts: restrict include to .ts/.tsx only; add *.test.js and *.spec.js to exclude (compiled outputs not tests) - HistoryReplayer.test.ts: update TodoWriteTool test — isTodoWriteTool now always returns false (Phase 2 replacement), so todo_write results emit tool_call_update instead of plan; assert new behavior with objectContaining Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ectory linting
ESLint flat config resolves `files` patterns relative to the config root.
When the package runs `eslint src` from its own directory, paths arrive as
`src/...` rather than `packages/vscode-ide-companion/src/...`, so the root
config's scoped overrides (import/no-internal-modules, no-unused-vars,
react/prop-types) do not match.
- Add packages/vscode-ide-companion/eslint.config.js: extends root config,
adds src/**/*.{ts,tsx,js} overrides with the correct rules for local invocation
- Remove now-redundant eslint-disable-next-line comments in webview/index.tsx
(import/no-internal-modules is now off for the whole package)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…giene
- telemetry/sdk.ts: add buildLangfuseSpanProcessor() — activates from env
vars (LANGFUSE_PUBLIC_KEY/SECRET_KEY/BASE_URL), sends traces to
${LANGFUSE_BASE_URL}/api/public/otel/v1/traces with Basic auth. Runs
alongside primary OTLP exporter even when getTelemetryEnabled() is false.
- telemetry/sdk.test.ts: isolate Langfuse env vars in beforeEach/afterEach
so host-env keys don't contaminate assertions about OTLPTraceExporterHttp
call counts.
- openaiContentGenerator/pipeline.ts: OTel span per LLM call with GenAI
semantic conventions (gen_ai.system, gen_ai.operation.name,
gen_ai.request.model). Raw chunk delta logging via createDebugLogger
('OPENAI_PIPELINE') — reveals whether LiteLLM routes thinking tokens to
reasoning_content or delta.content.
- .gitignore: suppress 741 co-located TypeScript compilation artifacts
(docs/, integration-tests/, scripts/, packages/*/src/, vitest.config.*,
__snapshots__/*.js.snap). Root tsconfig has no outDir so tsc emits
alongside .ts sources. gitignore is the correct fix — noEmit on the base
config breaks TS6310 composite project references.
- settings.schema.json: memoryConsolidation config block for Phase 3
(Dream Memory Consolidation).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enables qwen-code to read Claude Code project files without requiring manual conversion or duplication: - paths.ts, storage.ts: export CLAUDE_DIR = '.claude'; add '.claude' to SKILL_PROVIDER_CONFIG_DIRS so ~/.claude/skills/ and project/.claude/skills/ are searched alongside .qwen and .agents variants. - storage.ts: add getUserCommandsDirs() and getProjectCommandsDirs() returning both .qwen/commands and .claude/commands paths. - FileCommandLoader.ts: use plural methods so ~/.claude/commands/ and project/.claude/commands/ are loaded every session. - memoryTool.ts: add 'CLAUDE.md' to the context filename list. The existing upward-scan in memoryDiscovery already handles project-root CLAUDE.md files; this just enables the filename to be matched. - memoryDiscovery.ts: route CLAUDE.md global lookup to ~/.claude/ instead of ~/.qwen/ (matching Claude Code's own location). All other filenames continue to use ~/.qwen/. - skill-manager.test.ts: update base-dirs count assertions from 2 → 3. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Integrates obra/superpowers (https://github.com/obra/superpowers) as a native, zero-config behavioral layer. No hook configuration required. ## What's included 14 skills bundled at packages/core/src/skills/bundled/superpowers/: brainstorming, test-driven-development, writing-plans, executing-plans, subagent-driven-development, systematic-debugging, dispatching-parallel-agents, using-git-worktrees, verification-before-completion, finishing-a-development-branch, requesting-code-review, receiving-code-review, writing-skills, using-superpowers subagent-driven-development prompt templates adapted for quad-code: Task tool → Agent tool in implementer-prompt.md, spec-reviewer-prompt.md, code-quality-reviewer-prompt.md ## Bootstrap mechanism prompts.ts dynamicSuffix now reads the bundled using-superpowers/SKILL.md synchronously at session start and injects it wrapped in <EXTREMELY_IMPORTANT> tags — matching the original superpowers SessionStart hook design. The model receives the full behavioral scaffolding before the first user message with no tool round-trip required. The skill path resolves relative to prompts.js via import.meta.url, so it works in both dev (dist/src/core/ → dist/src/skills/bundled/) and the CLI bundle (copy_files.js carries .md files through the build). ## Effect Every session opens with the superpowers pipeline active: brainstorm → plan → subagent-execute → verify → finish Skills are also available by name via the Skill tool for on-demand invocation. Project or user skills in .qwen/skills/ or .claude/skills/ take precedence. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s them SkillManager.loadSkillsFromDir scans one level deep, so bundled/superpowers/*/SKILL.md was invisible. Move all superpowers skill dirs up to bundled/ directly and update the prompts.ts using-superpowers path accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reads installed_plugins.json and adds each plugin's commands/ dir to the user command search path, so quad inherits all installed Claude Code plugins (protolabs, rabbit-hole, etc.) with zero configuration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…support - Rename binary from quad/protocli to `proto` - Replace ANSI Shadow ASCII art with larry3d font for proto - Rename all user-facing "Qwen Code" strings to "proto" (91 files) - Replace in-memory TaskStore with beads_rust (`br`) CLI backend - SQLite + JSONL persistence via `br` subprocess calls - Falls back to original in-memory store if `br` not installed - Status mapping: open->pending, in_progress, closed->completed, deferred->blocked - Add protolabs MCP server config to ~/.qwen/settings.json - Rewrite README with proto branding, feature comparison table, and usage docs - Update remote to github.com/protoLabsAI/protoCLI Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…reaming Tools that completed while the model was still streaming its response were silently dropped by the isResponding guard in handleCompletedTools. This left stale toolCalls with responseSubmittedToGemini=false, keeping streamingState stuck on Responding indefinitely (the "I'm Feeling Lucky" spinner). Fix: queue completed tools in a ref and drain the queue via useEffect when isResponding transitions to false. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eading newline - Change QWEN_DIR from '.qwen' to '.proto' for all global and per-project paths - SKILL_PROVIDER_CONFIG_DIRS reads from .proto, .qwen, .agents, .claude (backwards compat) - Rename context file from QWEN.md to PROTO.md (reads QWEN.md + CLAUDE.md as fallbacks) - Rewrite AGENTS.md with proto branding and updated project overview - Trim leading newlines from first model content chunk (fixes blank line after diamond) - Update all user-facing path references (~/.proto/settings.json, .proto/commands/, etc.) - Add npm run ship script (build + link) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…points Drop the unused sdk-java package (~22K lines) and rewrite the README Quick Start section to walk through presetting an OpenAI-compatible endpoint with modelProviders, API key via .env, and auth bypass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the append-only PROTO.md bullet list with Claude Code-style
file-per-memory architecture:
- Each memory is a separate .md file with name/description/type frontmatter
- 4 memory types: user, feedback, project, reference
- MEMORY.md auto-generated index (max 200 lines / 25KB), loaded into system prompt
- save_memory tool now creates individual files via memoryStore.createMemory()
- New type param on save_memory for categorizing memories
- Memory system prompt with taxonomy injected when MEMORY.md exists
- Old PROTO.md memories still load (backward compat), migration available
- Storage helpers: getGlobalMemoryDir(), getProjectMemoryDir()
New files: packages/core/src/memory/{types,frontmatterParser,memoryStore,
memoryPrompt,migration,index}.ts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 2 of the memory system overhaul: - memoryExtractor.ts: spawns a restricted AgentHeadless after each conversation turn to extract memorable facts from recent messages. Fire-and-forget with cursor tracking (.cursor file) to avoid reprocessing. Max 5 turns, 2 minute timeout. - memoryScan.ts: scan memory headers and format as text manifest for injection into extraction agent prompts - memoryAge.ts: human-readable freshness (today/yesterday/N days ago) and staleness warnings for memories older than 30 days - Extraction triggered from useGeminiStream.ts finally block (non-blocking) - Restricted tool set: read_file, write_file, glob only Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- /memory list: shows all memory files across both scopes with type, age, staleness warnings, and description - /memory forget <name>: deletes a memory by name from either scope - Remove migration.ts (greenfield, no legacy memories to migrate) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add Memory section to README with type table, file format example, slash commands, and auto-extraction description - Update feature comparison table with memory row - Fix clone URL to protoLabsAI/protoCLI - Add memory commands to commands table - Update AGENTS.md with memory system overview and commands Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ages Replace raw isSubmittingQueryRef boolean with generation-based QueryGuard to prevent stale async finally blocks from releasing the lock prematurely. Add popLast() to message queue for one-at-a-time cancel behavior instead of dumping the entire queue into the input buffer. Improve queue display with a labeled header showing message count. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of holding queued messages until the turn finishes, drain them in handleCompletedTools and inject alongside tool results so the model sees user input immediately and can decide whether to act on it or continue current work. Fallback drain on idle catches pure text turns. Adds drain() to useMessageQueue with ref mirror for synchronous reads. Uses ref bridge in AppContainer to cross the hook ordering boundary. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
useMessageQueue is now a pure external store (MessageQueueStore class) subscribed via useSyncExternalStore. drain() and popLast() return values synchronously — no refs, no stale closures, no hook ordering hacks. Queue declared before useGeminiStream so drain is passed directly. Idle-drain effect moved to AppContainer where both submitQuery and the queue are in scope. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Run git status, branch, and recent commits at session init before the agent touches anything. Surfaces dirty working trees with a warning so the agent (and user) know the starting state. Supports an optional configurable verification command. Inspired by the "verify before building" pattern from Anthropic and OpenAI harness engineering guides. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After file-modifying tools (write_file, edit), run a configurable verify command and inject failures into the model context alongside tool results. The model sees build errors immediately and can self-correct without a new turn. Configure via settings: tools.verifyCommand (e.g. "npx tsc --noEmit"). Disabled by default — no overhead when unconfigured. Implements the "separate evaluator" pattern from Anthropic/OpenAI harness engineering guides: generation and evaluation are independent, and the evaluator is skeptical by default. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, verification
Four improvements informed by Anthropic/OpenAI harness engineering guides
and Claude Code prompt architecture audit:
1. Compression prompt: 9-section structured summary replacing 4-section
XML snapshot. Preserves user messages verbatim, debugging history,
reasoning chains, and precise work state. Adds "resume immediately"
rule to prevent wasted turns acknowledging summaries.
2. Memory extraction: strict 2-turn budget (was 5). Turn 1: all reads
in parallel. Turn 2: all writes in parallel. Prevents sprawl.
3. System prompt: failure recovery 6-step protocol, permission scope
non-generalization ("approval for X is not approval for Y"),
reversibility assessment before destructive actions.
4. Adversarial verification skill: rationalization trap list, spot-check
warning, adversarial probes (concurrency, boundary, idempotency),
structured PASS/FAIL/PARTIAL verdict format.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Restore lsp field to CliArgs interface (removed by hooks cleanup cherry-pick) - Add lsp: undefined to auth handler and gemini test fixtures - Resolve client.ts conflict: keep both endTurnSpan and cache-safe param saving - Fix speculationToolGate: ToolNames.TODO_WRITE → ToolNames.TASK_LIST - mcp-tool: replace getStringifiedResultForDisplay with getDisplayFromParts, remove unused allowlist field and truncateTextParts method Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ideCommand.test: remove install subcommand tests (no longer in ideCommand) - constants.test: update DISPLAY_HOOK_EVENTS length from 12→15 (3 new hook events) - Footer.test: mock VoiceMicButton to avoid UIActionsProvider dep, add voice state fields to mock UIState, update snapshots - client.test: add getDisableAllHooks mock for hooks cleanup change Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- constants.test: replace hardcoded count with Object.values(HookEventName).length so the test stays correct when the enum grows - ideCommand.test: remove unused getIdeInstaller mock from vi.mock block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- coreToolScheduler.test + nonInteractiveToolExecutor.test: add getDisableAllHooks mock to all mock configs (hooks cleanup change) - mcp-tool.ts: restore output truncation via truncateParts helper using existing truncateToolOutput utility - mcp-tool.ts: gate auto-reconnect on isConnectionError check so generic errors (Invalid parameters) don't trigger reconnect - extension/npm.ts: fix CodeQL alerts — use replaceAll for '/' encoding in scoped package names Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add file.on('error') handler to write stream in downloadNpmTarball so
stream errors during res.pipe() properly reject the Promise instead of
hanging forever
- Fix name.replace('/', '%2f') → replaceAll in downloadFromNpmRegistry
(line 285 was missed in previous commit; line 374 already correct)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…up, follow-up suggestions (#19) * fix: improve /compress split point selection for tool-heavy conversations When conversation history is near the context window limit and dominated by tool call/response cycles, findCompressSplitPoint would return a near-zero split point because it only considered non-functionResponse user messages as valid split points. This caused /compress to send almost no history to the compression API (e.g. 29 tokens), producing a useless summary that inflated token count instead of reducing it. Changes: - Track tool completion boundaries (positions after functionResponse) as fallback split points in findCompressSplitPoint - Add user-with-functionResponse to the compress-everything safety check - Use Math.max of primary and fallback split points for better coverage - Add minimum content guard (5% threshold) to prevent futile API calls - Add 4 new test cases covering tool-heavy conversation scenarios Fixes QwenLM#2647 * fix: handle orphaned funcCall and improve compression logic for tool-heavy conversations - 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 QwenLM#2647 * fix: upgrade @lydell/node-pty to 1.2.0-beta.10 to fix PTY FD leak 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> * fix(cli): add kitty sequence timeout management and buffer handling improvements in KeypressProvider * remove hooks experimental and refactor hook Config * fix(hooks): clean up abort listener in error handler The error handler in hookRunner cleared the timeout but did not remove the abort signal listener, unlike the close handler. When spawn fails (e.g. executable not found), only the error event fires — the close event is not guaranteed — so the abort listener leaked on the signal. * feat(extension): add npm registry support for extension installation - Add new npm extension installation channel via scoped packages (@scope/name) - Implement npm.ts module with registry resolution, authentication, and download logic - Support version pinning, dist-tags (latest, beta), and custom registries - Handle private registry auth via NPM_TOKEN env var and .npmrc _authToken entries - Update CLI install command with --registry flag for npm extensions - Add comprehensive tests for npm package parsing and registry operations - Update documentation for releasing and installing from npm registries - Integrate npm updates into extension manager and update checking flow This enables teams using npm for package distribution to publish Qwen Code extensions through their existing infrastructure, with full support for private registries and access control. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * feat(mcp): add reconnect command and implement auto-reconnect logic * refactor(mcp): enhance reconnect logic and error handling * test(mcp): update tests to include verification of reconnect command registration * feat(cli): add follow-up suggestions feature * fix: post-backport build fixes - Restore lsp field to CliArgs interface (removed by hooks cleanup cherry-pick) - Add lsp: undefined to auth handler and gemini test fixtures - Resolve client.ts conflict: keep both endTurnSpan and cache-safe param saving - Fix speculationToolGate: ToolNames.TODO_WRITE → ToolNames.TASK_LIST - mcp-tool: replace getStringifiedResultForDisplay with getDisplayFromParts, remove unused allowlist field and truncateTextParts method Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): update tests for upstream backport changes - ideCommand.test: remove install subcommand tests (no longer in ideCommand) - constants.test: update DISPLAY_HOOK_EVENTS length from 12→15 (3 new hook events) - Footer.test: mock VoiceMicButton to avoid UIActionsProvider dep, add voice state fields to mock UIState, update snapshots - client.test: add getDisableAllHooks mock for hooks cleanup change Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): harden test assertions per code review - constants.test: replace hardcoded count with Object.values(HookEventName).length so the test stays correct when the enum grows - ideCommand.test: remove unused getIdeInstaller mock from vi.mock block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests,core): resolve CI failures on upstream backport PR - coreToolScheduler.test + nonInteractiveToolExecutor.test: add getDisableAllHooks mock to all mock configs (hooks cleanup change) - mcp-tool.ts: restore output truncation via truncateParts helper using existing truncateToolOutput utility - mcp-tool.ts: gate auto-reconnect on isConnectionError check so generic errors (Invalid parameters) don't trigger reconnect - extension/npm.ts: fix CodeQL alerts — use replaceAll for '/' encoding in scoped package names Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(extension): harden npm download stream and fix slash encoding - Add file.on('error') handler to write stream in downloadNpmTarball so stream errors during res.pipe() properly reject the Promise instead of hanging forever - Fix name.replace('/', '%2f') → replaceAll in downloadFromNpmRegistry (line 285 was missed in previous commit; line 374 already correct) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: LaZzyMan <zeusdream7@gmail.com> Co-authored-by: tanzhenxin <tanzhenxing1987@gmail.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qqqys <qys177@gmail.com> Co-authored-by: DennisYu07 <617072224@qq.com> Co-authored-by: chinesepowered <nlai@rediffmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
IDE integration is no longer supported. Voice integration section covers: - audio backend requirements (sox/arecord) per OS - protoLabs hosted STT endpoint option - self-hosted faster-whisper-server option - settings.json config and /voice commands Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
No protoLabs-hosted voice service — self-hosted only. Also removes the unused HOSTED_STT_ENDPOINT export. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of loading all context files found (PROTO.md + AGENTS.md + QWEN.md + CLAUDE.md) at every directory in the walk, now stops at the first filename found per location. Global (~/.proto/, ~/.claude/) and each workspace directory independently cascade through the priority list: PROTO.md > AGENTS.md > QWEN.md > CLAUDE.md. Prevents context flooding when multiple compat aliases co-exist. Also updates repository/homepage metadata to protoLabsAI/protoCLI and protolabs.sh across root, cli, and sdk-typescript package.json files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…inism Recurring jobs get up to 15 min jitter. Ticking at 10:31 could land within the jitter window of a 10:30 job depending on the random job ID. Pin jitterMs to 0 so the test is deterministic — consistent with how other jitter tests work. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wenshao
requested changes
Apr 4, 2026
wenshao
left a comment
Collaborator
There was a problem hiding this comment.
Code Review: 16 findings (1 Critical, 13 Suggestions, 2 Nice to have)
This is a massive backport PR (842 files, +36K/-62K lines) bundling ~10 different features and fixes. While the individual changes are generally well-implemented, combining this many independent features into a single PR makes thorough review extremely difficult and increases merge risk.
Recommendation: Split into separate PRs 🔀
Each of these should be its own PR for better reviewability, bisectability, and safer rollbacks:
| # | Feature | Scope |
|---|---|---|
| 1 | MCP reconnect (/mcp reconnect) |
~200 lines |
| 2 | Compress fixes (orphaned funcCall + split point) | ~150 lines |
| 3 | PTY FD leak (node-pty upgrade) |
dependency bump |
| 4 | Kitty IME timeout | ~20 lines |
| 5 | Hooks cleanup (remove --experimental-hooks) |
~100 lines |
| 6 | npm extension install | ~200 lines |
| 7 | Web fetch in plan mode fix | ~10 lines |
| 8 | Follow-up suggestions | ~500 lines |
| 9 | Post-backport fixes | mixed |
Critical Finding
Session.ts: Plan mode check bypassed for tools withneedsConfirmation = false. These tools can now execute in plan mode, violating the plan mode contract.
Suggestions
reconnect.ts: PR description claims "auto-retry x3" but no retry loop exists in the codechatCompressionService.ts:compressIncrementalignores abort signal and lacksMIN_COMPRESSION_FRACTIONguarduseGeminiStream.ts: Cancelled edit tools still trigger post-edit verify;extractMemoriesfires on failed/cancelled turnsuseGeminiStream.ts: Cron prompts silently inject into conversation with no user-facing indicatorchatCompressionService.ts: Chunk boundaries may split tool-call sequences; ACK messages accumulate over cyclesSession.ts: DeadisTodoWriteTool = falsevariable and conditions
Full details available in the review — happy to provide more specifics on any item.
wenshao
added a commit
to wenshao/codeagents
that referenced
this pull request
Apr 4, 2026
New P2 item from QwenLM/qwen-code#2866 upstream backports analysis: - Claude Code: MAX_ERRORS_BEFORE_RECONNECT = 3, SSE auto-reconnect, session expired (404) auto-refresh - Qwen Code: no MCP reconnect mechanism - Source: services/mcp/client.ts L1225-L1357 Also confirmed PR #2866 items already covered: - Compress orphan funcCall → item 1 (compression) enhancement - API-round grouping → item 1 grouping.ts (63 lines) - Follow-up suggestions → item 3 (Speculation) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
wenshao
added a commit
to wenshao/codeagents
that referenced
this pull request
Apr 4, 2026
…#40) * feat: add MCP Auto-Reconnect as item 70 (from PR #2866 analysis) New P2 item from QwenLM/qwen-code#2866 upstream backports analysis: - Claude Code: MAX_ERRORS_BEFORE_RECONNECT = 3, SSE auto-reconnect, session expired (404) auto-refresh - Qwen Code: no MCP reconnect mechanism - Source: services/mcp/client.ts L1225-L1357 Also confirmed PR #2866 items already covered: - Compress orphan funcCall → item 1 (compression) enhancement - API-round grouping → item 1 grouping.ts (63 lines) - Follow-up suggestions → item 3 (Speculation) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: expand terminal rendering item + add MCP auto-reconnect Item 54 expanded from "Fullscreen Rendering" to full "终端渲染优化": - DEC 2026 synchronized output (BSU/ESU atomic rendering) - Cell-level differential rendering (ink/log-update.ts) - Double buffering (frontFrame/backFrame swap) - DECSTBM hardware scroll - CharCache/StylePool/CharPool caching (16K cap) - Damage tracking (dirty rectangle) - Render throttling (~60fps via queueMicrotask) - Alt-screen fullscreen mode Qwen Code has only message-splitting (useGeminiStream.ts L632-634). Claude Code has 8-layer anti-flicker in customized Ink engine (~7000 LOC). Item 70: MCP Auto-Reconnect (from PR #2866 analysis) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Backports 10 high-value upstream items from QwenLM/qwen-code into protoCLI.
What's included
/mcp reconnect+ auto-retry x3)/compressno longer corrupts history when agent was interrupted mid-tool-call@lydell/node-pty→ 1.2.0-beta.10)--experimental-hooksflag (hooks are now stable); fix abort listener leak in hook runnerproto /extension install npm:package-name— install extensions from npm registryWebFetchwas incorrectly blocked in plan mode; now shows approval dialoglspfield restored to CliArgs,ToolNames.TASK_LISTreplacing removedTODO_WRITE, mcp-tool cleanupWhat was skipped
channels/work (Telegram, WeChat, DingTalk, DingTalk) — Qwen-specific distribution modelTest plan
npm run build)/mcp reconnect <server>command exists--experimental-hooksflag is gone, hooks work without itproto /extension install npm:some-packageflows🤖 Generated with Claude Code