mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39: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:
@@ -35,7 +35,7 @@ When user says "COM":
|
|||||||
1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version CLAUDE.md`)
|
1. Increment version in BOTH `package.json` AND `CLAUDE.md` (verify they match with `grep version package.json && grep Version CLAUDE.md`)
|
||||||
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
|
2. Run: `git add -A && git commit -m "chore: bump version to X.XXXX" && git push && npm run build && systemctl --user restart claudeman-web`
|
||||||
|
|
||||||
**Version**: 0.1617 (must match `package.json`)
|
**Version**: 0.1618 (must match `package.json`)
|
||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "claudeman",
|
"name": "claudeman",
|
||||||
"version": "0.1617",
|
"version": "0.1618",
|
||||||
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
|
"description": "The missing control plane for Claude Code - run 20 autonomous agents with real-time monitoring and session persistence",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { EventEmitter } from 'node:events';
|
import type { EventEmitter } from 'node:events';
|
||||||
import type { ProcessStats, PersistedRespawnConfig, NiceConfig } from './types.js';
|
import type { ProcessStats, PersistedRespawnConfig, NiceConfig, ClaudeMode } from './types.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Multiplexer session metadata.
|
* Multiplexer session metadata.
|
||||||
@@ -71,6 +71,8 @@ export interface TerminalMultiplexer extends EventEmitter {
|
|||||||
name?: string,
|
name?: string,
|
||||||
niceConfig?: NiceConfig,
|
niceConfig?: NiceConfig,
|
||||||
model?: string,
|
model?: string,
|
||||||
|
claudeMode?: ClaudeMode,
|
||||||
|
allowedTools?: string,
|
||||||
): Promise<MuxSession>;
|
): Promise<MuxSession>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,5 +165,5 @@ export interface TerminalMultiplexer extends EventEmitter {
|
|||||||
isPaneDead(muxName: string): boolean;
|
isPaneDead(muxName: string): boolean;
|
||||||
|
|
||||||
/** Respawn a dead pane with a fresh command. Returns the new PID or null on failure. */
|
/** Respawn a dead pane with a fresh command. Returns the new PID or null on failure. */
|
||||||
respawnPane(sessionId: string, workingDir: string, mode: 'claude' | 'shell', niceConfig?: NiceConfig, model?: string): Promise<number | null>;
|
respawnPane(sessionId: string, workingDir: string, mode: 'claude' | 'shell', niceConfig?: NiceConfig, model?: string, claudeMode?: ClaudeMode, allowedTools?: string): Promise<number | null>;
|
||||||
}
|
}
|
||||||
|
|||||||
+53
-7
@@ -18,7 +18,7 @@
|
|||||||
import { EventEmitter } from 'node:events';
|
import { EventEmitter } from 'node:events';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import * as pty from 'node-pty';
|
import * as pty from 'node-pty';
|
||||||
import { SessionState, SessionStatus, SessionConfig, RalphTrackerState, RalphTodoItem, ActiveBashTool, NiceConfig, DEFAULT_NICE_CONFIG } from './types.js';
|
import { SessionState, SessionStatus, SessionConfig, RalphTrackerState, RalphTodoItem, ActiveBashTool, NiceConfig, DEFAULT_NICE_CONFIG, type ClaudeMode } from './types.js';
|
||||||
import type { TerminalMultiplexer, MuxSession } from './mux-interface.js';
|
import type { TerminalMultiplexer, MuxSession } from './mux-interface.js';
|
||||||
import { TaskTracker, type BackgroundTask } from './task-tracker.js';
|
import { TaskTracker, type BackgroundTask } from './task-tracker.js';
|
||||||
import { RalphTracker } from './ralph-tracker.js';
|
import { RalphTracker } from './ralph-tracker.js';
|
||||||
@@ -321,6 +321,10 @@ export class Session extends EventEmitter {
|
|||||||
// Claude model override (e.g., 'opus', 'sonnet', 'haiku')
|
// Claude model override (e.g., 'opus', 'sonnet', 'haiku')
|
||||||
private _model: string | undefined;
|
private _model: string | undefined;
|
||||||
|
|
||||||
|
// Claude CLI startup permission mode
|
||||||
|
private _claudeMode: ClaudeMode = 'dangerously-skip-permissions';
|
||||||
|
private _allowedTools: string | undefined;
|
||||||
|
|
||||||
// Session color for visual differentiation
|
// Session color for visual differentiation
|
||||||
private _color: import('./types.js').SessionColor = 'default';
|
private _color: import('./types.js').SessionColor = 'default';
|
||||||
|
|
||||||
@@ -374,6 +378,10 @@ export class Session extends EventEmitter {
|
|||||||
niceConfig?: NiceConfig; // Nice prioritying configuration
|
niceConfig?: NiceConfig; // Nice prioritying configuration
|
||||||
/** Claude model override (e.g., 'opus', 'sonnet', 'haiku') */
|
/** Claude model override (e.g., 'opus', 'sonnet', 'haiku') */
|
||||||
model?: string;
|
model?: string;
|
||||||
|
/** Claude CLI startup permission mode */
|
||||||
|
claudeMode?: ClaudeMode;
|
||||||
|
/** Comma-separated allowed tools (for 'allowedTools' mode) */
|
||||||
|
allowedTools?: string;
|
||||||
}) {
|
}) {
|
||||||
super();
|
super();
|
||||||
this.setMaxListeners(25);
|
this.setMaxListeners(25);
|
||||||
@@ -409,6 +417,14 @@ export class Session extends EventEmitter {
|
|||||||
this._model = config.model;
|
this._model = config.model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply Claude CLI permission mode
|
||||||
|
if (config.claudeMode) {
|
||||||
|
this._claudeMode = config.claudeMode;
|
||||||
|
}
|
||||||
|
if (config.allowedTools) {
|
||||||
|
this._allowedTools = config.allowedTools;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize task tracker and forward events (store handlers for cleanup)
|
// Initialize task tracker and forward events (store handlers for cleanup)
|
||||||
this._taskTracker = new TaskTracker();
|
this._taskTracker = new TaskTracker();
|
||||||
this._taskTrackerHandlers = {
|
this._taskTrackerHandlers = {
|
||||||
@@ -574,6 +590,36 @@ export class Session extends EventEmitter {
|
|||||||
return { ...this._niceConfig };
|
return { ...this._niceConfig };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Claude CLI startup permission mode */
|
||||||
|
get claudeMode(): ClaudeMode {
|
||||||
|
return this._claudeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allowed tools list (for 'allowedTools' mode) */
|
||||||
|
get allowedTools(): string | undefined {
|
||||||
|
return this._allowedTools;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build Claude CLI permission flags based on the configured mode.
|
||||||
|
* Returns an array of args to pass to the CLI.
|
||||||
|
*/
|
||||||
|
private _buildPermissionArgs(): string[] {
|
||||||
|
switch (this._claudeMode) {
|
||||||
|
case 'dangerously-skip-permissions':
|
||||||
|
return ['--dangerously-skip-permissions'];
|
||||||
|
case 'allowedTools':
|
||||||
|
if (this._allowedTools) {
|
||||||
|
return ['--allowedTools', this._allowedTools];
|
||||||
|
}
|
||||||
|
// Fall back to normal mode if no tools specified
|
||||||
|
return [];
|
||||||
|
case 'normal':
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set CPU priority configuration.
|
* Set CPU priority configuration.
|
||||||
* Note: This only affects new sessions; existing running processes won't be changed.
|
* Note: This only affects new sessions; existing running processes won't be changed.
|
||||||
@@ -829,9 +875,9 @@ export class Session extends EventEmitter {
|
|||||||
/**
|
/**
|
||||||
* Starts an interactive Claude CLI session with full terminal support.
|
* Starts an interactive Claude CLI session with full terminal support.
|
||||||
*
|
*
|
||||||
* This spawns Claude CLI with `--dangerously-skip-permissions` flag in
|
* This spawns Claude CLI in interactive mode with the configured permission
|
||||||
* interactive mode. If mux wrapping is enabled, the session runs inside
|
* mode (default: `--dangerously-skip-permissions`). If mux wrapping is enabled,
|
||||||
* a tmux session for persistence across disconnects.
|
* the session runs inside a tmux session for persistence across disconnects.
|
||||||
*
|
*
|
||||||
* @throws {Error} If a process is already running in this session
|
* @throws {Error} If a process is already running in this session
|
||||||
*
|
*
|
||||||
@@ -872,7 +918,7 @@ export class Session extends EventEmitter {
|
|||||||
let needsNewSession = false;
|
let needsNewSession = false;
|
||||||
if (this._muxSession && this._mux.isPaneDead(this._muxSession.muxName)) {
|
if (this._muxSession && this._mux.isPaneDead(this._muxSession.muxName)) {
|
||||||
console.log('[Session] Dead pane detected, respawning:', this._muxSession.muxName);
|
console.log('[Session] Dead pane detected, respawning:', this._muxSession.muxName);
|
||||||
const newPid = await this._mux.respawnPane(this.id, this.workingDir, 'claude', this._niceConfig, this._model);
|
const newPid = await this._mux.respawnPane(this.id, this.workingDir, 'claude', this._niceConfig, this._model, this._claudeMode, this._allowedTools);
|
||||||
if (!newPid) {
|
if (!newPid) {
|
||||||
console.error('[Session] Failed to respawn pane, will create new session');
|
console.error('[Session] Failed to respawn pane, will create new session');
|
||||||
needsNewSession = true;
|
needsNewSession = true;
|
||||||
@@ -888,7 +934,7 @@ export class Session extends EventEmitter {
|
|||||||
console.log('[Session] Attaching to existing mux session:', this._muxSession!.muxName);
|
console.log('[Session] Attaching to existing mux session:', this._muxSession!.muxName);
|
||||||
} else {
|
} else {
|
||||||
// Create a new mux session
|
// Create a new mux session
|
||||||
this._muxSession = await this._mux.createSession(this.id, this.workingDir, 'claude', this._name, this._niceConfig, this._model);
|
this._muxSession = await this._mux.createSession(this.id, this.workingDir, 'claude', this._name, this._niceConfig, this._model, this._claudeMode, this._allowedTools);
|
||||||
console.log('[Session] Created mux session:', this._muxSession.muxName);
|
console.log('[Session] Created mux session:', this._muxSession.muxName);
|
||||||
// No extra sleep — createSession() already waits for tmux readiness
|
// No extra sleep — createSession() already waits for tmux readiness
|
||||||
}
|
}
|
||||||
@@ -961,7 +1007,7 @@ export class Session extends EventEmitter {
|
|||||||
try {
|
try {
|
||||||
// Pass --session-id to use the SAME ID as the Claudeman session
|
// Pass --session-id to use the SAME ID as the Claudeman session
|
||||||
// This ensures subagents can be directly matched to the correct tab
|
// This ensures subagents can be directly matched to the correct tab
|
||||||
const args = ['--dangerously-skip-permissions', '--session-id', this.id];
|
const args = [...this._buildPermissionArgs(), '--session-id', this.id];
|
||||||
if (this._model) args.push('--model', this._model);
|
if (this._model) args.push('--model', this._model);
|
||||||
this.ptyProcess = pty.spawn('claude', args, {
|
this.ptyProcess = pty.spawn('claude', args, {
|
||||||
name: 'xterm-256color',
|
name: 'xterm-256color',
|
||||||
|
|||||||
+31
-4
@@ -30,7 +30,7 @@ import { existsSync, readFileSync, mkdirSync } from 'node:fs';
|
|||||||
import { writeFile, rename } from 'node:fs/promises';
|
import { writeFile, rename } from 'node:fs/promises';
|
||||||
import { dirname, join } from 'node:path';
|
import { dirname, join } from 'node:path';
|
||||||
import { homedir } from 'node:os';
|
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 { wrapWithNice } from './utils/nice-wrapper.js';
|
||||||
import { SAFE_PATH_PATTERN } from './utils/regex-patterns.js';
|
import { SAFE_PATH_PATTERN } from './utils/regex-patterns.js';
|
||||||
import type { TerminalMultiplexer, MuxSession, MuxSessionWithStats } from './mux-interface.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);
|
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.
|
* Manages tmux sessions that wrap Claude CLI or shell processes.
|
||||||
*
|
*
|
||||||
@@ -204,6 +229,8 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
|||||||
name?: string,
|
name?: string,
|
||||||
niceConfig?: NiceConfig,
|
niceConfig?: NiceConfig,
|
||||||
model?: string,
|
model?: string,
|
||||||
|
claudeMode?: ClaudeMode,
|
||||||
|
allowedTools?: string,
|
||||||
): Promise<MuxSession> {
|
): Promise<MuxSession> {
|
||||||
const muxName = `claudeman-${sessionId.slice(0, 8)}`;
|
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 safeModel = (model && /^[a-zA-Z0-9._-]+$/.test(model)) ? model : undefined;
|
||||||
const modelFlag = (mode === 'claude' && safeModel) ? ` --model ${safeModel}` : '';
|
const modelFlag = (mode === 'claude' && safeModel) ? ` --model ${safeModel}` : '';
|
||||||
const baseCmd = mode === 'claude'
|
const baseCmd = mode === 'claude'
|
||||||
? `claude --dangerously-skip-permissions --session-id "${sessionId}"${modelFlag}`
|
? `claude${buildClaudePermissionFlags(claudeMode, allowedTools)} --session-id "${sessionId}"${modelFlag}`
|
||||||
: '$SHELL';
|
: '$SHELL';
|
||||||
|
|
||||||
const config = niceConfig || DEFAULT_NICE_CONFIG;
|
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,
|
* Uses `tmux respawn-pane -k` to restart the command in the same pane,
|
||||||
* preserving the session and its scrollback buffer.
|
* 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);
|
const session = this.sessions.get(sessionId);
|
||||||
if (!session) return null;
|
if (!session) return null;
|
||||||
const muxName = session.muxName;
|
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 safeModel = (model && /^[a-zA-Z0-9._-]+$/.test(model)) ? model : undefined;
|
||||||
const modelFlag = (mode === 'claude' && safeModel) ? ` --model ${safeModel}` : '';
|
const modelFlag = (mode === 'claude' && safeModel) ? ` --model ${safeModel}` : '';
|
||||||
const baseCmd = mode === 'claude'
|
const baseCmd = mode === 'claude'
|
||||||
? `claude --dangerously-skip-permissions --session-id "${sessionId}"${modelFlag}`
|
? `claude${buildClaudePermissionFlags(claudeMode, allowedTools)} --session-id "${sessionId}"${modelFlag}`
|
||||||
: '$SHELL';
|
: '$SHELL';
|
||||||
|
|
||||||
const config = niceConfig || DEFAULT_NICE_CONFIG;
|
const config = niceConfig || DEFAULT_NICE_CONFIG;
|
||||||
|
|||||||
@@ -105,6 +105,14 @@ export interface LifecycleEntry {
|
|||||||
|
|
||||||
// ========== Session Types ==========
|
// ========== Session Types ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Claude CLI startup permission mode.
|
||||||
|
* - `'dangerously-skip-permissions'`: Bypass all permission prompts (default)
|
||||||
|
* - `'normal'`: Standard mode with permission prompts
|
||||||
|
* - `'allowedTools'`: Only allow specific tools (requires allowedTools list)
|
||||||
|
*/
|
||||||
|
export type ClaudeMode = 'dangerously-skip-permissions' | 'normal' | 'allowedTools';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration for creating a new session
|
* Configuration for creating a new session
|
||||||
*/
|
*/
|
||||||
|
|||||||
+23
-1
@@ -21,6 +21,7 @@ import { execSync } from 'node:child_process';
|
|||||||
import { homedir, totalmem, freemem, loadavg, cpus } from 'node:os';
|
import { homedir, totalmem, freemem, loadavg, cpus } from 'node:os';
|
||||||
import { EventEmitter } from 'node:events';
|
import { EventEmitter } from 'node:events';
|
||||||
import { Session, ClaudeMessage, type BackgroundTask, type RalphTrackerState, type RalphTodoItem, type ActiveBashTool } from '../session.js';
|
import { Session, ClaudeMessage, type BackgroundTask, type RalphTrackerState, type RalphTodoItem, type ActiveBashTool } from '../session.js';
|
||||||
|
import type { ClaudeMode } from '../types.js';
|
||||||
import { fileStreamManager } from '../file-stream-manager.js';
|
import { fileStreamManager } from '../file-stream-manager.js';
|
||||||
import { RespawnController, RespawnConfig, RespawnState } from '../respawn-controller.js';
|
import { RespawnController, RespawnConfig, RespawnState } from '../respawn-controller.js';
|
||||||
import type { TerminalMultiplexer } from '../mux-interface.js';
|
import type { TerminalMultiplexer } from '../mux-interface.js';
|
||||||
@@ -839,6 +840,7 @@ export class WebServer extends EventEmitter {
|
|||||||
const globalNice = await this.getGlobalNiceConfig();
|
const globalNice = await this.getGlobalNiceConfig();
|
||||||
const modelConfig = await this.getModelConfig();
|
const modelConfig = await this.getModelConfig();
|
||||||
const model = (body.mode !== 'shell') ? modelConfig?.defaultModel : undefined;
|
const model = (body.mode !== 'shell') ? modelConfig?.defaultModel : undefined;
|
||||||
|
const claudeModeConfig = await this.getClaudeModeConfig();
|
||||||
const session = new Session({
|
const session = new Session({
|
||||||
workingDir,
|
workingDir,
|
||||||
mode: body.mode || 'claude',
|
mode: body.mode || 'claude',
|
||||||
@@ -847,6 +849,8 @@ export class WebServer extends EventEmitter {
|
|||||||
useMux: true,
|
useMux: true,
|
||||||
niceConfig: globalNice,
|
niceConfig: globalNice,
|
||||||
model,
|
model,
|
||||||
|
claudeMode: claudeModeConfig.claudeMode,
|
||||||
|
allowedTools: claudeModeConfig.allowedTools,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.sessions.set(session.id, session);
|
this.sessions.set(session.id, session);
|
||||||
@@ -2631,6 +2635,7 @@ export class WebServer extends EventEmitter {
|
|||||||
const niceConfig = await this.getGlobalNiceConfig();
|
const niceConfig = await this.getGlobalNiceConfig();
|
||||||
const qsModelConfig = await this.getModelConfig();
|
const qsModelConfig = await this.getModelConfig();
|
||||||
const qsModel = (mode !== 'shell') ? qsModelConfig?.defaultModel : undefined;
|
const qsModel = (mode !== 'shell') ? qsModelConfig?.defaultModel : undefined;
|
||||||
|
const qsClaudeModeConfig = await this.getClaudeModeConfig();
|
||||||
const session = new Session({
|
const session = new Session({
|
||||||
workingDir: casePath,
|
workingDir: casePath,
|
||||||
mux: this.mux,
|
mux: this.mux,
|
||||||
@@ -2638,6 +2643,8 @@ export class WebServer extends EventEmitter {
|
|||||||
mode: mode,
|
mode: mode,
|
||||||
niceConfig: niceConfig,
|
niceConfig: niceConfig,
|
||||||
model: qsModel,
|
model: qsModel,
|
||||||
|
claudeMode: qsClaudeModeConfig.claudeMode,
|
||||||
|
allowedTools: qsClaudeModeConfig.allowedTools,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto-detect completion phrase from CLAUDE.md BEFORE broadcasting
|
// Auto-detect completion phrase from CLAUDE.md BEFORE broadcasting
|
||||||
@@ -4681,6 +4688,18 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper to get Claude CLI startup mode from settings
|
||||||
|
private async getClaudeModeConfig(): Promise<{ claudeMode?: ClaudeMode; allowedTools?: string }> {
|
||||||
|
const settings = await this.readSettings();
|
||||||
|
const claudeMode = settings.claudeMode as string | undefined;
|
||||||
|
const allowedTools = settings.allowedTools as string | undefined;
|
||||||
|
// Only return valid modes
|
||||||
|
if (claudeMode === 'dangerously-skip-permissions' || claudeMode === 'normal' || claudeMode === 'allowedTools') {
|
||||||
|
return { claudeMode, allowedTools };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// Helper to get model configuration from settings
|
// Helper to get model configuration from settings
|
||||||
private async getModelConfig(): Promise<{ defaultModel?: string; agentTypeOverrides?: Record<string, string> } | null> {
|
private async getModelConfig(): Promise<{ defaultModel?: string; agentTypeOverrides?: Record<string, string> } | null> {
|
||||||
const settings = await this.readSettings();
|
const settings = await this.readSettings();
|
||||||
@@ -5309,6 +5328,7 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
|
|||||||
const sessionName = savedState?.name || muxSession.name || muxSession.muxName;
|
const sessionName = savedState?.name || muxSession.name || muxSession.muxName;
|
||||||
|
|
||||||
// Create a session object for this mux session
|
// Create a session object for this mux session
|
||||||
|
const recoveryClaudeMode = await this.getClaudeModeConfig();
|
||||||
const session = new Session({
|
const session = new Session({
|
||||||
id: muxSession.sessionId, // Preserve the original session ID
|
id: muxSession.sessionId, // Preserve the original session ID
|
||||||
workingDir: muxSession.workingDir,
|
workingDir: muxSession.workingDir,
|
||||||
@@ -5316,7 +5336,9 @@ NOW: Generate the implementation plan for the task above. Think step by step.`;
|
|||||||
name: sessionName,
|
name: sessionName,
|
||||||
mux: this.mux,
|
mux: this.mux,
|
||||||
useMux: true,
|
useMux: true,
|
||||||
muxSession: muxSession // Pass the existing session so startInteractive() can attach to it
|
muxSession: muxSession, // Pass the existing session so startInteractive() can attach to it
|
||||||
|
claudeMode: recoveryClaudeMode.claudeMode,
|
||||||
|
allowedTools: recoveryClaudeMode.allowedTools,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update session name if it was a "Restored:" placeholder or doesn't match saved name
|
// Update session name if it was a "Restored:" placeholder or doesn't match saved name
|
||||||
|
|||||||
Reference in New Issue
Block a user