Skip to content

feat: live-refresh public data sources; make gallery a CQL engine#474

Open
skishore23 wants to merge 3 commits into
mainfrom
fix/live-refresh-data-sources
Open

feat: live-refresh public data sources; make gallery a CQL engine#474
skishore23 wants to merge 3 commits into
mainfrom
fix/live-refresh-data-sources

Conversation

@skishore23

Copy link
Copy Markdown
Contributor

Summary

Replaces hand-maintained / stale bundled data with live-refresh from the public Comfy repos, removes dead CQL-grammar artifacts that were never implemented, and cleans up the templates/CQL architecture.

Motivation: several data sets were either frozen until a pip install -U (node annotations), advertised features that didn't exist (--query CQL grammar, comfy query), or pointed at dead endpoints (api.comfy.org/openapi.yml → 404). This makes the public-repo data sources refresh themselves while staying offline-safe.

Changes

Data freshness — live fetch + 7-day TTL cache + offline fallback

  • Node annotations (supported_nodes.yaml, cloud_disable_config.yaml) now resolve via new cql/annotations_source.py: TTL-fresh cache → live fetch from Comfy-Org/comfy-complete → bundled snapshot fallback. The no-op comfy nodes refresh is repurposed to force a re-fetch. COMFY_CLI_NO_REMOTE_REFRESH=1 disables network for airgapped/CI.
  • Gallery (templates/index.json) brought to parity: 7-day TTL auto-refresh + graceful fall back to stale cache when offline (it previously cached forever and errored offline).

Architecture — gallery is now a proper CQL engine

  • Extracted the gallery-search engine (port of gallery_search.go predicates) out of command/templates.py into cql/gallery.py, so it sits beside the node-graph engine (cql/engine.py) and command/templates.py becomes a thin shell — mirroring how command/nodes.py wraps cql.engine.Graph.

Dead data / code removal

  • Deleted no_gpu_nodes.json (upstream source gone, file always empty) and the needs_gpu field / parse_no_gpu_nodes / annotate+load params it fed.
  • Removed the templates --query CQL stub (the grammar was never ported; it only ever returned an error), the now-orphaned cql_query_invalid error code, and its stale skill-doc section.
  • Removed fictional comfy query references (help_json examples + a run_cli demo step that invoked a non-existent command). The demo step now showcases the real flag-based comfy nodes commands.
  • Tightened the cql.data package-data glob to *.yaml.

generate refresh

  • Fails gracefully on the now-404 api.comfy.org/openapi.yml: explains the partner catalog ships bundled and updates via pip install -U, instead of dumping a raw HTTP error. (No public partner-proxy spec exists to live-refresh from.)

Tests

  • New cql/test_annotations_source.py and cql/test_gallery.py (TTL, stale-fallback, offline behavior, fetch-and-cache).
  • Coverage for nodes refresh and templates --query removal.
  • All suites pass, ruff clean.

Notes

  • The partner generation catalog (generate) remains bundled — there is no public machine-readable source for it, so it intentionally still updates via release. Everything with a public source now live-refreshes.

Replace hand-maintained / stale bundled data with live-refresh from the
public Comfy repos, and fix the architecture around CQL + templates.

Data freshness (live fetch + TTL cache + offline fallback):
- Node annotations (supported_nodes.yaml, cloud_disable_config.yaml) now
  resolve via new cql/annotations_source.py: 7-day TTL cache -> live fetch
  from Comfy-Org/comfy-complete -> bundled snapshot fallback. Repurpose the
  no-op `comfy nodes refresh` to force a re-fetch. COMFY_CLI_NO_REMOTE_REFRESH
  disables network for airgapped/CI.
- Gallery (templates/index.json) brought to parity: 7-day TTL auto-refresh
  and graceful fall back to stale cache when offline (previously cached
  forever and errored offline).

Remove dead data / code:
- Delete no_gpu_nodes.json (upstream source gone, file always empty) and the
  needs_gpu field / parse_no_gpu_nodes / annotate+load params it fed.
- Remove the templates `--query` CQL stub (the grammar was never ported; it
  only ever returned an error) plus the now-orphaned cql_query_invalid error
  code and its stale skill-doc section.
