Skip to content

fix(web-shell): stop toasting on failed background artifact refreshes - #7437

Closed
zjunothing wants to merge 1 commit into
QwenLM:mainfrom
zjunothing:fix/7427-silent-artifact-refresh
Closed

fix(web-shell): stop toasting on failed background artifact refreshes#7437
zjunothing wants to merge 1 commit into
QwenLM:mainfrom
zjunothing:fix/7427-silent-artifact-refresh

Conversation

@zjunothing

Copy link
Copy Markdown
Collaborator

What this PR does

Adds a { silent?: boolean } option to DaemonSessionActions.loadArtifacts: when set, the failure path skips dispatchActionError's error-severity notice and re-throws the raw error (the calling hook needs the throw for its local error state). useSessionArtifacts — the action's only caller, and a purely automatic one (panel mount, promptStatus → idle, the artifactsVersion workspace signal) — passes silent: true; its existing catch already preserves last-good artifacts. User-initiated actions keep their notices, and the change mirrors enqueueMidturnMessage's established best-effort-and-silent philosophy for background-refreshable actions.

Why it's needed

#7427: the artifact panel repeatedly toasts Load artifacts failed: Failed to fetch during transient connectivity hiccups, because every automatic background refresh routes failures through dispatchActionError, which unconditionally fires an error toast. The user can't act on a failed background poll, and the panel already keeps its last-good data — the toast is pure noise, reappearing on every retriggered refresh. The triage confirmed the root cause from source and the maintainer endorsed exactly this fix shape (interface option + conditional in the action + call-site update in the hook), including the regression-test design this PR implements.

Reviewer Test Plan

How to verify

  1. Run qwen serve, open the Web Shell with an active session, then briefly interrupt connectivity to the daemon (or block the artifacts endpoint). Before this PR: each automatic refresh pops an error toast. After: no toast; the panel keeps showing the last loaded artifacts; artifacts refresh resumes silently when connectivity returns.
  2. npx vitest run src/daemon/session/actions.test.ts (packages/webui) 26/26 and npx vitest run client/hooks/useSessionArtifacts.test.tsx (packages/web-shell) 3/3.

Evidence (Before & After)

Regression tests follow the design suggested on the issue, and both fail on the unpatched source (verified via git stash):

test unpatched patched
silent failure dispatches no notice, still rejects with the raw error ❌ (notice fired)
default (non-silent) failure keeps the daemon.load_artifacts.failed notice ✅ (unchanged)
the hook passes { silent: true } on every refresh; failure lands in local error state; last-good artifacts stay visible; loading settles ❌ (no silent arg)

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

Environment (optional)

macOS (Darwin 24.6), Node v22.23.1; vitest (jsdom for the hook). npm run typecheck, eslint --max-warnings 0, prettier all clean.

