Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f1a6fc4
feat(web-shell): share HTML artifacts through the OSS publisher
qqqys Aug 19, 2026
03f9870
feat(web-shell): let the share dialog set a public domain for the link
qqqys Aug 19, 2026
fa917a2
feat(web-shell): add managed artifact sharing
qqqys Aug 25, 2026
34173f1
Merge remote-tracking branch 'upstream/main' into feat/artifact-share
qqqys Aug 25, 2026
3063685
fix(cli): update artifact settings import after main merge
qqqys Aug 25, 2026
b16bdcd
fix(webui): scope artifact sharing to active workspace
qqqys Aug 25, 2026
bba81a3
Merge remote-tracking branch 'upstream/main' into feat/artifact-share
Aug 25, 2026
73381f8
fix(cli): fix artifact sharing test failures and review findings (#10…
qwen-code-dev-bot Aug 25, 2026
1f6c187
fix(cli): complete AppContainer SubagentManager mock for AgentTool st…
qwen-code-dev-bot Aug 25, 2026
e34a6cf
Merge branch 'main' into feat/artifact-share
qwen-code-dev-bot Aug 26, 2026
a0035e3
Merge branch 'main' into feat/artifact-share
qqqys Aug 26, 2026
09747eb
Merge branch 'main' into feat/artifact-share
qwen-code-dev-bot Aug 26, 2026
4ab71b5
Merge branch 'main' into feat/artifact-share
qwen-code-dev-bot Aug 26, 2026
f4eab1b
fix(cli): harden artifact sharing env scrubbing and Netlify setup (#1…
qwen-code-dev-bot Aug 27, 2026
74e1489
fix(core): repair telemetry-swap test mock missing getToolRegistry (#…
qwen-code-dev-bot Aug 27, 2026
7330ba5
Merge branch 'main' into feat/artifact-share
qwen-code-dev-bot Aug 27, 2026
b2f4c82
Merge remote-tracking branch 'upstream/main' into feat/artifact-share
qqqys Aug 28, 2026
de76d60
fix(web-shell): close the round-6 review findings on artifact sharing
qqqys Aug 28, 2026
7d2f844
Merge remote-tracking branch 'upstream/main' into feat/artifact-share
qqqys Aug 28, 2026
8f3ccb8
Merge branch 'main' into feat/artifact-share
qwen-code-dev-bot Aug 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/cli/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2316,6 +2316,8 @@ export async function loadCliConfig(
? {
uploadCommand: settings.artifact?.host?.uploadCommand ?? '',
urlTemplate: settings.artifact?.host?.urlTemplate ?? '',
urlFromCommandOutput:
settings.artifact?.host?.urlFromCommandOutput ?? false,
keyPrefix: settings.artifact?.host?.keyPrefix,
}
: undefined,
Expand Down
149 changes: 148 additions & 1 deletion packages/cli/src/config/settingsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3897,7 +3897,7 @@ const SETTINGS_SCHEMA = {
requiresRestart: true,
default: '',
description:
'Command that uploads the artifact, run with execFile (no shell). {file} = local HTML path, {key} = remote object key. e.g. "aws s3 cp {file} s3://bucket/{key} --content-type text/html".',
'Command run with execFile (no shell). Template mode uses {file} and {key}; command-output mode uses {dir} for the temporary static site directory.',
showInDialog: false,
},
urlTemplate: {
Expand All @@ -3910,6 +3910,16 @@ const SETTINGS_SCHEMA = {
'Shareable URL template; {key} is substituted. e.g. "https://bucket.example.com/{key}".',
showInDialog: false,
},
urlFromCommandOutput: {
type: 'boolean',
label: 'URL From Command Output',
category: 'Experimental',
requiresRestart: true,
default: false,
description:
'Deploy the temporary site directory through uploadCommand and read its public HTTPS URL from stdout. The command must include {dir}; stdout may be a URL or JSON containing url, ssl_url, deploy_url, deploy_ssl_url, or deployUrl.',
showInDialog: false,
},
keyPrefix: {
type: 'string',
label: 'Key Prefix',
Expand All @@ -3922,6 +3932,143 @@ const SETTINGS_SCHEMA = {
},
},
},
share: {
type: 'object',
label: 'Artifact Sharing',
Comment on lines +3935 to +3937

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.

Needs a maintainer's decision — not settled here. Restricting artifact publish-target state from workspace scope requires choosing where daemon-managed share state is persisted: enforce a workspace-scope restriction, or move the state to user-scope/daemon-owned storage. Which direction do you want? The thread stays open until answered.

中文说明

需要维护者决策——此处不做决定。限制 artifact 发布目标状态不得来自工作区作用域,需要先选择守护进程托管的共享状态持久化到哪里:强制工作区作用域限制,还是把状态移到用户作用域/守护进程自有存储。请选择方向?线程保持开放直至有答复。

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.

Needs a maintainer's decision — not settled here. Restricting artifact publish-target state from workspace scope requires choosing where daemon-managed share state is persisted: enforce a workspace-scope restriction, or move the state to user-scope/daemon-owned storage. Which direction do you want? The thread stays open until answered.

中文说明

需要维护者决策——此处不做决定。限制 artifact 发布目标状态不得来自工作区作用域,需要先选择守护进程托管的共享状态持久化到哪里:强制工作区作用域限制,还是把状态移到用户作用域/守护进程自有存储。请选择方向?线程保持开放直至有答复。

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.

Needs a maintainer's decision — not settled here. Restricting artifact publish-target state from workspace scope requires choosing where daemon-managed share state is persisted: enforce a workspace-scope restriction, or move the state to user-scope/daemon-owned storage. Which direction do you want? The thread stays open until answered.

中文说明

需要维护者决策——此处不做决定。限制 artifact 发布目标状态不得来自工作区作用域,需要先选择守护进程托管的共享状态持久化到哪里:强制工作区作用域限制,还是把状态移到用户作用域/守护进程自有存储。请选择方向?线程保持开放直至有答复。

Comment on lines +3935 to +3937

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.

Deferred — superseded by the re-post of this finding at later heads (round-6 thread 3876242254, round-7 3879310211, round-8 3882827665); the current status is recorded there. The maintainer's round-6 summary additionally defers this class (workspace-scope publish-target trust) to the policy owner as a follow-up. This round was scoped to the rejected verification gate only.

中文说明

延后——该发现已在更晚的 head 上重新发布(第 6 轮线程 3876242254、第 7 轮 3879310211、第 8 轮 3882827665),当前状态记录于相应线程。维护者的第 6 轮总结还把该类问题(工作区作用域的发布目标信任)交给策略负责人作为后续跟进。本轮只处理被拒的验证门禁。

Comment on lines +3935 to +3937

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.

Deferred by maintainer decision (round-6 summary comment): workspace-scope publish-target trust is a policy decision for the scope-policy owner, tracked as a follow-up. Re-posted at round 8 (3882827665) with the connectVercel pendingName entrance. This round was scoped to the rejected verification gate only.

中文说明

按维护者决定延后(第 6 轮总结评论):工作区作用域的发布目标信任是作用域策略负责人的策略决定,作为后续跟进。已在第 8 轮(3882827665)连同 connectVercel pendingName 入口重新发布。本轮只处理被拒的验证门禁。

Comment on lines +3935 to +3937

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.

Deferred by maintainer decision (round-6 summary comment): workspace-scope publish-target trust is a policy decision for the scope-policy owner, tracked as a follow-up. Still open at the current head (8f3ccb8). This round was scoped to the rejected verification gate only, which no longer reproduces (see the round report).

中文说明

按维护者决定延后(第 6 轮总结评论):工作区作用域的发布目标信任是作用域策略负责人的策略决定,作为后续跟进。在当前头(8f3ccb8ae6)仍开放。本轮只处理被拒的验证门禁,该失败已无法复现(见本轮报告)。

category: 'Experimental',
requiresRestart: false,
default: {},
description:
'Daemon-managed targets used by the Web Shell artifact sharing flow.',
showInDialog: false,
properties: {
enabled: {
type: 'boolean',
label: 'Artifact Sharing',
category: 'Artifacts',
requiresRestart: false,
default: true,
description:
'Show the Share action for workspace HTML artifacts and allow Web Shell publishing through configured hosting providers.',
showInDialog: true,
},
publications: {
type: 'array',
label: 'Artifact Publication History',
category: 'Experimental',
requiresRestart: false,
default: [],
description:
'Latest public deployment metadata used to avoid redeploying unchanged artifacts.',
showInDialog: false,
items: {
type: 'object',
additionalProperties: false,
properties: {
provider: {
type: 'string',
enum: ['cloudflare', 'vercel', 'netlify'],
required: true,
},
targetId: { type: 'string', required: true },
artifactId: { type: 'string', required: true },
contentHash: { type: 'string', required: true },
publishedId: { type: 'string', required: true },
url: { type: 'string', required: true },
publishedAt: { type: 'string', required: true },
},
},
},
cloudflare: {
type: 'object',
label: 'Cloudflare Pages',
category: 'Experimental',
requiresRestart: false,
default: {},
showInDialog: false,
properties: {
accountId: {
type: 'string',
label: 'Cloudflare Account ID',
category: 'Experimental',
requiresRestart: false,
default: '',
showInDialog: false,
},
projectName: {
type: 'string',
label: 'Cloudflare Pages Project',
category: 'Experimental',
requiresRestart: false,
default: '',
showInDialog: false,
},
},
},
vercel: {
type: 'object',
label: 'Vercel',
category: 'Experimental',
requiresRestart: false,
default: {},
showInDialog: false,
properties: {
projectId: {
type: 'string',
label: 'Vercel Project ID',
category: 'Experimental',
requiresRestart: false,
default: '',
showInDialog: false,
},
projectName: {
type: 'string',
label: 'Vercel Project',
category: 'Experimental',
requiresRestart: false,
default: '',
showInDialog: false,
},
scope: {
type: 'string',
label: 'Vercel Scope',
category: 'Experimental',
requiresRestart: false,
default: '',
showInDialog: false,
},
},
},
netlify: {
type: 'object',
label: 'Netlify',
category: 'Experimental',
requiresRestart: false,
default: {},
showInDialog: false,
properties: {
siteId: {
type: 'string',
label: 'Netlify Site ID',
category: 'Experimental',
requiresRestart: false,
default: '',
showInDialog: false,
},
dedicatedSiteId: {
type: 'string',
label: 'Netlify Dedicated Site ID',
category: 'Experimental',
requiresRestart: false,
default: '',
description:
"Set by the sharing setup when it creates a Netlify site of its own. Publishing relaxes a site's password and SSO protection only when this matches the target site, so a project you had already linked yourself keeps its access settings.",
showInDialog: false,
},
},
},
},
},
oss: {
type: 'object',
label: 'Artifact OSS',
Expand Down
8 changes: 8 additions & 0 deletions packages/cli/src/serve/process-env-guard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ const allowedProcessEnvAccesses = normalizeAllowances([
accesses: { whole: 1 },
},
],
[
'packages/cli/src/serve/routes/workspace-artifact-publish.ts',
{
reason:
'Artifact provider CLIs are process-scoped: they install under the daemon-wide Qwen directory rather than any workspace, and provider child processes inherit the daemon environment with PATH pinned to the daemon PATH. The credential-store location variables (XDG_* / APPDATA / LOCALAPPDATA) are read back from the daemon environment in a loop so a workspace overlay cannot redirect where the daemon-managed provider logins live.',
accesses: { 'computed:key': 1, 'key:PATH': 1, whole: 3 },
},
],
[
'packages/cli/src/serve/run-qwen-serve.ts',
{
Expand Down
Loading
Loading