Commit Graph
100 Commits
Author SHA1 Message Date
EthanfelandClaude Opus 4.6 f97f8a0616 feat: resolutions — 6 fixed slots, always visible
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 01:11:07 +02:00
EthanfelandClaude Opus 4.6 4b51d3c95d feat: simplify resolutions UI — fixed key, index-labeled rows, single add button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 01:07:59 +02:00
EthanfelandClaude Sonnet 4.6 281c04dd2e feat: ProjectResolution JS extension for ComfyUI frontend
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 00:42:46 +02:00
EthanfelandClaude Sonnet 4.6 31406cb092 feat: resolution series editor in sequence card
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 00:42:46 +02:00
EthanfelandClaude Sonnet 4.6 b31faa4274 feat: add ProjectResolution node
Implements ProjectResolution with TDD: fetches a [width, height] pair
from a resolution series by loop index, clamping out-of-bounds indices
to the last entry and returning (512, 512) defaults on error or missing key.
Also registers the node in mappings and updates TestNodeMappings count to 4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 00:42:46 +02:00
EthanfelandClaude Opus 4.6 80aff2ba43 fix: update ProjectSource tests for file_name output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 00:42:16 +02:00
Ethanfel c1c929722c Merge branch 'feat/snapshot-timeline' 2026-04-03 00:41:44 +02:00
EthanfelandClaude Opus 4.6 d3becdc598 docs: fix 4 bugs in resolution series plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 00:21:32 +02:00
EthanfelandClaude Opus 4.6 4f31d792df docs: resolution series implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 00:19:03 +02:00
EthanfelandClaude Opus 4.6 67c40c1ebe docs: resolution series design doc
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 00:15:08 +02:00
EthanfelandClaude Opus 4.6 ba8ce45846 fix: make snapshot list fill available viewport height
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 18:23:56 +01:00
EthanfelandClaude Opus 4.6 74b57f71ac feat: add file_name output to ProjectSource node
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 18:16:31 +01:00
EthanfelandClaude Opus 4.6 1ec3abf17a feat: replace Git-DAG timeline with flat snapshot browser
Replace HistoryTree (DAG with branches, Graphviz rendering) with a flat
chronological SnapshotTimeline. New UI features: split-view layout,
snapshot compare/diff, cherry-pick restore of individual sequences or
fields, auto-snapshots with debounce, and pin/filter support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 18:14:22 +01:00
EthanfelandClaude Opus 4.6 686d4687c3 fix: cast sequence_number to int in fetch_key
Hidden widget sync passes sequence_number as string, causing format
code errors downstream. Cast to int before use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 11:42:19 +01:00
EthanfelandClaude Opus 4.6 a37dd82ae3 fix: parse file list API response format correctly
API returns {"files": [{"name": "...", "data_type": "..."}]}, not a
plain array. Extract file names from the nested structure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 11:26:39 +01:00
EthanfelandClaude Opus 4.6 3b11a4e974 feat: file_name combo on ProjectSource, sequence_number output
- file_name is now a combo dropdown populated from the API when
  manager_url and project_name are set
