Ship MiniMax v2 identity refs and Qwen sidecar edits.
Keep v1 as the default video graph, relay image edits to the Qwen Lightning box, and keep /api/health up if one Comfy host is unset. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
"""Install scripts/comfy-host-agent.mjs on the sidecar image-Comfy PC over SSH.
|
||||
|
||||
Reads AIGEN_IMAGE_SSH_HOST, AIGEN_IMAGE_SSH_USER, and AIGEN_IMAGE_SSH_KEY
|
||||
(default: %USERPROFILE%\\.ssh\\aigen_image_comfy) or AIGEN_IMAGE_SSH_PASS.
|
||||
Installs the host agent only. Does not start Comfy or load models.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import paramiko
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
AGENT = ROOT / "scripts" / "comfy-host-agent.mjs"
|
||||
REMOTE_DIR = r"C:\Users\comfyapi\aigen-agent"
|
||||
REMOTE_AGENT = REMOTE_DIR + r"\comfy-host-agent.mjs"
|
||||
REMOTE_START = REMOTE_DIR + r"\start.cmd"
|
||||
NODE_ZIP = "https://nodejs.org/dist/v22.18.0/node-v22.18.0-win-x64.zip"
|
||||
|
||||
|
||||
def connect():
|
||||
host = os.environ.get("AIGEN_IMAGE_SSH_HOST", "192.168.77.101")
|
||||
user = os.environ.get("AIGEN_IMAGE_SSH_USER", "comfyapi")
|
||||
password = os.environ.get("AIGEN_IMAGE_SSH_PASS")
|
||||
key_path = os.environ.get("AIGEN_IMAGE_SSH_KEY") or str(Path.home() / ".ssh" / "aigen_image_comfy")
|
||||
if not Path(key_path).exists():
|
||||
key_path = os.environ.get("AIGEN_IMAGE_SSH_KEY")
|
||||
client = paramiko.SSHClient()
|
||||
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
kwargs = {
|
||||
"hostname": host,
|
||||
"username": user,
|
||||
"timeout": 15,
|
||||
"allow_agent": False,
|
||||
"look_for_keys": False,
|
||||
}
|
||||
if key_path:
|
||||
kwargs["key_filename"] = key_path
|
||||
elif password:
|
||||
kwargs["password"] = password
|
||||
else:
|
||||
raise SystemExit("Set AIGEN_IMAGE_SSH_PASS or AIGEN_IMAGE_SSH_KEY")
|
||||
client.connect(**kwargs)
|
||||
return client, host, user
|
||||
|
||||
|
||||
def run(client, cmd, timeout=120):
|
||||
stdin, stdout, stderr = client.exec_command(cmd, timeout=timeout)
|
||||
out = stdout.read().decode("utf-8", "replace")
|
||||
err = stderr.read().decode("utf-8", "replace")
|
||||
code = stdout.channel.recv_exit_status()
|
||||
return code, out, err
|
||||
|
||||
|
||||
def main():
|
||||
if not AGENT.exists():
|
||||
raise SystemExit(f"missing {AGENT}")
|
||||
token = os.environ.get("IMAGE_COMFY_CONTROL_TOKEN") or os.urandom(24).hex()
|
||||
token_file = Path(os.environ.get("TEMP", ".")) / "image_comfy_control_token"
|
||||
token_file.write_text(token, encoding="ascii")
|
||||
pubkey = Path.home() / ".ssh" / "aigen_image_comfy.pub"
|
||||
|
||||
start_cmd = "\r\n".join([
|
||||
"@echo off",
|
||||
f"cd /d {REMOTE_DIR}",
|
||||
"set COMFY_CONTROL_PORT=8199",
|
||||
"set COMFY_PROXY_PORT=8198",
|
||||
"set COMFY_HOST=http://127.0.0.1:8188",
|
||||
f"set COMFY_CONTROL_TOKEN={token}",
|
||||
r"set COMFY_LAUNCH_CWD=C:\ComfyUI-QwenEdit\ComfyUI",
|
||||
r"set COMFY_LAUNCH_CMD=C:\ComfyUI-QwenEdit\python\python.exe C:\ComfyUI-QwenEdit\ComfyUI\main.py --listen 0.0.0.0 --port 8188",
|
||||
r'"C:\Users\comfyapi\aigen-agent\node.exe" comfy-host-agent.mjs',
|
||||
"",
|
||||
])
|
||||
|
||||
client, host, user = connect()
|
||||
print("connected", user, host)
|
||||
code, out, err = run(client, f'mkdir "{REMOTE_DIR}" 2>nul & echo dir-ok')
|
||||
print("mkdir", code, out.strip() or err.strip())
|
||||
|
||||
sftp = client.open_sftp()
|
||||
with sftp.file(REMOTE_AGENT, "wb") as handle:
|
||||
handle.write(AGENT.read_bytes())
|
||||
with sftp.file(REMOTE_START, "w") as handle:
|
||||
handle.write(start_cmd)
|
||||
if pubkey.exists():
|
||||
run(client, r'if not exist "%USERPROFILE%\.ssh" mkdir "%USERPROFILE%\.ssh"')
|
||||
existing = ""
|
||||
try:
|
||||
with sftp.file(r"C:\Users\comfyapi\.ssh\authorized_keys", "r") as handle:
|
||||
existing = handle.read().decode("utf-8", "replace")
|
||||
except FileNotFoundError:
|
||||
existing = ""
|
||||
key_text = pubkey.read_text(encoding="ascii").strip()
|
||||
if key_text not in existing:
|
||||
with sftp.file(r"C:\Users\comfyapi\.ssh\authorized_keys", "a") as handle:
|
||||
handle.write(("\n" if existing and not existing.endswith("\n") else "") + key_text + "\n")
|
||||
print("authorized_keys updated")
|
||||
sftp.close()
|
||||
|
||||
code, out, err = run(client, f'if exist "{REMOTE_DIR}\\node.exe" echo node-present')
|
||||
if "node-present" not in out:
|
||||
print("downloading node")
|
||||
code, out, err = run(
|
||||
client,
|
||||
f'curl.exe -L --retry 3 -o "{REMOTE_DIR}\\node.zip" {NODE_ZIP}',
|
||||
timeout=180,
|
||||
)
|
||||
print("curl", code, (err or out)[-400:])
|
||||
code, out, err = run(
|
||||
client,
|
||||
f'"C:\\Program Files\\7-Zip\\7z.exe" x -y -o"{REMOTE_DIR}\\node-dist" "{REMOTE_DIR}\\node.zip"',
|
||||
timeout=120,
|
||||
)
|
||||
print("unzip", code, out[-400:] or err[-400:])
|
||||
run(client, f'copy /Y "{REMOTE_DIR}\\node-dist\\node-v22.18.0-win-x64\\node.exe" "{REMOTE_DIR}\\node.exe"')
|
||||
|
||||
run(client, r'powershell -NoProfile -Command "Get-Process node -ErrorAction SilentlyContinue | Where-Object { $_.Path -like \'*aigen-agent*\' } | Stop-Process -Force"')
|
||||
code, out, err = run(
|
||||
client,
|
||||
r'cmd /c start "" /MIN C:\Users\comfyapi\aigen-agent\start.cmd',
|
||||
)
|
||||
print("start", code, out.strip(), err.strip())
|
||||
run(
|
||||
client,
|
||||
r'schtasks /Create /TN AigenImageComfyAgent /TR "C:\Users\comfyapi\aigen-agent\start.cmd" /SC ONLOGON /F',
|
||||
)
|
||||
client.close()
|
||||
print("token-file", str(token_file))
|
||||
print("wait for agent")
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user