install.mjs 2.0 KB

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