Skip to content

fix(voice): bundle native audio addon into standalone archives - #5628

Merged
qqqys merged 5 commits into
QwenLM:mainfrom
qqqys:feat/voice-standalone-addon-bundle
Jun 22, 2026
Merged

fix(voice): bundle native audio addon into standalone archives#5628
qqqys merged 5 commits into
QwenLM:mainfrom
qqqys:feat/voice-standalone-addon-bundle

Conversation

@qqqys

@qqqys qqqys commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #5502 (voice dictation) — P0 standalone streaming (tracked in #5590).

Problem: standalone release archives ship only curated dist/ entries, not node_modules. The native addon @qwen-code/audio-capture is esbuild-external and resolved at runtime via import('@qwen-code/audio-capture'), so in a standalone install it can't be found → streaming voice is unavailable (batch only, and only if SoX is on PATH).

Fix: create-standalone-package.js now bundles the addon into lib/node_modules/ (where the bundled lib/cli.js resolves bare specifiers):

  • @qwen-code/audio-capture/: trimmed package.json (install hook removed; type/exports kept for ESM resolution) + dist/ + only this archive target's prebuilds/<platform>-<arch>/ (win-x64win32-x64).
  • node-gyp-build/ — the addon's only (zero-dep) runtime dependency.
  • Targets with no matching prebuild (e.g. local builds) ship without the addon and degrade to SoX/arecord as before (warns, doesn't fail).

The release pipeline already downloads prebuilds before packaging.

Validation: locally simulated the bundled layout and confirmed ESM import('@qwen-code/audio-capture') from lib/ resolves → loads the darwin-arm64 prebuild → getPlatformBackendName() = coreaudio, microphoneAuthorizationStatus() reads OK. Other targets use the same code path with their downloaded prebuild; full per-archive load is exercised by the release build.

Optional follow-up (not in this PR): extend verify:installation-release to assert the addon loads in each built archive, closing the per-platform loop in CI.

Refs #5502, #5590.

Standalone archives shipped only curated dist/ entries, so the esbuild-external
@qwen-code/audio-capture addon couldn't be resolved at runtime — streaming voice
was unavailable in standalone installs (batch only, and only with SoX on PATH).

create-standalone-package.js now bundles the addon into lib/node_modules (where
the bundled lib/cli.js resolves bare specifiers): the trimmed package.json
(install hook removed; type/exports kept for ESM resolution) + dist + only this
target's prebuild (win-x64 -> win32-x64) + its zero-dep runtime dependency
node-gyp-build. Targets without a matching prebuild (e.g. local builds) ship
without it and degrade to SoX/arecord as before (warns, doesn't fail). The
release pipeline already downloads prebuilds before packaging.

Refs: QwenLM#5502, QwenLM#5590.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
yiliang114
yiliang114 previously approved these changes Jun 22, 2026

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

wenshao
wenshao previously approved these changes Jun 22, 2026
@qqqys
qqqys enabled auto-merge (squash) June 22, 2026 09:48
@qqqys
qqqys dismissed stale reviews from wenshao and yiliang114 via fe50b80 June 22, 2026 09:50
Comment thread scripts/create-standalone-package.js Outdated
dereference: true,
verbatimSymlinks: false,
};
fs.cpSync(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] fs.cpSync copies the entire packages/audio-capture/dist/ verbatim, including platform.test.js, platform.test.d.ts, and platform.test.js.map. The addon's own package.json files field explicitly excludes test artifacts ("!dist/**/*.test.*"), but this raw filesystem copy bypasses that filter.

Suggested change
fs.cpSync(
fs.cpSync(
path.join(addonSrc, 'dist'),
path.join(addonDest, 'dist'),
{ ...copyOpts, filter: (src) => !/\.test\.[mc]?[jt]s(\.map)?$/.test(src) },
);

— qwen3.7-max via Qwen Code /review

wenshao
wenshao previously approved these changes Jun 22, 2026
@wenshao

wenshao commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Verification — native audio addon bundled into standalone archives ✅

This is a packaging change, so rather than driving the interactive TUI I verified by running the real standalone packaging locally (built from HEAD 2709c771, npm ci) on linux-x64. I created a genuine linux-x64 prebuild from the locally-compiled addon (packages/audio-capture/build/Release/audio_capture.node, a real ELF x86-64 .node), ran scripts/create-standalone-package.js, extracted the archive, and confirmed the bundled addon resolves and natively loads from the standalone lib/ layout — the exact failure this PR fixes.

Results

Check Result
New unit tests (install-script.test.js, the 3 audio cases) ✅ pass
Real packaging: addon bundled to lib/node_modules/@qwen-code/audio-capture
Trimmed manifest — type/exports kept; scripts/devDependencies dropped; node-gyp-build dep kept
Only this target's prebuild bundled (real ELF x86-64)
Test artifacts (*.test.js / .d.ts / .map) filtered out
node-gyp-build runtime dep bundled
No symlinks in the bundle
import('@qwen-code/audio-capture') resolves from lib/ + native load OK
REQUIRE=1 + missing prebuild → packaging fails (strict, official releases)
no REQUIRE + missing prebuild → warns, ships without addon (SoX fallback)
win-x64win32-x64 prebuild-dir mapping

Key evidence

Standalone load — probe run from inside the extracted archive's lib/ (no node_modules above it, i.e. a real standalone layout):

resolved      : file://…/qwen-code/lib/node_modules/@qwen-code/audio-capture/dist/index.js
node-gyp-build: file://…/qwen-code/lib/node_modules/node-gyp-build/index.js
backendName   : alsa-pulse
isRecording   : false
micAuthStatus : unknown
NATIVE LOAD OK

Bundled layout (extracted qwen-code-linux-x64.tar.gz):

lib/node_modules/
  @qwen-code/audio-capture/
    package.json            # trimmed: type+exports kept, scripts/devDeps gone, deps={node-gyp-build}
    dist/index.js           # present;  dist/platform.test.{js,d.ts,js.map} -> filtered out
    prebuilds/linux-x64/audio_capture.node   # real ELF 64-bit x86-64
  node-gyp-build/…          # runtime dep bundled
# symlinks under node_modules: 0

Strict / degrade / mapping:

REQUIRE=1, no prebuild (linux-x64)  -> Error: Required audio-capture prebuild is missing for linux-x64   (exit 1)
no REQUIRE, no prebuild (linux-x64) -> "[standalone] no audio-capture prebuild …; bundling without the native addon"  (exit 0, addon NOT bundled)
REQUIRE=1, no prebuild (win-x64)    -> Error: Required audio-capture prebuild is missing for win32-x64    (win-x64 → win32-x64 ✓)

Notes

  • The Node runtime archive was a fake (as the repo's own packaging tests use) — copyNativeAddon runs before Node extraction, and the bundled prebuild is the real locally-compiled linux-x64 binary, so the native load above is genuine.
  • One unrelated, pre-existing test failed in the full-file run: Linux/macOS installer end-to-end > preserves context when npm fallback also fails. It shells out to the installer and needs network/tooling unavailable in my sandbox (empty output after ~18s); it is not touched by this PR. The 3 new audio tests and the release.yml assertion all pass.

No issues found end-to-end — the fix bundles and loads the native addon in a standalone install, with correct strict/degrade and platform mapping. LGTM. 🚀

中文版(合并参考)

验证 —— 将原生音频 addon 打包进 standalone 归档 ✅

这是一个打包改动,因此我没有去驱动交互式 TUI,而是在本地 真实运行 standalone 打包流程(基于 HEAD 2709c771npm ci),目标平台 linux-x64。我用本地编译出的 addon(packages/audio-capture/build/Release/audio_capture.node,一个真实的 ELF x86-64 .node)造了一个真实的 linux-x64 prebuild,运行 scripts/create-standalone-package.js,解开归档,确认打进去的 addon 能从 standalone 的 lib/ 布局里 被解析并真正原生加载 —— 这正是本 PR 修复的问题。

结论

检查项 结果
新增单测(install-script.test.js 的 3 个音频用例) ✅ 通过
真实打包:addon 进入 lib/node_modules/@qwen-code/audio-capture
精简后的 manifest —— 保留 type/exports,去掉 scripts/devDependencies,保留 node-gyp-build 依赖
只打入当前目标的 prebuild(真实 ELF x86-64)
测试产物(*.test.js / .d.ts / .map)被过滤
addon 的运行时依赖 node-gyp-build 一并打入
包内无符号链接
lib/ 解析 import('@qwen-code/audio-capture') 且原生加载成功
REQUIRE=1 且缺 prebuild → 打包 失败(官方发布的严格模式)
REQUIRE 且缺 prebuild → 告警,不打入 addon(回退到 SoX)
win-x64win32-x64 prebuild 目录映射

关键证据

standalone 加载 —— 在解开后的归档 lib/ 目录内运行探针(其上层没有 node_modules,即真实的 standalone 布局):

resolved      : file://…/qwen-code/lib/node_modules/@qwen-code/audio-capture/dist/index.js
node-gyp-build: file://…/qwen-code/lib/node_modules/node-gyp-build/index.js
backendName   : alsa-pulse
isRecording   : false
micAuthStatus : unknown
NATIVE LOAD OK

打包布局(解开 qwen-code-linux-x64.tar.gz):

lib/node_modules/
  @qwen-code/audio-capture/
    package.json            # 精简:保留 type+exports,去掉 scripts/devDeps,deps={node-gyp-build}
    dist/index.js           # 存在;dist/platform.test.{js,d.ts,js.map} 已被过滤
    prebuilds/linux-x64/audio_capture.node   # 真实 ELF 64-bit x86-64
  node-gyp-build/…          # 运行时依赖已打入
# node_modules 下符号链接数:0

严格 / 降级 / 映射

REQUIRE=1,缺 prebuild(linux-x64)  -> Error: Required audio-capture prebuild is missing for linux-x64   (exit 1)
无 REQUIRE,缺 prebuild(linux-x64) -> "[standalone] no audio-capture prebuild …; bundling without the native addon"  (exit 0,未打入 addon)
REQUIRE=1,缺 prebuild(win-x64)    -> Error: Required audio-capture prebuild is missing for win32-x64    (win-x64 → win32-x64 ✓)

说明

  • Node 运行时归档用的是假的(与仓库自带打包测试一致)—— copyNativeAddon 在解 Node 之前执行,而打入的 prebuild 是本地真实编译的 linux-x64 二进制,所以上面的原生加载是真实的。
  • 整文件跑测时有 1 个 与本 PR 无关的既有 用例失败:Linux/macOS installer end-to-end > preserves context when npm fallback also fails。它会调起安装脚本、依赖我沙箱里没有的网络/工具(约 18s 后输出为空);该用例不在本 PR 改动范围内。3 个新增音频用例与 release.yml 断言均通过。

端到端未发现问题 —— 该修复确实把原生 addon 打进并能在 standalone 安装中加载,严格/降级与平台映射均正确。LGTM 🚀

wenshao
wenshao previously approved these changes Jun 22, 2026
return;
}

const nodeRequire = createRequire(import.meta.url);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] copyNativeAddon can throw raw ENOENT (if packages/audio-capture/dist/ is missing) or MODULE_NOT_FOUND (if node-gyp-build isn't resolvable) without a contextual error message. The rest of this file uses fail() with descriptive messages (e.g., "Required dist asset missing: ..."). Wrapping these calls in try/catch with fail(...) would match the existing pattern and make build failures self-diagnosing — especially important in CI where a raw ENOENT from cpSync doesn't mention the addon-bundling step.

Suggested change
const nodeRequire = createRequire(import.meta.url);
let nodeGypBuildSrc;
try {
const nodeRequire = createRequire(import.meta.url);
nodeGypBuildSrc = path.dirname(
nodeRequire.resolve('node-gyp-build/package.json'),
);
} catch {
fail('node-gyp-build (runtime dep of @qwen-code/audio-capture) is not resolvable from the repo root. Run npm install before packaging.');
}

Similarly, add an existence check before the dist/ copy:

const addonDist = path.join(addonSrc, 'dist');
if (!fs.existsSync(addonDist)) {
  fail(`audio-capture compiled output is missing: ${addonDist}. Run 'npm run build' first.`);
}

— qwen3.7-max via Qwen Code /review

'audio-capture',
'dist',
);
expect(existsSync(path.join(addonDist, 'index.js'))).toBe(true);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] This test verifies that dist/index.js is copied and test files are filtered, but never asserts the .node prebuild binary or node-gyp-build were bundled — the two core reasons copyNativeAddon exists. If the prebuild copy or node-gyp-build copy were accidentally removed, this test would still pass while streaming voice silently breaks in every standalone release.

