chore(deps): sync external-context version in package-lock.json - #8858
Conversation
The lockfile workspace entry still listed 0.21.8 while integrations/external-context/package.json is at 0.20.1, so every npm install rewrote the lockfile. Regenerated with npm install --package-lock-only.
|
Thanks for the PR! Template looks good ✓ Problem: real, and the root cause is now confirmed from the repo's own automation. Direction: lockfile hygiene plus a fix to the release automation that let the drift through — clearly in scope. The second commit lands the root-cause follow-up from the earlier review round. The diff touches the release workflow, but only to stage a file that workflow already modifies — release semantics are unchanged. Size: 2 files, +2/−2 — one lockfile metadata line and one release-workflow staging line. No production or test code. Approach: minimal, and it now covers both halves. Commit 1 resyncs the lockfile to the committed manifest ( Risk: no elevated risk signals — no high-risk paths touched. Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:真实存在,且根因已从仓库自身的自动化代码中确认。 方向:lockfile 卫生修复,外加修掉让漂移溜进来的 release 自动化——明显在范围内。第二个 commit 落实了上一轮 review 提出的根因修复。diff 触及 release workflow,但只是把该 workflow 自己已经修改的文件加入暂存——release 语义没有变化。 规模:2 个文件,+2/−2 —— 一行 lockfile 元数据、一行 release workflow 暂存列表。不涉及生产或测试代码。 方案:最小改动,且现在覆盖了问题的两面。Commit 1 把 lockfile 重新同步到已提交的 manifest( 风险:无升级风险信号——未触及高风险路径。 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewRe-run against the new head Independent proposal before reading the diff: resync the lockfile to the committed manifest with
No findings. Nothing to flag. TestingUnattended CI run — the PR's own CI is the evidence; no PR code was built or executed here. On The claims here are lockfile/manifest agreement and staging completeness — both settled by the static cross-checks above (deterministic npm reconciliation and a workspace-list comparison), with no runtime surface for a sandboxed lane to exercise. Real-scenario testing: N/A — nothing user-visible. Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 中文说明代码审查对新 head 读 diff 前的独立方案:用
无发现,无需标记的问题。 测试无人值守 CI 运行 —— 以 PR 自身的 CI 为证据;此处未构建或执行任何 PR 代码。 本 PR 的论点是 lockfile/manifest 一致与暂存完整性 —— 两者均已由上面的静态核对(npm 的确定性调和 + workspace 列表比对)解决,没有需要沙箱验证的运行时行为。真实场景测试:N/A —— 无用户可见变化。 CI 明细见上表。 — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 5/5 — clean across every stage, and now with the root cause fixed too: the lockfile resync is provably what npm itself regenerates, and the release staging line demonstrably covers every workspace the version bump touches, so this drift cannot recur. Reflection: round 1 reviewed the lockfile-only version and the follow-up review flagged that it treated the symptom only. The autofix round answered with exactly the right second commit — staging the external-context manifest in the release's version-commit step. I verified that commit against Approving, pinned to the reviewed commit. ✅ 中文说明置信度:5/5 —— 各阶段均干净,且现在连根因也已修复:lockfile 重同步可证明与 npm 自身重新生成的结果一致,release 暂存行经核实已覆盖所有被升版本的 workspace,此漂移不会再次发生。 复盘:第一轮审查的是仅含 lockfile 的版本,随后的 review 指出那只是治标。autofix 轮次给出了完全正确的第二个 commit —— 在 release 的版本提交步骤中暂存 external-context 的 manifest。我没有凭空采信,而是对照 批准已提交,绑定到本次审查的 commit。✅ — Qwen Code · qwen3.8-max Reviewed at |
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
中文说明
已审查——无阻断问题。 建议见行内评论。
— qwen3.8-max via Qwen Code /review (v0.21.8)
| "name": "@qwen-code/external-context", | ||
| "version": "0.21.8", | ||
| "version": "0.20.1", |
There was a problem hiding this comment.
[Suggestion] This fix addresses the symptom only — the release automation that created this lockfile/manifest drift will recreate it at the next release. scripts/version.js bumps every workspace not in workspacesToExclude (only @qwen-code/sdk and @qwen-code/mobile-mcp); @qwen-code/external-context is NOT excluded, so at release time its manifest is bumped on disk in the CI working tree and the final npm install --ignore-scripts writes the new version into the lockfile. But .github/workflows/release.yml:401 stages only package.json package-lock.json packages/*/package.json packages/channels/*/package.json — no glob matches integrations/external-context/package.json, so the lockfile bump is committed while the manifest bump is discarded. Release commit 4d6246bd88 (v0.21.8) did exactly this: it changed the lockfile entry 0.20.1 → 0.21.8 without touching the manifest. — Failure scenario: at the next release (e.g. v0.21.9) the identical drift recurs on main — the lockfile records the release version while the manifest stays at 0.20.1, so every local npm install rewrites the lockfile again, dirtying all contributors' working trees, and this identical cleanup PR is needed after every release. Fix: add integrations/external-context/package.json to the git add allowlist in release.yml (if it should be versioned with releases), or add @qwen-code/external-context to workspacesToExclude in scripts/version.js (if it should stay independently versioned like sdk/mobile-mcp).
中文说明
此修复只解决了表面问题 —— 导致本次 lockfile/manifest 版本漂移的发布自动化流程,会在下一次发布时再次制造同样的漂移。scripts/version.js 会升级所有不在 workspacesToExclude(目前只有 @qwen-code/sdk 和 @qwen-code/mobile-mcp)中的 workspace;@qwen-code/external-context 不在排除列表中,因此发布时它的 manifest 会在 CI 工作目录中被升级,随后的 npm install --ignore-scripts 又会把新版本写入 lockfile。但 .github/workflows/release.yml:401 只暂存 package.json package-lock.json packages/*/package.json packages/channels/*/package.json —— 没有任何 glob 能匹配到 integrations/external-context/package.json,所以只有 lockfile 的版本变更被提交,而 manifest 的版本变更被丢弃。发布提交 4d6246bd88(v0.21.8)正是这样做的:只有 lockfile 条目从 0.20.1 → 0.21.8,manifest 并未被改动。 —— 失败场景:下一次发布(例如 v0.21.9)时,main 分支上会再次出现同样的漂移 —— lockfile 记录的是发布版本,而 manifest 仍停留在 0.20.1,于是所有贡献者本地运行 npm install 都会再次改写 lockfile、弄脏工作区,每个发布周期都需要再提一个相同的清理 PR。修复建议:将 integrations/external-context/package.json 加入 release.yml 的 git add 允许列表(如果它应跟随发布版本),或将 @qwen-code/external-context 加入 scripts/version.js 的 workspacesToExclude(如果它应保持独立版本)。
— qwen3.8-max via Qwen Code /review (v0.21.8)
|
@qwen-code /takeover |
|
🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. Remove the 中文说明🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。移除 |
scripts/version.js bumps @qwen-code/external-context with every core release and the follow-up `npm install --ignore-scripts` writes that bump into package-lock.json, but the release version commit's `git add` allowlist does not cover integrations/external-context/package.json. The manifest bump is discarded while the lockfile bump is committed, recreating the drift this PR cleans up after every release (seen in v0.21.8, commit 4d6246b). Stage the manifest so both change together.
|
🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下: Review feedback addressed on PR #8858Base: [Suggestion] rc:3748376954 — Release automation will recreate the lockfile/manifest drift (
|
yiliang114
left a comment
There was a problem hiding this comment.
LGTM. The drift mechanism checks out: release.yml's version-bump step regenerated and committed the lockfile but its git add list omitted integrations/external-context/package.json, so the lockfile recorded 0.21.8 while the manifest stayed at 0.20.1 — and every local npm install since rewrites the lockfile back, dirtying every contributor's tree. This PR fixes both halves: the manifest path joins the add list (root cause, prevents the next release from re-drifting) and the lockfile entry is resynced to 0.20.1, byte-identical to what npm generates (verified the manifest at head is 0.20.1, so lockfile and manifest now agree and npm install is idempotent). Metadata-only; no resolution changes. CI has no failures on this head. Nothing blocks merge.
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 36 passed · 0 failed · 36 total 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:36 通过 · 0 失败 · 36 总计 Verification reportPR 8858 Deep Verification —
|
| cell | environment | observable oracle | result |
|---|---|---|---|
base (HEAD^1 77bd04b) |
worktree, lockfile blob efecb12f53 |
lockfile rewritten? diff shape? regenerated blob hash | rewritten; diff = exactly 2 lines (1−/1+), the 0.21.8 → 0.20.1 flip; regenerated blob b40cbe75cf… |
head (merge of HEAD^2 c17a34a) |
worktree, lockfile blob b40cbe75cf |
lockfile untouched? blob unchanged? | untouched; blob stays b40cbe75cf… |
The regenerated-on-base blob hash equals the committed-at-head blob hash (b40cbe75cf20e446f0aba888b739c8b209fb8f5f) — this proves the author's byte-identity claim with git's own hash, and simultaneously proves the head lockfile is npm's exact reconciliation output (idempotent). 8/8 assertions incl. npm exit codes. Witness: 01-ab-lockfile-base-dirty-vs-head-clean.png.
Sibling sweep / completeness: head-cell idempotency is a census, not a sample — npm's reconciler was given every chance to rewrite anything and changed nothing, so no other stale workspace entry remains. Independently: all 22 workspaces enumerated (npm ls --workspaces --json --depth=0); @qwen-code/external-context appears in the root lockfile only as its own workspace entry plus a link: true node — no semver-range reference anywhere (root manifest references it only in the workspaces array; no sub-project lockfile mentions it; the package is "private": true, so no publish-at-wrong-version risk). The version flip is pure metadata; npm ci installability at HEAD is evidenced by the workflow's own completed npm ci + npm run build (environment contract), and independently re-probed here: npm ci --dry-run --ignore-scripts exits 0 on both arms with an identical 2292 packages resolved — the flip changes no dependency edge, and (notably) the pre-PR drift did not break clean installs either, since npm ci's sync check validates dependency edges, not workspace-entry version metadata. That bounds the severity precisely: this was a dirty-working-tree / accidental-commit hazard, not a broken-install one.
Secondary claim — release replay: the allowlist change fixes the root cause
Mechanism verified from code first: scripts/version.js bumps every workspace except @qwen-code/sdk / @qwen-code/mobile-mcp (exclusion list read from source; @qwen-code/external-context confirmed present in the bumped set of 22), then npm install --ignore-scripts writes the bump into the lockfile. The commit step's git add allowlist is therefore the only gate deciding which bumped manifests enter the version commit.
The step's run: block was extracted verbatim with js-yaml from release.yml at base and head (control assertion: the two extractions differ in exactly one line — the PR hunk). A scratch repo was seeded with real manifests from the base tree; the on-disk effect of npm run release:version 0.21.9 was simulated (version bumps for root + all bumped workspaces, channel-base pinning, lockfile entry versions — the two excluded packages left untouched as controls); then each extracted block ran under the Actions default shell contract (bash --noprofile --norc -e, IS_DRY_RUN=true, RELEASE_TAG=v0.21.9-test).
| arm | version commit contains | post-step state | committed lockfile entry vs manifest |
|---|---|---|---|
| base | lockfile ✓, root/cli/core/channels ✓, external-context manifest ✗ (expected defect) | manifest bump left unstaged ( M) |
0.21.9 vs 0.20.1 — drift born, identical shape to the observed 0.21.8/0.20.1 |
| head | all of the above plus external-context manifest ✓ | clean (nothing unstaged) | 0.21.9 vs 0.21.9 — in sync |
Untouched-control assertions held on both arms: the un-bumped packages/sdk-typescript/package.json was matched by the packages/* glob but correctly not staged. 17/17 assertions. Witness: 02-release-replay-base-drops-manifest-head-stages-it.png.
Calibration note: the base arm reproduces the shape of the real v0.21.8 drift (which is physically present at HEAD^1 and reproduced byte-exactly by the central A/B) — the replay proves the allowlist mechanism that produces it, driven through the verbatim production command, but not from an actual recorded release run (see Not covered).
Gates
| gate | scope | result |
|---|---|---|
bash -n |
both extracted run blocks | clean; liveness proven (planted unterminated quote and unclosed if both → exit 2) |
| shellcheck 0.11.0 (repo excludes + bash dialect) | changed run block | clean; only pre-extraction artifacts (SC2148/SC2154) were symmetric between arms |
| actionlint 1.7.12 (repo flags) | release.yml at head and base |
exit 0 / exit 0 |
| yamllint line-length proxy | .github/workflows/*.yml |
2981 >80-col lines already present at BASE (the changed line itself was 103 cols pre-PR) — no line-length gate can be active in this repo, so the 148-col line adds no new gate risk |
npm ci --dry-run --ignore-scripts |
base and head worktrees | exit 0 / exit 0, 2292 == 2292 packages — resolution unchanged; the pre-PR drift did not break npm ci either |
npm ci + npm run build at HEAD |
whole tree | completed by the workflow before this round (environment contract) |
Findings
No blocking findings.
Suggestion (non-blocking, optional hardening): the version-commit allowlist remains a hand-maintained enumeration of workspace locations. It is complete today — every bumped workspace path (packages/*, packages/channels/*, integrations/external-context) is covered, and the excluded sdk/mobile-mcp are not bumped — but the same drift class will silently return if a future workspace is added outside those globs (as integrations/external-context did). Deriving the add-list from npm ls --workspaces --json output, or asserting manifest/lockfile sync as a release precondition, would close the class instead of the instance. No code change requested; the PR as scoped is correct.
Not covered
- Replay calibration against a real emitted release commit. The depth-2 checkout has no tags or release history (the commit message's cited
4d6246bd88is unreachable), so the replay is calibrated only against the drift shape physically present atHEAD^1, not against an actual recorded release run. Calibrating would require fetching the v0.21.8 version commit's tree from the network, which this sandbox does not do. - Per-commit attribution.
git rev-list HEAD^1..HEAD^2returns 1 on this grafted shallow checkout while the metadata snapshot lists 2 commits (72bd5bbdlockfile sync,c17a34a2release.yml) — per the shallow-boundary rule the individual commits are treated as unreachable. The aggregateHEAD^1..HEADdiff was verified, and each commit's declared scope maps to exactly one of the two files whose behavior was individually exercised above (A/B for the lockfile, replay for release.yml). - Full
npm install(with reification) — replaced by--package-lock-onlyin the A/B (identical lockfile computation) plus the workflow's completednpm ciat HEAD for installability. - yamllint binary — not installable in this container (no pip/pip3, venv creation fails on missing ensurepip). Mitigated by actionlint (YAML/workflow structure) and the line-length census above;
.yamllint.ymldefines noline-lengthoverride and the repo contains thousands of longer lines on main. - Repo-wide test suite / typecheck — deliberately skipped: the diff touches no production code; the workflow's own install + build gate at HEAD is cited instead.
- Actually executing
scripts/version.jsend-to-end — would require a fullnpm installand mutates the tree; its file-level effect was simulated instead (harness02-simulate-bump.mjs), matching steps 2–8 of the script. - Historical claim "seen in v0.21.8, commit 4d6246b" — unreachable at depth 2; the drift's present-day residue at
HEAD^1was verified instead.
Methodology
Environment: CI merge-ref checkout (HEAD = merge commit, HEAD^1 = base tip 77bd04bd61, HEAD^2 = PR head c17a34a27c), node v22.23.2 / npm 10.9.8 in the lane's node:22-bookworm container (author reported npm 10.9.7; the byte-identity proof is against this container's npm output, which is the stronger statement). Both A/B cells ran in detached git worktrees with no node_modules — symmetric, differing only by the PR diff (verified by diffing the two commits and checking the 38 merged-in main files contain no manifests). Harnesses 01-ab-lockfile.sh and 02-release-replay.sh (with 02-extract-run.mjs, 02-simulate-bump.mjs) live in this artifact dir; per-cell npm/step stdout+stderr are under logs/. The release replay executed the js-yaml-extracted production run: blocks verbatim under bash --noprofile --norc -e in throwaway scratch repos with IS_DRY_RUN=true (no push, no network writes); lint binaries were the repo-pinned versions fetched by scripts/lint.js --setup (actionlint 1.7.12, shellcheck 0.11.0). An early shakedown run of each harness surfaced two harness bugs (missing --ignore-scripts for the bare-worktree prepare hook; a wrong seed path packages/sdk → packages/sdk-typescript) — both fixed and re-run green; the final counts above come from the final runs. Worktrees were removed after capture.
Evidence images
Harness scripts and raw logs are in the workflow run artifacts (7-day retention).
— Qwen Code · sandboxed verification
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
|
Released in v0.21.9. |


What this PR does
This PR resyncs a stale workspace entry in the dependency lockfile. The lockfile still recorded an old version for the external-context integration workspace, while that workspace's own package manifest had long since been set to a different version. The lockfile metadata is regenerated with
npm install --package-lock-onlyso both agree again.Why it's needed
The version mismatch makes every local
npm installrewrite the lockfile, producing an unexpectedly dirty working tree for all contributors and risking accidental commits of lockfile churn. The drift surfaced while debugging a local build failure, where the lockfile was found out of sync with the installed dependency tree.Reviewer Test Plan
How to verify
On
main, runnpm install(ornpm install --package-lock-only) and observegit statusreporting a modified lockfile: the external-context workspace version flips from the stale recorded value to the value in that workspace's manifest. With this PR applied, the same command leaves the lockfile untouched. The committed change is byte-identical to what npm itself generates when reconciling the tree (same git blob hash), so the regeneration is idempotent and no dependency resolution changes.Evidence (Before & After)
Before (on
main, afternpm install):After (this PR): the committed lockfile content is exactly the output above, so a follow-up
npm installproduces no further changes andgit statusstays clean.Tested on
Lockfile metadata only; no platform-specific code is touched, and CI covers the dependency install on all platforms.
Environment (optional)
Node v22.22.2, npm 10.9.7, plain
npm installoutside any sandbox.Risk & Scope
npm ciinstalls are unaffected.Linked Issues
Discovered while debugging a local build failure; no linked issue.
中文说明
本 PR 做了什么
本 PR 重新同步了依赖 lockfile 中一个过期的 workspace 条目。lockfile 中 external-context 集成 workspace 记录的仍是旧版本,而该 workspace 自己的 package manifest 早已设置为另一个版本。通过
npm install --package-lock-only重新生成 lockfile 元数据,使两者重新一致。为什么需要
版本不一致会导致每个贡献者本地运行
npm install时都改写 lockfile,产生意外的脏工作区,还可能不小心把 lockfile 变动提交进去。这个问题是在排查一次本地构建失败时发现的:当时 lockfile 与已安装的依赖树不同步。评审者测试计划
如何验证
在
main分支上运行npm install(或npm install --package-lock-only),可以看到git status报告 lockfile 被修改:external-context workspace 的版本从过期的记录值翻转为该 workspace manifest 中的值。应用本 PR 后,同样的命令不会再改动 lockfile。本次提交的改动与 npm 自行调和依赖树时生成的结果逐字节一致(git blob 哈希相同),因此重新生成是幂等的,依赖解析结果没有任何变化。证据(修改前后对比)
修改前(
main分支,运行npm install后):修改后(本 PR):提交的 lockfile 内容正是上面的输出结果,因此再次运行
npm install不会产生任何变动,git status保持干净。测试环境
仅涉及 lockfile 元数据,未触碰任何平台相关代码,CI 会在所有平台上覆盖依赖安装。
环境(可选)
Node v22.22.2、npm 10.9.7,沙箱外的普通
npm install。风险与范围
npm ci安装均不受影响。关联 Issue
在排查本地构建失败时发现,无关联 issue。