feat(diagnostics): adicionar 16 ferramentas de diagnóstico DB Paperclip

14 tools read-only para inspecção da BD Paperclip directamente via MCP,
eliminando psql nos skills /clip-*. 2 tools write (rotation, cancel issue).

- src/db.ts: pool PG singleton + COMPANY_ID + helper query() parametrizado
- src/tools/diagnostics.ts: 16 tools, 100% queries com $1,$2 (zero injection)
- src/tools/index.ts: registo ...diagnosticsTools
- package.json: pg ^8.13.1 + @types/pg ^8.11.10
- CHANGELOG.md: changelog completo

Fix: diag_agents_without_membership cast a.id::text + filtros
principal_type='agent' AND status='active'.

Validado:
- 14/14 read tools testadas contra BD real (CEO=19 runs, 65 agentes,
  Reality Checker sem heartbeat/membership, 2 routines next_run_at NULL)
- npm audit: 0 vulnerabilidades
- grep '\${' em SQL: zero matches

Refs: Desk #2041

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 03:59:19 +01:00
parent 2b2b82c2a7
commit 281799fad2
5 changed files with 524 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
import pg from 'pg';
import { logger } from './utils/logger.js';
const { Pool } = pg;
let pool: pg.Pool | null = null;
export function getPool(): pg.Pool {
if (pool) return pool;
const connectionString = process.env.PAPERCLIP_DB_URL;
if (!connectionString) {
throw new Error('PAPERCLIP_DB_URL não definido — diagnostics tools requerem acesso BD');
}
pool = new Pool({
connectionString,
max: 5,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 5000,
});
pool.on('error', (err) => logger.error('pg pool error:', err));
return pool;
}
export async function query<T = Record<string, unknown>>(
text: string,
params: unknown[] = []
): Promise<T[]> {
const result = await getPool().query(text, params);
return result.rows as T[];
}
export const COMPANY_ID =
process.env.PAPERCLIP_COMPANY_ID ?? 'ebe10308-efd7-453f-86ab-13e6fe84004f';