- Remove fictional `comfy query` references (help_json examples + run_cli demo
  step that invoked a non-existent command); the run_cli step now demos the
  real flag-based `comfy nodes` commands.
- Tighten cql.data package-data glob to *.yaml.

Architecture:
- Extract the gallery-search engine (port of gallery_search.go predicates)
  out of command/templates.py into cql/gallery.py, so it sits beside the
  node-graph engine (cql/engine.py) and command/templates.py is a thin shell
  -- mirroring how command/nodes.py wraps cql.engine.Graph.

generate refresh:
- Fail gracefully on the now-404 api.comfy.org/openapi.yml: explain the
  partner catalog ships bundled and updates via `pip install -U` instead of
  dumping a raw HTTP error.

Tests: add cql/test_annotations_source.py and cql/test_gallery.py; cover
nodes refresh and templates --query removal. All suites pass, ruff clean.
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. enhancement New feature or request labels Jun 25, 2026
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds gallery and annotation refresh helpers, rewires template and node commands to use them, removes query-based CLI references and related metadata, and updates partner catalog refresh error handling.

Changes

Gallery, annotations, and query cleanup

Layer / File(s) Summary
Gallery engine
comfy_cli/cql/gallery.py, tests/comfy_cli/cql/test_gallery.py
Adds gallery index caching, template workflow fetching, row flattening/filtering, and tests covering cached loading, stale fallback, and GalleryError paths.
Annotation source
comfy_cli/cql/annotations_source.py, tests/comfy_cli/cql/test_annotations_source.py, pyproject.toml
Adds cache-backed resolution for supported-node and cloud-disable YAML, plus tests for bundled, cached, refresh, and disabled-network cases; package data is limited to YAML files.
Engine annotation loading
comfy_cli/cql/engine.py
Removes needs_gpu and no_gpu_json support from graph annotation and serialization, and switches default annotation loading to annotations_source.load_annotation_bytes().
Template commands
comfy_cli/command/templates.py, comfy_cli/schemas/templates.json, tests/comfy_cli/command/test_templates.py
Routes templates subcommands through gallery, removes --query, updates workflow fetch output/schema, and adjusts CLI tests to the new gallery-backed entry points.
Nodes refresh
comfy_cli/command/nodes.py, comfy_cli/command/run_cli.py, tests/comfy_cli/command/test_nodes_cli.py
Makes nodes refresh call annotations_source.refresh_annotations(), updates the demo step sequence to use comfy nodes, and adds refresh-command tests.
Query cleanup
comfy_cli/error_codes.py, comfy_cli/help_json.py, comfy_cli/skills/comfy-debug/SKILL.md
Removes the cql_query_invalid registry entry and the remaining comfy query help and skill references.

Partner catalog refresh handling

Layer / File(s) Summary
Partner catalog refresh
comfy_cli/command/generate/app.py
Treats HTTP 404 from the partner catalog fetch as a successful bundled-catalog fallback and exits 0; other httpx.HTTPStatusError cases still print a failure message and exit 1.

Possibly related PRs

  • Comfy-Org/comfy-cli#470: Both PRs touch the node-introspection and annotation-refresh path, including comfy_cli/command/nodes.py and comfy_cli/cql/engine.py.

Suggested reviewers

  • luke-mino-altherr
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/live-refresh-data-sources
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/live-refresh-data-sources

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot requested a review from luke-mino-altherr June 25, 2026 05:12

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
comfy_cli/command/templates.py (1)

219-232: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

refresh_cmd caches fetch_gallery() bytes without validating JSON.

Same family as the gallery.load_gallery concern: Line 228 writes the fetched bytes to the cache before any parse, so a non-JSON 200 response would persist a broken index that later templates ls reads as fresh. A quick json.loads(data) guard before write_bytes keeps the cache honest — no junk in the trunk.

🛡️ Proposed guard
     cache = gallery.cache_path()