- ProjectSource outputs sequence_number (INT) for downstream use
- Refreshes file list when project_name or manager_url changes
- Updated tests for new output and error-default behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 11:20:41 +01:00
EthanfelandClaude Opus 4.6 5eb82f8ff6 fix: preserve saved combo value across load-order race
When ProjectKey configures before ProjectSource, _getSourceLabels
returns empty. replaceWithCombo now always keeps the saved value in
the options list so it survives the race condition.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 22:24:17 +01:00
EthanfelandClaude Opus 4.6 bf598ebf80 fix: make key_name selection sticky, never auto-reset
The key_name combo now only updates its dropdown options from the API
but never changes the user's selected value. Only the output value
refreshes on execution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 21:01:03 +01:00
EthanfelandClaude Opus 4.6 6e232da193 fix: remove _refreshKeys from onMouseDown to prevent key reset
The async _refreshKeys call on every mouse click caused a race condition
where clicking the key_name dropdown would trigger a re-fetch that
overwrote the user's selection. Keys are now only refreshed on source
label change and workflow load.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 21:00:19 +01:00
EthanfelandClaude Opus 4.6 ff5802ab63 fix: don't crash on 404, add sync debug logging
ProjectKey.fetch_key now returns empty defaults instead of raising
RuntimeError on API errors. Added logging to _syncFromSource and
fetch_key to trace the seq=4001 vs seq=4 mismatch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:58:42 +01:00
EthanfelandClaude Opus 4.6 413e1c09e9 fix: ProjectKey pulls fresh data on click, add debug logging
ProjectKey onMouseDown now triggers _syncFromSource + _refreshKeys so
clicking a relay always picks up source config changes. Added console
logs to notifyRelays and _refreshKeys for diagnosing sync issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:46:50 +01:00
EthanfelandClaude Opus 4.6 672b28e27f feat: split lora name and strength into separate keys
Reverses the previous merge migration. Lora data is now stored as
separate keys: 'lora 1 high' (STRING name) and 'lora 1 high strength'
(FLOAT). This allows ProjectKey relay nodes to output name and strength
as properly typed separate values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 16:18:33 +01:00
EthanfelandClaude Opus 4.6 3dc91319a2 fix: notify relay nodes when source config changes
When ProjectSource widgets (url, project, file, sequence_number)
change, all ProjectKey nodes referencing that source now re-sync
and refresh their key dropdown immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 12:43:05 +01:00
EthanfelandClaude Opus 4.6 bd36b4b725 fix: prevent undefined in combo widgets with empty values
Combo widgets show "undefined" when values list is empty. Now ensures
at least one entry (empty string placeholder) and picks a valid default.
Also populates source labels immediately on node creation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 15:34:01 +01:00
EthanfelandClaude Opus 4.6 77eb3473ab fix: properly hide INT widgets and create real combo dropdowns
- INT widgets (sequence_number) now properly hidden using origType +
  hidden flag pattern from fast_saver.js
- source_label and key_name are now replaced with real combo widgets
  via addWidget("combo") instead of just setting type="combo" on
  STRING widgets, which didn't produce working dropdowns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 15:27:52 +01:00
EthanfelandClaude Opus 4.6 2cf8cc1f0a fix: add IS_CHANGED to ProjectKey and document source_label usage
ProjectKey fetches live API data, so it must re-execute on every queue.
Added comment explaining why source_label exists but is unused in Python.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 11:42:15 +01:00
EthanfelandClaude Opus 4.6 545b864c08 feat: add ProjectKey JS extension with source/key dropdowns
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 11:39:48 +01:00
EthanfelandClaude Opus 4.6 ad6cd76b08 feat: add ProjectSource JS extension with label title sync
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 11:36:29 +01:00
EthanfelandClaude Opus 4.6 bd7d314ae8 feat: add ProjectKey single-output relay node
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 11:34:22 +01:00
EthanfelandClaude Opus 4.6 628b256981 feat: add ProjectSource config-only node
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 11:32:47 +01:00
EthanfelandClaude Opus 4.6 fb007920ee Fix history_tree_backup bloat: strip snapshot data from backups
The history_tree_backup (created by _delete_nodes) was storing full
snapshot data in every backed-up node — 185MB+ per backup entry.
This caused the JSON file to re-bloat to 300MB on every save.

Now:
- _delete_nodes backs up tree metadata only (no snapshot data)
- Load paths strip snapshot data from existing backup entries
- Prevents both disk and RAM bloat from backup accumulation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 10:23:23 +01:00
EthanfelandClaude Opus 4.6 d3955c489b Write slim history tree to JSON when DB is enabled
The JSON file was storing full snapshot data in every history node,
causing files to grow to multi-GB. Now when DB is enabled:
- sync_to_db receives full tree (extracts snapshots to DB)
- save_json receives slim tree (no snapshot data)
- JSON file stays small, DB is authoritative for snapshots

When DB is disabled, JSON still stores full snapshots (only store).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 10:00:51 +01:00
EthanfelandClaude Opus 4.6 e575a78893 Fix missing import, add transaction safety, clean orphaned snapshots
- Add load_json to tab_timeline_ng imports (NameError on disk fallback)
- Wrap save_history_tree in BEGIN/COMMIT transaction (was autocommitting
  each statement, risking partial writes on failure)
