| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- #!/usr/bin/env node
- const fs = require('fs');
- const path = require('path');
- const { spawnSync } = require('child_process');
- const ROOT = __dirname;
- const MIN_NODE_MAJOR = 18;
- const PACKAGE_NAMES = new Set([
- 'claude-code-voc-intelligence',
- '@gangvy/claude-code-voc-intelligence'
- ]);
- function parseArgs(argv) {
- const opts = {
- check: false,
- smoke: false,
- skipInstall: false,
- help: false,
- noNext: false
- };
- for (const token of argv) {
- if (token === '--check') opts.check = true;
- else if (token === '--smoke') opts.smoke = true;
- else if (token === '--skip-install') opts.skipInstall = true;
- else if (token === '--no-next') opts.noNext = true;
- else if (token === '--help' || token === '-h') opts.help = true;
- }
- return opts;
- }
- function usage() {
- return [
- 'Claude Code VOC Intelligence 安装器',
- '',
- '用法:',
- ' node install.js',
- ' node install.js --smoke',
- ' node install.js --check',
- '',
- '参数:',
- ' --check 只检查文件和环境,不安装依赖',
- ' --smoke 安装后跑 sample 和 MCP smoke',
- ' --skip-install 跳过 npm install',
- ' --no-next 不打印下一步提示,供外层 CLI 调用',
- ' --help, -h 显示帮助'
- ].join('\n');
- }
- function run(command, args, options = {}) {
- const useCmd = process.platform === 'win32' && command === 'npm';
- const executable = useCmd ? 'cmd.exe' : command;
- const finalArgs = useCmd ? ['/d', '/s', '/c', 'npm', ...args] : args;
- const child = spawnSync(executable, finalArgs, {
- cwd: options.cwd || ROOT,
- encoding: 'utf8',
- stdio: options.stdio || 'inherit',
- maxBuffer: 1024 * 1024 * 100
- });
- if (child.status !== 0) {
- const detail = child.error ? `: ${child.error.message}` : '';
- throw new Error(`${command} ${args.join(' ')} failed with exit ${child.status}${detail}`);
- }
- return child;
- }
- function readJson(relativePath) {
- return JSON.parse(fs.readFileSync(path.join(ROOT, relativePath), 'utf8'));
- }
- function assertFile(relativePath) {
- const absolute = path.join(ROOT, relativePath);
- if (!fs.existsSync(absolute)) {
- throw new Error(`缺少必要文件:${relativePath}`);
- }
- }
- function checkNodeVersion() {
- const major = Number(process.versions.node.split('.')[0]);
- if (!Number.isFinite(major) || major < MIN_NODE_MAJOR) {
- throw new Error(`Node.js 版本过低:当前 ${process.version},需要 Node.js ${MIN_NODE_MAJOR}+`);
- }
- }
- function checkFiles() {
- [
- 'package.json',
- '.claude-plugin/plugin.json',
- '.mcp.json',
- 'skill-package-manifest.json',
- 'skills/xiaohongshu-trend-intelligence/SKILL.md',
- 'mcp/src/server.js'
- ].forEach(assertFile);
- const packageJson = readJson('package.json');
- const pluginJson = readJson('.claude-plugin/plugin.json');
- const mcpJson = readJson('.mcp.json');
- if (!PACKAGE_NAMES.has(packageJson.name)) {
- throw new Error('package.json name 不正确');
- }
- if (pluginJson.name !== 'voc-intelligence') {
- throw new Error('.claude-plugin/plugin.json name 不正确');
- }
- if (!mcpJson.mcpServers || !mcpJson.mcpServers['voc-intelligence']) {
- throw new Error('.mcp.json 未配置 voc-intelligence MCP server');
- }
- }
- function checkClaudeCommand() {
- const command = process.platform === 'win32' ? 'where' : 'which';
- const args = ['claude'];
- const child = spawnSync(command, args, {
- cwd: ROOT,
- encoding: 'utf8',
- stdio: 'pipe'
- });
- return child.status === 0;
- }
- function printNextSteps({ claudeAvailable }) {
- const loadCommand = `claude --plugin-dir "${ROOT}"`;
- console.log('');
- console.log('安装检查完成。');
- console.log('');
- console.log('下一步:');
- console.log(` 1. 启动 Claude Code:${loadCommand}`);
- console.log(' 2. 在 Claude Code 里说:');
- console.log(' 帮我做一份家装全屋定制行业的小红书趋势情报。');
- console.log(' 重点看女性客户下季度可能关注的设计元素、风格和消费顾虑。');
- console.log(' 先在聊天里给我第一轮样本观察和待确认问题,不要只给文件路径。');
- console.log('');
- if (!claudeAvailable) {
- console.log('提示:当前终端没有检测到 claude 命令。如果 Claude Code 已安装但不在 PATH 中,请在 Claude Code 所在终端里运行上面的加载命令。');
- console.log('');
- }
- console.log('真实采集需要配置小红书/TikHub token;未配置时仍可用 sample 模式做演示。');
- }
- function main() {
- const opts = parseArgs(process.argv.slice(2));
- if (opts.help) {
- console.log(usage());
- return;
- }
- console.log('');
- console.log('Claude Code VOC Intelligence 安装检查');
- console.log('====================================');
- console.log('');
- checkNodeVersion();
- checkFiles();
- console.log(`Node.js: ${process.version}`);
- console.log('必要文件:OK');
- if (!opts.check && !opts.skipInstall) {
- console.log('');
- console.log('正在安装依赖...');
- run('npm', ['install', '--omit=dev', '--ignore-scripts']);
- }
- if (opts.smoke) {
- console.log('');
- console.log('正在运行 sample / 偏好记忆 / MCP smoke...');
- run(process.execPath, ['scripts/smoke-package.js']);
- }
- if (!opts.noNext) {
- printNextSteps({ claudeAvailable: checkClaudeCommand() });
- }
- }
- try {
- main();
- } catch (error) {
- console.error('');
- console.error(`安装失败:${error.message}`);
- process.exit(1);
- }
|