feat(coding-agent): add switchSession to Extension API (#1191)

Allows extension commands to programmatically switch to a different session file via ctx.switchSession(sessionPath).

fixes #1187
This commit is contained in:
Juan Ibiapina 2026-02-02 18:03:26 +01:00 committed by GitHub
parent 0d934091f4
commit d0228412d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 24 additions and 0 deletions

View file

@ -4,6 +4,7 @@
### Added ### Added
- **Extension API switchSession**: Added `ctx.switchSession(sessionPath)` to `ExtensionCommandContext` for programmatic session switching in extension commands ([#1187](https://github.com/badlogic/pi-mono/issues/1187)).
- **Clear on shrink setting**: New `terminal.clearOnShrink` setting (and `/settings` toggle) controls whether empty rows are cleared when content shrinks. Disabled by default to reduce flicker. Enable via settings or `PI_CLEAR_ON_SHRINK=1` env var. - **Clear on shrink setting**: New `terminal.clearOnShrink` setting (and `/settings` toggle) controls whether empty rows are cleared when content shrinks. Disabled by default to reduce flicker. Enable via settings or `PI_CLEAR_ON_SHRINK=1` env var.
## [0.51.0] - 2026-02-01 ## [0.51.0] - 2026-02-01

View file

@ -14,6 +14,7 @@ export type {
NavigateTreeHandler, NavigateTreeHandler,
NewSessionHandler, NewSessionHandler,
ShutdownHandler, ShutdownHandler,
SwitchSessionHandler,
} from "./runner.js"; } from "./runner.js";
export { ExtensionRunner } from "./runner.js"; export { ExtensionRunner } from "./runner.js";
export type { export type {

View file

@ -106,6 +106,8 @@ export type NavigateTreeHandler = (
options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string }, options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string },
) => Promise<{ cancelled: boolean }>; ) => Promise<{ cancelled: boolean }>;
export type SwitchSessionHandler = (sessionPath: string) => Promise<{ cancelled: boolean }>;
export type ShutdownHandler = () => void; export type ShutdownHandler = () => void;
/** /**
@ -165,6 +167,7 @@ export class ExtensionRunner {
private newSessionHandler: NewSessionHandler = async () => ({ cancelled: false }); private newSessionHandler: NewSessionHandler = async () => ({ cancelled: false });
private forkHandler: ForkHandler = async () => ({ cancelled: false }); private forkHandler: ForkHandler = async () => ({ cancelled: false });
private navigateTreeHandler: NavigateTreeHandler = async () => ({ cancelled: false }); private navigateTreeHandler: NavigateTreeHandler = async () => ({ cancelled: false });
private switchSessionHandler: SwitchSessionHandler = async () => ({ cancelled: false });
private shutdownHandler: ShutdownHandler = () => {}; private shutdownHandler: ShutdownHandler = () => {};
private shortcutDiagnostics: ResourceDiagnostic[] = []; private shortcutDiagnostics: ResourceDiagnostic[] = [];
@ -221,6 +224,7 @@ export class ExtensionRunner {
this.newSessionHandler = actions.newSession; this.newSessionHandler = actions.newSession;
this.forkHandler = actions.fork; this.forkHandler = actions.fork;
this.navigateTreeHandler = actions.navigateTree; this.navigateTreeHandler = actions.navigateTree;
this.switchSessionHandler = actions.switchSession;
return; return;
} }
@ -228,6 +232,7 @@ export class ExtensionRunner {
this.newSessionHandler = async () => ({ cancelled: false }); this.newSessionHandler = async () => ({ cancelled: false });
this.forkHandler = async () => ({ cancelled: false }); this.forkHandler = async () => ({ cancelled: false });
this.navigateTreeHandler = async () => ({ cancelled: false }); this.navigateTreeHandler = async () => ({ cancelled: false });
this.switchSessionHandler = async () => ({ cancelled: false });
} }
setUIContext(uiContext?: ExtensionUIContext): void { setUIContext(uiContext?: ExtensionUIContext): void {
@ -436,6 +441,7 @@ export class ExtensionRunner {
newSession: (options) => this.newSessionHandler(options), newSession: (options) => this.newSessionHandler(options),
fork: (entryId) => this.forkHandler(entryId), fork: (entryId) => this.forkHandler(entryId),
navigateTree: (targetId, options) => this.navigateTreeHandler(targetId, options), navigateTree: (targetId, options) => this.navigateTreeHandler(targetId, options),
switchSession: (sessionPath) => this.switchSessionHandler(sessionPath),
}; };
} }

View file

@ -293,6 +293,9 @@ export interface ExtensionCommandContext extends ExtensionContext {
targetId: string, targetId: string,
options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string }, options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string },
): Promise<{ cancelled: boolean }>; ): Promise<{ cancelled: boolean }>;
/** Switch to a different session file. */
switchSession(sessionPath: string): Promise<{ cancelled: boolean }>;
} }
// ============================================================================ // ============================================================================
@ -1214,6 +1217,7 @@ export interface ExtensionCommandContextActions {
targetId: string, targetId: string,
options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string }, options?: { summarize?: boolean; customInstructions?: string; replaceInstructions?: boolean; label?: string },
) => Promise<{ cancelled: boolean }>; ) => Promise<{ cancelled: boolean }>;
switchSession: (sessionPath: string) => Promise<{ cancelled: boolean }>;
} }
/** /**

View file

@ -1059,6 +1059,10 @@ export class InteractiveMode {
return { cancelled: false }; return { cancelled: false };
}, },
switchSession: async (sessionPath) => {
await this.handleResumeSession(sessionPath);
return { cancelled: false };
},
}, },
shutdownHandler: () => { shutdownHandler: () => {
this.shutdownRequested = true; this.shutdownRequested = true;

View file

@ -59,6 +59,10 @@ export async function runPrintMode(session: AgentSession, options: PrintModeOpti
}); });
return { cancelled: result.cancelled }; return { cancelled: result.cancelled };
}, },
switchSession: async (sessionPath) => {
const success = await session.switchSession(sessionPath);
return { cancelled: !success };
},
}, },
onError: (err) => { onError: (err) => {
console.error(`Extension error (${err.extensionPath}): ${err.error}`); console.error(`Extension error (${err.extensionPath}): ${err.error}`);

View file

@ -277,6 +277,10 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
}); });
return { cancelled: result.cancelled }; return { cancelled: result.cancelled };
}, },
switchSession: async (sessionPath) => {
const success = await session.switchSession(sessionPath);
return { cancelled: !success };
},
}, },
shutdownHandler: () => { shutdownHandler: () => {
shutdownRequested = true; shutdownRequested = true;