#!/usr/bin/env node /** * P1 Patch: Agent 动态模型 + 最小权限 * - model: opus(质量关键) / sonnet(平衡) / haiku(速度) * - allowed-tools: 按角色最小权限 * 幂等: 检查 frontmatter 是否已含 model/allowed-tools */ 'use strict'; const fs = require('fs'); const path = require('path'); const AGENTS_DIR = path.resolve(__dirname, '..', '..', 'agents'); const CONFIG = { 'orchestrator': { model: 'sonnet' }, 'production-reviewer': { model: 'opus', tools: 'Read, Glob, Grep, Bash, WebFetch, WebSearch' }, 'red-team-attacker': { model: 'opus', tools: 'Read, Glob, Grep, Bash' }, 'red-team-logic': { model: 'opus', tools: 'Read, Glob, Grep, Bash' }, 'security-hardener': { model: 'sonnet', tools: 'Read, Edit, Write, Glob, Grep, Bash' }, 'full-stack-builder': { model: 'sonnet', tools: 'Read, Edit, Write, Glob, Grep, Bash' }, 'module-integrator': { model: 'sonnet', tools: 'Read, Edit, Write, Glob, Grep, Bash' }, 'quality-gate': { model: 'sonnet', tools: 'Read, Glob, Grep, Bash' }, 'research-analyst': { model: 'sonnet', tools: 'Read, Glob, Grep, Bash, WebFetch, WebSearch' }, 'self-auditor': { model: 'sonnet', tools: 'Read, Glob, Grep, Bash' }, 'self-healer': { model: 'sonnet', tools: 'Read, Edit, Write, Glob, Grep, Bash' }, 'canvas-ui-designer': { model: 'sonnet', tools: 'Read, Edit, Write, Glob, Grep, Bash' }, 'delivery-quality-assessor':{ model: 'sonnet', tools: 'Read, Glob, Grep, Bash' }, 'explore': { model: 'haiku', tools: 'Read, Glob, Grep, Bash' }, 'desktop-automator': { model: 'haiku' }, }; function patchAgent(name, cfg) { const fp = path.join(AGENTS_DIR, name + '.md'); if (!fs.existsSync(fp)) { process.stderr.write('[SKIP] ' + name + ' not found\n'); return false; } const src = fs.readFileSync(fp, 'utf8'); const lines = src.split('\n'); let inFm = false, closeIdx = -1; for (let i = 0; i < lines.length; i++) { if (lines[i].trim() === '---') { if (!inFm) { inFm = true; continue; } closeIdx = i; break; } } if (closeIdx === -1) { process.stderr.write('[SKIP] ' + name + ' no frontmatter\n'); return false; } const fmBlock = lines.slice(1, closeIdx).join('\n'); const toAdd = []; if (cfg.model && !fmBlock.includes('model:')) toAdd.push('model: ' + cfg.model); if (cfg.tools && !fmBlock.includes('allowed-tools:')) toAdd.push('allowed-tools: "' + cfg.tools + '"'); if (toAdd.length === 0) { process.stderr.write('[SKIP] ' + name + ' already configured\n'); return false; } fs.writeFileSync(fp + '.bak-p1.' + Date.now(), src); lines.splice(closeIdx, 0, ...toAdd); const tmp = fp + '.tmp.' + process.pid; fs.writeFileSync(tmp, lines.join('\n'), 'utf8'); fs.renameSync(tmp, fp); process.stderr.write('[DONE] ' + name + ' +' + toAdd.map(l => l.split(':')[0]).join(',') + '\n'); return true; } let count = 0; for (const [name, cfg] of Object.entries(CONFIG)) { if (patchAgent(name, cfg)) count++; } process.stderr.write('\nP1 Agent Config: ' + count + '/' + Object.keys(CONFIG).length + ' agents updated\n');