feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions (#1016)
* feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions Add a toggle in Developer Tools settings that enables "YOLO Mode" which starts Claude with the --dangerously-skip-permissions flag, bypassing all safety prompts. Changes: - Add dangerouslySkipPermissions setting to AppSettings interface - Add translation keys for YOLO mode (en/fr) - Modify claude-integration-handler to accept and append extra flags - Update terminal-manager and terminal-handlers to read and forward the setting - Add Switch toggle with warning styling in DevToolsSettings UI The toggle includes visual warnings (amber colors, AlertTriangle icon) to clearly indicate this is a dangerous option that bypasses Claude's permission system. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(terminal): address PR review issues for YOLO mode implementation - Add async readSettingsFileAsync to avoid blocking main process during settings read - Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings - Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches - Update switchClaudeProfile callback to pass stored YOLO mode setting These fixes address: - LOW: Synchronous file I/O in IPC handler - LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync - MEDIUM: YOLO mode not persisting when switching Claude profiles Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ import { terminalNameGenerator } from '../terminal-name-generator';
|
||||
import { debugLog, debugError } from '../../shared/utils/debug-logger';
|
||||
import { escapeShellArg, escapeShellArgWindows } from '../../shared/utils/shell-escape';
|
||||
import { getClaudeCliInvocationAsync } from '../claude-cli-utils';
|
||||
import { readSettingsFileAsync } from '../settings-utils';
|
||||
|
||||
|
||||
/**
|
||||
@@ -54,8 +55,17 @@ export function registerTerminalHandlers(
|
||||
ipcMain.on(
|
||||
IPC_CHANNELS.TERMINAL_INVOKE_CLAUDE,
|
||||
(_, id: string, cwd?: string) => {
|
||||
// Use async version to avoid blocking main process during CLI detection
|
||||
terminalManager.invokeClaudeAsync(id, cwd).catch((error) => {
|
||||
// Wrap in async IIFE to allow async settings read without blocking
|
||||
(async () => {
|
||||
// Read settings asynchronously to check for YOLO mode (dangerously skip permissions)
|
||||
const settings = await readSettingsFileAsync();
|
||||
const dangerouslySkipPermissions = settings?.dangerouslySkipPermissions === true;
|
||||
|
||||
debugLog('[terminal-handlers] Invoking Claude with dangerouslySkipPermissions:', dangerouslySkipPermissions);
|
||||
|
||||
// Use async version to avoid blocking main process during CLI detection
|
||||
await terminalManager.invokeClaudeAsync(id, cwd, undefined, dangerouslySkipPermissions);
|
||||
})().catch((error) => {
|
||||
debugError('[terminal-handlers] Failed to invoke Claude:', error);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
import { app } from 'electron';
|
||||
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
||||
import { promises as fsPromises } from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
@@ -58,3 +59,31 @@ export function writeSettingsFile(settings: Record<string, unknown>): void {
|
||||
|
||||
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse settings from disk asynchronously.
|
||||
* Returns the raw parsed settings object, or undefined if the file doesn't exist or fails to parse.
|
||||
*
|
||||
* This is the non-blocking version of readSettingsFile, safe to use in Electron main process
|
||||
* without blocking the event loop.
|
||||
*
|
||||
* This function does NOT merge with defaults or perform any migrations.
|
||||
* Callers are responsible for merging with DEFAULT_APP_SETTINGS.
|
||||
*/
|
||||
export async function readSettingsFileAsync(): Promise<Record<string, unknown> | undefined> {
|
||||
const settingsPath = getSettingsPath();
|
||||
|
||||
try {
|
||||
await fsPromises.access(settingsPath);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
try {
|
||||
const content = await fsPromises.readFile(settingsPath, 'utf-8');
|
||||
return JSON.parse(content);
|
||||
} catch {
|
||||
// Return undefined on parse error - caller will use defaults
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ function normalizePathForBash(envPath: string): string {
|
||||
return process.platform === 'win32' ? envPath.replace(/;/g, ':') : envPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag for YOLO mode (skip all permission prompts)
|
||||
* Extracted as constant to ensure consistency across invokeClaude and invokeClaudeAsync
|
||||
*/
|
||||
const YOLO_MODE_FLAG = ' --dangerously-skip-permissions';
|
||||
|
||||
// ============================================================================
|
||||
// SHARED HELPERS - Used by both sync and async invokeClaude
|
||||
// ============================================================================
|
||||
@@ -54,6 +60,7 @@ type ClaudeCommandConfig =
|
||||
* @param pathPrefix - PATH prefix for Claude CLI (empty string if not needed)
|
||||
* @param escapedClaudeCmd - Shell-escaped Claude CLI command
|
||||
* @param config - Configuration object with method and required options (discriminated union)
|
||||
* @param extraFlags - Optional extra flags to append to the command (e.g., '--dangerously-skip-permissions')
|
||||
* @returns Complete shell command string ready for terminal.pty.write()
|
||||
*
|
||||
* @example
|
||||
@@ -69,17 +76,19 @@ export function buildClaudeShellCommand(
|
||||
cwdCommand: string,
|
||||
pathPrefix: string,
|
||||
escapedClaudeCmd: string,
|
||||
config: ClaudeCommandConfig
|
||||
config: ClaudeCommandConfig,
|
||||
extraFlags?: string
|
||||
): string {
|
||||
const fullCmd = extraFlags ? `${escapedClaudeCmd}${extraFlags}` : escapedClaudeCmd;
|
||||
switch (config.method) {
|
||||
case 'temp-file':
|
||||
return `clear && ${cwdCommand}HISTFILE= HISTCONTROL=ignorespace ${pathPrefix}bash -c "source ${config.escapedTempFile} && rm -f ${config.escapedTempFile} && exec ${escapedClaudeCmd}"\r`;
|
||||
return `clear && ${cwdCommand}HISTFILE= HISTCONTROL=ignorespace ${pathPrefix}bash -c "source ${config.escapedTempFile} && rm -f ${config.escapedTempFile} && exec ${fullCmd}"\r`;
|
||||
|
||||
case 'config-dir':
|
||||
return `clear && ${cwdCommand}HISTFILE= HISTCONTROL=ignorespace CLAUDE_CONFIG_DIR=${config.escapedConfigDir} ${pathPrefix}bash -c "exec ${escapedClaudeCmd}"\r`;
|
||||
return `clear && ${cwdCommand}HISTFILE= HISTCONTROL=ignorespace CLAUDE_CONFIG_DIR=${config.escapedConfigDir} ${pathPrefix}bash -c "exec ${fullCmd}"\r`;
|
||||
|
||||
default:
|
||||
return `${cwdCommand}${pathPrefix}${escapedClaudeCmd}\r`;
|
||||
return `${cwdCommand}${pathPrefix}${fullCmd}\r`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,14 +380,21 @@ export function invokeClaude(
|
||||
cwd: string | undefined,
|
||||
profileId: string | undefined,
|
||||
getWindow: WindowGetter,
|
||||
onSessionCapture: (terminalId: string, projectPath: string, startTime: number) => void
|
||||
onSessionCapture: (terminalId: string, projectPath: string, startTime: number) => void,
|
||||
dangerouslySkipPermissions?: boolean
|
||||
): void {
|
||||
debugLog('[ClaudeIntegration:invokeClaude] ========== INVOKE CLAUDE START ==========');
|
||||
debugLog('[ClaudeIntegration:invokeClaude] Terminal ID:', terminal.id);
|
||||
debugLog('[ClaudeIntegration:invokeClaude] Requested profile ID:', profileId);
|
||||
debugLog('[ClaudeIntegration:invokeClaude] CWD:', cwd);
|
||||
debugLog('[ClaudeIntegration:invokeClaude] Dangerously skip permissions:', dangerouslySkipPermissions);
|
||||
|
||||
// Compute extra flags for YOLO mode
|
||||
const extraFlags = dangerouslySkipPermissions ? YOLO_MODE_FLAG : undefined;
|
||||
|
||||
terminal.isClaudeMode = true;
|
||||
// Store YOLO mode setting so it persists across profile switches
|
||||
terminal.dangerouslySkipPermissions = dangerouslySkipPermissions;
|
||||
SessionHandler.releaseSessionId(terminal.id);
|
||||
terminal.claudeSessionId = undefined;
|
||||
|
||||
@@ -433,7 +449,7 @@ export function invokeClaude(
|
||||
{ mode: 0o600 }
|
||||
);
|
||||
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'temp-file', escapedTempFile });
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'temp-file', escapedTempFile }, extraFlags);
|
||||
debugLog('[ClaudeIntegration:invokeClaude] Executing command (temp file method, history-safe)');
|
||||
terminal.pty.write(command);
|
||||
profileManager.markProfileUsed(activeProfile.id);
|
||||
@@ -442,7 +458,7 @@ export function invokeClaude(
|
||||
return;
|
||||
} else if (activeProfile.configDir) {
|
||||
const escapedConfigDir = escapeShellArg(activeProfile.configDir);
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'config-dir', escapedConfigDir });
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'config-dir', escapedConfigDir }, extraFlags);
|
||||
debugLog('[ClaudeIntegration:invokeClaude] Executing command (configDir method, history-safe)');
|
||||
terminal.pty.write(command);
|
||||
profileManager.markProfileUsed(activeProfile.id);
|
||||
@@ -458,7 +474,7 @@ export function invokeClaude(
|
||||
debugLog('[ClaudeIntegration:invokeClaude] Using terminal environment for non-default profile:', activeProfile.name);
|
||||
}
|
||||
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'default' });
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'default' }, extraFlags);
|
||||
debugLog('[ClaudeIntegration:invokeClaude] Executing command (default method):', command);
|
||||
terminal.pty.write(command);
|
||||
|
||||
@@ -540,14 +556,21 @@ export async function invokeClaudeAsync(
|
||||
cwd: string | undefined,
|
||||
profileId: string | undefined,
|
||||
getWindow: WindowGetter,
|
||||
onSessionCapture: (terminalId: string, projectPath: string, startTime: number) => void
|
||||
onSessionCapture: (terminalId: string, projectPath: string, startTime: number) => void,
|
||||
dangerouslySkipPermissions?: boolean
|
||||
): Promise<void> {
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] ========== INVOKE CLAUDE START (async) ==========');
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] Terminal ID:', terminal.id);
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] Requested profile ID:', profileId);
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] CWD:', cwd);
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] Dangerously skip permissions:', dangerouslySkipPermissions);
|
||||
|
||||
// Compute extra flags for YOLO mode
|
||||
const extraFlags = dangerouslySkipPermissions ? YOLO_MODE_FLAG : undefined;
|
||||
|
||||
terminal.isClaudeMode = true;
|
||||
// Store YOLO mode setting so it persists across profile switches
|
||||
terminal.dangerouslySkipPermissions = dangerouslySkipPermissions;
|
||||
SessionHandler.releaseSessionId(terminal.id);
|
||||
terminal.claudeSessionId = undefined;
|
||||
|
||||
@@ -604,7 +627,7 @@ export async function invokeClaudeAsync(
|
||||
{ mode: 0o600 }
|
||||
);
|
||||
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'temp-file', escapedTempFile });
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'temp-file', escapedTempFile }, extraFlags);
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] Executing command (temp file method, history-safe)');
|
||||
terminal.pty.write(command);
|
||||
profileManager.markProfileUsed(activeProfile.id);
|
||||
@@ -613,7 +636,7 @@ export async function invokeClaudeAsync(
|
||||
return;
|
||||
} else if (activeProfile.configDir) {
|
||||
const escapedConfigDir = escapeShellArg(activeProfile.configDir);
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'config-dir', escapedConfigDir });
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'config-dir', escapedConfigDir }, extraFlags);
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] Executing command (configDir method, history-safe)');
|
||||
terminal.pty.write(command);
|
||||
profileManager.markProfileUsed(activeProfile.id);
|
||||
@@ -629,7 +652,7 @@ export async function invokeClaudeAsync(
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] Using terminal environment for non-default profile:', activeProfile.name);
|
||||
}
|
||||
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'default' });
|
||||
const command = buildClaudeShellCommand(cwdCommand, pathPrefix, escapedClaudeCmd, { method: 'default' }, extraFlags);
|
||||
debugLog('[ClaudeIntegration:invokeClaudeAsync] Executing command (default method):', command);
|
||||
terminal.pty.write(command);
|
||||
|
||||
@@ -794,7 +817,7 @@ export async function switchClaudeProfile(
|
||||
terminal: TerminalProcess,
|
||||
profileId: string,
|
||||
getWindow: WindowGetter,
|
||||
invokeClaudeCallback: (terminalId: string, cwd: string | undefined, profileId: string) => Promise<void>,
|
||||
invokeClaudeCallback: (terminalId: string, cwd: string | undefined, profileId: string, dangerouslySkipPermissions?: boolean) => Promise<void>,
|
||||
clearRateLimitCallback: (terminalId: string) => void
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
// Always-on tracing
|
||||
@@ -875,13 +898,15 @@ export async function switchClaudeProfile(
|
||||
clearRateLimitCallback(terminal.id);
|
||||
|
||||
const projectPath = terminal.projectPath || terminal.cwd;
|
||||
console.warn('[ClaudeIntegration:switchClaudeProfile] Invoking Claude with profile:', profileId, '| cwd:', projectPath);
|
||||
console.warn('[ClaudeIntegration:switchClaudeProfile] Invoking Claude with profile:', profileId, '| cwd:', projectPath, '| YOLO:', terminal.dangerouslySkipPermissions);
|
||||
debugLog('[ClaudeIntegration:switchClaudeProfile] Invoking Claude with new profile:', {
|
||||
terminalId: terminal.id,
|
||||
projectPath,
|
||||
profileId
|
||||
profileId,
|
||||
dangerouslySkipPermissions: terminal.dangerouslySkipPermissions
|
||||
});
|
||||
await invokeClaudeCallback(terminal.id, projectPath, profileId);
|
||||
// Pass the stored dangerouslySkipPermissions value to preserve YOLO mode across profile switches
|
||||
await invokeClaudeCallback(terminal.id, projectPath, profileId, terminal.dangerouslySkipPermissions);
|
||||
|
||||
debugLog('[ClaudeIntegration:switchClaudeProfile] Setting active profile in profile manager');
|
||||
profileManager.setActiveProfile(profileId);
|
||||
|
||||
@@ -145,7 +145,7 @@ export class TerminalManager {
|
||||
/**
|
||||
* Invoke Claude in a terminal with optional profile override (async - non-blocking)
|
||||
*/
|
||||
async invokeClaudeAsync(id: string, cwd?: string, profileId?: string): Promise<void> {
|
||||
async invokeClaudeAsync(id: string, cwd?: string, profileId?: string, dangerouslySkipPermissions?: boolean): Promise<void> {
|
||||
const terminal = this.terminals.get(id);
|
||||
if (!terminal) {
|
||||
return;
|
||||
@@ -164,7 +164,8 @@ export class TerminalManager {
|
||||
this.terminals,
|
||||
this.getWindow
|
||||
);
|
||||
}
|
||||
},
|
||||
dangerouslySkipPermissions
|
||||
);
|
||||
}
|
||||
|
||||
@@ -172,7 +173,7 @@ export class TerminalManager {
|
||||
* Invoke Claude in a terminal with optional profile override
|
||||
* @deprecated Use invokeClaudeAsync for non-blocking behavior
|
||||
*/
|
||||
invokeClaude(id: string, cwd?: string, profileId?: string): void {
|
||||
invokeClaude(id: string, cwd?: string, profileId?: string, dangerouslySkipPermissions?: boolean): void {
|
||||
const terminal = this.terminals.get(id);
|
||||
if (!terminal) {
|
||||
return;
|
||||
@@ -191,7 +192,8 @@ export class TerminalManager {
|
||||
this.terminals,
|
||||
this.getWindow
|
||||
);
|
||||
}
|
||||
},
|
||||
dangerouslySkipPermissions
|
||||
);
|
||||
}
|
||||
|
||||
@@ -208,7 +210,7 @@ export class TerminalManager {
|
||||
terminal,
|
||||
profileId,
|
||||
this.getWindow,
|
||||
async (terminalId, cwd, profileId) => this.invokeClaudeAsync(terminalId, cwd, profileId),
|
||||
async (terminalId, cwd, profileId, dangerouslySkipPermissions) => this.invokeClaudeAsync(terminalId, cwd, profileId, dangerouslySkipPermissions),
|
||||
(terminalId) => this.lastNotifiedRateLimitReset.delete(terminalId)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ export interface TerminalProcess {
|
||||
worktreeConfig?: TerminalWorktreeConfig;
|
||||
/** Whether this terminal has a pending Claude resume that should be triggered on activation */
|
||||
pendingClaudeResume?: boolean;
|
||||
/** Whether Claude was invoked with --dangerously-skip-permissions (YOLO mode) */
|
||||
dangerouslySkipPermissions?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Code, Terminal, RefreshCw, Loader2, Check, FolderOpen } from 'lucide-react';
|
||||
import { Code, Terminal, RefreshCw, Loader2, Check, FolderOpen, AlertTriangle } from 'lucide-react';
|
||||
import { Label } from '../ui/label';
|
||||
import { Input } from '../ui/input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select';
|
||||
import { Button } from '../ui/button';
|
||||
import { Switch } from '../ui/switch';
|
||||
import { SettingsSection } from './SettingsSection';
|
||||
import type { AppSettings, SupportedIDE, SupportedTerminal } from '../../../shared/types';
|
||||
|
||||
@@ -364,6 +365,37 @@ export function DevToolsSettings({ settings, onSettingsChange }: DevToolsSetting
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* YOLO Mode Toggle */}
|
||||
<div className="space-y-3 rounded-md border border-amber-500/30 bg-amber-500/5 p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<AlertTriangle className="h-4 w-4 text-amber-500" />
|
||||
<Label htmlFor="yolo-mode" className="text-amber-200">
|
||||
{t('devtools.yoloMode.label', 'YOLO Mode')}
|
||||
</Label>
|
||||
</div>
|
||||
<Switch
|
||||
id="yolo-mode"
|
||||
checked={settings.dangerouslySkipPermissions ?? false}
|
||||
onCheckedChange={(checked) => {
|
||||
onSettingsChange({
|
||||
...settings,
|
||||
dangerouslySkipPermissions: checked
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<p className="text-xs text-amber-400/80">
|
||||
{t('devtools.yoloMode.description', 'Start Claude with --dangerously-skip-permissions flag, bypassing all safety prompts. Use with extreme caution.')}
|
||||
</p>
|
||||
{settings.dangerouslySkipPermissions && (
|
||||
<p className="text-xs text-amber-500 font-medium flex items-center gap-1">
|
||||
<AlertTriangle className="h-3 w-3" />
|
||||
{t('devtools.yoloMode.warning', 'This mode bypasses Claude\'s permission system. Only enable if you fully trust the code being executed.')}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Detection Summary */}
|
||||
{detectedTools && !isDetecting && (
|
||||
<div className="text-xs text-muted-foreground bg-muted/50 p-3 rounded-md">
|
||||
|
||||
@@ -261,7 +261,12 @@
|
||||
"detected": "Detected",
|
||||
"notInstalled": "Not installed",
|
||||
"detectedSummary": "Detected on your system:",
|
||||
"noToolsDetected": "No additional tools detected (VS Code and system terminal will be used)"
|
||||
"noToolsDetected": "No additional tools detected (VS Code and system terminal will be used)",
|
||||
"yoloMode": {
|
||||
"label": "YOLO Mode",
|
||||
"description": "Start Claude with --dangerously-skip-permissions flag, bypassing all safety prompts. Use with extreme caution.",
|
||||
"warning": "This mode bypasses Claude's permission system. Only enable if you fully trust the code being executed."
|
||||
}
|
||||
},
|
||||
"updates": {
|
||||
"title": "Updates",
|
||||
|
||||
@@ -261,7 +261,12 @@
|
||||
"detected": "Détecté",
|
||||
"notInstalled": "Non installé",
|
||||
"detectedSummary": "Détecté sur votre système :",
|
||||
"noToolsDetected": "Aucun outil supplémentaire détecté (VS Code et le terminal système seront utilisés)"
|
||||
"noToolsDetected": "Aucun outil supplémentaire détecté (VS Code et le terminal système seront utilisés)",
|
||||
"yoloMode": {
|
||||
"label": "Mode YOLO",
|
||||
"description": "Démarrer Claude avec le flag --dangerously-skip-permissions, contournant toutes les invites de sécurité. À utiliser avec une extrême prudence.",
|
||||
"warning": "Ce mode contourne le système de permissions de Claude. N'activez que si vous faites entièrement confiance au code exécuté."
|
||||
}
|
||||
},
|
||||
"updates": {
|
||||
"title": "Mises à jour",
|
||||
|
||||
@@ -279,6 +279,8 @@ export interface AppSettings {
|
||||
customIDEPath?: string; // For 'custom' IDE
|
||||
preferredTerminal?: SupportedTerminal;
|
||||
customTerminalPath?: string; // For 'custom' terminal
|
||||
// YOLO mode: invoke Claude with --dangerously-skip-permissions flag
|
||||
dangerouslySkipPermissions?: boolean;
|
||||
// Anonymous error reporting (Sentry) - enabled by default to help improve the app
|
||||
sentryEnabled?: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user