Consider adding:

// Verify .node prebuild is bundled
const addonPrebuild = path.join(
  extractDir, 'qwen-code', 'lib', 'node_modules',
  '@qwen-code', 'audio-capture', 'prebuilds', 'linux-x64',
);
expect(existsSync(path.join(addonPrebuild, '@qwen-code+audio-capture.node'))).toBe(true);

// Verify node-gyp-build is bundled
const nodeGypBuildDir = path.join(
  extractDir, 'qwen-code', 'lib', 'node_modules', 'node-gyp-build',
);
expect(existsSync(path.join(nodeGypBuildDir, 'package.json'))).toBe(true);

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@wenshao

wenshao commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

CI failure root cause: two new tests build a Linux tar fixture on the Windows runner without the itOnUnix guard

This isn't a compile/lint failure, and it's not in the app code. Only Test (windows-latest, Node 22.x) failed — macOS passed, Ubuntu is still running. Every vitest workspace suite passed; the failure is in the test:scripts stage, in scripts/tests/install-script.test.js:

FAIL  scripts/tests/install-script.test.js > standalone release packaging > requires the native audio prebuild when release packaging opts in
FAIL  scripts/tests/install-script.test.js > standalone release packaging > requires a native audio prebuild file when release packaging opts in
AssertionError: expected [Function] to throw error matching /audio-capture prebuild.*linux-x64/
  but got 'Command failed: tar -czf C:\Users\RUNNER~1\AppData\Local\Temp\qwen-package-test-…\node-v22.0.0-linux-x64.tar.gz -C … node-v22.0.0-linux-x64'

