#!/usr/bin/env node const fs = require('fs'); const os = require('os'); const path = require('path'); const { spawnSync } = require('child_process'); const ROOT = path.resolve(__dirname, '..'); const npmCache = path.join(os.tmpdir(), 'claude-voc-npm-cache-acceptance'); function main() { fs.mkdirSync(npmCache, { recursive: true }); run('npm', ['run', 'fmode:image:smoke'], ROOT); run('npm', ['run', 'smoke:package'], ROOT); run('npm', ['run', 'mcp:smoke'], ROOT); run('npm', ['run', 'acceptance:installer'], ROOT); run('npm', ['pack', '--dry-run'], ROOT); const workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'voc-workspace-install-')); run(process.execPath, [path.join(ROOT, 'bin', 'claude-voc.js'), 'workspace', '--smoke'], workspace); const mcpFile = path.join(workspace, '.mcp.json'); const pluginRoot = path.join(workspace, '.claude', 'plugins', 'voc-intelligence'); const pluginServer = path.join(pluginRoot, 'mcp', 'src', 'server.js'); const skillNames = [ 'xiaohongshu-trend-intelligence', 'douyin-trend-intelligence', 'voc-issue-pool', 'voc-problem-deep-dive', 'voc-content-plan', 'voc-speaking-script', 'voc-competitor-map', 'voc-business-workflow', 'fmode-image-analysis' ]; assert(fs.existsSync(mcpFile), 'workspace install should write .mcp.json'); assert(fs.existsSync(pluginServer), 'workspace install should copy plugin server'); for (const skillName of skillNames) { assert( fs.existsSync(path.join(workspace, '.claude', 'skills', skillName, 'SKILL.md')), `workspace install should write skill entry: ${skillName}` ); } const mcp = JSON.parse(fs.readFileSync(mcpFile, 'utf8')); const server = mcp.mcpServers && mcp.mcpServers.voc; assert(server, 'workspace .mcp.json should register voc server'); assert(Array.isArray(server.args) && path.isAbsolute(server.args[0]), 'workspace MCP server path should be absolute'); assert(path.resolve(server.args[0]) === path.resolve(pluginServer), 'workspace MCP server path should point to installed plugin server'); console.log(`acceptance ok: ${workspace}`); } function run(command, args, cwd) { const resolved = resolveCommand(command, args); const result = spawnSync(resolved.command, resolved.args, { cwd, stdio: 'inherit', shell: resolved.shell, env: { ...process.env, npm_config_cache: npmCache, NPM_CONFIG_CACHE: npmCache }, maxBuffer: 1024 * 1024 * 100 }); if (result.status !== 0) { throw new Error(`${command} ${args.join(' ')} failed in ${cwd}`); } } function resolveCommand(command, args) { if (command === 'npm' && process.env.npm_execpath) { return { command: process.execPath, args: [process.env.npm_execpath, ...args], shell: false }; } if (command === 'npm' && process.platform === 'win32') { return { command: 'npm.cmd', args, shell: true }; } return { command, args, shell: false }; } function assert(condition, message) { if (!condition) throw new Error(message); } try { main(); } catch (error) { console.error(error && error.stack ? error.stack : String(error)); process.exit(1); }