From 1c3db226d3bf104903852ba291763792a334047e Mon Sep 17 00:00:00 2001 From: Nicolas Date: Mon, 29 Jun 2026 21:57:28 -0400 Subject: [PATCH] fix: handle --agent-name flag by resolving and reviving target session The --agent-name flag was registered but never acted upon, since the postinstall patch that handled it was removed. This fix makes the extension itself resolve the flag value during session_start. - Adds resolveTargetSession() to daemon-client.ts for flag-to-session resolution with guard against re-entry (skips when flag matches current agent name). - In session_start, checks pi.getFlag("agent-name") and when the value names a different agent registered in the daemon, spawns a new pi --session process (mirroring the daemon's own resumeSession) and exits the current process. - Adds 5 tests for resolveTargetSession covering all edge cases (undefined, boolean, self-match, found, not-found). Co-authored-by: swift-badger-66 --- agent-identity/daemon-client.ts | 16 ++++++++++++++++ agent-identity/index.ts | 16 +++++++++++++++- test/agent-session.test.ts | 32 +++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/agent-identity/daemon-client.ts b/agent-identity/daemon-client.ts index c75c36e..5a82f6b 100644 --- a/agent-identity/daemon-client.ts +++ b/agent-identity/daemon-client.ts @@ -13,6 +13,22 @@ export function isDaemonRunning(socketPath: string = DEFAULT_SOCKET_PATH): boole return existsSync(socketPath); } +/** + * Resolve a --agent-name CLI flag value to a session file path. + * + * Returns null when the flag is unset, not a string, matches the current + * agent name, or the target agent isn't registered in the daemon. + */ +export async function resolveTargetSession( + flagValue: string | boolean | undefined, + currentAgentName: string, + socketPath: string = DEFAULT_SOCKET_PATH, +): Promise { + if (!flagValue || typeof flagValue !== "string") return null; + if (flagValue === currentAgentName) return null; + return await queryDaemonForSession(flagValue, socketPath); +} + /** * Query the daemon for an agent's session file path. * Connects, sends lookup_agent, returns sessionFile or null. diff --git a/agent-identity/index.ts b/agent-identity/index.ts index d1f255a..3c7adf8 100644 --- a/agent-identity/index.ts +++ b/agent-identity/index.ts @@ -19,7 +19,7 @@ import { createConnection, Socket } from "node:net"; import { existsSync, readFileSync } from "node:fs"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; -import { isDaemonRunning } from "./daemon-client.ts"; +import { isDaemonRunning, resolveTargetSession } from "./daemon-client.ts"; // ─── Name generation ──────────────────────────────────────────────────────── @@ -430,6 +430,20 @@ export default function (pi: ExtensionAPI) { // Capture session file path sessionFile = ctx.sessionManager.getSessionFile(); + // ── Handle --agent-name flag: resolve and revive target session ── + const flagValue = pi.getFlag("agent-name"); + const targetSession = await resolveTargetSession(flagValue, agentName); + if (targetSession) { + // Spawn a new pi process pointed at the target session, then exit. + // This mirrors the daemon's resumeSession behaviour. + spawn( + process.env["PI_CMD"] ?? "pi", + ["--session", targetSession], + { detached: true, stdio: "ignore", env: { ...process.env } }, + ).unref(); + process.exit(0); + } + if (ctx.hasUI) { ctx.ui.notify(`Agent identity: ${agentName}`, "info"); ctx.ui.setStatus("agent-identity", `🟡 ${agentName} (connecting to daemon...)`); diff --git a/test/agent-session.test.ts b/test/agent-session.test.ts index bff8b6f..690c4bf 100644 --- a/test/agent-session.test.ts +++ b/test/agent-session.test.ts @@ -10,7 +10,7 @@ import { describe, it, before, after } from "node:test"; import { strict as assert } from "node:assert"; import { createServer, Socket, Server } from "node:net"; import { existsSync, unlinkSync } from "node:fs"; -import { queryDaemonForSession } from "../agent-identity/daemon-client.ts"; +import { queryDaemonForSession, resolveTargetSession } from "../agent-identity/daemon-client.ts"; const SOCKET_PATH = "/tmp/agent-identity-daemon-test.sock"; @@ -104,4 +104,34 @@ describe("queryDaemonForSession without daemon", () => { }); }); +describe("resolveTargetSession", () => { + before(startMockDaemon); + after(stopMockDaemon); + + it("returns null when flag is undefined", async () => { + const result = await resolveTargetSession(undefined, "polar-lemur-69", SOCKET_PATH); + assert.equal(result, null); + }); + + it("returns null when flag is not a string (boolean)", async () => { + const result = await resolveTargetSession(true, "polar-lemur-69", SOCKET_PATH); + assert.equal(result, null); + }); + + it("returns null when flag matches current agent name", async () => { + const result = await resolveTargetSession("solar-falcon-55", "solar-falcon-55", SOCKET_PATH); + assert.equal(result, null); + }); + + it("resolves session file when flag differs and agent exists in daemon", async () => { + const result = await resolveTargetSession("test-fox-42", "polar-lemur-69", SOCKET_PATH); + assert.equal(result, "/tmp/test-session.jsonl"); + }); + + it("returns null when flag differs but agent not found in daemon", async () => { + const result = await resolveTargetSession("nonexistent-99", "polar-lemur-69", SOCKET_PATH); + assert.equal(result, null); + }); +}); +