Skip to content

Commit 3e045e1

Browse files
authored
Merge branch 'main' into jaeone/fe-1173-gated-hf-download-hint-action
2 parents 33b18fc + af68bb1 commit 3e045e1

87 files changed

Lines changed: 6592 additions & 4938 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci-perf-report.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
runs-on: ubuntu-latest
3232
timeout-minutes: 30
3333
container:
34-
image: ghcr.io/comfy-org/comfyui-ci-container:0.0.17
34+
image: ghcr.io/comfy-org/comfyui-ci-container:0.0.21
3535
credentials:
3636
username: ${{ github.actor }}
3737
password: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/ci-tests-e2e.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
runs-on: ubuntu-latest
6464
timeout-minutes: 60
6565
container:
66-
image: ghcr.io/comfy-org/comfyui-ci-container:0.0.17
66+
image: ghcr.io/comfy-org/comfyui-ci-container:0.0.21
6767
credentials:
6868
username: ${{ github.actor }}
6969
password: ${{ secrets.GITHUB_TOKEN }}
@@ -121,7 +121,7 @@ jobs:
121121
needs: setup
122122
runs-on: ubuntu-latest
123123
container:
124-
image: ghcr.io/comfy-org/comfyui-ci-container:0.0.17
124+
image: ghcr.io/comfy-org/comfyui-ci-container:0.0.21
125125
credentials:
126126
username: ${{ github.actor }}
127127
password: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/ci-website-e2e.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
if: ${{ needs.changes.outputs.app-website-changes == 'true' || needs.changes.outputs.packages-changes == 'true' }}
2929
runs-on: ubuntu-latest
3030
container:
31-
image: mcr.microsoft.com/playwright:v1.58.1-noble
31+
image: mcr.microsoft.com/playwright:v1.61.1-noble
3232
timeout-minutes: 15
3333
permissions:
3434
contents: read

.github/workflows/pr-update-playwright-expectations.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ jobs:
7777
needs: setup
7878
runs-on: ubuntu-latest
7979
container:
80-
image: ghcr.io/comfy-org/comfyui-ci-container:0.0.17
80+
image: ghcr.io/comfy-org/comfyui-ci-container:0.0.21
8181
credentials:
8282
username: ${{ github.actor }}
8383
password: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/pr-update-website-screenshots.yaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
update-screenshots:
1515
runs-on: ubuntu-latest
1616
container:
17-
image: mcr.microsoft.com/playwright:v1.58.1-noble
17+
image: mcr.microsoft.com/playwright:v1.61.1-noble
1818
timeout-minutes: 15
1919
permissions:
2020
contents: write
@@ -128,6 +128,9 @@ jobs:
128128

129129
- name: Remove label
130130
if: always() && github.event_name == 'pull_request'
131+
# Label cleanup is best-effort; the restricted pull_request token may
132+
# lack permission to remove labels and must not fail the run.
133+
continue-on-error: true
131134
uses: actions/github-script@v8
132135
env:
133136
PR_NUMBER: ${{ steps.pr-info.outputs.pr-number }}

apps/website/e2e/mcp.spec.ts

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1+
import type { Locator } from '@playwright/test'
12
import { expect } from '@playwright/test'
23

34
import { test } from './fixtures/blockExternalMedia'
45

56
const MCP_ENDPOINT = 'https://cloud.comfy.org/mcp'
67