+    try:
+        json.loads(data)  # don't cache a non-JSON body
+    except json.JSONDecodeError as e:
+        renderer.error(code="gallery_fetch_failed", message=f"remote returned non-JSON: {e}")
+        raise typer.Exit(code=1) from e
     cache.parent.mkdir(parents=True, exist_ok=True)
     cache.write_bytes(data)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/command/templates.py` around lines 219 - 232, `refresh_cmd` writes
the result of `gallery.fetch_gallery()` directly to the cache without verifying
it is valid JSON, so a successful but non-JSON response can poison the cached
gallery. Add a JSON validation step in `refresh_cmd` (using the fetched bytes
before `cache.write_bytes`) and fail with the existing error handling path if
parsing fails, so only valid gallery data is persisted; use the
`gallery.fetch_gallery`, `cache.write_bytes`, and `renderer.error` flow to
locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy_cli/cql/annotations_source.py`:
- Around line 82-93: The synchronous _fetch path in _resolve_one is blocking
comfy nodes on the default annotations load, so change the fallback behavior to
avoid waiting on network I/O in the hot path. Update _try_default_annotations
and/or _resolve_one so stale or bundled data is returned immediately, then
refresh the cache in the background, or fetch the two entries from _FILES
concurrently to reduce total latency. Keep the existing stale-cache and bundled
fallback logic intact and preserve the current cache write behavior in
annotations_source.py.

In `@comfy_cli/cql/gallery.py`:
- Around line 87-97: The gallery cache path in fetch_gallery() is writing raw
fetch_gallery() bytes to disk before validating them, which can poison the cache
with non-JSON payloads. Update the fetch-and-cache flow in gallery.py so the
data is parsed with json.loads(data) first, and only after that succeeds should
cache.write_bytes(data) run. Keep the existing fallback behavior for
cache.is_file() and the GalleryError path, but ensure only valid JSON ever
reaches the cache.

In `@tests/comfy_cli/cql/test_gallery.py`:
- Around line 98-152: Add a regression test in the gallery load suite for the
poisoned-cache path: when `gallery.load_gallery` calls `fetch_gallery` and
receives non-JSON bytes, it should fail before persisting anything. Reuse the
existing `test_load_gallery_fetches_and_caches` style with `monkeypatch` on
`gallery.cache_path` and `gallery.fetch_gallery`, then assert the cache file
does not exist or remains unwritten after the bad payload. This should
specifically cover the parse-before-write behavior in `load_gallery` so a
malformed upstream response cannot populate the cache.

---

Outside diff comments:
In `@comfy_cli/command/templates.py`:
- Around line 219-232: `refresh_cmd` writes the result of
`gallery.fetch_gallery()` directly to the cache without verifying it is valid
JSON, so a successful but non-JSON response can poison the cached gallery. Add a
JSON validation step in `refresh_cmd` (using the fetched bytes before
`cache.write_bytes`) and fail with the existing error handling path if parsing
fails, so only valid gallery data is persisted; use the `gallery.fetch_gallery`,
`cache.write_bytes`, and `renderer.error` flow to locate the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1735287c-0352-49ac-a93f-7f89c8791e9b

📥 Commits

Reviewing files that changed from the base of the PR and between 7e87c77 and 51d131b.

📒 Files selected for processing (16)
  • comfy_cli/command/generate/app.py
  • comfy_cli/command/nodes.py
  • comfy_cli/command/run_cli.py
  • comfy_cli/command/templates.py
  • comfy_cli/cql/annotations_source.py
  • comfy_cli/cql/data/no_gpu_nodes.json
  • comfy_cli/cql/engine.py
  • comfy_cli/cql/gallery.py
  • comfy_cli/error_codes.py
  • comfy_cli/help_json.py
  • comfy_cli/skills/comfy-debug/SKILL.md
  • pyproject.toml
  • tests/comfy_cli/command/test_nodes_cli.py
  • tests/comfy_cli/command/test_templates.py
  • tests/comfy_cli/cql/test_annotations_source.py
  • tests/comfy_cli/cql/test_gallery.py
💤 Files with no reviewable changes (4)
  • comfy_cli/skills/comfy-debug/SKILL.md
  • comfy_cli/help_json.py
  • comfy_cli/cql/data/no_gpu_nodes.json
  • comfy_cli/error_codes.py

Comment on lines +82 to +93
# Try the network when allowed and either forced or the cache is stale/missing.
if not _network_disabled():
try:
data = _fetch(filename)
try:
cache.parent.mkdir(parents=True, exist_ok=True)
cache.write_bytes(data)
except OSError:
pass # cache write is best-effort
return data
except Exception:
pass # fall through to stale cache / bundled

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Hot-path fetch can stall comfy nodes for up to ~10s once per TTL window.

