Skip to content
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f7ce806
fix(serve): post-merge fixes for #4291 review (7 threads) (#4305)
doudouOUC May 19, 2026
066cab2
fix(serve): post-merge P2 corrections from Codex review on #4282 (#4297)
doudouOUC May 19, 2026
981bc7c
feat(acp-bridge): F1 — acp-bridge package self-sufficiency (#4175 mec…
doudouOUC May 19, 2026
dfa8ca4
feat(serve): F1 follow-up — BridgeFileSystem wiring + #4325 channelIn…
doudouOUC May 20, 2026
8eeb510
feat(acp-bridge): F3 — multi-client permission coordination (#4175) (…
doudouOUC May 20, 2026
a60c1c5
feat(serve+sdk): F4 prereq — daemon protocol completion (serverTimest…
doudouOUC May 21, 2026
46f8d48
feat(serve): shared MCP transport pool [F2] (#4336)
doudouOUC May 21, 2026
d0563ec
feat(daemon): add shared UI transcript layer (#4328)
chiga0 May 22, 2026
c6deb58
perf(core): F2 cleanup PR A — R9/W11/W12/R10 (post-merge follow-ups) …
doudouOUC May 23, 2026
57d0478
refactor(acp-bridge): F1 test split — lift bridge.test.ts (6861 LOC) …
doudouOUC May 23, 2026
0c04309
fix(core): F2 cleanup PR B — self-heal observability (W133-a + W134) …
doudouOUC May 23, 2026
cf5c245
feat(sdk/daemon-ui): unified completeness follow-up to #4328 (#4353)
chiga0 May 24, 2026
a9d0c5f
chore(integration): sync main into daemon_mode_b_main (2026-05-24) (#…
doudouOUC May 24, 2026
63803de
docs(serve): v0.16-alpha known limits + SDK QWEN_SERVER_TOKEN env fal…
doudouOUC May 24, 2026
74c5d45
docs(deploy): local launch templates for v0.16-alpha (PR 30a) (#4483)
doudouOUC May 25, 2026
817f042
feat(daemon+sdk): cross-client real-time sync completeness (#4484)
chiga0 May 25, 2026
81b46c2
chore(integration): sync main into daemon_mode_b_main (2026-05-25) (#…
doudouOUC May 25, 2026
a529f05
docs(design): daemon side-channel coordination (A1/A2/A4/A5)
May 25, 2026
0448c3f
docs(design): revise daemon side-channel coordination per review (v2)
May 26, 2026
ee5d112
docs(design): daemon side-channel coordination v3 (2nd review round)
May 26, 2026
431e1d9
docs(design): daemon side-channel coordination v4 (third review round)
May 26, 2026
f0109cf
docs(design): daemon side-channel coordination v5 (fourth review round)
May 26, 2026
54e40a0
docs(design): daemon side-channel coordination v6 (fifth review round)
May 26, 2026
a703a14
docs(design): v7 — correct A1 transport (extNotification, not session…
May 26, 2026
9ff6fca
docs(design): bump header to v7
May 26, 2026
02a4e7e
docs(design): daemon side-channel coordination v8 (sixth review round)
May 26, 2026
b65aa05
docs(design): v9 — reconciliation uses an authoritative read, not the…
May 26, 2026
b150c14
docs(design): v10 — reconciliation generation-guard + retry; fix §8
May 27, 2026
a9124a2
docs(design): v11 — reconciliation contract hardening (failure baseli…
May 27, 2026
5966811
chore: merge daemon_mode_b_main to resolve conflicts
May 27, 2026
e1f3c32
docs(design): v12 — helper signature, structural non-recursion guard,…
May 27, 2026
cabc85c
docs(design): v13 — §7 atomic-coupling notes + §8 bounded-call-count …
May 27, 2026
0475658
docs(design): v13 — zombie-gap residual, reconciliation_failed contra…
May 27, 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