69 lines
3.1 KiB
JavaScript
69 lines
3.1 KiB
JavaScript
|
|
#!/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');
|