| 12345678910111213141516171819202122232425262728293031323334353637383940414243 |
- #!/usr/bin/env node
- // 技能安装器(npx 入口): 将本包内容安装/更新到 ~/.claude/skills/smartbadge-ops
- // 保护文件: .env/.token/out/__pycache__ 不覆盖(已配置凭据与登录态在升级时保留)
- // 用法:
- // npx --yes --package=<git|npm 包地址> smartbadge-ops # 安装/更新
- // node scripts/install.mjs --dest <路径> # 自定义安装目录(测试用)
- import fs from 'fs';
- import os from 'os';
- import path from 'path';
- import { fileURLToPath } from 'url';
- const PKG_ROOT = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
- const args = process.argv.slice(2);
- const argVal = (name) => {
- const i = args.indexOf(name);
- return i >= 0 ? args[i + 1] : undefined;
- };
- const TARGET = argVal('--dest') || path.join(os.homedir(), '.claude', 'skills', 'smartbadge-ops');
- const PRODUCTS = ['SKILL.md', 'README.md', '.env.example', '.gitignore', 'scripts', 'templates'];
- const PROTECTED = new Set(['.env', '.env.local', '.token', 'out', '__pycache__', '.git']);
- function copyEntry(src, dest) {
- if (PROTECTED.has(path.basename(src))) return;
- const stat = fs.statSync(src);
- if (stat.isDirectory()) {
- fs.mkdirSync(dest, { recursive: true });
- for (const name of fs.readdirSync(src)) copyEntry(path.join(src, name), path.join(dest, name));
- } else {
- fs.mkdirSync(path.dirname(dest), { recursive: true });
- fs.copyFileSync(src, dest);
- }
- }
- const existed = fs.existsSync(TARGET);
- for (const entry of PRODUCTS) {
- const src = path.join(PKG_ROOT, entry);
- if (fs.existsSync(src)) copyEntry(src, path.join(TARGET, entry));
- }
- const hasEnv = fs.existsSync(path.join(TARGET, '.env'));
- console.log(existed ? `已更新: ${TARGET}` : `已安装: ${TARGET}`);
- console.log(hasEnv ? '凭据/登录态已保留(.env/.token 未被覆盖)' : '下一步: 复制 .env.example 为 .env 并填入真实值(或配同名环境变量)');
- if (existed) console.log('提示: 升级后重跑 node scripts/check-online.mjs 验证; 若技能在运行中, 重启 Claude 会话以加载新 SKILL.md');
|