autosnippet
Version:
Extract code patterns into a knowledge base for AI coding assistants
284 lines (283 loc) • 10.5 kB
JavaScript
/**
* AutoSnippet VSCode Copilot 安装脚本
*
* 功能:
* 1. 自动配置 VSCode 全局和工作区 settings.json
* 2. 创建推荐扩展配置 (.vscode/extensions.json)
* 3. 生成或更新项目指令 (.github/copilot-instructions.md)
* 4. 验证 MCP 服务器连接
* 5. 提供快速启动指导
*
* 使用:
* node scripts/install-vscode-copilot.js [--path /path/to/project] [--global|--workspace]
* npm run install:vscode-copilot
*
* 选项:
* --path <path> 指定项目根目录(默认为 cwd)
* --global 仅配置全局 settings.json(~/.config/Code/User/settings.json)
* --workspace 仅配置工作区 settings.json(.vscode/settings.json)
* --skip-verify 跳过验证步骤
* --quiet 安静模式(无输出)
*/
import { TEMPLATES_DIR } from '../lib/shared/package-root.js';
const __dirname = import.meta.dirname;
import fs from 'node:fs';
import { createRequire } from 'node:module';
import path from 'node:path';
const require = createRequire(import.meta.url);
const args = require('minimist')(process.argv.slice(2));
const projectPath = args.path || args.p || process.cwd();
// 检测是否在 AutoSnippet 仓库内执行
const isAutoSnippetRepo = fs.existsSync(path.join(projectPath, 'bin/mcp-server.js')) &&
fs.existsSync(path.join(projectPath, 'bin/asd')) &&
fs.existsSync(path.join(projectPath, 'package.json'));
// 默认只做工作区配置,不做全局配置
// 如果在 AutoSnippet 仓库内执行且未明确指定 --path,跳过所有配置
const configWorkspace = !args.global && !isAutoSnippetRepo && (args.path || !isAutoSnippetRepo);
const skipVerify = args['skip-verify'];
const isQuiet = args.quiet || process.env.ASD_QUIET === 'true';
// ============ 颜色定义 ============
const colors = {
reset: '\x1b[0m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
red: '\x1b[31m',
};
function log(msg, color = 'reset') {
if (!isQuiet) {
}
}
function error(msg) {
console.error(colors.red + msg + colors.reset);
}
// ============ 助手函数 ============
function readJsonFile(filePath, defaultValue = {}) {
if (!fs.existsSync(filePath)) {
return defaultValue;
}
try {
const content = fs.readFileSync(filePath, 'utf8');
return JSON.parse(content);
}
catch (e) {
log(`⚠️ 无法解析 ${filePath}: ${e.message}`, 'yellow');
return defaultValue;
}
}
function writeJsonFile(filePath, data) {
try {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
return true;
}
catch (e) {
error(`✗ 无法写入 ${filePath}: ${e.message}`);
return false;
}
}
// ============ 获取 MCP 服务器路径 ============
function getMcpServerPath() {
const scriptPath = path.join(projectPath, 'bin/mcp-server.js');
if (!fs.existsSync(scriptPath)) {
error(`✗ MCP Server 不存在: ${scriptPath}`);
error(` 请确保在 AutoSnippet 项目目录下运行此脚本`);
process.exit(1);
}
return scriptPath;
}
// ============ 配置 VSCode settings.json ============
function configureVSCodeSettings() {
log('\n📝 配置 VSCode MCP 设置...', 'blue');
if (isAutoSnippetRepo && !args.path) {
log('ℹ️ 检测到在 AutoSnippet 仓库内执行,仅配置全局设置', 'yellow');
log(' 如需为其他项目配置,请使用: --path /path/to/project', 'yellow');
}
const mcpServerPath = getMcpServerPath();
const mcpServerConfig = {
type: 'stdio',
command: 'node',
args: [mcpServerPath],
env: {
ASD_UI_URL: 'http://localhost:3000',
},
};
let configured = false;
// 工作区配置 → .vscode/mcp.json(新标准格式)
if (configWorkspace) {
const vscodeDir = path.join(projectPath, '.vscode');
const mcpConfigPath = path.join(vscodeDir, 'mcp.json');
let config = {};
if (fs.existsSync(mcpConfigPath)) {
try {
config = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
}
catch {
/* ignore */
}
}
if (!config.servers) {
config.servers = {};
}
config.servers.autosnippet = mcpServerConfig;
if (writeJsonFile(mcpConfigPath, config)) {
log(`✅ 工作区 MCP 配置完成: ${mcpConfigPath}`, 'green');
configured = true;
}
}
return configured;
}
// ============ 创建推荐扩展配置 ============
function createExtensionsJson() {
log('\n📦 创建推荐扩展配置...', 'blue');
const extensionsPath = path.join(projectPath, '.vscode/extensions.json');
const extensions = {
recommendations: ['GitHub.copilot', 'GitHub.copilot-chat'],
unwantedRecommendations: [],
};
if (writeJsonFile(extensionsPath, extensions)) {
log(`✅ 扩展推荐配置完成: ${extensionsPath}`, 'green');
return true;
}
return false;
}
// ============ 生成项目指令 ============
function createCopilotInstructions() {
log('\n📖 生成项目指令 (.github/copilot-instructions.md)...', 'blue');
const instructionsPath = path.join(projectPath, '.github/copilot-instructions.md');
// 检查是否已存在
if (fs.existsSync(instructionsPath)) {
log(`✓ 项目指令已存在,跳过创建`, 'yellow');
return true;
}
// 从 conventions 模板生成(读模板 + 包装 HTML markers)
const templatePath = path.join(TEMPLATES_DIR, 'instructions/conventions.md');
if (!fs.existsSync(templatePath)) {
error(`✗ 模板文件不存在: ${templatePath}`);
return false;
}
const body = fs.readFileSync(templatePath, 'utf8').trimEnd();
const content = [
'<!-- autosnippet:begin -->',
'',
'# AutoSnippet Conventions',
'',
body,
'',
'<!-- autosnippet:end -->',
'',
].join('\n');
try {
fs.mkdirSync(path.dirname(instructionsPath), { recursive: true });
fs.writeFileSync(instructionsPath, content, 'utf8');
log(`✅ 项目指令生成完成: ${instructionsPath}`, 'green');
return true;
}
catch (e) {
error(`✗ 生成项目指令失败: ${e.message}`);
return false;
}
}
// ============ 验证配置 ============
function verifyConfiguration() {
if (skipVerify) {
return;
}
log('\n🔍 验证配置...', 'blue');
// 检查工作区 MCP 配置(.vscode/mcp.json)
if (configWorkspace) {
const mcpConfigPath = path.join(projectPath, '.vscode/mcp.json');
if (fs.existsSync(mcpConfigPath)) {
const config = readJsonFile(mcpConfigPath, {});
if (config.servers?.autosnippet) {
log(`✅ VSCode 工作区 MCP 配置验证成功 (.vscode/mcp.json)`, 'green');
}
else {
log(`⚠️ .vscode/mcp.json 中未找到 autosnippet 服务器`, 'yellow');
}
}
else {
log(`⚠️ 未找到 .vscode/mcp.json`, 'yellow');
}
}
// 检查推荐扩展
const extensionsPath = path.join(projectPath, '.vscode/extensions.json');
if (fs.existsSync(extensionsPath)) {
log(`✅ 推荐扩展配置存在`, 'green');
}
// 检查项目指令
const instructionsPath = path.join(projectPath, '.github/copilot-instructions.md');
if (fs.existsSync(instructionsPath)) {
log(`✅ 项目指令存在`, 'green');
}
}
// ============ 提供快速启动指导 ============
function printQuickStart() {
log(`\n${'='.repeat(60)}`, 'blue');
log('🎉 VSCode Copilot 配置完成!', 'green');
log('='.repeat(60), 'blue');
log('\n⚡ 3 步快速启动:\n', 'blue');
log('1️⃣ 启动 Dashboard');
log(' $ asd ui', 'yellow');
log(' 确认输出: ✓ Server running on http://localhost:3000\n');
log('2️⃣ 重启 VSCode');
log(' $ code -r\n');
log('3️⃣ 在 VSCode Copilot Chat 中测试');
log(' ⌘+⇧+I 打开 Copilot Chat');
log(' 输入: @autosnippet search async', 'yellow');
log(' 预期: 返回 async/await 代码片段\n');
log('📚 可用命令:\n', 'blue');
log(' @autosnippet search <关键词> # 代码搜索');
log(' @autosnippet recipes list # 查看 Recipe');
log(' @autosnippet create # 创建 Recipe');
log(' @autosnippet guard # 代码审查');
log(' @autosnippet when <场景> # 决策辅助\n');
log('📖 项目指令位置:');
log(` ${path.join(projectPath, '.github/copilot-instructions.md')}`, 'yellow');
log('\n📝 配置位置:');
if (configWorkspace) {
log(` MCP: ${path.join(projectPath, '.vscode/mcp.json')}`, 'yellow');
}
log('\n💡 提示:');
log(' - 首次配置需要重启 VSCode');
log(' - MCP 服务器需要 Node.js 18.0+');
log(' - Dashboard 运行在 http://localhost:3000');
log(' - MCP 配置位于 .vscode/mcp.json(可加入版本控制共享给团队)\n');
log(`${'='.repeat(60)}\n`, 'blue');
}
// ============ 主程序 ============
async function main() {
log('\n🚀 AutoSnippet VSCode Copilot 安装程序', 'blue');
log(`📍 项目路径: ${projectPath}\n`, 'blue');
const results = {
settings: false,
extensions: false,
instructions: false,
};
// 配置 settings.json
results.settings = configureVSCodeSettings();
// 创建推荐扩展配置
results.extensions = createExtensionsJson();
// 生成项目指令
results.instructions = createCopilotInstructions();
// 验证配置
verifyConfiguration();
// 提供快速启动指导
printQuickStart();
// 返回状态
const allSuccess = Object.values(results).every((v) => v);
if (allSuccess) {
log('✅ 所有配置完成!', 'green');
process.exit(0);
}
else {
log('⚠️ 部分配置可能未完成,请检查上述消息', 'yellow');
process.exit(1);
}
}
// 运行
main().catch((err) => {
error(`✗ 配置失败: ${err.message}`);
process.exit(1);
});