Repository navigation
Conversation
Adds a Share action to HTML artifact cards, next to Download and Open. It uploads the artifact and returns a link that can be sent to someone who cannot reach the workspace or the daemon. Sharing reuses the artifact publisher that already exists in core rather than introducing a second publishing path: the browser asks the daemon to publish a workspace file, and the daemon constructs OssPublisher and answers with the URL. Nothing is uploaded from the browser. Only the OSS backend is wired up here — the local backend produces an unshareable file:// URL, and the host backend runs a user-supplied command whose semantics need more design before a dialog can drive it. The dialog asks for an endpoint, a bucket, and an AccessKey pair, seeded from any existing artifact.oss settings so a configured user does not retype them. Nothing it collects is written to disk and no settings key is added: the values live in the running daemon and are forgotten when it exits, which the dialog states plainly. Credentials in the daemon environment remain the way to make one survive a restart, and are reported in the dialog when present. Nothing uploads until the user presses Upload. A workspace read returns at most 256 KB and rejects a larger request outright, so the route walks the file window by window instead of asking for the whole document at once, which failed on any page above that size. A public-read object ACL is overridden by a bucket that blocks public access, and the upload still reports success, so the daemon probes the returned URL and reports whether the link is actually reachable instead of handing over one that 403s. Co-Authored-By: Claude Opus 5 <[email protected]>
The OSS default domain answers HTML with a forced-download header, so a link built from it downloads the page instead of opening it. The dialog gains a public domain field, seeded from any configured value, whose hint says exactly that: leave it empty and browsers download, bind a custom domain to the bucket and the link opens. The upload still goes through the endpoint — only the returned link uses this domain. The credential and storage notes shrink to the smaller type size; they explain the defaults rather than needing to be read on the way to the button. Co-Authored-By: Claude Opus 5 <[email protected]>
# Conflicts: # packages/sdk-typescript/scripts/build.js # packages/web-shell/client/App.test.tsx # packages/web-shell/client/components/artifacts/ArtifactPanel.tsx # packages/web-shell/client/components/artifacts/TurnOutputs.tsx # packages/web-shell/client/e2e/utils/mockDaemon.ts
|
@qwen-code /takeover |
|
🔄 Takeover re-armed: the round counter starts a fresh window (previous rounds no longer count toward the cap); management continues. 中文说明🔄 已重新武装:轮次计数开启新窗口(此前轮次不再计入上限),托管继续。 |
doudouOUC
left a comment
There was a problem hiding this comment.
PR #10024 — Review Report
qwen review fetch-pr failed with getaddrinfo() thread failed to start — a Windows-specific git network issue preventing git fetch from GitHub. gh CLI works fine (the PR data and diff were obtained that way), but without a worktree, no build, typecheck, or test verification was possible. Findings below are based on manual diff review only, not verified against a live build.
Target: PR #10024 — feat(web-shell): share HTML artifacts through managed hosting
Author: qqqys
Head: b16bdcd9777c7d6ca823211178e247acc19caa11 (same head as superseded #9474)
Size: +9448/−49 across 32 files (5,067 production lines, 4,328 test lines)
State: OPEN, no existing reviews
Summary
This PR adds a managed provider flow for sharing HTML artifacts through Cloudflare, Vercel, and Netlify. The implementation is structurally sound — it extends the existing HostPublisher instead of building a parallel publisher, uses trusted-runtime gates, scrubs dangerous env vars before spawning provider CLIs, enforces HTTPS-only URLs, and provides 73 new tests with good coverage of cancellation, lock release, and security invariants.
No Critical blockers found. Three non-blocking observations below.
Findings
1. (Suggestion) — Dead explicit route registration shadows the parameterized one
The explicit /workspace/artifact/netlify/setup route is registered in both registerWorkspaceArtifactPublishRoutes and registerWorkspaceQualifiedArtifactPublishRoutes, followed by the parameterized /:provider/setup route that already dispatches netlify to the same handler. Express matches the first-registered route, so the parameterized route's netlify branch is unreachable. Either the explicit routes are redundant (if the parameterized one is the canonical path) or the parameterized route should exclude netlify from its provider check. Already noted in the triage — worth cleaning up before merge.
2. (Suggestion) — npm install --global installs to the user's global prefix, not "Qwen Code's managed tool location"
The PR description says provider CLIs are installed "into Qwen Code's managed tool location." The code uses npm install --global --cache <qwen-cache-dir> <package>. The --global flag installs to the user's global npm prefix (e.g. /usr/local/lib/node_modules on Linux), not to Qwen's managed location. The --cache flag only redirects the npm cache. This matters for two reasons:
- On machines where the global prefix is root-owned (common Linux setups), the install will fail with EACCES — the PR description's claim is misleading.
- For supply-chain auditing, the distinction between "installed under Qwen's directory" and "installed to the user's global tree" is significant.
The PR could either install to a managed directory (using --prefix instead of --global) or honestly describe the current behavior.
3. (Suggestion) — Machine-specific absolute paths in workspace settings are not portable
The Netlify connect flow persists process.execPath (e.g. /usr/local/bin/node) and the CLI entry path (e.g. /usr/local/lib/node_modules/netlify-cli/bin/run.js) into artifact.host.uploadCommand at workspace scope. If a user commits their workspace settings file, these paths will not resolve on any other machine. This is a documentation/awareness issue at minimum — the settings system should either warn about non-portable values or the route should reconstruct the path at runtime rather than storing it.
Existing observations from CI triage (still standing)
The CI triage bot (stages 1-3) already conducted a thorough review and raised three issues I'll confirm are still relevant:
- The three explicit route registrations are dead weight (confirmed — see finding 1 above).
- The
npm install --globalvs "managed tool location" discrepancy (confirmed — see finding 2 above). - Machine-specific absolute paths in workspace settings (confirmed — see finding 3 above).
The triage also deferred to the maintainer on the product-direction question (default-on public hosting with auto-installed third-party CLIs) and the size sign-off (5,067 production lines across core + six packages). These remain open questions that the code review cannot resolve.
What was not reviewed
- Build, typecheck, lint: The worktree could not be created (git fetch failure), so
npm run build && npm run typecheckwas not run. - Test execution: None of the 73 new tests were run against the working tree.
- Live provider behavior: All provider CLI interactions are mocked in tests, consistent with the triage findings.
Review complete: pr-10024 — COMMENT, not posted (0 Critical, 3 Suggestion)
|
@qwen-code /review |
|
Qwen Code review request accepted. Review is queued in workflow run. |
doudouOUC
left a comment
There was a problem hiding this comment.
Review of PR #10024 — feat(web-shell): share HTML artifacts through managed hosting
Reviewed at: bba81a37948a37b4998cfad7d2cbcf33594cbb62
Infrastructure note: git fetch is blocked on this Windows machine (getaddrinfo() thread failed to start), so no worktree, build, typecheck, or test verification was possible. Findings are based on the gh pr diff output only.
Context
This PR has already been reviewed by:
- doudouOUC — COMMENT (no Criticals, 3 Suggestions)
- CI triage stages 1-3 — deferred to maintainer on product direction (default-on public hosting with auto-installed third-party CLIs) and size (~5,067 production lines across core + six packages)
The head has moved from b16bdcd9777 (the commit reviewed by doudouOUC) to bba81a3794 (merge with upstream/main). The merge brought no changes to the artifact-share files — the diff delta is entirely upstream content (live-host package, goal checkpoint changes, channel TLS).
AutoFix round 1/100 is still running — no report posted yet.
Existing findings (confirmed standing)
All three Suggestions from the doudouOUC review remain valid at the current head:
-
Dead explicit route registrations — The explicit
/workspace/artifact/netlify/setuproutes in both route sets are registered before the parameterized/:provider/setuproute. Express matches the first-registered route, so the parameterized route's netlify branch is unreachable. The behavior is identical (both dispatch tohandleSetup), so this is dead code, not a bug. -
npm install --globalinstalls to the user's global prefix, not "Qwen Code's managed tool location" — The code usesnpm install --global --cache <qwen-cache-dir> <package>. The--globalflag writes to the user's global npm prefix, not to Qwen's managed directory. The--cacheflag only redirects the npm cache. On machines with root-owned global prefixes (common Linux), this will fail with EACCES. -
Machine-specific absolute paths in workspace settings — The Netlify connect flow persists
process.execPathand CLI entry paths intoartifact.host.uploadCommandat workspace scope. These paths are not portable if the workspace settings file is committed.
New observation: CI test failures
The test suite is failing on all three platforms at the current head:
| Platform | Status |
|---|---|
| Test (ubuntu-latest, Node 22.x) | fail |
| Test (windows-latest, Node 22.x) | fail |
| Test (macos-latest, Node 22.x) | fail |
The existing reviews did not capture this because the failures may have appeared after the merge with upstream/main. These could be pre-existing (the merge brought in a large upstream diff including a new packages/live-host package) or related to the PR changes. The failures should be investigated before merge.
Additional observations
- Cancellation architecture is well-designed. The
requestAbortScope+withCommandSignalpattern propagates request cancellation throughAbortSignal.anyto child processes, and thewithSetupLock/withPublishLockserialization uses promise chaining that self-heals on rejection. TheresetArtifactNetlifySetupStateForTestingexport correctly clears the module-level state. - Env var scrubbing is thorough.
providerEnvdeletesNODE_OPTIONS,NODE_PATH,LD_PRELOAD,DYLD_INSERT_LIBRARIES,DYLD_LIBRARY_PATH, and provider-specific vars (CLOUDFLARE_ACCOUNT_ID,VERCEL_ORG_ID,VERCEL_PROJECT_ID). - Publication record validation is defense-in-depth. URLs are validated for HTTPS-only, no embedded credentials, and length limits in both
publicationRecords()(settings read path) andvalidatePublishedUrl/parsePublishedUrl(publisher output path). - The
readWholeFilefunction correctly handles the >16 MB rejection path by checkingsizeByteson the first window read, bailing early without reading the full file. - Test coverage is comprehensive. The
windowReaderhelper andadaptTestRunnermock decorator are well-designed abstractions that make the 44 route tests (2,780 lines) readable and deterministic.
Verdict
No new Criticals or Suggestions beyond what the existing reviews already identified. The three Suggestions from doudouOUC remain standing. The CI test failures on all platforms should be investigated before merge. The product-direction and size questions remain deferred to the maintainer.
Review complete: pr-10024 — no new findings
|
🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下: Address-review summary — PR #10024 (same-run verification repair round)Round commit: Repaired rejection:
|
doudouOUC
left a comment
There was a problem hiding this comment.
PR #10024 — Review Report
Reviewed at: 1f6c187741f0eebe4b15f1839fee67daed48bad5 (current head, 2 new commits since prior review at bba81a37948)
Infrastructure note: git fetch is blocked on this Windows machine (getaddrinfo() thread failed to start), so no worktree, build, typecheck, or test verification was possible. Findings are based on gh pr diff output and raw file content from GitHub API.
Prior review status
The two new commits (73381f8a, 1f6c1877) have addressed 2 of 3 Suggestions from the doudouOUC review:
- ✅ Suggestion #1 (dead explicit routes): Fixed — the explicit
/workspace/artifact/netlify/setupand/workspaces/:workspace/artifact/netlify/setuproutes were removed from both route registrations. Only the parameterized/:provider/setuproute remains. - ✅ Suggestion #2 (npm --global prefix): Fixed —
readGlobalNpmPrefix()was removed. Thenpm install --globalcommand now includes--prefix artifactCliToolPrefix()which points toQwenDir/artifact-hosting/tools— Qwen's managed tool location. Tests updated to useTEST_ARTIFACT_TOOL_PREFIX. - ❌ Suggestion #3 (machine-specific absolute paths): Still standing —
netlifyUploadCommand()(line 1610) still storesprocess.execPathand the provider entry path inartifact.host.uploadCommandat workspace scope. These paths are not portable if the workspace settings file is committed.
New findings
Critical
C1. Global setup queue blocks all workspaces (workspace-artifact-publish.ts:85-86)
setupQueue is a module-level promise chain that serializes ALL provider setup operations across ALL providers and ALL workspaces:
let setupQueue: Promise<unknown> = Promise.resolve();
function withSetupLock<T>(operation: () => Promise<T>): Promise<T> {
const run = setupQueue.then(operation, operation);
setupQueue = run.then(() => undefined, () => undefined);
return run;
}If workspace A's Netlify login or sites:create hangs, every other workspace's provider setup is blocked until timeout. Compare with publishQueues (line 83), which is correctly scoped per-workspace via withPublishLock. Should be a Map<string, Promise<unknown>> keyed by workspaceCwd.
C2. Stale Netlify-only data attributes (ShareArtifactDialog.tsx)
The generic multi-provider dialog still carries data-share-netlify-progress, data-share-netlify-step, and data-share-netlify-action attributes. Any test or E2E selector relying on these to distinguish Cloudflare/Vercel from Netlify will fire on the wrong provider. Should be renamed to data-share-provider-*.
High
H1. Netlify popup blocker undetected (ShareArtifactDialog.tsx)
The Netlify authorization path opens a window via window.open('', ...) but never checks if the result is null (popup blocked). The popup-blocked error message is only shown for non-Netlify providers. A blocked Netlify auth window would leave the user stuck on "Authorization pending" with no error.
H2. Wrong ARIA role for provider selector (ShareArtifactDialog.tsx)
Provider selection buttons use aria-pressed (toggle button semantics) but should use role="radiogroup" / role="radio" with aria-checked. Screen readers will announce "pressed" state, which is confusing for a single-selection list.
H3. deployDirectory uses fragile absolute path heuristic for Cloudflare/Vercel (workspace-artifact-publish.ts:~2480)
For Cloudflare and Vercel, deployDirectory() picks the first absolute path from the argument array as the deployment directory:
const candidates = provider === 'netlify'
? optionValues(args, '--dir')
: args.filter((arg) => path.isAbsolute(arg));If any future parameter value (e.g., --project-name or --branch) happens to be an absolute path, the function silently picks the wrong directory. Netlify correctly uses optionValues(args, '--dir') — Cloudflare/Vercel should follow the same pattern.
Medium
M1. defaultCheckPublicUrl follows redirects without limit (workspace-artifact-publish.ts:~2610)
fetch(url, { redirect: 'follow' }) has no maxRedirects cap. The 2-second timeout mitigates infinite loops, but adding maxRedirects: 5 is cheap defense-in-depth against an SSRF vector if the URL from CLI output is attacker-controlled.
M2. Publish catch chain swallows original error (workspace-artifact-publish.ts:~2950)
.catch(() => {
abortScope.signal.throwIfAborted();
assertRuntimeOpen(runtime);
throw new SetupError(502, `${selectedProvider}_publish_failed`, ...);
});The original error variable is discarded and replaced with a generic "Try again" message. Should log or attach as cause.
M3. Copied URL feedback never clears (ShareArtifactDialog.tsx)
copiedUrl state is set after copy but never cleared. The copy button permanently shows a checkmark icon after the first copy, which is misleading as the user navigates the dialog.
Low
L1. loginTickets Map not cleaned up on workspace lifecycle — Expired tickets only purged on access. Minor memory leak in long-running daemon sessions.
L2. providerEnv overrides effectiveEnv's PATH with process.env.PATH — Behavior is equivalent in practice, but the construction is confusing.
L3. installProvider runs with full process.env — The npm install command for provider CLIs uses the unbounded process environment, not the scrubbed providerEnv. Workspace-effective npm_config_* variables could redirect the npm registry. Mitigated by hardcoded package names.
CI status
| Platform | Status |
|---|---|
| Test (ubuntu-latest, Node 22.x) | FAILURE |
| Test (windows-latest, Node 22.x) | IN_PROGRESS |
| Test (macos-latest, Node 22.x) | QUEUED |
The Ubuntu test failure (confirmed by prior review) persists. The review-pr workflow is also in progress (likely the AutoFix round).
Verdict
2 Criticals, 3 Highs, 3 Mediums, 3 Lows found. C1 (global setup queue) and C2 (stale Netlify data attributes) should be addressed before merge. The standing Suggestion #3 from the prior review (machine-specific paths in settings) also remains open.
Review complete: pr-10024 — COMMENT
|
🤖 AutoFix ran out of time before finishing (timeout (2700000ms)) (attempt 2/100) — it will retry on the next scan.
See the Qwen Autofix agent step logs for model/tool output. 中文说明🤖 AutoFix 在完成前耗尽了时间(timeout (2700000ms))(第 2/100 次尝试)—— 将在下次扫描时重试。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/32911202808 🧠 Handled by Qwen Code · model/模型 |
|
🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
|
🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
|
🤖 Addressed the latest review feedback (round 5/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 5/100 轮)。改动内容与我反驳保留之处如下: Address-review summary — PR #10024 (same-run verification repair)This round ran as a same-run verification repair under the workflow's budget warning: the rejected commit is preserved unchanged, and one follow-up commit fixes exactly the deterministic rejection — DiagnosisThe gate's Evidence trail:
Change this round
Witness/mutation evidence: the very run that reproduced the defect (pre-fix tree, identical otherwise — the working-tree diff is exactly these 3 lines) failed 9/10 tests with the gate's exact Feedback not acted on this roundEverything below stays open with a per-thread reply (
No conflict resolution was needed ( VerificationAll commands actually run this round (gate-shaped suites run under
中文说明处理评审意见总结 — PR #10024(同轮验证修复)本轮以同轮验证修复模式运行,且处于工作流的预算警告之下:被拒绝的提交原样保留,仅追加一次后续提交修复确定性拒绝本身—— 诊断门禁的 证据链:
本轮改动
见证/变异证据:复现缺陷的那次运行(修复前的树,其余完全一致——工作区 diff 恰好就是这 3 行)以门禁完全相同的 本轮未处理的反馈以下全部保持开放,并在各自线程中回复(
本轮无需解决冲突( 验证本轮实际运行的全部命令(门禁形态套件均在
Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。 🧠 Handled by Qwen Code · model/模型 |
|
🤖 AutoFix stopped: this counting window now contains 3 agent time-budget exhaustions (pushed rounds in between included; this round itself may have failed differently). That is 3 full agent runs that pushed nothing. A human should split or reduce the PR (or raise the agent time budget AND its step backstop together), then comment
See the Qwen Autofix agent step logs for model/tool output. 中文说明🤖 AutoFix 已停止:当前计数窗口内已累计 3 次时间预算耗尽(含其间推送过的轮次;本轮本身可能以别的方式失败)。即 3 次完整 agent 运行没有推送任何内容。应由人工拆分或缩减该 PR(或同时提高 agent 时间预算与其步骤兜底),然后评论 Run log: https://github.com/QwenLM/qwen-code/actions/runs/33059773196 🧠 Handled by Qwen Code · model/模型 |
|
⏸️ Takeover paused: this PR reached its round cap (100/100). Comment 中文说明⏸️ 托管已暂停:本 PR 达到轮次上限(100/100)。评论 |
|
@qwen-code /takeover |
|
🔄 Takeover re-armed: the round counter starts a fresh window (previous rounds no longer count toward the cap); management continues. 中文说明🔄 已重新武装:轮次计数开启新窗口(此前轮次不再计入上限),托管继续。 |
|
🤖 AutoFix updated a stale base — the fix did not pass verification, but this PR was behind Address-review round summary — PR #10024 (same-run verification repair)This is a same-run verification repair round. The previous commit The rejection and its fixRoot cause (reproduced, not guessed). The test's fake Fix (commit Why it was not pushed: Note: the base has since been auto-updated; the verdict below predates that update, and the next round's re-measurement may charge the round. tests failed in packages/cli 中文说明🤖 AutoFix 更新了一个过期的 base —— 修复未通过验证,但本 PR 落后于 验证门的拒绝原因与日志证据见上方英文部分(gate-rejection 不翻译)。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/33097756164 🧠 Handled by Qwen Code · model/模型 |
Round-6 findings: - Drop the duplicate `getToolRegistry` this branch added to the telemetry swap test's config literal. TS1117 broke the packages/core build, which blocked every dependent workspace's build and all test suites. - Detect the daemon's own Netlify command by its entry path, not by the interpreter's basename. `process.execPath` is whatever runs the daemon (`node-22`, Debian `nodejs`, a shim), so the daemon could not re-parse the command it had just written and setup 500'd after creating the site. - Keep the scheme the Vercel CLI already puts on `latestProductionUrl` instead of emitting `https://https://...`. - Strip Netlify password/SSO protection only for a site this flow created, tracked by a new `artifact.share.netlify.dedicatedSiteId`. `siteId` alone is also persisted for an adopted user-linked site, so the first publish removed that site's protection silently and without consent. Standing findings from earlier rounds: - Boundary-check the adoption branch, not just creation: netlify-cli resolves the link by walking up from the workspace cwd, so a nested workspace adopted and published into the parent repository's site. - Distinguish "no such site" from "the API could not be reached" in `readSiteRecord`; a transient failure dropped a ready workspace back to the setup stage and made its configured site look non-dedicated. - Accept any record `getSite` returns for the configured identifier, so a site name or subdomain alias is no longer rejected as unconfigured. - Treat absent `sso_login`/`has_password` as unprotected rather than unknown; a public site failed with `netlify_public_access_failed`. - Refuse to overwrite a user-authored `artifact.host.uploadCommand`. - Refuse to adopt a same-named Vercel project from another scope once a project id has been persisted. - Give the authorization poll its own AbortController: sharing one slot with setup and publish made them abort each other, stranding the dialog in a permanent polling state or killing an in-flight publish. - Stop reading `window.open(..., 'noopener')`'s null return as a blocked popup — it is null per spec either way, so authorization was reported blocked on success and the poll it depends on was suppressed. Claude-Session: https://claude.ai/code/session_018dYE4LwSMeMPFchXk5UBdM
|
Round-6 pass — 15 of the 19 open Criticals are closed in de76d60, and 7d2f844 merges upstream/main (two conflicts: the sdk bundle budget, taking main's 215KB, and the Each fix is answered in its own thread with the test that pins it. Every one was mutation-checked: reverting the fix turns the named test red. Suites: route 69/69, web-shell dialogs 302/302, telemetry swap 10/10, AppContainer 167/167; Four findings are deliberately left open — they are architectural rather than local, and each would change the feature's trust model in a way that wants its own review rather than being folded into this pass:
I would rather these were tracked as follow-ups than half-fixed here. Happy to take any of them in a separate PR — say which. |
|
🤖 AutoFix ran out of time before finishing (timeout (3600000ms)) (attempt 2/100) — it will retry on the next scan.
See the Qwen Autofix agent step logs for model/tool output. 中文说明🤖 AutoFix 在完成前耗尽了时间(timeout (3600000ms))(第 2/100 次尝试)—— 将在下次扫描时重试。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/33128178614 🧠 Handled by Qwen Code · model/模型 |
|
🤖 AutoFix updated a stale base — the fix did not pass verification, but this PR was behind Round 9 — PR #10024 same-run verification repairThe previous commit ( Root cause (evidence-based, reproduced locally)The test spawns a fake Why it was not pushed: Note: the base has since been auto-updated; the verdict below predates that update, and the next round's re-measurement may charge the round. tests failed in packages/cli 中文说明🤖 AutoFix 更新了一个过期的 base —— 修复未通过验证,但本 PR 落后于 验证门的拒绝原因与日志证据见上方英文部分(gate-rejection 不翻译)。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/33159300648 🧠 Handled by Qwen Code · model/模型 |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round report — no code changes this roundHead evaluated: Why no changesThis round's blocking item was the rejected verification gate from the previous attempt ("tests failed in packages/cli" — three failures in
No defect attributable to this PR's code was found, so there was nothing to fix and no commit this round. Environment note (local-only failures, proven infrastructural)Running the suite from this agent's shell initially produced failures that do not exist in CI. Three controlled experiments identified the causes:
These are sandbox/agent-environment artifacts, not PR defects — recorded here per the stop-rule evidence requirement rather than in Remaining review findingsPer the budget warning (the previous round exhausted its time budget), this round did not retry the full finding batch. All unresolved inline findings are answered in their own threads via VerificationCommands actually run this round, at head
No mutation probes this round: the round adds no guards, branches, or behavior changes. 中文说明Autofix 轮次报告 — 本轮无代码改动评估的分支头: 为什么没有改动本轮的阻断项是上一次尝试被拒的验证门禁("tests failed in packages/cli" —
未发现可归因于本 PR 代码的缺陷,因此本轮无修复、无提交。 环境说明(仅本地出现的失败,已证实为基础设施问题)在本代理的 shell 中运行测试套件最初出现了一些 CI 中不存在的失败。三组对照实验确定了原因:
这些是沙箱/代理环境的产物,不是 PR 缺陷——按停止规则的证据要求记录于此,而不是写入 剩余评审发现按预算警告(上一轮耗尽了时间预算),本轮未重试完整的发现批次。所有未解决的行内发现均已通过 验证本轮在分支头
本轮无变异探针:本轮未新增任何守卫、分支或行为改动。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix review round — no code changes (PR #10024)Head evaluated: What was triagedThe workflow-prepared feedback for this round contains no new reviews, inline comments, or issue-level comments since the last evaluation (2026-08-28T17:55:00Z). The only listed items are 86 check entries, all reading Why the CANCELLED entries are not actionableEach claim below was checked against the full check-run history (1,749 runs) rather than assumed:
These steps belong to the autofix loop's own workflow area, which this PR neither touches nor may modify; in any case no defect is evidenced. There is nothing a code change could address here. ConclusionThere was no actionable review feedback and no code-attributable check failure this round, so no changes were made and nothing was committed. The previous round already evaluated this exact head, confirmed by execution that the earlier verification-gate rejection no longer reproduces, and answered every open inline thread (see the round report comment of 2026-08-28T19:10Z). 中文说明Autofix 复审轮次 — 无代码变更(PR #10024)评估的 head: 本轮分诊内容本轮工作流准备的反馈中,自上次评估(2026-08-28T17:55:00Z)以来没有任何新的 review、行内评论或 issue 级评论。唯一列出的条目是 86 条检查记录,全部为 为什么这些 CANCELLED 条目不可处理以下每一项结论都是对照完整的检查运行历史(共 1,749 次运行)核实出来的,而非假设:
这些步骤属于 autofix 循环自身的工作流领域,本 PR 既未触及也不允许修改;而且无论如何都没有证据表明存在缺陷。这里没有任何可以通过代码变更解决的问题。 结论本轮没有可处理的评审反馈,也没有可归因于代码的检查失败,因此未做任何变更、未提交任何内容。上一轮已经评估过完全相同的 head,通过实际执行确认此前的验证门禁拒绝不再复现,并回复了所有未关闭的行内讨论串(见 2026-08-28T19:10Z 的轮次报告评论)。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
@qwen-code /triage |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix review round — no action takenNo new actionable feedback arrived for this round, so no code changes were made and nothing was committed. Feedback triage
Round state
The branch head remains unchanged at the last pushed commit. The pending sandboxed verification run will report its own outcome as a later comment; nothing in this round's feedback requires a code change. 中文说明Autofix 审查轮次 —— 未采取任何操作本轮没有收到新的可处理反馈,因此未做任何代码修改,也没有提交任何内容。 反馈分类
本轮状态
分支 head 保持不变,仍停留在上次推送的提交。正在进行的沙箱验证运行稍后会以新评论的形式报告其结果;本轮反馈中没有任何内容需要代码修改。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
🤖 AutoFix ran out of time before finishing (timeout (3600000ms)) (attempt 4/100) — it will retry on the next scan.
See the Qwen Autofix agent step logs for model/tool output. 中文说明🤖 AutoFix 在完成前耗尽了时间(timeout (3600000ms))(第 4/100 次尝试)—— 将在下次扫描时重试。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/33237036539 🧠 Handled by Qwen Code · model/模型 |
|
🤖 AutoFix hit a verification-gate error before reaching a verdict (attempt 5/100) — it will retry on the next scan. Autofix review round — PR #10024Feedback addressed: issue-level comment Findings1. Cloudflare/Vercel authorization cannot be completed from a remote browser (high) — addressed via the dialog copy remedy. The report offered two remedies: parse the authorization URL/device code out of the provider CLI stream and surface it like Netlify's **2. Process-wide setup lock froze every 中文说明🤖 AutoFix 在得出结论之前遇到验证门错误(第 5/100 次尝试)—— 将在下次扫描时重试。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/33244388739 🧠 Handled by Qwen Code · model/模型 |
|
🤖 AutoFix hit a verification-gate error before reaching a verdict (attempt 6/100) — it will retry on the next scan. Round summary — PR #10024 artifact sharing (maintainer runtime-verification feedback)All five findings from @wenshao's local runtime verification comment are addressed in one commit ( Findings and dispositions1. (high) Cloudflare/Vercel authorization cannot be completed from a browser that is not on the daemon host — Acted (the reviewer's minimal option). 中文说明🤖 AutoFix 在得出结论之前遇到验证门错误(第 6/100 次尝试)—— 将在下次扫描时重试。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/33251275125 🧠 Handled by Qwen Code · model/模型 |








What this PR does
Adds managed public sharing for available HTML artifacts in Web Shell. The Share action opens a guided provider flow with Cloudflare first, Vercel second, and Netlify third; each provider exposes the same Prepare → Authorize → Connect → Ready progress, a compact default view, and an expandable details section for users who want to see which official CLI, dedicated project, and workspace metadata are involved.
Qwen Code installs a missing provider CLI into its own managed tool location, opens the provider's browser authorization flow, connects a dedicated public project, and persists only the identifiers needed to reuse that project. Provider credentials and tokens remain under the official CLI's management and are not written to workspace settings. Setup and publishing are cancellable from the dialog, including while an authorization command, upload, public-link probe, or retry delay is in progress.
The feature is enabled by default and can be turned off under Settings → Features. When disabled, the Share action is hidden and daemon routes reject setup or publishing. Publication metadata includes the provider target, artifact identity, content hash, link, and time; unchanged content reuses the existing link instead of deploying again, while the dialog offers an explicit republish action. A new or changed artifact is deployed and the returned link is checked with bounded retries before the UI presents it as publicly accessible.
All daemon routes stay within the resolved, trusted workspace runtime. Web Shell actions use the selected workspace's qualified client rather than falling back to the process-primary workspace, and filesystem failures retain their structured status and remediation hint. Cloudflare and Vercel project creation tolerate provider-side eventual consistency and reuse a pending project name on retry, avoiding duplicate projects after a late CLI error.
Why it's needed
An HTML artifact is currently useful only to someone who can reach the daemon that produced it, so sharing it means downloading and manually uploading the file elsewhere. This change turns that manual workflow into one clear action while keeping hosting ownership with the user's provider account, making the public nature of the result explicit, and avoiding exposure of CLI credentials to the browser or workspace configuration.
Reviewer Test Plan
How to verify
Open a session containing an available HTML artifact and confirm its card offers Share beside Download and Open. Confirm non-HTML and unavailable artifacts do not expose Share. In Settings → Features, turn Artifact sharing off and confirm the action disappears; restore it and confirm the action returns.
Open Share and confirm Cloudflare is selected by default, followed by Vercel and Netlify. For an unconfigured provider, start setup and confirm the official browser authorization flow opens, the progress moves through authorization and project connection, and Stop immediately returns control without leaving the dialog or a workspace-wide setup/publish lock stuck. Expand Details and confirm it describes the CLI, dedicated target, saved identifiers, automatic installation boundary, and credential-storage boundary.
After a provider is ready, publish an HTML artifact and confirm the returned HTTPS link opens without daemon access. Reopen Share for unchanged content and confirm it shows the existing link with Open current and Republish instead of silently deploying again. Change the file and confirm the state becomes updated and offers Publish new version. If the provider accepts the deploy but the URL does not become public, confirm the dialog reports a provider-specific failure rather than presenting the link as successful.
Local verification on the exact submitted head:
The Netlify probe destroyed a request while the fake CLI login was deliberately left pending; the child signal aborted and a second setup request completed within one second, confirming cancellation releases the independent Netlify setup lock. The selected-workspace action path was also independently checked against the exact submitted head.
Evidence (Before & After)
Before — HTML artifacts offered Download and Open only:
After — the artifact card exposes Share:
Current managed-provider dialog captured from the submitted head on macOS:
Tested on
Environment (optional)
macOS local Web Shell served from the submitted source with real persisted provider status for the screenshot; Vitest and repository build/type/lint commands used the workspace toolchain. Provider CLI behavior and cancellation paths are deterministic in tests; no new live deployment was created solely for this review pass.
Risk & Scope
Linked Issues
None.
中文说明
这个 PR 做了什么
为 Web Shell 中状态可用的 HTML Artifact 增加托管式公开分享。点击「分享」会打开统一的平台引导流程,顺序是 Cloudflare、Vercel、Netlify;每个平台都使用「准备 → 授权 → 连接 → 可用」进度,默认界面保持简洁,同时提供可展开的「详细信息」,让需要了解底层过程的用户看到所用官方 CLI、专用项目和工作区保存信息。
Qwen Code 会把缺失的平台 CLI 安装到自身管理的工具目录,打开平台官方的浏览器授权流程,连接一个专用公开项目,并且只持久化复用该项目所需的标识。平台凭据和 token 仍由官方 CLI 管理,不会写入工作区设置。配置与发布都可以在对话框中中止,包括正在执行授权命令、上传、公开链接探测或重试等待时。
该功能默认开启,可在「设置 → 功能」中关闭。关闭后,「分享」操作会隐藏,daemon 路由也会拒绝配置或发布。发布记录包含平台目标、Artifact 标识、内容哈希、链接和时间;内容未变时会复用已有链接,不会静默重复部署,同时对话框提供显式「重新发布」。Artifact 新增或内容变化后才会重新部署,并在把链接展示为公开可用前进行有界重试检查。
所有 daemon 路由都限制在解析出的受信工作区运行时中。Web Shell 操作通过当前选中工作区的 qualified client 执行,不会回退到进程主工作区;文件系统错误会保留结构化状态和修复提示。Cloudflare 与 Vercel 的项目创建流程能够容忍平台侧最终一致性,并在重试时复用待确认的项目名,避免 CLI 延迟报错后重复创建项目。
为什么需要它
目前 HTML Artifact 只有能访问生成它的 daemon 的人才能查看,因此分享给别人时必须先下载再手动上传。这个改动把手工流程收敛为一个清晰动作,同时让托管所有权继续留在用户自己的平台账号中,明确提示结果会公开访问,并避免把 CLI 凭据暴露给浏览器或工作区配置。
审阅者测试计划
如何验证
打开一个包含可用 HTML Artifact 的会话,确认卡片在「下载」「打开」旁提供「分享」。确认非 HTML 或状态不可用的 Artifact 不显示「分享」。进入「设置 → 功能」,关闭「Artifact 分享」后确认操作消失;重新开启后确认操作恢复。
打开「分享」,确认默认选择 Cloudflare,后面依次是 Vercel 和 Netlify。对未配置平台开始配置,确认会打开官方浏览器授权流程,进度经过授权和项目连接;点击「中止」应立即恢复控制,不会卡住对话框,也不会残留工作区级配置/发布锁。展开「详细信息」,确认其中说明 CLI、专用发布目标、保存的标识、自动安装边界和凭据存储边界。
平台就绪后发布 HTML Artifact,确认返回的 HTTPS 链接在无法访问 daemon 的环境下也能打开。对未变化的内容重新打开「分享」,确认界面显示已有链接,并提供「打开当前版本」和「重新发布」,而不是直接重复部署。修改文件后,确认状态变为「已更新」并提供「发布新版本」。如果平台接受部署但 URL 始终未公开,确认对话框报告平台专属错误,不把该链接展示为成功结果。
在精确提交 head 上完成的本地验证:
Netlify 探针让假 CLI 登录保持挂起并销毁客户端请求;子进程信号随即中止,第二个配置请求在一秒内完成,证明取消会释放独立的 Netlify 配置锁。当前选中工作区的 action 路径也在精确提交 head 上做了独立复核。
证据(改动前后)
改动前——HTML Artifact 只有「下载」和「打开」:
改动后——Artifact 卡片提供「分享」:
在 macOS 上从当前提交 head 捕获的托管平台对话框:
测试环境
运行环境(可选)
macOS 本地 Web Shell 由当前提交源码启动,截图使用真实保存的平台状态;Vitest 与仓库 build/type/lint 命令使用工作区工具链。本轮审阅没有为了截图额外创建新的线上部署,平台 CLI 行为和取消路径由确定性测试覆盖。
风险与范围
关联 Issue
无。