Why it fails

Both new tests are shaped like this:

it('requires the native audio prebuild when release packaging opts in', () => {
  ...
  expect(() =>
    execFileSync('node', [
      'scripts/create-standalone-package.js',
      '--target', 'linux-x64',
      '--node-archive', createFakeNodeArchive(tmpDir),   // ← evaluated FIRST, inside the arrow
      ...
    ], { env: { ...QWEN_STANDALONE_REQUIRE_AUDIO_CAPTURE_PREBUILD: '1' }, stdio: 'pipe' }),
  ).toThrow(/audio-capture prebuild.*linux-x64/);
});

createFakeNodeArchive(tmpDir) builds a Linux Node runtime fixture by shelling out to tar (scripts/tests/install-script.test.js:4151):

const archive = path.join(tmpDir, 'node-v22.0.0-linux-x64.tar.gz');
execFileSync('tar', ['-czf', archive, '-C', tmpDir, path.basename(fakeNodeDir)], { ... stdio: 'ignore' });

On the Windows runner that tar -czf C:\…\node-v22.0.0-linux-x64.tar.gz … invocation fails (most likely the classic Windows GNU-tar gotcha — it reads the C:-prefixed -f path as a host:path remote spec; the real stderr is hidden because the helper uses stdio: 'ignore'). Because createFakeNodeArchive(tmpDir) is evaluated inside the expect(() => …) arrow, the arrow throws that tar "Command failed" error before create-standalone-package.js ever runs — so the assertion sees the tar error instead of the intended audio-capture prebuild … linux-x64 error, and fails.

