Commit Graph
154 Commits
Author SHA1 Message Date
DemonGatanjieuandClaude Opus 5.5 5c0448f009 Key parameters and parameter sets in view
Star a value in the comparison (key_params.js: node type + widget name, a hidden ComfyUI
setting) and it stays at the top of every comparison; equal values can be listed to be
starred. Recipe cards show 参数方案 N (sets unlike the recipe, from the new read-only
GET /anomalous/parameters/signatures) and open the Parameters tab; each set there shows
its key values, how many values differ from the recipe, and ⇄ to compare
(ui_param_set_keys.js). The window also compares saved workflows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 19:56:14 +08:00
DemonGatanjieuandClaude Opus 5.5 81fcc6ebc4 Merge feature/next: picker scroll, combo save burst, activity long-text fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:36:15 +08:00
DemonGatanjieuandClaude Opus 5.5 99576e60bd Fix picker jumping to the top, combo saved per tag, unreadable long-text activity
- Current node's model picker redrew the whole grid to mark the chosen card, so
  choosing one further down scrolled back to the top. The cards are repainted in
  place (paintCard) instead.
- The classic combo editor saved when its bilingual tags were shown and again for
  each tag's translation as it arrived: a long prompt wrote the combo dozens of
  times in a second (34 note_save entries in one user's log). Rendering no longer
  saves and the translations share one save half a second after the last. Its
  prompt placeholder moves into locales.js (no inline language branch).
- Activity values are capped at 400 characters from the start, so an edit late in
  a long prompt logged identical before and after. A long before/after pair is now
  cut around its first difference (test included).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 16:36:15 +08:00
Claude ca2cdecf7e fix(models): import upload and Tidy moves only from this computer
PUT /anomalous/import/upload and POST /anomalous/placement/move wrote
into the model folders for any caller, while place and identify already
answered only the computer ComfyUI runs on. With ComfyUI started with
--listen, another device could upload model files or move models
between folders. Both now check mcp_server._is_local first and answer
403 not_local, which the import and Tidy screens already show.

Tests drive both routes through a proxy header and check nothing was
written or moved; they fail without the check. Full suite: structure
check, every tests/*.mjs and 234 Python tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018P2T2R7TFbJsc3C9maCD8B
2026-10-08 20:35:57 +00:00
Claude 1b8839d2c6 Merge feature/next: Anomalous_TTS interface 13, no local paths
Brings stage 2 into stage 3: the gallery drag fix and the change that
follows Anomalous_TTS interface 13. No conflicts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018P2T2R7TFbJsc3C9maCD8B
2026-10-08 20:23:55 +00:00
Claude def279f434 Merge feature/ui-shell: Anomalous_TTS interface 13, no local paths
Brings stage 1 into stage 2: the gallery drag fix and the change that
follows Anomalous_TTS interface 13 (no server path picker, no storage
change or move, folders shown with the node's settings file).

Conflicts: the picker CSS, the storage-change activity label and its
locale keys are dropped; stage 2's model download and backup entries stay.
tests/tts_setup_api.mjs now checks the pretrained download route instead
of the removed storage and library routes, and that no export sends a
path on the computer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018P2T2R7TFbJsc3C9maCD8B
2026-10-08 20:23:29 +00:00
Claude fe8e08d8cf fix(tts): follow Anomalous_TTS interface 13, no local paths
Anomalous_TTS no longer takes a folder or file path on this computer from
a request (ComfyUI-Manager review of the node): the storage place, other
character folders and pretrained sources are set only in its settings
file, and imported files are always uploaded.

- GPT-SoVITS settings shows the storage place, other places and package
  sources without change, move or remove buttons, and names the node's
  settings file (status.settings_file) with a copy button and how to edit it.
- The import window drops "from this computer": no server path picker
  (ui_tts_path_picker.js is gone), no local folder scan or local clip
  preview; a very large upload is confirmed instead.
- tts_setup_api.js loses the removed routes; formatSize moves there.
- The storage-change activity entry, unused locale keys and picker CSS go.

Verified: tools/check_structure.mjs; tts_setup_api in Node with fetch
stubbed; the settings card, batch hero, add menu, file sources and player
rendered with jsdom and stubbed ComfyUI scripts. Not run in ComfyUI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018P2T2R7TFbJsc3C9maCD8B
2026-10-08 20:21:50 +00:00
DemonGatanjieuandClaude Opus 5.5 98148481bc Models page tabs, base model filter, Tidy tab redone with covers
- The models page has tabs: All models, Tidy (with its count) and Sources;
  the type bar keeps the type chips and Import.
- Base model chips under the type chips (All, Illustrious, SDXL, Unknown...),
  one per family the listed models have (model_bases.js; SDXL 1.0 = SDXL);
  models not scanned are listed by their header's guess (metadata base_guess).
- Tidy is cards with the model's cover and name in two steps: models in a
  folder whose loader cannot read them (from -> to, one plain reason, Move
  there, Change place), and identical files side by side with the copy to
  keep marked (the one in the right folder; click another to change) and one
  button for the extra copies. Models that load anyway and extra copies of a
  well-placed file are not in step 1. Same-size files up to 256 MB are
  compared at once; larger ones on Compare.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 23:02:00 +08:00
DemonGatanjieuandClaude Opus 5.5 552809c541 Tidy view: models in the wrong folder and identical copies
The models page's Tidy chip (with a count) reads every model's header
(model_kind) and lists files whose type does not match their folder - such
as an Anima/Flux/Wan diffusion model in checkpoints, which Civitai labels
"Checkpoint" - with why it matters, where it belongs (same subfolder, same
drive) and Move there, taking its cover, info and notes along; never over a
file. A whole checkpoint in diffusion models is marked as loading anyway.
Identical files are grouped by SHA-256 (scan hashes; same-size unscanned
files on Compare); each copy can go to the Recycle Bin. Moves are logged
(model_move). Also: opening the Tidy or Sources view stops cards of an
earlier load from being drawn into it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:02:14 +08:00
DemonGatanjieuandClaude Opus 5.5 f7447b2222 Import dropped model files into the right folders; version labels; settings tabs
- Models page: "+ Import" chip and model files dropped on the grid open an import
  window. model_kind.py tells a file's type (LoRA, checkpoint, VAE, text encoder,
  diffusion model, ControlNet, embedding, CLIP Vision, upscaler) and base model from
  its safetensors / GGUF header only; .ckpt/.pt are never opened. api/model_import.py
  finds the dropped file in Downloads/Desktop (name, size, time) and moves it, or
  takes an upload; checks it against Civitai and the scanned models; never replaces
  a file (" (2)"). New files are scanned after.
- Model cards show the Civitai version name (metadata version_name).
- Settings page in tabs (Look, Models, Workflows, Prompts, Backup, Help); the
  download folder is a choice of ready-made folders or typed by hand; default is now
  by base model ({base}).
- The scanner's offline base model uses model_kind (LoRAs, Qwen, Wan, Chroma...).
- AD-019: no Civitai browser inside the plugin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:07:43 +08:00
DemonGatanjieuandClaude Opus 5.5 7c140f59ac Settings: a DeepL key for prompt translation
Settings -> Translation -> DeepL key saves the user's own DeepL API key;
translation then asks DeepL first, else Google's free endpoint, else
MyMemory. Saving a key translates one sentence and says whether it works or
why not (a refused key, a used-up month, busy). Only the key's tag changes,
so the page keeps its scroll place. The key stays on this computer: backups
leave it out like the Civitai key.

DeepL stopped taking the key as an auth_key parameter in 2025, so a key put
in config.json by hand no longer worked. It now goes in the Authorization
header with a JSON body; targets are ZH-HANS and EN-US. When DeepL fails,
the answer carries deepl_error beside the other provider's translation.

Checked live: a made-up key is refused by DeepL's server and the dialog
says so; removing it switches back to Google.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 03:19:25 +08:00
DemonGatanjieuandClaude Opus 5.5 93cf8f122a Recipe packages: tell the receiver about the cover; unstretched cover preview
The import dialog said "with 1 picture" for a package with a cover and one
model thumbnail: the cover lives inside recipe.json as a small image, not as
an asset file. Inspect now returns has_cover and model_pictures, and the
dialog says "a cover, N model thumbnails".

The save dialog's cover preview stretched the chosen image to the dialog's
width; it now keeps its proportions (object-fit: contain).

Checked live: a recipe with an output-image cover and a LoRA thumbnail,
exported and imported with the output image moved away, shows both on the
new card and its detail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 01:14:29 +08:00
DemonGatanjieuandClaude Opus 5.5 da38e2d6ad feat(recipes): reopen recipe packages, imported through share and import
By the user's decision, recipe packages are open again: the card's
export button and the detail's More menu make a .zip named after the
recipe (workflow, notes, tags, parameters, cover, model thumbnails;
versions only when ticked). Dropping one into the Workflows page's
share and import dialog inspects it and keeps it as a new recipe card,
optionally opened on the canvas.

An import never replaces a recipe any more: the "replace" path, which
erased the old recipe for good, is gone; a taken name gets " (2)".
Assets and versions move in before the recipe file, and a failure
removes only this import's new folders. The release gates and their
503 answers are removed. Tests: new card and renaming, nothing left
after a failed import, tampered and escaping packages refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 00:32:05 +08:00
DemonGatanjieuandClaude Opus 5.5 d77655fb76 feat(backup): models' scan results, and Civitai covers on request
A backup now keeps each model's scan file (.info, small; on by default)
so names, trigger words and base models survive Civitai removing a
model, and on request Civitai's covers (stored once as the civitai_bak
copy; they can be hundreds of MB). Putting back writes a scan file only
where the model has none (replaced only with "replace") and Civitai's
cover only where it has no cover, with its civitai_bak copy so it stays
Civitai's and a later user cover still wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 23:11:51 +08:00
DemonGatanjieuandClaude Opus 5.5 1efa20fd91 feat(backup): download the models a new computer lacks
A backup also keeps a model list (each model's folder, path, size,
SHA-256 and link). Inspecting it names the models this computer lacks
(two copies of one file are one download); "Find downloads..." looks
them up like Model Check (Civitai by hash, the saved link, Hugging
Face), shows size, source and free space, and downloads the ticked ones
one after another into the path they had, each checked against its hash
and scanned after. A file found by name only starts unticked. Verified
on the isolated ComfyUI: an 18 MB Civitai LoRA came back to its folder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 18:23:37 +08:00
DemonGatanjieuandClaude Opus 5.5 797a52105e feat: Settings -> Backup, export and import the user's data
Export packs the stores (recipes, combos, materials, parameters, and
optionally ComfyUI's saved workflows), the plugin settings without the
Civitai key, and each model's user layer and own cover into one .zip to
keep on a cloud drive. Import lists what is new, the same or different
and the models it finds again (by SHA-256, else folder, path and size),
adds only what is missing by default, replaces differing files only on
request with this computer's going to the Recycle Bin first, merges a
model's name and notes field by field and puts the user's cover in
place of a Civitai one. Unsafe or foreign zips are refused. Both are
activity entries. tests/test_backup.py covers the rules; testing.md
names a single test file the way unittest finds it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 18:12:45 +08:00
DemonGatanjieuandClaude Opus 5.5 0dcc67f394 feat(combos): combos from the nodes picked on the canvas
A combo can now hold its own node structure: pick nodes on the canvas and
New -> From the nodes picked on the canvas keeps the model nodes (a
drop-down of model files) and the text nodes (a multiline text box by the
node's definition) with the links between them; other picked nodes and
links to them are left out, their ports stay open on the canvas.

Slots are per box, so a node with several model drop-downs has several; a
box fed by a link is no slot. Each model slot's folder is the one whose
files hold all its drop-down's model-file options (ComfyUI's /models
lists), never guessed from names. Every other box is stored by name and
put back untouched, in order (a count box adds its rows first).

The save dialog shows what is kept and dropped and lets slots be renamed
or unticked. The editor lists the slots: a picker of that folder's models
with covers, filtered by base model, and text boxes. Put on canvas makes
the nodes (missing node types and their packs are named before anything
is placed), fills the slots by name, links by port name and type, as one
Ctrl+Z step; a box or link that cannot be restored is reported, never
guessed. New -> Same structure as ... starts another combo from a saved
structure. The default combo is unchanged. MCP list_combos lists node
combos by slot and place_combo places them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 04:19:09 +08:00
DemonGatanjieuandClaude Opus 5.5 ca003d20d2 feat: Hugging Face first with the mirror, model card covers, text encoders shown, header search
- Downloads: with the China mirror on, a Civitai match whose very file (same
  SHA-256) is on Hugging Face too, by the workflow's link or ComfyUI-Manager's
  list, is fetched from Hugging Face; Civitai's name, base model and page stay.
- A file downloaded from Hugging Face gets its model card's first example
  image as cover and its base model, trigger words and example prompts as
  notes, with the repository as link (api/hf_card.py), never over what the
  user or a scan set.
- Text encoders, CLIP vision and upscalers are shown (and scanned) by
  default, so shared workflows carry their fingerprints; older configs get
  them turned on once (folder_defaults_version 2).
- The models page's search sits in the header (ui_model_search.js) instead
  of inside the folder list; it searches the whole type by name, file name,
  folder, trigger words, base model and notes, every word; Esc clears it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 03:37:17 +08:00
DemonGatanjieuandClaude Opus 5.5 9624ae1356 feat(model-download): find base models in ComfyUI-Manager's model list
Models not on Civitai (Flux's VAE, T5 / CLIP text encoders, upscalers,
ControlNets...) are looked up by file name in the model-list.json of the
ComfyUI-Manager installed here (api/manager_catalog.py), keeping entries
that fit the node's folder type. With the workflow's fingerprint only the
listed file with that SHA-256 counts (same-name entries are each asked);
without one, a single entry is offered as "Download by name" with a
warning, never in Download all or the MCP's download_missing_models.

A site that stops answering is skipped for the rest of a lookup while the
others are still asked, so Civitai failing in mainland China no longer
stops Hugging Face through its mirror. GitHub raw file links count as
sources; a Hugging Face file behind a login offers its repository page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 03:07:17 +08:00
DemonGatanjieuandClaude Opus 5.5 224d339afe feat(mcp): AI apps can download models
Three MCP tools: download_missing_models (Model Check's Download all for
the open workflow, through the page so the placement rules and the put-in
afterwards are the UI's own), download_model (one model from a Civitai
version link, a Hugging Face / GitHub file link or a Civitai hash, into a
folder of its type) and download_status. The default models folder of a
type is shared by the dialog and the tools.

A Civitai version link without a matching file name now takes the
version's primary model file (people rename their files); a hash, when
there is one, still decides.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 02:53:49 +08:00
DemonGatanjieuandClaude Opus 5.5 a04f1525d4 feat(model-download): Hugging Face through the China mirror
Settings > Model downloads can send Hugging Face downloads through
hf-mirror.com, on by default for the Chinese interface. The lookup and the
download use the chosen host whichever one the link names; when the mirror
sends a network outside China back to huggingface.co, the lookup follows
once for the size and SHA-256. A failed download from Hugging Face itself
suggests the mirror.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:46:09 +08:00
DemonGatanjieuandClaude Opus 5.5 698a256a16 feat(model-check): download missing models, to the folder you choose
Model Check offers Download (and Download all) for a missing model whose
source names one exact file: Civitai by the workflow's fingerprint, or a
Civitai version / Hugging Face / GitHub file link the workflow carries.
A dialog shows each file's size, source and full destination, with the
models folder (when there are several) and subfolder changeable; Settings
> Model downloads sets the default: where the workflow says (the node
needs no change) or a set folder, {base} sorting by base model and
matching an existing folder in any spelling.

Downloads run one at a time into <file>.part, continue after an
interruption, are checked against the SHA-256 before they get their name,
never replace a file, and send the Civitai key to Civitai only. Finished
files are put into their nodes (one Ctrl+Z step each), scanned for info
and covers, and recorded in the activity log.

A change of fingerprints alone (after any scan) no longer takes a Ctrl+Z
step that seemed to do nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 01:28:51 +08:00
DemonGatanjieuandClaude Opus 5.5 fa11c55293 feat(lora): one way to insert a LoRA, for Current node and MCP alike
Current node's "Insert LoRA before / after" refused the most common workflows: a
checkpoint whose CLIP feeds both prompts (one link per output only) and UNet workflows
with their own CLIP loader (MODEL and CLIP had to come from one node).

- graph_splice.js: planLoraInsertion decides the links (after a node: every link of its
  MODEL output; before one: only its own MODEL input) and, for LoRAs that train the text
  encoder, the CLIP line (same node, a UNet workflow's one CLIP source, or before a
  sampler the source its prompts share); spliceLora wires it, all or nothing. The old
  analyzeModelChainInsertion / spliceModelChainNode / spliceAfterOutputs are gone.
- api/lora_info.py: GET /anomalous/lora_info reads the LoRA's safetensors header; the
  picker asks it on confirm and inserts a model-only loader when there are no
  text-encoder weights. The MCP add_lora uses the same helper.
- Insertion messages speak of the MODEL line; the fan-out ones are removed.
- tests/graph_splice.mjs (local) covers checkpoint, UNet + CLIP loader, before a
  sampler, and the rollback.

Verified on 8199 through the Current node picker: after a checkpoint feeding two prompts
(full LoRA, both prompts moved) and before a sampler (model-only Flux LoRA).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 23:00:32 +08:00
DemonGatanjieuandClaude Opus 5.5 0529502421 fix(mcp): add_lora wires CLIP too when the LoRA trains the text encoder
A model-only LoRA loader was used for every UNet workflow, so a LoRA with text-encoder
weights lost them; and inserting after a checkpoint whose CLIP feeds both prompts was
refused (one link per output only).

- api/mcp_actions.py reads the LoRA's safetensors header: lora_te / te1 / te2 /
  text_encoder keys mean it trains the text encoder.
- Such a LoRA becomes a LoraLoader taking MODEL from the model line's end and CLIP from
  the same node (checkpoint, full LoRA loader) or a UNet workflow's one CLIP source;
  others stay model-only.
- graph_splice.js: spliceAfterOutputs puts a node after outputs on different nodes and
  moves every link each output had. The picker's spliceModelChainNode is back to its
  committed behavior (the `types` option is gone).

Verified on 8199: UNet + CLIP loader with a text-encoder LoRA, a model-only one after it
and another text-encoder one; a checkpoint feeding two prompts; Ctrl+Z after each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 22:47:14 +08:00
DemonGatanjieuandClaude Opus 5.5 80f41f98e9 feat(mcp): AI apps can act on the open workflow, scan and speak
The second batch of MCP tools: they change things, through the same code the UI uses.

- Canvas, done by the open ComfyUI page: describe_canvas, set_prompt, set_model,
  add_lora, place_combo, check_workflow_models, fix_workflow_models, run_workflow,
  open_in_anomalous. api/mcp_bridge.py sends the action over ComfyUI's websocket and
  waits; web/modules/mcp_bridge.js claims it (visible tab first), does it with
  Anomalous's canvas code and answers. Each change is one Ctrl+Z step, shows a toast and
  is logged as the AI's (activity entries carry via: "mcp", with their undo).
- This server: scan_models (new / look up again / picked models, via /anomalous/scan_all),
  list_voices and speak (Anomalous TTS through /prompt and /history).
- graph_splice.js takes the chain's slot types, so a LoRA can go into a model-only (UNet,
  Flux) chain as LoraLoaderModelOnly; the default (MODEL and CLIP) is unchanged.
- Nothing deletes or renames files; acting tools are not marked read-only, so AI apps
  ask before calling them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 22:13:28 +08:00
DemonGatanjieuandClaude Opus 5.5 358c2bc4d3 feat(mcp): AI apps can read the library through /anomalous/mcp
An MCP endpoint (Streamable HTTP) inside ComfyUI's server, so Claude, Cursor, Cherry
Studio and other MCP apps can ask about the user's library without anything extra
installed and without memory or VRAM while nobody is connected.

- api/mcp_server.py: one JSON-RPC message per POST, answered with JSON. Serves the
  2026-07-28 stateless protocol (headers must match the body) and the earlier
  initialize-based versions; no sessions. This computer only: loopback peer, no proxy
  headers, loopback Host and Origin (DNS rebinding).
- api/mcp_tools.py: 11 read-only tools: library overview, model search and details
  (optional cover), scan status, output-image search and generation settings
  (optional thumbnail), combos, workflow recipes, saved prompts, generated audio,
  activity log. Ids resolve inside their roots; tool failures come back as isError.
- docs/guides/mcp.md: setup for each app, what can be asked, privacy note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 21:26:10 +08:00
DemonGatanjieuandClaude Opus 5.5 d00882925c Prompt Studio: meanings in a chosen language, any language to English
Tag meanings are brighter and slightly larger, and the top bar picks
their language (Simplified/Traditional Chinese, Japanese, Korean,
Russian, Spanish, French, German, Portuguese, or none) for every
interface language; the old Chinese switch carries over. Typed text in
any language that is not plain English is translated to English, and
translating a box's foreign tags drops one whose English is already
there. The backend skips DeepL for targets it does not take instead of
falling back to English, and lets MyMemory detect other sources.
Unused prompt helpers in translation_service.js are removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 11:24:04 +08:00
DemonGatanjieuandClaude Opus 5.5 1d02d5b74d Remove the Material Library page; Prompts opens Prompt Studio
The page held four unrelated things, so each now lives where it is used:
the rail's Prompts entry (and the Ctrl+Shift+L shortcut) opens Prompt
Studio beside the canvas, where saved prompts are managed; the browser
comes back when the studio closes. Saved node values stay in Current
node, which can now delete them; moved whole workflows are no longer
offered there twice. Recent results, combos and whole workflows already
have their own homes.

Deleted ui_materials.js, ui_material_cards.js, ui_material_detail.js,
ui_material_application.js (its receipt is ui_apply_receipt.js) and
material_feedback.js, the recipe page's copy-to-library buttons and the
save_parameter_material route, with about 2,000 lines of CSS and 200 locale
keys. Words that said "material library" now say where things go.
Material files are untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 22:59:35 +08:00
DemonGatanjieuandClaude Opus 5.5 302fe7e6e8 Keep gallery results as a workflow, a combo or prompts
Every PNG in the gallery has a star that asks what to keep: the whole
workflow as a Workflow Recipe, its main model, LoRAs and positive prompt
as a combo (models looked up on this computer, missing ones left out), or
its prompts as a saved prompt. What is kept remembers its image, so
GET /anomalous/kept_images fills the star and the menu opens what was
kept. The image workbench's Keep opens the same menu instead of its name
and tags form. Things are named after the prompt's first tags.

The Material Library's Recent shelf and its route are gone: the gallery
lists the same images. Gallery cards moved to ui_gallery_card.js, and
deleting asks in the usual dialog. Two missing locale keys are fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 22:32:51 +08:00
DemonGatanjieuandClaude Opus 5.5 0f7d6317ad Put Prompt Notes on the Material Library's Prompts page
ui_material_notes.js lists the notes above the saved prompts, each with
its model, LoRAs and prompt, Put into this workflow and New group of
nodes; a card opens the note's editor, which now has a way back to the
library, and New note starts one. The separate Prompt Notes button goes,
and so does the editor's "save to library" card with the route only it
used (save_prompt_note_material): a note is in the library already.
Notes keep their own files; prompt materials saved from notes before
still list and open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:39:38 +08:00
DemonGatanjieuandClaude Opus 5.5 7bea74dd09 Keep whole workflows as recipes, not materials
Recent's star and the image workbench's whole-workflow save now make a
Workflow Recipe with the image as cover (recipe_save.js lays the image's
workflow on a canvas of its own and saves it through the same path as the
canvas save, now shared). The Material Library's "all" lists the pieces
only and loses its Workflow pill. Whole workflows kept as materials
before can be moved from the Workflows page: each becomes a recipe and
its material gains moved_to_recipe, which keeps it out of every listing
while the file stays. Recent marks images kept as recipes and opens them;
partial recipes are "Modules" everywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 17:20:28 +08:00
DemonGatanjieuandClaude Opus 5.5 e04fa66b0d Fix Model Check hashing same-size files inside ComfyUI
model_resolution imported calculate_sha256 and the header inference from
scraper.py, which only works when the plugin folder is on sys.path (the
tests); inside ComfyUI the import failed, so a renamed model the scan had
not hashed was reported missing and the route answered 500. Both
functions now live in model_identity.py, which the API and the scanner
already share; scraper.py keeps its printing wrapper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:46:57 +08:00
DemonGatanjieuandClaude Opus 5.5 4cfff5382e Make Model Check offer same-name files as candidates, not as the same file
For a workflow without fingerprints, a missing ordinary model took the
local same-name file's hash as its evidence, so it showed as "the same
file under another name" and counted among those put in at once. Only the
workflow's own record is evidence now; the one same-name file the node can
load is a candidate, and a size candidate with the same name is shown as
likely, first. Foundation components still go by fingerprint only. Model
Check also reads GGUF values and resolves upscale models.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 14:23:05 +08:00
DemonGatanjieuandClaude Opus 5.5 2104bb659f List GGUF, .pth, .sft and .bin models, in any case
The Models page, the folder counts, search and lookups only matched
.safetensors, .ckpt and .pt in lower case, so quantized GGUF models and
most upscalers never showed. One list, MODEL_EXTENSIONS, and
is_model_file() now decide what a model file is everywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:51:46 +08:00
DemonGatanjieuandClaude Opus 5.5 a8b75d33a6 Faster model cards, video posters, and a settings page
Card thumbnails lived in ComfyUI's temp folder, which ComfyUI empties on
every start, so each first visit after a restart remade them all. They now
live in <user>/anomalous/cache/card_thumbnails (still capped at 256 MB).
Listing a model type queues the missing ones for one background thread;
the first screen of cards loads before the rest. A video cover gets a
first-frame poster (PyAV) and fetches nothing until it plays; hover-play
is now the default, as the setting already recommended.

The gear opens a settings page instead of a pop-up with a dialog inside:
look and language, model cards and memory with the thumbnail cache (size,
empty), folders, workflow fingerprints, opening mode and window, help.
Display preferences live behind owner.displayPrefs. Also removes a dead
overlay rule that shared the new page's id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:00:47 +08:00
DemonGatanjieuandClaude Opus 5.5 20424e4428 Add a Recent shelf to the Material Library: one star keeps a result
Saving parameters asked people to decide, then save, while busy
generating. The library's first category, Recent, now lists the newest
output PNGs that carry their workflow, each with the start of its positive
prompt, the main model and steps / CFG / sampler / size (GET
/anomalous/recent_generations, read from PNG text chunks and cached). A star
keeps one as a whole-workflow material through the existing
save_image_material route, named after the prompt's first tags; a kept
image shows a filled star (matched by the image's SHA256, as the save
route's duplicate check does) and opens its material. The picture opens the
image workbench for keeping single nodes; the search box searches Recent
too. The empty-library guide points here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:53:13 +08:00
DemonGatanjieuandClaude Opus 5.5 a2a11ca2cf feat(scan): the scan page says in plain words why a model is not there
The lead says what a scan does (the file's fingerprint looked up on
Civitai). "Not found" lists the usual reasons (not published on Civitai,
as voice and upscale models mostly are; trained or merged; changed after
download) and that the model works as usual. A not-found model that is no
known image model says it may be a voice or upscale model.

The summary also lists model files in other formats (.pth, .ckpt, .bin...),
which scans never read, outside hidden folders; the page shows them under
"Other formats" with why, only when there are some.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 16:00:08 +08:00
DemonGatanjieuandClaude Opus 5.5 a173e4e561 feat(node): Current node panel with one list of saved parameters
The Node Assistant becomes "Current node" (当前节点): one page instead of the
"actions" / "parameter sets" tabs, model actions on top, Parameters below.

- node_parameter_sets.js: the node type's saved values from the material
  library and from recipes' parameter sets as one list; the same values
  saved in both are one entry naming both sources. For the selected node,
  exactly what an entry would change; seeds (and their after-run control),
  model files and choices this computer lacks are kept.
- ui_node_parameters.js: the list, "apply these N" (one undo in the
  receipt) and "save these values".
- api/node_material.py: POST /anomalous/save_node_material keeps one
  node's values as a node_parameter_selection material, deduplicated by
  type and values; the library lists it under parameters.
- Removed: ui_node_presets.js with its hover popovers, the beta notice and
  their styles and strings. The panel and help texts use the new name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 06:09:49 +08:00
DemonGatanjieuandClaude Opus 5.5 2358649f03 feat(doctor): Model Doctor checks each opened workflow and says what to do
A bar over the canvas appears when an opened workflow uses models this
computer does not have: how many, and how many are here under another
name or folder (same hash), with one press to put those in. The doctor
page is redone on the scan page's layout: what needs you first, why in
plain words, and a button per row (put in, use a same-size file, pick
one, look it up on Civitai); models that are fine fold away.

- model_check.js: the check (no DOM, changes nothing) and the fixes,
  which call the node's widget hooks so ComfyUI drops its red mark;
  the node picker does the same now.
- Opening the doctor no longer rewrites the workflow by itself.
- Removed: the auto-detect switch (nothing read it), the doctor's own
  deep hash scan and its routes (the resolver hashes same-size files on
  demand; the page points to the scan page), the hash dialog, the old
  resolver in hash_resolver.js, the unused pick-for-node path in
  ui_detail.js, 45 old strings.
- Node Assistant's diagnoseNode and LoRA insertion moved to
  ui_node_assistant.js.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 03:36:41 +08:00
DemonGatanjieuandClaude Opus 5.5 e466e9dfcf feat(scan): list unmatched and unscanned models, show each scan's result, explain why
The scan page now says which models are unmatched or not scanned yet (type, folder,
why Civitai had nothing) and what each scan did, model by model; rows open the model,
scan it, look it up again or search Civitai. The progress box shows the counts and,
when floating, a way to the result. The activity log records a scan when it ends with
its result, and model edits (from -> to) and deletions (files moved) in detail.

- scraper.py reports one JSON line per changed model (--report-file); a failing model
  no longer ends the scan. Unmatched info keeps why (not_found / network / offline);
  online scans look network/offline ones up again. After two models in a row without
  an answer the rest of the scan infers from the files (--civitai-down for the next
  folders) instead of waiting out every timeout.
- civitai_client.py: the network side moved out of scraper.py; tells a 404 from
  Civitai being unreachable (CivitaiUnreachable).
- api/scan_report.py: ScanJob turns a scan's reports into one result, kept as the last
  scan (/anomalous/last_scan) and logged; /anomalous/scan_model opens a listed model.
- /anomalous/scan_all takes picked or listed models as `targets`, so one scan has one
  result; scan_summary lists unmatched and new models with their reason.
- Activity middleware takes details a handler attaches (request[ACTIVITY_DETAIL]).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 02:52:17 +08:00
DemonGatanjieuandClaude Opus 5.5 e689cc3dac chore: restore consistent CRLF line endings in six files
Edits in the last commits left some LF-only lines in files the repository
keeps with CRLF. Line endings only; no content change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:57:06 +08:00
DemonGatanjieuandClaude Opus 5.5 00ea3f78c4 feat(models): the user's edits are a layer of their own; scans keep the user's covers
A model's information now has three layers, the user's first:
<model>.anomalous.json (written only by the model editor), the scan result
(<model>.info, or another tool's .civitai.info with Civitai ids; id -1 =
inferred from the file) and the file itself. get_metadata reads the user
layer last, so it wins (an emptied field stays empty), and reports
info_source (civitai / local / "") and user_fields. Edits saved by earlier
versions in .civitai.info keep working.

- The editor writes .anomalous.json (atomically) instead of mixing edits
  into .civitai.info, which other tools rewrite.
- scan_info_path: a .civitai.info holding only old edits is not a scan
  result. Editing a never-scanned model used to make scans skip it for good.
- Covers: a cover is Civitai's only while byte-identical to
  <model>.civitai_bak.*; any other cover is the user's and is never
  replaced. "Fetch again" updates only Civitai's own cover, keeps names,
  notes and covers, and asks before starting.
- A scan no longer downloads covers and model pages again for models whose
  information is already on disk (it did for every model, every scan).
- The earlier "keep the editor's name" change in the scraper is reverted:
  editor names never lived in .info; the CHANGELOG entry is corrected.
- .anomalous.json moves and goes to the Recycle Bin with its model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:49:10 +08:00
DemonGatanjieuandClaude Opus 5.5 a2e3077726 feat(files): deleting the user's files goes to the Recycle Bin
recycle_bin.move_to_trash is now the only way the plugin deletes the
user's files: SHFileOperationW with FOF_ALLOWUNDO on fixed Windows drives
(send2trash or gio elsewhere). Where there is no Recycle Bin (USB stick,
network share) it raises TrashUnavailable and nothing is deleted; the API
says so (api/trash.trash_failure), including "file in use".

Routed through it: model delete (model + sidecars in one operation, or
nothing), cover replacement and cover reset, output images, generated
audio, recipes with history and images, materials with images, prompt
notes, parameter notes, the duplicate copy a physical rename finds and the
covers a forced rescan replaces. Temp files, caches and the bounded recipe
history are still removed directly.

The unused POST /anomalous/clean_civitai_info, which erased every
.civitai.info in the library (with the names users set), is removed with
its activity-log label. Delete confirmations say where things go. Tests use
a fake Recycle Bin (none of their files reach the real one).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:42:49 +08:00
DemonGatanjieuandClaude Opus 5.5 fb21e6c6e9 feat(scan): the scan page, scan runner and scanner changes (completes 5af9b6d)
5af9b6d was committed with only the removal of ui_scan_wizard.js staged;
this adds everything its message describes, so the branch works again:

- ui_scan_page.js / scan_runner.js / 18-scan-page.css: the scan page with
  matched / unmatched / not-scanned counts, one scan button, "look up the
  unmatched models again", progress in the page, Advanced options.
- api/scan_summary.py: GET /anomalous/scan_summary.
- scraper.py: --retry-unmatched (saved hash when the file is unchanged,
  covers kept); display names set in the editor survive scans.
- api/scanner.py: one request-to-switch mapping (_scraper_flags) and one
  cache-clearing helper for both scan routes.
- model_identity.py: sidecar_info / is_unmatched shared by scraper and API.
- Shell wiring (rail, Home, panel lists, close), the provenance switch in
  Settings -> Model settings, locale keys, docs and CHANGELOG.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 01:14:54 +08:00
DemonGatanjieuandClaude Opus 5.5 3a221b71d3 feat(models): type chips head the model grid; voice tag buttons say what they copy
The models page starts with a chip per models folder (Checkpoint, LoRA, ...)
and its count. A chip lists the whole folder with its subfolders
(GET /anomalous/type_models); a folder picked in the list narrows the grid
to that folder, shown as a crumb whose x goes back to the whole type. The
chosen type is remembered.

owner.modelScope now says what the grid lists; currentType/PathIdx/Subfolder
stay the folder of the model at hand, set from each card (focusModel), so
the editor, the scanner and "add to canvas" get the right subfolder.

Voice clips: the copy button reads "Copy {tag}" with a tooltip on what
pasting it does, and is gone for characters with only a main voice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 01:09:40 +08:00
DemonGatanjieuandClaude Opus 5.5 230566b864 perf(gallery): show thumbnails in the output gallery; release its images when closed
The gallery grid loaded every output at full size: a 1024x1536 PNG decodes to
about 6 MB in the browser, so a few pages of outputs held hundreds of MB to
GBs of browser memory and graphics memory. Cards now use a cached 512 px WebP
from /anomalous/output_thumbnail (the model cards' thumbnail cache; about
0.7 MB decoded); dragging to the canvas, the viewer and the workbench still use
the original. When the browser has been closed for 90 s its gallery images are
released like the model grid, and reopening on the gallery reloads them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:39:48 +08:00
DemonGatanjieuandClaude Opus 5.5 9b0b95ff22 fix(shell): the narrow-window list is a drawer; cap the activity log at 2 MB
In a narrow or docked window the open list now sits against the rail over a
dimmed page, and closes when a folder or character is picked, when the dimmed
page is pressed (that press does not reach the cards) or on Esc. Wide windows
are unchanged.

The activity log also drops its oldest entries past 2 MB, so long canvas
entries cannot outgrow the JSON writer's limit and stop the log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:14:28 +08:00
DemonGatanjieuandClaude Opus 5.5 376284e647 feat(activity): log what Anomalous changed on the canvas and in files
A new Activity page on the rail (and the home page's recent list) shows, by day,
what the plugin changed. Record only; undo comes later (AD-018).

- api/activity_log.py keeps the newest 500 entries in the ComfyUI user folder.
  A middleware records this plugin's and Anomalous_TTS's write requests after
  they succeed (including the 200 + {"status": "error"} style as failure), from
  one route table; the log never fails the request it records.
- activity_canvas.js: a press inside Anomalous snapshots the canvas; the next
  press or key outside it (or the next press inside) logs the difference, so
  every button, drag and dialog that writes nodes is covered and the user's own
  edits are not. Opening another workflow is logged as that. <html> carries an
  Anomalous class and does not count as the plugin's interface.
- activity_diff.js: pure snapshot and difference; activity_log.js: client and
  wording; ui_activity.js: the page (filters, details, find on canvas, clear)
  and the home list.
- Tests: tests/activity_diff.mjs, tests/test_activity_log.py (local).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 00:00:28 +08:00
DemonGatanjieuandClaude Opus 5.5 32a3719d97 fix: offline scans stay offline, workshop snap dock, 400 on malformed requests
From an outside audit:
- The scan wizard's offline mode still sent the greyed-out rename and
  overwrite options, and scraper.py fetched Civitai model pages and preview
  media for models whose .info held a Civitai id. Offline now implies no
  media and no model page; the folder scan and scan_all refuse a missing or
  non-object body instead of defaulting to an online scan.
- The Prompt Workshop's snap dock referenced leftSearch from the source deck
  module (ReferenceError on click); the deck now exposes focusSearch().
- translate, delete_model, delete_gallery_image and the image-material
  routes answer malformed bodies with 400 instead of 500.
- Removed six unused imports in ui_doctor.js and 16 duplicate locale keys
  per language (the later, effective entry is kept, so nothing changes on
  screen).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:36:07 +08:00
DemonGatanjieuandClaude Opus 5.5 721a006b16 refactor(audio): drop F5-TTS, the audio page manages GPT-SoVITS only
The F5-TTS voice library (input/F5-TTS scanning, voice upload with ffmpeg
conversion, romanization, Load Audio clip drags) and the engine switch are
removed. The audio page now works with one engine, Anomalous_TTS
(GPT-SoVITS): characters, drags onto its node, the Script Director with
direct generation, pronunciation and settings. The audio gallery and its
stream route stay (output and temp folders only). The root PATH hack that
existed for F5-TTS's ffmpeg lookup is gone. Recorded as AD-016.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 13:53:07 +08:00