// Identity resolution for the MCP Watcher. // // Mirrors the layered resolution shipped in agent-ping (PR #1). The CLI // has four layers (--as flag, env, $CLAUDE_HOME/ping-agent, ~/.ping-agent); // the watcher subprocess has three (no argv override useful in MCP context). // // Spec: agent-ping spec §9; agent-watcher spec §4.4. import { homedir } from "node:os"; import { existsSync, readFileSync } from "node:fs"; import { join } from "node:path"; export interface ResolvedIdentity { agent: string; source: string; } /** * Resolve this process's agent identity. * Layers, first match wins: * 1. PING_AGENT_IDENTITY env var * 2. $CLAUDE_HOME/ping-agent (if CLAUDE_HOME is set and file exists) * 3. ~/.ping-agent * * Throws if no layer resolves. */ export function resolveIdentity(env: NodeJS.ProcessEnv = process.env): ResolvedIdentity { const envId = (env.PING_AGENT_IDENTITY ?? "").trim(); if (envId) { return { agent: envId, source: "PING_AGENT_IDENTITY env var" }; } const claudeHome = (env.CLAUDE_HOME ?? "").trim(); if (claudeHome) { const f = join(claudeHome, "ping-agent"); if (existsSync(f)) { const name = readFileSync(f, "utf8").trim(); if (name) { return { agent: name, source: f }; } } } const home = env.HOME ?? homedir(); const defaultFile = join(home, ".ping-agent"); if (existsSync(defaultFile)) { const name = readFileSync(defaultFile, "utf8").trim(); if (name) { return { agent: name, source: defaultFile }; } } throw new Error( `agent-watcher-mcp: no identity resolved. Set PING_AGENT_IDENTITY, ` + `$CLAUDE_HOME/ping-agent, or ${defaultFile}.`, ); }