Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/core/src/tools/exit-plan-mode.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,26 @@ Ask the user for specific feedback on how to improve the plan.`,
});
});

describe('execute when shouldConfirmExecute is never called', () => {
it('should approve with DEFAULT mode when approvalPayload is null (policy ALLOW skips confirmation)', async () => {
const planRelativePath = createPlanFile('test.md', '# Content');
const invocation = tool.build({ plan_path: planRelativePath });

// Simulate the scheduler's policy ALLOW path: execute() is called
// directly without ever calling shouldConfirmExecute(), leaving
// approvalPayload null.
const result = await invocation.execute(new AbortController().signal);
const expectedPath = path.join(mockPlansDir, 'test.md');

expect(result.llmContent).toContain('Plan approved');
expect(result.returnDisplay).toContain('Plan approved');
expect(mockConfig.setApprovalMode).toHaveBeenCalledWith(
ApprovalMode.DEFAULT,
);
expect(mockConfig.setApprovedPlanPath).toHaveBeenCalledWith(expectedPath);
});
});

describe('getApprovalModeDescription (internal)', () => {
it('should handle all valid approval modes', async () => {
const planRelativePath = createPlanFile('test.md', '# Content');
Expand Down
12 changes: 10 additions & 2 deletions packages/core/src/tools/exit-plan-mode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,16 @@ export class ExitPlanModeInvocation extends BaseToolInvocation<
};
}

const payload = this.approvalPayload;
if (payload?.approved) {
// When a user policy grants `allow` for exit_plan_mode, the scheduler
// skips the confirmation phase entirely and shouldConfirmExecute is never
// called, leaving approvalPayload null. Treat that as an approval with
// the default mode — consistent with the ALLOW branch inside
// shouldConfirmExecute.
const payload = this.approvalPayload ?? {
approved: true,
approvalMode: ApprovalMode.DEFAULT,
};
if (payload.approved) {
const newMode = payload.approvalMode ?? ApprovalMode.DEFAULT;

if (newMode === ApprovalMode.PLAN || newMode === ApprovalMode.YOLO) {
Expand Down
Loading