When the cache goes stale, _resolve_one performs a synchronous _fetch (5s timeout) per file, sequentially across both _FILES, on the implicit load path invoked by _try_default_annotations. On a slow or flaky link that's a noticeable, blocking lag for a routine introspection command — not a bug, but a UX wrinkle worth ironing.

Consider serving the stale cache immediately and refreshing in the background, or fetching the two files concurrently to halve the worst case. The bundled/stale fallbacks already keep correctness intact.

🧰 Tools
🪛 Pylint (4.0.6)

[warning] 92-92: Catching too general exception Exception

(W0718)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/cql/annotations_source.py` around lines 82 - 93, The synchronous
_fetch path in _resolve_one is blocking comfy nodes on the default annotations
load, so change the fallback behavior to avoid waiting on network I/O in the hot
path. Update _try_default_annotations and/or _resolve_one so stale or bundled
data is returned immediately, then refresh the cache in the background, or fetch
the two entries from _FILES concurrently to reduce total latency. Keep the
existing stale-cache and bundled fallback logic intact and preserve the current
cache write behavior in annotations_source.py.

Source: Linters/SAST tools

Comment thread comfy_cli/cql/gallery.py
Comment on lines +87 to +97
try:
data = fetch_gallery()
except (GalleryError, OSError) as e:
# Fetch failed — fall back to whatever cache we have (even if stale).
if cache.is_file():
return json.loads(cache.read_bytes())
raise GalleryError(f"gallery unavailable and no cache present: {e}") from e

cache.parent.mkdir(parents=True, exist_ok=True)
cache.write_bytes(data)
return json.loads(data)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate JSON before writing the cache to avoid a week-long poisoned cache.

fetch_gallery() returns raw bytes that are written to disk at Line 96 before json.loads(data) runs at Line 97. If upstream serves a 200 with non-JSON (an HTML error/interstitial page, a truncated body, etc.), the bad bytes get cached and stamped fresh. Since _is_fresh only checks st_mtime, every subsequent load for the next 7 days reads that poisoned cache and re-raises JSONDecodeError — and even the offline fallback path at Lines 91-92 reads the same broken bytes. Parse first, then write, so only valid payloads ever land in the cache. An ounce of parse-then-cache prevents a week of crash-and-gasp.

🛡️ Proposed fix: parse before persisting
     try:
         data = fetch_gallery()
     except (GalleryError, OSError) as e:
         # Fetch failed — fall back to whatever cache we have (even if stale).
         if cache.is_file():
             return json.loads(cache.read_bytes())
         raise GalleryError(f"gallery unavailable and no cache present: {e}") from e

-    cache.parent.mkdir(parents=True, exist_ok=True)
-    cache.write_bytes(data)
-    return json.loads(data)
+    parsed = json.loads(data)  # validate before persisting to avoid caching garbage
+    cache.parent.mkdir(parents=True, exist_ok=True)
+    cache.write_bytes(data)
+    return parsed
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try:
data = fetch_gallery()
except (GalleryError, OSError) as e:
# Fetch failed — fall back to whatever cache we have (even if stale).
if cache.is_file():
return json.loads(cache.read_bytes())
raise GalleryError(f"gallery unavailable and no cache present: {e}") from e
cache.parent.mkdir(parents=True, exist_ok=True)
cache.write_bytes(data)
return json.loads(data)
try:
data = fetch_gallery()
except (GalleryError, OSError) as e:
# Fetch failed — fall back to whatever cache we have (even if stale).
if cache.is_file():
return json.loads(cache.read_bytes())
raise GalleryError(f"gallery unavailable and no cache present: {e}") from e
parsed = json.loads(data) # validate before persisting to avoid caching garbage
cache.parent.mkdir(parents=True, exist_ok=True)
cache.write_bytes(data)
return parsed
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/cql/gallery.py` around lines 87 - 97, The gallery cache path in
fetch_gallery() is writing raw fetch_gallery() bytes to disk before validating
them, which can poison the cache with non-JSON payloads. Update the
fetch-and-cache flow in gallery.py so the data is parsed with json.loads(data)
first, and only after that succeeds should cache.write_bytes(data) run. Keep the
existing fallback behavior for cache.is_file() and the GalleryError path, but
ensure only valid JSON ever reaches the cache.

