148 lines
4.5 KiB
JavaScript
148 lines
4.5 KiB
JavaScript
#!/usr/bin/env node
|
|
import fs from 'fs/promises';
|
|
|
|
const DEFAULT_PACKS = [
|
|
['ComfyUI-Manager', 'https://github.com/Comfy-Org/ComfyUI-Manager.git'],
|
|
['christian-byrne/audio-separation-nodes-comfyui', 'https://github.com/christian-byrne/audio-separation-nodes-comfyui.git'],
|
|
['yvann-ba/ComfyUI_Yvann-Nodes', 'https://github.com/yvann-ba/ComfyUI_Yvann-Nodes.git'],
|
|
['yolain/ComfyUI-Easy-Use', 'https://github.com/yolain/ComfyUI-Easy-Use.git'],
|
|
['wildminder/ComfyUI-VoxCPM', 'https://github.com/wildminder/ComfyUI-VoxCPM.git'],
|
|
['kijai/ComfyUI-WanVideoWrapper', 'https://github.com/kijai/ComfyUI-WanVideoWrapper.git'],
|
|
['civen-cn/ComfyUI-Whisper-Translator', 'https://github.com/civen-cn/ComfyUI-Whisper-Translator.git'],
|
|
['kijai/ComfyUI-KJNodes', 'https://github.com/kijai/ComfyUI-KJNodes.git'],
|
|
];
|
|
|
|
const args = new Set(process.argv.slice(2));
|
|
const configPath = valueArg('--config') || 'config.toml';
|
|
const baseUrl = trimSlash(
|
|
process.env.BOOSAPI_COMFYUI__BASE_URL
|
|
|| process.env.COMFYUI_CLOUD_BASE_URL
|
|
|| (await readComfyConfig(configPath)).base_url
|
|
|| 'https://cloud.comfy.org'
|
|
);
|
|
const apiKey = process.env.BOOSAPI_COMFYUI__API_KEY
|
|
|| process.env.COMFYUI_CLOUD_API_KEY
|
|
|| (await readComfyConfig(configPath)).api_key
|
|
|| '';
|
|
const dryRun = args.has('--dry-run');
|
|
|
|
if (!baseUrl) {
|
|
fail('Missing Cloud base URL. Set BOOSAPI_COMFYUI__BASE_URL or [comfyui].base_url.');
|
|
}
|
|
|
|
if (!apiKey) {
|
|
fail('Missing Cloud API key. Set BOOSAPI_COMFYUI__API_KEY or [comfyui].api_key.');
|
|
}
|
|
|
|
console.log(`Cloud backend: ${baseUrl}`);
|
|
console.log(`Packs: ${DEFAULT_PACKS.length}`);
|
|
if (dryRun) {
|
|
for (const [id, repository] of DEFAULT_PACKS) {
|
|
console.log(`[dry-run] ${id} <- ${repository}`);
|
|
}
|
|
process.exit(0);
|
|
}
|
|
|
|
await request('GET', '/api/manager/queue/start').catch((error) => {
|
|
console.warn(`manager queue start warning: ${error.message}`);
|
|
});
|
|
|
|
const results = [];
|
|
for (const [id, repository] of DEFAULT_PACKS) {
|
|
const payload = {
|
|
id,
|
|
version: 'nightly',
|
|
selected_version: 'nightly',
|
|
repository,
|
|
mode: 'remote',
|
|
channel: 'default',
|
|
skip_post_install: false,
|
|
};
|
|
try {
|
|
await request('POST', '/api/manager/queue/install', payload);
|
|
console.log(`queued: ${id}`);
|
|
results.push({ id, ok: true });
|
|
} catch (error) {
|
|
console.error(`failed: ${id}: ${error.message}`);
|
|
results.push({ id, ok: false, error: error.message });
|
|
}
|
|
}
|
|
|
|
await request('GET', '/api/manager/queue/status')
|
|
.then((status) => console.log(`queue status: ${JSON.stringify(status)}`))
|
|
.catch((error) => console.warn(`queue status warning: ${error.message}`));
|
|
|
|
const failed = results.filter((item) => !item.ok);
|
|
if (failed.length > 0) {
|
|
console.error(`\n${failed.length} pack(s) failed to queue. If Cloud returned 403/404, the hosted backend does not allow Manager installs for this workspace/API key.`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log('\nAll install jobs were queued. Restart the Cloud ComfyUI runtime if Manager asks for it.');
|
|
|
|
async function request(method, path, body) {
|
|
const response = await fetch(`${baseUrl}${path}`, {
|
|
method,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json',
|
|
'Authorization': `Bearer ${apiKey}`,
|
|
'X-API-Key': apiKey,
|
|
},
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
});
|
|
const text = await response.text();
|
|
const data = text ? safeJson(text) : null;
|
|
if (!response.ok) {
|
|
throw new Error(`${response.status} ${response.statusText}: ${text.slice(0, 500)}`);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function safeJson(text) {
|
|
try {
|
|
return JSON.parse(text);
|
|
} catch {
|
|
return { body: text };
|
|
}
|
|
}
|
|
|
|
async function readComfyConfig(path) {
|
|
const result = {};
|
|
let section = '';
|
|
let text = '';
|
|
try {
|
|
text = await fs.readFile(path, 'utf8');
|
|
} catch {
|
|
return result;
|
|
}
|
|
for (const rawLine of text.split(/\r?\n/)) {
|
|
const line = rawLine.trim();
|
|
if (!line || line.startsWith('#')) continue;
|
|
const sectionMatch = line.match(/^\[([^\]]+)\]$/);
|
|
if (sectionMatch) {
|
|
section = sectionMatch[1];
|
|
continue;
|
|
}
|
|
if (section !== 'comfyui') continue;
|
|
const match = line.match(/^([A-Za-z0-9_]+)\s*=\s*"(.*)"\s*$/);
|
|
if (match) result[match[1]] = match[2];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function trimSlash(value) {
|
|
return String(value || '').trim().replace(/\/+$/, '');
|
|
}
|
|
|
|
function valueArg(name) {
|
|
const prefix = `${name}=`;
|
|
const found = process.argv.slice(2).find((arg) => arg.startsWith(prefix));
|
|
return found ? found.slice(prefix.length) : '';
|
|
}
|
|
|
|
function fail(message) {
|
|
console.error(message);
|
|
process.exit(2);
|
|
}
|