- Clean up orphaned history_snapshots in sync_to_db when nodes are
  removed from the tree

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 09:56:10 +01:00
EthanfelandClaude Opus 4.6 a1a85ecc4d Fix bugs in snapshot stripping: auto-note, mass update, DB-off, fallback
- _auto_change_note now loads previous snapshot from DB instead of
  reading stripped in-memory node (was producing wrong commit messages)
- _render_mass_update now strips snapshots after save (was leaking RAM)
- Only strip snapshots when DB is enabled (preview/restore still works
  without DB via in-memory or disk fallback)
- _render_data_preview adds disk fallback matching _restore_node

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 09:52:46 +01:00
EthanfelandClaude Opus 4.6 eac4e4f08b Fix RAM leak: strip history snapshots from memory, load on demand
History tree nodes stored full data snapshots in memory (5-50MB each),
accumulating with every save. Now:

- New `history_snapshots` DB table stores node data separately
- `save_history_tree` and `sync_to_db` extract snapshots before saving
- In-memory tree nodes only hold metadata (id, parent, note, timestamp)
- Restore and preview load snapshots from DB on demand
- `save_and_snap` uses json roundtrip instead of deepcopy (1 copy not 2)
- `_src_cache` moved to AppState, cleared on file switch
- `strip_snapshots()` method on HistoryTree for explicit cleanup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 09:48:47 +01:00
EthanfelandClaude Opus 4.6 79e1426036 Fix dict mutation race: snapshot data before background save/sync
json.dump in a background thread would crash with "dictionary changed
size during iteration" when the UI mutated data concurrently. Now all
save_json and sync_to_db calls receive a json.loads(json.dumps(data))
snapshot, isolating the serialization from live UI mutations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 09:36:46 +01:00
EthanfelandClaude Opus 4.6 ba330dd208 Fix sub-segment ordering: group subs after their parent in DB load
ORDER BY sequence_number put all subs (>=1000) at the end. Now groups
by parent (seq/1000), main first, then subs in order.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 00:25:19 +01:00
EthanfelandClaude Opus 4.6 9c560ccfd0 Add timing breakdown to load_full_data for performance diagnosis
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 00:21:59 +01:00
EthanfelandClaude Opus 4.6 480131e327 Add load_full_data method to reconstruct data from DB
Replaces slow JSON file parsing with fast DB queries for file loading.
Returns the same dict structure as load_json (top-level + batch_data +
history_tree).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 00:19:44 +01:00
EthanfelandClaude Opus 4.6 fac5013359 Load data from DB instead of parsing huge JSON files
- load_file and on_select try db.load_full_data first (~0.01s),
  fall back to load_json only when DB has no data
- Fix unawaited coroutine warning for auto-load (asyncio.ensure_future)
- Fix radio on_change to properly await async load_file
- Reuse current data cache when source file matches current file,
  eliminating a redundant 1.3s JSON parse during render

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 00:17:20 +01:00
EthanfelandClaude Opus 4.6 45ce264675 Fix DB init crash: wrap bulk migration in explicit transaction
The COMMIT without BEGIN failed in autocommit mode, crashing ProjectDB
init and leaving _shared_db as None ("Database not initialized").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 00:03:13 +01:00
EthanfelandClaude Opus 4.6 0f134a1a20 Add one-time bulk migration to merge lora keys in all stored sequences
Runs at DB startup, only updates rows that have stale separate strength
keys. No-op once all data is migrated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:58:56 +01:00
EthanfelandClaude Opus 4.6 a9197efacd Merge lora name+strength into single key to stay under 32 output limit
Combines separate lora name and strength keys into "name:strength" format,
removing 6 strength keys to free output slots for mode. Migration handles
legacy <lora:> wrapper, separate strength keys, and already-merged formats.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:58:32 +01:00
EthanfelandClaude Opus 4.6 ecb5cdc13f Add comprehensive timing logs across all critical paths
Logs with perf_counter timing on: file load/save, DB sync, all
render functions, save & snap (with deepcopy/save/sync breakdown),
graphviz cache hit/miss, node restore, and API endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:53:30 +01:00
EthanfelandClaude Opus 4.6 1386043f69 Remove blanket DEFAULTS backfill that exceeded MAX_DYNAMIC_OUTPUTS
Adding all 33 DEFAULTS keys to sequences caused the ComfyUI loader
to exceed its 32 output slot limit, triggering tuple index out of
range errors. Only lora strength migration remains on load/sync.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:47:16 +01:00
EthanfelandClaude Opus 4.6 c4700c620d Backfill default keys during sync_to_db before writing sequences
Ensures mode and all other DEFAULTS keys are present in DB
sequences without bloating API read responses with unexpected keys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:42:34 +01:00
EthanfelandClaude Opus 4.6 589c84fd95 Fix remaining blocking I/O calls and N+1 project query
- tab_batch_ng.py: async create_batch with to_thread save/sync
- tab_raw_ng.py: async do_save with to_thread, replace deepcopy
  with dict comprehension for display data