macOS passed because BSD tar there handles the absolute path fine. This is purely the Windows runner.

The actual defect

This file already guards Linux-fixture tests so they don't run on Windows — scripts/tests/install-script.test.js:43:

const itOnUnix = process.platform === 'win32' ? it.skip : it;

Every other test that builds a Linux tar fixture uses itOnUnix and is correctly skipped on Windows — you can see its siblings marked (skipped) in the same run (dereferences safe Node.js runtime symlinks, does not package audio-capture test artifacts, etc.). The two new audio-prebuild tests were written with a bare it(...), so they run a Linux-only tar fixture on Windows.

Suggested fix

Switch the two new tests from it( to itOnUnix( (around :1690 and :1727), matching the established convention for Linux-fixture tests in this file:

itOnUnix('requires the native audio prebuild when release packaging opts in', () => { ... });
itOnUnix('requires a native audio prebuild file when release packaging opts in', () => { ... });

The --target linux-x64 audio-prebuild requirement is inherently a Linux packaging concern, so skipping it on Windows loses no coverage. (Alternatively createFakeNodeArchive could pass --force-local to tar, but since the Linux fixture isn't meaningful to validate on Windows, skipping is cleaner and consistent with the rest of the file.)

中文版

CI 失败根因:两个新测试在 Windows runner 上构建 Linuxtar fixture,却漏了 itOnUnix 守卫

这不是编译/lint 失败,也不在应用代码里。只有 Test (windows-latest, Node 22.x) 挂了——macOS 通过,Ubuntu 还在跑。所有 vitest 工作区套件都通过;失败发生在 test:scripts 阶段的 scripts/tests/install-script.test.js:

FAIL  ... > requires the native audio prebuild when release packaging opts in
FAIL  ... > requires a native audio prebuild file when release packaging opts in
AssertionError: expected [Function] to throw error matching /audio-capture prebuild.*linux-x64/
  but got 'Command failed: tar -czf C:\Users\RUNNER~1\...\node-v22.0.0-linux-x64.tar.gz ...'

失败原因

两个新测试的写法是:

expect(() =>
  execFileSync('node', [
    'scripts/create-standalone-package.js', '--target', 'linux-x64',
    '--node-archive', createFakeNodeArchive(tmpDir),   // ← 在箭头函数里最先被求值
    ...
  ], ...),
).toThrow(/audio-capture prebuild.*linux-x64/);

createFakeNodeArchive(tmpDir)(install-script.test.js:4151)通过调用 tar 来构建一个 Linux 的 Node 运行时 fixture:

execFileSync('tar', ['-czf', archive, '-C', tmpDir, path.basename(fakeNodeDir)], { ... stdio: 'ignore' });

在 Windows runner 上,这条 tar -czf C:\…\node-v22.0.0-linux-x64.tar.gz … 失败了(最可能是经典的 Windows GNU-tar 坑——它把 C: 开头的 -f 路径当成了 host:path 远程规格;由于 helper 用了 stdio: 'ignore',真正的 stderr 被吞掉了)。而 createFakeNodeArchive(tmpDir)expect(() => …) 箭头函数内部被求值的,所以 tar 一失败,箭头函数就抛出这个 "Command failed" 的 tar 错误,create-standalone-package.js 根本还没运行——于是断言拿到的是 tar 错误,而不是预期的 audio-capture prebuild … linux-x64 错误,测试失败。

macOS 通过是因为那里的 BSD tar 能正常处理绝对路径。这纯粹是 Windows runner 的问题。

真正的缺陷

这个文件本来就有针对 Linux fixture 的守卫,避免它们在 Windows 上跑(install-script.test.js:43):

const itOnUnix = process.platform === 'win32' ? it.skip : it;

其它所有构建 Linux tar fixture 的测试都用 itOnUnix,在 Windows 上被正确跳过——同一次运行里能看到它的兄弟用例标着 (skipped)。而这两个的 audio-prebuild 测试用的是裸 it(...),所以在 Windows 上跑起了 Linux 专用的 tar fixture。

修复建议

把这两个新测试从 it( 改成 itOnUnix((大约在 :1690:1727),与本文件 Linux-fixture 测试的既有约定保持一致:

itOnUnix('requires the native audio prebuild when release packaging opts in', () => { ... });
itOnUnix('requires a native audio prebuild file when release packaging opts in', () => { ... });

--target linux-x64 的 audio-prebuild 校验本质上就是 Linux 打包的事,在 Windows 上跳过不损失任何覆盖。(也可以让 createFakeNodeArchivetar--force-local,但既然这个 Linux fixture 在 Windows 上验证没意义,直接跳过更干净、也和文件其余部分一致。)

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@qqqys
qqqys merged commit 8809c16 into QwenLM:main Jun 22, 2026
22 checks passed

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @qqqys — thanks for the PR! The change itself looks well-thought-out (and @wenshao already ran thorough verification).

However, the PR body doesn't follow our PR template. It uses custom headings (Problem / Fix / Validation) instead of the required template sections:

  • ## What this PR does
  • ## Why it's needed
  • ## Reviewer Test Plan (with How to verify, Evidence, Tested on)
  • ## Risk & Scope
  • ## Linked Issues
  • <details>中文说明</details>

Could you restructure the PR description to match the template? The content is all there — it just needs to be organized into the expected sections so reviewers can quickly find what they need (especially the Tested-on matrix and risk/scope callouts for a cross-platform packaging change like this).

Also, @wenshao identified a CI failure in the two new tests: they use bare it() instead of itOnUnix(), causing the Linux tar fixture to fail on Windows runners. That'll need fixing too.

中文说明

@qqqys 你好 — 感谢 PR!改动本身考虑得很周全(@wenshao 也已经做了详细验证)。

但 PR 正文没有按照我们的 PR 模板 来写。用的是自定义标题(Problem / Fix / Validation),缺少模板要求的章节:

  • ## What this PR does
  • ## Why it's needed
  • ## Reviewer Test Plan(含 How to verify、Evidence、Tested on)
  • ## Risk & Scope
  • ## Linked Issues
  • <details>中文说明</details>

能否按模板重新组织一下 PR 描述?内容其实都有了,只是需要按预期章节整理,方便 reviewer 快速找到关键信息(尤其是这种跨平台打包改动的 Tested-on 矩阵和风险/范围说明)。

另外,@wenshao 发现了 CI 失败的原因:两个新测试用了裸 it() 而不是 itOnUnix(),导致 Linux 的 tar fixture 在 Windows runner 上失败。这个也需要一起修。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @qqqys — re-triage after your latest commit (26d8120 — Windows test fix).

Template: the PR body still uses custom headings (Problem / Fix / Validation) instead of the PR template sections (What this PR does, Why it's needed, Reviewer Test Plan, Risk & Scope, Linked Issues). Would be great to align for consistency — but noting this isn't blocking given the technical quality and maintainer sign-off.

Direction: clearly aligned — standalone archives can't resolve @qwen-code/audio-capture without this, making streaming voice unavailable. Direct follow-up to #5502/#5590 (P0). Fills a real gap.

Approach: minimal and focused. One new function (copyNativeAddon) slotted into the existing packaging pipeline, graceful degradation when prebuilds are absent, strict mode for official releases via QWEN_STANDALONE_REQUIRE_AUDIO_CAPTURE_PREBUILD. Three focused files, no scope creep.

Code review: clean implementation — follows the existing code style in create-standalone-package.js, reuses assertNoSymlinks/fail patterns already established. The TARGET_PREBUILD_DIR map and hasNativePrebuild helper are straightforward. Test artifact filtering (*.test.*) is correct. The node-gyp-build runtime dep bundling is the right call. No issues found.

CI: all green — macOS ✓, Windows ✓ (after your latest fix), Ubuntu ✓, Lint ✓, CodeQL ✓.

Prior verification from @wenshao confirmed the addon bundles and loads correctly in a real standalone layout, strict/degrade/mapping all work as designed. LGTM.

中文说明

Hi @qqqys —— 在你最新提交 (26d8120 — Windows 测试修复) 之后重新过了一遍 triage。

模板: PR 描述仍然使用自定义标题(Problem / Fix / Validation),而非 PR 模板 要求的章节(What this PR doesWhy it's neededReviewer Test PlanRisk & ScopeLinked Issues)。建议后续对齐以保持一致性——但鉴于技术质量和 maintainer 签核,这不是阻塞项。

方向: 明确对齐 —— standalone 归档无法解析 @qwen-code/audio-capture,导致流式语音不可用。是 #5502/#5590(P0)的直接后续。填补了实际缺口。

方案: 最小且聚焦。一个新函数(copyNativeAddon)嵌入现有打包流水线,prebuild 缺失时优雅降级,官方发布通过 QWEN_STANDALONE_REQUIRE_AUDIO_CAPTURE_PREBUILD 启用严格模式。3 个文件,无范围蔓延。

代码审查: 实现干净 —— 遵循 create-standalone-package.js 现有代码风格,复用已有的 assertNoSymlinks/fail 模式。TARGET_PREBUILD_DIR 映射和 hasNativePrebuild 辅助函数都很简洁。测试产物过滤(*.test.*)正确。node-gyp-build 运行时依赖一并打入是正确的做法。未发现问题。

CI: 全绿 —— macOS ✓、Windows ✓(最新修复后)、Ubuntu ✓、Lint ✓、CodeQL ✓。

@wenshao 之前的验证已确认 addon 在真实 standalone 布局中正确打包并加载,严格/降级/映射均按预期工作。LGTM。

Qwen Code · qwen3.7-max

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants