Skip to content

Commit dc2f094

Browse files
cruzanstxclaude
andcommitted
fix(cli): prevent root rejection when using canCallTool with bypassPermissions
When running as root, Claude Code rejects --dangerously-skip-permissions (mapped from --permission-mode bypassPermissions). Since canCallTool already handles permission auto-approval via --permission-prompt-tool stdio, skip passing the redundant --permission-mode flag in that case. Also fixes abort error being overwritten by exit code error (else-if), captures stderr via logDebug for diagnostics, improves error logging in remote launcher, and falls back to first online machine in sync engine. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c868204 commit dc2f094

File tree

3 files changed

+10
-15
lines changed

3 files changed

+10
-15
lines changed

cli/src/claude/claudeRemoteLauncher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ class ClaudeRemoteLauncher extends RemoteLauncherBase {
361361
session.client.sendSessionEvent({ type: 'message', message: 'Aborted by user' });
362362
}
363363
} catch (e) {
364-
logger.debug('[remote]: launch error', e);
364+
logger.debug('[remote]: launch error', e instanceof Error ? `${e.name}: ${e.message}\n${e.stack}` : JSON.stringify(e));
365365
if (!this.exitReason) {
366366
session.client.sendSessionEvent({ type: 'message', message: 'Process exited unexpectedly' });
367367
continue;

cli/src/claude/sdk/query.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,9 @@ export function query(config: {
307307
if (disallowedTools.length > 0) args.push('--disallowedTools', disallowedTools.join(','))
308308
if (additionalDirectories.length > 0) args.push('--add-dir', ...additionalDirectories)
309309
if (strictMcpConfig) args.push('--strict-mcp-config')
310-
if (permissionMode) args.push('--permission-mode', permissionMode)
310+
if (permissionMode && !(canCallTool && permissionMode === 'bypassPermissions')) {
311+
args.push('--permission-mode', permissionMode)
312+
}
311313

312314
if (fallbackModel) {
313315
if (model && fallbackModel === model) {
@@ -361,12 +363,10 @@ export function query(config: {
361363
childStdin = child.stdin
362364
}
363365

364-
// Handle stderr in debug mode
365-
if (process.env.DEBUG) {
366-
child.stderr.on('data', (data) => {
367-
console.error('Claude Code stderr:', data.toString())
368-
})
369-
}
366+
// Handle stderr - always capture for diagnostics
367+
child.stderr.on('data', (data) => {
368+
logDebug('Claude Code stderr: ' + data.toString())
369+
})
370370

371371
// Setup cleanup
372372
const cleanup = () => {
@@ -383,8 +383,7 @@ export function query(config: {
383383
child.on('close', (code) => {
384384
if (config.options?.abort?.aborted) {
385385
query.setError(new AbortError('Claude Code process aborted by user'))
386-
}
387-
if (code !== 0) {
386+
} else if (code !== 0) {
388387
query.setError(new Error(`Claude Code process exited with code ${code}`))
389388
} else {
390389
resolve()

hub/src/sync/syncEngine.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,9 @@ export class SyncEngine {
359359
const hostMatch = onlineMachines.find((machine) => machine.metadata?.host === metadata.host)
360360
if (hostMatch) return hostMatch
361361
}
362-
return null
362+
return onlineMachines[0]
363363
})()
364364

365-
if (!targetMachine) {
366-
return { type: 'error', message: 'No machine online', code: 'no_machine_online' }
367-
}
368-
369365
const spawnResult = await this.rpcGateway.spawnSession(
370366
targetMachine.id,
371367
metadata.path,

0 commit comments

Comments
 (0)