mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-14 22:02:59 -07:00
fix(core): trigger JIT directory provisioning synchronously in enter-plan-mode to restore sandbox compatibility
This fixes a regression where sandboxed environments (like Windows bwrap) would crash when attempting to bind the plans directory if it was lazily created after the sandbox was initialized. Additionally, documented the sticky extension context logic in AppContainer to address code review feedback.
This commit is contained in:
@@ -1384,12 +1384,19 @@ Logging in with Google... Restarting Gemini CLI to continue.
|
||||
|
||||
if (config) {
|
||||
if (parsedCommand.extensionContext) {
|
||||
// Explicit extension invocation sets the "sticky" context to that extension,
|
||||
// allowing subsequent multi-turn conversational replies (e.g. "yes, do that")
|
||||
// to continue interacting with the extension's isolated plan directory.
|
||||
if (config.hasExtensionPlanDir(parsedCommand.extensionContext)) {
|
||||
config.setActiveExtensionContext(parsedCommand.extensionContext);
|
||||
} else {
|
||||
// Extension doesn't have a plan dir registered, so fallback to default workspace context
|
||||
config.setActiveExtensionContext(undefined);
|
||||
}
|
||||
} else if (parsedCommand.commandToExecute?.name === 'plan') {
|
||||
// If the user explicitly runs the native global /plan command (e.g., "/plan copy"),
|
||||
// they are signaling an intent to manage their standard workspace plans,
|
||||
// so we clear the sticky extension context to avoid misdirecting the operation.
|
||||
config.setActiveExtensionContext(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,17 @@ describe('EnterPlanModeTool', () => {
|
||||
expect(result.returnDisplay).toBe('Switching to Plan mode');
|
||||
});
|
||||
|
||||
it('should call getPlansDir immediately after setting ApprovalMode.PLAN to ensure JIT directory creation', async () => {
|
||||
const invocation = tool.build({});
|
||||
|
||||
await invocation.execute({ abortSignal: new AbortController().signal });
|
||||
|
||||
expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(
|
||||
ApprovalMode.PLAN,
|
||||
);
|
||||
expect(mockConfig.getPlansDir).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should include optional reason in output display but not in llmContent', async () => {
|
||||
const reason = 'Design new database schema';
|
||||
const invocation = tool.build({ reason });
|
||||
|
||||
@@ -19,6 +19,7 @@ import { ENTER_PLAN_MODE_TOOL_NAME } from './tool-names.js';
|
||||
import { ApprovalMode } from '../policy/types.js';
|
||||
import { ENTER_PLAN_MODE_DEFINITION } from './definitions/coreTools.js';
|
||||
import { resolveToolDeclaration } from './definitions/resolver.js';
|
||||
import { debugLogger } from '../utils/debugLogger.js';
|
||||
|
||||
export interface EnterPlanModeParams {
|
||||
reason?: string;
|
||||
@@ -123,6 +124,18 @@ export class EnterPlanModeInvocation extends BaseToolInvocation<
|
||||
|
||||
this.config.setApprovalMode(ApprovalMode.PLAN);
|
||||
|
||||
// Trigger JIT provisioning immediately. In sandboxed environments,
|
||||
// the plans directory must exist on the host before it can be bound/allowed.
|
||||
try {
|
||||
this.config.getPlansDir();
|
||||
} catch (e) {
|
||||
// Log error but don't fail; write_file will try again later if possible
|
||||
debugLogger.error(
|
||||
'Failed to create plans directory during initialization.',
|
||||
e,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
llmContent: 'Switching to Plan mode.',
|
||||
returnDisplay: this.params.reason
|
||||
|
||||
Reference in New Issue
Block a user