acceptance.js 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const os = require('os');
  4. const path = require('path');
  5. const { spawnSync } = require('child_process');
  6. const ROOT = path.resolve(__dirname, '..');
  7. const npmCache = path.join(os.tmpdir(), 'claude-voc-npm-cache-acceptance');
  8. function main() {
  9. fs.mkdirSync(npmCache, { recursive: true });
  10. run('npm', ['run', 'fmode:image:smoke'], ROOT);
  11. run('npm', ['run', 'smoke:package'], ROOT);
  12. run('npm', ['run', 'mcp:smoke'], ROOT);
  13. run('npm', ['pack', '--dry-run'], ROOT);
  14. const workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'voc-workspace-install-'));
  15. run(process.execPath, [path.join(ROOT, 'bin', 'claude-voc.js'), 'workspace', '--smoke'], workspace);
  16. const mcpFile = path.join(workspace, '.mcp.json');
  17. const pluginRoot = path.join(workspace, '.claude', 'plugins', 'voc-intelligence');
  18. const pluginServer = path.join(pluginRoot, 'mcp', 'src', 'server.js');
  19. const skillNames = [
  20. 'xiaohongshu-trend-intelligence',
  21. 'douyin-trend-intelligence',
  22. 'voc-issue-pool',
  23. 'voc-problem-deep-dive',
  24. 'voc-content-plan',
  25. 'voc-speaking-script',
  26. 'voc-competitor-map',
  27. 'voc-business-workflow',
  28. 'fmode-image-analysis'
  29. ];
  30. assert(fs.existsSync(mcpFile), 'workspace install should write .mcp.json');
  31. assert(fs.existsSync(pluginServer), 'workspace install should copy plugin server');
  32. for (const skillName of skillNames) {
  33. assert(
  34. fs.existsSync(path.join(workspace, '.claude', 'skills', skillName, 'SKILL.md')),
  35. `workspace install should write skill entry: ${skillName}`
  36. );
  37. }
  38. const mcp = JSON.parse(fs.readFileSync(mcpFile, 'utf8'));
  39. const server = mcp.mcpServers && mcp.mcpServers.voc;
  40. assert(server, 'workspace .mcp.json should register voc server');
  41. assert(Array.isArray(server.args) && path.isAbsolute(server.args[0]), 'workspace MCP server path should be absolute');
  42. assert(path.resolve(server.args[0]) === path.resolve(pluginServer), 'workspace MCP server path should point to installed plugin server');
  43. console.log(`acceptance ok: ${workspace}`);
  44. }
  45. function run(command, args, cwd) {
  46. const resolved = resolveCommand(command, args);
  47. const result = spawnSync(resolved.command, resolved.args, {
  48. cwd,
  49. stdio: 'inherit',
  50. shell: resolved.shell,
  51. env: {
  52. ...process.env,
  53. npm_config_cache: npmCache,
  54. NPM_CONFIG_CACHE: npmCache
  55. },
  56. maxBuffer: 1024 * 1024 * 100
  57. });
  58. if (result.status !== 0) {
  59. throw new Error(`${command} ${args.join(' ')} failed in ${cwd}`);
  60. }
  61. }
  62. function resolveCommand(command, args) {
  63. if (command === 'npm' && process.env.npm_execpath) {
  64. return { command: process.execPath, args: [process.env.npm_execpath, ...args], shell: false };
  65. }
  66. if (command === 'npm' && process.platform === 'win32') {
  67. return { command: 'npm.cmd', args, shell: true };
  68. }
  69. return { command, args, shell: false };
  70. }
  71. function assert(condition, message) {
  72. if (!condition) throw new Error(message);
  73. }
  74. try {
  75. main();
  76. } catch (error) {
  77. console.error(error && error.stack ? error.stack : String(error));
  78. process.exit(1);
  79. }