Skip to content

Commit c0d17e2

Browse files
yiliang114qwen-code-ci-botcarffucawenshaoverify
authored
feat(desktop): establish OpenWork on the Qwen Tauri Web Shell (#81)
* feat(desktop): bridge Electron users to Tauri updates (#8392) * feat(desktop): bridge Electron updates to Tauri * test(desktop): cover parseArguments validation in electron bridge manifest (#8392) * chore(desktop): address bridge review follow-ups --------- Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> * fix(web-shell): prevent table dialog close scroll jump (#8407) * ci: bump qwen-code-action to 05f8171 (skip redundant install, surface install errors) (#8444) * ci: bump qwen-code-action to 05f8171 * ci: bump qwen-code-action to 05f8171 * ci: bump qwen-code-action to 05f8171 * ci: bump qwen-code-action to 05f8171 * ci: remove broken legacy scheduled PR triage workflow (#8434) The Gemini-era scheduled PR triage workflow has been dead weight for a long time: - Its only business value — syncing labels from the linked issue to the PR — never fires: gh exports closingIssuesReferences as a flat array, so the script's '.closingIssuesReferences.nodes[0].number' jq path always errors, the error is swallowed by 2>/dev/null, and every PR falls into the "No linked issue found" branch. The latest production run logged 157 "No linked issue" hits and zero label syncs, despite many of those PRs having linked issues. - LABELS_TO_REMOVE is computed but never applied, PRS_NEEDING_COMMENT is never appended to, and the prs_needing_comment job output has no consumer — the rest of the script is dead code. - It burns 1+N API calls against every open PR every 15 minutes. - The id-token: write permission is a leftover from the Gemini/GCP OIDC era; nothing in the bash script uses it. Real PR triage lives in qwen-triage.yml. Remove the workflow and its script, drop the stale docs section describing behavior it never had, and pin the file into the legacy-workflow regression list. Co-authored-by: verify <verify@local> * feat(telemetry): Track tool execution outcomes (#8180) * feat(telemetry): track tool execution outcomes Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(telemetry): address execution-status review feedback (#8180) - Update stale nonInteractiveToolExecutor expectations for executionStatus (red CI) - Scope the cancelled span-status short-circuit to tool_call events so other cancelled events carrying an error keep ERROR status - Record loop-detection skips as UNKNOWN, not EXECUTION_DENIED, keeping the denial metric accurate - Assert execution_status on the resolved-with-error PostToolBatch path - Raise tool-call observer-failure logging from warn to error - Clarify subagent-projection exclusion and JSONL compatibility in design doc * fix(core): address review findings 3-6 on tool execution status (#8180) - recordToolExecutionMetrics now merges common attributes (session.id opt-in) like every other counter in metrics.ts - Lift TOOL_FAILURE_KIND_ATTRIBUTE / TOOL_FAILURE_KIND_CANCELLED into telemetry/constants.ts so coreToolScheduler and session-tracing share one definition - Add debugLogger to runToolTelemetrySink catch (was silent) - Replace delete-based absence in withPostToolBatchStop with conditional spread * fix(core): address remaining review findings on tool execution status (#8180) - Pass the frozen executionStatus variable instead of the literal 'success' in the post-hook-stop error response, keeping the frozen value the single source of truth (finding 4) - Force-finalize the deferred PostToolBatch parent span in the abort drain, since that terminal path cancels the batch hook that otherwise owns the span; documents the invariant at the call site (finding 6) - Comment the loop-detection guard so the permission-cancellation exclusion from invalid-param loop detection is explicit (finding 9) - Rename the design doc to the dated docs/design convention and note the schedule()/handleConfirmationResponse() resolution contract change for embedders (finding 2, doc convention) * docs(core): note schedule() resolution contract in tool execution status design (#8180) Record the embedder-facing behavior change that schedule() and handleConfirmationResponse() resolve with a terminal error call rather than rejecting, so a failing tool no longer aborts its siblings. * fix(telemetry): address review feedback for tool execution status (#8180) - Document the new tool_call attributes (call_id, execution_status), the qwen-code.tool.execution.count metric, the tool.execution span attributes, and the tool.failure_kind=cancelled span field in telemetry.md. - Pass ToolErrorType explicitly at loop-detection skip sites instead of inferring it from the skip message string, so copy edits cannot silently reclassify loop skips as approval denials. - Simplify withPostToolBatchStop response construction (drop the destructure-and-reattach used to preserve a missing execution status). - Add a debug breadcrumb when a PostToolBatch stop has no span to attach to, and a one-time warning when PostToolBatch hook detection fails open. - Drop the try/catch wrapping the pure isTelemetrySdkInitialized getter. - Clarify the design doc invalid-combination wording and note that the execution-failure SLI cannot be attributed to a specific tool. - Add a regression test pinning that schedule() resolves (not rejects) when a tool execution throws. * fix(telemetry): address round-7 review feedback for tool execution status (#8180) * fix(telemetry): restore type-safety fallback for executionErrorType (#8180) * fix(telemetry): align tool execution failure outcomes Keep Core and ACP cancellation arbitration consistent, preserve structured post-processing errors, and restore QwenLogger MCP metadata privacy. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): address review suggestions for tool execution status (#8180) * test(core,cli): strengthen test-efficacy for tool execution status (#8180) * fix(core): address review suggestions for tool execution status (#8180) - Improve post-processing cancellation message to indicate the tool had already completed, preventing silent model redo of completed work - Remove dead !isExecutionTimeout conjunct in Session.ts PostToolUse cancellation check (unreachable: timeout always sets toolResult.error) - Replace construct-then-delete with destructuring in withPostToolBatchStop - Move all failure-kind constants to telemetry/constants.ts so the full documented vocabulary lives in one place - Re-export StructuredToolError from tool-error.ts instead of importing from the unrelated priorReadEnforcement module - Add JSDoc to normalizeToolCallEvent documenting key-absent semantics - Add ordering-safety comment to createParentAbortRace microtask guarantee - Document endToolExecutionSpan not_started guard as defence-in-depth - Document PostToolBatch span leak window in finalizeToolSpan - Add design doc note about hand-placed cancellation check invariant - Add test for unknown execution_status normalization path - Revert unrelated generate-notices.js formatting change * fix(core): address review feedback for tool execution status (#8180) - Gate cancel message on executionThrew so the model sees 'User cancelled tool execution.' when execute() rejected under abort, reserving 'already completed' wording for post-processing cancels - Move StructuredToolError into tool-error.ts to break the tool-error ↔ priorReadEnforcement module cycle - Revert unrelated Prettier reformat in generate-notices.js * test(core): pin both tool cancellation notices; extract them as constants afd349ca gated the cancel message on executionThrew but left the two wordings as bare literals at four sites and added no test. That is the exact shape the bug had: it was introduced by editing one literal and missing the others. Extract TOOL_CANCELLED_{BEFORE,AFTER}_COMPLETION_MESSAGE so the four sites cannot drift, and add regression tests for both paths — a tool interrupted mid-flight (execute() rejected under abort) must report "User cancelled tool execution.", while a cancel after execute() returned must report that the output was discarded. The mid-flight test fails against the pre-afd349ca behaviour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(core): keep MCP reconnect for a timeout on a dead transport Classifying every `-32001` as EXECUTION_TIMEOUT skips handleReconnectOnError, which previously recovered one real case: the transport dies mid-request, the SDK request times out because no response will ever arrive, and the server is already recorded DISCONNECTED. That reconnected and retried; now it hard-fails and the user has to retry by hand. Divert back to the reconnect path only on positive evidence the transport is dead. Note that getMCPServerStatus() reports DISCONNECTED for servers it has never seen, so the guard checks for a *recorded* DISCONNECTED — the naive comparison misroutes every timeout from a server whose status was never registered, which broke four existing timeout tests when tried. A timeout on a healthy server is still EXECUTION_TIMEOUT: retrying it after a reconnect would just double the wait. The client-side idle timeout keeps classifying unconditionally; it is our own timer, not a transport signal. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(core): address blocking review feedback for tool execution status (#8180) Two blocking items from the maintainer review: 1. Post-processing cancellations dropped persistedOutputFiles (and visionBridgeNotice) along with the model-visible output, orphaning files the tool had already spilled to disk. createCancelledResponse now carries both, and every cancelAfterPostProcessing site passes what it has; the settle-then-abort and hook-stop paths do the same. 2. A -32001 that lands while the parent signal is aborted is the SDK's abort rejection or a timeout that raced with a cancel; classifying it EXECUTION_TIMEOUT would count user cancels against the timeout SLI. isExecutionTimeoutFailure now defers to the abort in both catch blocks, regardless of which side settled the race first. The two tests that pinned the opposite timeout-wins ordering are updated to the abort-wins semantics the review asked for. Co-Authored-By: Qwen Code <noreply@alibaba-inc.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: qwen-code-bot <qwen-code-bot@users.noreply.github.com> Co-authored-by: qwen-code-ci-bot <253268222+qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Qwen Code <noreply@alibaba-inc.com> * fix(core): Clarify write_file prior-read guidance (#8428) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(desktop): read Windows smoke log from LocalAppData (#8381) * fix(desktop): read Windows smoke log from LocalAppData * fix(desktop): validate Windows smoke log path * test(desktop): guard smoke log fallback branch and capture ordering (#8381) * fix(desktop): cross-check smoke appId against tauri config and fail closed on log rotation (#8381) * fix(desktop): reset smoke log baseline on truncation and test behavior (#8381) The Tauri app truncates the log on every startup (main.rs: fs::write(&log_path, b"")), so the second smoke run on any non-ephemeral Windows machine always failed with "truncated or rotated". Reset the baseline and keep polling instead of aborting. Extract resolveLogRoot into a tiny module so test-release.js can verify the platform/env resolution behaviorally rather than regex-matching source text. Hoist the duplicated tauri.conf.json parse, add logPath to the timeout diagnostic, and note the shared-log hermeticity constraint. * test(desktop): pin stale-log protection wiring in smoke source guard (#8381) * test(desktop): extract sliceNewLog helper and harden ordering assertion (#8381) * test(desktop): pin resolveLogRoot and dual readNewLog sites in smoke guard (#8381) * fix(desktop): log path in smoke errors; warn only on real truncation (#8381) * fix(desktop): make smoke truncation warning reachable; relax guard regexes (#8381) * fix(desktop): rebase smoke log baseline on truncation; embed full log on timeout (#8381) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(desktop): drop dead truncation flags from smoke log reader (#8381) * fix(desktop): isolate packaged smoke settings --------- Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com> Co-authored-by: Qwen Code <qwen-code@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): Avoid replaying unsafe MCP tool calls (#8387) * fix(core): Avoid replaying unsafe MCP tool calls Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): Revalidate MCP replay after reconnect Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(core): stop goal retries on evidence exhaustion (#8430) Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com> * ci: externalize review timeout to repository variables (#8460) Read review timeout settings from two GitHub Actions repository variables instead of hardcoding them, so tuning no longer requires a code change: QWEN_REVIEW_JOB_TIMEOUT_MINUTES (default: 360) - review-pr job-level hard cap (was hardcoded 300) QWEN_REVIEW_MAX_TIMEOUT_MINUTES (default: 300) - per-review max timeout: validation ceiling, large PR auto-scale, and fallback comment message (was hardcoded 240 in 3 places) Constraint: QWEN_REVIEW_JOB_TIMEOUT_MINUTES must stay above QWEN_REVIEW_MAX_TIMEOUT_MINUTES so retry + comment posting never hit the job-level cap. * fix(review): stand a drifted launch whose payload provably arrived (#8466) A model asked to copy the roster's twelve blocks normalized one word in every block's tail ("you" -> "it"). Every launch failed the verbatim containment check, check-coverage reported the whole roster undelivered, and the run relaunched all twelve agents -- the most expensive repair in the pipeline, spent redelivering text the agents had already acted on. Measured on a live run: ~10M input tokens and 17 minutes of wall clock. The verbatim check was written when the launch prompt carried the payload. It no longer does: the brief on disk holds the method, the severity bar and the project rules, and the transcript records whether the agent opened it and whether it read the diff. When both facts are on record, a drifted launch is a delivery that happened, not one that failed. check-coverage now reports such launches under driftedLaunches -- a NOTE, not a failure: ok stays true, nothing enters the posted body, and no relaunch is owed. The rescue is injective like the verbatim matching (one transcript, one requirement) and requires the diff read for a role whose brief reads the diff, so every true failure -- a drift with no brief-open, a dropped read list, a hand-written prompt with no record -- stays exactly where it was. Step 4/5 delivery classification is unchanged: a verify/reverse-audit launch carries the findings list in the prompt itself, and drift tolerance there would excuse a dropped payload. Co-authored-by: verify <verify@local> * feat(review): Add structured Web Shell review results (#8402) * feat(review): add Web Shell review artifacts Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(web-shell): add code review artifact visual scenario (#8402) * fix(review): address Web Shell review artifact feedback (#8402) * save-artifact: document why paths resolve against the daemon workspace root (QWEN_CODE_PROJECT_DIR) instead of cwd, and cover the relative-path form the skill documents with a test where the two roots differ. * CLI/renderer contract: the renderer hand-duplicates the findings vocabulary and fails closed on unknown values, so name the renderer as a second consumer beside the CLI's lists and check in a contract fixture generated through the real pipeline (validateFindings -> buildReport -> save-artifact) that exercises every source, severity, confidence and outcome. Exporting the vocabulary through the SDK stays deferred: it is a public cross-package API change beyond this PR's seam. * resolve-anchors now validates `line` exactly like `findings` does (positive safe integer); the two validators in one pipeline no longer disagree. Note: an in-flight `.qwen/tmp` findings file carrying `line: 0` fails where it previously did not. * The renderer validates markdownReportPath (relative, no ".." segments, .md suffix) before it becomes a readWorkspaceFile call, resets the severity/confidence filters when switching artifacts, and surfaces heldByMeasurement so a nonzero Held count is attributable. * save-artifact refuses low effort structurally (choices and library guard) instead of by prose, stats the Markdown report before reading it so a directory reports "not a file", and the component no longer shadows the DOM `document` global. * The case-insensitive alias test now skips visibly on case-sensitive filesystems instead of passing vacuously. * Comment the kept `turnOutputs.review` key and document the JSON companion in the user docs. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(review): address second Web Shell review artifact feedback round (#8402) --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> * ci: reduce SDK Java runner queueing (#8441) * ci: cancel stale SDK Java pull request runs * fix(ci): preserve SDK Java push scheduling * ci: route trusted SDK Java jobs to ECS * ci: simplify SDK Java runner routing * fix(ci): provision Maven on ECS Java jobs * fix(ci): clean SDK daemon ECS test state * fix(ci): satisfy SDK Java lint * fix(core): align MCP reconnect timeout test with safe replay policy (#8478) The reconnect-on-timeout test still built its mock tools without server trust or tool annotations, which the safe replay change now requires before automatically replaying a connection-loss failure. Update the fixtures the same way the surrounding reconnect tests were updated, keeping the test's original assertion that a timeout on a known disconnected server goes through the reconnect path. * feat(core): support Qwen 3.8 reasoning effort (#8472) * fix(ci): align review workflow tests with externalized timeout variables (#8486) #8460 moved the review timeouts into the QWEN_REVIEW_JOB_TIMEOUT_MINUTES and QWEN_REVIEW_MAX_TIMEOUT_MINUTES repository variables but left the workflow-text assertions in scripts/tests/qwen-resolve-workflow.test.js pinned to the old hardcoded 240/300 values, so the workspace test suite fails (Release Quality Checks and the PR Test job). * chore(release): v0.21.5 (#8505) * chore(release): v0.21.5 * docs(changelog): sync for v0.21.5 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * feat(browser-ext): add alpha readiness diagnostics (#6739) * feat(browser-ext): add alpha readiness diagnostics * test(browser-ext): automate readiness verification * fix(browser-ext): support current devtools adapter * test(browser-ext): verify restored page after reconnect * fix(browser-ext): harden release and acceptance checks * test(browser-ext): cover onboarding transitions * fix(browser-ext): harden alpha diagnostics * test(cli): sync serve capabilities baseline * feat(browser-ext): add alpha readiness diagnostics * test(browser-ext): automate readiness verification * fix(browser-ext): support current devtools adapter * test(browser-ext): verify restored page after reconnect * fix(browser-ext): harden release and acceptance checks * test(browser-ext): cover onboarding transitions * fix(browser-ext): finalize Chrome Web Store package * fix(browser-ext): harden CDP diagnostics per review feedback (#6739) * fix(browser-ext): harden CDP diagnostics per review feedback (#6739) Distinguish the ACP child's idle placeholder (initialized: false, discoveryState: 'not_started') from a genuinely empty server list so the panel no longer shows a false "adapter is not connected" warning before the first session or after the child is reaped. Compare the tunnel endpoint's host+port against the daemon baseUrl to detect cross-daemon shadowing (a chrome-devtools entry pointing at a different daemon's /cdp was previously reported as connected). Guard package-extension and symlink tests with skipIf(process.platform === 'win32') so the Windows merge-queue gate does not fail on missing zip.exe or privilege-dependent symlinkSync. Also: destructure QwenCapabilityStatus lazily inside probeState so a missing capability-status.js no longer throws before the welcome screen renders; add the missing license header to manifest-version.js; replace the leftover #welcome height:100vh with flex sizing; add cross-reference comments for the shared /cdp path pattern. Note: probeJson intentionally drops the .catch(() => ({})) fallback so a 200 with a non-JSON body reads as unreachable; this also makes /health stricter than before. * fix(browser-ext): resolve CDP diagnostics review findings (#6739) * fix(browser-ext): mirror nightly build number in manifest test oracle (#6739) * fix(browser-ext): address alpha diagnostics review feedback (#6739) - declare the semver dependency used by manifest-version.js so an isolated workspace install no longer relies on root hoisting - make artifact-scan skip the root CLI bundle metafile with a warning when it is absent (it only exists after `cross-env DEV=true npm run bundle`), keeping the extension metafile required, so package-level test:release no longer fails - throttle the side panel /workspace/mcp probe to every 5th tick and reuse the cached snapshot in between, avoiding a cross-process RPC on every 2s poll - document the per-session CDP event fan-out and pin single-path event counts; note that Target.getDevToolsTarget is deliberately unsupported - guard the nightly build-number git lookup and the zip end handler - disclose the daemon-to-model-provider page-content flow in PRIVACY.md - drop brittle source-substring panel tests and add coverage for a chrome-devtools server with no config args * fix(browser-ext): improve acceptance diagnostics and honest phase naming (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(cli): stabilize flaky orphan-session transport tests (#6739) Replace hardcoded setTimeout(40ms) + assertion with vi.waitFor() in the session/new and session/load orphan tests. The 40ms budget is too tight under CI parallelism, causing intermittent removeSession-not-called failures. vi.waitFor polls until the assertion holds (default 1s timeout), matching the pattern already used elsewhere in this file. * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(cli): restore PAGE_SESSION_ID forwarding for lazy-attach path (#6739) The autoAttachActive gate on PAGE_SESSION_ID command forwarding broke the cdp-ws lazy-attach path, which sends commands with PAGE_SESSION_ID without a Target.setAutoAttach handshake. Revert the forwarding gate to unconditional PAGE_SESSION_ID acceptance while keeping the gated Target.attachedToTarget emission (the Critical fix). * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): make survivor tests load-bearing with log assertions (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): address review feedback on diagnostics PR (#6739) * fix(browser-ext): resolve review findings on diagnostics tests (#6739) - reject preview-range QWEN_CHROME_EXTENSION_BUILD_NUMBER values at the env var boundary with a message naming the variable, value, and range - assert the package-extension symlink test observably ran main() instead of passing on equality alone when both runs fail identically - add CLI-level tests proving explicit positional roots are scanned and a clean scan exits 0, covering paths the symlink-only tests skip on Windows Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com> Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: document headless Goal workflows (#8503) * feat(core): guide recording of PR, issue, and comment URLs as artifacts (#8453) * ci: route trusted-author fork PRs and no-checkout jobs to the ECS pool (#8502) * ci: route trusted-author fork PRs and no-checkout jobs to the ECS pool Fork PRs whose author has write access (OWNER/MEMBER/COLLABORATOR association) now run Linux CI on the self-hosted ECS pool instead of the saturated GitHub-hosted quota, and bot workflows that check out no code move to ECS unconditionally. Everything stays gated on the MAINTAINER_ECS_RUNNER_DISABLED kill-switch. * ci: address review — real write-permission routing, watchdog independence, timeouts Route the triage agent on the collaborator-permission API result computed by authorize instead of the coarse author_association, which admits org members and read-only collaborators; the two permission-gate jobs revert to the same-repo guard. Keep the fleet watchdog and the CI-failure reporter hosted so they stay independent of the pool they watch. Add missing timeouts, wipe serve-ab's reused workspace, and pin the routing logic with drift and negative-case tests. --------- Co-authored-by: 易良 <1204183885@qq.com> * fix(web-shell): keep pending background agents active (#8413) * fix(web-shell): keep pending background agents active * test(web-shell): cover pending agent activity edge cases * fix(web-shell): preserve background agent elapsed time * test(web-shell): require shared active tool status classification * refactor(web-shell): centralize active tool status * fix(web-shell): keep parallel agents clock monotonic * refactor(web-shell): consolidate active tool checks and walkers (#8413) Drop the duplicate hasActiveTool wrapper in favor of the adapters' hasActiveAgents so the package keeps a single any-active predicate, share one turn walker between turnOwnsCallId and turnHasActiveAgent so the tool-carrying DisplayItem set is encoded once, and cover the parallel-agents clock latch re-arm when a second wave of agents starts after the group went fully terminal. * fix(desktop): rotate Tauri updater signing key (#8511) * fix(desktop): rotate Tauri updater signing key The original minisign private key paired with the pubkey in tauri.conf.json was lost and could not be recovered from any local worktree or branch. Generate a fresh keypair and update the public key so the TAURI_SIGNING_PRIVATE_KEY GitHub Secret can sign updater artifacts for the first stable Tauri desktop release. * chore: trigger CI rerun * chore: rerun CI * chore: rerun CI (retry runner) * fix(web-shell): add explicit ::selection for message content in Firefox (#8417) * fix(web-shell): add explicit ::selection for message content in Firefox Firefox does not paint the default selection highlight for text whose element chain passes through a display:contents element (the data-user-selectable wrapper on MessageItem). The logical selection (copy, selectionchange popup) works fine - only the visual highlight is missing. An explicit ::selection background makes Firefox paint the highlight where the default painting fails. Fixes #8214 * fix: use fixed color instead of non-existent CSS variable --selection-bg was never defined in the codebase (only --chat-editor-selection-bg exists in App.module.css). Use a fixed hsl(210 100% 50% / 30%) to avoid confusion. * test(web-shell): pin ::selection rule and soften root-cause framing Reframe the standalone.css comment and PR description as a defensive workaround, not a confirmed root-cause fix: the data-user-selectable wrapper is shared by user and assistant rows, and the reporter's screenshot shows an embedding-page toolbar this package does not ship. Add a getComputedStyle(..., '::selection') assertion to the smoke e2e so a future cleanup cannot silently drop the rule. * fix(web-shell): move ::selection rule to component-scoped globals.css The defensive ::selection rule for [data-user-selectable] message content was in standalone.css, which is only loaded by the standalone app entry (client/main.tsx) and the e2e harness. The npm package entry (client/index.tsx via vite.lib.config.ts) never loads standalone.css, so embedded deployments of @qwen-code/web-shell - including the reporter of #8214 - did not receive the rule and still saw no selection highlight. Move it to globals.css, which is imported by App.tsx and WebShellTranscript.tsx and therefore ships with the component-scoped stylesheet. Verified against the lib build: the rule now appears in dist/index.js correctly scoped under [data-web-shell-root][data-web-shell-shadcn]. The standalone app also loads globals.css, so the e2e smoke pin still passes. Addresses the review finding on standalone.css:119. * test(web-shell): pin ::selection across all rows and in the lib bundle Address review findings on the round-3 move to globals.css: - The smoke e2e only sampled the first [data-user-selectable] row (the user row in this fixture). Assert the rule on every selectable row so a future narrowing to user rows keeps assistant rows covered. - Nothing asserted the rule survives in the npm lib bundle - the deployment this fix exists for. Add a build-artifact test that parses the injected component CSS in dist/index.js and pins the scoped [data-user-selectable] ::selection rule under [data-web-shell-root]. * test(web-shell): assert ::selection on selectable wrapper rows, not descendants Per review: querySelectorAll('[data-user-selectable] *') counts element descendants, not the wrapper rows themselves - a single user row renders 4+ descendants, so the >=2 invariant did not actually enforce that both roles are present. Match the [data-user-selectable] wrappers directly and sample one descendant per row. * test(web-shell): match ::selection lib-bundle pin by effect, not notation Per review (R6-1): the pin matched an exact selector substring (including the space) and an exact prop name, coupling to the current notation. A maintainer switching 'background' to 'background-color' (the CSS Pseudo-Elements-4 name) would fail this test with a misleading message while the e2e pin stayed green. Match the two selector halves independently and accept either prop name. --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> * refactor(core): move review skill incident narratives to DESIGN.md (#8499) * perf(review): issue independent setup calls in one response Measured on a real small-PR run: the stretch from parse-args to the first agent launch took 7 minutes of wall clock, one round-trip at a time, on calls that never needed an order — pr-context, comment-status and the Step 2 rules load are mutually independent reads. Step 1 now tells the orchestrator to issue all three in a single response (the same rule Step 3 already enforces for the agent fan-out) and to page their outputs in shared responses too. comment-status loses its wait-for-the-context-file guard in worktree mode: learning whether inline comments exist cost a serial round-trip, while running it on a commentless PR just writes an empty index. Step 6's two deterministic gates (script-lint, test-plan) get the same one-response note. The orderings that matter are kept explicit: fetch-pr before everything (it creates the worktree and the plan), the roster after the rules load (it bakes the rules into every brief). * refactor(core): move review skill incident narratives to DESIGN.md SKILL.md is injected wholesale into the review orchestrator's context on every /review run and re-billed on each of its turns, and ~16KB of it was incident narrative — accounts of past dogfood failures and measurements that justify rules but are not themselves instructions. Move 50 such narrative blocks into a new 'Measured incidents (moved from SKILL.md)' section of DESIGN.md (47 anchors, not loaded at runtime), leaving every rule in place with a short '(measured; DESIGN.md — <anchor>)' pointer. Force-bearing figures stay inline where the number is the argument (e.g. the ~161s cold npm ci, the 41% test-code median, the PR #6457 one-of-five checklist measurement). No instruction, gate, format, flag, threshold, or ordering changed; the YAML frontmatter and all 35 fenced code blocks are byte-identical, and the MUST / Do not / never imperative counts are unchanged outside the moved narrative text (verified by script). SKILL.md: 237,847 -> 228,266 bytes; DESIGN.md: 106,708 -> 125,184 bytes. * fix(review): keep DESIGN.md out of the runtime bundle and pin pointers The slim refactor left DESIGN.md shipped beside SKILL.md in dist/bundled/, so one curious read_file of the 125 KB maintainer document would cost more context than the refactor saves. The bundle copy now skips DESIGN.md, and SKILL.md gains a one-line guard telling the orchestrator the pointers are for humans auditing a rule. Also addresses review feedback: a test pins both directions of the SKILL.md incident-pointer mapping, the transcribed-argument narrative keeps its referent after the move, the incidents section title loses its changelog suffix, and Step 2 no longer asks for a base fetch that fetch-pr already performed. * fix(review): gate setup batching by effort and consolidate incident blocks Address round-1 review feedback on the skill-slim PR: - Gate the ONE-response setup batch and the comment-status call to high and medium effort, matching Step 2's low-effort skip. - Scope the Step 6 lint/test-plan batching to same-repo PR reviews. - Merge same-run incident blocks (self-composed Approve into the paraphrased roster prompt; archive verdict into the narrated-away cap), cross-reference the roster-size and relocated-Critical tellings, and state the #8368 path in its block plus the pointer it was missing. - Pointer-ize the last inline QQChannel narrative and fix the scripts-nobody-ran summary to match its block. - Extend the DESIGN.md exclusion to copy_files.js so the transpiled dist/src build and the published core tarball stop shipping it. - Pin the no-read_file guard and the batch ordering constraints in SKILL.test.ts, and fail loudly on pointers the regex cannot parse. --------- Co-authored-by: verify <verify@local> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> * fix(core): harden Qwen 3.8 reasoning effort wire shape (#8488) * fix(core): harden Qwen 3.8 reasoning effort wire shape (#8472 follow-up) Follow-up to #8472, addressing the post-merge review findings: - Drop enable_thinking/thinking_budget after the extra_body merge whenever reasoning_effort ships: the Token Plan preset made qwen3.8-max-preview carry both thinking knobs, and DashScope rejects reasoning_effort combined with thinking_budget - Family-gate the new tool_choice=required strip clause to qwen wire models: reasoning_effort is an opaque sampling override on non-qwen DashScope models, and dropping forced tool selection degraded their structured side queries - Prefix-match the qwen3.8-max family so dated snapshots and -latest aliases receive the selected tier instead of silently collapsing to enable_thinking - Log the tool_choice strip; restore the effort-config JSDoc and comment the request-level override copy * fix(core): family-gate DashScope thinking-knob drop (#8488) --------- Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com> * perf(review): the review-round refinements for the setup batch (#8487) The batched-setup paragraph merged to main through #8499's squash of its base branch, without the two review rounds that followed on #8487. This re-lands those refinements as the delta against main's current text: - 'ONE response' now says separate tool calls, never an &&/;-joined Shell chain — a chain changes the failure semantics (pr-context failing must warn-and-continue, not skip the other two) and merges the warning: size lines the paging decisions read. - The rules load names its ref uniformly (<remote>/<baseRefName>, the ref fetch-pr just updated) with the baseFetchFailed carve-out spelled in both Step 1 and Step 2, replacing the prefer-local probe language — deciding 'does <base> exist locally' costs exactly the serial turn the batch removes, and an unresolvable ref makes load-rules report 'no rules found', indistinguishable from a repo that has none. - The incremental-cache read pairs with the fetch-report read where the read is instructed (both read_file, genuinely parallel). - The executable-script lint's enumeration counts file reviews — they have a tree and scriptLintGate owes them the lint; the adjacent gate note already said so. Co-authored-by: verify <verify@local> * fix(review): stop the reverse-audit loop while there is still time to report (#8468) * fix(review): stop the reverse-audit loop while there is still time to report Measured on CI run #8368 (+1699 lines): the iterative reverse audit ran to its 5-round cap, each round a per-chunk fan-out whose findings then went back through verification, and the loop consumed 3.5 of the job's 4 budgeted hours. The outer GNU-timeout kill arrived while round 5's findings were still being verified. The review died holding every confirmed finding it had; nothing reached the pull request. The loop's rounds are driven by the orchestrator, but every round begins at the same place: agent-prompt building the round's prompts. So the builder becomes the loop's clock. When the environment carries a review deadline (QWEN_REVIEW_DEADLINE_EPOCH, exported per attempt by the review workflow) and the remaining time is inside the reserve kept for the last verification, compose-review and submission (default 60 minutes, QWEN_REVIEW_DEADLINE_RESERVE_SECONDS to override), a reverse-audit round is refused: a BUDGET line on stderr, exit code 4, no prompt built and no record written. The message carries the exact unreviewedDimensions entry to file, so the disclosure that caps the verdict is the CLI's text, and Step 6 proceeds with the findings already confirmed. Local runs have no deadline and are untouched. A malformed deadline fails open — the outer kill still bounds the run, and a broken variable must degrade to today's behaviour rather than wedge every budgeted review at round 1. The verifier is deliberately not gated: the reserve exists so it can run. * fixup: scale the deadline reserve to the externally-chosen budget The budget is not this workflow's to assume: it arrives from a repository variable, a workflow input, or a /review --timeout=N comment. A fixed 60-minute reserve would consume most of a 70-minute budget and refuse the audit loop outright on a 30-minute one. The workflow now passes a reserve of a quarter of the attempt, floored at 10 minutes and capped at 60; the CLI constant remains only the fallback for a caller that sets a deadline without a reserve. * review feedback: admit the round only if IT fits, and cap deterministically Three findings from review, all taken: 1. The gate budgeted for the tail but not for the round it admits — the terminal round is by construction the one that starts closest to the boundary, so the killed-mid-verification failure survived one round wide. The gate now requires remaining >= round + reserve, where the round's cost is the previous round's, measured admission-to-admission from a stamp the builder writes (one per round; a same-round rebuild is not a round), falling back to a 30-minute constant for round 1, which starts with the most headroom. 2. The refusal was deterministic; the disclosure that caps the verdict was prose the orchestrator had to carry. The builder now records a budget-stop marker beside the prompt records and compose-review synthesizes the unreviewedDimensions entry from it — deduped against a relayed copy — so a run that drops the sentence still cannot approve past a truncated audit. 3. Exit code 4 is documented in the command's describe. Also restores the Step 5 bullet the previous commit's edit displaced (new findings merge into the cumulative list before the next round). * review feedback: pin the budget gate's all-chunks refusal and ordering Cover the two behaviours the review noted were only asserted on the bare --findings form: an exhausted budget refuses the loop's real --all-chunks round before ANY of the per-chunk records is written, and a malformed call (--round 0) still gets its validation error first — exit 4 is for a well-formed round the budget refuses, never a replacement error. Also name what the code already does: reserve=0 is the deliberate escape hatch (the gate shrinks to the round estimate alone), and the workflow's 3600s cap mirrors DEFAULT_RESERVE_SECONDS. * docs(review): describe the soft-deadline env vars for time-budgeted runs The review noted the two new variables appeared in no user-facing doc; the reserve in particular is an operator-facing knob. State what each does, the fail-open posture, and how the refusal surfaces in the verdict. * fix(cli): align budget-stop disclosure with the gate's refusal (#8468) A round-1 budget refusal left no reverse-audit records, so the Step 4/5 floor reported the deliberate stop as a rogue/unlaunched audit with a rebuild FIX the same gate deterministically rejects; the refusal's own disclosure was swallowed by the caller-echo dedup. The floor now stands down when the budget-stop marker exists, and compose-review renders the disclosure structurally, bilingually, from the marker. Also: `--role reverse-audit` requires `--round <k>` (an unlabeled admission stamps an entry no estimate can attribute), the budget gate runs after the plan/findings reads (a broken plan or unreadable findings deserves its own error, and nothing is stamped ahead of a buildable call), and the gate's admission boundary, measured-cost behaviour, and the workflow env contract are pinned by tests. * review: a budget stop excuses only the round it refused The budget-stop suppression keyed on the marker's existence alone, so every reverse-audit gap shape went silent once any round was refused — including the shapes that describe rounds which RAN before the budget hit. A hand-written round-1 launch is exactly as undelivered when round 3 later hits the budget, and suppressing its disclosure let 'stopped before round 3' imply the rounds that did run were faithful. Exactly one shape is by design under a marker: not-built — the refusal writes no record, so an audit with no records IS the audit the gate stopped, and its FIX (rebuild the round) would be refused by the same gate. The suppression now names that shape and no other; a rewritten, unlaunched or brief-unread round keeps its disclosure and its repair. The new test pins the operative halves: the verdict stays capped, the marker's disclosure posts, and the operator channel carries the rewritten round's exact repair. (The posted body collapses same-subject disclosures — both say 'reverse audit' — so the author sees the stop; repairs are acted on from stderr, where the rewritten fix rides.) * fix(review): fence budget state per run, and let gate errors beat budget stops Address the round-2 review threads on the reverse-audit budget gate: - Fence budget-rounds.json and budget-stop.json by the plan's own mtime. Every run rewrites the plan at its Step 1 capture, so records older than the plan belong to a previous run of the same PR: a run killed before cleanup no longer prices the next run's rounds off stale stamps (an hours-old stamp read as an hours-long round refused round 1 of a fresh budget) and no longer caps a later run's verdict on a stop that did not happen in it (R2-1, R2-2). - Refuse a structurally unbuildable plan (no chunks[], duplicate or non-integer ids) with its own error ahead of the budget gate, so the same corruption gets the same diagnosis whatever the clock says, and no budget-stop marker is written over a corrupt plan (R2-5). - Stamp a round admitted only after its build succeeds: a build that throws leaves no stamp, so the next round's cost is never measured from a build that produced nothing and floored to 600s (R2-6). - Keep the budget entry's 'reverse audit' subject out of the caller-echo prefix filter: other reverse-audit scopes the orchestrator disclosed (a twice-whiffed chunk from the rounds that DID run) are no longer silently dropped in the marker's shadow; the marker's own relays stay deduped by the phrase splice (R2-7). - Render --round unbracketed in the reverse-audit rebuild fix — the CLI refuses a round-less reverse-audit call, so the paste-and-run repair must not present the flag as optional (R2-14). - Document the deliberate one-verification overlap between the measured round estimate and the tail reserve, at both definitions (R2-13). - Test hardening, each assertion mutation-probed to fail its named mutant: a reshaped relay only the marker-phrase splice dedups (R2-8); the stamp's round label and the verifier's no-stamp invariant (R2-9); whole-line, unit-arithmetic and reserve-cap pins on the CI wiring contract (R2-10); the first-wins stamp survivor (R2-11); the reserve=0 escape hatch (R2-12). --------- Co-authored-by: verify <verify@local> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> * fix(autofix): normalize paginated fetches to one flat array per file (#8438) * fix(autofix): normalize paginated fetches to one flat array per file gh api --paginate emits one JSON array PER PAGE, so any PR past 100 comments/reviews/events produces a multi-document stream. The workflow already slurps correctly in a few readers (jq -rs add, --slurpfile + add), but more than a dozen plain-jq consumers of the WORKDIR files mis-aggregate on a multi-doc input: - MARKERS/REARM_AT/RED_HEAD/REARM_KEY in the scan and their LIVE_* mirrors in prepare emit one result per page; ROUND then becomes a multi-line string, [[ -ge ]] arithmetic fails, and the round cap silently stops holding — on exactly the PRs (takeover, 100-round cap, one report comment per round) that reach page two first. - CAP_NOTICED / BASE_UPDATE_RECENT / LAST_REJECTION / PRIOR_TIMEOUTS / the milestone census and the report-step consecutive-failure census all degrade the same way. - NEWEST and LIVE_NEW bind rv/rc/ic/checks POSITIONALLY (.[0]..[3]); a two-page rv.json shifts rc/ic into the wrong slots and later feedback is silently lost. Fix at the fetch sites: every --paginate that lands in a WORKDIR json file (and the report step's COMMENTS_JSON fallback) now pipes through jq -s 'add // []', so each file holds ONE flat array. Existing slurp-style readers are unaffected — add is idempotent over a single array — and every plain consumer becomes correct past 100 items with no program changes. Failure semantics are preserved: the workflow-level bash default gives -eo pipefail, so a failed gh still fails the pipeline exactly where it failed the bare redirect before, and the pr-events/COMMENTS_JSON fallbacks keep their '[]' paths. The check-runs/annotations/status-comment reads stay raw on purpose: they aggregate per-page via --jq + slurp, line-streams, or .[][] and were already pagination-safe. Tests: a behavioral case runs the real MARKERS→ROUND pipeline and the positional NEWEST program against two-page fixtures through the normalizer, with negative controls demonstrating the pre-fix corruption (two MARKERS lines; the page-2 review timestamp lost to slot shift). Shape assertions pin all nine normalized fetch sites and ban raw --paginate file redirects. * fix(autofix): pin total --paginate occurrence count in tripwire test (#8438) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(autofix): correct gh --paginate merge model in pagination comments (#8438) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(autofix): make engage-ack ic re-fetch atomic on failure (#8438) * test(autofix): pin atomic engage-ack re-fetch and empty-input normalization (#8438) --------- Co-authored-by: verify <verify@local> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * feat(web-shell): bind plan approval to its Todo revision (#8393) * feat(web-shell): gate session workflow behind experimental setting * feat(web-shell): bind plan approval to todo revision * fix(cli): clear stale workflow revision on plan entry * test(web-shell): pin revised workflow snapshot * fix(cli): clear stale plan revisions on restore * fix(cli): keep replayed history from rebinding plan revisions History replay re-sends stale plan updates through Session.sendUpdate, re-stamping activeTodoPlanRevision from finished plan cycles. Clear the revision after every replay path (cold replayHistory and live non-bulk loadSession) so a replayed snapshot can never bind a later exit_plan_mode approval; reloaded sessions fall back to text-only approval until the next live todo_write re-establishes the binding. Also drop the bulk-load restore that could never be read before a plan-mode transition cleared it, and pin the workflow gates and mode-entry clears with negative tests. * test(web-shell): pin older plan revision in ChatPane approval test (#8393) * test(cli): pin unbindable plan updates in approval revision test (#8393) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): clear Todo plan revision on history restore (#8393) restoreHistory was the one history-resetting path that kept activeTodoPlanRevision, so a restored snapshot could let a stale revision bind the next exit_plan_mode approval. Clear it like the sibling reset paths, pin the behavior with a test, and pin the live-load clear ordering after the replayed updates. * fix(cli): restore Todo stop guard clear on plan re-select (#8393) The previous-mode guard added for the revision binding also skipped the Todo Stop Guard trust clear on a redundant plan re-select; scope the guard to the revision reset so every transition into plan clears the stop guard as before. The replay-time revision clears now run in finally blocks so a transport failure part-way through a replay cannot leave a replayed binding on the live session, and the web-shell exit-plan approval rule is unified in one predicate. Revision tests assert through the observable qwenTodoApproval approval metadata instead of the private field. --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> * fix(core): resolve DashScope thinking-knob conflicts by family (#8488 round 2) (#8536) Second review round on #8488: - Honour an explicit extra_body enable_thinking: false on the qwen3.8-max family as reasoning_effort: 'none' instead of silently deleting it and re-enabling thinking - Legacy qwen hybrids now drop the inert reasoning_effort override when it conflicts with a meaningful thinking_budget, keeping the knobs the model actually reads - Family-gate the pipeline's enable_thinking tool_choice clause like the reasoning_effort clause: on non-qwen models sharing the endpoint the field is an opaque no-op (GLM reads thinking.enabled), and stripping forced tool selection there degraded their side queries - The tier-native disable path emits reasoning_effort: 'none' — the knob the family reads — instead of enable_thinking: false; the required-thinking retry trigger recognises the new shape so runtime learning still fires - Warn once per generator (not debug per request) when user extra_body knobs are dropped; hoist the wire-model family predicates to modalityDefaults.ts and share the provider's extra_body merge tail - Tests for every behavior above (all load-bearing, verified by targeted mutation); docs attribute the vendor rejection to thinking_budget only and document the extra_body exceptions * fix(cli): stop review test-efficacy tests depending on ambient tmpdir vitest (#8537) Two tests failed on hosts where vitest resolves up-tree from os.tmpdir() (observed on self-hosted CI where a node_modules above TMPDIR provides one): findVitestBin's "cannot be resolved" case never threw, and runControlMutant's "cannot run" case executed the probe for real instead of throwing. Make the failure conditions host-deterministic while keeping every assertion: findVitestBin accepts an injected resolver (default unchanged) so the MODULE_NOT_FOUND case is forced directly, and the runControlMutant test plants a shadow vitest whose exports hide package.json, which wins resolution from any ancestor install and makes the run fail deterministically. * feat(serve): add a required external tool guard provider (#8125) * feat(serve): add required external tool guard * fix(serve): keep guard constants off fast path closure * test(serve): cover guard startup options * refactor(acp-bridge): centralize external tool guard validation and ack value (#8125) * fix(core): align MCP reconnect timeout test with safe replay policy (#8125) The reconnect-on-timeout test still built its mock tools without server trust or tool annotations, which the safe replay change now requires before automatically replaying a connection-loss failure. Update the fixtures the same way the surrounding reconnect tests were updated, keeping the test's original assertion that a timeout on a known disconnected server goes through the reconnect path. Mirrors the same alignment already landed on main. * fix(cli): alias externalToolGuard subpath for vitest source resolution (#8125) This PR added `@qwen-code/acp-bridge/externalToolGuard` imports to cli serve/acp modules but not the vitest source alias every other acp-bridge subpath carries. Without it, any vitest run whose acp-bridge dist is stale or absent fails to resolve the import and the five serve test files die at transform time. Add the alias following the documented convention in the config so tests read the live source. * fix(serve): reject non-ASCII external tool guard bearer tokens A token outside the ASCII range passed construction but made the handshake throw ERR_INVALID_CHAR when interpolated into the Authorization header, blocking qwen serve startup in required mode with an unexplained error. Enforce printable ASCII (0x21-0x7E) at validation time so the configuration fails fast with a clear message. --------- Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> * fix(desktop): codesign ripgrep and node binaries before tauri build (#8518) * fix(desktop): codesign ripgrep and node binaries before tauri build macOS notarization rejects the app bundle because Tauri only signs the main binary, not the embedded ripgrep and Node.js runtime binaries under Contents/Resources/runtime/qwen-code/. Add a pre-build codesign step that signs all native macOS executables in the bundled runtime with the Developer ID identity, hardened runtime, and the existing entitlements. * fix(desktop): allow Windows build without signing certificate The Tauri release workflow threw when WINDOWS_CERTIFICATE was missing, blocking the entire release (including macOS). Mirror the old Electron workflow behavior: warn and continue unsigned when no cert is configured. Also add fallback to legacy WIN_CSC_LINK/WIN_CSC_KEY_PASSWORD secrets so existing Electron-era credentials still work if present. * fix(desktop): allow unsigned Windows artifacts in verify step The 'Verify Windows signature' step threw on any non-Valid status, including NotSigned. With no Windows code signing certificate configured, this blocked the Windows build job, which in turn blocked the publish job (needs: [prepare, build]). Allow NotSigned with a warning instead of throwing, matching the fallback behavior of the 'Import Windows certificate' step. A genuinely invalid signature (HashMismatch, etc.) still throws. * fix(desktop): narrow find scope and deduplicate pfx import - Scope ripgrep codesign find to *-darwin/* paths so Linux ELF binaries (built in the same matrix) aren't targeted. - Unify the two pfx-import branches into a single code path to eliminate duplicated write/import/configure logic. * fix(desktop): guard optional Windows signing config * fix(desktop): harden vendor signing workflow * fix(core): reuse prompt cache for multimodal compression (#8419) * fix(core): reuse prompt cache for multimodal compression * test(core): remove inert media modality fixture * fix(core): guard compression cache-sharing window * fix(core): harden compression cache-sharing gate * fix(core): tighten compression cache preflight * test(core): pin lazy compression slimming * fix(cli): preserve Qwen Review startup version in footers (#8431) * fix(cli): preserve review startup version in footers * fix(cli): keep review startup version dynamic in bundle * fix(cli): reset review version after managed update * test(cli): use indexed env access * fix(cli): harden review footer strip and version stamping (#8431) * fix(tests): sync qwen-resolve-workflow expectations with externalized review timeouts (#8431) The timeout externalization in #8460 replaced the hardcoded 300/240 values in qwen-code-pr-review.yml with the QWEN_REVIEW_JOB_TIMEOUT_MINUTES and QWEN_REVIEW_MAX_TIMEOUT_MINUTES repository variables but left scripts/tests/qwen-resolve-workflow.test.js asserting the old literals, so the full-profile Test job fails on any branch carrying that change. Update the three affected assertions to pin the externalized shape. * fix(cli): harden the review footer strip per review feedback (#8431) The strip regex kept a 2^(N-1) partition ambiguity for same-line footer runs (measured 5.3 s at n=20) and missed footers truncated before their closing `_`; forged footers also survived on the body channel through `bodyCriticals`, and the values interpolated into the footer were not shape-validated. Guard the repeated group so an iteration cannot span another footer's start, make the final `_` optional, strip body Criticals per entry, refuse footer-forging model ids and non-version stamps, refuse non-object comment entries, pin the CLI-glue test suite against an ambient startup stamp, and cross-assert the LGTM filter regex against the footer builder. * fix(cli): strip review footers before ledger carryover * fix(cli): align ledger footer regression expectation --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> * fix(serve): detect lineEnding across the file, not the returned slice (#8383) * fix(serve): detect lineEnding across the file, not the returned slice `readText` reported `meta.lineEnding` from the slice it was about to return. A slice holding a single CRLF line arrives as text ending in '\r' — the '\n' was consumed as that line's terminator — so detecting on it answers 'lf'. Page one of a cursor sequence then disagreed with page two about the same file, and a client that trusts the first page would rewrite CRLF content as LF. The truncation branch re-detected on the truncated slice for the same reason and had the same flaw. Detect on the whole decoded file once, which is what the field is describing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(serve): guard byte-truncated reads against slice-based lineEnding re-detection * fix(core): report crlf on cursor pages resuming after a CRLF terminator (#8383) * fix(core): count a skipped CRLF terminator on byte-truncated pages (#8383) When a window's first line exceeds both the read-chunk size and maxOutputBytes, the byte cut fires before the line's terminator is decoded, and the re-snap then walks over that terminator without reading it. The next page seeds from the pair and reports 'crlf' while the cut page reported 'lf' — adjacent pages of one file disagreeing, the exact symptom this PR removes. Consume the same two-byte evidence after the re-snap so the pages agree. Also qualify the design-doc agreement guarantee to files with uniform line endings (mixed-ending files can still flip between pages), and pin the seed's load-bearing placement with tests: it must run on the snapped offset, and the minimum probe offset (startOffset == 2) is now covered. * docs: correct the lineEnding spec for byte-cursor pages (#8383) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: qualify the mixed-EOL verification bullet for byte-cursor pages (#8383) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: name the uniform-file line-window-vs-cursor lineEnding split (#8383) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * perf(core): clear tool results to a low watermark to preserve prompt cache (#8464) * perf(core): clear tool results to a low watermark to preserve prompt cache Size-triggered microcompaction now clears oldest compactable tool results down to half the threshold instead of stopping just below it, so the conversation prefix stays stable between clearings and provider prompt caches keep matching. The recent-result budget now protects committed results only; pending results no longer consume protection slots but stay counted, uncleared, and live for file-read-cache resolution. Adds the watermark to cleanup metadata and the debug log. Fixes #8463 * fix(core): harden size-cleanup protection against zero-char and pending refs Review follow-up for the low-watermark change: keepRecent now selects from committed results that are actually clearable (positive, successful, uncleared output), so trailing errors, prior placeholders, and empty outputs no longer absorb protection slots. Pending refs are dropped from the keep set entirely — a pending read may be a cache-hit placeholder rather than file bytes, so it must not suppress eviction reporting; over-disarming only costs a redundant re-read. Adds regression tests for both plus the protected-saturation consecutive-trigger corner. * qwen: address PR review feedback (#8464) Pin the (soft-exceeded) log marker with the one-line assertion suggested by the sandboxed verification report (finding S-1): the all-protected overage test now asserts 'target 250000 (soft-exceeded)', killing the surviving mutant M4. * qwen: address PR review feedback (#8464) * qwen: address PR review feedback (#8464) * qwen: address PR review feedback (#8464) Two P1 context-integrity fixes from review: (1) media-only tool results (image/PDF reads with empty text output and bytes on functionResponse.parts) stay in the idle-path keepRecent candidates instead of being dropped by the zero-char filter; (2) only write_file results vouch for file residency in kept-path accounting — edit calls carry just old/new snippets while still setting the cache's sticky full-read flags, so a kept edit can no longer suppress eviction reporting after the full read is blanked. Regression tests for both. * qwen: address PR review feedback (#8464) Pin the absence of the (soft-exceeded) marker at the exact watermark boundary: clearing that lands the virtual total exactly on the watermark must not be flagged. Kills the >= and always-true mutants of the marker condition that previously surviv…
1 parent 547c885 commit c0d17e2

8,233 files changed

Lines changed: 3310326 additions & 724 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dockerignore

Lines changed: 9 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,11 @@
1-
# Dependencies (rebuilt inside container)
2-
node_modules/
1+
# Dependencies (npm ci installs fresh inside the container)
2+
node_modules
3+
**/node_modules
34

4-
# Build artifacts
5-
dist/
6-
*.tgz
5+
# Build artifacts (rebuilt from scratch inside the container)
6+
dist
7+
**/dist
8+
**/tsconfig.tsbuildinfo
79

8-
# Electron app output (not needed for server)
9-
apps/electron/release/
10-
apps/electron/vendor/
11-
12-
# Git
13-
.git/
14-
.gitignore
15-
16-
# IDE
17-
.vscode/
18-
.idea/
19-
*.swp
20-
*.swo
21-
22-
# OS
23-
.DS_Store
24-
Thumbs.db
25-
26-
# CI/CD
27-
.github/
28-
29-
# Tests
30-
**/*.test.ts
31-
**/*.spec.ts
32-
**/tests/
33-
**/test/
34-
**/__tests__/
35-
36-
# Top-level docs (not resource docs used by server)
37-
/docs/
38-
apps/online-docs/
39-
README*.md
40-
CONTRIBUTING*.md
41-
CHANGELOG*.md
42-
LICENSE*
43-
44-
# Docker files (avoid recursive context)
45-
Dockerfile*
46-
docker-compose*.yml
47-
.dockerignore
48-
49-
# Smoke test script (not needed inside image)
50-
scripts/docker-smoke-test.sh
10+
# Version control
11+
.git

.editorconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
insert_final_newline = true
6+
end_of_line = lf
7+
indent_style = space
8+
indent_size = 2
9+
max_line_length = 80
10+
11+
[Makefile]
12+
indent_style = tab
13+
indent_size = 8

.gitattributes

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Set the default behavior for all files to automatically handle line endings.
2+
# This will ensure that all text files are normalized to use LF (line feed)
3+
# line endings in the repository, which helps prevent cross-platform issues.
4+
* text=auto eol=lf
5+
6+
# Explicitly declare files that must have LF line endings for proper execution
7+
# on Unix-like systems.
8+
*.sh eol=lf
9+
*.bash eol=lf
10+
Makefile eol=lf
11+
12+
# Windows cmd.exe expects batch installers to be checked out with CRLF.
13+
scripts/installation/install-qwen-standalone.bat text eol=crlf
14+
15+
# Explicitly declare binary file types to prevent Git from attempting to
16+
# normalize their line endings.
17+
*.png binary
18+
*.jpg binary
19+
*.jpeg binary
20+
*.gif binary
21+
*.ico binary
22+
*.pdf binary
23+
*.woff binary
24+
*.woff2 binary
25+
*.eot binary
26+
*.ttf binary
27+
*.otf binary

.github/CODEOWNERS

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# ============================================================
2+
# Qwen Code CODEOWNERS
3+
# ============================================================
4+
5+
# --- CODEOWNERS file itself ---
6+
/.github/CODEOWNERS @pomelo-nwu @wenshao
7+
8+
# --- Core package ---
9+
/packages/core/ @wenshao @tanzhenxin @yiliang114 @LaZzyMan @doudouOUC
10+
11+
# --- CUA Driver & Mobile MCP ---
12+
/packages/cua-driver/ @LaZzyMan
13+
/packages/mobile-mcp/ @LaZzyMan
Lines changed: 37 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,58 @@
1-
name: Bug Report
2-
description: Report a bug or unexpected behavior in OpenWork
3-
labels: ["bug"]
1+
name: 'Bug Report'
2+
description: 'Report a bug to help us improve Qwen Code'
3+
labels: ['type/bug', 'status/needs-triage']
44
body:
5-
- type: markdown
5+
- type: 'markdown'
66
attributes:
7-
value: |
8-
Thanks for taking the time to report a bug! Please fill out the sections below so we can reproduce and fix the issue.
7+
value: |-
8+
> [!IMPORTANT]
9+
> Thanks for taking the time to fill out this bug report!
10+
>
11+
> Please search **[existing issues](https://github.com/QwenLM/qwen-code/issues)** to see if an issue already exists for the bug you encountered.
912
10-
- type: input
11-
id: version
13+
- type: 'textarea'
14+
id: 'problem'
1215
attributes:
13-
label: OpenWork Version
14-
description: "Found in Settings or the title bar (e.g. 0.4.6)"
15-
placeholder: "0.4.6"
16+
label: 'What happened?'
17+
description: 'A clear and concise description of what the bug is.'
1618
validations:
1719
required: true
1820

19-
- type: dropdown
20-
id: os
21+
- type: 'textarea'
22+
id: 'expected'
2123
attributes:
22-
label: Operating System
23-
options:
24-
- macOS (Apple Silicon)
25-
- macOS (Intel)
26-
- Windows 11
27-
- Windows 10
28-
- Linux (Ubuntu/Debian)
29-
- Linux (Fedora/RHEL)
30-
- Linux (Arch)
31-
- Linux (Other)
24+
label: 'What did you expect to happen?'
3225
validations:
3326
required: true
3427

35-
- type: input
36-
id: os_version
28+
- type: 'textarea'
29+
id: 'info'
3730
attributes:
38-
label: OS Version
39-
description: "e.g. macOS 15.3, Windows 11 24H2, Ubuntu 24.04"
40-
placeholder: "macOS 15.3"
41-
validations:
42-
required: true
43-
44-
- type: dropdown
45-
id: ai_provider
46-
attributes:
47-
label: AI Provider
48-
description: Which AI provider/connection are you using?
49-
options:
50-
- Anthropic API (direct)
51-
- Anthropic API (custom endpoint)
52-
- OpenAI / Codex
53-
- Copilot (GitHub)
54-
- Other
55-
validations:
56-
required: true
57-
58-
- type: input
59-
id: model
60-
attributes:
61-
label: Model
62-
description: "Which model are you using? (e.g. Claude Opus 4.7, GPT-4.1)"
63-
placeholder: "Claude Opus 4.7"
64-
65-
- type: textarea
66-
id: description
67-
attributes:
68-
label: Description
69-
description: A clear description of what the bug is.
70-
validations:
71-
required: true
72-
73-
- type: textarea
74-
id: steps
75-
attributes:
76-
label: Steps to Reproduce
77-
description: Step-by-step instructions to reproduce the behavior.
31+
label: 'Client information'
32+
description: 'Please paste the full text from the `/about` command run from Qwen Code. Also include which platform (macOS, Windows, Linux).'
7833
value: |
79-
1.
80-
2.
81-
3.
82-
validations:
83-
required: true
34+
<details>
35+
<summary>Client Information</summary>
8436
85-
- type: textarea
86-
id: expected
87-
attributes:
88-
label: Expected Behavior
89-
description: What did you expect to happen?
90-
validations:
91-
required: true
37+
Run `qwen` to enter the interactive CLI, then run the `/about` command.
9238
93-
- type: textarea
94-
id: actual
95-
attributes:
96-
label: Actual Behavior
97-
description: What actually happened?
39+
```console
40+
$ qwen /about
41+
# paste output here
42+
```
43+
44+
</details>
9845
validations:
9946
required: true
10047

101-
- type: textarea
102-
id: screenshots
48+
- type: 'textarea'
49+
id: 'login-info'
10350
attributes:
104-
label: Screenshots / Screen Recordings
105-
description: |
106-
For **UI issues**, please attach screenshots or screen recordings showing the problem.
107-
You can drag and drop images/videos directly into this field.
108-
109-
- type: textarea
110-
id: logs
111-
attributes:
112-
label: Debug Logs
113-
description: |
114-
For **non-UI issues** (crashes, errors, connection problems), please attach relevant logs from a debug session.
115-
116-
Launch the app with `-- --debug` and reproduce the issue.
117-
render: shell
51+
label: 'Login information'
52+
description: 'Describe how you are logging in (e.g., API Config).'
11853

119-
- type: textarea
120-
id: additional
54+
- type: 'textarea'
55+
id: 'additional-context'
12156
attributes:
122-
label: Additional Context
123-
description: Any other context about the problem (MCP sources used, workspace config, etc.)
57+
label: 'Anything else we need to know?'
58+
description: 'Add any other context about the problem here.'
Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,35 @@
1-
name: Feature Request
2-
description: Suggest a new feature or enhancement
3-
labels: ["enhancement"]
1+
name: 'Feature Request'
2+
description: 'Suggest an idea for this project'
3+
labels:
4+
- 'type/feature-request'
5+
- 'status/needs-triage'
46
body:
5-
- type: markdown
7+
- type: 'markdown'
68
attributes:
7-
value: |
8-
Have an idea for OpenWork? We'd love to hear it!
9+
value: |-
10+
> [!IMPORTANT]
11+
> Thanks for taking the time to suggest an enhancement!
12+
>
13+
> Please search **[existing issues](https://github.com/QwenLM/qwen-code/issues)** to see if a similar feature has already been requested.
914
10-
- type: textarea
11-
id: problem
15+
- type: 'textarea'
16+
id: 'feature'
1217
attributes:
13-
label: Problem or Motivation
14-
description: What problem does this feature solve, or what workflow does it improve?
18+
label: 'What would you like to be added?'
19+
description: 'A clear and concise description of the enhancement.'
1520
validations:
1621
required: true
1722

18-
- type: textarea
19-
id: solution
23+
- type: 'textarea'
24+
id: 'rationale'
2025
attributes:
21-
label: Proposed Solution
22-
description: Describe the feature or change you'd like to see.
26+
label: 'Why is this needed?'
27+
description: 'A clear and concise description of why this enhancement is needed.'
2328
validations:
2429
required: true
2530

26-
- type: textarea
27-
id: alternatives
31+
- type: 'textarea'
32+
id: 'additional-context'
2833
attributes:
29-
label: Alternatives Considered
30-
description: Any workarounds or alternative approaches you've tried.
31-
32-
- type: textarea
33-
id: additional
34-
attributes:
35-
label: Additional Context
36-
description: Screenshots, mockups, links, or any other context.
34+
label: 'Additional context'
35+
description: 'Add any other context or screenshots about the feature request here.'

.github/actionlint.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
self-hosted-runner:
2+
labels:
3+
- 'ecs-qwen'
4+
- 'ecs-win'
5+
- 'ecs-update-sg'
6+
- 'ecs-update-64c'
7+
8+
config-variables: null
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: 'Configure Windows self-hosted runner'
2+
description: 'Tunes a self-hosted Windows runner for the test gates: exports the Linux gates'' C.UTF-8 locale env (inert on Windows, where Node collates through ICU), redirects TEMP/TMP to RUNNER_TEMP, and puts Git Bash on PATH for bash-shell steps. Runs after actions/checkout because repository-local actions resolve from the workspace; callers turn off autocrlf before the checkout itself. Shared by the Windows merge-queue gate and the runner smoke workflow so both always run an identical configuration.'
3+
4+
runs:
5+
using: 'composite'
6+
steps:
7+
- name: 'Configure Windows test environment'
8+
# Self-hosted runners have Windows PowerShell, not necessarily pwsh.
9+
# Force UTF-8 so GITHUB_ENV/GITHUB_PATH are not written as UTF-16LE.
10+
shell: 'powershell'
11+
run: |-
12+
$ErrorActionPreference = 'Stop'
13+
"TEMP=$env:RUNNER_TEMP" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
14+
"TMP=$env:RUNNER_TEMP" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
15+
"LC_ALL=C.UTF-8" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
16+
$gitBash = 'C:\Program Files\Git\bin'
17+
if (!(Test-Path $gitBash)) {
18+
Write-Output "::error::Git Bash not found at $gitBash"
19+
exit 1
20+
}
21+
$gitBash | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

0 commit comments

Comments
 (0)