init claude-code
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { feature } from 'bun:bundle'
|
||||
import type { ToolPermissionContext } from '../../Tool.js'
|
||||
import { logForDebugging } from '../debug.js'
|
||||
import type { PermissionMode } from './PermissionMode.js'
|
||||
import {
|
||||
getAutoModeUnavailableReason,
|
||||
isAutoModeGateEnabled,
|
||||
transitionPermissionMode,
|
||||
} from './permissionSetup.js'
|
||||
|
||||
// Checks both the cached isAutoModeAvailable (set at startup by
|
||||
// verifyAutoModeGateAccess) and the live isAutoModeGateEnabled() — these can
|
||||
// diverge if the circuit breaker or settings change mid-session. The
|
||||
// live check prevents transitionPermissionMode from throwing
|
||||
// (permissionSetup.ts:~559), which would silently crash the shift+tab handler
|
||||
// and leave the user stuck at the current mode.
|
||||
function canCycleToAuto(ctx: ToolPermissionContext): boolean {
|
||||
if (feature('TRANSCRIPT_CLASSIFIER')) {
|
||||
const gateEnabled = isAutoModeGateEnabled()
|
||||
const can = !!ctx.isAutoModeAvailable && gateEnabled
|
||||
if (!can) {
|
||||
logForDebugging(
|
||||
`[auto-mode] canCycleToAuto=false: ctx.isAutoModeAvailable=${ctx.isAutoModeAvailable} isAutoModeGateEnabled=${gateEnabled} reason=${getAutoModeUnavailableReason()}`,
|
||||
)
|
||||
}
|
||||
return can
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the next permission mode when cycling through modes with Shift+Tab.
|
||||
*/
|
||||
export function getNextPermissionMode(
|
||||
toolPermissionContext: ToolPermissionContext,
|
||||
_teamContext?: { leadAgentId: string },
|
||||
): PermissionMode {
|
||||
switch (toolPermissionContext.mode) {
|
||||
case 'default':
|
||||
// Ants skip acceptEdits and plan — auto mode replaces them
|
||||
if (process.env.USER_TYPE === 'ant') {
|
||||
if (toolPermissionContext.isBypassPermissionsModeAvailable) {
|
||||
return 'bypassPermissions'
|
||||
}
|
||||
if (canCycleToAuto(toolPermissionContext)) {
|
||||
return 'auto'
|
||||
}
|
||||
return 'default'
|
||||
}
|
||||
return 'acceptEdits'
|
||||
|
||||
case 'acceptEdits':
|
||||
return 'plan'
|
||||
|
||||
case 'plan':
|
||||
if (toolPermissionContext.isBypassPermissionsModeAvailable) {
|
||||
return 'bypassPermissions'
|
||||
}
|
||||
if (canCycleToAuto(toolPermissionContext)) {
|
||||
return 'auto'
|
||||
}
|
||||
return 'default'
|
||||
|
||||
case 'bypassPermissions':
|
||||
if (canCycleToAuto(toolPermissionContext)) {
|
||||
return 'auto'
|
||||
}
|
||||
return 'default'
|
||||
|
||||
case 'dontAsk':
|
||||
// Not exposed in UI cycle yet, but return default if somehow reached
|
||||
return 'default'
|
||||
|
||||
|
||||
default:
|
||||
// Covers auto (when TRANSCRIPT_CLASSIFIER is enabled) and any future modes — always fall back to default
|
||||
return 'default'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the next permission mode and prepares the context for it.
|
||||
* Handles any context cleanup needed for the target mode (e.g., stripping
|
||||
* dangerous permissions when entering auto mode).
|
||||
*
|
||||
* @returns The next mode and the context to use (with dangerous permissions stripped if needed)
|
||||
*/
|
||||
export function cyclePermissionMode(
|
||||
toolPermissionContext: ToolPermissionContext,
|
||||
teamContext?: { leadAgentId: string },
|
||||
): { nextMode: PermissionMode; context: ToolPermissionContext } {
|
||||
const nextMode = getNextPermissionMode(toolPermissionContext, teamContext)
|
||||
return {
|
||||
nextMode,
|
||||
context: transitionPermissionMode(
|
||||
toolPermissionContext.mode,
|
||||
nextMode,
|
||||
toolPermissionContext,
|
||||
),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user