- main.py: async create_new with to_thread save
- tab_projects_ng.py: replace per-project count_data_files with
  single list_projects_with_file_counts JOIN query
- db.py: add list_projects_with_file_counts method

Zero blocking I/O calls remain in UI callbacks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:40:32 +01:00
EthanfelandClaude Opus 4.6 37e9e1001e Remove blanket DEFAULTS backfill from DB get_sequence
Adding all DEFAULTS keys to API responses shifted output slot
indices, breaking existing ComfyUI workflow links (tuple index
out of range). Only lora migration remains on the DB read path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:35:40 +01:00
EthanfelandClaude Opus 4.6 526af7097d Backfill default keys in DB get_sequence for API responses
Ensures the project loader API always returns all expected keys
like mode, cfg, etc. even if they were missing from stored data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:28:51 +01:00
EthanfelandClaude Opus 4.6 c880c16865 Backfill missing default keys into sequences on JSON load
Ensures all sequences have required keys like mode, cfg, etc.
from DEFAULTS via setdefault so they persist on next save.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:24:34 +01:00
EthanfelandClaude Opus 4.6 82e4ba526c Ensure lora strength is always a float in API and JSON
Force float coercion in both migration paths (load_json and DB read)
and override type detection in get_sequence_keys so lora strength
keys always report as FLOAT regardless of JSON deserialization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 23:02:04 +01:00
EthanfelandClaude Opus 4.6 08338746e2 Deactivate graph poll timer on client disconnect
Prevents 'parent slot deleted' RuntimeError when the timeline
tab is destroyed while the timer is still firing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 22:59:24 +01:00
EthanfelandClaude Opus 4.6 15047016b9 Migrate legacy LoRA format at JSON load time
Run _migrate_lora_keys on every load_json call so all sequences
get split name/strength keys immediately, not just when the LoRA
expansion is rendered. Next save writes the clean format to disk.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 22:55:38 +01:00
EthanfelandClaude Opus 4.6 29aa87ee00 Migrate legacy LoRA format on DB read so API returns split keys
Add _migrate_lora_keys to get_sequence() so the /api endpoints
always return separate lora name and strength keys, even for
data stored in the old <lora:name:strength> format.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 22:52:13 +01:00
EthanfelandClaude Opus 4.6 be9c95ffbd Split LoRA keys into separate name and strength fields
Store lora name and strength as independent JSON keys instead of the
combined <lora:name:strength> format. Legacy format is auto-migrated
on load. Timeline preview updated to show all 6 LoRA slots.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 22:21:48 +01:00
EthanfelandClaude Opus 4.6 074e36f883 Fix blocking I/O on event loop, cache graphviz, optimize DB sync
Move all save_json/load_json/sync_to_db/DB calls off the event loop
with asyncio.to_thread to prevent UI freezes. Cache graphviz SVG by
DOT source hash (bounded LRU of 20). Replace DELETE-all/re-INSERT in
sync_to_db with UPSERT + targeted DELETE. Add DB indexes, COUNT query,
and reduce graph poll interval to 0.5s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-18 22:17:25 +01:00
EthanfelandClaude Opus 4.6 b36200faaa Detect stale project references and offer clear/recreate options
When current_project in config references a project not found in the
database, show a warning with buttons to either clear the reference
or recreate the project instead of displaying a misleading label.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 23:36:28 +01:00
EthanfelandClaude Opus 4.6 5aac1677f7 Fix page reset on save: async I/O and avoid needless deepcopy
Root cause: save_json + sync_to_db blocked the event loop while
serializing the growing history tree (all snapshots) as JSON,
causing NiceGUI websocket timeout and client reconnect.

- Skip history tree in snapshot deepcopy (copied only to discard)
- Move save_json/sync_to_db to asyncio.to_thread in all callbacks
- Make save_and_snap, commit, sort_by_number, shift_fts,
  _add_sequence, apply_mass_update async

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 23:17:53 +01:00
EthanfelandClaude Opus 4.6 f3ad3e01bc Fix page reset on save: disable reload, handle orphaned timers
- Set reload=False to prevent watchfiles from triggering full page
  reloads when JSON/DB files are written during save
- Timeline graph poll timer (200ms) now deactivates itself when its
  parent slot is deleted during UI refresh
- Comfy monitor poll timer catches RuntimeError from deleted parent
  slots instead of crashing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 22:50:11 +01:00
EthanfelandClaude Opus 4.6 efd0a31426 Restrict reload watcher to .py files to prevent page reload on save
reload=True was watching all file changes, causing full page reloads
when save_json/save_config wrote .json and .json.tmp files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 22:30:57 +01:00
EthanfelandClaude Opus 4.6 b042fe4368 Fix 25+ bugs across rounds 4-8 of comprehensive code review
history_tree.py:
- Cycle protection in generate_graph() parent walk
- KeyError → .get() for malformed node data in commit() and generate_graph()
- UUID collision check with for/else raise in commit() and _migrate_legacy()
- RuntimeError → ValueError for consistent exception handling

tab_timeline_ng.py:
- Re-parent children walks to surviving ancestor for batch deletes
- Branch tip deletion re-points to parent instead of removing branch
- Cycle protection in _walk_branch_nodes and _find_branch_for_node
- Full data.clear() restore instead of merge in _restore_node
- Safe .get('data', {}) in restore and preview
- Reset stale branch selection after node deletion
- json.dumps for safe JS string escaping in graphviz renderer

tab_batch_ng.py:
- NaN/inf rejection in dict_number with math.isfinite()
- _safe_int used in recalc_vace, update_mode_label, frame_to_skip
- Uncaught ValueError from htree.commit() caught with user notification

tab_comfy_ng.py:
- asyncio.get_event_loop() → get_running_loop()

utils.py:
- Atomic writes for save_config and save_snippets
- save_config extra_data can't override explicit last_dir/favorites

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 10:23:14 +01:00
EthanfelandClaude Opus 4.6 04b9ed0e27 Fix 4 bugs: SQL conflict handling, HTML escaping, backup cap, safe int cast
- sync_to_db: use ON CONFLICT for duplicate sequence numbers
- history_tree: html.escape() for Graphviz DOT labels
- tab_timeline_ng: cap history_tree_backup to 10 entries
- tab_batch_ng: add _safe_int() helper for VACE settings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:03:13 +01:00
EthanfelandClaude Opus 4.6 1b8d13f7c4 Fix 7 bugs: bounds checks, deepcopy, time import, JS keys, unused import
- Add bounds check on src_batch index in add_from_source and copy_source
- Guard delete callback against stale index after rapid clicks
- Replace __import__('time').time() with time.time() in sync_to_db
- Use deepcopy(DEFAULTS) consistently in utils.py and main.py
- Use JSON.stringify in JS onConfigure fallback path for key storage
- Read state.show_comfy_monitor for checkbox initial value
- Remove unused KEY_BATCH_DATA import from tab_projects_ng

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:41:00 +01:00
EthanfelandClaude Opus 4.6 497e6b06fb Fix 7 bugs: async proxies, mode default, JS key serialization, validation
- Use asyncio.to_thread for proxy endpoints to avoid blocking event loop
- Add mode to DEFAULTS so it doesn't silently insert 0
- Use JSON serialization for keys in project_dynamic.js (with comma fallback)
- Validate path exists in change_path, friendly error on duplicate rename
- Remove unused exp param from rename closure
- Use deepcopy for DEFAULTS consistently

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:29:24 +01:00
EthanfelandClaude Opus 4.6 993fc86070 Auto-detect change notes when saving without a manual note
Compares current batch data against the last snapshot to generate
descriptive notes like "Added seq 3; Changed: prompt, seed".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:24:07 +01:00
EthanfelandClaude Opus 4.6 c9bcc735f4 Change refresh input from INT to combo dropdown (off/on)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:29:30 +01:00
EthanfelandClaude Opus 4.6 dc8f44f02b Add refresh input to ProjectLoaderDynamic to force re-fetch
Changing the refresh value triggers the node to re-fetch keys from
the API, picking up any new or modified fields in the data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 14:27:51 +01:00
EthanfelandClaude Opus 4.6 2a6b4f5245 Add mode integer field above sequence number in batch cards
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 01:07:09 +01:00
EthanfelandClaude Opus 4.6 60d1162700 Fix async callbacks: make rename/change_path directly async
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:42:00 +01:00
EthanfelandClaude Opus 4.6 204fc4ea85 Add rename for sequences and projects, per-sub color cycling, project path editing
- Sequences: add rename button with name shown in expansion header
- Subsequences: cycle through 6 distinct border colors by sub-index
- Projects: add rename and change path buttons with DB methods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:40:35 +01:00
Ethanfel 033b3415c2 Merge branch 'feature/sqlite-project-db' 2026-03-01 00:32:07 +01:00
EthanfelandClaude Opus 4.6 2ccc3821d6 Add visual distinction for subsequence cards with teal border
The subsegment-card CSS class was not being applied to subsequence
expansion items. Add the class conditionally and include the teal
accent CSS rules with a 6px left border.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:31:00 +01:00
EthanfelandClaude Opus 4.6 187b85b054 Clean up: remove unnecessary info.outputs logic, set label on reused slots
The actual fix was setting slot.label alongside slot.name. Reverted
onConfigure to read from widget values (which work correctly) and
ensured label is set on both new and reused output slots.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:12:30 +01:00
EthanfelandClaude Opus 4.6 a0d8cb8bbf Fix: set output label alongside name for LiteGraph rendering
LiteGraph renders slot.label over slot.name — we were updating name
but the display uses label.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:10:50 +01:00
EthanfelandClaude Opus 4.6 d55b3198e8 Fix output names not surviving page refresh in ProjectLoaderDynamic
Read output names from info.outputs (serialized node data) instead of
hidden widget values, which ComfyUI may not persist across reloads.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:43:34 +01:00
EthanfelandClaude Opus 4.6 bf2fca53e0 Remove JSONLoaderDynamic, handled by ComfyUI-JSON-Dynamic extension
The separate ComfyUI-JSON-Dynamic extension provides the same node.
Removes json_loader.py, web/json_dynamic.js, and their tests. Only
ProjectLoaderDynamic remains in this extension.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:18:39 +01:00
EthanfelandClaude Opus 4.6 5b71d1b276 Fix output name persistence: use comma-separated like reference impl
JSON.stringify format for hidden widget values didn't survive ComfyUI's
serialization round-trip. Switch to comma-separated strings matching
the proven ComfyUI-JSON-Dynamic implementation. Remove properties-based
approach in favor of the simpler, working pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:11:04 +01:00
EthanfelandClaude Opus 4.6 027ef8e78a Fix ProjectLoaderDynamic output names lost on page reload
Hidden widget values for output_keys/output_types were not reliably
restored by ComfyUI on workflow reload. Store keys/types in
node.properties (always persisted by LiteGraph) as primary storage,
with hidden widgets as fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 23:04:14 +01:00
EthanfelandClaude Opus 4.6 86693f608a Remove 9 redundant JSON loader nodes, keep only JSONLoaderDynamic
JSONLoaderDynamic auto-discovers keys at runtime, making the hardcoded
Standard, Batch, and Custom nodes unnecessary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:36:33 +01:00
Ethanfel 615755ba44 Revert "Remove 9 redundant JSON loader nodes, keep only JSONLoaderDynamic"
This reverts commit 4b09491242.
2026-02-28 22:36:25 +01:00
EthanfelandClaude Opus 4.6 4b09491242 Remove 9 redundant JSON loader nodes, keep only JSONLoaderDynamic
JSONLoaderDynamic auto-discovers keys at runtime, making the hardcoded
Standard, Batch, and Custom nodes unnecessary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:33:51 +01:00
EthanfelandClaude Opus 4.6 4b5fff5c6e Improve ProjectLoaderDynamic UX: single node, error feedback, auto-refresh
Remove 3 redundant hardcoded nodes (Standard/VACE/LoRA), keeping only the
Dynamic node. Add total_sequences INT output (slot 0) for loop counting.
Add structured error handling: _fetch_json returns typed error dicts,
load_dynamic raises RuntimeError with descriptive messages, JS shows
red border/title on errors. Add 500ms debounced auto-refresh on widget
changes. Add 404s for missing project/file in API endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 22:16:08 +01:00
EthanfelandClaude Opus 4.6 d07a308865 Harden ROLLBACK against I/O errors in transactions
If the original error (e.g., disk full) also prevents ROLLBACK from
executing, catch and suppress the ROLLBACK failure so the original
exception propagates cleanly and the connection isn't left in a
permanently broken state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:44:12 +01:00
EthanfelandClaude Opus 4.6 c4d107206f Fix 4 bugs from third code review
- Fix delete_proj not persisting cleared current_project to config:
  page reload after deleting active project restored deleted name,
  silently breaking all DB sync
- Fix sync_to_db crash on non-dict batch_data items: add isinstance
  guard matching import_json_file
- Fix output_types ignored in load_dynamic: parse declared types and
  use to_int()/to_float() to coerce values, so downstream ComfyUI
  nodes receive correct types even when API returns strings
- Fix backward-compat comma-split for types not trimming whitespace:
  legacy workflows with "STRING, INT" got types " INT" breaking
  ComfyUI connection type-matching

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:38:37 +01:00
EthanfelandClaude Opus 4.6 b499eb4dfd Fix 8 bugs from second code review
HIGH:
- Fix JS TypeError on empty API response: validate keys/types are arrays
  before using them; add HTTP status check (resp.ok)
- Fix BEGIN IMMEDIATE conflict: set isolation_level=None (autocommit) on
  SQLite connection so explicit transactions work without implicit ones

MEDIUM:
- Fix import_json_file non-atomic: wrap entire operation in BEGIN/COMMIT
  with ROLLBACK on error — no more partial imports
- Fix crash on non-dict batch_data items: skip non-dict elements
- Fix comma-in-key corruption: store keys/types as JSON arrays in hidden
  widgets instead of comma-delimited strings (backward-compat fallback)
- Fix blocking I/O in API routes: change async def to def so FastAPI
  auto-threads the synchronous SQLite calls

LOW:
- Fix missing ?. on app.graph.setDirtyCanvas in refreshDynamicOutputs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:32:35 +01:00
EthanfelandClaude Opus 4.6 ba8f104bc1 Fix 6 bugs found during code review
- Fix NameError: pass state to _render_vace_settings (tab_batch_ng.py)
- Fix non-atomic sync_to_db: use BEGIN IMMEDIATE transaction with rollback
- Fix create_secondary() missing db/current_project/db_enabled fields
- Fix URL encoding: percent-encode project/file names in API URLs
- Fix import_json_file crash on re-import: upsert instead of insert
- Fix dual DB instances: share single ProjectDB between UI and API routes
- Also fixes top_level metadata never being updated on existing data_files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:25:31 +01:00
EthanfelandClaude Opus 4.6 6b7e9ea682 Port dynamic node improvements from ComfyUI-JSON-Dynamic
- Deferred output cleanup (_configured flag + queueMicrotask) to prevent
  breaking links when other nodes (e.g. Kijai Set/Get) resolve outputs
  during graph loading
- file_not_found error handling in refresh to keep existing outputs intact
- Fallback widget sync in onConfigure when widget values are empty but
  serialized outputs exist

Applied to both json_dynamic.js and project_dynamic.js.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:15:56 +01:00
EthanfelandClaude Opus 4.6 c15bec98ce Add SQLite project database + ComfyUI connector nodes
- db.py: ProjectDB class with SQLite schema (projects, data_files,
  sequences, history_trees), WAL mode, CRUD, import, and query helpers
- api_routes.py: REST API endpoints on NiceGUI/FastAPI for ComfyUI
  to query project data over the network
- project_loader.py: ComfyUI nodes (ProjectLoaderDynamic, Standard,
  VACE, LoRA) that fetch data from NiceGUI REST API via HTTP