Comment on lines +98 to +152
def test_load_gallery_fetches_and_caches(tmp_path, monkeypatch):
monkeypatch.setattr(gallery, "cache_path", lambda: tmp_path / "g" / "index.json")
payload = json.dumps(CATEGORIES[:1]).encode()
monkeypatch.setattr(gallery, "fetch_gallery", lambda *a, **k: payload)
cats = gallery.load_gallery(None, refresh=True)
assert cats[0]["title"] == "Image"
# Cached to disk; a second non-refresh load reads cache without fetching.
monkeypatch.setattr(gallery, "fetch_gallery", lambda *a, **k: pytest.fail("should use cache"))
again = gallery.load_gallery(None)
assert again[0]["title"] == "Image"


def test_load_gallery_refetches_when_cache_stale(tmp_path, monkeypatch):
cache = tmp_path / "g" / "index.json"
cache.parent.mkdir(parents=True)
cache.write_bytes(json.dumps([{"title": "OldImage", "type": "image", "templates": []}]).encode())
# Age the cache past the TTL.
import os

old = time.time() - gallery._CACHE_TTL_SECONDS - 100
os.utime(cache, (old, old))
monkeypatch.setattr(gallery, "cache_path", lambda: cache)
monkeypatch.setattr(gallery, "fetch_gallery", lambda *a, **k: json.dumps(CATEGORIES[:1]).encode())

cats = gallery.load_gallery(None)
assert cats[0]["title"] == "Image" # fetched fresh, not the stale "OldImage"


def test_load_gallery_falls_back_to_stale_cache_when_offline(tmp_path, monkeypatch):
cache = tmp_path / "g" / "index.json"
cache.parent.mkdir(parents=True)
cache.write_bytes(json.dumps([{"title": "StaleImage", "type": "image", "templates": []}]).encode())
old = time.time() - gallery._CACHE_TTL_SECONDS - 100
import os

os.utime(cache, (old, old))
monkeypatch.setattr(gallery, "cache_path", lambda: cache)

def offline(*a, **k):
raise gallery.GalleryError("network down")

monkeypatch.setattr(gallery, "fetch_gallery", offline)
cats = gallery.load_gallery(None)
assert cats[0]["title"] == "StaleImage" # degraded gracefully to stale cache


def test_load_gallery_errors_when_offline_and_no_cache(tmp_path, monkeypatch):
monkeypatch.setattr(gallery, "cache_path", lambda: tmp_path / "g" / "index.json")

def offline(*a, **k):
raise gallery.GalleryError("network down")

monkeypatch.setattr(gallery, "fetch_gallery", offline)
with pytest.raises(gallery.GalleryError, match="no cache present"):
gallery.load_gallery(None)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Solid cache/offline coverage — consider one more case for the poisoned-cache path.

The load tests cover explicit-path, fetch+cache, stale-refetch, offline-stale-fallback, and offline-no-cache nicely. If you adopt the parse-before-write fix flagged in gallery.py, add a regression test where fetch_gallery returns non-JSON bytes and assert the cache file is not written, so a bad upstream body can't haunt the cache.

🧰 Tools
🪛 ast-grep (0.44.0)

[info] 99-99: use jsonify instead of json.dumps for JSON output
Context: json.dumps(CATEGORIES[:1])
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 112-112: use jsonify instead of json.dumps for JSON output
Context: json.dumps([{"title": "OldImage", "type": "image", "templates": []}])
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 119-119: use jsonify instead of json.dumps for JSON output
Context: json.dumps(CATEGORIES[:1])
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 128-128: use jsonify instead of json.dumps for JSON output
Context: json.dumps([{"title": "StaleImage", "type": "image", "templates": []}])
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🪛 Pylint (4.0.6)

[convention] 98-98: Missing function or method docstring

(C0116)


[convention] 110-110: Missing function or method docstring

(C0116)


[convention] 115-115: Import outside toplevel (os)

(C0415)


[warning] 117-117: Access to a protected member _CACHE_TTL_SECONDS of a client class

(W0212)


