Commit Graph

7877 Commits

Author SHA1 Message Date
GitHub Action
cb6accaca5 [automated] Apply ESLint and Oxfmt fixes 2026-05-04 23:08:56 +00:00
bymyself
f1df30f24f refactor(website): fix model pages architecture and design token violations
Architecture:
- Replace 1585-line hand-coded models.ts with generated-models.json (207 models,
  auto-generated by running pnpm generate:models) + 40-line model-metadata.ts for
  editorial overrides (docsUrl, blogUrl, featured) + slim 65-line models.ts that
  merges both. No more manually maintained data file.
- Remove 830 per-model translation keys from translations.ts — displayName is now
  a plain string from the generator, not a TranslationKey
- models.ts no longer imports TranslationKey; displayName/description are strings
- Add generate:models script to website package.json

Design token fixes (pattern-compliance violations):
- Replace text-[var(--color-primary-comfy-yellow)] with text-primary-comfy-yellow
- Replace text-white/70 with text-primary-comfy-canvas/70 (matches existing components)
- Replace invented --color-accent/--color-text-secondary with real tokens
- Fix h1 text from text-white to text-primary-comfy-canvas (matches HeroSection pattern)

i18n fixes:
- Add models.hero.tutorialCta, models.hero.blogLink, models.whatIs.heading,
  models.whatIs.tutorialLink keys
- Use t() for all button labels and UI strings in ModelHeroSection.vue
- partner_nodes added to dirLabel in index.astro

Other:
- H1 now reads "{displayName} in ComfyUI" (FE-421 spec)
- Remove description prop from hero (redundant with What-is section)
- Fix GH Actions discovery: m.slug field now matches generator output
- Update add-model-page skill to document new 3-file architecture
2026-05-04 23:08:56 +00:00
GitHub Action
dd0816af3d [automated] Apply ESLint and Oxfmt fixes 2026-05-04 23:08:56 +00:00
bymyself
f22efbb986 fix(website): address review comments on model pages PR
- Fix missing comma in translations.ts (broke build/oxfmt parse)
- Fix partner node huggingFaceUrl: use empty string instead of HF homepage
- Add rel="noopener noreferrer" to external anchor tags
- Remove client:load from ModelHeroSection (presentational, no JS needed)
- Fix GH Actions workflow: rename .yml→.yaml, bump to @v6 actions (pinact exempt),
  pin pnpm action to SHA, fix m.slug→m.suggestedSlug in discovery comparison
- Rewrite add-model-page skill to be repo-agnostic (no Glary-Bot references,
  no hardcoded paths/system assumptions)
2026-05-04 23:08:56 +00:00
bymyself
aaf0ceac9f feat(website): add SEO model pages infrastructure
- 103-model registry (100 local + 3 partner nodes) in models.ts with docsUrl/blogUrl fields
- Dynamic [slug].astro route with SoftwareApplication + BreadcrumbList + FAQPage JSON-LD
- ModelHeroSection.vue with partner node support and docs/tutorial CTAs
- "What is X?" section on every model page targeting AI Overviews / PAA
- generate-models.ts parser with API_PROVIDER_MAP for 30+ partner node providers
- Auto-discovery GH Actions workflow (weekly, opens issue on new models)
- add-model-page Glary-Bot skill for non-dev Slack-driven PRs
- Index page listing all 103 models

