From 2cc5ad719b01df11e462736becda9ee7568405c5 Mon Sep 17 00:00:00 2001 From: attacker Date: Mon, 6 Jul 2026 22:50:57 +0800 Subject: [PATCH] =?UTF-8?q?refactor(quality):=20Q7=20=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E5=B7=A8=E5=9E=8B=E7=BB=84=E4=BB=B6=E6=8B=86=E5=88=86=20?= =?UTF-8?q?=E2=80=94=20AgentCLI=20814L=E2=86=92521L=20(-36%),=20=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E5=B7=A5=E5=85=B7=E6=A0=8F+=E5=B8=B8=E9=87=8F+?= =?UTF-8?q?=E7=A9=BA=E7=8A=B6=E6=80=81+=E6=BB=9A=E5=8A=A8=E6=8C=89?= =?UTF-8?q?=E9=92=AE=204=20=E4=B8=AA=E7=8B=AC=E7=AB=8B=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PROJECT_EVALUATION.md | 2 +- ROADMAP.md | 33 ++ frontend/src/components/ScrollButtons.tsx | 43 ++ frontend/src/components/aiops/AgentCLI.tsx | 387 +++--------------- .../components/aiops/AgentCLIEmptyState.tsx | 42 ++ .../src/components/aiops/AgentCLIToolbar.tsx | 281 +++++++++++++ .../components/aiops/agent-cli-constants.ts | 89 ++++ 7 files changed, 536 insertions(+), 341 deletions(-) create mode 100644 frontend/src/components/ScrollButtons.tsx create mode 100644 frontend/src/components/aiops/AgentCLIEmptyState.tsx create mode 100644 frontend/src/components/aiops/AgentCLIToolbar.tsx create mode 100644 frontend/src/components/aiops/agent-cli-constants.ts 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) => ( -
- -
-
{t.title}
-
{t.desc}
-
-
- ))} -
-
-
+ {/* 主工作区:可折叠历史 + 对话区全宽 // 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) => ( +
+ +
+
{t.title}
+
{t.desc}
+
+
+ ))} +
+
+
+ ); +} 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})`; +}