feat: run_command 改为下拉框设置自动/需确认/禁用三种模式
- 替换原有开关为下拉选择框(selectRunCommandMode) - 新增 setRunCommandMode() 动态控制确认行为 - 需确认模式:弹窗确认后执行 - 自动模式:直接执行,无需确认 - 禁用模式:工具不可用 - 新增 .tool-card-badge.disabled 样式 - 状态从 runCommandEnabled(bool) 迁移为 runCommandMode(string)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import { state, KEYS } from '../state/state.js';
|
||||
import { setToolEnabled } from '../services/tool-registry.js';
|
||||
import { setToolEnabled, setRunCommandMode } from '../services/tool-registry.js';
|
||||
import { showToast } from './toast.js';
|
||||
import { logInfo, logWarn } from '../services/log-service.js';
|
||||
import type { ChatDB } from '../types.js';
|
||||
@@ -44,34 +44,47 @@ export function initToolsModal(): void {
|
||||
});
|
||||
}
|
||||
|
||||
// run_command 开关
|
||||
const toggle2 = modalEl.querySelector('#toggleRunCommand2') as HTMLInputElement;
|
||||
if (toggle2) {
|
||||
toggle2.addEventListener('change', async () => {
|
||||
// run_command 模式下拉框
|
||||
const selectMode = modalEl.querySelector('#selectRunCommandMode') as HTMLSelectElement;
|
||||
if (selectMode) {
|
||||
selectMode.addEventListener('change', async () => {
|
||||
const db = state.get<ChatDB | null>(KEYS.DB);
|
||||
state.set('runCommandEnabled', toggle2.checked);
|
||||
if (db) await db.saveSetting('runCommandEnabled', toggle2.checked);
|
||||
setToolEnabled('run_command', toggle2.checked);
|
||||
if (toggle2.checked) {
|
||||
showToast('命令执行已开启(每次执行需确认)', 'info');
|
||||
logInfo('命令执行已开启');
|
||||
} else {
|
||||
showToast('命令执行已关闭', 'info');
|
||||
logInfo('命令执行已关闭');
|
||||
}
|
||||
const mode = selectMode.value as 'auto' | 'confirm' | 'disabled';
|
||||
state.set('runCommandMode', mode);
|
||||
if (db) await db.saveSetting('runCommandMode', mode);
|
||||
setRunCommandMode(mode);
|
||||
updateRunCommandBadge(mode);
|
||||
|
||||
const modeNames: Record<string, string> = { auto: '自动执行', confirm: '需确认', disabled: '已禁用' };
|
||||
showToast(`命令执行模式:${modeNames[mode]}`, 'info');
|
||||
logInfo(`命令执行模式已切换: ${mode}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateRunCommandBadge(mode: string): void {
|
||||
const badge = modalEl.querySelector('#runCommandBadge') as HTMLElement;
|
||||
if (!badge) return;
|
||||
const map: Record<string, { text: string; cls: string }> = {
|
||||
auto: { text: '自动', cls: 'auto' },
|
||||
confirm: { text: '需确认', cls: 'confirm' },
|
||||
disabled: { text: '禁用', cls: 'disabled' }
|
||||
};
|
||||
const info = map[mode] || map.confirm;
|
||||
badge.textContent = info.text;
|
||||
badge.className = `tool-card-badge ${info.cls}`;
|
||||
}
|
||||
|
||||
export function openToolsModal(): void {
|
||||
// 同步开关状态
|
||||
const toolCallingEnabled = state.get<boolean>('toolCallingEnabled', false);
|
||||
const toggleTC = modalEl.querySelector('#toggleToolCalling') as HTMLInputElement;
|
||||
if (toggleTC) toggleTC.checked = toolCallingEnabled;
|
||||
|
||||
const runCmdEnabled = state.get<boolean>('runCommandEnabled', true);
|
||||
const toggle2 = modalEl.querySelector('#toggleRunCommand2') as HTMLInputElement;
|
||||
if (toggle2) toggle2.checked = runCmdEnabled;
|
||||
const runCommandMode = state.get<string>('runCommandMode', 'confirm');
|
||||
const selectMode = modalEl.querySelector('#selectRunCommandMode') as HTMLSelectElement;
|
||||
if (selectMode) selectMode.value = runCommandMode;
|
||||
updateRunCommandBadge(runCommandMode);
|
||||
|
||||
modalEl.style.display = '';
|
||||
}
|
||||
|
||||
@@ -426,14 +426,15 @@
|
||||
<div class="tool-card-desc">文件内查找替换,支持全部替换</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
<div class="tool-card-header"><span class="tool-card-icon">💻</span><span class="tool-card-name">run_command</span><span class="tool-card-badge confirm">需确认</span></div>
|
||||
<div class="tool-card-header"><span class="tool-card-icon">💻</span><span class="tool-card-name">run_command</span><span class="tool-card-badge confirm" id="runCommandBadge">需确认</span></div>
|
||||
<div class="tool-card-desc">执行 shell 命令,无超时限制</div>
|
||||
<div style="margin-top:6px;display:flex;align-items:center;gap:8px;">
|
||||
<label class="toggle-label" style="margin:0;font-size:11px;">
|
||||
<input type="checkbox" id="toggleRunCommand2">
|
||||
<span class="toggle-slider"></span>
|
||||
<span style="margin-left:4px;">启用命令执行</span>
|
||||
</label>
|
||||
<label style="margin:0;font-size:11px;color:var(--text-secondary);">执行模式:</label>
|
||||
<select id="selectRunCommandMode" style="font-size:11px;padding:2px 6px;background:var(--bg-tertiary);color:var(--text-primary);border:1px solid var(--border-color);border-radius:4px;">
|
||||
<option value="confirm">需确认</option>
|
||||
<option value="auto">自动执行</option>
|
||||
<option value="disabled">禁用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool-card">
|
||||
|
||||
@@ -22,7 +22,7 @@ import { initHistoryModal, closeHistoryModal } from './components/history-modal.
|
||||
import { initMemoryModal } from './components/memory-modal.js';
|
||||
import { initToolsModal, closeToolsModal } from './components/tools-modal.js';
|
||||
import { initMemoryManager } from './services/memory-manager.js';
|
||||
import { setToolEnabled } from './services/tool-registry.js';
|
||||
import { setToolEnabled, setRunCommandMode } from './services/tool-registry.js';
|
||||
import { initToolConfirmModal } from './components/tool-confirm-modal.js';
|
||||
import { initWorkspacePanel } from './components/workspace-panel.js';
|
||||
import { initLogPanel, addLog } from './services/log-service.js';
|
||||
@@ -190,7 +190,7 @@ async function init(): Promise<void> {
|
||||
|
||||
// ── 防御性重置:确保首次启动不会遗留脏状态 ──
|
||||
state.set('toolCallingEnabled', false);
|
||||
state.set('runCommandEnabled', true); // 默认开启(需确认)
|
||||
state.set('runCommandMode', 'confirm'); // 默认需确认
|
||||
state.set('memoryEnabled', true);
|
||||
state.set('thinkEnabled', false);
|
||||
|
||||
@@ -236,14 +236,12 @@ async function init(): Promise<void> {
|
||||
|
||||
// ── Tool Calling 设置 ──
|
||||
const toolCallingEnabled = await db.getSetting('toolCallingEnabled', false);
|
||||
const runCommandEnabled = await db.getSetting('runCommandEnabled', true); // 默认开启(需确认)
|
||||
const runCommandMode = await db.getSetting('runCommandMode', 'confirm') as 'auto' | 'confirm' | 'disabled';
|
||||
state.set('toolCallingEnabled', toolCallingEnabled);
|
||||
state.set('runCommandEnabled', runCommandEnabled);
|
||||
if (!runCommandEnabled) setToolEnabled('run_command', false); // 仅在用户明确关闭时禁用
|
||||
state.set('runCommandMode', runCommandMode);
|
||||
setRunCommandMode(runCommandMode);
|
||||
const toggleTC = document.querySelector<HTMLInputElement>('#toggleToolCalling');
|
||||
if (toggleTC) toggleTC.checked = toolCallingEnabled;
|
||||
const toggleRC = document.querySelector<HTMLInputElement>('#toggleRunCommand');
|
||||
if (toggleRC) toggleRC.checked = runCommandEnabled;
|
||||
|
||||
// ── Agent 记忆设置 ──
|
||||
const memoryEnabled = await db.getSetting('memoryEnabled', true);
|
||||
|
||||
@@ -356,9 +356,24 @@ export const TOOL_DEFINITIONS: ToolDefinition[] = [
|
||||
const CONFIRM_TOOLS = ['run_command'];
|
||||
|
||||
export function needsConfirmation(toolName: string): boolean {
|
||||
if (toolName === 'run_command') {
|
||||
// run_command 确认模式由 runCommandMode 状态控制
|
||||
const runCommandMode = (window as any).__runCommandMode || 'confirm';
|
||||
return runCommandMode === 'confirm';
|
||||
}
|
||||
return CONFIRM_TOOLS.includes(toolName);
|
||||
}
|
||||
|
||||
/** 设置 run_command 执行模式 */
|
||||
export function setRunCommandMode(mode: 'auto' | 'confirm' | 'disabled'): void {
|
||||
(window as any).__runCommandMode = mode;
|
||||
if (mode === 'disabled') {
|
||||
setToolEnabled('run_command', false);
|
||||
} else {
|
||||
setToolEnabled('run_command', true);
|
||||
}
|
||||
}
|
||||
|
||||
let enabledTools: Set<string> = new Set([
|
||||
'read_file', 'list_directory', 'search_files',
|
||||
'write_file', 'create_directory', 'delete_file',
|
||||
|
||||
@@ -2937,6 +2937,12 @@ html, body {
|
||||
border: 1px solid rgba(252, 225, 0, 0.15);
|
||||
}
|
||||
|
||||
.tool-card-badge.disabled {
|
||||
color: var(--critical);
|
||||
background: var(--critical-bg);
|
||||
border: 1px solid rgba(241, 112, 123, 0.15);
|
||||
}
|
||||
|
||||
.tool-card-desc {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
|
||||
Vendored
+1
-1
@@ -274,7 +274,7 @@ export type StateKey =
|
||||
| 'temperature'
|
||||
| 'thinkEnabled'
|
||||
| 'toolCallingEnabled'
|
||||
| 'runCommandEnabled'
|
||||
| 'runCommandMode'
|
||||
| 'memoryEnabled'
|
||||
| 'memoryEntries'
|
||||
| 'embeddingModel';
|
||||
|
||||
Reference in New Issue
Block a user