Typing "F" only found file names with a word starting with F (FTS5
prefix match), so the grid did not list e.g. sunflower.png or
ComfyUI_00001_.png. Single-word queries now add a filename LIKE
'%text%' branch to the global and scoped FTS queries and their counts,
ranked after FTS hits, with LIKE wildcards escaped. Multi-word and
quoted queries stay pure FTS.
- Watcher: a sidecar JSON created or edited next to an unchanged media
file now invalidates that file's metadata cache and scan journal and
forces a re-extraction; a non-incremental re-index no longer skips
assets that already have a metadata row when the cache was cleared.
- Merge index rows that are one file under different Windows path
spellings at startup, keeping the best rating, all tags, the stack
cover, execution ids and the vector embedding.
- Remove deleted/removed assets from the generated feed too.
- Scope the floating viewer's single-letter shortcuts to the viewer
(pointer, focus or pop-out) instead of the whole page.
- Take LGraph/LGraphCanvas types from comfyui-frontend-types and drop
@comfyorg/litegraph; delete five dead frontend files.
- Fix an order-dependent test that leaked an input-directory override.
- Search: tokens were filtered down to nothing for inputs like "at-7",
"(2)", "AND", a single letter or a lone quote, producing an empty FTS
MATCH and "Invalid search query syntax". Fall back to the raw words,
treat punctuation-only input as browse-all, keep non-Latin scripts and
fold accents on Latin letters only (as FTS5 unicode61 does).
- Sidecar JSON (<file>.<ext>.json, then <stem>.json) now supplies the
workflow/prompt/generation data of images, videos and audio when none
is embedded; shared with the 3D extractor; BOM tolerated.
- Workflow tab: skip hidden folders (.history version snapshots were
listed as workflows), only list UI exports, API prompts and wrappers,
read with utf-8-sig, drop invalid JSON from the index (version 5),
and load API-format workflows with app.loadApiJson.
- Floating viewer: release (not just pause) videos before re-rendering
and on dispose, so Live mode no longer accumulates media players.
- Fix assets_fts triggers: the external-content FTS5 table was updated
with plain UPDATE/DELETE, so every rename or move failed with
"database disk image is malformed" and the watcher fell back to
delete + re-index, losing ratings, tags and collections. Use the FTS5
'delete' command, limit the update trigger to filename/subfolder and
repair existing databases (plus an FTS rebuild) at startup.
- Wait for the prompt history entry before post-execution ingestion:
ComfyUI fires on_prompt_end before task_done() stores history, so
outputs of prompts queued from the API or another client could be
missed.
- Scan prune only removes assets whose absence is confirmed; a stat
error or an unreadable scan root no longer deletes user data. Report
pruned assets instead of SQLite change counts.
- Emit mjr-assets-removed for watcher deletes and scan prunes and
mjr-asset-updated for moves so open grids update in place.
- Annotate mjr-scan-complete with origin and needs_refresh; reload the
grid once when live events cannot cover a change and summarise a
finished directory scan in one ComfyUI core toast.
- Document the comparison with ComfyUI core's asset system.
- Move the read-only OpenAPI compat surface from /api/v2/assets to
/mjr/am/compat/assets so it never squats ComfyUI core's /api namespace;
the legacy alias is opt-in via MJR_AM_LEGACY_API_V2_ASSETS=1.
- Allow Python 3.14 (requires-python <3.15) and add 3.14 to CI and tox.
- Stop wrapping api.queuePrompt: progress tracking now resolves the
running prompt from the core Jobs API (getJobDetail), then /queue and
/history, driven by websocket events. Remove wrapHostQueuePrompt.
- Add opt-in Majoor.Integration.HideNativeAssetsTab setting that hides
ComfyUI's native Assets sidebar tab through the official
getSidebarTabs/unregisterSidebarTab API and restores it when disabled.
- Fix all 913 type errors in tsconfig.test.json and type-check tests in
CI; drop a duplicated `stubs` key in asset_card_inner test; make
addToastHistory's type argument optional for the object form.
- Update audit report, changelog, API reference and env var docs.
- hostAdapter: serialize the root graph instead of calling the now-async
graphToPrompt() synchronously (avoids exporting only the open subgraph
and an unhandled rejection); read dirty state from the workflow store.
- Bump @comfyorg/comfyui-frontend-types to ^1.60.0: 1.57.3 was published
without index.d.ts, so the official ComfyApp type was silently lost.
- Backend: typed aiohttp request keys (web.RequestKey when available)
to silence NotAppKeyWarning on aiohttp >= 3.13 and avoid key clashes.
- Fix ruff import-order failures; rebuild dist bundle.
- Add docs/COMFYUI_INTEGRATION_AUDIT.md with remaining conflict risks
and an integration roadmap.
Paging, prefetch and a reload per generation could exceed 50 list requests per minute and stall the grid. Loopback clients are exempt; remote clients are still throttled.
Add the missing extensions to the shared classifier. EXR and TIFF are served to the viewer as a JPEG preview (EXR tone-mapped from scene-linear), ?original=1 returns the source file, and SVG is served sandboxed.
Read generation time and execution ids case-insensitively from Matroska tags, read Majoor keys from AVIF/WebP EXIF text, and route JPEG and TIFF through the EXIF text reader so Prompt:/Workflow: and A1111 parameters are found.
Resolve dict-form subgraph links, bridge subgraph inputs and outputs, expand nested subgraphs, keep linked widgets aligned with widgets_values and name widgets from the live node schema. Derive the sampler name from sampler selector classes, recognise the remaining core output nodes as sinks, accept single-node prompts, and parse gen info per producing node when a prompt writes several files.
Save Image gains format, input_color_space and crf options backed by the core Save Image (Advanced) encoders. Save Video gains mp4/mkv/webm with H.264 or AV1 and keeps the source bit depth and HDR colour space. Both nodes return their frames, and the video sidecar PNG now honours --disable-metadata.
The core-assets integration was calling module paths and function
names that don't exist in ComfyUI 0.38's app.assets system
(app.assets.database.queries.asset_reference, app.assets.database
.get_session, extract_asset_data/extract_reference_data, services
.list_assets_page), so core_assets_enabled() always returned False
and the whole integration was dead code regardless of --enable-assets.
Rewrites the adapter against the real service/query layer
(get_record_by_path_or_none, get_asset_detail, update_asset_metadata),
offloads the now-synchronous core DB calls via asyncio.to_thread, and
fixes sync_user_metadata_by_asset_id to merge onto the asset's
existing user_metadata instead of clobbering it (update_asset_metadata
replaces that field wholesale). Tests now mock the real import paths
instead of ones that never existed.
The frontend called checkMajoorVersion() unconditionally on startup,
and the backend /mjr/am/releases endpoint made outbound requests to
api.github.com to power it. This violates the no-internet-requests
policy for core ComfyUI code, even for update checks framed as
diagnostic or opt-out. Removes the endpoint, the frontend check, the
now-dead version-update badge dot in HeaderSection.vue, and associated
tests/docs.
Exclude development-only content from Registry packages while retaining runtime
docs and vendor assets. Centralize environment access and media process execution,
validate filesystem inputs, and restrict nested media protocols.
Route update checks through the backend GitHub boundary and read version metadata
without spawning Git. Preserve annotated-tag priority over lightweight nightly
tags, including packed refs, with regression coverage. Rebuild the frontend bundle.
Validation: Python tests with coverage, JS tests, targeted media/version regression
tests, and the canonical Python quality gate.
_detect_comfy_root() located the ComfyUI install by walking up from the
output directory (or this package's own file) looking for a folder
containing both main.py and folder_paths.py side by side. Under
non-standard install layouts that heuristic can silently fail and return
None, which makes managed_workflow_root() return None too - so every
workflow path check fails with "Workflow path is not allowed" regardless
of the configured Workflow Roots setting.
Add get_base_path() to the comfy_core adapter (folder_paths.base_path,
the root ComfyUI itself resolves at startup) and try it first, falling
back to the old heuristic only when it's unavailable.
A prompt that produces both an "output" file (Save Image) and a "temp" file
(e.g. a Preview Image node) was indexed with one shared base_dir computed via
commonpath across both, which walks up to their shared ComfyUI-root ancestor
and makes every subfolder wrongly include "output" or "temp" as a literal
leading segment - breaking the /view URL built from it and preventing the
grid from loading the image.
Group refs by item_type and call index_paths once per group against its own
correct root (runtime output root vs ComfyUI temp dir).
- Require the same Comfy auth on all Majoor GET routes as on writes, closing
a read-confidentiality gap for remote/multi-user deployments (no-op when
Comfy auth is disabled, the default single-user setup).
- Gate nightly and stable releases on a quality job (pytest, mypy, frontend
typecheck/build/tests, dist/ drift check) before publishing, and refresh
the committed dist/ bundle to match a clean build.
- Pin softprops/action-gh-release and Comfy-Org/publish-node-action to
commit SHAs.
- Resolve ComfyUI's CacheProvider through the public comfy_api.latest.Caching
alias instead of the underscore-private _caching module.
- Make asset-delete DB cleanup atomic: a failed cleanup statement now aborts
the transaction instead of committing a partial delete.
MajoorGenInfoOverride/MajoorSaveImage/MajoorSaveVideo now use
comfy_api.latest.io.ComfyNode (define_schema/execute) exposed via
comfy_entrypoint(), replacing the legacy NODE_CLASS_MAPPINGS dict style.
node_id values are unchanged so existing saved workflows keep resolving
to the same node classes.
Also bumps @comfyorg/comfyui-frontend-types to 1.54.3 (was pinned to
1.47.12) so JS typechecking matches the frontend versions ComfyUI
actually ships.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Security
--------
ComfyUI's PromptServer.add_routes() mirrors every registered route under a
second "/api" prefix, so /mjr/am/<mutation> is also served at
/api/mjr/am/<mutation>. The auth middleware matched only the canonical
prefix, so the mirrored path reached the same handler with the
authentication check skipped entirely, and without the hardening headers:
POST /mjr/am/assets/delete -> requires_auth = True
POST /api/mjr/am/assets/delete -> requires_auth = False
Replaced the prefix test with a shared _is_majoor_path() boundary covering
the canonical prefixes, ComfyUI's /api mirror, and the /api/v2/assets
compat surface. Verified it does not capture ComfyUI's own routes. CSRF,
rate limiting and safe-mode gates are per-handler and were unaffected.
Licensing
---------
PrimeVue 5 is no longer MIT: PrimeTek moved it to the commercial "PrimeUI"
license, which requires a key, shows a license notice without one, and
forbids redistributing it "as a component library or development tool"
without a separate OEM License. Dependabot had auto-merged 4.5.5 -> 5.0.1.
This project is GPL-3.0 and commits dist/ to the repo, so shipping it would
nag every user and conflict with the GPL's redistribution requirement.
Pinned back to 4.5.5 (last MIT release). The 5.x bump had touched only
package.json/package-lock.json, so no source depended on v5 APIs. The
revert drops @primeui/license-manager and its @noble/ed25519 key-signature
stack; the primevue chunk shrinks 555.70 -> 520.61 kB. Dependabot is now
configured to ignore primevue major bumps.
Correctness
-----------
- api_v2_assets: stop returning the DB's absolute filepath on this
network-reachable surface; subfolder + root_id already convey location
without disclosing local disk layout.
- watcher: enforce _RECENT_GENERATED_HARD_CAP after inserting a batch;
pruning only beforehand let a large batch overshoot the cap.
- routes/registry: track registered route groups individually so a group
failing part-way through does not re-register earlier groups on retry.
- fs_walker/scanner: apply the viewer's root check to symlinked files, so
the scanner stops indexing symlinks whose target escapes every allowed
root ("ghost assets" the viewer then refuses to open). Consulted only for
actual symlinks, so ordinary scans pay no extra I/O.
- routes/registry_app: skip the redundant app.add_routes() on the live
PromptServer app; ComfyUI adds the shared table itself after node
loading, so every core and Majoor route was registered twice at startup.
- Result: unwrap()/unwrap_or()/map() gated on `data is not None`, treating
a legitimate Ok(None) as failure; gate on `ok` instead.
- custom_roots: replace a leftover debug print() that wrote user file paths
to stderr on every move request with logger.debug.
- schema: drop the redundant UNIQUE(filepath, source, root_id) index
(migration m022). assets.filepath is already UNIQUE, so it could never
reject a row the column constraint does not, nor narrow a lookup - it
only cost a second B-tree write per asset on the scan hot path.
Frontend
--------
- entry.ts: app.registerExtension() throws on a duplicate name and ComfyUI
exposes no unregisterExtension, so a live re-import threw before setup()
ran and the reload-safe teardown never executed. Catch it and re-run
setup() directly.
- Rebuilt dist/ so both the reload fix and the PrimeVue revert ship.
CI / tooling
------------
- frontend-compat-nightly: the types step died with a bare "cp: cannot
stat" (upstream's build has not emitted dist/index.d.ts since Aug 26).
Check both candidate paths and dump dist/ with an actionable message.
- package.json: lenient checks that swallowed their exit code are now
suffixed :advisory, the plain names are strict, and quality:strict runs
the full set.
Verified: 1841 Python tests pass (5 skipped, symlink privileges), ruff
clean; tsc --noEmit clean, 831 JS tests pass, eslint clean, build succeeds.
- Add _Settings mock returning show_folders=False to 3 DB-index tests
so they bypass the new browse mode and exercise the index path.
- Add mode='filesystem' to _build_browse_response payload for
consistency with the filesystem-fallback path.
- Resolve CodeQL py/path-injection alerts: enforce lexical containment
(normpath + prefix check) before any filesystem access in
list_workflow_versions, diff_workflow_versions,
list_workflow_thumbnail_candidates and _resolve_path_under_roots,
with post-resolve symlink re-validation. Also removes a file
existence oracle for paths outside the allowed roots.
- npm audit fix: brace-expansion DoS (GHSA-3jxr-9vmj-r5cp, dev-only).