8+
// The setup island hydrates on visibility; clicks before hydration are
9+
// no-ops, so retry until the tab actually activates.
10+
async function selectClientTab(setup: Locator, name: string) {
11+
const tab = setup.getByRole('tab', { name })
12+
await expect(async () => {
13+
await tab.click()
14+
await expect(tab).toHaveAttribute('data-state', 'active', { timeout: 500 })
15+
}).toPass()
16+
}
17+
718
test.describe('MCP page @smoke', () => {
819
test.beforeEach(async ({ page }) => {
920
await page.goto('/mcp')
@@ -19,53 +30,80 @@ test.describe('MCP page @smoke', () => {
1930
}
2031
})
2132

22-
test('setup section shows both install options', async ({ page }) => {
33+
test('Claude Desktop is the default tab and shows only the connector card', async ({
34+
page
35+
}) => {
2336
const setup = page.locator('#setup')
2437
await setup.scrollIntoViewIfNeeded()
2538
await expect(
26-
setup.getByRole('heading', {
27-
name: 'Ask your agent to install Comfy MCP'
28-
})
29-
).toBeVisible()
39+
setup.getByRole('tab', { name: 'Claude Desktop' })
40+
).toHaveAttribute('data-state', 'active')
3041
await expect(
31-
setup.getByRole('heading', { name: 'Install manually' })
42+
setup.getByRole('heading', { name: 'Add Custom Connector' })
3243
).toBeVisible()
3344
await expect(setup.getByText(MCP_ENDPOINT, { exact: true })).toBeVisible()
45+
await expect(
46+
setup.getByRole('heading', {
47+
name: 'Ask your agent to install Comfy MCP'
48+
})
49+
).toHaveCount(0)
50+
await expect(setup.locator('video')).toBeVisible()
3451
})
3552

36-
test('client tabs swap install instructions', async ({ page }) => {
53+
test('client tabs swap install instructions and agent-card visibility', async ({
54+
page
55+
}) => {
3756
const setup = page.locator('#setup')
3857
await setup.scrollIntoViewIfNeeded()
3958
const activePanel = setup.locator('[role="tabpanel"][data-state="active"]')
59+
const agentHeading = setup.getByRole('heading', {
60+
name: 'Ask your agent to install Comfy MCP'
61+
})
4062

41-
// Claude Code is the default tab and carries the CLI command
42-
await expect(
43-
setup.getByRole('tab', { name: 'Claude Code' })
44-
).toHaveAttribute('data-state', 'active')
63+
await expect(activePanel).toContainText('Add custom connector')
64+
65+
// First interaction retries until the island hydrates; later switches
66+
// assert synchronously so steady-state click regressions fail.
67+
await selectClientTab(setup, 'Claude Code Terminal')
4568
await expect(activePanel).toContainText(
4669
`claude mcp add --transport http comfy-cloud ${MCP_ENDPOINT}`
4770
)
71+
await expect(
72+
setup.getByRole('heading', { name: 'Install manually' })
73+
).toBeVisible()
74+
await expect(agentHeading).toBeVisible()
4875

49-
await setup.getByRole('tab', { name: 'Claude Desktop' }).click()
50-
await expect(activePanel).toContainText('Add custom connector')
76+
await setup.getByRole('tab', { name: 'Codex' }).click()
77+
await expect(activePanel).toContainText(
78+
`codex mcp add comfy-cloud --url ${MCP_ENDPOINT}`
79+
)
80+
await expect(agentHeading).toHaveCount(0)
81+
await expect(setup.locator('video')).toBeVisible()
5182

5283
await setup.getByRole('tab', { name: 'Cursor' }).click()
5384
await expect(activePanel).toContainText('X-API-Key')
5485
await expect(
5586
activePanel.getByRole('link', { name: 'platform.comfy.org' })
5687
).toHaveAttribute('href', 'https://platform.comfy.org/profile/api-keys')
88+
await expect(agentHeading).toBeVisible()
5789

58-
await setup.getByRole('tab', { name: 'Codex' }).click()
90+
await setup.getByRole('tab', { name: 'OpenClaw' }).click()
5991
await expect(activePanel).toContainText(
60-
`codex mcp add comfy-cloud --url ${MCP_ENDPOINT}`
92+
'openclaw skills install @comfy-org/comfy'
6193
)
94+
await expect(agentHeading).toBeVisible()
95+
96+
await setup.getByRole('tab', { name: 'Others' }).click()
97+
await expect(activePanel).toContainText('remote MCP server')
98+
await expect(agentHeading).toBeVisible()
6299
})
63100

64101
test('skills plugin link lives in the agent option card', async ({
65102
page
66103
}) => {
67104
const setup = page.locator('#setup')
68105
await setup.scrollIntoViewIfNeeded()
106+
await selectClientTab(setup, 'Claude Code Terminal')
69107
await expect(
70108
setup.getByRole('link', { name: 'View on GitHub' })
71109
).toHaveAttribute('href', 'https://github.com/Comfy-Org/comfy-skills')
@@ -105,7 +143,10 @@ test.describe('MCP page zh-CN @smoke', () => {
105143
await page.goto('/zh-CN/mcp')
106144
const setup = page.locator('#setup')
107145
await setup.scrollIntoViewIfNeeded()
108-
await expect(setup.getByText('方式一')).toBeVisible()
146+
await expect(
147+
setup.getByRole('heading', { name: '添加自定义连接器' })
148+
).toBeVisible()
149+
await selectClientTab(setup, 'Claude Code Terminal')
109150
await expect(setup.getByRole('heading', { name: '手动安装' })).toBeVisible()
110151
await expect(setup.getByText(MCP_ENDPOINT, { exact: true })).toBeVisible()
111152
})
664 KB
Binary file not shown.
710 KB
Binary file not shown.

apps/website/src/components/common/VideoPlayer.vue

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const {
3333
minimal = false,
3434
hideControls = false,
3535
fit = 'cover',
36+
ariaLabel,
3637
class: className
3738
} = defineProps<{
3839
locale?: Locale
@@ -44,6 +45,7 @@ const {
4445
minimal?: boolean
4546
hideControls?: boolean
4647
fit?: 'cover' | 'contain'
48+
ariaLabel?: string
4749
class?: HTMLAttributes['class']
4850
}>()
4951
@@ -93,6 +95,28 @@ watch(videoEl, syncNativeDuration)
9395
useEventListener(videoEl, 'loadedmetadata', syncNativeDuration)
9496
useEventListener(videoEl, 'durationchange', syncNativeDuration)
9597
98+
// The muted attribute only sets defaultMuted, so SSR-rendered autoplay
99+
// videos count as unmuted and get blocked; force the property and kick
100+
// playback. Scoped to hideControls (decorative) clips so chrome-visible
101+
// consumers keep native semantics. flush: 'post' guarantees this runs
102+
// after useMediaControls' internal muted watcher on the same source.
103+
watch(
104+
[videoEl, () => src],
105+
([el]) => {
106+
if (!el || !autoplay || !hideControls) return
107+
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
108+
el.pause()
109+
return
110+
}
111+
el.muted = true
112+
el.play().catch((error: unknown) => {
113+
if (error instanceof Error && error.name === 'AbortError') return
114+
console.warn('VideoPlayer autoplay failed', error)
115+
})
116+
},
117+
{ flush: 'post' }
118+
)
119+
96120
const effectiveDuration = computed(() => duration.value || nativeDuration.value)
97121
98122
// Scrubber (modeled after VueUse demo Scrubber.vue)
@@ -207,6 +231,7 @@ function toggleFullscreen() {
207231
<video
208232
v-if="src"
209233
ref="videoEl"
234+
:aria-label="ariaLabel"
210235
:class="
211236
cn('size-full', fit === 'contain' ? 'object-contain' : 'object-cover')
212237
"

apps/website/src/i18n/translations.ts

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ const translations = {
8383
'如果您是 ComfyUI 新手,可以从 App 模式开始——这是工作流的简化视图。您随时可以切换回节点图视图以深入了解。'
8484
},
8585
'showcase.feature3.title': {
86-
en: 'Community Workflows on Comfy Hub',
87-
'zh-CN': 'Comfy Hub 上的社区工作流'
86+
en: 'Community Workflows on Comfy Workflows',
87+
'zh-CN': 'Comfy Workflows 上的社区工作流'
8888
},
8989
'showcase.feature3.description': {
9090
en: 'Browse and remix thousands of community-shared workflows. Start from a proven template and customize it to your needs.',
@@ -1919,42 +1919,48 @@ const translations = {
19191919
'zh-CN': '配置 Comfy MCP'
19201920
},
19211921
'mcp.setup.subtitle': {
1922-
en: 'Two ways to connect: ask your agent to install it, or add the server yourself. Sign in once, and the full ComfyUI toolset is available right in your chat.',
1922+
en: 'Two ways to connect: add the server yourself, or ask your agent to install it. Sign in once, and the full ComfyUI toolset is available right in your chat.',
19231923
'zh-CN':
1924-
'两种接入方式:让你的智能体自动安装,或自行添加服务器。登录一次,ComfyUI 全套工具即可直接在对话中使用。'
1924+
'两种接入方式:自行添加服务器,或让你的智能体自动安装。登录一次,ComfyUI 全套工具即可直接在对话中使用。'
19251925
},
1926-
'mcp.setup.option1.label': { en: 'OPTION 1', 'zh-CN': '方式一' },
1927-
'mcp.setup.option1.title': {
1928-
en: 'Ask your agent to install Comfy MCP',
1929-
'zh-CN': '让你的智能体安装 Comfy MCP'
1930-
},
1931-
'mcp.setup.option1.command': {
1932-
en: 'Help me install Comfy MCP.\nFollow the setup guide at {url}',
1933-
'zh-CN': '帮我安装 Comfy MCP。\n请按照 {url} 上的设置指南操作。'
1934-
},
1935-
'mcp.setup.option1.description': {
1936-
en: 'Paste this into Claude, Cursor, Codex, or any MCP-compatible agent. It reads the docs and adds the connector for you.',
1937-
'zh-CN':
1938-
'将它粘贴到 Claude、Cursor、Codex 或任意兼容 MCP 的智能体中。它会读取文档并为你添加连接器。'
1939-
},
1940-
'mcp.setup.option2.label': { en: 'OPTION 2', 'zh-CN': '方式二' },
1941-
'mcp.setup.option2.title': {
1926+
'mcp.setup.manual.title': {
19421927
en: 'Install manually',
19431928
'zh-CN': '手动安装'
19441929
},
1945-
'mcp.setup.option2.description': {
1946-
en: 'Prefer manual setup? Add this URL as a custom connector or remote MCP server in your client, then sign in when prompted.',
1930+
'mcp.setup.manual.description': {
1931+
en: 'Add this URL as a custom connector or remote MCP server in your client, then sign in when prompted.',
19471932
'zh-CN':
1948-
'想手动配置?将此 URL 添加为客户端的自定义连接器或远程 MCP 服务器,然后按提示登录。'
1933+
'将此 URL 添加为客户端的自定义连接器或远程 MCP 服务器,然后按提示登录。'
19491934
},
1950-
'mcp.setup.option2.tabsLabel': {
1935+
'mcp.setup.manual.tabsLabel': {
19511936
en: 'Pick your client',
19521937
'zh-CN': '选择你的客户端'
19531938
},
1939+
'mcp.setup.agent.title': {
1940+
en: 'Ask your agent to install Comfy MCP',
1941+
'zh-CN': '让你的智能体安装 Comfy MCP'
1942+
},
1943+
'mcp.setup.agent.command': {
1944+
en: 'Help me install Comfy MCP.\nFollow the setup guide at {url}',
1945+
'zh-CN': '帮我安装 Comfy MCP。\n请按照 {url} 上的设置指南操作。'
1946+
},
1947+
'mcp.setup.agent.description': {
1948+
en: 'Prefer to let your agent do it? Paste this into Claude, Cursor, Codex, or any MCP-compatible agent. It reads the docs and adds the connector for you.',
1949+
'zh-CN':
1950+
'想让智能体代劳?将它粘贴到 Claude、Cursor、Codex 或任意兼容 MCP 的智能体中。它会读取文档并为你添加连接器。'
1951+
},
19541952
'mcp.setup.clients.claudeCode.step': {
19551953
en: 'Run this in your terminal, then use /mcp to pick comfy-cloud and authenticate.',
19561954
'zh-CN': '在终端运行以下命令,然后通过 /mcp 选择 comfy-cloud 并完成认证。'
19571955
},
1956+
'mcp.setup.walkthroughAlt': {
1957+
en: '{client} setup walkthrough',
1958+
'zh-CN': '{client} 设置演示'
1959+
},
1960+
'mcp.setup.clients.claudeDesktop.manualTitle': {
1961+
en: 'Add Custom Connector',
1962+
'zh-CN': '添加自定义连接器'
1963+
},
19581964
'mcp.setup.clients.claudeDesktop.step': {
19591965
en: 'Click Customize in the sidebar, open Connectors, choose Add custom connector, paste the URL above, and sign in.',
19601966
'zh-CN':
@@ -1973,9 +1979,13 @@ const translations = {
19731979
en: 'Run this in your terminal, then codex mcp login comfy-cloud to sign in.',
19741980
'zh-CN': '在终端运行以下命令,然后执行 codex mcp login comfy-cloud 登录。'
19751981
},
1982+
'mcp.setup.clients.openclaw.step': {
1983+
en: 'Run these in your terminal, then openclaw mcp login comfy to sign in.',
1984+
'zh-CN': '在终端运行以下命令,然后执行 openclaw mcp login comfy 登录。'
1985+
},
19761986
'mcp.setup.clients.other.name': {
1977-
en: 'Other clients',
1978-
'zh-CN': '其他客户端'
1987+
en: 'Others',
1988+
'zh-CN': '其他'
19791989
},
19801990
'mcp.setup.clients.other.step': {
19811991
en: 'Add the URL above as a remote MCP server. No OAuth in your client? Use an X-API-Key header instead. Full walkthroughs live in the ',
@@ -2190,9 +2200,9 @@ const translations = {
21902200
'zh-CN': '我需要 API 密钥吗?'
21912201
},
21922202
'mcp.faq.3.a': {
2193-
en: 'Not for Claude Code, Claude Desktop, or Codex. You need a Comfy API key for Cursor, Hermes, and OpenClaw for now. Just copy https://docs.comfy.org/agent-tools/cloud and your agent will figure out the installation for you.',
2203+
en: 'Not for Claude Code, Claude Desktop, Codex, or OpenClaw. You need a Comfy API key for Cursor and Hermes for now. Just copy https://docs.comfy.org/agent-tools/cloud and your agent will figure out the installation for you.',
21942204
'zh-CN':
2195-
'Claude Code、Claude Desktop 和 Codex 不需要。Cursor、HermesOpenClaw 目前需要 Comfy API 密钥。只需复制 https://docs.comfy.org/agent-tools/cloud,你的智能体就会为你完成安装。'
2205+
'Claude Code、Claude Desktop、CodexOpenClaw 不需要。Cursor 和 Hermes 目前需要 Comfy API 密钥。只需复制 https://docs.comfy.org/agent-tools/cloud,你的智能体就会为你完成安装。'
21962206
},
21972207
'mcp.faq.4.q': {
21982208
en: 'Does it cost anything?',
@@ -2262,7 +2272,7 @@ const translations = {
22622272
en: 'Comfy Enterprise',
22632273
'zh-CN': 'Comfy 企业版'
22642274
},
2265-
'nav.comfyHub': { en: 'Comfy Hub', 'zh-CN': 'Comfy Hub' },
2275+
'nav.comfyHub': { en: 'Comfy Workflows', 'zh-CN': 'Comfy Workflows' },
22662276
'nav.gallery': { en: 'Gallery', 'zh-CN': '画廊' },
22672277
'nav.learning': { en: 'Learning', 'zh-CN': '学习' },
22682278
'nav.blogs': { en: 'Blog', 'zh-CN': '博客' },
@@ -4292,8 +4302,8 @@ const translations = {
42924302
'zh-CN': '{count} 个工作流'
42934303
},
42944304
'models.list.contact.label': {
4295-
en: 'COMFY HUB',
4296-
'zh-CN': 'COMFY HUB'
4305+
en: 'COMFY WORKFLOWS',
4306+
'zh-CN': 'COMFY WORKFLOWS'
42974307
},
42984308
'models.showcase.label': { en: 'AI MODELS', 'zh-CN': 'AI 模型' },
42994309
'models.showcase.heading': {
@@ -4329,9 +4339,9 @@ const translations = {
43294339
'zh-CN': 'Wan 2.2\n文字转视频'
43304340
},
43314341
'models.list.contact.heading': {
4332-
en: 'Pick a model and explore what the community has built. <a href="https://comfy.org/workflows" target="_blank" rel="noopener noreferrer" class="text-primary-comfy-yellow underline">Browse Comfy Hub</a> for the newest workflows.',
4342+
en: 'Pick a model and explore what the community has built. <a href="https://comfy.org/workflows" target="_blank" rel="noopener noreferrer" class="text-primary-comfy-yellow underline">Browse Comfy Workflows</a> for the newest workflows.',
43334343
'zh-CN':
4334-
'选择一个模型,浏览社区的创作成果。<a href="https://comfy.org/workflows" target="_blank" rel="noopener noreferrer" class="text-primary-comfy-yellow underline">访问 Comfy Hub</a> 查看最新工作流。'
4344+
'选择一个模型,浏览社区的创作成果。<a href="https://comfy.org/workflows" target="_blank" rel="noopener noreferrer" class="text-primary-comfy-yellow underline">访问 Comfy Workflows</a> 查看最新工作流。'
43354345
},
43364346

43374347
// Payment status pages

0 commit comments

Comments
 (0)