[convention] 126-126: Missing function or method docstring

(C0116)


[warning] 130-130: Access to a protected member _CACHE_TTL_SECONDS of a client class

(W0212)


[convention] 131-131: Import outside toplevel (os)

(C0415)


[convention] 144-144: Missing function or method docstring

(C0116)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/comfy_cli/cql/test_gallery.py` around lines 98 - 152, Add a regression
test in the gallery load suite for the poisoned-cache path: when
`gallery.load_gallery` calls `fetch_gallery` and receives non-JSON bytes, it
should fail before persisting anything. Reuse the existing
`test_load_gallery_fetches_and_caches` style with `monkeypatch` on
`gallery.cache_path` and `gallery.fetch_gallery`, then assert the cache file
does not exist or remains unwritten after the bad payload. This should
specifically cover the parse-before-write behavior in `load_gallery` so a
malformed upstream response cannot populate the cache.

…-out

`comfy --json templates fetch <name>` (no --out) previously returned only
metadata — the documented `data.workflow` field was never populated, so a JSON
consumer had no way to retrieve the fetched workflow. Include the parsed
workflow under `data.workflow` when there's no file destination (pretty mode
already streams it to stdout); omit it with --out since it's on disk. Document
the field in schemas/templates.json and add tests for both paths.

Found via subagent CLI testing of the CQL command surface.
…-robust

- Apply `ruff format` to nodes.py + test_nodes_cli.py (CI runs
  `ruff format --diff`, which I'd missed locally).
- test_ls_query_option_removed asserted on Rich-rendered error text that wraps
  by terminal width; assert only on Click's exit code 2 (usage error), the
  stable cross-environment signal.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy_cli/command/nodes.py`:
- Around line 889-891: The bundled-fallback message in refresh_annotations
output is too failure-like for the intentional COMFY_CLI_NO_REMOTE_REFRESH path.
Update the rprint wording in nodes.py so the refresh flow uses neutral “bundled”
fallback language instead of “remote fetch failed,” and let the existing
error/reason field from refresh_annotations convey why the bundled snapshot was
used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 00173e53-033c-4108-bc84-dd1a5a80f4b4

📥 Commits

Reviewing files that changed from the base of the PR and between 4720d3f and b43914c.

📒 Files selected for processing (3)
  • comfy_cli/command/nodes.py
  • tests/comfy_cli/command/test_nodes_cli.py
  • tests/comfy_cli/command/test_templates.py

Comment on lines +889 to +891
rprint(
f"[yellow]![/yellow] {r['name']}: remote fetch failed, using bundled snapshot "
f"([dim]{r.get('error', '')}[/dim])"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use neutral bundled-fallback wording.

When COMFY_CLI_NO_REMOTE_REFRESH is set, refresh_annotations() returns source: "bundled" with an error explaining remote refresh is disabled, so this pretty output reports an intentional airgapped path as a failure. Tiny wording goblin: let the reason carry the why.

Proposed wording tweak
                 rprint(
-                    f"[yellow]![/yellow] {r['name']}: remote fetch failed, using bundled snapshot "
-                    f"([dim]{r.get('error', '')}[/dim])"
+                    f"[yellow]![/yellow] {r['name']}: using bundled snapshot "
+                    f"([dim]{r.get('error') or 'remote unavailable'}[/dim])"
                 )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
rprint(
f"[yellow]![/yellow] {r['name']}: remote fetch failed, using bundled snapshot "
f"([dim]{r.get('error', '')}[/dim])"
rprint(
f"[yellow]![/yellow] {r['name']}: using bundled snapshot "
f"([dim]{r.get('error') or 'remote unavailable'}[/dim])"
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/command/nodes.py` around lines 889 - 891, The bundled-fallback
message in refresh_annotations output is too failure-like for the intentional
COMFY_CLI_NO_REMOTE_REFRESH path. Update the rprint wording in nodes.py so the
refresh flow uses neutral “bundled” fallback language instead of “remote fetch
failed,” and let the existing error/reason field from refresh_annotations convey
why the bundled snapshot was used.

@skishore23

Copy link
Copy Markdown
Contributor Author

I have read and agree to the Contributor License Agreement

comfy-legal added a commit to Comfy-Org/comfy-cla that referenced this pull request Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant