Skip to content

Commit 2cae362

Browse files
committed
fix(ssh): align session restore with pi 0.65
Prefer persisted SSH state over env fallback, stop relying on removed session_fork hooks, and add session messages when SSH mode is toggled so the agent sees state changes in conversation context.
1 parent bfbb86e commit 2cae362

1 file changed

Lines changed: 19 additions & 9 deletions

File tree

config/pi/extensions/ssh.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -369,13 +369,14 @@ function getCommandCompletions(currentState: SshState | null, prefix: string): A
369369
return filtered.length > 0 ? filtered : null;
370370
}
371371

372-
function findPersistedState(ctx: SessionRestoreContext): SshState | null {
372+
function findPersistedState(ctx: SessionRestoreContext): { found: boolean; state: SshState | null } {
373373
const entry = ctx.sessionManager
374374
.getEntries()
375375
.filter((item) => item.type === "custom" && item.customType === ENTRY_TYPE)
376376
.pop();
377377

378-
return deserializeState(entry?.data);
378+
if (!entry) return { found: false, state: null };
379+
return { found: true, state: deserializeState(entry.data) };
379380
}
380381

381382
export default function (pi: ExtensionAPI) {
@@ -421,7 +422,8 @@ export default function (pi: ExtensionAPI) {
421422
};
422423

423424
const restoreState = (ctx: SessionRestoreContext) => {
424-
activeSsh = loadStateFromEnv() ?? findPersistedState(ctx);
425+
const persisted = findPersistedState(ctx);
426+
activeSsh = persisted.found ? persisted.state : loadStateFromEnv();
425427
writeStateToEnv(activeSsh);
426428
updateStatus(ctx);
427429
};
@@ -486,24 +488,36 @@ export default function (pi: ExtensionAPI) {
486488

487489
if (["off", "disable", "clear"].includes(trimmed)) {
488490
await applyState(null, ctx, { persist: true });
491+
pi.sendMessage({
492+
customType: "ssh-state-change",
493+
content: "SSH mode disabled. All tool calls (read, write, edit, bash) and user ! commands now execute locally.",
494+
display: true,
495+
}, { deliverAs: "nextTurn" });
489496
return;
490497
}
491498

492499
try {
493500
const nextState = await resolveSshTarget(trimmed, localCwd);
494501
await applyState(nextState, ctx, { persist: true });
502+
pi.sendMessage({
503+
customType: "ssh-state-change",
504+
content: `SSH mode enabled: ${nextState.remote}:${nextState.remoteRootCwd}\nAll tool calls (read, write, edit, bash) and user ! commands now execute on this remote host.`,
505+
display: true,
506+
}, { deliverAs: "nextTurn" });
495507
} catch (error) {
496508
const message = error instanceof Error ? error.message : String(error);
497509
if (ctx.hasUI) ctx.ui.notify(`Failed to enable SSH mode: ${message}`, "error");
498510
}
499511
},
500512
});
501513

502-
pi.on("session_start", async (_event, ctx) => {
514+
pi.on("session_start", async (event, ctx) => {
503515
const flag = pi.getFlag("ssh");
516+
const shouldNotify = !event.reason || event.reason === "startup" || event.reason === "reload";
517+
504518
if (typeof flag === "string" && flag.trim()) {
505519
try {
506-
await applyState(await resolveSshTarget(flag, localCwd), ctx, { notify: true });
520+
await applyState(await resolveSshTarget(flag, localCwd), ctx, { notify: shouldNotify });
507521
return;
508522
} catch (error) {
509523
const message = error instanceof Error ? error.message : String(error);
@@ -518,10 +532,6 @@ export default function (pi: ExtensionAPI) {
518532
restoreState(ctx);
519533
});
520534

521-
pi.on("session_fork", async (_event, ctx) => {
522-
restoreState(ctx);
523-
});
524-
525535
pi.on("user_bash", () => {
526536
if (!getSsh()) return;
527537
return { operations: createRemoteBashOps(getSsh) };

0 commit comments

Comments
 (0)