mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 15:09:42 +02:00
fix: respect Claude CLI startup mode setting (#12)
The "Startup Mode" setting (normal/bypass/allowedTools) was saved to settings but never read when spawning sessions. All code paths had --dangerously-skip-permissions hardcoded. Now reads claudeMode from ~/.claudeman/settings.json and passes it through Session → TmuxManager. Closes #12 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+31
-4
@@ -30,7 +30,7 @@ import { existsSync, readFileSync, mkdirSync } from 'node:fs';
|
||||
import { writeFile, rename } from 'node:fs/promises';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { homedir } from 'node:os';
|
||||
import { ProcessStats, PersistedRespawnConfig, getErrorMessage, NiceConfig, DEFAULT_NICE_CONFIG, type PaneInfo } from './types.js';
|
||||
import { ProcessStats, PersistedRespawnConfig, getErrorMessage, NiceConfig, DEFAULT_NICE_CONFIG, type PaneInfo, type ClaudeMode } from './types.js';
|
||||
import { wrapWithNice } from './utils/nice-wrapper.js';
|
||||
import { SAFE_PATH_PATTERN } from './utils/regex-patterns.js';
|
||||
import type { TerminalMultiplexer, MuxSession, MuxSessionWithStats } from './mux-interface.js';
|
||||
@@ -111,6 +111,31 @@ function isValidPath(path: string): boolean {
|
||||
return SAFE_PATH_PATTERN.test(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Claude CLI permission flags for the tmux command string.
|
||||
* Validates allowedTools to prevent command injection.
|
||||
*/
|
||||
function buildClaudePermissionFlags(claudeMode?: ClaudeMode, allowedTools?: string): string {
|
||||
const mode = claudeMode || 'dangerously-skip-permissions';
|
||||
switch (mode) {
|
||||
case 'dangerously-skip-permissions':
|
||||
return ' --dangerously-skip-permissions';
|
||||
case 'allowedTools':
|
||||
if (allowedTools) {
|
||||
// Sanitize: allow tool names with patterns like Bash(git:*), space/comma-separated
|
||||
// Block shell metacharacters: ; & | $ ` \ { } < > ' " newlines
|
||||
const hasDangerousChars = /[;&|$`\\{}<>'"[\]\n\r]/.test(allowedTools);
|
||||
if (!hasDangerousChars) {
|
||||
return ` --allowedTools "${allowedTools}"`;
|
||||
}
|
||||
}
|
||||
// Fall back to normal mode if tools are invalid or missing
|
||||
return '';
|
||||
case 'normal':
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages tmux sessions that wrap Claude CLI or shell processes.
|
||||
*
|
||||
@@ -204,6 +229,8 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
name?: string,
|
||||
niceConfig?: NiceConfig,
|
||||
model?: string,
|
||||
claudeMode?: ClaudeMode,
|
||||
allowedTools?: string,
|
||||
): Promise<MuxSession> {
|
||||
const muxName = `claudeman-${sessionId.slice(0, 8)}`;
|
||||
|
||||
@@ -250,7 +277,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
const safeModel = (model && /^[a-zA-Z0-9._-]+$/.test(model)) ? model : undefined;
|
||||
const modelFlag = (mode === 'claude' && safeModel) ? ` --model ${safeModel}` : '';
|
||||
const baseCmd = mode === 'claude'
|
||||
? `claude --dangerously-skip-permissions --session-id "${sessionId}"${modelFlag}`
|
||||
? `claude${buildClaudePermissionFlags(claudeMode, allowedTools)} --session-id "${sessionId}"${modelFlag}`
|
||||
: '$SHELL';
|
||||
|
||||
const config = niceConfig || DEFAULT_NICE_CONFIG;
|
||||
@@ -394,7 +421,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
* Uses `tmux respawn-pane -k` to restart the command in the same pane,
|
||||
* preserving the session and its scrollback buffer.
|
||||
*/
|
||||
async respawnPane(sessionId: string, workingDir: string, mode: 'claude' | 'shell', niceConfig?: NiceConfig, model?: string): Promise<number | null> {
|
||||
async respawnPane(sessionId: string, workingDir: string, mode: 'claude' | 'shell', niceConfig?: NiceConfig, model?: string, claudeMode?: ClaudeMode, allowedTools?: string): Promise<number | null> {
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session) return null;
|
||||
const muxName = session.muxName;
|
||||
@@ -415,7 +442,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
const safeModel = (model && /^[a-zA-Z0-9._-]+$/.test(model)) ? model : undefined;
|
||||
const modelFlag = (mode === 'claude' && safeModel) ? ` --model ${safeModel}` : '';
|
||||
const baseCmd = mode === 'claude'
|
||||
? `claude --dangerously-skip-permissions --session-id "${sessionId}"${modelFlag}`
|
||||
? `claude${buildClaudePermissionFlags(claudeMode, allowedTools)} --session-id "${sessionId}"${modelFlag}`
|
||||
: '$SHELL';
|
||||
|
||||
const config = niceConfig || DEFAULT_NICE_CONFIG;
|
||||
|
||||
Reference in New Issue
Block a user