feat: restore previous permission mode when exiting plan mode (#866)

This commit is contained in:
paulbettner
2026-02-08 21:10:21 -06:00
committed by GitHub
parent 89ace569d7
commit f5c143ec74
3 changed files with 58 additions and 3 deletions

View File

@@ -9559,9 +9559,11 @@ ${SYSTEM_REMINDER_CLOSE}
lastPlanFilePathRef.current = planFilePath;
// Exit plan mode
const newMode = acceptEdits ? "acceptEdits" : "default";
permissionMode.setMode(newMode);
setUiPermissionMode(newMode);
const restoreMode = acceptEdits
? "acceptEdits"
: (permissionMode.getModeBeforePlan() ?? "default");
permissionMode.setMode(restoreMode);
setUiPermissionMode(restoreMode);
try {
// Execute ExitPlanMode tool to get the result

View File

@@ -16,10 +16,12 @@ export type PermissionMode =
// This prevents Bun's bundler from creating duplicate instances of the mode manager
const MODE_KEY = Symbol.for("@letta/permissionMode");
const PLAN_FILE_KEY = Symbol.for("@letta/planFilePath");
const MODE_BEFORE_PLAN_KEY = Symbol.for("@letta/permissionModeBeforePlan");
type GlobalWithMode = typeof globalThis & {
[MODE_KEY]: PermissionMode;
[PLAN_FILE_KEY]: string | null;
[MODE_BEFORE_PLAN_KEY]?: PermissionMode | null;
};
function getGlobalMode(): PermissionMode {
@@ -45,6 +47,16 @@ function setGlobalPlanFilePath(value: string | null): void {
global[PLAN_FILE_KEY] = value;
}
function getGlobalModeBeforePlan(): PermissionMode | null {
const global = globalThis as GlobalWithMode;
return global[MODE_BEFORE_PLAN_KEY] ?? null;
}
function setGlobalModeBeforePlan(value: PermissionMode | null): void {
const global = globalThis as GlobalWithMode;
global[MODE_BEFORE_PLAN_KEY] = value;
}
/**
* Permission mode state for the current session.
* Set via CLI --permission-mode flag or settings.json defaultMode.
@@ -62,11 +74,33 @@ class PermissionModeManager {
* Set the permission mode for this session
*/
setMode(mode: PermissionMode): void {
const prevMode = this.currentMode;
// If we are entering plan mode, remember what mode we were previously in so
// ExitPlanMode can restore it (e.g. YOLO).
if (mode === "plan" && prevMode !== "plan") {
setGlobalModeBeforePlan(prevMode);
}
this.currentMode = mode;
// Clear plan file path when exiting plan mode
if (mode !== "plan") {
setGlobalPlanFilePath(null);
}
// Once we leave plan mode, the remembered mode has been consumed.
if (prevMode === "plan" && mode !== "plan") {
setGlobalModeBeforePlan(null);
}
}
/**
* Get the permission mode that was active before entering plan mode.
* Used to restore the user's previous setting (e.g., bypassPermissions).
*/
getModeBeforePlan(): PermissionMode | null {
return getGlobalModeBeforePlan();
}
/**
@@ -261,6 +295,8 @@ class PermissionModeManager {
*/
reset(): void {
this.currentMode = "default";
setGlobalPlanFilePath(null);
setGlobalModeBeforePlan(null);
}
}

View File

@@ -452,3 +452,20 @@ test("Permission mode takes precedence over CLI allowedTools", () => {
// Clean up
cliPermissions.clear();
});
test("plan mode - remembers and restores previous mode", () => {
permissionMode.setMode("bypassPermissions");
expect(permissionMode.getMode()).toBe("bypassPermissions");
// Enter plan mode - should remember prior mode.
permissionMode.setMode("plan");
expect(permissionMode.getMode()).toBe("plan");
expect(permissionMode.getModeBeforePlan()).toBe("bypassPermissions");
// Exit plan mode by restoring previous mode.
permissionMode.setMode(permissionMode.getModeBeforePlan() ?? "default");
expect(permissionMode.getMode()).toBe("bypassPermissions");
// Once we leave plan mode, the remembered mode is consumed.
expect(permissionMode.getModeBeforePlan()).toBe(null);
});