Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
b0ea9f4
fix(core): decouple auto-memory recall from main-agent request path (…
LaZzyMan May 19, 2026
a7e0530
feat(worktree): Phase C — session persistence, hooksPath, Footer + Wo…
LaZzyMan May 19, 2026
87404da
fix(core): apply defaultModalities() on env-var-only model config (#4…
LaZzyMan May 19, 2026
078bee6
fix(cli): block Windows Tab approval-mode toggle when input has a Tab…
LaZzyMan May 19, 2026
2429949
fix(core): mirror Qwen3 reasoning on outbound history (#4294)
Alexxigang May 19, 2026
5fe12d4
feat(core): extend cross-auth fast models to agents (#4153)
tanzhenxin May 19, 2026
1b66f79
feat(cli,core): add Auto approval mode with LLM classifier (#4151)
LaZzyMan May 20, 2026
ee6746e
fix(test): count result messages instead of assistant messages in mul…
wenshao May 20, 2026
0a14bf8
feat(cli): per-turn /diff with interactive dialog (#4277)
BZ-D May 20, 2026
dc6a5ad
feat(cli): add session path status command (#4124)
kkhomej33-netizen May 20, 2026
16f0fde
fix(test): raise timeout for Windows installer end-to-end tests (#4352)
wenshao May 20, 2026
d97b85f
Pin fetch to bundled undici for undici higher versions compatibility …
ideal May 20, 2026
96fa061
fix(review): harden SKILL.md against weak-model rule skipping (#4340)
wenshao May 20, 2026
1a59f20
chore: add .github/release.yml to support skip-changelog label (#4327)
yiliang114 May 20, 2026
aedbf37
feat(core): inject git status into system prompt and refine Explore/g…
DennisYu07 May 20, 2026
a552df8
refactor(auth): unify provider config in core, simplify /auth as "Con…
pomelo-nwu May 20, 2026
ed14a33
feat(core): add NotebookEdit tool for Jupyter notebooks
zhangxy-zju May 20, 2026
4b25f9c
fix(core): set x-api-key alongside Authorization on Anthropic outboun…
LaZzyMan May 21, 2026
7c4b7f5
fix(cli): remove QWEN_OAUTH gate from feedback dialog (#4316)
pomelo-nwu May 21, 2026
a303788
fix(core): replace structuredClone with shallow copy to prevent OOM i…
yiliang114 May 21, 2026
b588f74
fix(core): align session hook matcher targets (#4354)
qqqys May 21, 2026
c4421ac
Expose active goal in stream JSON (#4314)
qqqys May 21, 2026
60d8ffa
feat(cli): respect /editor preference in Ctrl+X external editor (#4310)
dreamWB May 21, 2026
b58fe19
feat(telemetry): Phase 2 — tool.blocked_on_user + hook spans (#3731) …
doudouOUC May 21, 2026
d59c9e7
feat(installer): add standalone hosted install and uninstall flow (#3…
yiliang114 May 21, 2026
59d5c1f
fix(core): handle MiMo tool-result media (#4281)
DragonnZhang May 21, 2026
64401e1
feat(telemetry): support custom resource attributes and add metric ca…
doudouOUC May 21, 2026
80895d5
fix(core): deduplicate geminiChat recovery continuation text (#3966)
chiga0 May 21, 2026
d2ece83
feat(skills): support priority field in SKILL.md for sorting skill di…
yiliang114 May 21, 2026
262a15e
fix(ci): resolve TS5055 release build failure since May 19 (#4383)
yiliang114 May 21, 2026
ce82d65
Revert "fix(core): set x-api-key alongside Authorization on Anthropic…
LaZzyMan May 21, 2026
fc15b33
chore(release): v0.16.0 (#4404)
yiliang114 May 21, 2026
6b0e758
fix(core,cli): close tool_use↔tool_result invariant across all failur…
wenshao May 21, 2026
94f7cb5
fix(vscode): skip redundant tsc build in prepackage to prevent TS5055…
yiliang114 May 21, 2026
48b0a8b
fix(core): preserve tab-indented notebook formatting (#4373)
zhangxy-zju May 21, 2026
fd75f77
feat(telemetry): Phase 4a — TTFT capture + GenAI semconv dual-emit (#…
doudouOUC May 22, 2026
0cb9ff0
fix: renormalize CRLF storage for install-qwen-standalone.bat (#4427)…
wenshao May 22, 2026
61d91ad
fix(build): tree-shake React reconciler dev build to prevent Performa…
huww98 May 23, 2026
15247f4
chore(deps): update express from 4.21.2 to 5.2.1 (#4458)
yiliang114 May 23, 2026
b602a72
fix(cli): stabilize flaky sticky-todo remeasure test (#4416)
pomelo-nwu May 23, 2026
e43852f
fix(cli): gate mintty OSC 8 detection on TERM_PROGRAM_VERSION ≥ 3.3 (…
wenshao May 23, 2026
a41afc4
fix(release): move constants above entry point to avoid TDZ error (#4…
yiliang114 May 23, 2026
94982c6
fix(build): clean stale outputs before tsc --build to prevent TS5055 …
doudouOUC May 23, 2026
394e2a3
chore(release): v0.16.1 [skip ci]
qwen-code-ci-bot May 23, 2026
4dc9848
feat(cli): do not append trailing space for directory completions (#4…
dykebo May 23, 2026
4bc526d
Merge main into daemon_mode_b_main (2026-05-24 sync)
doudouOUC May 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
*.bash eol=lf
Makefile eol=lf

# Windows cmd.exe expects batch installers to be checked out with CRLF.
scripts/installation/install-qwen-standalone.bat text eol=crlf

# Explicitly declare binary file types to prevent Git from attempting to
# normalize their line endings.
*.png binary
Expand Down
6 changes: 6 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Configuration for GitHub's automatic release notes generation
# PRs with 'skip-changelog' label will be excluded from release notes
changelog:
exclude:
labels:
- 'skip-changelog'
199 changes: 187 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:

steps:
- name: 'Checkout'
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0
Expand Down Expand Up @@ -89,7 +89,7 @@ jobs:
echo "is_dry_run=${is_dry_run}" >> "${GITHUB_OUTPUT}"

- name: 'Setup Node.js'
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
Expand Down Expand Up @@ -153,13 +153,13 @@ jobs:

steps:
- name: 'Checkout'
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0

- name: 'Setup Node.js'
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
Expand Down Expand Up @@ -206,13 +206,13 @@ jobs:

steps:
- name: 'Checkout'
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0

- name: 'Setup Node.js'
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
Expand Down Expand Up @@ -247,13 +247,13 @@ jobs:

steps:
- name: 'Checkout'
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0

- name: 'Setup Node.js'
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
Expand Down Expand Up @@ -317,13 +317,13 @@ jobs:

steps:
- name: 'Checkout'
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
with:
ref: '${{ github.event.inputs.ref || github.sha }}'
fetch-depth: 0

- name: 'Setup Node.js'
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
uses: 'actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e' # v6.4.0
with:
node-version-file: '.nvmrc'
cache: 'npm'
Expand Down Expand Up @@ -386,6 +386,63 @@ jobs:
RELEASE_VERSION: '${{ needs.prepare.outputs.release_version }}'
run: 'npm run package:standalone:release -- --version "${RELEASE_VERSION}" --out-dir dist/standalone'

- name: 'Verify Installation Release Assets'
run: 'npm run verify:installation-release -- --dir dist/standalone'

- name: 'Package Hosted Installation Assets'
env:
RELEASE_VERSION: '${{ needs.prepare.outputs.release_version }}'
run: 'npm run package:hosted-installation -- --out-dir dist/installation --version "${RELEASE_VERSION}"'

- name: 'Install ossutil'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' }}
env:
OSSUTIL_URL: "${{ vars.OSSUTIL_URL || 'https://gosspublic.alicdn.com/ossutil/1.7.19/ossutil-v1.7.19-linux-amd64.zip' }}"
OSSUTIL_SHA256: "${{ vars.OSSUTIL_SHA256 || 'dcc512e4a893e16bbee63bc769339d8e56b21744fd83c8212a9d8baf28767343' }}"
run: |-
set -euo pipefail

tmp_dir="$(mktemp -d)"
curl -fsSL --connect-timeout 15 --max-time 300 "${OSSUTIL_URL}" -o "${tmp_dir}/ossutil.zip"
echo "${OSSUTIL_SHA256} ${tmp_dir}/ossutil.zip" | sha256sum -c -
unzip -q "${tmp_dir}/ossutil.zip" -d "${tmp_dir}"

ossutil_path="$(find "${tmp_dir}" -type f \( -name 'ossutil' -o -name 'ossutil64' \) -print -quit)"
if [[ -z "${ossutil_path}" ]]; then
echo "::error::ossutil binary not found in downloaded archive"
exit 1
fi

chmod +x "${ossutil_path}"
mkdir -p "${HOME}/.local/bin"
install -m 0755 "${ossutil_path}" "${HOME}/.local/bin/ossutil"
echo "${HOME}/.local/bin" >> "${GITHUB_PATH}"
rm -rf "${tmp_dir}"
"${HOME}/.local/bin/ossutil" >/dev/null

- name: 'Configure Aliyun OSS Credentials'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' }}
env:
ALIYUN_OSS_ACCESS_KEY_ID: '${{ secrets.ALIYUN_OSS_ACCESS_KEY_ID }}'
ALIYUN_OSS_ACCESS_KEY_SECRET: '${{ secrets.ALIYUN_OSS_ACCESS_KEY_SECRET }}'
ALIYUN_OSS_ENDPOINT: "${{ vars.ALIYUN_OSS_ENDPOINT || 'https://oss-cn-hangzhou.aliyuncs.com' }}"
run: |-
set -euo pipefail

if [[ -z "${ALIYUN_OSS_ACCESS_KEY_ID}" || -z "${ALIYUN_OSS_ACCESS_KEY_SECRET}" ]]; then
echo "::error::Missing Aliyun OSS credentials. Set ALIYUN_OSS_ACCESS_KEY_ID and ALIYUN_OSS_ACCESS_KEY_SECRET in the production-release environment secrets."
exit 1
fi

ossutil config \
-e "${ALIYUN_OSS_ENDPOINT}" \
-i "${ALIYUN_OSS_ACCESS_KEY_ID}" \
-k "${ALIYUN_OSS_ACCESS_KEY_SECRET}" \
-L EN \
-c "${RUNNER_TEMP}/.ossutilconfig"

- name: 'Publish @qwen-code/qwen-code'
working-directory: 'dist'
run: |-
Expand All @@ -411,21 +468,139 @@ jobs:
IS_NIGHTLY: '${{ needs.prepare.outputs.is_nightly }}'
IS_PREVIEW: '${{ needs.prepare.outputs.is_preview }}'
run: |-
set -euo pipefail

PRERELEASE_FLAG=""
if [[ "${IS_NIGHTLY}" == "true" || "${IS_PREVIEW}" == "true" ]]; then
PRERELEASE_FLAG="--prerelease"
fi

mapfile -t release_assets < <(node scripts/verify-installation-release.js --dir dist/standalone --list-release-asset-paths)

gh release create "${RELEASE_TAG}" \
dist/cli.js \
dist/standalone/qwen-code-* \
dist/standalone/SHA256SUMS \
"${release_assets[@]}" \
--target "${RELEASE_BRANCH}" \
--title "Release ${RELEASE_TAG}" \
--notes-start-tag "${PREVIOUS_RELEASE_TAG}" \
--generate-notes \
${PRERELEASE_FLAG}

- name: 'Sync Release Assets to Aliyun OSS'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' }}
env:
ALIYUN_OSS_BUCKET: "${{ vars.ALIYUN_OSS_BUCKET || 'qwen-code-assets' }}"
RELEASE_TAG: '${{ needs.prepare.outputs.release_tag }}'
run: |-
set -euo pipefail

mapfile -t release_assets < <(node scripts/verify-installation-release.js --dir dist/standalone --list-release-asset-paths)
node scripts/upload-aliyun-oss-assets.js \
--bucket "${ALIYUN_OSS_BUCKET}" \
--config "${RUNNER_TEMP}/.ossutilconfig" \
--prefix "releases/qwen-code/${RELEASE_TAG}" \
"${release_assets[@]}"

- name: 'Verify Aliyun OSS Release Assets'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' }}
env:
ALIYUN_OSS_PUBLIC_BASE_URL: "${{ vars.ALIYUN_OSS_PUBLIC_BASE_URL || 'https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com' }}"
RELEASE_TAG: '${{ needs.prepare.outputs.release_tag }}'
run: |-
set -euo pipefail

npm run verify:installation-release -- --base-url "${ALIYUN_OSS_PUBLIC_BASE_URL}/releases/qwen-code/${RELEASE_TAG}"

- name: 'Sync Hosted Installation Assets to Aliyun OSS'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' && needs.prepare.outputs.is_nightly == 'false' && needs.prepare.outputs.is_preview == 'false' }}
env:
ALIYUN_OSS_BUCKET: "${{ vars.ALIYUN_OSS_BUCKET || 'qwen-code-assets' }}"
RELEASE_TAG: '${{ needs.prepare.outputs.release_tag }}'
run: |-
set -euo pipefail

hosted_assets=(
dist/installation/install-qwen-standalone.sh
dist/installation/install-qwen-standalone.ps1
dist/installation/install-qwen-standalone.bat
dist/installation/uninstall-qwen-standalone.sh
dist/installation/uninstall-qwen-standalone.ps1
dist/installation/SHA256SUMS
)
node scripts/upload-aliyun-oss-assets.js \
--bucket "${ALIYUN_OSS_BUCKET}" \
--config "${RUNNER_TEMP}/.ossutilconfig" \
--prefix "installation/${RELEASE_TAG}" \
"${hosted_assets[@]}"
node scripts/upload-aliyun-oss-assets.js \
--bucket "${ALIYUN_OSS_BUCKET}" \
--config "${RUNNER_TEMP}/.ossutilconfig" \
--prefix "installation" \
"${hosted_assets[@]}"

- name: 'Verify Aliyun OSS Hosted Installation Assets'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' && needs.prepare.outputs.is_nightly == 'false' && needs.prepare.outputs.is_preview == 'false' }}
env:
ALIYUN_OSS_PUBLIC_BASE_URL: "${{ vars.ALIYUN_OSS_PUBLIC_BASE_URL || 'https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com' }}"
RELEASE_TAG: '${{ needs.prepare.outputs.release_tag }}'
run: |-
set -euo pipefail

hosted_tmp_dir="$(mktemp -d)"
trap 'rm -rf "${hosted_tmp_dir}"' EXIT
mkdir -p "${hosted_tmp_dir}/versioned" "${hosted_tmp_dir}/global"
for asset in install-qwen-standalone.sh install-qwen-standalone.ps1 install-qwen-standalone.bat uninstall-qwen-standalone.sh uninstall-qwen-standalone.ps1 SHA256SUMS; do
url="${ALIYUN_OSS_PUBLIC_BASE_URL}/installation/${RELEASE_TAG}/${asset}"
global_url="${ALIYUN_OSS_PUBLIC_BASE_URL}/installation/${asset}"
curl -fsSL --connect-timeout 15 --max-time 300 "${url}" -o "${hosted_tmp_dir}/versioned/${asset}"
curl -fsSL --connect-timeout 15 --max-time 300 "${global_url}" -o "${hosted_tmp_dir}/global/${asset}"
done
cmp -s "dist/installation/SHA256SUMS" "${hosted_tmp_dir}/versioned/SHA256SUMS" || {
echo "::error::Hosted installation SHA256SUMS does not match local dist/installation/SHA256SUMS"
diff -u "dist/installation/SHA256SUMS" "${hosted_tmp_dir}/versioned/SHA256SUMS" || true
exit 1
}
cmp -s "dist/installation/SHA256SUMS" "${hosted_tmp_dir}/global/SHA256SUMS" || {
echo "::error::Global hosted installation SHA256SUMS does not match local dist/installation/SHA256SUMS"
diff -u "dist/installation/SHA256SUMS" "${hosted_tmp_dir}/global/SHA256SUMS" || true
exit 1
}
(cd "${hosted_tmp_dir}/versioned" && sha256sum -c SHA256SUMS)
(cd "${hosted_tmp_dir}/global" && sha256sum -c SHA256SUMS)

- name: 'Publish Aliyun OSS Latest VERSION'
# Run last so the `latest/VERSION` pointer only flips after every
# release asset and hosted installer object has been uploaded and
# verified. If any earlier step fails, the pointer keeps referring
# to the previously-good release.
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' && needs.prepare.outputs.is_nightly == 'false' && needs.prepare.outputs.is_preview == 'false' }}
env:
ALIYUN_OSS_BUCKET: "${{ vars.ALIYUN_OSS_BUCKET || 'qwen-code-assets' }}"
ALIYUN_OSS_PUBLIC_BASE_URL: "${{ vars.ALIYUN_OSS_PUBLIC_BASE_URL || 'https://qwen-code-assets.oss-cn-hangzhou.aliyuncs.com' }}"
RELEASE_TAG: '${{ needs.prepare.outputs.release_tag }}'
run: |-
set -euo pipefail

printf '%s\n' "${RELEASE_TAG}" > "${RUNNER_TEMP}/qwen-code-latest-version"
ossutil cp "${RUNNER_TEMP}/qwen-code-latest-version" "oss://${ALIYUN_OSS_BUCKET}/releases/qwen-code/latest/VERSION" -c "${RUNNER_TEMP}/.ossutilconfig" -f --acl public-read

latest_version="$(curl -fsSL --connect-timeout 15 --max-time 300 "${ALIYUN_OSS_PUBLIC_BASE_URL}/releases/qwen-code/latest/VERSION" | tr -d '[:space:]')"
if [[ "${latest_version}" != "${RELEASE_TAG}" ]]; then
echo "::error::Aliyun latest VERSION points to ${latest_version}, expected ${RELEASE_TAG}"
exit 1
fi

- name: 'Cleanup Aliyun OSS Credentials'
if: |-
${{ always() && needs.prepare.outputs.is_dry_run == 'false' }}
run: |-
rm -f "${RUNNER_TEMP}/.ossutilconfig"

- name: 'Create PR to merge release branch into main'
if: |-
${{ needs.prepare.outputs.is_dry_run == 'false' && needs.prepare.outputs.is_nightly == 'false' && needs.prepare.outputs.is_preview == 'false' }}
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ bundle
junit.xml
packages/*/coverage/

# PR body draft
pr_body.md

# Generated files
packages/cli/src/generated/
packages/core/src/generated/
Expand Down
Loading
Loading