Closes FE-421
2026-05-04 23:08:26 +00:00
Christian Byrne
5e3266e0c2 test: add e2e tests for node replacement flows (#11242)
## Summary

Add Playwright e2e tests for the node replacement feature (swap nodes UI
in the errors tab).

## Changes

- **What**: 6 e2e test cases across two describe blocks covering single
and multi-type node replacement flows. Tests verify swap nodes group
visibility, in-place replacement, widget value preservation, Replace All
across multiple types, output connection preservation, and success toast
display. Includes typed mock data for `/api/node_replacements` and two
workflow fixture files with fake missing node types mapped to real core
nodes.

## Review Focus

- Mock setup pattern in `setupNodeReplacement` — enables feature flag
via `page.evaluate` and routes the API endpoint
- Workflow fixture design — uses fake node types (E2E_OldSampler,
E2E_OldUpscaler) that map to real registered types (KSampler,
ImageScaleBy)
- Assertion coverage for link preservation after replacement

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11242-test-add-e2e-tests-for-node-replacement-flows-3426d73d3650811e87d7f0d96fd66433)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Connor Byrne <c.byrne@comfy.org>
2026-05-04 15:52:33 -07:00
Terry Jia
b5b502755f fix(load3d): parse [output]/[input]/[temp] annotation when loading (#11805)
## Summary
The Vue node model picker mixes output assets into the dropdown with a
trailing ' [output]' suffix on the value. Forwarding that string to
loadModel as a literal filename under the configured input folder caused
a 404 and the model never rendered. Strip the trailing folder annotation
per call and use the matching folder so picking an output asset loads
correctly while plain values keep the configured folder.

Output assets stored under a subfolder (e.g. 3d/) were exposed in the
Vue node dropdown as just '<filename> [output]', so selection produced
an /api/view URL with empty subfolder and a 404. Read the subfolder from
the asset's OutputAssetMetadata and prefix it onto the annotated path so
the downstream load handler can split it back out and target the correct
folder.

## Screenshots (if applicable)

https://github.com/user-attachments/assets/463d1071-efdc-46a4-b101-8e1c012d19c7

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11805-fix-load3d-parse-output-input-temp-annotation-when-loading-3536d73d365081a8ac9cf75d14ae29e6)
by [Unito](https://www.unito.io)
2026-05-04 18:44:52 -04:00
pythongosssss
5fbcea6b27 test: add test for workflow delete confirmation (#11780)
## Summary

Adds tests for the `Comfy.Workflow.ConfirmDelete` setting

## Changes

- **What**: 
- ensures dialog does/doesnt appear based on the setting

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11780-test-add-test-for-workflow-delete-confirmation-3526d73d36508134a3cdf0e908b95919)
by [Unito](https://www.unito.io)

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-05-04 21:51:50 +00:00
Comfy Org PR Bot
ac36dc47a4 docs: Weekly Documentation Update (#11465)
## Summary

Fixed two minor documentation inaccuracies found during comprehensive
documentation audit:
- Corrected outdated "Lodash" reference to "Utility Functions" in unit
testing guide
- Updated package manager command from `npx` to `pnpm dlx` in Playwright
skill documentation

## Changes Made

### Documentation Fixes

#### docs/testing/unit-testing.md:150
- **Before**: `## Mocking Lodash Functions`
- **After**: `## Mocking Utility Functions`
- **Reason**: The section describes mocking `es-toolkit/compat`
functions, not Lodash. The project uses es-toolkit as stated in
AGENTS.md line 158 and docs/guidance/typescript.md line 60.

#### .claude/skills/writing-playwright-tests/SKILL.md:117
- **Before**: `npx playwright show-trace trace.zip`
- **After**: `pnpm dlx playwright show-trace trace.zip`
- **Reason**: Project standardizes on pnpm, explicitly avoiding npx per
AGENTS.md line 42: "use `pnpx` or `pnpm dlx` — never `npx`"

## Audit Summary

Comprehensive audit verified accuracy of:
-  Core documentation (CLAUDE.md, AGENTS.md, README.md)
-  All docs/**/*.md files (40+ files including ADRs, testing guides,
architecture docs)
-  All README files throughout repository (21 files)
-  All .claude/commands/*.md files (8 files)
-  Code examples and API references
-  File structure references (verified src/router.ts, src/i18n.ts,
src/main.ts, config files exist)
-  Package dependencies (es-toolkit ^1.39.9 confirmed)
-  Script commands (pnpm test:unit, pnpm test:browser:local, etc.)
-  External resource links
-  ADR index and dates

All other documentation remains accurate and up-to-date as of
2026-05-04.

## Review Notes

This PR contains only two trivial corrections to terminology/commands.
No functional changes, no code changes, no breaking changes. The
documentation audit found the codebase documentation to be in excellent
condition overall.

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
2026-05-04 21:37:52 +00:00
Christian Byrne
aef71852f0 feat: add demo pages with Arcade embeds at /demos/{slug} (#11436)
*PR Created by the Glary-Bot Agent*

---

## Summary

Adds a demo pages system to the website that embeds Arcade interactive
walkthroughs at `comfy.org/demos/{slug}`. These pages will be linked
from welcome/lifecycle emails via Customer.io.

- Adds `/demos/image-to-video` and `/demos/workflow-templates` as the
first two demos
- Follows the existing `customers/[slug].astro` pattern exactly
(config-driven `getStaticPaths()`)
- Full SEO: OG/Twitter cards, HowTo + LearningResource + BreadcrumbList
JSON-LD schemas
- GEO: AI crawler directives in robots.txt, crawlable transcript
alongside iframe
- A11y: iframe title, sr-only transcript, aria-expanded toggle, noscript
fallback
- Email optimization: 1200x630 OG images, SSG pre-rendered, preconnect
to Arcade CDN
- Full zh-CN localization
- Library index stub at /demos for future expansion
- Automatic sitemap inclusion

## Architecture

Adding a new demo = adding one object to `src/config/demos.ts`.

## Note

OG images are tiny placeholders — replace with real 1200x630 screenshots
before go-live.

## Screenshots

![Demo detail page showing Arcade embed with full design
system](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/d4e44d93c258f779ed62667c7924810f9ae7f20f0c9105acd9c3f86f63816bd1/pr-images/1776645565133-5566bf1b-e965-437d-b21f-89e7a751f883.png)

![Demo library index - Coming Soon
stub](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/d4e44d93c258f779ed62667c7924810f9ae7f20f0c9105acd9c3f86f63816bd1/pr-images/1776645565461-0e334640-13e6-4554-ad6e-b3843e107572.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11436-feat-add-demo-pages-with-Arcade-embeds-at-demos-slug-3486d73d365081abbd72e02bf497a43a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 14:53:36 -07:00
Dante
94b570a177 test: rename misnamed Mixpanel test and cover the actual provider class (#11749)
## Summary

The existing \`MixpanelTelemetryProvider.test.ts\` was misnamed: it only
tested \`getExecutionContext\` from \`../../utils/getExecutionContext\`,
never the provider class itself — provider coverage sat at **0%**
despite a 239-line test file living next to it.

This PR:

1. **Renames** the existing test file to
\`src/platform/telemetry/utils/getExecutionContext.test.ts\` (co-located
with the source it actually tests). Updates its relative import to
\`./getExecutionContext\`.
2. **Adds** a fresh
\`src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.test.ts\`
covering the provider class.

Lifts provider coverage from **0% → 81.1%** lines (functions 73.5%,
branches 88.5%).

## Test Coverage (new tests)

Constructor / initialization:
- Without \`mixpanel_token\`, warns and disables itself; subsequent
\`trackXxx\` calls are no-ops.
- With \`mixpanel_token\`, dynamically imports mixpanel-browser, calls
\`init\`, and after \`loaded()\` fires identifies users via
\`onUserResolved\`.

Queueing semantics:
- Events fired before \`loaded()\` are queued and flushed in order once
Mixpanel reports ready.

Filtering:
- Events listed in the default \`disabledEvents\` set (e.g.
\`workflow_opened\`) are suppressed.

Direct dispatchers (parameterized \`it.each\`):
- 16 \`trackXxx\` methods covered: signup/auth/login, subscription
lifecycle, credit topup events, template lifecycle, workflow
imported/saved, default-view, enter-linear, share-flow, execution
success/error.
- \`trackApiCreditTopupButtonPurchaseClicked\` payload includes
\`credit_amount\`.
- \`trackEmailVerification\` dispatches the matching
\`USER_EMAIL_VERIFY_*\` event for each stage.
- \`trackSubscription\` maps \`'modal_opened'\` and
\`'subscribe_clicked'\` to their distinct events.
- \`trackRunButton\` populates \`RunButtonProperties\` from the
execution context.
- \`trackWorkflowExecution\` consumes the latest \`trigger_source\` from
\`trackRunButton\`, then resets it to \`'unknown'\`.

Survey:
- On \`'submitted'\`, normalized properties are written to
\`Mixpanel.people\`.
- On \`'opened'\`, \`Mixpanel.people\` is not touched.

Topup delegation:
- \`startTopupTracking\`, \`clearTopupTracking\`,
\`checkForCompletedTopup\` all forward to the \`topupTracker\` utility.

## Testing

\`\`\`bash
pnpm vitest run
src/platform/telemetry/providers/cloud/MixpanelTelemetryProvider.test.ts
pnpm vitest run src/platform/telemetry/utils/getExecutionContext.test.ts
\`\`\`

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11749-test-rename-misnamed-Mixpanel-test-and-cover-the-actual-provider-class-3516d73d365081609c54f34bd2d8b00d)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <cbyrne@comfy.org>
2026-05-04 14:52:03 -07:00
Comfy Org PR Bot
846412af17 [chore] Update Ingest API types from cloud@758732f (#11479)
## Automated Ingest API Type Update

This PR updates the Ingest API TypeScript types and Zod schemas from the
latest cloud OpenAPI specification.

- Cloud commit: 758732f
- Generated using @hey-api/openapi-ts with Zod plugin

These types cover cloud-only endpoints (workspaces, billing, secrets,
assets, tasks, etc.).
Overlapping endpoints shared with the local ComfyUI Python backend are
excluded.

---------

Co-authored-by: skishore23 <178779+skishore23@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-05-04 21:37:31 +00:00
Benjamin Lu
aa2169e108 test: reset queue history cap in browser tests (#11773)
## Summary
- Reset `Comfy.Queue.MaxHistoryItems` in the shared browser-test
`comfyPage` setup so worker-persisted queue settings cannot leak between
tests.
- Keep the queue settings spec focused on asserting the setting behavior
without local cleanup scaffolding.

## Validation
- `PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://127.0.0.1:65419
PLAYWRIGHT_SETUP_API_URL=http://127.0.0.1:65400
TEST_COMFYUI_DIR=/Users/ben/.codex/comfyui-preview-env/runtime/worktrees/fe-500-maxhistoryitems
pnpm exec playwright test
browser_tests/tests/queue/queueSettings.spec.ts --project=chromium
--workers=1`
- `pnpm exec eslint browser_tests/tests/queue/queueSettings.spec.ts
browser_tests/fixtures/ComfyPage.ts`
- `pnpm exec oxlint browser_tests/tests/queue/queueSettings.spec.ts
browser_tests/fixtures/ComfyPage.ts`
- `pnpm typecheck:browser`
- `git diff --check`
- commit hook: staged oxfmt, oxlint, eslint, `pnpm typecheck`, `pnpm
typecheck:browser`

Linear: FE-500
v1.44.16
2026-05-04 21:31:36 +00:00
Comfy Org PR Bot
cc24d1411a 1.44.16 (#11813)
Patch version increment to 1.44.16

**Base branch:** `main`

---------

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-04 21:30:31 +00:00
AustinMroz
c2abbeda80 Fix core node detection for missing nodes (#11809)
Nodes in the 'essentials' category do not have type 'core'. The check
has been updated to instead use the dedicated `isCoreNode` prop.

No tests currently. The existing tests for this code section all mock
out the relevant code path and properly writing a test for this would
take far more time than I can allocate right now.

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11809-Fix-core-node-detection-for-missing-nodes-3536d73d3650815aabb2deb54c4ecec4)
by [Unito](https://www.unito.io)
2026-05-04 14:21:35 -07:00
Benjamin Lu
56ac3762a0 fix: catch angle-bracket Error assertions (#11909)
## Summary

Extends the new unsafe Error assertion lint rule from #11845 to also
reject angle-bracket assertions.

## Changes

- **What**: Adds a `TSTypeAssertion` selector alongside the existing
`TSAsExpression` selector and broadens the lint message to cover Error
type assertions generally.

## Review Focus

This is stacked on #11845 and only addresses the lint-rule bypass for
`<Error>value` syntax.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11909-fix-catch-angle-bracket-Error-assertions-3566d73d365081f58ecfecfa2e948c33)
by [Unito](https://www.unito.io)

---------

Co-authored-by: bymyself <cbyrne@comfy.org>
2026-05-04 14:16:47 -07:00
guill
f70285dcb2 fix(website): point Install via GitHub buttons to install docs anchor (#11852)
*PR Created by the Glary-Bot Agent*

---

## Summary

Updates the "Install via GitHub" CTA buttons on the `/download` page to
deep-link to the install instructions section of the ComfyUI README
(`#installing`) instead of the repo root, so users land directly on
setup steps.

## Changes

- `apps/website/src/config/routes.ts`: add `externalLinks.githubInstall
= 'https://github.com/Comfy-Org/ComfyUI#installing'` (separate from
`externalLinks.github`, which is still used by the navbar/footer/star
badge for the generic repo link).
- `apps/website/src/components/product/local/HeroSection.vue`: switch
the secondary CTA next to "Download Local" from `externalLinks.github`
to `externalLinks.githubInstall`.
- `apps/website/src/components/product/local/EcoSystemSection.vue`: same
swap on the ecosystem-section CTA.

The platform-aware `Download Local` button (Windows/macOS installers via
`useDownloadUrl`) and the generic GitHub social/repo links elsewhere on
the site are unchanged.

## Verification

- `pnpm --filter @comfyorg/website typecheck` — 0 errors
- `pnpm --filter @comfyorg/website test:unit` — 23/23 passing
- `pnpm exec eslint` on changed files — clean
- `pnpm exec oxfmt --check` — clean
- Manual via `pnpm dev` + Playwright DOM assertion on `/download`:
- Hero "INSTALL FROM GITHUB" →
`https://github.com/Comfy-Org/ComfyUI#installing` ✓
- EcoSystem "INSTALL FROM GITHUB" →
`https://github.com/Comfy-Org/ComfyUI#installing` ✓
- Other "GitHub" links (nav, footer, star badge) → unchanged at
`https://github.com/Comfy-Org/ComfyUI` ✓

Per request from #website-and-docs: the local download surfaces should
at least link to the ComfyUI install instructions on GitHub. Companion
change to comfy-org/website#227.

## Screenshots

![Download page hero with INSTALL FROM GITHUB button now linking to
install docs
anchor](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/3c608b478e1150f3fc43b6092811c93ff3cd90a253263ab05ac43fe8ce7a0843/pr-images/1777761785467-060efddb-f5a0-44a8-8bbe-287c991171ee.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11852-fix-website-point-Install-via-GitHub-buttons-to-install-docs-anchor-3546d73d365081fe8370cd675ae8f896)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 14:16:36 -07:00
Christian Byrne
6762c08134 feat(website): add payment success and failed pages (#11855)
*PR Created by the Glary-Bot Agent*

---

## Summary

Recreate the two payment status pages that were never migrated from
Framer (they weren't in the sitemap, so were missed). The Stripe
checkout flow in `comfy-api` redirects to
`https://www.comfy.org/payment/{success,failed}` after a checkout
session, so users currently hit a 404 on completion or cancel.

## Changes

- **What**: New static Astro pages at `/payment/success`,
`/payment/failed` and their `/zh-CN/` variants, sharing a
`PaymentStatusSection.vue` component built from the existing
`BrandButton` / `SectionLabel` primitives. Translation keys live in
`src/i18n/translations.ts` for both locales. Pages are `noindex` and
explicitly excluded from the generated sitemap. Adds a Playwright e2e
spec covering both pages in both locales.
- **Dependencies**: none

## Review Focus

- **URL slug**: matches production Stripe config
(`STRIPE_CANCEL_URL=…/payment/failed` in
`comfy-api/run-service-{prod,staging}.yaml`), not `/payment/failure`.
- **Primary CTA target**: links to `externalLinks.apiKeys`
(`platform.comfy.org/profile/api-keys`) — the platform root is just a
redirect, so this avoids a hop.
- **Locale-aware secondary CTA**: derived from `getRoutes(locale)` so
future i18n/route changes flow through the existing helper.
- **Stale fallback** (out of scope):
`comfy-api/gateways/stripe/stripe.go:159` has an unrelated stale
fallback pointing at `/payments/` (plural) that's overridden by the env
config in production. Worth fixing in a follow-up.

## Screenshots

EN success / failed and zh-CN success / failed at desktop widths. Mobile
viewport stacks the CTA buttons vertically (verified locally).

## Screenshots

![Payment success page (EN,
desktop)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/c44f59e47f22968047255c353237b19fb0543c1e166ec4c315cd9c1085308814/pr-images/1777774408278-fd3b63f2-357d-401a-8861-5e45050bc930.png)

![Payment failed page (EN,
desktop)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/c44f59e47f22968047255c353237b19fb0543c1e166ec4c315cd9c1085308814/pr-images/1777774408672-a8ada80c-030c-4f7e-805d-c9e3edd2ec1e.png)

![Payment success page (zh-CN,
desktop)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/c44f59e47f22968047255c353237b19fb0543c1e166ec4c315cd9c1085308814/pr-images/1777774408994-2ac1dc5a-8556-4ca1-929b-71d8812337e1.png)

![Payment failed page (zh-CN,
desktop)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/c44f59e47f22968047255c353237b19fb0543c1e166ec4c315cd9c1085308814/pr-images/1777774409357-a79be0ae-36b3-4c1a-84ce-cb65415fee0a.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11855-feat-website-add-payment-success-and-failed-pages-3556d73d3650819f8f45d8ecf27cb264)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 14:15:57 -07:00
Alexander Brown
211c49f538 docs(skill): improve backport-management with tiered triage, path pre-filter, and public-API conflict review (#11868)
*PR Created by the Glary-Bot Agent*

---

Synthesizes lessons from the recent `v1.43.16` backport session (PRs
#11856–#11862) into the `.claude/skills/backport-management/` skill.

**Documentation only — no code, no workflow, no automation changes.**

## What's new

### `SKILL.md`
- **Quick Start** expanded from 7 to 12 steps, surfacing the pre-filter
and target-file-existence check that should run BEFORE per-PR triage
- **New gotcha**: *Cherry-Picked Tests Can Reference Files Added By
Earlier Unbackported PRs* — drop the test, document why
- **New gotcha**: *Backport-Only Compatibility Shims* — when a
refactor-style fix's mechanism relies on changes that aren't on the
older branch, a literal cherry-pick can recreate the bug for extensions
still using the old contract. Real example: #11541 + `LGraphNode.vue`
`handleDrop`
- **New section**: *Path Pre-Filter* under Auto-Skip Categories —
auto-skip PRs touching only `apps/website/`, `browser_tests/`,
`.github/`, `packages/design-system/`, generated types, `.claude/`,
`docs/`, or `*.stories.ts`. Removes 30–50% of candidates without reading
their bodies

### `reference/analysis.md`
- **New subsection**: *Verify Target File Existence* — `git cat-file -e`
before cherry-pick to skip PRs targeting features the branch doesn't
ship, faster than letting cherry-pick fail with modify/delete
- **New section**: *Tiered Triage* — **Tier 1** (core editor
must-haves), **Tier 2** (cloud-distribution only), **Tier 3** (skip)
before per-PR Y/N. Surfaces release-engineering decisions a flat
MUST/SHOULD list obscures

### `reference/discovery.md`
- Reconciliation workflow combining Slack bot list + git gap,
subtracting already-backported PRs (extracted via `Backport of #` grep
on the branch)
- Clarifies that no single source is authoritative

### `reference/execution.md`
- **New Step 0**: *Test-Then-Resolve Pre-Pass* — moved the dry-run loop
to the top of the workflow so you classify clean vs conflict before
triggering automation
- **New inline guard**: *Public-API conflict review* in the manual
cherry-pick loop — consult oracle BEFORE pushing if resolution touches
LiteGraph callbacks, `node.*` methods, or extension-API surfaces
- **Per-PR validation block** (typecheck + targeted unit tests + ESLint
+ oxfmt) before push, in addition to wave verification
- **Three new lessons learned** (19–21) covering the above
- **New PR Body Template** for manual cherry-picks — non-negotiable
conflict-resolution section so reviewers don't have to re-derive
resolution logic from the diff six months later

## Why

1. **Path pre-filtering** caught 35 of 61 candidates as `skip` before
any per-PR analysis was needed during the `v1.43.16` session
(`apps/website/`, CI, tests, design-system). The previous flat
MUST/SHOULD/SKIP rubric meant reading every PR.

2. **Oracle review on PR #11856** (#11541 backport) caught a regression
in `LGraphNode.vue:823` where the upstream PR's removal of the legacy
`handled === true` sync-return path would silently break custom nodes
still using the old `onDragDrop` contract — recreating the very
duplicate-node bug the PR was fixing. The skill had no guidance for this
class of issue.

3. **Two separate backports** (#11180, #11541) hit the same
modify/delete conflict pattern: a test file added on `main` by an
earlier unbackported PR. The skill's *Conflict Triage* table covered
modify/delete generally but didn't surface this specific anti-pattern of
smuggling in test scaffolding without its prerequisites.

4. **Discovery sources** — the skill assumed Slack bot + git gap as
inputs but didn't show how to reconcile them with already-backported
PRs, leading to potential double-cherry-picking.

## Verification

- No code, no workflow, no automation changes — skill documentation only
- `git diff --check` clean
- All four edited files render as valid markdown
- Cross-references between SKILL.md and `reference/*.md` files validated
by line-count check

## Out of scope (intentionally not changed)

- The `pr-backport.yaml` GitHub Action — the skill describes this but
doesn't own it
- The Slack bot — described as *Source 1*, not modified
- The PR title convention `[backport TARGET] ...` — kept as-is
(CodeRabbit's auto-skip filter relies on it)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11868-docs-skill-improve-backport-management-with-tiered-triage-path-pre-filter-and-public-3556d73d3650814faec3df795567bee3)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
2026-05-04 14:13:13 -07:00
Christian Byrne
b83602fd23 feat: hide Google SSO button in embedded webviews (#10699)
Hide the Google SSO login/signup button when the app runs inside an
embedded webview (Android WebView, iOS WKWebView, social app in-app
browsers), where Google blocks OAuth with a `403 disallowed_useragent`
error.


Fixes #7017

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-10699-feat-hide-Google-SSO-button-in-embedded-webviews-3326d73d365081048e35d9d678fe1a2f)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com>
2026-05-04 14:08:06 -07:00
Christian Byrne
aee2e6e6dd test: add e2e tests for nested SubgraphNode input target resolution (#11405)
*PR Created by the Glary-Bot Agent*

---

## Summary

- Adds four Playwright tests targeting `resolveSubgraphInputTarget`
lines 20-31 — the `inputNode.isSubgraphNode()` branch where the target
widget is a PromotedWidgetView
- These lines had 0% e2e coverage because no existing test loaded a
multi-level nested subgraph with VueNodes enabled
- Tests use the existing `subgraph-nested-promotion.json` workflow (node
5 → Sub 0 → node 6 → Sub 1), which has outer SubgraphNode inputs
connecting to an inner SubgraphNode

## Test cases

| Test | Coverage target | Mechanism |
|---|---|---|
| Nested SubgraphNode promoted widgets render without resolution
failures | Lines 20-31 (via VueNodes rendering) | Console warning
collection + widget count assertion |
| Subgraph input resolves through inner SubgraphNode with
PromotedWidgetView | Lines 20-31 (graph structure verification) |
`page.evaluate` walks link chain, asserts `isSubgraphNode() === true`
and `isPromotedWidgetView === true` |
| Promoted widgets from inner SubgraphNode carry correct source identity
| Lines 24-31 (source identity) | Asserts widgets with `sourceNodeId ===
'6'` have correct `sourceWidgetName` |
| Serialize and reload preserves nested promoted widget resolution |
Lines 20-31 (persistence) | `serializeAndReload()` + polled widget count
comparison |

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11405-test-add-e2e-tests-for-nested-SubgraphNode-input-target-resolution-3476d73d365081ab932edc8a01c55c40)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Connor Byrne <c.byrne@comfy.org>
2026-05-04 13:53:16 -07:00
Christian Byrne
2a3b692c0b Repair: re-add bug-dump-ingest skill (#11460) — GitHub squash-commit incident recovery, step 2 of 2 (#11630)
*PR Created by the Glary-Bot Agent*

---

## Step 2 of 2 — GitHub squash-commit incident recovery for #11460

This is the companion to #11629. After #11629 (the revert) merges, this
PR re-applies the original PR #11460 contents on top of the post-revert
`main`, restoring the intended state of the codebase.

### ⚠️ Sequencing — must merge after #11629

Until #11629 is merged, this PR's diff against `main` is empty (because
`main` currently still contains the squashed bug-dump-ingest commit that
#11629 will revert). After #11629 is merged into `main`, GitHub will
recompute the diff and this PR will show a clean re-add of the same 5
`.claude/skills/bug-dump-ingest/` files.

### Verification

The branch was constructed by:
1. Branching from `glary/revert-pr-11460` (the revert branch in #11629).
2. `git checkout FETCH_HEAD -- .claude/skills/bug-dump-ingest/` from
`refs/pull/11460/head` to restore the exact files.
3. Committing them as a single squash-style commit.

I verified that all 5 file blobs are byte-for-byte identical to the
original squash commit `559922eaa5c129767c22275c206c6877931ac15c` by
comparing git object SHAs:

| File | Object SHA |
|---|---|
| `.claude/skills/bug-dump-ingest/SKILL.md` |
`413737835fa1c996291019483effdd39e6da33e5` |
| `.claude/skills/bug-dump-ingest/reference/examples.md` |
`4fc54a4f14b1359de63f558acca0de48c1b65c57` |
| `.claude/skills/bug-dump-ingest/reference/linear-api.md` |
`57986740df2ee02c19b81059f0f1e00e54c2a042` |
| `.claude/skills/bug-dump-ingest/reference/schema.md` |
`84db1a5818c04ee53a94167092ec76dd814992d4` |
| `.claude/skills/bug-dump-ingest/reference/verify-commands.md` |
`a2c99a43a030ccc3769692d3c09be74132645bb4` |

### Notes

- One commit on `refs/pull/11460/head` (an automated lint commit
`76ca1598e`) modified
`src/renderer/extensions/vueNodes/widgets/components/WidgetChart.test.ts`
to remove an `eslint-disable` directive. That change was **not** in the
original squash commit on `main` (verified via `git show --stat`), and
the directive has separately been removed from `main` by an unrelated
commit (#11550), so re-applying that change would now be a no-op. This
repair PR therefore intentionally restores **only the 5 bug-dump-ingest
files**, matching the original squash commit exactly.
- Branch name is `glary/repair-pr-11460` (the `glary/` prefix is
required by the tooling; otherwise equivalent to GitHub's suggested
`repair-pr-11460`).

Refs: #11460, #11629

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11630-Repair-re-add-bug-dump-ingest-skill-11460-GitHub-squash-commit-incident-recovery--34d6d73d365081acbd54c19316561fa9)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 13:51:29 -07:00
Alexander Brown
dac3396de8 test: add selection paste, rename, and batch rename browser tests (#11367)
*PR Created by the Glary-Bot Agent*

---

## Summary

Adds `browser_tests/tests/selectionPasteRename.spec.ts` covering the
untested `pasteSelection()` and `renameSelection()` paths in
`useSelectionOperations.ts`.

### Coverage gaps filled
- `pasteSelection()` — copy → paste creates new nodes
- `renameSelection()` single node path — opens title editor
- `renameSelection()` batch path — prompt dialog with sequential naming
- Empty selection → toast warning

### References
- Follows patterns from `selectionToolboxMoreActions.spec.ts` (More
Options menu, `selectNodeWithPan`)
- Follows `browser_tests/AGENTS.md` directory structure
- Follows `browser_tests/FLAKE_PREVENTION_RULES.md` assertion patterns

### Verification
- TypeScript: clean
- ESLint: clean
- oxlint: clean
- oxfmt: formatted

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11367-test-add-selection-paste-rename-and-batch-rename-browser-tests-3466d73d3650812194a4d8bfbed3dee7)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-05-04 20:30:42 +00:00
Christian Byrne
d253d87c92 Revert "feat: add bug-dump-ingest skill (#11460)" — GitHub squash-commit incident recovery (#11629)
*PR Created by the Glary-Bot Agent*

---

## Step 1 of 2 — GitHub squash-commit incident recovery for #11460

GitHub flagged the squash commit for #11460
(`559922eaa5c129767c22275c206c6877931ac15c`) as affected by the
squash-commit incident that produced non-deterministic merges. This PR
is **step 1 of 2** in the recovery procedure GitHub asked us to follow.

### What this PR does

Reverts `559922eaa5c129767c22275c206c6877931ac15c` (the affected squash
commit for #11460, "feat: add bug-dump-ingest skill") on top of current
`main`.

### Diff

5 files removed, all under `.claude/skills/bug-dump-ingest/`:
- `.claude/skills/bug-dump-ingest/SKILL.md`
- `.claude/skills/bug-dump-ingest/reference/examples.md`
- `.claude/skills/bug-dump-ingest/reference/linear-api.md`
- `.claude/skills/bug-dump-ingest/reference/schema.md`
- `.claude/skills/bug-dump-ingest/reference/verify-commands.md`

`git revert` applied cleanly with no conflicts.

### Recovery procedure

Per GitHub's instructions:

1. **This PR (step 1)** — Revert the affected squash commit. Removes
both the original changes and any unintended changes that the incident
may have introduced.
2. **Next PR (step 2)** — Re-apply the original PR's changes from
`refs/pull/11460/head`, rebased onto post-revert `main`. Will be opened
as a separate "repair" PR.

### Review notes

- This is a pure revert; please confirm the diff is exactly the inverse
of #11460.
- After this PR is merged, the companion repair PR will land the
original changes back on `main` from a clean source ref, restoring the
intended state of the codebase.
- Branch name is `glary/revert-pr-11460` (the `glary/` prefix is
required by the tool that opened this PR — it's otherwise equivalent to
GitHub's suggested `revert-pr-11460`).
- Code review: Oracle reviewed and found 0 issues
(critical/warning/suggestion all 0). Ready to merge.

Refs: #11460

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11629-Revert-feat-add-bug-dump-ingest-skill-11460-GitHub-squash-commit-incident-recove-34d6d73d3650810f9ed3f6068e4f1511)
by [Unito](https://www.unito.io)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 13:17:28 -07:00
Marwan Ahmed
4033dde983 refactor(website): replace UseCaseSection scroll override with hover on desktop (#11696)
## Summary

Per product feedback, scroll-jacking the page to step through
'Industries that create with ComfyUI' categories feels bad on desktop.
This PR removes the desktop scroll override and switches to hover-driven
imagery on lg+, while preserving the existing pin/scrub interaction on
mobile/touch breakpoints.

## Changes

- **What**:
- Gate `usePinScrub` setup to `(max-width: 1023px)` so the pin/scrub
only runs on touch breakpoints; desktop never engages it.
- Wire `@mouseenter` and `@focus` on each category button to update the
active category on desktop. Click still works on both modes via the
existing `scrollToIndex` (which falls through to a direct ref set when
no ScrollTrigger instance is present).
- Pass the same `(max-width: 1023px)` to `useParallax` via its existing
`mediaQuery` option so parallax doesn't run against the no-longer-pinned
section on desktop.
- Apply the section's `lg:h-[calc(100vh+60px)]` unconditionally on lg+
since pin no longer drives it; mobile height is still managed
dynamically by `usePinScrub`'s `cacheLayout`.
- **Breaking**: None.
- **Dependencies**: None.

## Review Focus

- Mobile path inside `usePinScrub.onMounted` is byte-identical to main —
only the early-return condition gained one extra clause
(`!window.matchMedia('(max-width: 1023px)').matches`), which mobile
evaluates to `false` so it falls through to the existing setup.
- `onCategoryHover` early-returns when `isEnabled` is true, making it a
no-op on mobile (where pin is engaged), so a tap doesn't accidentally
fight the scrub.
- `@focus` is wired alongside `@mouseenter` so keyboard tab navigation
also previews the imagery.
- The previous Lenis-on-macOS workaround from this branch is reverted —
it was only needed because the scroll override existed.

## Screenshots (if applicable)

N/A — interaction change. Test on desktop (≥1024px) by hovering category
labels — imagery should swap with no scroll-jacking. Test on mobile
(<1024px) by scrolling the section; pin/scrub should engage as before.

---------

Co-authored-by: Marwan Ahmed <marwan@Marwans-MacBook-Pro.local>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-04 13:16:34 -07:00
Christian Byrne
61a444ed99 test: combine duplicated undo/redo and settings dialog E2E tests with test.step (#11835)
## Summary

Refactor E2E tests added in #11210 that repeated full prior-test bodies
as setup, combining duplicate pairs into single tests with named
`test.step()` blocks.

## Changes

- **What**: In
[`browser_tests/tests/keyboardShortcutActions.spec.ts`](../blob/batch-dispatch/cr-11556/browser_tests/tests/keyboardShortcutActions.spec.ts):
- Merge `Ctrl+Z undoes` + `Ctrl+Shift+Z redoes` → single test with two
`test.step()` blocks.
- Merge `Ctrl+, opens settings dialog` + `Escape closes settings dialog`
→ single test with two `test.step()` blocks.
- **What**: In
[`browser_tests/tests/topbarMenuCommands.spec.ts`](../blob/batch-dispatch/cr-11556/browser_tests/tests/topbarMenuCommands.spec.ts):
- Merge `Edit > Undo` + `Edit > Redo` → single test with two
`test.step()` blocks.

The redo step now reuses the post-undo state from its preceding step
instead of re-creating and re-undoing the node, removing the duplicated
setup the reviewer flagged.

## Review Focus

- Naming of combined tests and `test.step()` labels.
- Note: per @AustinMroz's [comment
thread](https://github.com/Comfy-Org/ComfyUI_frontend/pull/11210#discussion_r3113526265),
location 2 in the issue refers to the `Escape closes settings dialog`
test (which duplicated the `Ctrl+,` test body), not the `Delete` test
(which has unique logic). Treated accordingly.

Fixes #11556

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11835-test-combine-duplicated-undo-redo-and-settings-dialog-E2E-tests-with-test-step-3546d73d365081689df3c56bfbb6f4e4)
by [Unito](https://www.unito.io)
2026-05-04 12:54:52 -07:00
Christian Byrne
385a1d421d [chore] Update Comfy Registry API types from comfy-api@84a4468 (#11910)
## Automated API Type Update

This PR updates the Comfy Registry API types from the latest comfy-api
OpenAPI specification.

- API commit: 84a4468
- Generated on: 2026-05-04T15:45:35Z

These types are automatically generated using openapi-typescript.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11910-chore-Update-Comfy-Registry-API-types-from-comfy-api-84a4468-3566d73d365081ef8771cb77b5de6119)
by [Unito](https://www.unito.io)

Co-authored-by: bigcat88 <13381981+bigcat88@users.noreply.github.com>
2026-05-04 19:27:33 +00:00
Christian Byrne
341fef46a9 refactor: replace unsafe as Error assertions with type guards (#11845)
## Summary

Replaces all 7 production `as Error` type assertions with proper
`instanceof Error` narrowing or a new `toError()` helper, and adds an
ESLint rule to prevent new ones. First slice of #11429 (the `as Error`
category — 9 total occurrences, 7 production + 2 in a test file left
untouched).

## Changes

- **What**:
- New `src/utils/errorUtil.ts` exporting `toError(value: unknown):
Error` and `getErrorMessage(value: unknown): string | undefined`.
`toError` returns the value unchanged if already an `Error`, otherwise
wraps it (handles strings, `undefined`, JSON-serializable objects, and
circular refs via `String()` fallback).
  - Refactored 7 production call sites:
- `src/services/gateway/registrySearchGateway.ts` — `toError(error)` for
`lastError` assignment in fallback loop
- `src/platform/cloud/onboarding/auth.ts` (×2) — `toError(error)` for
`captureApiError` Sentry calls
-
`src/renderer/extensions/vueNodes/widgets/composables/audio/useAudioRecorder.ts`
— `toError(err)` before forwarding to `options.onError`
- `src/extensions/core/load3d/LoaderManager.ts` — replaced `error as
Error & { response?: ... }` cast inside `isNotFoundError` with
`'response' in error` + nested narrowing
- `apps/desktop-ui/src/stores/maintenanceTaskStore.ts` — inline `error
instanceof Error ? error.message : String(error)`
- `apps/desktop-ui/src/components/maintenance/TaskListPanel.vue` —
inline `error instanceof Error ? error.message : undefined`
- New ESLint rule (`no-restricted-syntax` block named
`comfy/no-unsafe-error-assertion`) banning `TSAsExpression
TSTypeReference[typeName.name='Error']` in `src/**` and `apps/*/src/**`,
with test files (`*.test.ts`, `*.spec.ts`) excluded.
  - 12 unit tests for the new helpers in `src/utils/errorUtil.test.ts`.
- **Breaking**: none
- **Dependencies**: none

## Review Focus

- The lint rule is scoped to non-test source files. Test files retain
freedom to use `as Error` for fixture construction; only 2 occurrences
exist (in `teamWorkspaceStore.test.ts` and `errorDialog.spec.ts`) and
they're intentional.
- `toError` is duplicated as inline `instanceof` narrowing in
`apps/desktop-ui/` rather than imported, since the desktop-ui workspace
doesn't share `@/utils/` with the main app and adding a path mapping for
one helper felt heavier than two inline guards.
- Remaining `as`-on-DOM categories (HTMLElement ×133, HTMLInputElement
×55, HTMLCanvasElement ×36, KeyboardEvent ×7, Element ×3, MouseEvent ×2,
Event ×2) are intentionally left for follow-up PRs to keep this one
reviewable.

Refs #11429

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11845-refactor-replace-unsafe-as-Error-assertions-with-type-guards-3546d73d36508137a015c4f9e8708f23)
by [Unito](https://www.unito.io)
2026-05-04 11:40:28 -07:00
Yourz
24b548aebc fix: route footer Support link to Zendesk help center (#11904)
*PR Created by the Glary-Bot Agent*

---

## Summary

The "Support" link in the marketing site footer (Contact column) was
reusing
the Discord external link. Update it to point at the Zendesk help center
at
`https://support.comfy.org/hc/en-us`, as requested in the
`#website-and-docs` Slack thread.

## Changes

- `apps/website/src/config/routes.ts` — add `support` entry to
`externalLinks`
  pointing at `https://support.comfy.org/hc/en-us`.
- `apps/website/src/components/common/SiteFooter.vue` — use
  `externalLinks.support` for the Contact > Support entry instead of
  `externalLinks.discord`.

## Verification

- `pnpm format` and `pnpm exec eslint` clean on both files.
- `pnpm typecheck` passes.
- Verified locally with `pnpm dev` (Astro on `localhost:4321`); the
rendered
footer Support link now resolves to `https://support.comfy.org/hc/en-us`
  (screenshot below).

## Notes

Reviewer flagged that `/hc/en-us` forces English and bypasses Zendesk
locale
negotiation. The exact URL was explicitly requested by the user in the
Slack
thread, so it is preserved here. Switching to a locale-neutral
`https://support.comfy.org/` can be done as a follow-up if desired.


## Screenshots

![Marketing site footer with Support link pointing to
support.comfy.org/hc/en-us](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/7cb1cde676098ecfc7a07ab2b8d341ba402b097e134b5eaaf42572e925bd6d40/pr-images/1777906238675-00158842-4368-478a-ae6e-c91d536a7986.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11904-fix-route-footer-Support-link-to-Zendesk-help-center-3566d73d36508189abcff34ae766d3c4)
by [Unito](https://www.unito.io)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 17:28:39 +00:00
Christian Byrne
6ea278da30 [chore] Update Comfy Registry API types from comfy-api@9ec8c25 (#11906)
## Automated API Type Update

This PR updates the Comfy Registry API types from the latest comfy-api
OpenAPI specification.

- API commit: 9ec8c25
- Generated on: 2026-05-04T15:11:04Z

These types are automatically generated using openapi-typescript.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11906-chore-Update-Comfy-Registry-API-types-from-comfy-api-9ec8c25-3566d73d365081e394a6c13c0e30499b)
by [Unito](https://www.unito.io)

Co-authored-by: coderfromthenorth93 <213232275+coderfromthenorth93@users.noreply.github.com>
2026-05-04 16:32:34 +00:00
Christian Byrne
560e53c68f fix: remove coming soon badge from parallel job execution (#11819)
*PR Created by the Glary-Bot Agent*

---

Removes the "coming soon" badge from the Parallel Job Execution feature
card on the cloud pricing page (`comfy.org/cloud/pricing`).

## Changes

- `apps/website/src/components/pricing/WhatsIncludedSection.vue`: drop
`isComingSoon: true` from feature11 so it renders with the standard
check icon and no badge.

The `isComingSoon` mechanism (clock icon + yellow badge) is preserved in
the component for future use on other features.

## Note

The FAQ copy elsewhere on the site (`cloud.faq.9.a`) still references
"one active job at a time" and "parallel runs soon". That copy will be
updated separately.

## Verification

- `pnpm typecheck` (website): 0 errors
- `pnpm lint`: clean (1 pre-existing warning unrelated to this change)
- `pnpm format:check`: clean
- `pnpm test:unit` (website): 20 passed
- Visual check via Playwright on local dev server (see screenshot)

## Screenshots

![Pricing page after change: Parallel job execution row shows green
check icon and no coming soon
badge](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/54c41067c2ba0bce5de11dd3b919e3c370be4eba2fd44eb3c411921f34bc088e/pr-images/1777688853166-87c5c07e-e4ad-4ef3-a892-f3e01e2f980f.png)

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11819-fix-remove-coming-soon-badge-from-parallel-job-execution-3546d73d365081d19060f976095d03ac)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 15:27:31 +00:00
Yourz
1999b7fba0 fix: remove (beta) from cloud.faq.3.a (#11905)
*PR Created by the Glary-Bot Agent*

---

## Summary

Remove `(beta)` from the `cloud.faq.3.a` translation entry in both
English and Simplified Chinese (`zh-CN`), since Comfy Cloud is no longer
in beta.

## Changes

`apps/website/src/i18n/translations.ts`:
- en: `Comfy Cloud (beta) has zero setup...` → `Comfy Cloud has zero
setup...`
- zh-CN: `Comfy Cloud(测试版)无需任何设置...` → `Comfy Cloud 无需任何设置...`

## Verification

- Pre-commit hooks (oxfmt, oxlint, eslint, typecheck, typecheck:website)
all passed
- Code review (oracle): 0 issues, ready to merge
- Manual verification via Playwright on `/cloud` and `/zh-CN/cloud` —
FAQ item 3 renders updated copy in both locales (screenshots attached)

## Screenshots

![English FAQ item 3 expanded — 'Comfy Cloud has zero setup...' (no
beta)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/226e1a7ea5794b251aeaa587f0696b945f264afd4db5933eaa0125c5d12235ec/pr-images/1777906512798-b5b8fc07-1ed1-43e2-88f5-35efd6ee7254.png)

![Simplified Chinese FAQ item 3 expanded — 'Comfy Cloud 无需任何设置...' (no
测试版)](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/226e1a7ea5794b251aeaa587f0696b945f264afd4db5933eaa0125c5d12235ec/pr-images/1777906513275-1c0c0f6b-0408-4cc2-93e6-4a5e0d02a101.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11905-fix-remove-beta-from-cloud-faq-3-a-3566d73d36508150997bcf2c89826091)
by [Unito](https://www.unito.io)

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 15:03:06 +00:00
Christian Byrne
285421a87c feat: add queue progress overlay feature survey (#11560)
*PR Created by the Glary-Bot Agent*

---

## Summary

Registers a new nightly feature survey for the Queue Progress Overlay
using the existing feature-survey registry (same pattern as the merged
node-search survey, PRs #8175/#8355/#9934).

- New registry entry `queue-progress-overlay` → Typeform `HZ5saxry`,
threshold **16**, 5s display delay.
- `trackFeatureUsed()` wired at the major user-initiated handlers inside
the overlay so the survey triggers regardless of panel location
(floating-right v1 or docked-left v2).
- Run button and other ActionBar items that the overlay pops over from
are deliberately **not** tracked — tracking is scoped to interactions
that originate inside the job panel / queue progress overlay itself.

## Tracked interactions

Both variants share most sub-components, so tracking is instrumented
once at each logical surface:

- **`QueueProgressOverlay.vue`** (v1 container): `viewAllJobs`,
`interruptAll`, `cancelQueuedWorkflows`, `onClearHistoryFromMenu`,
`toggleAssetsSidebar`, `onCancelItem`, `onDeleteItem`, `inspectJobAsset`
- **`QueueOverlayExpanded.vue`**: job tab switches
- **`JobHistorySidebarTab.vue`** (v2 docked): job tab switches,
`clearQueuedWorkflows`, `onClearHistory`, `onCancelItem`,
`onDeleteItem`, `onViewItem`
- **`JobFilterActions.vue`** (shared): workflow filter + sort mode
selections
- **`JobHistoryActionsMenu.vue`** (shared): docked-history toggle +
run-progress-bar toggle

Deliberately **not tracked** to keep the signal clean:
- Hover handlers (ambient preview behaviour)
- Search-box keystrokes (debounced typing)
- Context menu open and menu-item dispatch — menu actions either bubble
through already-tracked terminal handlers (e.g. inspect-asset →
`onViewItem`) or are secondary operations (copy-id, open-workflow,
download). Avoids double-counting per code review feedback.

## How it works (inherits from existing infrastructure)

1. `surveyRegistry.ts` drives `NightlySurveyController` →
`NightlySurveyPopover`, which handles the Typeform embed.
2. Eligibility already gated on `isNightly && !isCloud && !isDesktop`,
once-per-user, 4-day global cooldown across all surveys, and opt-out.
3. Typeform response routing to #C0ALLT6Q3SQ is handled on the Typeform
side.

## Verification

- `pnpm typecheck` 
- `pnpm lint`  (no new warnings)
- `pnpm knip` 
- `pnpm test:unit` on `src/components/queue`,
`src/components/sidebar/tabs/JobHistorySidebarTab`,
`src/platform/surveys` → **123/123 passing**
- Pre-commit hooks (stylelint, oxfmt, oxlint, eslint, typecheck) all
pass
- Manual: dev server + backend boot cleanly, app loads without new
runtime errors, `localStorage['Comfy.FeatureUsage']` layout verified to
match what `useFeatureUsageTracker` writes

## Notes

- Survey key `queue-progress-overlay` covers both v1 (floating-right)
and v2 (docked-sidebar) per product guidance: _"This should trigger
regardless of the location of the panel (docked from left or floating on
right)."_ Both surfaces are the same product feature — the survey is
intentionally scoped to the whole job-panel experience.


## Screenshots

![App loads cleanly with the new survey code in place — empty canvas
with Run button and sidebar, no runtime
errors](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/fd18977704544ba278ad3fa42c695289ae7e02001550ce38955d6fb47d872146/pr-images/1776914667332-03e4ef0a-4137-47c6-87b8-b554770b8900.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11560-feat-add-queue-progress-overlay-feature-survey-34b6d73d3650819a9a50fd67fd9b5941)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 14:50:18 +00:00
Christian Byrne
5523df1aea fix(website): unstretch See all case studies button (#11854)
*PR Created by the Glary-Bot Agent*

---

## Summary

The "See all case studies" button on the homepage
`CaseStudySpotlightSection` was rendering oddly stretched because it had
`class="flex-1 text-center"` while being the sole child of a `flex-row`
container — it expanded to fill the entire content column (~592px)
instead of sizing to its label.

This drops `flex-1`/`text-center` and adds `items-start` to the wrapper
so the button sizes to its content and is left-aligned, matching the
proportions of every other outline `BrandButton` on the site (Hero,
UseCase, customer detail, etc.).

## Changes

- `apps/website/src/components/home/CaseStudySpotlightSection.vue`:
remove `flex-1 text-center` from the `BrandButton` and align the row's
items to the start.

`BrandButton` already centers its label internally via `inline-flex …
justify-center`, so dropping `text-center` is a no-op visually.

## Before / After

- Desktop before: button width = 592px (stretched across the column)
- Desktop after: button width = 223px (natural)
- Mobile: 1-column layout, now consistently left-aligned

## Review Focus

Whether the fix should also live on the `BrandButton` component itself
(e.g. a global `max-width`) instead of at the call site. I went with the
instance-level fix because every other CTA in the website intentionally
uses bare `BrandButton` and lets the content size it; only this one had
`flex-1`. A blanket `max-width` would risk changing Hero/MobileMenu
buttons that explicitly opt into `w-full lg:w-auto lg:min-w-60`.

## Screenshots

![Before: button stretched across the full content
column](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/19522cd256addec524dfcc25228a9ad732d07646330472c58513d6b4714808ca/pr-images/1777774244354-4dd9af45-2458-4d8a-a1a7-1f6b88b6fc4b.png)

![After: button sized to content,
left-aligned](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/19522cd256addec524dfcc25228a9ad732d07646330472c58513d6b4714808ca/pr-images/1777774244808-5bab2801-0140-4b4a-9d9e-61a467090de3.png)

![After: mobile view, left-aligned natural
width](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/19522cd256addec524dfcc25228a9ad732d07646330472c58513d6b4714808ca/pr-images/1777774245316-1ca9609d-3de0-4c85-973e-a87e296fa65f.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11854-fix-website-unstretch-See-all-case-studies-button-3556d73d365081abb3bbe9dbc51cbc07)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 14:03:39 +00:00
Christian Byrne
65876c635d feat(website): add responsive media tooling for marketing assets (#11869)
*PR Created by the Glary-Bot Agent*

---

## Summary

Adds the building blocks for a responsive media system on
`apps/website`, motivated by the gallery video blurriness raised in
Slack. Three independent pieces:

1. **`<SiteVideo>` Vue component + URL helper** — emits a `<video>` with
multiple `<source>` tags, designed to pair with assets named
`${name}-${width}.${format}` on `media.comfy.org`.
2. **`scripts/process-videos.sh`** — local-developer `ffmpeg` helper
that produces VP9/WebM + H.264/MP4 variants and a poster JPG. Not wired
into CI; the team uploads to `media.comfy.org` out-of-band.
3. **Marketing image conventions** — shared `MARKETING_FORMATS` /
`MARKETING_WIDTHS` constants and a README documenting how to render
local marketing images via Astro's built-in `<Picture>` from
`astro:assets`.

This PR is **infrastructure only** — no existing pages are modified.
Adoption (e.g. converting `HeroSection`, gallery videos) is a follow-up.
The new files are added to knip's ignore list with the existing "pending
stacked PR" pattern.

## Why this shape

- **No custom `<Picture>` wrapper.** Astro 5 already ships a
`ResponsiveImage` component (name conflict), and Astro's
`LocalImageProps | RemoteImageProps` discriminated union does not
survive a thin wrapper without unsafe `as` casts. Shared constants give
the consistency benefit at lower cost.
- **No CI media-upload step.** The `Release: Website` workflow currently
only refreshes the Ashby snapshot; wiring GCS uploads into it would
require new secrets and team coordination beyond this PR's scope. The
script runs locally and outputs are uploaded to `media.comfy.org` the
same way as today.
- **Single resolution per `<video>`.** `<source media="...">` inside
`<video>` is unreliable across browsers (Safari ignores it). The script
generates multiple widths so callers can pick one per page; JS-based
selection can be layered on later if metrics demand it.

## What's verified

- `pnpm --filter @comfyorg/website test:unit` — 30 pass (7 new for
`buildVideoSources` / `videoKey`)
- `pnpm --filter @comfyorg/website typecheck` — clean
- `pnpm --filter @comfyorg/website build` — 41 pages built clean
- `pnpm knip` — exit 0
- `oxfmt --check` and `oxlint` clean on all changed files
- `bash -n` on `process-videos.sh` clean; usage and missing-deps paths
exercised manually
- Manual: home page and `/gallery` rendered via `astro dev` — both
unchanged with zero console errors (screenshots attached)

## Review feedback addressed

After Oracle review, three follow-up commits land:

- **`SiteVideo` reactivity** — `sources` is now `computed`; the
`<video>` is keyed on the joined source URLs so it remounts when the
source set changes (browsers don't reload on `<source>` mutation).
- **`SiteVideo` accessibility** — `aria-hidden="true"` only when truly
decorative (no `alt` and no `controls`).
- **Shell script robustness** — probes duration with `ffprobe` and falls
back to `t=0` for clips shorter than 1s; enables `nocaseglob` so
`CLIP.MP4` is picked up.
- **Docs** — clarifies when to use `<SiteVideo>` (lightweight
multi-source) vs `<VideoPlayer>` (captions, controls, scrubber).

## Out of scope (follow-ups)

- Converting existing pages (`HeroSection`, customer detail heros,
gallery) to use the new components. Most current images are CDN-hosted
and migrating them is a separate decision.
- Re-encoding the gallery videos at a higher source width to actually
fix the blurriness — that requires the team to run `process-videos.sh`
against the source clips and re-upload.
- Combining `<SiteVideo>`'s multi-source support with `<VideoPlayer>`'s
rich chrome.

## Screenshots

![Home page renders unchanged with no console
errors](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/df0d9bade4eca96daf49f97a3e6864cc74345f430e4a9308e2e68d635dfd8e04/pr-images/1777791647863-fb1ea2bf-32fc-40d9-852d-cceb3bc148f7.png)

![Gallery page renders unchanged with no console
errors](https://pub-1fd11710d4c8405b948c9edc4287a3f2.r2.dev/sessions/df0d9bade4eca96daf49f97a3e6864cc74345f430e4a9308e2e68d635dfd8e04/pr-images/1777791648186-0b598260-a836-4866-9c55-9d0e99de6d4c.png)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11869-feat-website-add-responsive-media-tooling-for-marketing-assets-3556d73d3650818899c7f9ed3204c9a5)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
2026-05-04 13:25:20 +00:00
jaeone94
04918360eb Use hash lookup for missing asset detection (#11873)
## Summary

Use exact BLAKE3 hash lookups first for missing model/media detection,
and add a separate public-inclusive input asset cache so public input
assets are considered missing-detection candidates without changing the
user-only input assets shown in the UI.

## Changes

- **What**:
- Added `assetService.checkAssetHash()` for `HEAD
/api/assets/hash/{hash}` status-only existence checks.
- Added strict BLAKE3 hash helpers so only `blake3:<64 hex>` media
values and raw 64-hex BLAKE3 model metadata are sent to the hash
endpoint.
- Updated missing media detection to group BLAKE3 candidates by hash,
resolve them through the hash endpoint, and fall back to the legacy
asset list path for invalid/unverifiable/non-hash values.
- Updated missing model detection to use hash lookup for BLAKE3-backed
asset-supported candidates before falling back to the existing node-type
asset matching path.
- Added `assetService.getInputAssetsIncludingPublic()` backed by a
dedicated cache that fetches input assets with `include_public=true` for
missing media fallback checks.
- Kept `assetsStore.inputAssets` user-only for widget/UI display, while
invalidating the public-inclusive missing-detection cache when input
assets may change.
- Added abort handling for paginated asset fetches and shared
public-input cache callers so one aborted caller does not cancel the
shared fetch for other callers.
- Added regression coverage for hash lookup, fallback behavior, abort
paths, public input fallback detection, and cache invalidation.
- **Dependencies**: None.
- **Change size**:
  - Production code: 4 files, 400 insertions, 24 deletions, net +376.
  - Test code: 4 files, 806 insertions, 59 deletions, net +747.
  - Total: 8 files, 1206 insertions, 83 deletions, net +1123.

## Review Focus

- The public-inclusive input asset cache is intentionally separate from
`assetsStore.inputAssets`. The existing store data is user-only and
drives the asset widgets/sidebar, so using it for missing input
detection misses public assets. Making that store public-inclusive would
change UI data semantics; this PR instead keeps the UI dataset unchanged
and adds a missing-detection-specific cache in `assetService`.
- Hash lookup is only used when the workflow exposes a valid BLAKE3
hash. Filename-like values and invalid hash values still use the legacy
fallback path.
- Missing model detection keeps the existing fallback behavior for
non-hash candidates and for hash checks that are invalid or fail
transiently.
- Async model download cache refresh behavior is left unchanged; this PR
avoids coupling model download completion to input asset cache
invalidation.
- No browser/e2e test was added because this changes the missing asset
detection data path, not UI interaction or rendering. The behavioral
coverage is in unit tests for the asset service and the missing
media/model scanners.

## Follow-up Items

- Fix `assetsStore.updateAssetTags()` partial-failure recovery. If
`removeAssetTags()` succeeds and `addAssetTags()` fails, the local model
asset cache can roll back to tags that the backend has already removed;
this should be handled in a focused model asset cache PR.
- Consider extracting shared hash-verification flow used by missing
media and missing model scans after this behavior stabilizes.
- Consider adding a concurrency cap or short-lived request cache for
large workflows with many unique hash lookups.
- Consider splitting `assetService.ts` further, e.g. hash helpers, abort
utilities, and the public-inclusive input asset cache.
- Consider tightening the asset hash service API shape so callers do not
directly depend on HTTP-oriented statuses such as `invalid`.
- Consider adding broader mutation-path coverage for public-inclusive
input cache invalidation once the cache has more consumers.

Linear: FE-534

## Screenshots (if applicable)

Before <false positive / missing image / public asset>


https://github.com/user-attachments/assets/db7ce2a9-b169-4fae-bf9f-98bb93d3ee6d

After 


https://github.com/user-attachments/assets/29af9f9e-b536-4fcd-a426-3add40bcb165



┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11873-Use-hash-lookup-for-missing-asset-detection-3556d73d36508165babafb16614be0d8)
by [Unito](https://www.unito.io)
2026-05-04 03:59:54 +00:00
Dante
af70d88860 fix: keep finished badge fully opaque in ProgressToastItem (#11542)
## Summary
- fix
**[slack](https://comfy-organization.slack.com/archives/C0A4XMHANP3/p1776801170742579)**
- Move `opacity-50` off the row container onto the asset-name column
only, so the contrast badge (white pill, dark label) is not dimmed to
gray-on-gray when a download completes.
- Matches the Figma intent that the `FINISHED` badge stands out —
designer spec uses `base/foreground` for pill, `base/background` for
text, which is unreadable when the parent is 50% opacity.

<img width="560" height="269" alt="Screenshot 2026-04-23 at 2 46 17 PM"
src="https://github.com/user-attachments/assets/fb84aa57-c348-4a86-9a65-9342c12400e1"
/>
<img width="764" height="332" alt="Screenshot 2026-04-23 at 2 46 41 PM"
src="https://github.com/user-attachments/assets/ecbe6a5f-c2e8-4427-9c1d-f8f123009d2e"
/>


## Before / After

![before /
after](https://raw.githubusercontent.com/Comfy-Org/ComfyUI_frontend/jaewon/fe-237-fix-honeytoast-badge-finished-opacity/.github/pr-images/fe-237-before-after.png)

## Repro
Cloud → trigger a model download → wait for completion → the `FINISHED`
badge is the same tone as the toast surface (see Slack thread
screenshots).

## Test plan
- [ ] Complete a model download in cloud and confirm the `FINISHED`
badge is clearly legible in both themes.
- [ ] File name + subtitle still appear dimmed to signal the row is
completed.
- [ ] Running / failed / pending states unchanged.

- Fixes
[FE-237](https://linear.app/comfyorg/issue/FE-237/fix-honeytoast-badge-text-color-for-finished-job-matches-background)
2026-05-03 08:40:27 +00:00
Christian Byrne
c955309b26 [chore] Update Comfy Registry API types from comfy-api@911406c (#11518)
## Automated API Type Update

This PR updates the Comfy Registry API types from the latest comfy-api
OpenAPI specification.

- API commit: 911406c
- Generated on: 2026-04-17T16:10:40Z

These types are automatically generated using openapi-typescript.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11518-chore-Update-Comfy-Registry-API-types-from-comfy-api-911406c-3496d73d36508146a1e2e1ee90640fa4)
by [Unito](https://www.unito.io)

Co-authored-by: coderfromthenorth93 <213232275+coderfromthenorth93@users.noreply.github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
2026-05-03 01:01:41 -07:00
Comfy Org PR Bot
7abd9d12c8 chore(website): refresh Ashby roles snapshot (#11851)
Automated refresh of `apps/website/src/data/ashby-roles.snapshot.json`
from the Ashby job board API.

**Flow:**
1. `Release: Website` workflow ran (manual trigger).
2. This PR opens with the regenerated snapshot.
3. `CI: Vercel Website Preview` deploys a preview for review.
4. Merging to `main` triggers the production Vercel deploy.

The snapshot fallback in `apps/website/src/utils/ashby.ts` remains
intact: builds without `WEBSITE_ASHBY_API_KEY` continue to use the
committed snapshot.

Triggered by workflow run `25260868155`.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11851-chore-website-refresh-Ashby-roles-snapshot-3546d73d365081579f98f13f7b58e611)
by [Unito](https://www.unito.io)

Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com>
2026-05-02 14:15:34 -07:00
Yourz
dd9cb42fa1 feat: add Run your first workflow button to home hero (#11848)
## Summary

Add an outline-style `BrandButton` to the right side of the home page
hero section linking to the workflows page.

## Changes

- **What**: 
- Added a `Run your first workflow` outline button below the subtitle in
`apps/website/src/components/home/HeroSection.vue`, linking to
`externalLinks.workflows`. Mirrors the button pattern from
`product/local/HeroSection.vue`.
- Added `hero.runFirstWorkflow` i18n entry (en + zh-CN) in
`apps/website/src/i18n/translations.ts`.

## Review Focus

- Confirmed alignment with design spec.

<img width="1505" height="776" alt="image"
src="https://github.com/user-attachments/assets/215e667d-1827-447b-99b8-eba8cb5ec7e3"
/>
<img width="335" height="700" alt="image"
src="https://github.com/user-attachments/assets/aeac0876-74c3-4e12-a4b3-203f9e541bc2"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11848-feat-add-Run-your-first-workflow-button-to-home-hero-3546d73d365081358d54eddfda71111e)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-05-02 20:18:28 +00:00
pythongosssss
ccd19d8695 test: add metadata parser coverage (#11307)
## Summary
Adds tests for metadata parsers

## Changes

- **What**: 
- add test file generation script
- identified & fixed bug in webp exif parsing over-reading
- identified & fix bug in mp3/ogg parser where it would read from a
fixed position instead of relative, causing incorrect reads throwing
RangeError
- added catch in latent + json parsing to resolve errors

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11307-test-add-metadata-parser-coverage-3446d73d36508108ac36dddcec0a54d4)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-05-02 13:18:45 -07:00
Yourz
809fba7b36 feat: add Groove Jones customer story (#11849)
## Summary

Add a new customer story for Groove Jones — Crocs x NFL FOOH holiday
campaign for Dick's Sporting Goods, delivered with Comfy.

## Changes

- **What**:
- New entry in
[`apps/website/src/config/customerStories.ts`](https://github.com/Comfy-Org/ComfyUI_frontend/blob/feat/groove-jones-customer-story/apps/website/src/config/customerStories.ts)
registering slug `groove-jones` with cover image hosted on
`media.comfy.org/website/customers/groove-jones/`.
- Added `customers.story.groove-jones.{category,title,body}` and
`customers.detail.groove-jones.topic-1` … `topic-10` translations (en +
zh-CN) in
[`apps/website/src/i18n/translations.ts`](https://github.com/Comfy-Org/ComfyUI_frontend/blob/feat/groove-jones-customer-story/apps/website/src/i18n/translations.ts).
10 sections matching design sidebar: INTRO, THE OUTPUT, THE PROBLEM, HOW
COMFY SOLVED THE PROBLEM, BRAND-TRAINED LORAS, MULTI-MODEL
ORCHESTRATION, THE PIPELINE, VERSION CONTROL, FINISHING IN NUKE, THE
TAKEAWAY.
- Includes 2 pull quotes (Doug Hogan, Dale Carman), 1 final blockquote +
author card, and 3 inline images.
- Routes `/customers/groove-jones` and `/zh-CN/customers/groove-jones`
are auto-generated by `[slug].astro`.

## Review Focus

- Contributors author card uses `TBD` placeholder names/roles — to be
filled in.
- No `readMoreHref` set yet (no public blog post URL).
- All 4 images uploaded to
`gs://comfy-org-videos/website/customers/groove-jones/` and served via
`media.comfy.org`.

<img width="1000" height="535" alt="Kapture 2026-05-02 at 23 17 04"
src="https://github.com/user-attachments/assets/28654d24-0d49-4303-82ac-b6923cd6bc93"
/>


┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11849-feat-add-Groove-Jones-customer-story-3546d73d36508128a64bd6809ad77447)
by [Unito](https://www.unito.io)

Co-authored-by: Amp <amp@ampcode.com>
2026-05-02 18:31:18 +00:00
Christian Byrne
df2ae6f2d0 fix(load3d): dispose THREE.Points GPU resources in clearModel() (#11836)
Fixes #11345

## Summary

`clearModel()` in `SceneModelManager` only traversed and disposed
`THREE.Mesh` instances, leaving `THREE.Points` objects (created by
`handlePLYModeSwitch()` for point-cloud mode) leaking GPU geometry and
material memory on repeated point-cloud loads/clears.

## Changes

- `SceneModelManager.ts`: extend the dispose traversal in `clearModel()`
to also handle `THREE.Points`, mirroring the pattern already used by
`removeAllMainModelsFromScene()`.
- `SceneModelManager.test.ts`: add regression test verifying
`geometry.dispose()` and `material.dispose()` are called for
`THREE.Points` children on `clearModel()`.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11836-fix-load3d-dispose-THREE-Points-GPU-resources-in-clearModel-3546d73d365081718338e824bc3e737d)
by [Unito](https://www.unito.io)
2026-05-02 12:39:12 +00:00
Christian Byrne
3c7781190a feat(website): add llms.txt for GEO discovery by AI search agents (#11830)
## Summary

Adds `/llms.txt` at the apex following the [llms.txt
standard](https://llmstxt.org) — a curated, link-based markdown file
that tells LLM-based search agents (ChatGPT search, Perplexity, Claude
search, Google AI Overviews, etc.) what's most important on the site. It
complements `robots.txt` (crawler permissions) and `sitemap-index.xml`
(URL inventory) by giving AI agents a short, prose-friendly index they
can ingest into a context window.

## What's in the file

28 links across 6 sections:

- **Product** (6) — homepage, Local download, Cloud, Cloud pricing, API,
Enterprise
- **Workflows and Gallery** (2) — gallery + community workflows site
- **Customers and Case Studies** (5) — customers index + 4 named studios
(Series Entertainment, Moment Factory, Ubisoft Chord, Open Story
Movement)
- **Developers and Documentation** (4) — docs.comfy.org, ComfyUI repo,
Comfy-Org GitHub org, registry.comfy.org
- **Company** (6) — about, careers, contact, blog, privacy, terms
- **Optional** (5) — `zh-CN` locale variant, long-form enterprise case
studies, blog posts (de-prioritized per spec — agents can skip if
context-limited)

The intro paragraph names the four product surfaces (Local, Cloud, API,
Enterprise), the named customers, and the use-case industries (VFX &
animation, advertising, gaming, eCommerce/fashion) — so an agent that
ingests only the prose still gets the elevator pitch.

## Verification

- All 28 URLs verified live (`HTTP 200`) before commit.
- File is plain markdown — no build step. Astro/Vercel will serve it
from `apps/website/public/llms.txt` exactly as it serves `robots.txt`
(which lives in the same directory and ships at
`https://comfy.org/robots.txt`).
- Will verify on the Vercel preview deploy after this PR opens that
`curl -sI https://<preview>/llms.txt` returns `200` with a sensible
`content-type`. (`robots.txt` currently serves as `text/plain;
charset=utf-8` — `.txt` will likely do the same; that's fine for AI
agents.)

## Decisions

- **No `llms-full.txt` yet.** That variant inlines full prose of key
pages and requires curating substantive content. Deferred to a follow-up
— the marketing-site pages are mostly Vue-rendered hero/feature blocks
rather than long-form prose, so a meaningful `llms-full.txt` would need
either dedicated copy or a build step that flattens i18n strings +
section text. Tracking separately.
- **No comment line in `robots.txt`.** I considered adding a `# AI
agents: see /llms.txt` comment above the `Sitemap:` directive, but
decided against it: (a) the convention is to probe the well-known path
`/llms.txt` directly, not to discover it via robots.txt; (b)
`robots.txt` was just polished in #11823 with a deliberate compact
design and adding a non-standard comment would muddy that; (c) zero
implementations I checked actually parse robots.txt for llms.txt hints.
Easy to add later if needed.

## Context

Third of three follow-ups from the SEO/GEO sweep on 2026-05-02:

1. ~~Comfy-Router: add `X-Content-Type-Options: nosniff` to apex
security headers~~ (separate PR on `Comfy-Org/comfy-router`)
2. ~~Cloudflare: enable "Always Use HTTPS"~~ (dashboard toggle, no PR)
3. **This PR** — add `llms.txt` for GEO discovery

## Testing

- [x] All linked URLs return 200
- [x] File parses as valid markdown
- [ ] Preview deploy serves `/llms.txt` (will verify once preview is up)

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11830-feat-website-add-llms-txt-for-GEO-discovery-by-AI-search-agents-3546d73d365081a98c6bfc5301699f64)
by [Unito](https://www.unito.io)
2026-05-02 07:16:27 +00:00
Christian Byrne
167a1e6a0c fix(website): override X-Robots-Tag to index,follow on production deployment (#11831)
## P0 SEO fix — entire marketing site is currently `noindex`

A deep-audit sweep on **2026-05-02** confirmed that every page on
`comfy.org` (home, `/about`, `/pricing`, `/customers`, `/careers`, …) is
being served with:

```
x-robots-tag: noindex
```

This hides the entire marketing site from Google and other search
engines.

### Root cause

`comfy.org` reaches the Astro marketing site via a Cloudflare Worker
reverse proxy
([`comfy-router`](https://github.com/Comfy-Org/comfy-router)) that does:

```js
fetch('https://website-frontend-comfyui.vercel.app/...')
```

Per Vercel's KB article [Avoiding duplicate-content with vercel.app
URLs](https://vercel.com/kb/guide/avoiding-duplicate-content-with-vercel-app-urls):

> By default, Vercel adds an `X-Robots-Tag: noindex` HTTP header to all
deployments hosted on `vercel.app` URLs. […] This header tells search
engines like Google not to index these deployment URLs.

Because `website-frontend-comfyui.vercel.app` is **not** registered as a
Production custom domain on the Vercel project, Vercel applies that
header — and our Worker faithfully forwards it back to `comfy.org`
clients (and Googlebot).

### Fix

Vercel's documented workaround for proxied `*.vercel.app` setups is to
override the header via `vercel.json` ([blog post by Dan
Denney](https://www.dandenney.com/posts/front-end-dev/fixing-x-robots-nofollow-with-vercel/)):

```json
"headers": [
  {
    "source": "/(.*)",
    "has": [
      { "type": "host", "value": "website-frontend-comfyui.vercel.app" }
    ],
    "headers": [
      { "key": "X-Robots-Tag", "value": "index, follow" }
    ]
  }
]
```

### Why the `has` host filter

Critical scoping detail: without the `has` filter, the override would
also apply to PR-preview deployments at
`comfy-website-preview-pr-N.vercel.app`. We want previews to **stay**
`noindex` to avoid duplicate-content competition with production.

The filter pins the override to the production deployment hostname only.
The hostname matches `WEBSITE_ORIGIN` in `comfy-router/src/index.js`:

```js
const WEBSITE_ORIGIN = 'https://website-frontend-comfyui.vercel.app';
```

### Defense in depth

A parallel PR on `comfy-router` (TBD) will also strip `X-Robots-Tag:
noindex` at the Worker layer, so the public `comfy.org` response is
correct even if a future Vercel project change re-introduces the
upstream header.

### Verification (after merge + Vercel production deploy)

```bash
# Production should no longer be noindex
curl -sI https://comfy.org/ | grep -i x-robots-tag
curl -sI https://comfy.org/about | grep -i x-robots-tag
curl -sI https://comfy.org/pricing | grep -i x-robots-tag
# Expect: empty output, OR "x-robots-tag: index, follow"

# Direct Vercel production hostname
curl -sI https://website-frontend-comfyui.vercel.app/ | grep -i x-robots-tag
# Expect: "x-robots-tag: index, follow"

# Preview deploys must stay noindex (proves the host filter works)
curl -sI https://comfy-website-preview-pr-<N>.vercel.app/ | grep -i x-robots-tag
# Expect: "x-robots-tag: noindex"
```

### Pre-merge state (for the record)

```
$ curl -sI https://comfy.org/ | grep -iE 'x-robots-tag|x-served-by'
x-served-by: vercel-website
x-robots-tag: noindex
```

### Scope

Minimum delta — only `apps/website/vercel.json`. No other files touched.

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11831-fix-website-override-X-Robots-Tag-to-index-follow-on-production-deployment-3546d73d365081489b62e6633d25dfe5)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Christian Byrne <christian@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
2026-05-01 23:03:25 -07:00
Alexander Brown
e4e1546458 test: add queue notification banners lifecycle browser tests (#11366)
*PR Created by the Glary-Bot Agent*

---

## Summary

- Adds `browser_tests/tests/queueNotificationBanners.spec.ts` covering
`useQueueNotificationBanners` composable E2E behavior
- Adds `data-testid="queue-notification-banner"` to
`QueueNotificationBannerHost.vue` for stable test targeting
- Registers the new test ID in `TestIds.queue.notificationBanner`

### Test coverage added (7 tests)

| Group | Tests | Behavior |
|---|---|---|
| Queuing lifecycle | 4 | `promptQueueing` → banner appears,
`promptQueued` upgrades to queued, batch plural text, requestId mismatch
doesn't upgrade |
| Auto-dismiss | 1 | Banner disappears after 4s timeout |
| FIFO queue | 1 | Second notification shows after first auto-dismisses
|
| Direct queued | 1 | `promptQueued` without prior `promptQueueing`
shows banner directly |

### Approach
Tests dispatch `promptQueueing`/`promptQueued` custom events directly
via `window.app.api.dispatchCustomEvent()` inside `page.evaluate()`,
matching how `app.ts` triggers these events during real queue
operations. This avoids needing a running execution pipeline while
exercising the full composable → component → DOM rendering chain.

### Verification
- TypeScript: zero errors
- ESLint: clean
- oxlint: clean
- oxfmt: formatted
- Playwright execution requires running ComfyUI backend (not available
in sandbox)

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11366-test-add-queue-notification-banners-lifecycle-browser-tests-3466d73d36508172a7ffd3fe3b4fd925)
by [Unito](https://www.unito.io)

---------

Co-authored-by: Glary-Bot <glary-bot@users.noreply.github.com>
Co-authored-by: Amp <amp@ampcode.com>
2026-05-02 05:40:45 +00:00
Christian Byrne
c1954028d1 feat(ci): add Release:Website workflow to refresh Ashby snapshot (#11829)
## Summary

Adds a unified manual-trigger release flow for the `apps/website`
package
(careers/marketing site at comfy.org), mirroring how main-app releases
work.

**User-facing flow:**

```
workflow_dispatch ──► fresh Ashby pull ──► auto-PR with snapshot bump
                                                      │
                                                      ▼
                              existing CI / Vercel preview deploy
                                                      │
                                                      ▼
                                  human merges ──► auto prod deploy
```

The careers data on comfy.org comes from Ashby and is fetched at build
time by
`apps/website/src/utils/ashby.ts`. Without `WEBSITE_ASHBY_API_KEY`, the
build
falls back to a committed snapshot at
`apps/website/src/data/ashby-roles.snapshot.json`. That snapshot has
been
going stale because no CI workflow was passing the API key. This PR
fixes
both: a manual refresh workflow + day-to-day secrets wiring.

## Files

**Added**
- `.github/actions/ashby-pull/action.yaml` — composite action that runs
`pnpm --filter @comfyorg/website ashby:refresh-snapshot` with the Ashby
  secrets piped in. Uses the existing `setup-frontend` composite for
  pnpm/Node setup.
- `.github/workflows/release-website.yaml` — `workflow_dispatch`-only
  release workflow. Checks out `main`, refreshes the snapshot via the
  composite action, opens a PR labelled `Release:Website` via
  `peter-evans/create-pull-request@c0f553fe…` (the same SHA pin used by
  `release-version-bump.yaml`).

**Modified**
- `.github/workflows/ci-website-build.yaml` — adds
`WEBSITE_ASHBY_API_KEY`
  and `WEBSITE_ASHBY_JOB_BOARD_NAME` env to the `Build website` step.
- `.github/workflows/ci-vercel-website-preview.yaml` — adds the same env
  to both `vercel build` steps (preview + production).

## Snapshot fallback preserved

`apps/website/src/utils/ashby.ts` keeps using the committed snapshot
when
the API key is absent (e.g. fork PRs, secret rotation). Verified
locally:

```
$ pnpm --filter @comfyorg/website ashby:refresh-snapshot
Snapshot refresh aborted. Outcome: stale; reason: missing WEBSITE_ASHBY_API_KEY...
```

The release workflow surfaces this as a job failure, which is the
desired
behavior for a manual release trigger.

## Validation

- `yamllint --config-file .yamllint` on all changed YAML — clean
- `./scripts/cicd/check-yaml.sh` — clean
- `pinact run --check` on new files — clean (matches `.pinact.yaml`
policy)
- `pnpm install --frozen-lockfile` — works with `.nvmrc` Node 24
- Husky pre-commit hooks (eslint + typecheck + lint-staged) passed

## Caveats

- **Cannot fully end-to-end test until merged.** `workflow_dispatch`
  workflows only run from branches that exist on `main`. The first
  manual run can only happen after this PR lands. The pieces that
  *can* be tested pre-merge — yamllint, pinact pin validation, and
  the existing `CI: Website Build` / `CI: Vercel Website Preview`
  workflows now picking up the secret — will run on this PR.
- **`Release:Website` label needs to be created** in the repo before
the auto-PR step will successfully apply it.
`peter-evans/create-pull-request`
  will warn but not fail if the label doesn't exist. Suggested color:
  `#4f6ef5` (matches `cloud/*` family in `release-branch-create.yaml`).
- The release workflow uses `secrets.PR_GH_TOKEN` (matching
  `release-version-bump.yaml`) so the auto-PR can be authored by a
  PAT and trigger downstream CI workflows. Without `PR_GH_TOKEN` it
  will fall back behavior is up to GitHub Actions defaults — confirm
  the secret exists before the first run.

## Context

Came out of work on `comfy-router#22` + `ComfyUI_frontend#11823`
(comfy.org/countdown subpage / website refresh). Discovered the
8+-day-stale snapshot while auditing the website build path.

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11829-feat-ci-add-Release-Website-workflow-to-refresh-Ashby-snapshot-3546d73d3650811eb300d8bcb593c652)
by [Unito](https://www.unito.io)
2026-05-02 05:31:00 +00:00
Christian Byrne
5cad2c952b refactor+test: extract useSubscriptionCheckout composable, rewrite tests (#11396)
## Summary

Adds 20 component tests for
`SubscriptionRequiredDialogContentWorkspace.vue` covering:

- **Initial rendering**: pricing table display, close/back button
visibility, out_of_credits reason message
- **Close button**: calls onClose callback
- **Subscribe click flow**: pricing→preview transitions (new
subscription & upgrade), error toasts for disallowed/missing/failed
previews, monthly billing cycle
- **Back button**: returns from preview to pricing step
- **Add credit card**: handles subscribed status (success toast +
close), needs_payment_method (opens Stripe URL), error state
- **Confirm transition**: success path with close emit, error toast on
failure
- **Resubscribe**: success path with toast + close, error toast on
failure

## Testing

```bash
pnpm test:unit -- src/platform/workspace/components/SubscriptionRequiredDialogContentWorkspace.test.ts
```

All 20 tests pass. Quality gates (typecheck, lint, format, knip) pass.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11396-test-add-component-tests-for-SubscriptionRequiredDialogContentWorkspace-3476d73d36508156a218dcb67a2a334e)
by [Unito](https://www.unito.io)
2026-05-02 04:50:44 +00:00
Daxiong (Lin)
e356addeb6 feat: add model links for default workflow (#11308)
We now support detecting the missing models when loading the workflow.
But the default workflow didn't include an embedded model link,

so users don't know where to download the model or which one to use.

Users will see an error when loading the default workflow every time, so
I updated it to include the model link.

Before
<img width="1920" height="1050" alt="image"
src="https://github.com/user-attachments/assets/08774480-78ae-41b4-85bd-64b431079ec1"
/>

After

<img width="1920" height="1050" alt="image"
src="https://github.com/user-attachments/assets/dcec5a02-94ad-416f-9881-d761f4137fbd"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-11308-feat-add-model-links-for-default-workflow-3446d73d365081188978e1d313c38ffe)
by [Unito](https://www.unito.io)

---------

Co-authored-by: GitHub Action <action@github.com>
2026-05-02 04:24:08 +00:00
Christian Byrne
e831daae59 feat(website): point robots.txt at /sitemap-index.xml + AI crawler rules (#11823)
## Summary

Once
[comfy-router#22](https://github.com/Comfy-Org/comfy-router/pull/22)
ships, `comfy.org/sitemap-index.xml` will return a unified index
aggregating both the website (38 URLs) and workflow-templates sitemaps.
This PR:

1. Reverts `Sitemap:` back to `/sitemap-index.xml` (was `/sitemap-0.xml`
in #11802 as a workaround for the 404).
2. Adds explicit allow records for 21 search and AI/LLM crawlers
(GPTBot, ChatGPT-User, OAI-SearchBot, Google-Extended, ClaudeBot,
Claude-Web, anthropic-ai, PerplexityBot, Perplexity-User,
Applebot-Extended, Bytespider, Amazonbot, CCBot, Meta-ExternalAgent,
Meta-ExternalFetcher, Diffbot, etc.).
3. Adds `Disallow:` for `/_astro/`, `/_website/`, `/_vercel/` — Vercel
build artifacts that aren't useful to crawl.

## Why granular UAs

Stacked `User-agent:` records (per [RFC 9309
§2.2](https://datatracker.ietf.org/doc/html/rfc9309#section-2.2)) share
one rule block. Listing each bot explicitly:

- Signals intent to AI bots that look for their UA in robots.txt before
crawling more aggressively.
- Surfaces our crawl policy clearly to anyone inspecting the file.
- Lets us add per-bot Disallows in future without restructuring.

## Merge order

⚠️ **Do NOT merge until comfy-router#22 is deployed to production.**
Until then, `/sitemap-index.xml` returns 404 and this PR would re-break
the issue PR #11802 patched. Verification:

```bash
curl -sI https://comfy.org/sitemap-index.xml
# expect: HTTP/2 200, x-served-by: worker-sitemap-index
```

Once that returns 200, this is safe to merge.

## Verification (after merge + deploy)

```bash
# robots.txt is served and points at the unified index
curl -s https://comfy.org/robots.txt | grep '^Sitemap:'
# → Sitemap: https://comfy.org/sitemap-index.xml

# Each AI crawler can fetch it
for ua in 'GPTBot/1.0' 'ClaudeBot/1.0' 'PerplexityBot/1.0' 'Google-Extended' 'Applebot-Extended'; do
  curl -s -o /dev/null -w "$ua → %{http_code}\n" -A "$ua" https://comfy.org/robots.txt
done

# Sitemap is reachable from robots.txt
SITEMAP=$(curl -s https://comfy.org/robots.txt | awk -F': ' '/^Sitemap:/ {print $2}')
curl -s "$SITEMAP" | xmllint --noout - && echo "valid XML"
```

## Linear / closes

- Closes FE-437 (AI crawler rules)
- Updates FE-432 — the robots.txt change in #11802 was a workaround
that's no longer needed once #22 ships

┆Issue is synchronized with this [Notion
page](https://app.notion.com/p/PR-11823-feat-website-point-robots-txt-at-sitemap-index-xml-AI-crawler-rules-3546d73d3650811dbceedd06c00db444)
by [Unito](https://www.unito.io)
2026-05-01 21:04:45 -07:00