16 Commits

Author SHA1 Message Date
Ethanfel ed322c9ec2 feat: disabled mode (TENACIOUSLOAD_DISABLED=1) — no-op but keep the loading bar
A one-flag kill-switch: when set, the pack installs no middleware, registers no
refresh routes, computes no fingerprint and exposes no graph node — ComfyUI runs
exactly as if it weren't installed. Only the read-only /tenaciousload/status
route stays so the loading-screen overlay still shows (a generic 'Loading node
definitions…' bar, since there's no build to track). The refresh menu buttons
hide themselves when status reports enabled:false.

Useful for A/B testing or as a safety kill-switch. Requires a restart (the
middleware is installed at startup). Unit-tested both modes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 20:52:43 +02:00
Ethanfel 85552d8b25 fix: single-flight object_info build (prevents concurrent-build hang)
The off-loop (threaded) build introduced a concurrency bug: ComfyUI's
cache_helper is a global, so a manual refresh (R) fired while a rebuild was
still running started a SECOND build; when the first finished it cleared the
shared cache_helper, making the second re-walk the CIFS mount per-node = hang.

Now an asyncio lock serialises builds: concurrent object_info requests wait for
the in-flight build and serve its result instead of starting another. Verified:
3 concurrent requests -> exactly one build.

Docs: note that Quick refresh detects changes by directory mtime, which network
mounts (cache=loose CIFS) can report stale/coarse, so it may miss a brand-new
file -- use Full refresh for just-added models.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 09:27:10 +02:00
Ethanfel 86b9e9cf22 feat: loading-screen status overlay (no more silent 'Comfy' splash)
Adds a small status line on ComfyUI's loading splash showing whether
Tenaciousload is serving object_info from cache or building it (live node
count + elapsed time, with a 'scanning model folders over the network' hint
when the CIFS walk stalls progress). Removes itself on the app 'setup' hook.

Backend tracks build progress (_build_state) and exposes GET /tenaciousload/status;
frontend web/loading-status.js polls it and renders an unobtrusive overlay.
Unit-tested progress tracking + status shape.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 09:16:20 +02:00
Ethanfel ddbaa21b10 fix: make input-folder watching opt-in (default off) to keep restarts fast
Folding the input-dir mtime into the cache fingerprint backfired on busy input
folders (e.g. a video workflow constantly adding clips): the input dir changed
on nearly every restart, invalidating the cache and forcing a ~5-min rebuild of
the (now 74 MB) object_info over the CIFS model mount on each load -- the exact
slowness the pack exists to avoid.

Input watching is now opt-in via TENACIOUSLOAD_WATCH_INPUT=1. By default new
input files are picked up via a refresh button, same as new models. Node code
changes are still auto-detected. Unit-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 08:50:57 +02:00
Ethanfel 0d2b5e0819 fix: detect new input-folder files across restarts
Same root cause as the node-update bug: the input file list (LoadImage etc. do
os.listdir(input) in INPUT_TYPES) is baked into the cached object_info, which
persists across restarts, so new input files were invisible until a manual
refresh. The input dir is listed non-recursively, so its own mtime reliably
flags add/remove -- fold it (one stat) into the node fingerprint so a restart
picks up new input files. Model folders are nested + on a slow mount, so they
are intentionally not fingerprinted (use a refresh button for new models).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 11:59:05 +02:00
Ethanfel fcd7c49da5 fix: detect in-place node updates (not just install/remove)
The node-set fingerprint only hashed NODE_CLASS_MAPPINGS keys, so updating an
existing node (new feature, same class name) didn't change it -> the stale
object_info kept being served across restarts and the update never appeared
(removing Tenaciousload 'fixed' it because the cache was gone).

