Governed substrate for autonomous agents: scoped identity (passports), audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
78 lines
2.7 KiB
JavaScript
78 lines
2.7 KiB
JavaScript
#!/usr/bin/env node
|
|
// ADR-0025 A.5 — prepend §11.1 guard to 8 active agent prompts (idempotent)
|
|
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
import jwt from 'jsonwebtoken';
|
|
|
|
const SECRET = 'REDACTED-SET-VIA-JWT_SECRET-ENV';
|
|
const BASE = 'https://devcrm.hltrn.cc/api/v3';
|
|
const TABLE = 1784;
|
|
const GUARD = readFileSync('/tmp/adr0025_a5_guard.md', 'utf8');
|
|
const SENTINEL = '## §11.1 — Suicide-PM2 Guard';
|
|
|
|
const AGENTS = [
|
|
{ id: 110507, name: 'Agent Smith' },
|
|
{ id: 33491, name: 'Architect' },
|
|
{ id: 31113, name: 'Developer Ralph' },
|
|
{ id: 31114, name: 'Frontend' },
|
|
{ id: 33484, name: 'SysAdmin' },
|
|
{ id: 31115, name: 'Test Runner' },
|
|
{ id: 33485, name: 'Frontend QA' },
|
|
{ id: 31112, name: 'Orchestrator' },
|
|
];
|
|
|
|
const token = jwt.sign(
|
|
{ userId: 24, email: 'architect@hltrn.cc', role: 'admin' },
|
|
SECRET,
|
|
{ expiresIn: '1h' }
|
|
);
|
|
|
|
const headers = { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' };
|
|
|
|
async function getRow(id) {
|
|
const r = await fetch(`${BASE}/tables/${TABLE}/rows/${id}`, { headers });
|
|
if (!r.ok) throw new Error(`GET ${id}: ${r.status}`);
|
|
return r.json();
|
|
}
|
|
|
|
async function updateRow(id, data) {
|
|
const r = await fetch(`${BASE}/tables/${TABLE}/rows/${id}`, {
|
|
method: 'PUT',
|
|
headers,
|
|
body: JSON.stringify({ data }),
|
|
});
|
|
if (!r.ok) throw new Error(`PUT ${id}: ${r.status} ${await r.text()}`);
|
|
return r.json();
|
|
}
|
|
|
|
const today = new Date().toISOString().slice(0, 10);
|
|
const snapDir = `/root/production/business-crm/.cleanup-snapshots/${today}`;
|
|
mkdirSync(snapDir, { recursive: true });
|
|
const snapPath = `${snapDir}/agent_prompts_pre-11.1.json`;
|
|
|
|
// Phase 1: snapshot all 8 rows BEFORE any write.
|
|
const snapshots = {};
|
|
for (const a of AGENTS) {
|
|
const row = await getRow(a.id);
|
|
const cur = row?.data?.system_prompt ?? row?.row?.system_prompt ?? row?.system_prompt ?? '';
|
|
snapshots[a.id] = { name: a.name, system_prompt: cur };
|
|
}
|
|
writeFileSync(snapPath, JSON.stringify(snapshots, null, 2));
|
|
|
|
// Phase 2: update only rows that lack the sentinel.
|
|
const report = [];
|
|
for (const a of AGENTS) {
|
|
const cur = snapshots[a.id].system_prompt;
|
|
if (typeof cur !== 'string') {
|
|
report.push({ id: a.id, name: a.name, status: 'ERROR_NO_STRING', len: 0 });
|
|
continue;
|
|
}
|
|
if (cur.includes(SENTINEL)) {
|
|
report.push({ id: a.id, name: a.name, status: 'ALREADY_PRESENT', len: cur.length });
|
|
continue;
|
|
}
|
|
const next = GUARD + cur;
|
|
await updateRow(a.id, { system_prompt: next });
|
|
report.push({ id: a.id, name: a.name, status: 'PREPENDED', len_before: cur.length, len_after: next.length });
|
|
}
|
|
|
|
console.log(JSON.stringify({ snapshot: snapPath, guard_bytes: GUARD.length, agents: report }, null, 2));
|