* fix(logs): declare the compressed length so a log download finishes The gzip middleware compressed a text body but kept the handler's declared Content-Length (the uncompressed size), so a browser waited for bytes that never came: downloading any log over 1 KB hung, in the workspace and on the admin page. The middleware now drops a declared length before compressing. Part of #329 * feat(system): show Diagnostics & logs natively and retire the hand-off panel System › Diagnostics & logs is native (D109, D110): the concept's Diagnostics surface with the live database, source, Viewer.js and renderer lines, Run checks (the shared Health report), the diagnostic report, Inspect and the confirmed test link; and the Logs surface with the minimum-level viewer, Lines 1-500, statistics, the log download, the runtime level and console setting saved by Save preferences, the log files with their downloads, Review log cleanup (the rotated_logs maintenance plan, no backup box, Listed files) and a confirmed Clear all logs. D94's hand-off panel, SECTION_HANDOFFS and the undelivered runtime adapter are gone. The browser server logs into its own temporary root. Part of #329 * test(system): compare Diagnostics & logs with the concept System › Diagnostics & logs and its log cleanup review are compared with the concept (app.js 694–695 and maintenancePlan("rotated logs")) in both themes at 1600x1100 and 390x844, with D109 and D110 (and D100 for the review) as the only mapped differences, a 320-wide select check and a mutation check. The fixture gains a concept seed mode (the concept's four log lines, a 1.4 MB active log with three rotated copies, console logging off), and the plan dialog's measureReview and mapPlanConcept move unchanged into concept-inventory.mjs for Maintenance and this review. The comparison found that the Database line read a report key that does not exist (database_info.size_bytes) and so always showed "0 bytes"; it now reads database_size_bytes, the key get_database_info() returns. Part of #329 * test(system): prove every legacy System capability has an owner TESTING.md gains "Legacy System capability coverage": every System capability of the legacy admin and gallery pages with its anchor on main, owner, status (covered, kept in legacy or approved removal), native control and the exact title of the test that proves it. tests/vendor/legacy-coverage.test.mjs (with tools/vendor/legacy-coverage.mjs) fails on a row with no owner, an unknown status, a malformed native control, a control on a row that is not covered, or a test title its file does not declare; a title only in a comment does not count. workspace-system.spec's "every covered legacy System capability has its native control" opens each covered row's section and finds the control by role and accessible name. Versus the design's table: the anchors are re-checked against main, "Run health checks" is on Maintenance (D123), not Overview, Diagnostics run is proven by "Run checks opens the shared Health report", and the export rows repeat their test title instead of "(same as above)". Part of #329 * fix(system): confirm Clear all logs on a fresh file list and record coverage Review fixes for the Diagnostics & logs section: - Clear all logs reads the log files again before it confirms, so the dialog names the copies it deletes now (a list it cannot read gives the general sentence, never an old count); Refresh reads the files too. - Runtime values that cannot be read stay disabled and say so. - Create test link holds its button until the write answered, so a second press cannot write a second record. - The Lines field names its range. - The browser server builds its logger in its own root, so no log file is ever opened in another folder; the fixture closes every directory scan and replaces a link instead of writing through it. - system.mjs drops the unused section fallback; frontend coverage floors recorded with coverage:update (system-diagnostics.mjs 97.5% lines). Part of #329 * fix(system): read the database size the report sends The Database line read database_info.size_bytes, a key the report does not have (get_database_info answers database_size_bytes), so it always read "Readable · 0 bytes · N images". The browser test now requires a non-zero size. Found by PR 3's concept comparison. Part of #329 * test(system): require a running test and a control for every covered capability Review fixes for the legacy coverage proof: - A title declared only with test.skip, .fixme or .fail no longer proves a row (.only and .slow still do). - Every covered row names its native control, except the rows in CONTROL_EXEMPTIONS, each with its reason (today only the gallery per-image auto-tag row, owned by the Images selection bar). The browser test asserts that the covered rows without a control are exactly the exemptions. - JavaScript comments are stripped across the whole source, wherever a block comment starts, skipping strings, template literals and regular expressions. A Python def test_ counts only at function or method indentation and outside comments and docstrings. - A control name several rows share ("Review plan", "Review options", "Refresh") is looked up inside the row the table names (· in "<row>"). - The diagnostics comparison records each select's chosen option, so a wrong default level is caught. Part of #329
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.