fix(live-host-release): correct setup-node action SHA for qwen-live publish - #10826
fix(live-host-release): correct setup-node action SHA for qwen-live publish#10826LaZzyMan wants to merge 13 commits into
Conversation
`qwen-live init` walks a new user through setup: - Scans PATH for supported coding agents (qodercli, qwen, gemini, claude, codex) via `--version` probe, resolving each to an absolute path. Native agents (qodercli/qwen/gemini) use their resolved binary directly; adapter-based agents (claude/codex) configure npx to run the ACP adapter, passing the detected binary via env (CODEX_PATH). - Interactive prompts (prompts library) let the user pick a default backend, add additional backends, enter their DashScope API key (with env-var reuse option), and set a working directory. - macOS: checks the Live Host app via LiveHostInstaller.refresh(); offers to install if missing. Non-macOS: informs the user the Host is required. - Writes ~/.qwen-live/config.json atomically (tmp + rename) with user-only permissions (0o600). Subcommand dispatch in index.ts: `qwen-live init` runs the wizard, everything else starts the daemon.
The injector's playback window no longer guesses from byte counts;
the Host app sends real playback_started/completed events.
Protocol:
- LIVE_HOST_PROTOCOL_VERSION 6 → 7 (types.ts both copies +
live-host shared/protocol.ts)
- New Host → Daemon messages: host.playback_started, host.playback_completed
(both carry epoch for call-scoping)
- CLI coordinator copy accepts the new messages (v7 Host connecting to
built-in serve is not rejected as invalid)
- FakeHost in e2e harness bumped to v7
Daemon side (packages/qwen-live):
- Injector: replaces playbackDeadline (byte ÷ 48kB/s estimation) with
playbackInProgress boolean + playbackCompletedAt timestamp.
notePlaybackStarted/notePlaybackCompleted replace noteOutputAudio.
windowClosedForMs returns -1 while playback is active, waits
completedAt + quietGapMs after completion, returns 0 if no playback
or cleared.
- v6 forward compatibility: onOutputAudioDelta calls notePlaybackStarted
as a fallback (v6 Host never sends receipts; v7 Host does). The
fallback preserves the existing "speech after audio triggers
clearOutput" behavior without the byte-estimation wait.
- live-session: onPlaybackStarted/onPlaybackCompleted wired from
coordinator handlers to injector signals
- Coordinator: parseHostMessage + handleTextFrame dispatch the new
messages; LiveCallHandlers gains optional onPlaybackStarted/
onPlaybackCompleted; epoch-scoped (stale receipts ignored)
Host app (packages/live-host):
- audio-engine.ts: constructor gains onPlaybackStarted/
onPlaybackCompleted callbacks; play() fires started on 0→1 source
transition; source.onended fires completed on 1→0 transition
(generation-guarded so clearOutput's stop() doesn't false-fire)
- preload/index.ts: callbacks → IPC live:audio:playback-started/
playback-completed with the current epoch; play IPC payload changes
from bare Uint8Array to { audio, epoch }
- main/index.ts: IPC handlers validate epoch === daemon.getEpoch(),
call daemon.sendPlaybackStarted/sendPlaybackCompleted
- daemon-connection.ts: sendPlaybackStarted/sendPlaybackCompleted
via sendControl
Tests: injector tests rewritten for receipt-based timing (started
holds, completed + gap delivers); e2e discovery assertion bumped to v7.
- live-host parity test: version assertion bumped 6→7, 13/13 pass - injector tests rewritten: playback_started holds window, playback_completed + quiet gap delivers, clearOutput reopens immediately, speech-started returns playbackInProgress - e2e: FakeHost protocol version v7, discovery record assertion v7
The playback-started/completed IPC channels skipped the sender validation every sibling channel applies — an untrusted renderer could forge playback receipts. Added isTrustedSender(event) as the first guard, matching the pattern in live:set-output-muted etc.
…e with Host release
Two fixes in one commit:
1. Playback receipt wiring (qqqys's blocking review):
- daemon.ts setHandlers now passes onPlaybackStarted/
onPlaybackCompleted to the session
- LiveSession gains notePlaybackStarted/notePlaybackCompleted
methods that resolve the active context by epoch and forward
to the injector
- The per-delta notePlaybackStarted fallback in onOutputAudioDelta
is removed — it latched playbackInProgress closed with no matching
completion, blocking all queued injections until the user spoke
- v7 Host receipts now flow end-to-end: Host audio engine →
IPC → daemon-connection → WS frame → coordinator → session →
injector
- Test updated to call session.notePlaybackStarted directly
(matching the production coordinator→session path)
2. qwen-live npm publish in live-host-release.yml:
- Added checkout + install + build + npm publish steps to the
Host release publish job
- Version aligned with the Host release version via npm version
- Published as @qwen-code/qwen-live with --provenance
- Tag: "preview" for prereleases, "latest" for stable
- Skips if the version is already published
@qwen-code/qwen-live does not exist on npm yet; provenance requires an existing package. The workflow now checks if the package exists and omits --provenance on the first publish, adds it on subsequent ones.
GitHub Actions expressions require single quotes for string literals; double quotes cause actionlint to fail.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Thanks for catching this, @LaZzyMan — but I can't move it forward as-is, for two reasons.
1. The PR body doesn't follow the PR template. All required sections are missing: "What this PR does", "Why it's needed", "Reviewer Test Plan" (How to verify / Evidence / Tested on), "Risk & Scope", "Linked Issues", and the Chinese <details> translation. Please fill it in.
2. The diff is much larger than the described fix. The description says this is a one-line SHA fix, but the PR is 25 files / +839/−82 and currently conflicts with main. That's because the branch (feat/qwen-live-m5) is 16 commits behind, and the qwen-live M5 content this diff re-adds was already merged today via #10769.
The underlying problem is real: main's live-host-release.yml currently pins actions/setup-node@49933f5360751b6f8e5e4b6c6f3a8c3c5c5c5c5c (introduced by #10769), which matches no setup-node release and differs from the v6.4.0 SHA (48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e) every other workflow uses — the publish job would indeed fail with "Unable to resolve action".
Suggestion: rebase this branch onto current main — the diff should shrink to the single SHA line — or close this and open a fresh one-line PR. Then fill in the template and this can move quickly.
中文说明
@LaZzyMan 感谢发现这个问题,但目前有两点无法继续推进。
1. PR 描述未遵循 PR 模板:缺少所有必填部分——"What this PR does"、"Why it's needed"、"Reviewer Test Plan"(How to verify / Evidence / Tested on)、"Risk & Scope"、"Linked Issues" 以及中文 <details> 翻译。请补全。
2. 实际 diff 与描述的修复严重不符:描述说是一行 SHA 修复,但 PR 涉及 25 个文件、+839/−82,且当前与 main 冲突。原因是分支(feat/qwen-live-m5)落后 16 个提交,而 diff 中的全部 qwen-live M5 内容今天已经通过 #10769 合入,diff 在重复添加这些内容。
问题本身是真实存在的:main 的 live-host-release.yml 目前固定了 actions/setup-node@49933f5360751b6f8e5e4b6c6f3a8c3c5c5c5c5c(由 #10769 引入),该 SHA 与任何 setup-node 版本都对不上,也和仓库其他所有工作流统一使用的 v6.4.0 SHA(48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e)不一致——publish 任务确实会因 "Unable to resolve action" 失败。
建议: 把分支 rebase 到当前 main——diff 应该会缩小到只剩那一行 SHA 修改;或者直接关闭本 PR,重新提一个一行修复的 PR。之后补全模板即可快速推进。
— Qwen Code · qwen3.8-max
One-line fix: the setup-node action SHA in the qwen-live npm publish step was invalid, causing the publish job to fail with 'Unable to resolve action'. Changed to the same SHA used by every other workflow in the repo (v6.4.0).