authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-09-10 23:39:31-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-10 23:39:31-03:00
log5735693d4acb949c2b0daf1219b4f62845115435
tree1e836dc9067be7e1511fc6f60eae482bbd7e387f
parent48654c1182c41dbd5e99ef0d6620a13ba2400f26
signature Signed by PGP key B5690EEEBB952194

fix(server): let Claude launch args override the derived permission mode (#11026)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

2 files changed, 36 insertions(+), 2 deletions(-)

apps/server/src/provider/Layers/ClaudeAdapter.test.ts+23
...@@ -422,6 +422,29 @@ describe("ClaudeAdapterLive", () => {...@@ -422,6 +422,29 @@ describe("ClaudeAdapterLive", () => {
422 );422 );
423 });423 });
424424
425 it.effect("lets a launch-arg permission flag win over the thread runtime mode", () => {
426 const harness = makeHarness({
427 claudeConfig: { launchArgs: "--dangerously-skip-permissions --verbose" },
428 });
429 return Effect.gen(function* () {
430 const adapter = yield* ClaudeAdapter;
431 yield* adapter.startSession({
432 threadId: THREAD_ID,
433 provider: ProviderDriverKind.make("claudeAgent"),
434 runtimeMode: "auto-accept-edits",
435 });
436
437 const createInput = harness.getLastCreateQueryInput();
438 assert.equal(createInput?.options.permissionMode, "bypassPermissions");
439 assert.equal(createInput?.options.allowDangerouslySkipPermissions, true);
440 // The honored flag is dropped from extraArgs so the CLI sees it once.
441 assert.deepEqual(createInput?.options.extraArgs, { verbose: null });
442 }).pipe(
443 Effect.provideService(Random.Random, makeDeterministicRandomService()),
444 Effect.provide(harness.layer),
445 );
446 });
447
425 it.effect("loads Claude filesystem settings sources for SDK sessions", () => {448 it.effect("loads Claude filesystem settings sources for SDK sessions", () => {
426 const harness = makeHarness();449 const harness = makeHarness();
427 return Effect.gen(function* () {450 return Effect.gen(function* () {
apps/server/src/provider/Layers/ClaudeAdapter.ts+13-2
...@@ -4608,7 +4608,11 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (...@@ -4608,7 +4608,11 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
4608 ) => runPromise(handleResumeDialog(request, callbackOptions));4608 ) => runPromise(handleResumeDialog(request, callbackOptions));
46094609
4610 const claudeBinaryPath = claudeSdkExecutablePath;4610 const claudeBinaryPath = claudeSdkExecutablePath;
4611 const extraArgs = parseCliArgs(claudeSettings.launchArgs).flags;4611 const {
4612 "permission-mode": launchArgPermissionMode,
4613 "dangerously-skip-permissions": launchArgSkipPermissions,
4614 ...extraArgs
4615 } = parseCliArgs(claudeSettings.launchArgs).flags;
4612 const selectedModel =4616 const selectedModel =
4613 input.modelSelection?.instanceId === boundInstanceId ? input.modelSelection : undefined;4617 input.modelSelection?.instanceId === boundInstanceId ? input.modelSelection : undefined;
4614 const modelSelection = selectedModel4618 const modelSelection = selectedModel
...@@ -4649,7 +4653,14 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (...@@ -4649,7 +4653,14 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
4649 auto: "auto",4653 auto: "auto",
4650 "full-access": "bypassPermissions",4654 "full-access": "bypassPermissions",
4651 };4655 };
4652 const permissionMode = runtimeModeToPermission[input.runtimeMode];4656 // A permission launch arg is folded into the mode T3 sends rather than
4657 // passed through: the CLI resolves both inputs together, so argv order
4658 // never let the user's flag win.
4659 const permissionMode =
4660 (launchArgPermissionMode as PermissionMode | null | undefined) ??
4661 (launchArgSkipPermissions === null || launchArgSkipPermissions === "true"
4662 ? "bypassPermissions"
4663 : runtimeModeToPermission[input.runtimeMode]);
4653 const settings = {4664 const settings = {
4654 ...(typeof thinking === "boolean" ? { alwaysThinkingEnabled: thinking } : {}),4665 ...(typeof thinking === "boolean" ? { alwaysThinkingEnabled: thinking } : {}),
4655 ...(fastMode ? { fastMode: true } : {}),4666 ...(fastMode ? { fastMode: true } : {}),