diff --git a/packages/coding-agent/docs/extensions.md b/packages/coding-agent/docs/extensions.md index a9271ee8..83c367a8 100644 --- a/packages/coding-agent/docs/extensions.md +++ b/packages/coding-agent/docs/extensions.md @@ -322,6 +322,9 @@ user sends another prompt ◄───────────────── ├─► session_start { reason: "fork", previousSessionFile } └─► resources_discover { reason: "startup" } +/name or pi.setSessionName() + └─► session_info_changed + /compact or auto-compaction ├─► session_before_compact (can cancel or customize) └─► session_compact @@ -395,6 +398,17 @@ pi.on("session_start", async (event, ctx) => { }); ``` +#### session_info_changed + +Fired when the current session display name is set via `/name`, RPC, or `pi.setSessionName()`. + +```typescript +pi.on("session_info_changed", async (event, ctx) => { + // event.name - current normalized name, or undefined if cleared + ctx.ui.notify(`Session renamed: ${event.name ?? "(none)"}`, "info"); +}); +``` + #### session_before_switch Fired before starting a new session (`/new`) or switching sessions (`/resume`). diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index efd21e71..c5304a0f 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -2683,7 +2683,9 @@ export class AgentSession { */ setSessionName(name: string): void { this.sessionManager.appendSessionInfo(name); - this._emit({ type: "session_info_changed", name: this.sessionManager.getSessionName() }); + const event = { type: "session_info_changed", name: this.sessionManager.getSessionName() } as const; + this._emit(event); + void this._extensionRunner.emit(event); } // ========================================================================= diff --git a/packages/coding-agent/src/core/extensions/index.ts b/packages/coding-agent/src/core/extensions/index.ts index 3ed7a662..32fdd048 100644 --- a/packages/coding-agent/src/core/extensions/index.ts +++ b/packages/coding-agent/src/core/extensions/index.ts @@ -128,6 +128,7 @@ export type { SessionBeforeTreeResult, SessionCompactEvent, SessionEvent, + SessionInfoChangedEvent, SessionShutdownEvent, // Events - Session SessionStartEvent, diff --git a/packages/coding-agent/src/core/extensions/types.ts b/packages/coding-agent/src/core/extensions/types.ts index 7234d4e4..73780027 100644 --- a/packages/coding-agent/src/core/extensions/types.ts +++ b/packages/coding-agent/src/core/extensions/types.ts @@ -551,6 +551,13 @@ export interface SessionStartEvent { previousSessionFile?: string; } +/** Fired when the current session metadata changes. */ +export interface SessionInfoChangedEvent { + type: "session_info_changed"; + /** Current normalized session name. Undefined when the name is cleared. */ + name: string | undefined; +} + /** Fired before switching to another session (can be cancelled) */ export interface SessionBeforeSwitchEvent { type: "session_before_switch"; @@ -630,6 +637,7 @@ export interface SessionTreeEvent { export type SessionEvent = | SessionStartEvent + | SessionInfoChangedEvent | SessionBeforeSwitchEvent | SessionBeforeForkEvent | SessionBeforeCompactEvent @@ -1133,6 +1141,7 @@ export interface ExtensionAPI { on(event: "project_trust", handler: ProjectTrustHandler): void; on(event: "resources_discover", handler: ExtensionHandler): void; on(event: "session_start", handler: ExtensionHandler): void; + on(event: "session_info_changed", handler: ExtensionHandler): void; on( event: "session_before_switch", handler: ExtensionHandler, diff --git a/packages/coding-agent/src/index.ts b/packages/coding-agent/src/index.ts index 0be0a8da..1b64d97a 100644 --- a/packages/coding-agent/src/index.ts +++ b/packages/coding-agent/src/index.ts @@ -122,6 +122,7 @@ export type { SessionBeforeSwitchEvent, SessionBeforeTreeEvent, SessionCompactEvent, + SessionInfoChangedEvent, SessionShutdownEvent, SessionStartEvent, SessionTreeEvent, diff --git a/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts b/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts index 6265ce96..721c29df 100644 --- a/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts +++ b/packages/coding-agent/test/suite/regressions/3686-session-name-event.test.ts @@ -37,4 +37,25 @@ describe("regression #3686: session name changes emit an event", () => { expect(harness.sessionManager.getSessionName()).toBe("from extension"); expect(harness.eventsOfType("session_info_changed").map((event) => event.name)).toEqual(["from extension"]); }); + + it("emits session_info_changed to extensions", async () => { + let api: ExtensionAPI | undefined; + const events: Array<{ name: string | undefined }> = []; + const harness = await createHarness({ + extensionFactories: [ + (pi) => { + api = pi; + pi.on("session_info_changed", (event) => { + events.push({ name: event.name }); + }); + }, + ], + }); + harnesses.push(harness); + + api?.setSessionName("first"); + harness.session.setSessionName("second"); + + expect(events).toEqual([{ name: "first" }, { name: "second" }]); + }); });