diff --git a/PROJECT_EVALUATION.md b/PROJECT_EVALUATION.md
index 2279a48..954415e 100644
--- a/PROJECT_EVALUATION.md
+++ b/PROJECT_EVALUATION.md
@@ -129,7 +129,7 @@
| ~~`api.ts` 1324 行/352 方法~~ → 已拆分为 12 个域文件 (api/kubernetes.ts, deploy.ts, monitor.ts 等) | ✅ 已解决 | 前端 | ~~P0~~ done |
| 前端 **1026 处** `any` 类型 | 类型安全缺失,重构风险高 | 前端全局 | ~~P0~~ **done** (any 1076→40, unused 25→6, console 93→1, tsc --noEmit=0) |
| ~~K8s 双路由体系(集群域+Kuboard 域)~~ → code 路由统一为主,ID 路由标记 deprecated 向后兼容 | ✅ 已解决 | 后端 | ~~P1~~ done |
-| 25 个 ≥500 行巨型组件 | 拆分困难 | 前端 | P1 → **Q6 done: 最大组件 ResourceVisualEditor 882L→282L (-68%),提取 5 个独立编辑器文件** |
+| 25 个 ≥500 行巨型组件 | 拆分困难 | 前端 | P1 → **Q6+Q7 done: 最大组件 ResourceVisualEditor 882L→282L (-68%) + AgentCLI 814L→521L (-36%),累计提取 11 个独立组件文件** |
### 3.2 🟡 中优先级
diff --git a/ROADMAP.md b/ROADMAP.md
index 177d68b..dcb1839 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -478,6 +478,7 @@ services/api.ts (1324L)
| U13 | 主机监控大屏挂载(HostMonitorDashboard 死代码复活) | P3 | **done** |
| U14 | ESLint 冗余 disable 指令清理(unused eslint-disable 6→0) | P3 | **done** |
| Q6 | 前端巨型组件拆分(ResourceVisualEditor 882L→282L,提取 5 个独立编辑器) | P0 | **done** |
+| Q7 | 前端巨型组件拆分(AgentCLI 814L→521L,提取工具栏+常量+空状态+滚动按钮) | P0 | **done** |
---
@@ -645,3 +646,35 @@ pending → in_progress → done / blocked
- [x] 17/17 集成回归测试通过(零回归)
- [x] Docker 部署 healthy
- [x] K8s 资源 YAML API 链路验证通过(visual editor dispatch 正常)
+
+---
+
+## Q7: 前端巨型组件拆分 — AgentCLI [done]
+
+**问题**: `AgentCLI.tsx`(814 行)是 Q6 拆分后项目最大的前端组件,包含 AI 运维 Agent 执行页面的全部逻辑:WebSocket 事件处理、工具栏控制(模式切换/主机选择/集群选择/Pod选择/安全模式/状态徽章/核心能力说明)、对话区空状态、滚动按钮。单文件过大导致维护困难。
+
+**已完成 (2026-07-06)**:
+
+将内联的静态数据、工具栏 UI、空状态、滚动按钮提取为独立文件:
+
+| 新文件 | 行数 | 职责 |
+|--------|------|------|
+| `agent-cli-constants.ts` | 89 | WS 事件接口 + 安全模式定义 + 核心能力说明 + Pod 占位符 + 主机标签格式化 |
+| `AgentCLIToolbar.tsx` | 281 | 工作区控制栏(模式切换 + 目标选择 + 安全模式 + 状态徽章 + 核心能力 Popover) |
+| `AgentCLIEmptyState.tsx` | 42 | 对话区空状态(未选目标/连接中/就绪提示) |
+| `ScrollButtons.tsx` | 43 | 浮动滚动按钮(回到顶部/底部),通用可复用组件 |
+
+主文件 `AgentCLI.tsx` 从 **814 行降至 521 行**(-36%),仅保留:状态管理、WebSocket 连接生命周期、事件处理(handleEvent switch)、发送/停止/恢复逻辑、对话区布局(AgentChatTimeline + 输入区)。
+
+**提取原则**: 常量文件为纯数据(零 React 依赖,仅 lucide 图标类型引用);工具栏为受控组件(接收全部状态 + setter 作为 props,内部无独立状态);空状态为纯展示组件;滚动按钮为通用可复用组件(不限于 AgentCLI)。零逻辑变更。
+
+**验收标准**:
+- [x] AgentCLI.tsx 从 814 行降至 **521 行**(-36%)
+- [x] 4 个提取的文件全部 < 300 行(最大 AgentCLIToolbar 281 行)
+- [x] `tsc -b` 零错误
+- [x] `npm run build` 零错误(✓ built in 16.95s)
+- [x] ESLint errors 保持 **0**(清理 6 个 unused 变量/import)
+- [x] ESLint warnings 保持 **59**(无新增)
+- [x] `go build` 零错误
+- [x] 17/17 集成回归测试通过(零回归)
+- [x] Docker 部署 healthy
diff --git a/frontend/src/components/ScrollButtons.tsx b/frontend/src/components/ScrollButtons.tsx
new file mode 100644
index 0000000..8dbbcd4
--- /dev/null
+++ b/frontend/src/components/ScrollButtons.tsx
@@ -0,0 +1,43 @@
+// ScrollButtons.tsx — 浮动滚动按钮(回到顶部/底部),AgentCLI 对话区复用
+import { Button } from '@/components/ui/button';
+import { ChevronUp, ChevronDown } from 'lucide-react';
+
+export interface ScrollButtonsProps {
+ show: boolean;
+ atTop: boolean;
+ atBottom: boolean;
+ onScrollTop: () => void;
+ onScrollBottom: () => void;
+}
+
+export default function ScrollButtons({ show, atTop, atBottom, onScrollTop, onScrollBottom }: ScrollButtonsProps) {
+ if (!show || (atTop && atBottom)) return null;
+ return (
+
+ {!atTop && (
+
+ )}
+ {!atBottom && (
+
+ )}
+
+ );
+}
diff --git a/frontend/src/components/aiops/AgentCLI.tsx b/frontend/src/components/aiops/AgentCLI.tsx
index d1daeec..ab781e7 100644
--- a/frontend/src/components/aiops/AgentCLI.tsx
+++ b/frontend/src/components/aiops/AgentCLI.tsx
@@ -4,100 +4,22 @@
import { useState, useRef, useEffect, useCallback } from 'react';
import { Card } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
-import { Badge } from '@/components/ui/badge';
-import {
- Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
-} from '@/components/ui/select';
-import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { useConfirm } from '@/components/ui/confirm-dialog';
import { serverApi } from '@/api';
import { kubernetesApi } from '@/api/kubernetes';
import { buildAgentCliWsUrl, type AgentCliMode } from '@/api/aiops/agent-cli';
import { toast } from 'sonner';
import {
- Send, Square, Terminal, Shield, Brain, Cpu, Database, Loader2, Bot, Lightbulb, Server,
- PanelLeftClose, History, ChevronUp, ChevronDown, Boxes, Cloud,
+ Send, Square, Bot,
} from 'lucide-react';
-import { Input } from '@/components/ui/input';
import AgentCLIHistory from './AgentCLIHistory';
import { AgentChatTimeline, type ChatItem } from './AgentCLIMessages';
+import AgentCLIToolbar from './AgentCLIToolbar';
+import AgentCLIEmptyState from './AgentCLIEmptyState';
+import ScrollButtons from '@/components/ScrollButtons';
import type { AgentCliSession } from '@/api/aiops/agent-cli';
import { PageShell } from '@/components/layout/PageShell';
-
-// WS 事件类型(后端 wsEvent 对应) // Logan.Li
-interface WsEvent {
- type: string;
- round?: number;
- session_id?: number;
- thought?: string;
- tool_name?: string;
- tool_args?: Record;
- risk?: string;
- output?: string;
- success?: boolean;
- duration?: string;
- tokens?: number;
- answer?: string;
- message?: string;
- confirm_id?: string;
- command?: string;
-}
-
-// 四大核心模块说明(灯泡 Popover) // Logan.Li
-const POD_NONE = '__none__';
-
-const TIPS_HOST = [
- { icon: Cpu, title: 'LLM + 工具层', color: 'text-sky-400',
- desc: 'OpenAI 兼容 LLM;工具含 ssh_execute(远程执行)与 analyze_output(输出分析)。' },
- { icon: Shield, title: '安全 + Prompt', color: 'dg-text-yellow',
- desc: '五级风险评估 + 三级安全模式;危险命令硬性拒绝,高危命令弹框确认。' },
- { icon: Brain, title: 'ReAct 核心引擎', color: 'dg-text-purple',
- desc: '思考→行动→观察循环(最多 16 轮),失败换法重试,循环检测防死循环。' },
- { icon: Database, title: '自进化引擎', color: 'dg-text-green',
- desc: '四层记忆异步学习,同类任务自动注入历史经验,越用越聪明。' },
-];
-
-const TIPS_KUBERNETES = [
- { icon: Cloud, title: 'Kubernetes 查询', color: 'text-sky-400',
- desc: 'kubernetes_get 统一查询节点/Pod/Deployment/事件等;pod_logs 拉取容器日志。' },
- { icon: Terminal, title: 'Pod 执行', color: 'dg-text-purple',
- desc: '选定 Pod 后可用 pod_execute 进入容器排障;kubernetes_action 执行重启/扩缩容等变更。' },
- { icon: Shield, title: '安全 + ReAct', color: 'dg-text-yellow',
- desc: '只读工具自动执行;变更与危险命令弹框确认,最多 16 轮循环排障。' },
- { icon: Database, title: '自进化引擎', color: 'dg-text-green',
- desc: '按集群/命名空间分桶学习,同类 Kubernetes 排障任务越用越准。' },
-];
-
-// 安全模式说明(灯泡 Popover 展示) // Logan.Li
-const SAFETY_MODES = [
- {
- value: 'strict',
- label: '严格',
- short: '中风险+确认',
- desc: 'chmod、文件修改、服务重启等中风险及以上命令均需弹框确认。适合生产环境或不熟悉的主机。',
- examples: 'chmod、mv、systemctl restart',
- },
- {
- value: 'balanced',
- label: '均衡',
- short: '高风险+确认',
- desc: '日常排障命令(查看日志、ps、df)自动执行;删除文件、重启服务等高风险操作才需确认。推荐日常使用。',
- examples: 'cat/grep/df 自动 · rm/reboot 确认',
- recommended: true,
- },
- {
- value: 'permissive',
- label: '宽松',
- short: '仅拦截危险',
- desc: '除 rm -rf /、mkfs 等危险命令硬性拦截外,其余全部自动执行。仅适合隔离测试环境。',
- examples: 'rm -rf / 拦截 · 其余自动',
- },
-] as const;
-
-// formatServerLabel 主机下拉展示文案 // Logan.Li
-function formatServerLabel(s: { hostname: string; ip: string }) {
- return `${s.hostname}(${s.ip})`;
-}
+import { POD_NONE, type WsEvent } from './agent-cli-constants';
export default function AgentCLI() {
const confirm = useConfirm();
@@ -136,14 +58,8 @@ export default function AgentCLI() {
setItems((prev) => [...prev, { ...it, id: nextId() }]);
}, []);
- const currentSafety = SAFETY_MODES.find((m) => m.value === safetyMode) ?? SAFETY_MODES[1];
- const currentTips = cliMode === 'kubernetes' ? TIPS_KUBERNETES : TIPS_HOST;
const selectedCluster = clusters.find((c) => c.code === clusterCode);
const wsReady = cliMode === 'host' ? Boolean(serverId) : Boolean(clusterCode && namespace);
- const filteredPods = pods.filter((p) => {
- const q = podSearch.trim().toLowerCase();
- return !q || p.name.toLowerCase().includes(q);
- });
// 加载主机列表 // Logan.Li
useEffect(() => {
@@ -473,7 +389,6 @@ export default function AgentCLI() {
setTokens(0);
};
- const selectedServer = servers.find((s) => String(s.id) === serverId);
const canResumeView = viewSession && ['done', 'aborted', 'error'].includes(viewSession.status);
return (
@@ -485,203 +400,34 @@ export default function AgentCLI() {
className="h-full"
contentClassName="h-full flex flex-col min-h-0 gap-2"
>
- {/* 工作区控制栏:主机 + 安全模式 + 状态,不挤占对话区宽度 // Logan.Li */}
-
-
-
-
-
-
- {cliMode === 'host' ? (
-
- ) : (
- <>
-
-
-
-
-
-
-
- setPodSearch(e.target.value)}
- placeholder="搜索 Pod 名称"
- className="h-8 text-xs dg-input"
- />
-
-
- {filteredPods.map((p) => (
-
- ))}
- {filteredPods.length === 0 && (
-
无匹配 Pod
- )}
-
-
-
- >
- )}
-
-
-
-
-
-
-
-
- 安全模式说明
-
- 控制 AI 执行远程命令前是否需要你确认。危险命令(如 rm -rf /)任何模式均硬性拦截。
-
- {SAFETY_MODES.map((m) => (
-
-
- {m.label}
- {m.short}
- {'recommended' in m && m.recommended && (
- 推荐
- )}
-
-
{m.desc}
-
例:{m.examples}
-
- ))}
-
-
-
-
-
-
-
-
- {connected && (
-
- 已连接
-
- )}
- {viewMode && (
-
查看记录
- )}
- {canContinue && !running && !viewMode && (
-
可追问
- )}
- {running && (
-
- 第 {round} 轮 · {tokens}t
-
- )}
-
-
-
-
-
-
- 核心能力
- {currentTips.map((t) => (
-
- ))}
-
-
-
+
{/* 主工作区:可折叠历史 + 对话区全宽 // Logan.Li */}
@@ -721,62 +467,23 @@ export default function AgentCLI() {
className="flex-1 min-h-0 overflow-y-auto p-4 space-y-3"
>
{items.length === 0 && (
-
-
- {!wsReady ? (
- <>
-
- {cliMode === 'kubernetes' ? '请先选择集群和命名空间' : '请先选择一台目标主机'}
-
- >
- ) : !connected ? (
- <>
-
-
{cliMode === 'kubernetes' ? '正在连接集群...' : '正在连接主机...'}
- >
- ) : (
-
- {cliMode === 'kubernetes'
- ? '描述 Kubernetes 排障任务,例如「查看 NotReady 节点」或「分析 nginx Pod 重启原因」'
- : '描述你要执行的任务,例如「检查磁盘使用率并清理大文件」'}
-
- 当前安全模式:{currentSafety.label}({currentSafety.short})
- {cliMode === 'kubernetes' && podName === POD_NONE && ' · 未选 Pod,仅集群/NS 级查询'}
-
-
- )}
-
+
)}
- {items.length > 0 && (!scrollAtTop || !scrollAtBottom) && (
-
- {!scrollAtTop && (
-
- )}
- {!scrollAtBottom && (
-
- )}
-
- )}
+ 0}
+ atTop={scrollAtTop}
+ atBottom={scrollAtBottom}
+ onScrollTop={scrollToTop}
+ onScrollBottom={scrollToBottom}
+ />
{/* 加宽输入区:多行 + 独立操作栏 // Logan.Li */}
diff --git a/frontend/src/components/aiops/AgentCLIEmptyState.tsx b/frontend/src/components/aiops/AgentCLIEmptyState.tsx
new file mode 100644
index 0000000..7765756
--- /dev/null
+++ b/frontend/src/components/aiops/AgentCLIEmptyState.tsx
@@ -0,0 +1,42 @@
+// AgentCLIEmptyState.tsx — AgentCLI 对话区空状态(未选目标/连接中/就绪提示)
+import { Terminal, Loader2 } from 'lucide-react';
+import type { AgentCliMode } from '@/api/aiops/agent-cli';
+import { POD_NONE, SAFETY_MODES } from './agent-cli-constants';
+
+export interface AgentCLIEmptyStateProps {
+ cliMode: AgentCliMode;
+ wsReady: boolean;
+ connected: boolean;
+ safetyMode: string;
+ podName: string;
+}
+
+export default function AgentCLIEmptyState({ cliMode, wsReady, connected, safetyMode, podName }: AgentCLIEmptyStateProps) {
+ const currentSafety = SAFETY_MODES.find((m) => m.value === safetyMode) ?? SAFETY_MODES[1];
+ const isK8s = cliMode === 'kubernetes';
+ return (
+
+
+ {!wsReady ? (
+
+ {isK8s ? '请先选择集群和命名空间' : '请先选择一台目标主机'}
+
+ ) : !connected ? (
+ <>
+
+
{isK8s ? '正在连接集群...' : '正在连接主机...'}
+ >
+ ) : (
+
+ {isK8s
+ ? '描述 Kubernetes 排障任务,例如「查看 NotReady 节点」或「分析 nginx Pod 重启原因」'
+ : '描述你要执行的任务,例如「检查磁盘使用率并清理大文件」'}
+
+ 当前安全模式:{currentSafety.label}({currentSafety.short})
+ {isK8s && podName === POD_NONE && ' · 未选 Pod,仅集群/NS 级查询'}
+
+
+ )}
+
+ );
+}
diff --git a/frontend/src/components/aiops/AgentCLIToolbar.tsx b/frontend/src/components/aiops/AgentCLIToolbar.tsx
new file mode 100644
index 0000000..33ab19e
--- /dev/null
+++ b/frontend/src/components/aiops/AgentCLIToolbar.tsx
@@ -0,0 +1,281 @@
+// AgentCLIToolbar.tsx — AgentCLI 工作区控制栏(从 AgentCLI.tsx 提取)
+// 包含:模式切换(主机/K8s) + 目标选择(主机/集群/NS/Pod) + 安全模式 + 状态徽章 + 核心能力说明
+import { Button } from '@/components/ui/button';
+import { Badge } from '@/components/ui/badge';
+import {
+ Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
+} from '@/components/ui/select';
+import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
+import { Input } from '@/components/ui/input';
+import {
+ Terminal, Shield, Lightbulb, Server,
+ PanelLeftClose, History, Boxes, Cloud, Loader2,
+} from 'lucide-react';
+import type { AgentCliMode } from '@/api/aiops/agent-cli';
+import {
+ POD_NONE, TIPS_HOST, TIPS_KUBERNETES, SAFETY_MODES, formatServerLabel,
+ type TipItem,
+} from './agent-cli-constants';
+
+interface PodInfo { name: string; status: string; image: string; restarts: number }
+interface ServerInfo { id: number; hostname: string; ip: string }
+interface ClusterInfo { id: number; name: string; code: string }
+
+export interface AgentCLIToolbarProps {
+ cliMode: AgentCliMode;
+ setCliMode: (m: AgentCliMode) => void;
+ // 主机模式
+ servers: ServerInfo[];
+ serverId: string;
+ setServerId: (v: string) => void;
+ // Kubernetes 模式
+ clusters: ClusterInfo[];
+ clusterCode: string;
+ setClusterCode: (v: string) => void;
+ namespaces: string[];
+ namespace: string;
+ setNamespace: (v: string) => void;
+ pods: PodInfo[];
+ podName: string;
+ setPodName: (v: string) => void;
+ podSearch: string;
+ setPodSearch: (v: string) => void;
+ // 安全模式
+ safetyMode: string;
+ setSafetyMode: (v: string) => void;
+ // 状态
+ connected: boolean;
+ viewMode: boolean;
+ canContinue: boolean;
+ running: boolean;
+ round: number;
+ tokens: number;
+ historyOpen: boolean;
+ setHistoryOpen: (fn: (v: boolean) => boolean) => void;
+}
+
+export default function AgentCLIToolbar(props: AgentCLIToolbarProps) {
+ const {
+ cliMode, setCliMode,
+ servers, serverId, setServerId,
+ clusters, clusterCode, setClusterCode,
+ namespaces, namespace, setNamespace,
+ pods, podName, setPodName, podSearch, setPodSearch,
+ safetyMode, setSafetyMode,
+ connected, viewMode, canContinue, running, round, tokens,
+ historyOpen, setHistoryOpen,
+ } = props;
+
+ const currentTips: TipItem[] = cliMode === 'kubernetes' ? TIPS_KUBERNETES : TIPS_HOST;
+ const selectedServer = servers.find((s) => String(s.id) === serverId);
+ const filteredPods = pods.filter((p) => {
+ const q = podSearch.trim().toLowerCase();
+ return !q || p.name.toLowerCase().includes(q);
+ });
+
+ return (
+
+ {/* 模式切换 */}
+
+
+
+
+
+ {/* 目标选择 */}
+ {cliMode === 'host' ? (
+
+ ) : (
+ <>
+
+
+ {/* Pod 选择 Popover */}
+
+
+
+
+
+ setPodSearch(e.target.value)}
+ placeholder="搜索 Pod 名称"
+ className="h-8 text-xs dg-input"
+ />
+
+
+ {filteredPods.map((p) => (
+
+ ))}
+ {filteredPods.length === 0 && (
+
无匹配 Pod
+ )}
+
+
+
+ >
+ )}
+
+ {/* 安全模式选择 + 说明 */}
+
+
+
+
+
+
+
+ 安全模式说明
+
+ 控制 AI 执行远程命令前是否需要你确认。危险命令(如 rm -rf /)任何模式均硬性拦截。
+
+ {SAFETY_MODES.map((m) => (
+
+
+ {m.label}
+ {m.short}
+ {'recommended' in m && m.recommended && (
+ 推荐
+ )}
+
+
{m.desc}
+
例:{m.examples}
+
+ ))}
+
+
+
+
+ {/* 历史折叠 */}
+
+
+
+
+ {/* 状态徽章 */}
+ {connected && (
+
+ 已连接
+
+ )}
+ {viewMode && (
+
查看记录
+ )}
+ {canContinue && !running && !viewMode && (
+
可追问
+ )}
+ {running && (
+
+ 第 {round} 轮 · {tokens}t
+
+ )}
+
+ {/* 核心能力说明 Popover */}
+
+
+
+
+
+ 核心能力
+ {currentTips.map((t) => (
+
+ ))}
+
+
+
+ );
+}
diff --git a/frontend/src/components/aiops/agent-cli-constants.ts b/frontend/src/components/aiops/agent-cli-constants.ts
new file mode 100644
index 0000000..bc5541d
--- /dev/null
+++ b/frontend/src/components/aiops/agent-cli-constants.ts
@@ -0,0 +1,89 @@
+// agent-cli-constants.ts — AgentCLI 静态配置/类型(从 AgentCLI.tsx 提取)
+// 纯数据:WS 事件接口、安全模式定义、核心能力说明、Pod 占位符、主机标签格式化
+import {
+ Cpu, Shield, Brain, Database, Terminal, Cloud,
+} from 'lucide-react';
+
+// WS 事件类型(后端 wsEvent 对应)
+export interface WsEvent {
+ type: string;
+ round?: number;
+ session_id?: number;
+ thought?: string;
+ tool_name?: string;
+ tool_args?: Record;
+ risk?: string;
+ output?: string;
+ success?: boolean;
+ duration?: string;
+ tokens?: number;
+ answer?: string;
+ message?: string;
+ confirm_id?: string;
+ command?: string;
+}
+
+// Pod 占位符:未选定 Pod 时使用
+export const POD_NONE = '__none__';
+
+export interface TipItem {
+ icon: typeof Cpu;
+ title: string;
+ color: string;
+ desc: string;
+}
+
+// 四大核心模块说明(灯泡 Popover)— 主机模式
+export const TIPS_HOST: TipItem[] = [
+ { icon: Cpu, title: 'LLM + 工具层', color: 'text-sky-400',
+ desc: 'OpenAI 兼容 LLM;工具含 ssh_execute(远程执行)与 analyze_output(输出分析)。' },
+ { icon: Shield, title: '安全 + Prompt', color: 'dg-text-yellow',
+ desc: '五级风险评估 + 三级安全模式;危险命令硬性拒绝,高危命令弹框确认。' },
+ { icon: Brain, title: 'ReAct 核心引擎', color: 'dg-text-purple',
+ desc: '思考→行动→观察循环(最多 16 轮),失败换法重试,循环检测防死循环。' },
+ { icon: Database, title: '自进化引擎', color: 'dg-text-green',
+ desc: '四层记忆异步学习,同类任务自动注入历史经验,越用越聪明。' },
+];
+
+// 四大核心模块说明(灯泡 Popover)— Kubernetes 模式
+export const TIPS_KUBERNETES: TipItem[] = [
+ { icon: Cloud, title: 'Kubernetes 查询', color: 'text-sky-400',
+ desc: 'kubernetes_get 统一查询节点/Pod/Deployment/事件等;pod_logs 拉取容器日志。' },
+ { icon: Terminal, title: 'Pod 执行', color: 'dg-text-purple',
+ desc: '选定 Pod 后可用 pod_execute 进入容器排障;kubernetes_action 执行重启/扩缩容等变更。' },
+ { icon: Shield, title: '安全 + ReAct', color: 'dg-text-yellow',
+ desc: '只读工具自动执行;变更与危险命令弹框确认,最多 16 轮循环排障。' },
+ { icon: Database, title: '自进化引擎', color: 'dg-text-green',
+ desc: '按集群/命名空间分桶学习,同类 Kubernetes 排障任务越用越准。' },
+];
+
+// 安全模式说明(灯泡 Popover 展示)
+export const SAFETY_MODES = [
+ {
+ value: 'strict',
+ label: '严格',
+ short: '中风险+确认',
+ desc: 'chmod、文件修改、服务重启等中风险及以上命令均需弹框确认。适合生产环境或不熟悉的主机。',
+ examples: 'chmod、mv、systemctl restart',
+ },
+ {
+ value: 'balanced',
+ label: '均衡',
+ short: '高风险+确认',
+ desc: '日常排障命令(查看日志、ps、df)自动执行;删除文件、重启服务等高风险操作才需确认。推荐日常使用。',
+ examples: 'cat/grep/df 自动 · rm/reboot 确认',
+ recommended: true,
+ },
+ {
+ value: 'permissive',
+ label: '宽松',
+ short: '仅拦截危险',
+ desc: '除 rm -rf /、mkfs 等危险命令硬性拦截外,其余全部自动执行。仅适合隔离测试环境。',
+ examples: 'rm -rf / 拦截 · 其余自动',
+ },
+] as const;
+
+// formatServerLabel 主机下拉展示文案
+export function formatServerLabel(s: { hostname: string; ip: string }) {
+ return `${s.hostname}(${s.ip})`;
+}