Files
ComfyAssets-ComfyUI_PromptM…/tools/vendor
Vito 69de20a427 feat(system): Sources & scans (#309)
* feat(system): report configured, effective and watched sources

GET /prompt_manager/settings adds settings.monitoring_enabled, a sources
block (configured roots with valid/code/reason, effective roots with their
listing index and watch state, auto_detected) and the monitor state
(present, observer_alive, scheduled). Every path is a public path.

A source is "watching" only while a live observer scheduled it, "manual"
when monitoring is off or the process has no monitor, and otherwise
"restart_pending".

POST accepts monitoring_enabled as a strict bool, saved under
gallery.monitoring.enabled; restart_required_fields names it when the
running observer does not already match. A save that changes the sources
runs as a "Source change" records hold, so it is refused with 409 busy
while a scan runs. Case variants of one folder are saved once.

POST /prompt_manager/settings/validate-source {path} checks a path
lexically (no "..", no control characters, native path forms only) and
then against the gallery-root rules, answering a code and reason, and
writes nothing.

* fix(system): no existence oracle in source validation

A gallery root's containment in the allowed ComfyUI folders is now
decided before its existence and type, so a path outside them answers
"outside-allowed" whether or not it exists. validate-source also folds
the filesystem-root and home-directory codes into "outside-allowed", with
one reason, and logs the detail server-side only. Paths inside the
allowed folders still say "not-found" or "not-directory". The legacy
settings save shares the same check.

* feat(scan): scan one selected source

POST /prompt_manager/jobs/scan accepts roots: indexes into the effective
sources, strict non-negative ints (no bools or floats), deduplicated, at
most 64, non-empty when present. An index past the sources is a 400
"unknown-source" and starts nothing. The job walks only the selected
sources, resolved when it was requested, and keeps each file's listing
root_index. Its scope records files, roots (null for every source) and
output_folders, the number of folders walked, which the log's first line
counts. The legacy /scan route still scans every source, and attaching to
a scoped job keeps its payload keys.

* feat(system): manage sources and start scans natively

System > Sources & scans renders the concept's section on the server's
sources: one row per effective source with its watch state and a scan
scoped to that source, the 3.2.0 update notice with the legacy dismissal,
Add source checked by validate-source, Remove, monitoring and worker
threads as host drafts behind the one Save row, and Refresh files.
A save refused by a running scan names the job. Thumbnail generation
hands off to the legacy gallery until S5.

Deviations D98, D113 and D-NEW-S4-1 are recorded in TESTING.md.

* fix(security): decide source containment as text before any filesystem access

Every caller (validate-source, POST /settings, config.json at load) now
refuses a source through one check, sources.source_problem: the form
check first, then GalleryConfig.gallery_root_problem, which compares the
normalised spelling with the allowed folders before anything resolves,
stats or opens the path. A UNC share, the \\?\ and \\.\ namespaces, a
device or any outside folder is refused with no SMB request, no
executor stall and no existence or timing oracle; only then is the path
resolved and contained again, which still catches a symlink out. The
filesystem root and the home directory answer outside-allowed with the
same reason as any outside path, so no caller learns the home path.

Also:
- POST /settings runs the form checks and parses the roots off the loop;
  an unusable source is a coded 400 invalid-source naming its public
  path (as text) and its index.
- ComfyUI folders outside the base directory are path anchors, so their
  sources round-trip and never collide by folder name.
- A per-source scan sends each index with its public path; a stale or
  shifted index is 409 sources-changed and starts nothing.
- A source still watched after monitoring was switched off is
  "stopping".
- Roots are compared as folders, not spellings, so an unchanged legacy
  resend takes no source-change hold.
- Tests: no realpath/stat/lstat of an outside path (native and Windows
  forms with ntpath fakes), the alike answers with /, ~ and a link to ~,
  an event instead of a timer wait, and a teardown that drains jobs
  before the temporary database goes.

* fix(system): say what Sources saved, refused and still watches

- A per-source scan sends the source's public path; when the sources
  changed since they were read the toast says the server's reason and
  the list and saved values are read again.
- "watching until restart" for a source the running monitor still
  watches after monitoring was saved off, and the status adds "Restart
  ComfyUI to apply: Watch for new outputs." from restart_required_fields.
- A save refused for one unusable source marks that row and the status
  is the server's message naming it.
- A valid configured source the effective list holds under another
  spelling reads "same folder as another source".
- The busy toast names the job the 409 named (ApiError keeps a
  validated running job and refused source), falling back to the list.
- The Add source dialog's listeners live on the page scope and Enter
  adds; its markup is compared with the concept (D127).
- TESTING.md: D-NEW-S4-1 is D127; D-NEW-S4-2 records the new copy; the
  Sources contract describes the lexical containment, invalid-source and
  sources-changed.

* fix(security): guard the Windows form probes on a token of their own

The no-filesystem guard matched "C:", which on a Windows runner is also
the temporary ComfyUI tree the save may resolve for its trusted first
entry. The probe paths now carry a token no trusted directory holds.

* docs(system): number the Sources states deviation D128
2026-10-23 13:15:06 -07:00
..

Viewer.js maintenance

ComfyUI serves the committed files in web/lib/viewerjs/. Node and npm are only needed by maintainers and CI. Keep upstream files pristine; application behavior belongs in web/js/, and theme overrides belong in comfyui-theme.css.

Install and verify

Use Node 24 or newer. From the repository root:

npm ci --prefix tools/vendor --ignore-scripts
npm run --prefix tools/vendor check
npm run --prefix tools/vendor test
node --test tests/js/*.test.js
npx --prefix tools/vendor playwright install chromium
npm run --prefix tools/vendor test:browser

On Linux, use playwright install --with-deps chromium when browser system libraries are missing. The browser tests use synthetic images and mock the ComfyUI API boundary; they run production viewer methods and the committed Viewer.js JS/CSS, without a running ComfyUI instance.

check is read-only and fails if any JS, CSS, license, or provenance file differs from the installed package. The manifest, lockfile, installed package, and asset version banners must agree. The lockfile records npm's archive integrity; provenance.json records the upstream source, package integrity, and SHA-256 of each copied file. A normal npm ci --ignore-scripts verifies archive integrity.

Full-page workflows, frontend coverage gates, and required merge checks are documented in TESTING.md. The viewerjs CI check runs both the fixture tests above and the real-page workflows on every PR.

Update

npm run --prefix tools/vendor update
# Or select a specific stable version:
npm run --prefix tools/vendor update -- --version 1.15.2

The command installs an exact version with lifecycle scripts disabled and copies dist/viewer.min.js, dist/viewer.min.css, and LICENSE. It writes deterministic provenance with no timestamps. Repeat the checks above and commit the manifest, lockfile, and all vendor files together. To regenerate files from the current pin without changing versions, run npm run --prefix tools/vendor sync.

Automated update PRs

Update vendored Viewer.js checks npm's stable release daily at 07:30 UTC and supports Actions → Update vendored Viewer.js → Run workflow, with an optional version. It tests the generated update before opening deps/viewerjs-X.Y.Z. Existing open or closed PRs for that release are left alone. A failed test does not publish a branch or PR. Changes require review; the workflow never merges or approves PRs.

The organization and repository must enable Actions → General → Workflow permissions → Allow GitHub Actions to create and approve pull requests. Keep default workflow permissions read-only. Only the update job requests contents: write, pull-requests: write, and actions: write.

The workflow uses GITHUB_TOKEN; no personal token is needed. Because bot-token pushes do not normally trigger other workflows, it explicitly dispatches the read-only Viewer.js vendor and compatibility workflow on the update branch. Both workflow files must be merged into the default branch before scheduling or manual dispatch becomes available.

Compatibility checklist

Check gallery grid/list views, navigation across 100-image windows, metadata, slideshow/fullscreen, keyboard navigation, Escape and focus cleanup. Check the admin gallery/filmstrip and tag viewer. On touch devices, test long swipes, short drags, and pinch/rotate gestures. Confirm the ComfyUI theme remains usable.

The gallery keeps its bounded viewer and custom slideshow. Upstream navbar windowing is not a replacement for bounding the supplied image list: native slideshow playback can still preload every supplied original. Review new preloading defaults, gesture behavior, CSS changes, and any adapter use of Viewer.js internal methods before adopting another release.

Shared ComfyAssets test tooling

The exact toolkit commit archive in package.json / package-lock.json supplies host orchestration and coverage helpers. comfyui-host.mjs is PromptManager's configuration adapter; keep reusable lifecycle changes in the toolkit source. The existing npm scripts remain the public maintainer entry points. See TESTING.md for the managed real-host matrix and update policy.

Shared ComfyAssets browser controls

Prompt Manager (Classic) consumes the same pinned toolkit's browser controls. The node identifier remains PromptManager; existing workflows, sockets, and immediate result selection are preserved. PromptManager Text is unchanged.

Committed assets in web/js/shared/toolkit/ work without npm or KikoTools installed. Maintain common controls in ComfyAssets Toolkit, then update the exact archive pin and lockfile here. Regenerate using npm run --prefix tools/vendor sync:toolkit; npm run --prefix tools/vendor check verifies both Viewer.js and the toolkit without rewriting files. The toolkit distribution includes its license, source history, archive integrity and per-file hashes. Do not edit its copied files directly. Classic's controller and layout remain in web/js/classic-node.js and web/js/classic-node.css.

Run the frontend coverage/browser suites and managed Classic/Nodes 2.0 matrix after updates. Shared modules participate in the frontend coverage gate. Pixaroma's reusable framework inspired this architecture; no Pixaroma code, styles or assets are included.