Skip to content

ci(deps): bump actions/setup-python from 5 to 6#4

Closed
dependabot[bot] wants to merge 558 commits intomainfrom
dependabot/github_actions/actions/setup-python-6
Closed

ci(deps): bump actions/setup-python from 5 to 6#4
dependabot[bot] wants to merge 558 commits intomainfrom
dependabot/github_actions/actions/setup-python-6

Conversation

@dependabot
Copy link
Copy Markdown

@dependabot dependabot Bot commented on behalf of github Apr 19, 2026

Bumps actions/setup-python from 5 to 6.

Release notes

Sourced from actions/setup-python's releases.

v6.0.0

What's Changed

Breaking Changes

Make sure your runner is on version v2.327.1 or later to ensure compatibility with this release. See Release Notes

Enhancements:

Bug fixes:

Dependency updates:

New Contributors

Full Changelog: actions/setup-python@v5...v6.0.0

v5.6.0

What's Changed

Full Changelog: actions/setup-python@v5...v5.6.0

v5.5.0

What's Changed

Enhancements:

Bug fixes:

... (truncated)

Commits
  • a309ff8 Bump urllib3 from 2.6.0 to 2.6.3 in /tests/data (#1264)
  • bfe8cc5 Upgrade @​actions dependencies to Node 24 compatible versions (#1259)
  • 4f41a90 Bump urllib3 from 2.5.0 to 2.6.0 in /tests/data (#1253)
  • 83679a8 Bump @​types/node from 24.1.0 to 24.9.1 and update macos-13 to macos-15-intel ...
  • bfc4944 Bump prettier from 3.5.3 to 3.6.2 (#1234)
  • 97aeb3e Bump requests from 2.32.2 to 2.32.4 in /tests/data (#1130)
  • 443da59 Bump actions/publish-action from 0.3.0 to 0.4.0 & Documentation update for pi...
  • cfd55ca graalpy: add graalpy early-access and windows builds (#880)
  • bba65e5 Bump typescript from 5.4.2 to 5.9.3 and update docs/advanced-usage.md (#1094)
  • 18566f8 Improve wording and "fix example" (remove 3.13) on testing against pre-releas...
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

64v and others added 30 commits April 10, 2026 20:26
One-click Windows script that:
- Builds installer, manual-update, and Wizard Guild executables
- Commits to SFW repo and pushes
- Mirrors source + binaries to NSFW sibling repo and pushes
- Supports --no-push, --installer-only, --guild-only, --push-only

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previous version tried to git-commit 300MB .exe files which exceeds
GitHub's 100MB limit. Now:
- Adds .gitignore (dist/, build/, __pycache__, etc.)
- Builds all executables into dist/
- Pushes SOURCE only to both SFW and NSFW repos
- Uploads binaries to GitHub Release via gh CLI or Python fallback
- Uses selective file copy for NSFW mirror (preserves NSFW-only content)
- Supports --tag vX.Y to set release version

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ntax

Inline Python in batch files breaks cmd.exe parser. Moved release
upload to standalone release_upload.py. Also fixed NSFW mirror to
use selective copy preserving NSFW-only content.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root now shows only:
  Install.bat      — run the installer
  Settings.bat     — configure guild settings
  Wizard Guild.bat — launch the wizard guild

Developer scripts moved to dev/ (rebuild.bat, release_upload.py,
debug_guild.bat, update.bat). Rebuild.bat paths updated for dev/ location.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Canonical spellcaster_core/ package with architectures, composites,
node_factory, model_detect, and prompt_enhance modules. GIMP plugin
and Wizard Guild now import from this single source via thin shims.

4 ComfyUI nodes: SpellcasterLoader (auto-arch), SpellcasterPromptEnhance
(LLM), SpellcasterSampler (auto-config), SpellcasterOutput (privacy).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds _install_spellcaster_nodes() to copy comfyui-spellcaster/ into
custom_nodes/ComfyUI-Spellcaster during installation. Skips local
nodes in the git clone loop. Manifest updated with node pack entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ComfyUI-Spellcaster now lives at github.com/laboratoiresonore/ComfyUI-Spellcaster
- Installer manifest updated: git clone (auto-update) instead of local copy
- Removed _install_spellcaster_nodes() local copy logic from installer
- Synced all rewritten node files with correct ComfyUI APIs
- Added web extension, workflow templates, README, LICENSE

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Added comfyui-spellcaster/ with all 4 base nodes + 2 NSFW additions:
  SpellcasterNSFWLoRA (preset/manual/stack) and SpellcasterNSFWLoRAModelOnly
- NSFW LoRA presets for Flux Dev, Klein, SDXL, Illustrious, WAN I2V
- Updated manifest.json to git clone from ComfyUI-Spellcaster-NSFW repo
- Updated rebuild.bat to sync only base files (preserve NSFW additions)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…aming

- Fix missing architectures (ltx, wan, seedvr, chroma, pony) in GIMP,
  Darktable, and guild_common ARCH_LORA_PREFIXES — video LoRAs no longer
  leak into SDXL/SD1.5 dropdowns
- Change server.py LoRA fallback from ["sd15"] to ["unknown"] to prevent
  unclassified LoRAs from polluting SD1.5 menus
- Add POST /api/scaffold_edit endpoint with persistent scaffold_overrides.json
  — scaffold editor changes now survive restarts
- Wire frontend ScaffoldEditor to debounce-save edits to server
- Load server-side scaffolds into editor on mount (auto-detected wizards
  now appear in the scaffold list)
- Add background LLM-powered scaffold enhancement: auto-names "Unnamed
  Wizard" entries using local LLM when available
- Installer: add LLM URL prompt, ComfyUI server probing, shared settings
- Add "Wan-2.2-I2V\\" to wan LoRA prefixes in canonical model_detect.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When installed via ComfyUI Manager (git clone), users only get the
nodes. On first load, Spellcaster now:
- Drops Install_Spellcaster_Suite.bat into custom_nodes/ — one click
  to clone the full repo and run the installer
- Prints a console banner with instructions
- Shows a dismissable toast in the ComfyUI web UI pointing to the bat

All signals are suppressed once the full suite is detected
(spellcaster_settings.json or .suite_installed marker).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nager flow

- Main README: add "Already Using ComfyUI Manager?" section explaining
  the auto-dropped Install_Spellcaster_Suite.bat
- ComfyUI node README: add Full Spellcaster Suite section, note about
  install toast, add Pony to supported architectures table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
During installation, features whose custom nodes and required models are
already present on the ComfyUI server are now shown as locked (✓) and
cannot be toggled off — reinstalling them would be a no-op.

- Add feature_already_installed() that cross-references manifest against
  server_info from probing (nodes via provides, models via filename match)
- step_select_features now accepts server_info, shows locked features as
  cyan [✓] with "Already on server" reason
- step_install_nodes skips node packs whose provides are already in
  available_nodes
- Hardware profile summary shows installed count separately

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract KLEIN_MODELS, FLUX2_VAE to module-level constants in
  _workflows_v2.py; delete 8 duplicated inline dicts (~70 lines)
- Import KLEIN_MODELS in comfyui-connector.py instead of redefining
- Add STUDIO_FACE/BODY/SCENE dimension constants for canvas-aware
  compositing across the Magic Studio 5-act pipeline
- build_photobooth: fixed square output (STUDIO_FACE_W×STUDIO_FACE_H)
  instead of deriving from reference aspect; add transparent= flag
  for rembg background removal with alpha matting
- build_rembg: expose alpha_matting and model params
- build_klein_blend: default scale from STUDIO_BODY_IN_SCENE_SCALE
  so body PNGs fill ~85% of scene height automatically

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
For users who run ComfyUI on a separate machine in their local network.
Probes the remote server, auto-detects local apps (GIMP, Darktable),
installs plugins + Wizard Guild + shortcuts — zero interaction needed.

- install_remote.py: standalone autonomous installer
  - Network scan (--scan) to auto-discover ComfyUI on /24 subnet
  - Server probing via /system_stats + /object_info endpoints
  - Feature detection by cross-referencing server nodes vs manifest
  - Auto-detect GIMP, Darktable paths (cross-platform)
  - Plugin deployment with remote server URL pre-configured
  - Wizard Guild + scaffold installation with launcher scripts
  - Desktop/Start Menu shortcuts pointing at remote ComfyUI
  - --dry-run, --interactive, --skip-* flags for flexibility

- build_installer.py: --remote / --remote-only flags for PyInstaller build

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The remote installer now probes the ComfyUI server's LoRA and model lists
for known NSFW patterns (nicegirls, aidmansfw, phr00t, etc.) to detect
whether the SFW or NSFW edition is running. Based on detection:

- Writes nsfw_mode flag to spellcaster_settings.json
- Sets up nsfw/.github_token for Wizard Guild NSFW auto-updates
- Shows edition in summary banner

New flags: --nsfw-token <PAT>, --force-sfw

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Documents the new install_remote.py with usage examples, feature list,
full flag reference, and download badges. Updates the existing installer
walkthrough to link to the dedicated remote installer section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e instructions

No release binary exists yet — point users at the Python script instead,
with a note on how to build the standalone .exe themselves.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a clearly labeled button on page 1 of the GUI installer for users
whose ComfyUI backend runs on a separate LAN machine. The button
launches install_remote.py --interactive in a new terminal window.

Descriptive text makes it clear this only installs local plugins and
shortcuts (GIMP, Darktable, Wizard Guild) — it does NOT install
ComfyUI or models on the local machine.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The main GUI installer now has the Antenna Installer button built into
the Welcome page, so the verbose clone-and-run-from-source instructions,
build-your-own-exe section, collapsible walkthrough, and CLI flag table
are no longer needed. Replaced with a single sentence pointing users to
the button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When user enters a remote ComfyUI server URL in the Welcome page prereqs
panel and the connection test succeeds, the Antenna Installer button now
appears right there — offering to install only local plugins and
shortcuts without going through the full 8-step wizard.

Also scrubs remaining example IPs from install.py and
patch_sillytavern.py doc strings, replacing with <SERVER-IP> placeholders.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rebuild.bat now passes --remote to build_installer.py so the
spellcaster-remote-installer.exe is built alongside the main installer
and uploaded to GitHub Releases.

_launch_antenna_installer now correctly handles frozen .exe mode by
looking for spellcaster-remote-installer.exe next to the main
installer, instead of trying to run a .py with no Python interpreter.
Also passes the server URL if the user already entered one.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace supplementary-plane emoji (U+1F4E1) with BMP arrow (U+2192)
in antenna button labels — Tcl/Tk on Windows can choke on codepoints
above U+FFFF in certain widget contexts.

Replace <SERVER-IP> placeholder in entry field with plain text
"your-server-ip" to avoid potential Tcl angle-bracket interpretation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of warning and skipping, rebuild.bat now clones
spellcaster_NSFW automatically next to the SFW repo when it
can't find it. Falls back gracefully if the clone fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Windows 'start' command interprets the first quoted argument as
a window title. When the exe path has spaces, start treats it as
the title and launches nothing (or crashes). Fix: pass empty ""
as the title so the exe path is correctly interpreted as the
program to run.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The NSFW repo is private. The previous clone URL had no auth and
would hang prompting for credentials or fail with 403. Now extracts
the full remote URL from the SFW repo (which includes the PAT) and
swaps the repo name, so the clone authenticates automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Step 7 crash: The Python one-liner for version auto-detection had
nested single quotes that broke cmd.exe parsing (`.read( was
unexpected`). Fixed by writing to a temp .py file first.

Steps 5/6 push failures: Added git pull --rebase before push for
both SFW and NSFW repos so remote changes don't cause rejections.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parentheses in .read() and .group(1) were parsed by cmd.exe as
batch block delimiters when inside an if() block. Moved the
detection outside the if block using goto, and pipe output to a
temp file with set /p instead of for /f. Uses \x22 and \x27
escapes for quote chars to avoid all quoting conflicts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
64v and others added 25 commits April 18, 2026 15:41
…ing installer)

Rule 13 warns that Guild and GIMP plugin restarts auto-download from main
and OVERWRITE uncommitted local edits. Details:
  - Which updater fires when, what's protected, what gets clobbered
  - Pre-restart git-status check that Claude must run
  - Three safe-restart options (commit, DEVNOUPDATE launcher, stash)
  - Explicit rule: never say a restart is "safe" without checking first

Rule 14 documents the new self-updating installer bootstrap pattern so
future Claude sessions know the .exe doesn't need rebuilding for most
fixes. Just push to main and existing .exe picks it up.

Also added cross-reference from Rule 5 (local GIMP deploy) to Rule 13,
and rule #6 in spellcaster-expert.md subagent prompt teaching the same.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Spellcaster's "antenna" was a probe-only client installer — it could
detect what was on a remote ComfyUI but couldn't install anything. The
user's vision: one agent per server machine on the LAN, each advertising
what it hosts (LLM / ComfyUI / Resolve), clients routing requests to
whichever agent they need.

This commit is Phase 1 foundation:

  antenna/README.md    Full architecture spec + threat model + multi-machine
                       diagram (Machine A = LLM, B = ComfyUI, C = Resolve
                       with one client coordinating).
  antenna/__init__.py  Version.
  antenna/config.py    First-launch bootstrap:
                       - ~/.spellcaster/antenna_config.json (port, bind,
                         services list, service-specific paths)
                       - ~/.spellcaster/antenna_token (secrets.token_urlsafe
                         256-bit bearer, 0600 on POSIX)
                       - ~/.spellcaster/antenna.crt + .key (openssl-generated
                         self-signed RSA2048, 10yr, SANs for hostname +
                         localhost + LAN IP so clients connecting by any
                         address pass hostname verification)
                       - cert_fingerprint() helper for client pinning
                       - rotate_token() for "token leaked, nuke it" scenarios

Zero non-stdlib deps. openssl CLI used for cert generation (every
realistic ComfyUI host has it; stdlib fallback path raises with an
install-openssl message).

Services layer (Phase 1 = "comfyui", Phase 2 = "llm", Phase 4 =
"resolve") declared in config["services"] so adding a new service type
is a new file in antenna/services/, not a rewrite.

Live-tested on this box: bootstrap() generates config + token + cert,
cert SANs include hostname/localhost/LAN IP, fingerprint is 64-char
SHA-256 pair-formatted for easy client comparison.

Next: auth.py (token compare + rate limit), agent.py (HTTPS server),
first endpoints (/, /status).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 1 incremental — standing up the TLS server with full auth pipeline
and the two endpoints clients need to discover a box on the LAN.

antenna/auth.py
  - load_token() re-reads from disk per request so rotate-token takes
    effect without restarting the agent
  - verify_token() uses hmac.compare_digest (constant-time)
  - extract_bearer() strict parser — case-insensitive scheme, rejects
    non-Bearer, rejects empty values
  - RateLimiter: sliding-window per IP, thread-safe deque, default
    30 req/min configurable via antenna_config.json
  - authenticate_request() returns (ok, error_msg) so the agent can
    echo a short, non-sensitive reason in the JSON 401

antenna/agent.py
  - ThreadingHTTPServer wrapped in TLS 1.2+ SSLContext from the
    self-signed cert built by config.py
  - 6-step request pipeline: rate-limit → route-match → auth →
    body-parse → dispatch → audit-log
  - Lazy endpoint imports so antennas with services=["llm"] don't need
    comfyui endpoint modules installed
  - CORS preflight + Access-Control-Allow headers so the Wizard Guild
    (browser JS) can call us cross-origin
  - 1 MB request body cap
  - Exception handler catches unhandled endpoint errors, logs the
    traceback to stderr + audit log, returns generic 500 to client
    (no internal leakage)
  - Graceful SIGINT/SIGTERM via threaded server.shutdown()
  - log_message override silences default stderr access-log noise —
    we have our own structured audit log

antenna/endpoints/__init__.py — handler contract docstring
antenna/endpoints/status.py
  - GET / — unauthenticated liveness, deliberately minimal
    (service name + version + protocol num only; no hostname, no paths)
  - GET /status — authenticated, rich: version, uptime_seconds,
    hostname (already in cert SAN), services_declared, services_detail
    with per-service reachability probe. Paths returned as basenames
    only so attackers can't use the response to guess the user's home
    directory layout.
  - _probe_comfyui() hits /system_stats, extracts gpu_name + VRAM
    total/free, swallows exceptions into an error string
  - _probe_llm() probes Kobold (/api/v1/model) or Ollama (/api/tags)
    based on config.llm_engine

Live-tested end-to-end:
  GET /              → 200 {"service":"spellcaster-antenna",...}
  GET /status (no auth)     → 401 missing Authorization...
  GET /status (wrong token) → 401 invalid token
  GET /status (valid token) → 200 full JSON w/ ComfyUI probe result
  GET /nonexistent          → 404
  31 rapid hits              → 30 pass, then 429 with Retry-After

Audit log writes every request line with status code. TLS handshake
verified (curl -k needed for self-signed; clients will pin the
fingerprint instead).

Next: integration with Mega Bridge's /api/interfaces heartbeat, then
POST /install-node and POST /install-model endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…artup

Adding a new Spellcaster-compatible service (e.g. SillyTavern, a future
video tool, etc.) previously needed a .py edit + rebuild. Now it's a
JSON file that both the installer and the antenna fetch from main at
runtime, with the baked copy as offline fallback.

New files:
  installer/remote_services.json   registry: 7 services (comfyui, kobold,
                                   ollama, sillytavern, gimp, darktable,
                                   resolve). Each entry has key, label,
                                   description, default_port, detect_paths,
                                   detect_process, probe_path, managed_ops.

  installer/remote_services.py     dynamic loader:
                                     1. Fetch GitHub JSON (5s timeout)
                                     2. Validate required keys
                                     3. Fall back to baked copy
                                   Module-level cache + refresh=True for
                                   long-running antennas. Convenience
                                   accessors: by_key(), all_keys(),
                                   desktop_apps(), network_services().

Pattern matches installer/bootstrap.py — fetch-latest-from-GitHub with
offline fallback. Pushing a new service to main reaches every running
installer/antenna on next startup, no redistribution needed.

Live-tested: `python3 -m installer.remote_services` with no network
access → falls back to baked copy, lists all 7 services correctly.
After push, the fetch path will activate.

Next: installer step_ask_remote_services() that loops over this list
asking "is X on another machine?" per service, then generates a
per-machine antenna.bat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The installer now asks, per registered service (comfyui, kobold, ollama,
sillytavern, gimp, darktable, resolve, ...), where it runs:

  [1] Local — on THIS machine
  [2] Remote — on another machine on my network
  [3] Skip — I'm not using this

Remote selections are grouped by IP so one antenna.bat is generated per
machine, not per service. A single box hosting both ComfyUI + Ollama
gets a single .bat that advertises both.

Generated files per remote machine (written to <install>/antennas/):
  - antenna_for_<ip>.bat    Windows launcher
  - antenna_for_<ip>.sh     Linux/macOS launcher
  - README.txt              One-line instructions per file

Each launcher:
  - Embeds a UNIQUE per-machine token (secrets.token_urlsafe(32))
    so leaking one bat doesn't compromise other remotes
  - Embeds the hub URL (auto-detected via LAN socket trick)
  - Embeds the services array the remote antenna should advertise
  - On first launch: downloads the antenna bundle from
    <hub>/api/antenna/bundle.zip (endpoint coming next commit),
    writes config + token to ~/.spellcaster/, launches the agent
  - On subsequent launches: just starts the agent
  - Friendly error if hub is unreachable

step_ask_remote_services(args) returns a dict suitable for passing
straight into generate_antenna_files(remotes, output_dir, hub_url).
install.py will wire these into main() in the next commit.

Live-tested:
  - 2 remote machines declared (ComfyUI+Ollama, SillyTavern)
  - Correct per-machine service isolation (sillytavern box doesn't
    advertise comfyui in its 'services' array)
  - Tokens are unique per machine (verified via regex extraction)
  - README lists each remote with its services

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…esence

Introduces the "no dead functions" architecture. Every frontend (GIMP,
Darktable, Resolve, Guild, SillyTavern, Signal) can now publish events,
upload assets, and heartbeat its presence to the Wizard Guild. The UI
renders interface-specific chips (Send to Resolve / Open in GIMP / Edit
in Darktable) only when the target is actually installed + enabled +
online — never dead buttons pointing at nonexistent plugins.

Core modules (spellcaster_core/, synced across 4 repos):
- event_bus.py       — thread-safe pub/sub with ring-buffer replay
- interface_registry.py — installed+enabled+online gate for every UI
- asset_gallery.py   — hash-indexed shared asset store with SHA-256
                       dedup and sharded blob layout
- cross_interface.py — thin HTTP client every frontend imports
- model_registry.py  — unified /object_info cache shared across tools
- signal_notifier.py — outbound notifications on render completion

Guild server (tavern/server.py):
- Added 8 endpoints: /api/interfaces, /api/interfaces/heartbeat,
  /api/events, /api/events/stream, /api/events/emit, /api/assets (GET/POST),
  /api/assets/<hash>, /api/models
- HTTPServer → ThreadingHTTPServer so SSE subscriptions don't block
  the rest of the API

Guild UI (tavern/static/):
- Sidebar "Connected apps" strip polls /api/interfaces every 10s,
  renders only active interfaces. Empty = hidden entirely.
- Image action chips filter by interface availability. New cross-
  interface chips: 🎬 Send to Resolve, 🖼️ Open in GIMP, 📷 Edit in
  Darktable. Each first persists the image to the shared gallery,
  then emits the bus event with a stable hash URL.

DaVinci Resolve plugin suite (plugins/resolve/):
- Spellcaster Bridge workflow integration (always-on): SSE client,
  media pool sync, auto-heartbeat, bus subscription to resolve.* events
- Generate from Playhead: keyboard-shortcut script that grabs the
  current frame and creates a new shot on the Guild
- Smart Fill Gap: detects gaps between clips and queues FLF renders
- Shared HTTP client + resolve_helpers, README with install paths

GIMP plugin:
- Lazy-start cross-interface client, auto-heartbeat on every menu
  invocation, _publish_event helper ready for _run_* methods

Darktable plugin:
- guild_heartbeat() + guild_emit_event() helpers (curl-based to match
  existing HTTP pattern), fires a heartbeat on plugin load

Dynamic presence guarantee: all "Send to X" chips, overflow entries,
sidebar items, and event handlers gate on the registry. No UI element
exists for a plugin that isn't there — verified end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User hit RuntimeError on first launch: 'openssl is required' even
though Git for Windows was installed (bundles openssl, just not on
PATH). Now:

1. _find_openssl() searches PATH first, then Git-for-Windows common
   locations (Program Files\Git\usr\bin, mingw64\bin), Chocolatey bin,
   and C:\OpenSSL-Win64. Anyone who cloned via Git has openssl.

2. _generate_cert_powershell() added as Windows-without-openssl fallback
   using New-SelfSignedCertificate. The PFX-to-PEM extraction is a
   dangling TODO — noted with a clear RuntimeError that directs the
   user to install Git or OpenSSL instead. Easiest win given the
   PKCS12-decode complexity without the cryptography package.

3. ANTENNA_NO_TLS=1 escape hatch in config.tls_enabled() + agent.serve():
   - Skips cert generation entirely on bootstrap
   - Serves plain HTTP on the configured port instead of wrapping TLS
   - Startup banner shows scheme + reminds user it's plain HTTP
   - Bearer token auth still required — LAN + token alone is 95% safe
   - Clear "install openssl to re-enable TLS" hint in banner

4. Flushed the 'Ready' banner so buffered stdout in subprocess launches
   displays the full startup header immediately instead of waiting for
   the first request (saw this in earlier testing on Windows).

The user can now run ANTENNA_NO_TLS=1 python -m antenna.agent on the
ComfyUI box and the agent starts immediately. Upgrade to TLS later by
installing openssl + re-running without the env var.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enables zero-touch remote iteration: dev pushes to main, curls
/self-update with the bearer token, the remote agent pulls the new
code and restarts within ~2 seconds. The operator never has to touch
the remote terminal.

Endpoint flow:
  1. git fetch + reset --hard origin/main   (if source is a git repo)
  2. Compile-check every antenna/**/*.py    (py_compile each file)
  3. On syntax error:
       - git reset back to the pre-update SHA
       - return 500 with the error — agent stays alive on old code
  4. On success:
       - record pre-update SHA to ~/.spellcaster/antenna_last_sha
       - return 202 with {updated_from, updated_to}
       - schedule a detached successor process (python -m antenna.agent)
         after a 500ms delay so the HTTP response flushes first
       - os._exit(0) after the successor has had 800ms to rebind :7334

Rollback mode ({"rollback": true} in body):
  - Reads antenna_last_sha
  - git reset --hard to it
  - Re-validates + restarts
  - Returns 202 {rolled_back_to: <sha>}
  - 409 if no last_sha exists (nothing to roll back to)

Safety layers:
  - Bearer-token gated (audit-logged)
  - Syntax validation BEFORE restart — bad push never bricks remote
  - Never touches ~/.spellcaster/ (token, cert, audit log, last_sha
    all survive the git reset)
  - Timeouts on every subprocess call (no hung git fetches)
  - Detached successor on Windows (CREATE_NEW_PROCESS_GROUP +
    DETACHED_PROCESS) so parent exit doesn't kill child

From here on, every installer/antenna fix can reach the remote box
via one curl to /self-update.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_build_routes() was swallowing all ImportErrors silently, making it
impossible to debug why /self-update wasn't appearing. Now:

  - ImportError → WARN line to stderr with the error
  - Any other exception → also logged (catches SyntaxError in
    dynamically-imported modules which isn't an ImportError)
  - Success → 'registered: POST /self-update'
  - At end of _build_routes: prints full route table

Safe for production — no behaviour change, just better observability
on startup. Operators can now tell from the first 20 lines of stdout
whether an endpoint module loaded or failed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
First real auto-deploy round-trip confirmed:
  push a923fa4 → curl /self-update → successor process started → old
  agent exited → new agent (uptime 3s) serving requests on the same port.

No more manual restarts needed on the remote box.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…dge)

Remote antennas now advertise each declared service as its own
interface chip in the Guild sidebar. A beefy GPU box running both
ComfyUI and Ollama emits two heartbeats per cycle:
  interface=antenna.comfyui, meta={machine, ip, agent_url, vram_*}
  interface=antenna.ollama,  meta={machine, ip, agent_url, reachable}

The antenna.* namespace keeps remote services distinct from local
ones of the same name (local GIMP and remote GIMP coexist without
collision). Meta includes machine hostname + LAN IP + agent_url so
cross-app events (davinci.asset.send, gimp.asset.open) can route to
the right box.

antenna/heartbeat.py
  - _HeartbeatThread: daemon thread, 10s interval, wake-on-stop event
  - _build_payloads: one payload per service, adds service-specific
    vitals (ComfyUI VRAM probe)
  - _send_one: POST with 5s timeout, silent on transport errors
  - Consecutive-failure tracking: log first failure + every 30th
    (every 5 min at 10s interval) instead of spamming stderr
  - start()/stop() idempotent singleton

antenna/agent.py
  - Import heartbeat module
  - serve() calls heartbeat.start(cfg) after server banner
  - No-op when cfg["hub_url"] is empty (local-only agent)

The protocol contract (POST {hub}/api/interfaces/heartbeat, body
{interface, meta}) matches the Mega Bridge Round 1 spec. If that
evolves, only _build_payloads() needs updating.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…to main()

Closes the installer loop for multi-machine setups. After the regular
install finishes, the installer asks per service (ComfyUI, Kobold,
Ollama, SillyTavern, GIMP, Darktable, Resolve) whether it's local,
remote, or skipped. Each remote IP collected gets one tailored
.bat + .sh with:

  - Embedded unique bearer token (secrets.token_urlsafe 256-bit)
  - Embedded hub_url pointing at THIS machine (installer LAN IP:7777)
  - Embedded services array the remote antenna should advertise
  - git clone bootstrap on first launch (replaces the old
    /api/antenna/bundle.zip approach — simpler, no Guild endpoint
    dependency, works today since all boxes cloning via git already
    have git)
  - git pull on subsequent launches so the antenna picks up updates
    even when /self-update isn't reachable
  - Prominent bootstrap banner on first launch printing token +
    fingerprint so the operator can paste back if needed

Install.py integration:
  - Only runs in interactive mode (skipped on --yes / --dry-run)
  - Any exception in the remote step logs a warning but never crashes
    the install (user's local setup is done before we ask about remotes)
  - Output dir: <install>/../antennas/ — sits next to ComfyUI so the
    user can see it in the same directory they set during install
  - Prints generated filenames + README.txt pointer

The generated scripts no longer depend on /api/antenna/bundle.zip —
one less hub endpoint to build. Each remote box pulls directly from
GitHub via git. The hub URL is still used for heartbeats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…estarts

When the operator edits ~/.spellcaster/antenna_config.json manually
(e.g. setting hub_url after bootstrap), they need a way to restart the
agent to pick up the new config without pushing a code change. Now
POST /self-update with {"force": true} does exactly that — no code
pull needed, just schedules a restart.

No-force behavior unchanged: already-up-to-date returns 200 with a
helpful hint about the force flag.
Operators couldn't tell from outside whether the antenna was actually
trying to heartbeat or silently skipping. Now /status includes:

  'heartbeat': {
    'enabled': true,
    'hub_url': 'http://...',
    'consecutive_failures': 3,
    'last_cycle_ok': false,
    'interval_seconds': 10
  }

So a client curling /status can distinguish:
  - enabled=false → antenna wasn't given a hub_url
  - enabled=true, last_cycle_ok=true → heartbeats are flowing
  - enabled=true, last_cycle_ok=false → antenna is trying but hub
    is unreachable (firewall, down, wrong URL, etc.)

Useful right now: the user's Guild hit a startup error and isn't
accepting connections. With this, we can confirm the antenna side
is healthy while debugging the hub side independently.
load_config() drops any key not in DEFAULT_CONFIG as a typo guard.
hub_url wasn't listed, so every time the agent restarted, it silently
stripped the user's hub_url out of their config file.

Symptom: heartbeat thread always showed {enabled: false, hub_url: null}
on /status despite the user having manually added hub_url to their
antenna_config.json.

Now hub_url is a first-class config key with empty-string default
(= heartbeats disabled, agent still serves /status locally).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
HANDOVER_*.md files at repo root contain real LAN IPs + local paths
(intended for Claude-to-Claude orchestration between sessions, never
for the public repo). Per CLAUDE.md rule 11.

Also deleted 7 throwaway Playwright screenshots that were cluttering
the repo root from prior automated testing runs.
Rounds 37-43 (all fully shipped, 384 tests pass):
- R37: prompt character count + limit warning
- R38: auto-scroll to rendering shot, data-shot-id attr
- R39: queue ETA from historical render-time avg
- R40: shot diff indicator — prompt/preset/overrides vs last render
- R41: revert shot to last-rendered settings (per-shot + audit)
- R42: side-by-side comparison view for changed fields
- R43: negative prompt in diff/revert, batch revert for selected shots

Round 44 (PARTIAL — backend + server only, no frontend, no tests yet):
- Shotboard.batch_prompt_edit(shot_ids, prefix, suffix, mode)
  Idempotent add/remove of common prefix/suffix across selected
  prompts. Skips locked shots. Returns {modified, skipped}.
- POST /api/video/batch-prompt-edit with 400-validation on missing
  prefix+suffix, invalid mode, empty shot_ids.

R44 frontend (batch UI + keyboard nav) and tests land in the next
commit per the 2-features-per-round-commit contract — this partial
is safe because the endpoint is auth-gated and the method is
idempotent with no cross-shot side effects.

Verified backward-compat (audit 2026-04-18):
- GIMP plugin standalone works without Guild
- Guild works without antennas or bridge wiring
- test_video_layer.py exercises only shotboard + /api/video/*

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every successful ComfyUI download now also uploads to the Wizard
Guild's shared asset gallery via CrossInterfaceClient.upload_asset(),
firing a gimp.asset.uploaded bus event. That lights the image up in
the Guild's Recent-across-apps sidebar strip, so generations made in
GIMP are visible to users in the Guild chat UI without re-upload.

Implementation:
- _maybe_publish_to_guild_gallery(data, filename) — best-effort
  helper with silent-fail semantics. Hooked into _download_image at
  both the cache-hit and cache-miss branches.
- Size gate: skip <100 bytes (sentinel error images) and >32 MB
  (probably video frames — gallery is image-only).
- Extension gate: only .png/.jpg/.jpeg/.webp uploaded; skip video
  and anim formats to avoid flooding.
- Zero breakage when Guild is offline — lazy CrossInterfaceClient
  returns None when unreachable; try/except wraps the whole path.

Audit-confirmed backward-compat: GIMP plugin standalone operation
(no Guild running) unaffected. All errors swallowed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Thread-safe bounded deque (100 msgs, 5-min TTL) exposing:
  - Mailbox class with deliver() / peek(consume=..., since_id=...) / ack_ids()
  - get_mailbox(iface_key) singleton registry
  - fanout_from_event(event) — origin-aware router that drops
    <iface>.<rest> events into the matching mailbox, skipping echo

Synced to canonical (comfyui-spellcaster/) and dev copy
(plugins/gimp/comfyui-connector/). Sibling repos
(ComfyUI-Spellcaster[-NSFW]) get this in their own commits.

Not yet wired into tavern/server.py — the route table / handler
methods the Mega Bridge handover describes were never saved to disk
by the originating session. This primitive is ready for whoever
picks up that work. Zero runtime impact until wired: audit confirmed
no file imports mailbox outside its own docstring example.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- spellcaster_api.py: queue_shot() added with render_shot back-compat
  alias; list_presets() normalises 4 different server response shapes
- media_pool_sync.py: accept both new 'shot-update' SSE shape AND
  legacy 'shot.ready' / 'shot.updated' events
- scripts/generate_from_playhead.py + smart_fill_gap.py: updated
  against the current /api/video/* contract

Pure drift fixes. Independent of the mailbox / cross-iface work.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5f — ship antenna/endpoints/comfyui.py as Phase-2 stubs
  Previously every antenna startup logged
    [antenna] comfyui service declared but endpoints not yet built
  because agent.py unconditionally imports this module. Stubs expose
  install_node() and install_model() returning 501 not_yet_implemented
  with a clear hint pointing operators at the CLI installer for now.
  Future request/response shapes documented in docstrings so client
  code written today pins the right contract.

5g — README endpoint table split Phase 1 (live) vs Phase 2 (stub)
  Was misleading operators into curl-ing /install-node and seeing it
  "work" (it was previously a 404 when the agent had the ImportError
  silently swallowed). Now the table explicitly flags Phase 1 vs Phase
  2 status, cross-links to the endpoint stubs.

Both fixes from the backward-compat audit 2026-04-18. Zero behavior
change for existing Phase 1 endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GitHub's dependency graph only tracks PyPI packages, but Spellcaster's real
AI-side dependencies are ComfyUI custom-node packs (24 of them, tracked in
installer/manifest.json). This adds:

- DEPENDENCIES.md  — human-readable table grouped into required (20) vs
  optional (4) packs, with repo links, the features each unlocks, and notes.
- scripts/generate_dependencies_md.py — regenerator that keeps DEPENDENCIES.md
  in sync with installer/manifest.json as the single source of truth.
- README: extra status badges (stars, issues, last-commit, downloads, dep
  count) and a Dependencies link in the nav row.

Part of the GitHub discoverability pass across the Spellcaster ecosystem.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Auto-surfaces which Spellcaster-compatible apps are present on the
machine where the antenna runs, without needing to manually edit
antenna_config.json's services array. Callers get an inventory keyed
by service_key with installed/evidence/signals details.

Three detection signals, combined (ANY hit = installed=True):

1. Filesystem — walks drive letters (Windows) / $HOME, /Applications,
   /opt, /usr (POSIX) looking for declared detect_paths. Hits return
   the full resolved path as evidence.
2. Process   — tasklist/ps scan for detect_process substring match.
3. Network   — HTTP GET on http://127.0.0.1:<default_port><probe_path>
   with 1.5s timeout (only for services with default_port > 0).

Evidence priority: network > process > filesystem (stronger signals
win). Parallelized via threads with a 3-second batch cap so /status
stays snappy. 30-second result cache so consecutive /status calls
don't re-probe.

Surface:
- `antenna/detect.py:detect_installed_services(services)` — pure
  function, returns {key: evidence}. No side effects.
- `antenna/detect.py:invalidate_cache()` — force re-probe (called by
  self-update after code refresh).
- `antenna/endpoints/status.py` — /status response now includes
  `services_detected` alongside `services_declared`. Operators can
  see "hey, Darktable's installed here but I didn't enable it on
  the antenna — maybe add it".

Stdlib-only. Silent on every error path — detection must never 500
the /status endpoint. All exceptions caught and surfaced as
"evidence: detect failed: <msg>".

Live-tested on this machine: 7 services inventoried correctly —
GIMP/Darktable via filesystem, Ollama via network+process, others
correctly reported absent.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5 to 6.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot @github
Copy link
Copy Markdown
Author

dependabot Bot commented on behalf of github Apr 19, 2026

Labels

The following labels could not be found: ci, dependencies. Please create them before Dependabot can add them to a pull request.

Please fix the above issues or remove invalid values from dependabot.yml.

@dependabot @github
Copy link
Copy Markdown
Author

dependabot Bot commented on behalf of github May 2, 2026

OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting @dependabot ignore this major version or @dependabot ignore this minor version. You can also ignore all major, minor, or patch releases for a dependency by adding an ignore condition with the desired update_types to your config file.

If you change your mind, just re-open this PR and I'll resolve any conflicts on it.

@dependabot dependabot Bot deleted the dependabot/github_actions/actions/setup-python-6 branch May 2, 2026 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant