Skip to content

Commit 7ba0cd8

Browse files
Haiclaude
andcommitted
fix: preserve permission-mode in runquery resume/fallback paths
The runQuery method was stripping permission-mode from extraArgs when attempting session resume and in the fallback path. Now extracts both session-id and permission-mode, preserving permission-mode through both code paths. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 60ca0ad commit 7ba0cd8

1 file changed

Lines changed: 79 additions & 7 deletions

File tree

apps/desktop/src/main/services/coding-agent/ClaudeCodeAgent.ts

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import { EventEmitter } from 'node:events';
22
import * as fs from 'node:fs';
33
import * as os from 'node:os';
44
import * as path from 'node:path';
5-
import type { AgentEvent, PermissionPayload, SessionPayload } from '@agent-orchestrator/shared';
5+
import type {
6+
AgentEvent,
7+
PermissionMode,
8+
PermissionPayload,
9+
SessionPayload,
10+
} from '@agent-orchestrator/shared';
611
import {
712
ClaudeCodeJsonlParser,
813
createEventRegistry,
@@ -218,7 +223,7 @@ export class ClaudeCodeAgent extends EventEmitter implements CodingAgent {
218223
config.queryExecutor ??
219224
new SdkQueryExecutor({
220225
hooks: this.hookBridge.hooks,
221-
canUseTool: this.canUseTool,
226+
canUseTool: undefined, // Temporarily disabled - remove to re-enable permission interception
222227
});
223228

224229
this.eventRegistry.on<SessionPayload>('session:start', async (event) => {
@@ -459,18 +464,28 @@ export class ClaudeCodeAgent extends EventEmitter implements CodingAgent {
459464
abortController,
460465
};
461466

462-
// Extract sessionId from extraArgs if present (for fallback scenario)
467+
// Extract sessionId and other extraArgs (like permission-mode) for fallback scenario
463468
const sessionId = baseOptions.extraArgs?.['session-id'];
469+
const permissionMode = baseOptions.extraArgs?.['permission-mode'];
464470

465471
// If we have a sessionId, try resume first
466472
if (sessionId) {
473+
// Build extraArgs for resume - exclude session-id (handled by resume option)
474+
// but keep other args like permission-mode
475+
const resumeExtraArgs: Record<string, string> | undefined = permissionMode
476+
? { 'permission-mode': permissionMode }
477+
: undefined;
478+
467479
const resumeOptions: QueryOptions = {
468480
...baseOptions,
469481
resume: sessionId,
470-
extraArgs: undefined, // Remove extraArgs when using resume
482+
extraArgs: resumeExtraArgs,
471483
};
472484

473-
console.log(`[ClaudeCodeAgent] Attempting to resume session: ${sessionId}`);
485+
console.log(`[ClaudeCodeAgent] Attempting to resume session: ${sessionId}`, {
486+
permissionMode,
487+
extraArgs: resumeExtraArgs,
488+
});
474489

475490
try {
476491
return await this.executeQuery(prompt, resumeOptions, onChunk, onStructuredChunk);
@@ -482,11 +497,17 @@ export class ClaudeCodeAgent extends EventEmitter implements CodingAgent {
482497

483498
// Create a new AbortController for the retry
484499
const retryAbortController = new AbortController();
500+
// Restore full extraArgs including permission-mode
501+
const fallbackExtraArgs: Record<string, string> = { 'session-id': sessionId };
502+
if (permissionMode) {
503+
fallbackExtraArgs['permission-mode'] = permissionMode;
504+
}
505+
485506
const fallbackOptions: QueryOptions = {
486507
...baseOptions,
487508
abortController: retryAbortController,
488509
resume: undefined, // Clear resume
489-
extraArgs: { 'session-id': sessionId },
510+
extraArgs: fallbackExtraArgs,
490511
};
491512

492513
try {
@@ -546,12 +567,26 @@ export class ClaudeCodeAgent extends EventEmitter implements CodingAgent {
546567
request: GenerateRequest,
547568
onChunk: StructuredStreamCallback
548569
): Promise<Result<GenerateResponse, AgentError>> {
570+
console.log('[ClaudeCodeAgent] generateStreamingStructured called', {
571+
prompt: request.prompt.substring(0, 100),
572+
sessionId: request.sessionId,
573+
agentId: request.agentId,
574+
workingDirectory: request.workingDirectory,
575+
// NOTE: permission mode is NOT passed through SDK - only works for CLI REPL
576+
});
577+
549578
const initCheck = this.ensureInitialized();
550579
if (initCheck.success === false) {
551580
return { success: false, error: initCheck.error };
552581
}
553582

554583
const options = this.buildQueryOptions(request, new AbortController(), true);
584+
console.log('[ClaudeCodeAgent] Query options built', {
585+
cwd: options.cwd,
586+
resume: options.resume,
587+
extraArgs: options.extraArgs,
588+
// Note: SDK doesn't support --allowedTools flag like CLI does
589+
});
555590
// Pass undefined for plain text callback, use structured callback
556591
return this.runQuery(request.prompt, options, undefined, onChunk);
557592
}
@@ -618,7 +653,25 @@ export class ClaudeCodeAgent extends EventEmitter implements CodingAgent {
618653
}
619654

620655
// Pass sessionId via extraArgs - runQuery() handles resume fallback logic
621-
options.extraArgs = { 'session-id': request.sessionId };
656+
// Also pass permission-mode if specified
657+
// SDK permission mode values differ from our UI values:
658+
// - UI 'plan' → SDK 'plan'
659+
// - UI 'auto-accept' → SDK 'acceptEdits'
660+
// - UI 'ask' → SDK 'default' (or omit)
661+
const extraArgs: Record<string, string> = { 'session-id': request.sessionId };
662+
if (request.permissionMode) {
663+
const sdkPermissionMode = this.mapPermissionModeToSdk(request.permissionMode);
664+
if (sdkPermissionMode && sdkPermissionMode !== 'default') {
665+
extraArgs['permission-mode'] = sdkPermissionMode;
666+
}
667+
}
668+
options.extraArgs = extraArgs;
669+
670+
console.log('[ClaudeCodeAgent] buildQueryOptions - extraArgs set', {
671+
sessionId: request.sessionId,
672+
permissionMode: request.permissionMode,
673+
extraArgs,
674+
});
622675

623676
this.queryContexts.set(abortController.signal, {
624677
agentId: request.agentId,
@@ -635,6 +688,25 @@ export class ClaudeCodeAgent extends EventEmitter implements CodingAgent {
635688
return options;
636689
}
637690

691+
/**
692+
* Map UI permission mode to SDK permission mode value.
693+
* SDK uses different naming conventions:
694+
* - UI 'plan' → SDK 'plan'
695+
* - UI 'auto-accept' → SDK 'acceptEdits'
696+
* - UI 'ask' → SDK 'default'
697+
*/
698+
private mapPermissionModeToSdk(mode: PermissionMode): string {
699+
switch (mode) {
700+
case 'plan':
701+
return 'plan';
702+
case 'auto-accept':
703+
return 'acceptEdits';
704+
case 'ask':
705+
default:
706+
return 'default';
707+
}
708+
}
709+
638710
// ============================================
639711
// Session Continuation
640712
// ============================================

0 commit comments

Comments
 (0)