/** * Per-agent destination map + ACL. * * Each row means: agent `agent_group_id` is allowed to send messages to * target (`target_type`, `target_id`), and refers to it locally as `local_name`. * * Names are local to each source agent — they exist only inside that agent's * namespace. The host uses this table both for routing (resolve name → ID) * and for permission checks (row exists ⇒ authorized). */ import type { AgentDestination } from '../types.js'; import { getDb } from './connection.js'; export function createDestination(row: AgentDestination): void { getDb() .prepare( `INSERT INTO agent_destinations (agent_group_id, local_name, target_type, target_id, created_at) VALUES (@agent_group_id, @local_name, @target_type, @target_id, @created_at)`, ) .run(row); } export function getDestinations(agentGroupId: string): AgentDestination[] { return getDb() .prepare('SELECT * FROM agent_destinations WHERE agent_group_id = ?') .all(agentGroupId) as AgentDestination[]; } export function getDestinationByName(agentGroupId: string, localName: string): AgentDestination | undefined { return getDb() .prepare('SELECT * FROM agent_destinations WHERE agent_group_id = ? AND local_name = ?') .get(agentGroupId, localName) as AgentDestination | undefined; } /** Reverse lookup: what does this agent call the given target? */ export function getDestinationByTarget( agentGroupId: string, targetType: 'channel' | 'agent', targetId: string, ): AgentDestination | undefined { return getDb() .prepare( 'SELECT * FROM agent_destinations WHERE agent_group_id = ? AND target_type = ? AND target_id = ?', ) .get(agentGroupId, targetType, targetId) as AgentDestination | undefined; } /** Permission check: can this agent send to this target? */ export function hasDestination( agentGroupId: string, targetType: 'channel' | 'agent', targetId: string, ): boolean { const row = getDb() .prepare( 'SELECT 1 FROM agent_destinations WHERE agent_group_id = ? AND target_type = ? AND target_id = ? LIMIT 1', ) .get(agentGroupId, targetType, targetId); return !!row; } export function deleteDestination(agentGroupId: string, localName: string): void { getDb().prepare('DELETE FROM agent_destinations WHERE agent_group_id = ? AND local_name = ?').run(agentGroupId, localName); } /** Normalize a human-readable name into a lowercase, dash-separated identifier. */ export function normalizeName(name: string): string { return ( name .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, '') || 'unnamed' ); }