Risk & Scope

  • Main risk or tradeoff: a persistent artifact-endpoint outage no longer surfaces a toast — by design for background polls; the hook still records the error locally, and hard failures of user-initiated actions are unaffected. The maintainer's optional fast-follow (suppress only transient network errors, still toast 401/403/404) is deliberately left out to keep this PR the simple shape endorsed on the issue; happy to do it as a follow-up.
  • Not validated / out of scope: getStats shares the dispatchActionError pattern but is only invoked by the explicit /stats command, so it keeps its notice (per the maintainer's note); no other action changes.
  • Breaking changes / migration notes: none — the option is additive and optional.

Linked Issues

Fixes #7427

中文说明

本 PR 做了什么

DaemonSessionActions.loadArtifacts 增加 { silent?: boolean }:置位时失败路径跳过 dispatchActionError 的 error 级 notice、重抛原始错误(调用方 hook 需要 throw 来设置本地 error 状态)。唯一调用方 useSessionArtifacts 的刷新完全是自动触发(面板挂载、prompt→idle、artifactsVersion 信号),现传 silent: true;其既有 catch 已保留上次成功的 artifacts。用户主动操作保留 notice;与同文件 enqueueMidturnMessage 的 best-effort-and-silent 先例一致。

为什么需要

#7427:artifact 面板在瞬时连接抖动期间反复弹 Load artifacts failed: Failed to fetch——每次自动后台刷新的失败都走 dispatchActionError 无条件弹 toast。用户对失败的后台轮询无从行动、面板本就保留旧数据——toast 纯属噪音且随每次重触发反复出现。triage 已源码确认根因,维护者背书了正是本 PR 的修复形状(接口选项 + action 条件 + hook 调用点),包括本 PR 实现的回归测试设计。

审阅测试计划

如何验证

  1. qwen serve 开 Web Shell 活跃会话,短暂中断与 daemon 的连接:本 PR 之前每次自动刷新弹错误 toast;之后无 toast、面板保留上次 artifacts、恢复连接后静默恢复刷新;
  2. webui actions 26/26 + web-shell hook 3/3。

证据(Before & After)

回归测试按 issue 中建议的设计实现,且都在未修复源码上失败(git stash 验证):silent 失败不派发 notice 仍拒绝;默认路径保留 notice;hook 每次刷新都传 silent、失败落本地 error、旧 artifacts 可见、loading 归位。

测试平台

macOS 已本地验证(✅);Windows / Linux 依赖 CI(⚠️)。

环境

macOS(Darwin 24.6)、Node v22.23.1;vitest(hook 用 jsdom);typecheck / eslint / prettier 全绿。

风险与范围

  • 主要风险/权衡:artifact 端点持续故障不再弹 toast——这正是后台轮询的设计意图;hook 仍本地记录错误,用户主动操作的失败不受影响。维护者提到的可选快跟(仅抑制瞬态网络错误、401/403/404 仍弹)有意留作 follow-up,保持本 PR 为 issue 上背书的简单形状。
  • 未验证/超出范围:getStats 共享同模式但仅由显式 /stats 命令调用,按维护者说明保留 notice;无其它 action 变更。
  • 破坏性变更/迁移说明:无——选项为可选新增。

关联 Issue

Fixes #7427

🤖 Generated with Claude Code

The session artifact panel's refresh is purely automatic — mount,
prompt->idle, and the artifactsVersion workspace signal — yet
loadArtifacts() routed every failure through dispatchActionError, which
always fires an error-severity notice. During transient connectivity
hiccups the panel repeatedly toasted "Load artifacts failed: Failed to
fetch" for background polls the user cannot act on (QwenLM#7427).

loadArtifacts now accepts { silent?: boolean }: when set, the failure
notice is suppressed and the raw error is re-thrown (the calling hook
needs the throw for its local error state). useSessionArtifacts passes
silent: true from its only — automatic — call site; its existing catch
already preserves last-good artifacts. This mirrors
enqueueMidturnMessage's best-effort-and-silent philosophy for
background-refreshable actions, per the maintainer's endorsed direction
on the issue. User-initiated actions keep their notices.

Regression tests per the issue's suggestion: a silent failure dispatches
no notice while still rejecting; the default path keeps the notice; the
hook passes silent on every refresh, lands the failure in local error
state, and keeps last-good artifacts visible. Both new tests fail on
the unpatched source.

Fixes QwenLM#7427

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

🖼️ web-shell visual preview

Rendered against a mock daemon (no real backend): the PR base vs this PR head 4440615. Only screenshots that changed are shown (flows below, if any, are head-only) — refreshes on every push.

Screenshots · before / after

No screenshot changes against the PR base.

Full-resolution recordings (.webm) are attached to the workflow run.

Qwen Code · web-shell visuals

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed bug with clear evidence — #7427 reports the artifact panel spamming Load artifacts failed: Failed to fetch toasts during transient connectivity hiccups. Root cause was confirmed from source by the triage bot and independently verified by a maintainer: loadArtifacts() unconditionally routes through dispatchActionError, which always fires an error-severity toast, even for purely automatic background refreshes. The maintainer endorsed the exact fix shape this PR implements.

Direction: aligned. Suppressing toasts for background-refreshable actions follows the established enqueueMidturnMessage best-effort-and-silent precedent in the same file. The maintainer explicitly endorsed this direction and marked the issue welcome-pr. CHANGELOG: no direct reference, but the area (web-shell artifact panel UX) is clearly relevant.

Size: not applicable — no core module paths touched (packages/web-shell/client/hooks/ and packages/webui/src/daemon/session/ are not core).

Approach: the scope feels right — interface option + conditional in the action + call-site update in the hook is the minimum viable change. The transient-vs-hard-error distinction (only suppress network-class failures) is deliberately left as a fast-follow per the maintainer's suggestion, which keeps this PR focused. No unrelated changes or drive-by refactors.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:已观测到的 bug,有明确证据——#7427 报告 artifact 面板在瞬时连接抖动期间反复弹出 Load artifacts failed: Failed to fetch toast。triage bot 从源码确认了根因,维护者独立验证:loadArtifacts() 无条件走 dispatchActionError,总是触发 error 级 toast,即使是纯自动后台刷新也是如此。维护者背书了本 PR 实现的修复形状。

方向:对齐。抑制后台可刷新操作的 toast 遵循同文件中 enqueueMidturnMessage 的 best-effort-and-silent 先例。维护者明确背书了这个方向并标记了 welcome-pr

规模:不适用——未触及核心模块路径。

方案:范围合理——接口选项 + action 条件 + hook 调用点更新是最小可行变更。瞬态/硬错误区分按维护者建议留作快跟,保持本 PR 聚焦。无无关改动。

进入代码审查 🔍

Qwen Code · qwen3.7-max

Reviewed at 4440615cbc4ec4ab283339c862488d294fd2e748 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code review

Independent proposal (before reading the diff): given the title and motivation, I'd add an optional silent flag to loadArtifacts — when set, the catch block skips dispatchActionError's addNotice call and re-throws the raw error so the hook can still set its local error state. The hook passes silent: true since all three of its triggers (mount, prompt→idle, artifactsVersion) are automatic. This is exactly what the PR does.

Findings: no critical blockers, no AGENTS.md violations.

The implementation is clean and minimal — three production files changed (interface in types.ts, conditional in actions.ts, call-site in useSessionArtifacts.ts), each doing exactly one thing. A few things I verified:

  • The silent path correctly skips markNoticeDispatched along with addNotice. This is fine: _alreadyDispatched is only read by App.tsx's top-level error handlers to avoid double-toasting, but the hook catches the error locally — it never propagates there.
  • useSessionArtifacts is the sole production caller of loadArtifacts (confirmed via grep — the other hits are test mocks in ChatPane.test.tsx and App.test.tsx), so the silent: true at the call site covers every automatic refresh path.
  • The enqueueMidturnMessage precedent cited in the PR is accurate — it's explicitly "best-effort and silent" in the same file, never raising a user-facing notice.
  • The JSDoc on the interface is helpful and correctly scoped.

Tests are well-structured: the action-level tests verify both the silent path (no notice, still rejects) and the default path (notice preserved), and the hook-level test verifies silent: true is passed on every refresh call, failure lands in local error state, last-good artifacts survive, and loading settles.

Real-scenario testing

This is a browser-based web-shell feature — the artifact panel toast fires in the React UI when a background refresh fails. It can't be driven through tmux (no browser available in this environment). I verified what I could: the daemon starts and serves the web shell correctly with the PR code, and the unit tests comprehensively cover the behavior change.

$ npm run dev -- serve --port 19876

> @qwen-code/qwen-code@0.20.0 dev
> node scripts/dev.js serve --port 19876

qwen serve: daemon log → /home/github-runner/actions-runner-6/_work/_temp/qwen-home/debug/daemon/daemon.log
qwen serve: Web Shell UI served from .../packages/web-shell/dist
qwen serve listening on http://127.0.0.1:19876 (mode=http-bridge, workspace=...)
qwen serve: bound to workspace "..."
qwen serve: startup timing: processToListenMs=2620 runQwenServeToListenMs=1868
qwen serve: bearer auth disabled (loopback default). Set QWEN_SERVER_TOKEN to enable.
[DAEMON] deferred runtime: scheduling fallback start in 1000ms
[DAEMON] deferred runtime: fallback timer fired, starting
[DAEMON] ideEnvPresent=false primary=... secondary= daemon workspace roots initialized
qwen serve: session reaper started (interval 60000ms, idle threshold 1800000ms)
qwen serve: /acp WebSocket transport enabled on /acp

Unit tests (the definitive verification for this client-side behavior change):

$ cd packages/webui && npx vitest run src/daemon/session/actions.test.ts

 ✓ src/daemon/session/actions.test.ts (26 tests) 74ms

 Test Files  1 passed (1)
      Tests  26 passed (26)

$ cd packages/web-shell && npx vitest run client/hooks/useSessionArtifacts.test.tsx

 ✓ hooks/useSessionArtifacts.test.tsx (3 tests) 18ms

 Test Files  1 passed (1)
      Tests  3 passed (3)

Typecheck clean on both packages/webui and packages/web-shell. Build succeeds.

中文说明

代码审查

独立方案(未看 diff 前):根据标题和动机,我会给 loadArtifacts 加一个可选的 silent 标志——置位时 catch 跳过 dispatchActionErroraddNotice 调用并重抛原始错误,hook 仍可设置本地 error 状态。hook 传 silent: true,因为它的三个触发器(挂载、prompt→idle、artifactsVersion)都是自动的。PR 的实现与此完全一致。

发现: 无关键阻塞,无 AGENTS.md 违规。

实现干净且最小化——三个生产文件变更(types.ts 接口、actions.ts 条件、useSessionArtifacts.ts 调用点),每个只做一件事。验证了以下几点:

  • silent 路径正确跳过了 markNoticeDispatchedaddNotice。这没问题:_alreadyDispatched 只被 App.tsx 的顶层错误处理器读取以避免重复 toast,但 hook 在本地捕获了错误——不会传播到那里。
  • useSessionArtifactsloadArtifacts 的唯一生产调用方(grep 确认——其他命中是测试 mock),所以调用点的 silent: true 覆盖了所有自动刷新路径。
  • PR 引用的 enqueueMidturnMessage 先例准确——同文件中明确标注为 "best-effort and silent"。
  • 接口上的 JSDoc 有用且范围正确。

测试结构良好:action 级测试验证了 silent 路径(无 notice,仍拒绝)和默认路径(保留 notice),hook 级测试验证了每次刷新都传 silent: true、失败落入本地 error 状态、旧 artifacts 保留、loading 归位。

真实场景测试

这是浏览器端的 web-shell 功能——artifact 面板 toast 在后台刷新失败时由 React UI 触发。无法通过 tmux 驱动(此环境无浏览器)。已验证:daemon 使用 PR 代码正常启动并提供 web shell,单元测试全面覆盖了行为变更。

单元测试 29/29 通过。两个包的 typecheck 均干净。构建成功。

Qwen Code · qwen3.7-max

Reviewed at 4440615cbc4ec4ab283339c862488d294fd2e748 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 5/5 — clean across every stage; the maintainer endorsed this exact fix shape on the issue, the implementation matches it precisely, and the tests are solid.

This is a textbook small fix: the problem is real and well-documented (#7427, root cause confirmed from source, maintainer-verified), the solution is the minimum viable change (one interface option, one conditional, one call-site update), and it follows an established precedent in the same file (enqueueMidturnMessage's best-effort-and-silent philosophy). The transient-vs-hard-error refinement is correctly deferred to a fast-follow rather than bloating this PR.

My independent proposal before reading the diff was identical to what the PR does — I didn't find a simpler path it missed. The code is straightforward, every change is necessary, and the _alreadyDispatched interaction is correctly handled (the silent path skips it, which is fine because the hook catches the error locally and it never reaches App.tsx's top-level handlers). Tests cover both the silent and default paths at the action level, and the hook-level test verifies the full refresh cycle. 29/29 pass, typecheck clean, build succeeds.

If I had to maintain this in six months, I'd thank the author — clear comments, a well-documented interface, and a focused scope that's easy to reason about.

中文说明

置信度:5/5 —— 每个阶段都干净;维护者在 issue 上背书了正是这个修复形状,实现精确匹配,测试扎实。

这是一个教科书式的小修复:问题真实且有充分文档(#7427,根因从源码确认,维护者验证),方案是最小可行变更(一个接口选项、一个条件、一个调用点更新),遵循同文件中已有的先例(enqueueMidturnMessage 的 best-effort-and-silent 哲学)。瞬态/硬错误细化正确地推迟到快跟,而非膨胀本 PR。

我在看 diff 前的独立方案与 PR 完全一致——没找到更简路径。代码直白,每个改动都必要,_alreadyDispatched 交互正确处理。测试覆盖 action 级的 silent 和默认路径,hook 级测试验证完整刷新周期。29/29 通过,typecheck 干净,构建成功。

Qwen Code · qwen3.7-max

Reviewed at 4440615cbc4ec4ab283339c862488d294fd2e748 · re-run with @qwen-code /triage

@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.

LGTM, looks ready to ship. ✅

@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.

No issues found. LGTM! ✅

— qwen3.7-max via Qwen Code /review

@doudouOUC doudouOUC 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.

Reviewed — no blockers. Suggestions are inline.

— qwen3.7-max via Qwen Code /review

Comment on lines 1178 to 1180
const session = requireSessionForAction(
addNotice,
sessionRef.current,

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] requireSessionForAction sits before the try/catch block and calls dispatchActionError unconditionally when the session is gone — the silent check inside catch is never consulted for that error path. The hook's isConnected guard makes this unreachable today, but the type-level contract in types.ts ("silent: true suppresses the error-severity notice on failure") is incomplete: a future caller relying on it would still see a toast on session disconnection. The design precedent this PR cites (enqueueMidTurnMessage, line ~1008) avoids this by checking sessionRef.current directly and returning silently — it never calls requireSessionForAction. — Failure scenario: background refresh fires at the moment the session is torn down but React state is stale → requireSessionForAction toasts "Load artifacts failed" — the exact noise silent was designed to suppress.

Suggested change
const session = requireSessionForAction(
addNotice,
sessionRef.current,
if (options?.silent && !sessionRef.current) {
throw new Error('Daemon session is not connected');
}
const session = requireSessionForAction(
addNotice,
sessionRef.current,

— qwen3.7-max via Qwen Code /review

@gwinthis gwinthis 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.

Architecture Review — PR #7437

Verdict: ✅ Approve — correct silent-refresh pattern.

Design pattern: Silent background refresh

Automatic refreshes (mount, prompt→idle, artifactsVersion bump) pass { silent: true } to suppress the error toast. A transient fetch failure on an automatic poll is noise the user cannot act on.

Key properties:

  • Error still thrown: silent doesn't mean swallowed — the error propagates to the calling hook, which stores it in local state
  • Last-good data preserved: On refresh failure, artifacts state is NOT cleared — the UI shows stale-but-valid data instead of going blank
  • Explicit opt-out: The silent flag is per-call, not global — user-initiated refreshes still toast on failure

This mirrors the enqueueMidturnMessage best-effort-and-silent philosophy already established in the codebase.

@wenshao

wenshao commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Local verification — merge reference

I built and ran the real tests locally (Linux, Node v22.22.2, vitest v3.2.4, fresh worktrees). The PR is internally sound, but the bug it fixes (#7427) has already been fixed on main by #7477 (cd5e1973e, merged today), so this PR is now superseded and conflicts.

verification report

What holds up ✅

  • PR head is self-consistent: packages/webui actions.test.ts 26/26 and packages/web-shell useSessionArtifacts.test.tsx 3/3 pass at the PR head.
  • The new regression tests are effective: reverting only the source to the PR base (keeping the tests) fails suppresses…silent (webui) and passes silent… (web-shell) — exactly the "fails on unpatched" claim in the PR body.
  • The web-shell: artifact panel spams 'Load artifacts failed: Failed to fetch' on automatic refresh #7427 diagnosis was correct against the PR's base: on 22433b642, a failed background refresh did route through dispatchActionError and fire an error-severity toast.

Why it's superseded ⚠️

#7477 landed on main today and reworked both sides of this exact path:

current main (after #7477) this PR
actions.ts loadArtifacts no try/catch, no dispatchActionError → rejects raw error, no toast re-adds try/catch + dispatchActionError, gated by { silent }
useSessionArtifacts catch catch { setError(null) }swallows the error entirely, keeps last-good catch { setError(err.message) } — keeps error in local state

So on current main, the background-refresh toast is already gone — in fact suppressed more aggressively than this PR does. Running the PR's own tests against current main source proves it:

scenario C — PR tests vs current main

  • suppresses the failure notice for silent loadArtifactsPASSES on main (main is already silent).
  • keeps the failure notice for default loadArtifactsFAILS on main (main deleted that notice on purpose).

Merge status

Real conflict in packages/webui/src/daemon/session/actions.ts at loadArtifacts (confirmed by a clean test-merge into origin/main@434137b71; GitHub's CONFLICTING is accurate). The PR's only caller — useSessionArtifacts, which is fully automatic — would pass silent: true, so the restored non-silent toast branch is dead code. Net user-visible behavior after a conflict resolution that keeps the PR side = identical to main today, just with more code.

Recommendation

Verified on: origin/main @ 434137b71 · PR head @ 4440615cb (base 22433b642). Screenshots are real vitest runs from symlinked-node_modules worktrees.

🇨🇳 中文版(点击展开)

本地验证 — 合并参考

我在本地真实构建并运行了测试(Linux,Node v22.22.2,vitest v3.2.4,独立 worktree)。PR 本身自洽,但它修复的 #7427 已经被今天合入 main#7477cd5e1973e)抢先修掉了,因此本 PR 已被取代(superseded)且当前冲突。

成立的部分 ✅

  • PR head 自洽packages/webuiactions.test.ts 26/26packages/web-shelluseSessionArtifacts.test.tsx 3/3 在 PR head 全绿。
  • 新增回归测试有效:只把源码回退到 PR 基线(保留测试)后,suppresses…silent(webui)与 passes silent…(web-shell)失败——与 PR 描述里"未修复源上失败"一致。
  • web-shell: artifact panel spams 'Load artifacts failed: Failed to fetch' on automatic refresh #7427 的根因诊断正确(针对 PR 的基线):在 22433b642 上,后台刷新失败确实走 dispatchActionErrorerror 级 toast。

为何被取代 ⚠️

#7477 今天合入 main,对这条路径的两端都做了改写

当前 main#7477 之后) 本 PR
actions.ts loadArtifacts try/catch、无 dispatchActionError → 直接 reject 原始错误,不弹 toast 重新加回 try/catch + dispatchActionError,由 { silent } 控制
useSessionArtifacts catch catch { setError(null) }彻底吞掉错误、保留 last-good catch { setError(err.message) } — 把错误记进本地状态

也就是说当前 main 上后台刷新的 toast 已经消失——而且比本 PR 抑制得更彻底。把 PR 自己的测试跑在当前 main 源码上即可证明:

  • suppresses the failure notice for silent loadArtifacts → 在 main通过(main 本就静默)。
  • keeps the failure notice for default loadArtifacts → 在 main失败(main 有意删掉了该 notice)。

合并状态

packages/webui/src/daemon/session/actions.tsloadArtifacts 处存在真实冲突(在干净的 origin/main@434137b71 上试合并已确认;GitHub 的 CONFLICTING 属实)。PR 唯一调用方 useSessionArtifacts 完全是自动触发、会传 silent: true,因此被恢复的非 silent toast 分支是死代码。若按保留 PR 一侧来解冲突,最终用户可见行为与今天的 main 完全相同,只是代码更多。

建议

验证于:origin/main @ 434137b71 · PR head @ 4440615cb(base 22433b642)。截图为 symlink-node_modules worktree 中的真实 vitest 运行。

@wenshao wenshao closed this Jul 22, 2026
@zjunothing

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough local verification @wenshao — agreed, #7477 landing first supersedes this cleanly, and it's good to see the endorsed fix shape ship either way. Closing out my tracking on this one.

中文:感谢 wenshao 的完整本地验证——同意,#7477 先行合入后本 PR 被合理取代,背书的修复形状最终落地即是好结局。此条跟踪就此收尾。

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.

web-shell: artifact panel spams 'Load artifacts failed: Failed to fetch' on automatic refresh

5 participants