import { agentClientId, encodeAwareness } from "./room-awareness";
const AGENT_PRESENCE_MS = 30 * 1000;
const AGENT_COLOR = "#a371f7";
/** Agents are keyed by (user, name) so two people's "claude" don't overwrite each other's presence. */
export function agentKey(userId: string, agent: string): string {
return `${userId}:${agent}`;
}
export type TextEdit = { from: number; to: number; insert: string };
export type ApplyResult =
| { ok: true; version: number; text: string }
| { ok: false; error: "stale" | string; version: number; text: string };
type AgentRow = { name: string; user_name: string; path: string | null; clock: number };
/** Records an agent's latest activity and returns the awareness update announcing its cursor. */
export function touchAgent(sql: SqlStorage, agent: string, user: string, path: string, cursor: number): Uint8Array {
const row = sql.exec<{ clock: number }>("SELECT clock FROM agents WHERE name = ?", agent).toArray()[0];
const clock = (row?.clock ?? 0) + 1;
sql.exec(
`INSERT INTO agents (name, user_name, path, clock, expires_at) VALUES (?, ?, ?, ?, ?)
ON CONFLICT(name) DO UPDATE SET user_name = excluded.user_name, path = excluded.path, clock = excluded.clock, expires_at = excluded.expires_at`,
agent,
user,
path,
clock,
Date.now() + AGENT_PRESENCE_MS,
);
return agentUpdate({ name: agent, user_name: user, path, clock, cursor });
}
export function liveAgents(sql: SqlStorage): AgentRow[] {
return sql
.exec<AgentRow>("SELECT name, user_name, path, clock FROM agents WHERE expires_at > ?", Date.now())
.toArray();
}
export function expireAgents(sql: SqlStorage): Array<{ name: string; clock: number }> {
const expired = sql