- web/project_dynamic.js: Frontend JS for dynamic project loader node
- tab_projects_ng.py: Projects management tab in NiceGUI UI
- state.py: Added db, current_project, db_enabled fields
- main.py: DB init, API route registration, projects tab
- utils.py: sync_to_db() dual-write helper
- tab_batch_ng.py, tab_raw_ng.py, tab_timeline_ng.py: dual-write
  sync calls after save_json when project DB is enabled
- __init__.py: Merged project node class mappings
- tests/test_db.py: 30 tests for database layer
- tests/test_project_loader.py: 17 tests for ComfyUI connector nodes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 21:12:05 +01:00
EthanfelandClaude Opus 4.6 0d8e84ea36 Add .gitignore with worktrees, pycache, pytest_cache
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:59:39 +01:00
EthanfelandClaude Opus 4.6 e2f30b0332 Color graph nodes by branch for visual distinction
Each branch gets a unique subtle tint (grey, blue, purple, coral,
teal, sand) so sub-branches are visually distinguishable. HEAD
(yellow) and branch tip (green) colors still take priority.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 20:22:45 +01:00
EthanfelandClaude Opus 4.6 24f9b7d955 Fix graph interactivity: use querySelector instead of NiceGUI DOM ID
The c{id} DOM ID pattern was wrong. Use document.querySelector with
the timeline-graph class instead, with retries until g.node elements
are present in the DOM.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:27:00 +01:00
EthanfelandClaude Opus 4.6 d56f6d8170 Fix graphviz crash: use polyline splines instead of ortho
splines=ortho triggers a trapezoid-table overflow assertion in
graphviz's dot layout engine on complex graphs. polyline gives
similar angled edges without the crash.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:21:43 +01:00
EthanfelandClaude Opus 4.6 f2980a9f94 Fix graph: NiceGUI blocks script tags in ui.html()
Move JS back to ui.run_javascript() with retry-based DOM lookup
using NiceGUI's element ID (c{id}). CSS stays inline via style tag.
Retries up to 10 times at 50ms intervals to handle Vue async render.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:20:32 +01:00
EthanfelandClaude Opus 4.6 4e3ff63f6a Fix graph interactivity: embed JS/CSS inline in HTML
Previous approach used ui.run_javascript with getElement() which
failed due to Vue rendering timing. Now embeds the script and style
directly inside the HTML content so there are no DOM lookup or
timing issues — the script runs inline when parsed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:19:26 +01:00
EthanfelandClaude Opus 4.6 6e01cab5cd Fix graph interactivity: use NiceGUI element ref and requestAnimationFrame
The click handlers weren't attaching because getElementById couldn't
find the container — Python's id() generated IDs that didn't survive
NiceGUI's DOM rendering. Now uses getElement() with the NiceGUI
element ID and defers JS via requestAnimationFrame to ensure the
DOM is ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:15:56 +01:00
EthanfelandClaude Opus 4.6 16ed81f0db Fix tiny graph: keep SVG natural size, scroll on overflow
Stop replacing the SVG's width/height attributes — this was shrinking
the graph to fit the container. Instead keep graphviz's native pt
dimensions and let the scroll container handle overflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:14:25 +01:00
EthanfelandClaude Opus 4.6 d98cee8015 Fix timeline graph height: remove invalid SVG height="auto"
Drop the fixed height attribute entirely instead of setting it to
"auto", which SVGs don't support. The viewBox attribute handles
proportional scaling when only width="100%" is set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:11:03 +01:00
EthanfelandClaude Opus 4.6 2ebf3a4fcd Interactive timeline graph: click nodes to select in node manager
Add click-to-select functionality to the graphviz SVG timeline graph.
Clicking a node highlights it with an amber border, auto-switches the
branch selector, and updates the node manager panel. The SVG is now
responsive (100% width, scroll container) instead of fixed-size.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 00:06:13 +01:00
EthanfelandClaude Opus 4.6 a4cb979131 Remove stale Streamlit references from comments
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:18:37 +01:00
EthanfelandClaude Opus 4.6 9a3f7b7b94 Remove old Streamlit UI files superseded by NiceGUI migration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:17:38 +01:00