feat(desktop): 工业化升级 D —— 内容可信(Markdown 渲染 + 健康五灯全真)

- components/Markdown.tsx:零依赖、行级 Markdown 渲染(# 标题 / **粗** *斜* `码` /
  - 与 1. 列表 / > 引用 / --- 分隔 / 段落),流式安全(每 token 重渲染容忍残缺)。
  报告正文与运行输出从裸 <pre> 换成真排版,瞬间像份报告。
- 健康聚合:mcp-go 加 rag.Status() + health 工具(milvus/neo4j/embedding 就绪);
  gateway GET /api/v1/health 聚合 gateway/nats/db/redis(本地) + milvus/neo4j(经 mcp-go);
  health.ts 轮询 /health,TopBar 五盏灯(Gateway/DB/NATS/Milvus/Neo4j)从"灰=未知"变真实绿/红。

验证:浏览器(Preview)跑报告——正文以标题/有序列表/引用/分隔线/二级标题排版呈现;
五盏灯全绿(/health 返回 db/gateway/milvus/nats/neo4j/redis 全 true)。tsc + vite build + 后端 build 通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-06-12 17:34:54 +08:00
parent 4d9d1ac615
commit d5ae2f71d4
9 changed files with 186 additions and 17 deletions
@@ -3,6 +3,7 @@ import { Play, Download, FileText, ExternalLink } from "lucide-react";
import { generateReport, streamTokens, streamExec, reportDownloadUrl, type Identity, type ExecEvent } from "../lib/api";
import { isDesktop, saveReportAs, openReport, notify } from "../lib/desktop";
import { ExecTrace } from "../components/ExecTrace";
import { Markdown } from "../components/Markdown";
import { Button, Input, Field, Panel, Dot, EmptyState, useToast } from "../ui";
// 安全文件名:去掉路径不安全字符,限长。
@@ -130,7 +131,7 @@ export function ReportView({ identity }: { identity: Identity }) {
}
>
{out ? (
<pre className="whitespace-pre-wrap break-words font-sans text-sm leading-relaxed text-slate-300">{out}</pre>
<Markdown text={out} className="text-sm" />
) : (
<EmptyState icon={FileText} title="尚未生成报告" desc="输入主题并点击「生成报告」,这里将实时显示规划与撰写过程。" />
)}
@@ -1,5 +1,6 @@
import { Activity, FileText } from "lucide-react";
import { ExecTrace } from "../components/ExecTrace";
import { Markdown } from "../components/Markdown";
import { deriveNodes, type RunState } from "../lib/run";
import { Panel, Dot, EmptyState } from "../ui";
@@ -42,7 +43,7 @@ export function RunsView({ run }: { run: RunState }) {
<Panel title="模型输出" icon={FileText}>
{run.output ? (
<pre className="whitespace-pre-wrap break-words font-sans text-sm leading-relaxed text-slate-300">{run.output}</pre>
<Markdown text={run.output} className="text-sm" />
) : (
<EmptyState
icon={Activity}