| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- #!/usr/bin/env node
- /**
- * fmode-bypass-permission checker — YOLO 模式体检与幂等修复
- * 零依赖(Node ≥18)。只动 Agent 工具自身配置,改动前备份。
- *
- * 用法:
- * node checker.mjs check # 体检输出 JSON
- * node checker.mjs enforce # 体检+修复不合规项
- */
- import fs from 'fs';
- import os from 'os';
- import path from 'path';
- const HOME = os.homedir();
- const TS = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14);
- function readJson(p) { try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return null; } }
- function backup(p) { if (fs.existsSync(p)) fs.copyFileSync(p, `${p}.bak-${TS}`); }
- /** 探测 Hermes config.yaml 位置 */
- function hermesConfigPath() {
- const candidates = [
- path.join(HOME, '.hermes', 'config.yaml'),
- '/opt/data/.hermes/config.yaml',
- path.join(HOME, '.fmode-harness-agent', 'config', 'fmodeagent', 'config.yaml'),
- ];
- for (const p of candidates) if (fs.existsSync(p)) return p;
- return null;
- }
- export function check() {
- const result = { hermes_approvals: null, hermes_yolo: null, claude_bypass: null, env_yolo: !!(process.env.HERMES_YOLO || process.env.CLAUDE_YOLO) };
- // Hermes yaml: 简易解析(不引依赖)
- const hp = hermesConfigPath();
- if (hp) {
- const t = fs.readFileSync(hp, 'utf8');
- const am = t.match(/approvals:[\s\S]{0,80}?mode:\s*(\w+)/);
- result.hermes_approvals = am ? am[1] : null;
- const ym = t.match(/^yolo:\s*(true|false)/m) || t.match(/^\s*yolo:\s*(true|false)/m);
- result.hermes_yolo = ym ? ym[1] === 'true' : null;
- result.hermes_config_path = hp;
- }
- // Claude settings
- for (const p of [path.join(HOME, '.claude', 'settings.json'), path.join(HOME, '.claude', 'settings.local.json')]) {
- const j = readJson(p);
- if (j && j.permissions && Array.isArray(j.permissions.allow)) {
- if (j.permissions.allow.some(x => /Bash\(\*\)|dangerously/i.test(x))) { result.claude_bypass = true; break; }
- }
- }
- if (result.claude_bypass === null) {
- // 进程参数兜底
- try { const cmd = fs.readFileSync(`/proc/${process.ppid}/cmdline`, 'utf8'); result.claude_bypass = cmd.includes('dangerously-skip-permissions'); } catch {}
- }
- result.compliant = (result.hermes_approvals === 'off' || result.env_yolo) &&
- (result.hermes_yolo === true || result.env_yolo) &&
- (result.claude_bypass === true || result.env_yolo);
- return result;
- }
- function fixHermes() {
- const hp = hermesConfigPath();
- if (!hp) { console.error('未找到 hermes config.yaml,跳过 hermes 修复'); return; }
- backup(hp);
- let t = fs.readFileSync(hp, 'utf8');
- if (!/approvals:/.test(t)) t += '\napprovals:\n mode: off\n';
- else t = t.replace(/(approvals:[\s\S]{0,80}?mode:\s*)(\w+)/, '$1off');
- if (!/^yolo:/m.test(t)) t += 'yolo: true\n';
- else t = t.replace(/^yolo:\s*false/m, 'yolo: true');
- fs.writeFileSync(hp, t);
- console.log('已修复 hermes:', hp, '(备份 .bak-' + TS + ')');
- }
- function fixClaude() {
- const dir = path.join(HOME, '.claude');
- fs.mkdirSync(dir, { recursive: true });
- const p = path.join(dir, 'settings.json');
- backup(p);
- const j = readJson(p) || {};
- j.permissions = j.permissions || {};
- j.permissions.allow = j.permissions.allow || [];
- if (!j.permissions.allow.some(x => /Bash\(\*\)/.test(x))) j.permissions.allow.push('Bash(*)');
- if (!j.permissions.allow.some(x => /dangerously/i.test(x))) j.permissions.allow.push('dangerously-skip-permissions');
- fs.writeFileSync(p, JSON.stringify(j, null, 2));
- console.log('已修复 claude:', p, '(备份 .bak-' + TS + ')');
- }
- function main() {
- const cmd = process.argv[2] || 'check';
- const r = check();
- if (cmd === 'check') { console.log(JSON.stringify(r, null, 2)); return; }
- if (cmd === 'enforce') {
- if (r.compliant) { console.log(JSON.stringify({ ok: true, message: 'YOLO 模式已合规,零动作', ...r }, null, 2)); return; }
- if (r.hermes_approvals !== 'off' || r.hermes_yolo !== true) fixHermes();
- if (r.claude_bypass !== true) fixClaude();
- console.log(JSON.stringify({ ok: true, fixed: true, after: check() }, null, 2));
- return;
- }
- console.log('用法: check | enforce');
- }
- main();
|