Now the fingerprint also hashes every custom-node .py path+mtime, so an in-place
update (git pull/edit) changes it and the cache auto-invalidates on the next
restart -- which is when node code reloads anyway, so the update just shows up.
__pycache__/.git/node_modules are skipped (no false positives). Measured 0.27s
for 4268 .py files; runs once per startup. Unit-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 11:56:09 +02:00
Ethanfel 04f6271867 fix: build object_info off the event loop so a slow mount can't hang ComfyUI
Root cause of 'refresh hangs ComfyUI': object_info is built by walking the model
folders synchronously on the single aiohttp event loop. When the model tree is on
a slow/stalling network mount (CIFS), that walk blocks in 'wait_for_response' and
freezes the entire UI until the NAS answers.

Fix:
- Run the object_info build in a worker thread (folder-walk syscalls release the
  GIL, so the loop stays responsive). Uses ComfyUI's real node_info, resolved
  from the /object_info route closure, with a safe fallback to the in-loop build.
- Offload the Quick scan and Register work to a thread too (POST no longer freezes).
- Guard the incremental scanner against symlink cycles (visited realpaths).

Unit-tested: threaded build bypasses the in-loop handler; node_info resolves;
cycle guard terminates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 11:51:45 +02:00
Ethanfel 4a1c2f3a99 feat: auto-invalidate cache when installed node set changes
Fingerprints NODE_CLASS_MAPPINGS; on the first object_info request after a
restart, drops the cached object_info if a node was installed/updated/enabled/
removed, so new nodes appear without a manual refresh. First run (no stored
signature) does not invalidate. Unit-tested.

Also documents that the pack has no deps and does not interfere with other
nodes' installs/updates or their own routes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:16:39 +02:00
Ethanfel a8d8b3792c feat: add Quick (incremental) and Register refresh modes
- quick:    incremental rescan — re-walks only folders whose mtime changed
            (per-dir snapshot persisted to cache/scan_snapshot.json); reuses
            the cache for unchanged folders. Catches new/removed/renamed files.
- register: append specific file path(s) with NO folder walk (instant disk-wise)
- full:     unchanged default (clear cache -> full re-walk)

Frontend exposes all three as Extensions-menu commands; the graph node gains a
quick/full mode widget. POST /tenaciousload/refresh now takes {mode, folder, files}.
Unit-tested: incremental scan rescans only the changed dir; register adds/skips.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 01:25:12 +02:00
Ethanfel 55a23d0fe9 docs: add PNG exports of banner + how-it-works (2x) for sharing
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 00:56:12 +02:00
Ethanfel fa6f78220c docs: add 1280x640 social preview card (SVG source + PNG)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 00:44:57 +02:00
Ethanfel 0084c0bd12 docs: soften remaining 'milliseconds' in alt-text for consistency
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 00:42:05 +02:00
Ethanfel e3a8af5a53 docs: honest 'minutes -> seconds' framing + document --enable-compress-response-body
- banner/diagram: replace localhost '4 ms' (server-only) with the real
  page-load experience (minutes -> seconds); soften tagline to 'Fast'
- README: add section on the optional --enable-compress-response-body flag
  for gzipping the rest of ComfyUI (frontend scripts, other APIs)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 00:41:41 +02:00
Ethanfel f2df35f04c fix(banner): widen 'cold build' pill so text no longer clips
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 00:31:08 +02:00
Ethanfel ee1932a534 docs: add banner + how-it-works SVG diagrams to README
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 00:28:12 +02:00
Ethanfel 2c1777ae4e Initial commit: in-process object_info cache + refresh UI
ComfyUI-Tenaciousload speeds up ComfyUI page loads for large model/LoRA
collections by caching the slow /api/object_info response in memory and on
disk (survives restarts) and serving it gzipped in ~milliseconds, instead of
rebuilding it (and freezing the event loop) on every load.

Adds a "Refresh Models / LoRAs" menu button, a graph node, and a
POST /tenaciousload/refresh endpoint to rebuild the cache after adding or
removing models. No external dependencies; no nginx/docker required.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 00:25:41 +02:00