119 lines
4.4 KiB
JavaScript
Executable file
119 lines
4.4 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
/**
|
|
* setup.js - Downloads/updates the JAE Image Skill reference library.
|
|
*
|
|
* Fully dynamic: reads manifest.json first to discover all categories.
|
|
* New/renamed/removed categories are handled automatically — no hardcoding.
|
|
*
|
|
* Usage:
|
|
* node scripts/setup.js # Download missing files only
|
|
* node scripts/setup.js --force # Force re-download all references
|
|
* node scripts/setup.js --check # Auto-update if stale (> 24h)
|
|
*
|
|
* Override source if needed:
|
|
* JAE_IMAGE_SKILL_BASE_URL=https://example.com/references node scripts/setup.js --force
|
|
*/
|
|
|
|
import { existsSync, mkdirSync, statSync, writeFileSync, readFileSync, readdirSync, unlinkSync } from 'fs';
|
|
import { join, dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const refsDir = join(__dirname, '..', 'references');
|
|
const stampFile = join(refsDir, '.last-updated');
|
|
|
|
const BASE_URL = (process.env.JAE_IMAGE_SKILL_BASE_URL || 'https://jaeswift.xyz/skills/JAE-image-skill/references').replace(/\/$/, '');
|
|
const STALE_HOURS = Number(process.env.JAE_IMAGE_SKILL_STALE_HOURS || 24);
|
|
|
|
function isStale() {
|
|
if (!existsSync(stampFile)) return true;
|
|
const ts = parseInt(readFileSync(stampFile, 'utf8').trim(), 10);
|
|
return (Date.now() - ts) / 1000 / 3600 > STALE_HOURS;
|
|
}
|
|
|
|
async function fetchText(url) {
|
|
if (typeof fetch !== 'function') {
|
|
throw new Error('This installer requires Node.js 18+ with global fetch. Node 20+ is recommended.');
|
|
}
|
|
const res = await fetch(url);
|
|
if (!res.ok) throw new Error(`HTTP ${res.status} — ${url}`);
|
|
return res.text();
|
|
}
|
|
|
|
async function setup() {
|
|
const args = process.argv.slice(2);
|
|
const forceMode = args.includes('--force');
|
|
const checkMode = args.includes('--check');
|
|
|
|
if (checkMode && !isStale()) {
|
|
return;
|
|
}
|
|
|
|
if (!existsSync(refsDir)) mkdirSync(refsDir, { recursive: true });
|
|
|
|
const label = forceMode ? 'Updating' : 'Downloading';
|
|
console.log(`[setup] ${label} JAE Image Skill reference library from ${BASE_URL} ...`);
|
|
|
|
let categories;
|
|
try {
|
|
const manifestText = await fetchText(`${BASE_URL}/manifest.json`);
|
|
const manifest = JSON.parse(manifestText);
|
|
categories = manifest.categories;
|
|
if (!Array.isArray(categories) || categories.length === 0) throw new Error('manifest has no categories');
|
|
writeFileSync(join(refsDir, 'manifest.json'), manifestText, 'utf8');
|
|
console.log(` manifest: ${categories.length} categories, ${manifest.totalPrompts} prompts total`);
|
|
} catch (err) {
|
|
console.warn(`[setup] Could not fetch manifest: ${err.message}`);
|
|
console.warn('[setup] Falling back to existing local manifest...');
|
|
const localManifest = join(refsDir, 'manifest.json');
|
|
if (!existsSync(localManifest)) {
|
|
console.error('[setup] No manifest available. Install from the bundled repo/archive or retry with --force.');
|
|
process.exit(0);
|
|
}
|
|
categories = JSON.parse(readFileSync(localManifest, 'utf8')).categories;
|
|
}
|
|
|
|
const validFiles = new Set([...categories.map(c => c.file), 'manifest.json', '.last-updated', '.gitkeep']);
|
|
if (forceMode && existsSync(refsDir)) {
|
|
for (const f of readdirSync(refsDir)) {
|
|
if (!validFiles.has(f)) {
|
|
unlinkSync(join(refsDir, f));
|
|
console.log(` removed stale: ${f}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
let downloaded = 0, skipped = 0, failed = 0;
|
|
for (const cat of categories) {
|
|
const dest = join(refsDir, cat.file);
|
|
if (!forceMode && existsSync(dest) && statSync(dest).size > 100) {
|
|
skipped++;
|
|
continue;
|
|
}
|
|
process.stdout.write(` → ${cat.file} (${cat.title}, ${cat.count} prompts) ... `);
|
|
try {
|
|
const text = await fetchText(`${BASE_URL}/${cat.file}`);
|
|
JSON.parse(text);
|
|
writeFileSync(dest, text, 'utf8');
|
|
console.log('✓');
|
|
downloaded++;
|
|
} catch (err) {
|
|
console.log(`✗ (${err.message})`);
|
|
failed++;
|
|
}
|
|
}
|
|
|
|
if (failed === 0) writeFileSync(stampFile, String(Date.now()), 'utf8');
|
|
|
|
if (downloaded > 0) {
|
|
console.log(`[setup] Done! ${downloaded} file(s) ${forceMode ? 'updated' : 'downloaded'}. JAE Image Skill is ready.`);
|
|
} else if (skipped === categories.length) {
|
|
console.log('[setup] All references up to date. Use --force to refresh.');
|
|
}
|
|
if (failed > 0) console.warn(`[setup] ${failed} file(s) failed. Run again to retry.`);
|
|
}
|
|
|
|
setup().catch(err => {
|
|
console.warn('[setup] Warning (non-fatal):', err.message);
|
|
process.exit(0);
|
|
});
|