From 528044ac8598237759d45444f8a7b4dc09360c26 Mon Sep 17 00:00:00 2001 From: Hooray <304327508@qq.com> Date: Wed, 1 Apr 2026 13:51:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=20postinstall=20?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E4=BB=A5=E6=94=AF=E6=8C=81=E6=8A=80=E8=83=BD?= =?UTF-8?q?=E9=93=BE=E6=8E=A5=E5=92=8C=E6=96=87=E4=BB=B6=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- scripts/postinstall.ts | 95 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 scripts/postinstall.ts diff --git a/package.json b/package.json index 3724760a..b89a3bc8 100755 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "lint:eslint": "eslint . --cache --fix", "lint:stylelint": "stylelint \"{apps,packages}/**/*.{css,scss,vue}\" --cache --fix", "preinstall": "npx only-allow pnpm", - "postinstall": "simple-git-hooks", + "postinstall": "simple-git-hooks && tsx scripts/postinstall.ts", "taze": "taze minor -wIr", "commit": "git cz", "release": "bumpp" diff --git a/scripts/postinstall.ts b/scripts/postinstall.ts new file mode 100644 index 00000000..6fa1fcc9 --- /dev/null +++ b/scripts/postinstall.ts @@ -0,0 +1,95 @@ +#!/usr/bin/env node + +import fs from 'node:fs' +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const rootDir = path.resolve(__dirname, '..') +const isWindows = process.platform === 'win32' + +const sourceDir = path.resolve(rootDir, '.agents/skills') +const targetDirs = [ + '.claude/skills', + // '.other-agent/skills', +] + +// 根目录文件链接:[source, link] +const fileLinks = [ + ['AGENTS.md', 'CLAUDE.md'], +] + +function syncSkillLinks() { + if (!fs.existsSync(sourceDir)) { + return + } + + const skills = fs.readdirSync(sourceDir, { withFileTypes: true }) + .filter(entry => entry.isDirectory()) + .map(entry => entry.name) + + for (const targetDir of targetDirs) { + const absTargetDir = path.resolve(rootDir, targetDir) + fs.mkdirSync(absTargetDir, { recursive: true }) + + let created = 0 + + for (const skill of skills) { + const linkPath = path.join(absTargetDir, skill) + const skillSourcePath = path.join(sourceDir, skill) + + // 已存在则先删除(兼容 symlink / junction / 普通目录) + try { + fs.lstatSync(linkPath) + fs.rmSync(linkPath, { recursive: true, force: true }) + } + catch { + // 不存在,正常继续创建 + } + + if (isWindows) { + // Windows 使用 junction(目录联接),无需管理员权限 + fs.symlinkSync(skillSourcePath, linkPath, 'junction') + } + else { + // Mac/Linux 使用相对路径软链接 + const relativePath = path.relative(absTargetDir, skillSourcePath) + fs.symlinkSync(relativePath, linkPath) + } + + created++ + } + + if (created > 0) { + console.log(`[postinstall] Linked ${created} skill(s) to ${targetDir}/`) + } + } +} + +function syncFileLinks() { + for (const [source, link] of fileLinks) { + const sourcePath = path.resolve(rootDir, source) + const linkPath = path.resolve(rootDir, link) + + if (!fs.existsSync(sourcePath)) { + console.warn(`[postinstall] Source file not found, skipping: ${source}`) + continue + } + + // 已存在则先删除 + try { + fs.lstatSync(linkPath) + fs.rmSync(linkPath, { force: true }) + } + catch { + // 不存在,正常继续创建 + } + const relativePath = isWindows ? sourcePath : path.relative(rootDir, sourcePath) + fs.symlinkSync(relativePath, linkPath, 'file') + console.log(`[postinstall] Linked file: ${link} -> ${source}`) + } +} + +syncSkillLinks() +syncFileLinks()