import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { resolveIdentity } from "../src/identity.js"; let dir: string; beforeEach(() => { dir = mkdtempSync(join(tmpdir(), "watcher-id-")); }); afterEach(() => { rmSync(dir, { recursive: true, force: true }); }); describe("resolveIdentity", () => { it("uses PING_AGENT_IDENTITY env var first", () => { writeFileSync(join(dir, ".ping-agent"), "default-agent\n"); const r = resolveIdentity({ HOME: dir, PING_AGENT_IDENTITY: "envname", }); expect(r.agent).toBe("envname"); expect(r.source).toMatch(/env/i); }); it("uses $CLAUDE_HOME/ping-agent next", () => { writeFileSync(join(dir, ".ping-agent"), "default-agent\n"); const claudeHome = join(dir, "claude-sandbox"); mkdirSync(claudeHome); writeFileSync(join(claudeHome, "ping-agent"), "sandbox\n"); const r = resolveIdentity({ HOME: dir, CLAUDE_HOME: claudeHome, PING_AGENT_IDENTITY: "", }); expect(r.agent).toBe("sandbox"); expect(r.source).toContain(claudeHome); }); it("falls through to ~/.ping-agent", () => { writeFileSync(join(dir, ".ping-agent"), "bob\n"); const r = resolveIdentity({ HOME: dir }); expect(r.agent).toBe("bob"); expect(r.source).toContain(".ping-agent"); }); it("throws when nothing resolves", () => { expect(() => resolveIdentity({ HOME: dir })).toThrow(/no identity/); }); it("ignores empty CLAUDE_HOME/ping-agent and falls through", () => { writeFileSync(join(dir, ".ping-agent"), "bob\n"); const claudeHome = join(dir, "claude-sandbox"); mkdirSync(claudeHome); writeFileSync(join(claudeHome, "ping-agent"), ""); const r = resolveIdentity({ HOME: dir, CLAUDE_HOME: claudeHome }); expect(r.agent).toBe("bob"); }); it("trims whitespace from identity files", () => { writeFileSync(join(dir, ".ping-agent"), " bob \n\n"); const r = resolveIdentity({ HOME: dir }); expect(r.agent).toBe("bob"); }); });