install-rules.mjs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. #!/usr/bin/env node
  2. /**
  3. * install-rules.mjs —— 把 fmode-code-agent 的智能体规则装入目标项目的 ./.claude/rules/。
  4. *
  5. * 用法:
  6. * node install-rules.mjs [targetDir] [--force]
  7. * node install-rules.mjs [targetDir] --from <rulesRepoDir> # 指定规则仓根目录
  8. *
  9. * 规则来源优先级:--from > 技能同仓 ../../../.claude/rules > 内置最小规则集。
  10. * 已存在文件默认不覆盖(--force 覆盖)。
  11. */
  12. import { mkdirSync, writeFileSync, existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
  13. import { join, resolve, dirname } from 'node:path';
  14. import { fileURLToPath } from 'node:url';
  15. const __dirname = dirname(fileURLToPath(import.meta.url));
  16. const args = process.argv.slice(2);
  17. const target = resolve(args.find((a) => a && !a.startsWith('-')) || '.');
  18. const force = args.includes('--force');
  19. const fromIdx = args.indexOf('--from');
  20. const fromDir = fromIdx > -1 ? resolve(args[fromIdx + 1]) : null;
  21. // 规则来源候选(技能在 <repo>/skills/fmode-code-agent/scripts/)
  22. const candidates = [
  23. fromDir,
  24. resolve(__dirname, '../../../.claude/rules'),
  25. resolve(__dirname, '../../.claude/rules'),
  26. ].filter(Boolean);
  27. const srcRules = candidates.find((d) => d && existsSync(d) && existsSync(join(d, 'agent-architecture.md')));
  28. if (!srcRules) {
  29. console.error('(!) 未找到规则源。请用 --from <规则仓根目录> 指定(需含 .claude/rules/agent-architecture.md)。');
  30. process.exit(1);
  31. }
  32. const destRules = join(target, '.claude', 'rules');
  33. mkdirSync(destRules, { recursive: true });
  34. let created = 0, skipped = 0;
  35. function copyTree(from, to) {
  36. for (const name of readdirSync(from)) {
  37. const s = join(from, name), d = join(to, name);
  38. if (statSync(s).isDirectory()) { mkdirSync(d, { recursive: true }); copyTree(s, d); continue; }
  39. if (!name.endsWith('.md')) continue;
  40. if (existsSync(d) && !force) { skipped++; continue; }
  41. writeFileSync(d, readFileSync(s));
  42. created++;
  43. }
  44. }
  45. copyTree(srcRules, destRules);
  46. // 在目标 CLAUDE.md 里追加一段指引(若还没有)
  47. const claudeMd = join(target, 'CLAUDE.md');
  48. const MARK = '<!-- fmode-code-agent rules -->';
  49. const snippet = `
  50. ${MARK}
  51. ## 智能体开发规则(fmode-code-agent)
  52. 本项目遵守 **fmode-code-agent** 规则。写任何智能体/Agent/MCP/Skill 代码前先读
  53. \`.claude/rules/agent-architecture.md\`,再按 CLAUDE.md 索引查具体篇。
  54. 四条铁律:① 浏览器+Node 双兼容 ② 不用构建(importmap)③ 凭据不进 Worker/日志/代码
  55. ④ 参数以实测为准(网关会静默忽略参数,须验证副作用)。
  56. `;
  57. if (existsSync(claudeMd)) {
  58. const cur = readFileSync(claudeMd, 'utf8');
  59. if (!cur.includes(MARK)) { writeFileSync(claudeMd, cur.trimEnd() + '\n' + snippet); console.log(' · 已向 CLAUDE.md 追加规则指引'); }
  60. } else {
  61. writeFileSync(claudeMd, `# 项目规范\n${snippet}`);
  62. console.log(' · 已创建 CLAUDE.md');
  63. }
  64. console.log(`规则安装完成:新增 ${created} 个,跳过(已存在)${skipped} 个 → ${destRules}`);
  65. if (skipped && !force) console.log(' (要覆盖已存在文件:加 --force)');