import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { spawnSync } from 'node:child_process'; import manifest from '../skill-package-manifest.json' with { type: 'json' }; const packageRoot = path.resolve(import.meta.dirname, '..'); const workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'fmode-image-set-installer-')); fs.writeFileSync(path.join(workspace, '.mcp.json'), JSON.stringify({ mcpServers: { existing: { command: 'keep-me' } } }, null, 2)); try { const result = spawnSync(process.execPath, [path.join(packageRoot, 'bin', 'fmode-image-set.js'), 'workspace', '--skip-install', '--force'], { cwd: workspace, encoding: 'utf8' }); if (result.status !== 0) throw new Error(result.error?.message || result.stderr || result.stdout || `workspace install failed (status=${result.status}, signal=${result.signal})`); const installed = path.join(workspace, '.claude', 'plugins', 'fmode-image-set'); if (!fs.existsSync(path.join(installed, 'mcp', 'src', 'server.mjs'))) throw new Error('MCP server not installed'); for (const skill of manifest.skills) if (!fs.existsSync(path.join(workspace, '.claude', 'skills', skill, 'SKILL.md'))) throw new Error(`Skill not exposed: ${skill}`); const mcp = JSON.parse(fs.readFileSync(path.join(workspace, '.mcp.json'), 'utf8')); if (!mcp.mcpServers.existing || !mcp.mcpServers['fmode-image-set']) throw new Error('.mcp.json merge failed'); if (!path.isAbsolute(mcp.mcpServers['fmode-image-set'].cwd) || !fs.existsSync(mcp.mcpServers['fmode-image-set'].args[0])) throw new Error('MCP paths are invalid'); if (mcp.mcpServers['fmode-image-set'].env?.FMODE_WORKSPACE_ROOT !== workspace) throw new Error('Workspace root env was not injected'); for (const forbidden of ['node_modules', '.env', 'outputs', '输出']) if (fs.existsSync(path.join(installed, forbidden))) throw new Error(`Forbidden copy: ${forbidden}`); for (const legacy of ['qwen-vision.mjs', 'jimeng.mjs']) { if (fs.existsSync(path.join(installed, 'mcp', 'src', 'providers', legacy))) throw new Error(`Legacy provider remained installed: ${legacy}`); } console.log(JSON.stringify({ status: 'ok', installed, skills: manifest.skills.length }, null, 2)); } finally { fs.rmSync(workspace, { recursive: true, force: true }); }