install.mjs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. #!/usr/bin/env node
  2. /**
  3. * install.mjs —— 把 fmode-code-lit 技能安装到 Claude Code 技能目录。
  4. *
  5. * 用法:
  6. * node install.mjs install # → ~/.claude/skills/fmode-code-lit/(全局,默认)
  7. * node install.mjs workspace # → ./.claude/skills/fmode-code-lit/(当前项目)
  8. * node install.mjs install --target <dir> [--force]
  9. * node install.mjs check # 校验安装
  10. */
  11. import { mkdirSync, copyFileSync, existsSync, readdirSync, statSync } from 'node:fs';
  12. import { join, resolve, dirname } from 'node:path';
  13. import { homedir } from 'node:os';
  14. import { fileURLToPath } from 'node:url';
  15. const __dirname = dirname(fileURLToPath(import.meta.url));
  16. const SKILL_SRC = resolve(__dirname, '..'); // <...>/skills/fmode-code-lit
  17. const SKILL_NAME = 'fmode-code-lit';
  18. const args = process.argv.slice(2);
  19. const cmd = args[0] && !args[0].startsWith('--') ? args[0] : 'install';
  20. const force = args.includes('--force');
  21. const tIdx = args.indexOf('--target');
  22. const globalTarget = join(homedir(), '.claude', 'skills', SKILL_NAME);
  23. const workspaceTarget = join(process.cwd(), '.claude', 'skills', SKILL_NAME);
  24. function copyTree(from, to) {
  25. mkdirSync(to, { recursive: true });
  26. for (const name of readdirSync(from)) {
  27. if (name === 'node_modules') continue;
  28. const s = join(from, name), d = join(to, name);
  29. if (statSync(s).isDirectory()) copyTree(s, d);
  30. else if (!existsSync(d) || force) copyFileSync(s, d);
  31. }
  32. }
  33. function verify(target) {
  34. const must = ['SKILL.md'];
  35. const missing = must.filter((f) => !existsSync(join(target, f)));
  36. if (missing.length) { console.error(`✗ 安装不完整,缺少:${missing.join(', ')}`); process.exit(1); }
  37. console.log(`✓ 技能已就位:${target}`);
  38. console.log(` SKILL.md 存在,scripts/ ${existsSync(join(target, 'scripts')) ? '存在' : '缺失'}`);
  39. }
  40. function main() {
  41. const target = cmd === 'workspace' || cmd === 'install-workspace'
  42. ? workspaceTarget
  43. : (tIdx > -1 ? resolve(args[tIdx + 1]) : globalTarget);
  44. if (cmd === 'check') { verify(target); return; }
  45. if (!existsSync(SKILL_SRC)) { console.error(`✗ 找不到技能源:${SKILL_SRC}`); process.exit(1); }
  46. console.log(`安装 ${SKILL_NAME} → ${target}${force ? '(--force 覆盖)' : ''}`);
  47. copyTree(SKILL_SRC, target);
  48. verify(target);
  49. console.log(`\n触发词:lit 项目 / lit 组件 / 无构建前端 / WebComponent / importmap`);
  50. }
  51. main();