目标:在
ai-electron/frontend里新开一个独立包,基于已集成的 Codex 基座,做一个数据分析类的对话产品。 约束:不复用src/ai/的聊天代码;新建代码文件一律codex前缀;业务/后端接口ai-server不动。 版本号用于跟踪进度:每个版本一次提交 + 一次验收,未验收不进下一版。
ai-electron/electron/)| 层 | 文件 | 状态 |
|---|---|---|
| Controller | controller/codexCtl.ts |
已有,ee-core 自动注册,统一返回 {success, data} |
| Service | service/codex/{codexRuntime,codexLocator,codexHome,eventLog,eventMapper,approvalBroker,mcpService,skillService,providerService,jsonRpcPeer}.ts |
已有 |
| 推送通道 | codex/event、codex/status、codex/approval、codex/approval-closed、codex/diagnostic |
已有 |
| 渲染进程 IPC 封装 | src/ai/api/codexApi.ts |
已有(非聊天代码,属基础设施) |
已可直接调用的方法:ping / status / start / stop / restart / listModels / probeProvider / applyProvider / clearProvider / mcpList|Save|Remove / skillList|Read|InstallFolder|InstallZip|Remove|SetEnabled|OpenFolder / threadStart / turnRun / turnInterrupt / threadUnsubscribe / approvalResolve / eventsRead / logsTail。
AgentEvent 形状(前端唯一渲染输入):
{ id, threadId, turnId, kind: 'lifecycle'|'assistant'|'thought'|'tool'|'file'|'plan'|'error', title, message, timestamp, method?, itemId?, isDelta? }
渲染规则:同 id 覆盖,isDelta=true 追加。
codex/approval / codex/approval-closed,但 codexApi.ts 里只有 onCodexEvent/onCodexStatus/onCodexDiagnostic,没有 onCodexApproval。→ 需补。codexCtl 里没有任何文件读写。产物=Codex 在 cwd(默认 %data%/codex-data/workspace)里生成的文件。要做列表 / 预览 / 另存为下载,必须新增主进程能力(沙箱限定在 workspace 内)。→ 需新增 codexArtifactCtl。eventsRead(threadId),没有 threadList。会话列表只能前端自持(localStorage 存 threadId + 标题 + 时间)。→ 前端方案,后端不加接口。config.default.ts 里 nodeIntegration: true + contextIsolation: false,产物能力也可以走 IPC(推荐),不依赖 fs 直读。src/core/store/modules/menu.json(permission.ts 直接 import)。src/core/router/helper/routeHelper.ts 的 explicitDynamicViewMap(AI 三个页面已在此登记),不走 glob。所以新增一个页面 = 改 2 个文件 + 建 1 个视图。
包根:ai-electron/frontend/src/codex/(与 src/ai/、src/graph/ 平级)。所有新建文件 codex 前缀。
src/codex/
codexIndex.ts # 包出口(唯一不是 index.ts 的地方:文件名也要 codex 前缀)
styles/codexTheme.less # 设计 token:--codex-*(--ai-* 那套不依赖,自建)
types/codexTypes.ts # 消息模型 / 块模型 / 产物模型
api/codexApi.ts # IPC 封装(从 src/ai/api/codexApi.ts 搬家 + 补审批通道)
api/codexArtifactApi.ts # 产物 IPC 封装
store/codexChatStore.ts # pinia:运行时状态 / 会话列表 / 消息流 / 产物
utils/codexEventReducer.ts # AgentEvent → 消息模型
utils/codexBlockParser.ts # 围栏协议解析
utils/codexEcharts.ts # echarts 按需注册
utils/codexArtifact.ts # 产物类型判定、大小/时间格式化
utils/codexReportExport.ts # 报告导出(md/html/png/xlsx)
utils/codexReportTemplate.ts # 报告模板
components/codexSessionSidebar.vue
components/codexChatToolbar.vue # 状态条:运行时/模型/工作目录
components/codexMessageList.vue
components/codexMessageItem.vue
components/codexComposer.vue
components/codexProcessTimeline.vue
components/codexToolCard.vue
components/codexApprovalDialog.vue
components/codexBlockRenderer.vue
components/codexMarkdownBlock.vue
components/codexCodeBlock.vue
components/codexTableBlock.vue
components/codexJsonBlock.vue
components/codexChartBlock.vue
components/codexGraphBlock.vue
components/codexArtifactPanel.vue
components/codexArtifactPreview.vue
components/codexDiagnosticDrawer.vue
views/codexAnalysis/codexAnalysis.vue # 页面入口
包外仅新增 2 处登记(不改现有逻辑):
routeHelper.ts → explicitDynamicViewMap['/codexAnalysis/codexAnalysis']core/store/modules/menu.json → 新增菜单项(挂在 10263 "AI 数据分析" 分组下,标题「Codex 分析」,path/component/url 均为 /codexAnalysis/codexAnalysis)src/codex/index.ts、styles/codexTheme.less、views/codexAnalysis/codexAnalysis.vue(三栏骨架:会话栏 / 消息区 / 产物栏,内容为占位)、routeHelper.ts + menu.json 两处登记。pnpm build 通过;pnpm type:check 本包文件 0 报错。api/codexApi.ts(搬家 + 补 onCodexApproval / onCodexApprovalClosed)、store/codexChatStore.ts、components/codexSessionSidebar.vue、components/codexChatToolbar.vue。ping/status 门禁(未就绪 → 提示去「插件」页配模型);threadStart 新建会话;会话列表 localStorage 持久化(threadId / 标题取首条输入 / 时间);切换会话走 eventsRead 恢复现场。utils/codexEventReducer.ts、components/codexMessageList.vue、codexMessageItem.vue、codexComposer.vue。turnRun 提交;订阅 codex/event + codex/status + codex/diagnostic;assistant 增量聚合、思考/工具/文件/计划/错误分列;停止 = turnInterrupt;贴底滚动 + 复制 + 重发;cwd 可由用户选目录。status 变化实时反映到顶部。utils/codexBlockParser.ts、components/codexBlockRenderer.vue、codexMarkdownBlock.vue、codexCodeBlock.vue、codexTableBlock.vue、codexJsonBlock.vue。parseMessageContent.ts):
```echarts ``` 、 ```graph ``` 、 ```table ``` 、 ```sql ``` 、 ```json ``` 、 ```report ```
- 验收:markdown 表格/代码块(行号+复制)/JSON 折叠 正常;超长表格可翻页 + 导出 CSV。
### v1.4.0 — 图表与关系图
- 交付:components/codexChartBlock.vue、codexGraphBlock.vue、utils/codexEcharts.ts。
- 内容:echarts 按需注册 + 自适应 + 全屏 + 导出 PNG;关系图节点/边/缩放/筛选 + 导出。
- 验收:模型输出 echarts /graph 时能渲染、能全屏、能导出图片。
### v1.5.0 — 过程可视化:工具与审批
- 交付:components/codexProcessTimeline.vue、codexToolCard.vue、codexApprovalDialog.vue。
- 内容:一次 turn 的 lifecycle/thought/tool/plan 折叠成时间线;命令与输出折叠面板、diff 高亮;消费 codex/approval → approvalResolve(accept / acceptForSession / decline / cancel,含 answers 表单)。
- 验收:approvalPolicy=on-request 时能弹审批并把决策回传主进程。
### v1.6.0 — 产物:列表 / 预览 / 下载
- 交付(主进程,唯一需要动 electron 的一版):electron/controller/codexArtifactCtl.ts + electron/service/codex/codexArtifactService.ts(沙箱限定在会话 cwd 内,拒绝 .. 穿越)。
方法:list / readText / readBase64 / saveAs / revealInFolder / open。
- 交付(前端):api/codexArtifactApi.ts、utils/codexArtifact.ts、components/codexArtifactPanel.vue(目录树 + 大小/时间 + 新产物角标 + 刷新)、codexArtifactPreview.vue(md / html / 代码 / 图片 / pdf / 表格 六类预览)。
- 验收:Codex 产出的文件出现在产物栏,可预览、可另存为。
### v1.7.0 — 报告生成与导出
- 交付:utils/codexReportTemplate.ts、utils/codexReportExport.ts。
- 内容:导出 md / html / png(html2canvas)/ xlsx(xlsx)—— 复用仓库已有依赖,实现自写(不复用 src/ai/utils/reportExport.ts)。报告含:标题、时间、结论、图表快照、数据附表。
- 验收:一键导出可用,图表与表格进报告。
### v1.8.0 — 会话恢复与诊断
- 交付:components/codexDiagnosticDrawer.vue + store 持久化完善。
- 内容:消息流落盘(消息 + 过程事件)、eventsRead 恢复、logsTail 诊断抽屉、失败重试与错误码文案、runtime 未就绪禁用输入。
- 验收:刷新页面后会话与过程可完整恢复。
### v1.9.0 — 打磨与端到端联调
- 内容:快捷键、空态引导 + 示例 prompt、窄屏适配、loading 骨架、错误边界。
- 验收:完整走通「提问 → 过程 → 图表/关系图 → 产物 → 报告下载」;pnpm type:check(本包 0 报错)+ pnpm build 通过。
---
## 四、v2.0.0 — 数据分析增强(计划 + 实施)
> 定位:v1.x 解决「能用」,v2.0 解决「日常顺手」。全部在前端闭环,不动 ai-server。
> 版本号继续递进,每个子版本单独可验收。
### 前置修正(v1.9.1)——先补 v1.x 的两处偏差
| # | 内容 | 交付 | 验收 |
| --- | --- | --- | --- |
| v1.9.1 ✅ | ① 关系图导出成图片;② HTML 报告内嵌真实图表图片 | 新增 utils/codexVisualRegistry.ts(内容哈希 → 图片提供者的注册表);codexGraphBlock.vue 增加 captureImage() 与「导出图片」;codexReportTemplate 的 HTML 分支改为 <img> 内嵌 data URL,取不到时回退折叠 JSON | 关系图能导出 PNG;导出的 HTML 报告里图表/关系图是图片,单文件可离线打开 |
### v2.0.0 子版本
#### v2.0.1 — 分析模板库
- 问题:每次都要重新组织提问措辞,高频分析(概览 / TopN / 时序 / 资金流向)无法复用。
- 交付:utils/codexTemplateLibrary.ts(预置模板 + 自定义模板 + localStorage CRUD)、components/codexTemplatePanel.vue(抽屉:分组列表、搜索、一键填入、保存当前输入为模板、删除自定义)。
- 预置模板(贴合案件数据研判场景,8 条):数据概览、字段画像与空值排查、TopN 排行、时序趋势、资金流向链路、时空碰撞、异常值排查、结论报告成稿。
- 验收:抽屉里选模板能填入输入框;自定义模板保存后重启仍在;预置模板不可删除。
#### v2.0.2 — 工作目录管理
- 问题:目录只能选一次、忘了上次选的是哪儿;换数据就得手动翻文件夹。
- 交付:store 增加 recentCwds(去重、上限 10、localStorage)、components/codexWorkspacePicker.vue(弹窗:最近目录列表 + 原生选择 + 一键「用该目录新建会话」+ 移除记录)。
- 验收:选过的目录进入最近列表;能从列表直接新建会话并落到该目录;目录被删/不可用时给出明确提示。
#### v2.0.3 — 多会话并行
- 问题:submitting 是全局单飞,A 会话跑着就没法去 B 会话提问,切走等于干等。
- 交付:store 把 submitting: boolean 改为 runningThreads: string[],新增 isThreadRunning();send() 只拦「同一会话重复提交」;侧栏会话行显示运行中点;工具栏显示在跑会话数;输入区按当前会话判断可用性。
- 验收:在 A 会话发问后切到 B 会话可继续发问;两个会话的事件互不串台;切回 A 能看到它自己的增量输出。
#### v2.0.4 — 会话内检索与定位
- 问题:长会话翻历史靠滚动。
- 交付:消息流顶部检索条(codexMessageList 内),关键词高亮 + 上/下跳转 + 命中计数。
- 验收:输入关键词能逐个跳转到命中位置并高亮。
#### v2.0.5 — 案件工作空间联动
- 问题:案件的数据文件都在后端的案件工作空间里;Codex 用客户端默认目录时看不到案件数据,每次都得手动指路,等于把「工作空间」这件事交给了用户记。
- 先摸清的事实:后端 PathConst.WORKSPACE = <user.dir>/QingJian/workspace,案件工作空间即 workspace/<案件ID>
(CaseInfoService.create() 建案时就已经 FileUtil.mkdir 建好,duckdb 也放在里面)。
但 CaseInfo 的 db / db_path 都标了 @JsonIgnore,工作空间路径没有回传给前端。
- 交付
- 后端(ai-server,纯增量,不改既有逻辑):
① CaseInfo 增加非持久化字段 workspacePath(@TableField(exist = false),MyBatis-Plus 不落库);
② CaseInfoService 增加 workspacePath(caseId) 与 fillWorkspacePath(caseInfo)(与建案时同一套推导,顺带 mkdir 兜底);
③ 在 listByOwner() / current() 返回前置值,CaseInfoController.open() 回传前补一次(该接口原本又 getById 取了一次,正好在返回前补)。
- 前端:plat/api/case/caseApi.ts 的 CaseInfo 增 workspacePath?: string;
codex store 增 caseWorkspace,cwd 解析优先级改为
会话自身 cwd → 案件工作空间 → 用户手选目录 → 客户端默认目录;
工作目录卡片与目录弹窗标明当前来源(案件工作空间 / 手动目录 / 客户端默认)。
- 验收:进入案件后新建会话,Codex 的 cwd 即该案件工作空间,产物栏直接列出案件数据文件;切换案件后新会话跟着切;没有案件时仍回落到手动目录 / 客户端默认目录。
- 风险与理由:这是本项目里唯一一次动 ai-server(此前约定不动后端)。用户本轮明确要求「后端返回该案件的工作空间」,故只做「加一个非持久化字段 + 返回前置值」,不触碰数据源、权限、校验等任何既有逻辑。
### v2.0.0 完成情况
| 版本 | 交付 | 状态 |
| --- | --- | --- |
| v1.9.1 | utils/codexVisualRegistry.ts(内容哈希 → 图片提供者);codexGraphBlock 的 captureImage() + 「导出图片」;codexReportTemplate.visualBlockToHtml() 内嵌 <img>;downloadCodexDataUrl() 收敛三处重复的 base64→Blob 逻辑 | ✅ |
| v2.0.1 | utils/codexTemplateLibrary.ts(8 条预置模板 + 自定义模板 localStorage CRUD)、components/codexTemplatePanel.vue | ✅ |
| v2.0.2 | store 的 recentCwds / rememberCwd / removeRecentCwd、components/codexWorkspacePicker.vue | ✅ |
| v2.0.3 | store 的 runningThreads / isThreadRunning、侧栏运行中呼吸点、工具栏运行中会话数 | ✅ |
| v2.0.4 | codexMessageList 会话内检索(粘顶检索条、命中计数、上/下一条居中跳转、utils/codexHighlight.ts 文本级关键词高亮)、codexMessageItem 命中强调条 | ✅ |
| v2.0.5 | 后端:CaseInfo.workspacePath(@TableField(exist = false))、CaseInfoService.workspacePath(caseId) / fillWorkspacePath(caseInfo)(在 listByOwner / current / CaseInfoController.open 返回前置值);前端:CaseInfo.workspacePath、store 的 caseId / caseWorkspace / cwdOverrides / syncCaseContext() / activeCwdSource,cwd 优先级改为「会话 → 案件手动覆盖 → 案件工作空间 → 客户端默认」,视图与目录弹窗标明来源 | ✅ |
### v2.0.0 验证结果(同前一轮口径)
| 项 | 结果 |
| --- | --- |
| 前端 pnpm type:check | 89 条 = 仓库既有基线,本包 0 报错 |
| 前端 pnpm build | exit=0 |
| 后端 mvn -o -DskipTests compile | exit=0;已用 javap 核验 CaseInfo.workspacePath 与 CaseInfoService.workspacePath/fillWorkspacePath 真的进了 class |
| 主进程 | 本轮未改 electron 代码,沿用上一轮 tsc --noEmit / 91 单测 / build-electron 全绿 |
### v2.0.0 实现要点(容易踩的地方)
- 关系图导出图片用 html2canvas 整块栅格化:节点是 HTML、连线是 SVG,手撸 SVG 只能拿到半张图。
导出前 zoomToFit() 保证整图进框;报告内嵌用的缓存图用 scale=1 且不改用户当前视图。
- 图片提供者必须同步返回(注册表是同步取值),所以关系图走「延迟 600ms 后台截图 → 缓存 → 提供者读缓存」,
缓存没就绪时报告自动回退成折叠 JSON,不会出现空白图。
- 多会话并行把 submitting: boolean 换成 runningThreads: string[]:
只拦「同一会话重复提交」,不同会话各跑各的(事件本来就按 threadId 分流)。
输入区因此不再因别的会话在跑而禁用,只有当前会话在跑时按钮变「停止」。
- 不用 window.prompt:Electron 渲染进程不支持,模板命名改成抽屉里的行内表单。
- 关键词高亮不改已渲染的 DOM:手工替换文本节点会破坏 Vue 缓存的 vnode 引用,
下一次 patch 会把新文本写进已脱离文档的旧节点,表现为「内容卡住不更新」。
所以 markdown(v-html)走字符串替换(标签逐段跳过,天然不碰标签与属性),
提问气泡与代码块走插值切段加 class,两条路都不碰渲染后的 DOM。
### v2.0.0 交付物清单(供核对)
新增文件(前端 src/codex/,共 4 个,本轮第 4 个):
utils/codexVisualRegistry.ts、utils/codexTemplateLibrary.ts、components/codexTemplatePanel.vue、
components/codexWorkspacePicker.vue、utils/codexHighlight.ts。
改动文件:codexGraphBlock(导出图片 + 图片提供者)、codexChartBlock(登记图片提供者)、
codexReportTemplate(内嵌图片)、codexReportExport、codexFormat(downloadCodexDataUrl)、
codexChatStore(recentCwds / runningThreads / caseId / caseWorkspace / cwdOverrides)、
codexComposer(模板与目录入口、草稿上抛)、codexChatToolbar(检索入口、运行中会话数)、
codexSessionSidebar(运行中呼吸点)、codexMessageList(检索条)、codexMessageItem(命中态与关键词)、
codexBlockRenderer / codexMarkdownBlock / codexCodeBlock(关键词透传)、codexAnalysis.vue(装配)。
### 不在 v2.0.0 范围(需先确认前提)
- cwd 直连「当前案件数据目录」:需要先确认案件数据在本机是否有确定的落地目录(目前数据在 ai-server 侧,桌面端只有 codex-data / codex-home)。前提不明就不做,避免写死一个不存在的路径。
- SQL 结果直连预览:Codex 自己执行命令取数,客户端代执行 SQL 没有意义,跳过。
---
### 待定 v2.1.0+(已展开,见文末「八、v2.1.0 — 可用性补强与协作(可执行计划)」)
分析结论沉淀成可对比的快照、模板导出/导入(团队共享)、图表联动筛选、产物变更 diff;
另补一项实现缺口(运行参数被硬编码)与两项评估后不做的说明,详见第八节。
---
## 五、决策点
已拍板(2026-09-24 本次确认):
| # | 决策 | 结论 |
| --- | --- | --- |
| D1 | 视图文件名 | ✅ 严格全部 codex 前缀 → views/codexAnalysis/codexAnalysis.vue,菜单 component 写 /codexAnalysis/codexAnalysis |
| D4 | 产物能力放哪 | ✅ 新建 electron/controller/codexArtifactCtl.ts(允许新增主进程代码,沙箱限定在会话 cwd 内) |
| D8 | 执行节奏 | ✅ 逐版本做完停下 review,未验收不进下一版 |
| D3 | 会话列表来源 | ✅ 前端自持(localStorage),本期不动后端接口 |
待定(不阻塞 v1.0.0,到对应版本前再确认):
| # | 决策 | 选项 | 我的建议 |
| --- | --- | --- | --- |
| D2 | IPC 封装放哪 | A) 新包自持 + 老文件一行转发src/ai/api/codexApi.ts | ✅ 已按 A 落地:src/codex/api/codexApi.ts 为唯一实现,src/ai/api/codexApi.ts 改为 export * from '@/codex/api/codexApi' |
| D5 | 报告导出实现 | A) 自写 codexReportExport.tssrc/ai/utils/reportExport.ts | ✅ 已按 A 落地:只复用 xlsx / html2canvas / downloadByData 这些底层依赖 |
| D6 | 富内容块协议 | echarts/graph/table/json/report 围栏;要不要 mermaid | ✅ 本期不引入 mermaid |
| D7 | 菜单挂哪 | A) 挂 10263 分组ai-server 后端、src/ai/** 的聊天代码(仅 D2 里 codexApi.ts 可能变成转发,行为不变)。
- 验证:每版 pnpm build(cwd ai-electron/frontend)+ pnpm type:check。
注意:type:check 仓库本身有约 89 条既有报错(集中在 call/trans/graph/otg/person),判断标准是本包文件 0 报错,不看退出码。
- 清理:不留临时脚本、临时日志。
---
## 七、完成情况(v1.0.0 → v1.9.0 全部落地)
### 前端新包 src/codex/(31 个文件,全部 codex 前缀)
| 层 | 文件 |
| --- | --- |
| 入口 / 样式 | codexIndex.ts、styles/codexTheme.less |
| 类型 | types/codexTypes.ts、types/codexModuleShims.d.ts(markdown-it 无类型声明的最小补丁) |
| API | api/codexApi.ts(+ 审批通道)、api/codexArtifactApi.ts |
| 状态 | store/codexChatStore.ts |
| 工具 | codexEventReducer、codexBlockParser、codexMarkdown、codexEcharts、codexFullscreen、codexArtifact、codexReportTemplate、codexReportExport、codexFormat |
| 组件 | codexChatToolbar、codexSessionSidebar、codexMessageList、codexMessageItem、codexComposer、codexProcessTimeline、codexToolCard、codexApprovalDialog、codexBlockRenderer、codexMarkdownBlock、codexCodeBlock、codexTableBlock、codexJsonBlock、codexChartBlock、codexGraphBlock、codexArtifactPanel、codexArtifactPreview、codexDiagnosticDrawer |
| 视图 | views/codexAnalysis/codexAnalysis.vue |
### 主进程新增
- electron/service/codex/codexArtifactService.ts —— 产物读写,双重边界:root 白名单(落盘 codex-data/artifact-roots.json,重启后仍可读)+ 路径穿越校验;只读不写、不提供删除。
- electron/controller/codexArtifactCtl.ts —— 7 个方法:list / readText / readBinary / saveAs / reveal / open / openRoot。
- codexCtl.ts 三处增量(不改变既有行为):threadStart 返回 cwd 并登记产物 root、turnRun 登记可选 cwd、新增 defaultWorkspace。
### 行为要点
- 会话:threadStart 拿 threadId + 真实 cwd,列表存 localStorage,切换走 eventsRead 回读;删除只从本地列表移除(不删 Codex 落盘历史)。
- 提问落盘:Codex 的事件流里只有 agent 侧输出,eventsRead 回读不到我们发出去的文本 —— 所以提问另存 codex.prompts.v1,否则刷新后会「只剩回复、看不到问过什么」。
- 事件:codex/event 按 threadId 缓存,同 id 覆盖、isDelta 追加;turn/completed 决定回合结局(done / error / interrupted)。
- 审批:codex/approval → 弹窗 → approvalResolve(accept / acceptForSession / decline / cancel),input 类支持 questions 表单;遮罩点击等同拒绝(避免静默挂到 2 分钟超时)。
- 围栏协议:```echarts ```graph ```table ```json ```report ```,解析失败一律回退成代码块展示原文。
- 产物:回合结束后对比上一轮快照,新出现的文件打「新」角标;手动刷新即清除。
- 导出:Markdown / HTML(自包含单文件)/ Excel(表格合集)/ PNG(html2canvas 截图真实 DOM,图表关系图一起进图)。
### 与计划的偏差(如实记录)
| 计划原文 | 实际实现 | 状态 |
| --- | --- | --- |
| v1.4.0「关系图…+ 导出」/ 验收「能导出图片」 | 初版只给了导出数据(JSON) | ✅ v1.9.1 已补齐:按钮「导出图片」,html2canvas 栅格化整块图谱(节点是 HTML、连线是 SVG,只有整块 DOM 截图能一次拿全),导出前自动适配画布保证整图进框 |
| v1.7.0「报告含…图表快照」 | 初版 HTML 报告里图表是折叠的 ECharts option | ✅ v1.9.1 已补齐:块组件按内容哈希登记图片提供者(utils/codexVisualRegistry.ts),HTML 报告内嵌真实 <img src="data:...">,单文件离线可看;取不到图时回退折叠 JSON |
| v1.8.0「消息流落盘(消息 + 过程事件)」 | 过程事件走主进程 eventsRead 回读(本来就有落盘),本地只落提问 | 等价或更好,但与原文描述不同 |
| v1.5.0「diff 高亮」 | 文件变更的 patch 用代码块展示,未做行级 diff 染色 | 未做(可读性略低) |
| v1.9.0「端到端联调」 | 只做了编译/类型/单测三重验证,未在真机 GUI 里点一遍全链路 | 待你实际跑一次确认交互 |
> Markdown 报告仍保留原始围栏块(<img> 的 data URL 会让 .md 变成几十 MB,不适合再加工场景),
> 需要图片就走 HTML / PNG 导出。
### 验证结果
| 项 | 命令 | 结果 |
| --- | --- | --- |
| 前端类型 | pnpm type:check | 89 条(= 仓库既有基线),codex 包 0 报错 |
| 前端构建 | pnpm build | exit=0,产出 codexAnalysis-*.{js,css} |
| 主进程类型 | npx tsc --noEmit(cwd ai-electron) | exit=0,0 报错 |
| 主进程单测 | npm test | 6 文件 / 91 用例全通过 |
| 主进程打包 | npm run build-electron | exit=0,codexArtifactCtl 已进 bundle |
### 环境提示(worktree 首次使用)
- 本仓库 ai-electron 是 npm 项目(只有 package-lock.json,node_modules 无 .pnpm),不能用 pnpm 装;且 package-lock.json 被 gitignore,worktree 里需要从主仓库拷。
- frontend 是 pnpm 项目,首次安装要用 pnpm install --ignore-scripts(esbuild postinstall 会因 EBUSY 失败并导致 .bin 不生成)。
---
## 八、v2.1.0 — 可用性补强与协作(可执行计划)
> 定位:v2.0 把「进案件 → 工作空间 → 取数出图」跑通了,v2.1 磨掉日常使用里真正硌手的地方。
> 执行原则沿用:前端闭环优先、不动 ai-server、每子版本一次验收(pnpm type:check + pnpm build)、做完停下 review。
### 8.1 版本总览与执行顺序
| 顺序 | 版本 | 主题 | 依赖 | 改动面 |
| --- | --- | --- | --- | --- |
| 1 | v2.1.1 | 运行参数显式化(补 v2.0 实现缺口) | 无 | store + composer + 类型,约 5 个文件 |
| 2 | v2.1.5 | 产物增强:搜索 / 类型筛选 / 本轮变更 | 产物服务(已有) | 产物栏 + 事件归并,约 4 个文件 |
| 3 | v2.1.2 | 块级「钉到看板」 | 块注册表 codexVisualRegistry(已有) | 新看板组件 + 3 个块加按钮,约 6 个文件 |
| 4 | v2.1.3 | 结论快照与对比 | parseCodexBlocks(已有) | 新快照 + diff 模块 + 抽屉,约 4 个文件 |
| 5 | v2.1.4 | 模板 / 会话列表 导入导出 | 模板库(已有) | 模板抽屉 + 会话栏,约 3 个文件 |
排序理由:先补「运行参数被硬编码」这个实现缺口(它关系到安全语义,最该先修),再做低风险、无新 UI 的产物增强,
最后做三个带新界面的(看板 / 快照 / 导入导出)。
---
### 8.2 v2.1.1 — 运行参数显式化
问题:v2.0 里 threadStart / turnRun 的 sandbox 与 approvalPolicy 是我硬编码的
(workspace-write + on-request)。用户想做「只读分析」(更安全)或「无人值守」时无从下手。
这不是新需求,是实现缺口。
交付物
- 类型:CodexSessionMeta 增 sandbox: CodexSandbox、approvalPolicy: CodexApprovalPolicy(默认沿用现值,兼容已有 localStorage 数据)。
- store:setSessionRunOptions(threadId, { sandbox, approvalPolicy });send() 与 createSession() 从会话取参下发(不再写死)。
- UI:components/codexRunOptionsPanel.vue —— composer 的 popover(a-popover + 全局类名,避开 teleport 作用域问题),
两个下拉:沙箱模式、审批策略,各带一句后果说明。
- 工具栏:非默认参数时显示徽标(只读 / 全权 / 免审批),点击可回到该面板。
验收
- 切到 read-only 后让 Codex 写文件,应被拒绝(Codex 侧报错,前端如实显示)。
- 切到 never(免审批)后不弹审批弹窗。
- 重启客户端后参数仍在;徽标与实际参数一致。
决策点:D1 —— 参数按会话记还是全局默认?→ 建议按会话记 + 一份全局默认(新会话继承全局默认)。
风险:danger-full-access 是真危险项。
→ 对策:选它或选 never 时 Modal.confirm 二次确认(文案写清后果),且不允许作为全局默认被静默继承。
---
### 8.3 v2.1.5 — 产物增强(搜索 / 筛选 / 本轮变更)
问题:产物栏只能一层层翻目录;Codex 改了哪些文件、这轮新增了什么,看不出来(v2.0 只给新文件打了「新」角标)。
交付物
- utils/codexArtifactChange.ts:把 kind === 'file' 的事件按路径聚合成「本轮回合变更清单」。
路径来源:item/fileChange/patchUpdated 的 patch 里形如 *** Update File: <path> / *** Add File: 的行;
item/completed(fileChange 类型)里 changes 的路径字段作为补充。
- 产物栏:搜索框(按文件名过滤)、类型筛选(全部 / 表格 / 图片 / 报告 / 代码 / 其他)、
「本轮变更」分区(列出改动文件 + 点击展开 patch,patch 用 codexCodeBlock 渲染)。
- store:artifactChanges 在回合结束时落定,手动刷新即清空。
验收
- 让 Codex 改一个已有文件:产物栏「本轮变更」能列出它,点开能看到 patch。
- 搜索框输入即过滤;类型筛选切换正确。
风险:patch 的路径提取依赖 Codex 的输出格式。
→ 对策:解析失败一律静默降级 —— 只显示原始 patch,不猜路径、不误报、不抛错。
决策点:D2 —— patch 里可能带真实数据片段,是否默认折叠?→ 建议默认折叠,点开才展开。
---
### 8.4 v2.1.2 — 块级「钉到看板」
问题:一次分析常产出多个图表与表格,要滚回去对照很累;右侧产物栏又被文件占着。
交付物
- 表格 / 图表 / 关系图三个块头加「钉住 / 取消钉住」。
- components/codexBoardPanel.vue:产物栏上方新增可折叠「看板」分区,把钉住的块按原样渲染在一起,
支持上下排序、单个取消、一键清空。
- 持久化:只存「内容哈希 + 类型 + 标题」(复用 codexTextKey),切会话 / 刷新后按哈希从当前会话内容里找回块;
内容已变(哈希对不上)时把该钉住项标为失效并允许移除 —— 不假装还在。
验收
- 钉 3 个块 → 切到别的会话再切回来,看板仍在。
- 表格与图表在看板里都能正常渲染(图表自适应宽度、可导出 PNG)。
- 取消钉住即从看板移除。
风险:看板里重复渲染 ECharts 会翻倍开销。
→ 对策:看板折叠时用 v-if 不渲染、最多钉 6 个、超出时提示先取消。
决策点:D3 —— 看板放右侧产物栏上方,还是底部抽屉?→ 建议产物栏上方(与「分析的产物」同侧;窄屏本就收起产物栏,行为一致)。
---
### 8.5 v2.1.3 — 结论快照与对比
问题:同一个问题隔几天再问一次,两次结论的差异只能靠人眼在长对话里比对。
交付物
- utils/codexSnapshot.ts:把会话的(提问 + 回复正文 + 表格数据)存成本地快照,键 codex.snapshots.v1;
只存文本与表格、不存图片,单条上限 200 KB(超出截断并标注),可命名、可删除。
- utils/codexTextDiff.ts:最简行级 LCS diff,输出 {type: 'same'|'add'|'del', text} 序列。
- components/codexSnapshotPanel.vue(抽屉):存快照、快照列表、勾两个 → 并排 diff 视图。
- 快照可导出 Markdown(复用 codexReportExport)。
验收
- 存两次快照 → 并排看到新增/删除行被高亮。
- 删除快照;重启客户端后快照仍在。
风险:localStorage 配额(快照文本可能较大)。
→ 对策:单条 200 KB 上限 + 最多 20 条 + 超限时提示先删旧快照;写入失败静默降级并提示。
决策点:D4 —— diff 配色。建议新增绿 / 删除红(这是通用 diff 语义,与本项目「股价涨红跌绿」属不同语境,不冲突)。
若你希望和项目色系保持一致,也可以改成「新增=主色、删除=警告色」,请在验收前定。
---
### 8.6 v2.1.4 — 模板 / 会话列表 导入导出
问题:模板与会话列表都只在本机 localStorage;换机器、重装客户端就没了,也没法给同事。
交付物
- 模板抽屉加「导出 / 导入」:导出 { version, exportedAt, templates[] } JSON;
导入时先把同名冲突列出来让用户确认覆盖还是跳过。
- 会话栏加「导出会话列表 / 导入」:只导出元数据(threadId / 标题 / cwd / 模型 / 时间 / 回合数),
不含消息正文(正文在主进程事件日志里,导出没意义)。
- 导入按 threadId 去重,已存在则跳过并给出统计(导入 N 条 / 跳过 M 条)。
验收
- 导出 → 清空(或换目录)→ 导入,模板与会话列表恢复。
- 重复导入不产生重复项;冲突处理和提示一致。
风险:导入的会话 threadId 在本机 Codex 侧并不存在 → 点开必然读不到事件。
→ 对策:导入的会话打「来自外部」标记,打开时明确提示「本机无该会话记录」,不装作能恢复(与 v2.0「删除只从本地列表移除」同一套诚实原则)。
决策点:D5 —— 是否顺手把会话元数据下沉到主进程文件(codex-data/sessions.json),彻底摆脱 localStorage?
→ 建议本版不做(导入导出已覆盖跨机场景,下沉单独排 v2.2.0,避免这次改动面过大)。
---
### 8.7 评估后不做(附理由,避免以后重复讨论)
| 登记项 | 结论 |
| --- | --- |
| 图表联动筛选 | 做不出可靠交互:图表与表格没有统一数据模型与字段映射,只能靠「图表 x 轴类目值 ∩ 表格某列值」这种启发式猜关联,猜错比不做更糟。替代:v2.1.2「钉到看板」解决「对照」这个真实诉求 |
| SQL 结果直连预览 | Codex 自己执行命令取数,客户端代执行 SQL 没有意义(v2.0 已判定,维持) |
| 消息级删除 / 编辑历史 | Codex 侧不支持删回合,前端删掉就是撒谎(v2.0 已判定,维持) |
### 8.8 决策点汇总(验收前需你确认)
| # | 决策 | 我的建议 |
| --- | --- | --- |
| D1 | 运行参数按会话记还是全局默认 | 按会话记 + 一份全局默认(新会话继承) |
| D2 | 产物 patch 是否默认折叠 | 默认折叠(可能含真实数据片段) |
| D3 | 看板位置:产物栏上方 / 底部抽屉 | 产物栏上方 |
| D4 | diff 配色:通用(新增绿/删除红)还是项目色系 | 通用 diff 语义(与股价红涨绿跌不同语境) |
| D5 | 本版是否下沉会话元数据到主进程 | 不在本版,排 v2.2.0 |
### 8.9 v2.2.0 候选(先登记,不展开)
- 会话元数据下沉主进程(codex-data/sessions.json),彻底摆脱 localStorage
- 产物打包导出 zip(需先评估是否引入 zip 依赖;现有 yauzl 只解压)
- 多会话标签页(现在靠侧栏切换)
- 主进程 threadList 对接(前提是 Codex 后续提供该接口;目前只有 eventsRead)
- 报告模板自定义(标题页、页眉页脚、单位信息)
---
## 九、v2.1.0 完成情况
### 9.1 交付清单
| 版本 | 新增文件 | 改动文件 |
| --- | --- | --- |
| v2.1.1 运行参数显式化 | components/codexRunOptionsPanel.vue | types/codexTypes.ts(CodexSandbox/CodexApprovalPolicy/CodexRunOptions 归位)、api/codexApi.ts(类型转出)、store(runDefaults / setRunDefaults / setSessionRunOptions / activeRunOptions,会话字段归一化)、codexComposer(挂载面板)、codexChatToolbar(参数徽标) |
| v2.1.5 产物增强 | — | utils/codexArtifactChange.ts(新)、codexArtifactPanel(容器重构 + 搜索 + 类型筛选 + 本轮变更) |
| v2.1.2 钉到看板 | components/codexBoardPanel.vue | store(board / toggleCodexBoardItem / isOnCodexBoard / removeCodexBoardItem / moveCodexBoardItem / clearCodexBoard / boardBlocks / boardFull)、三个可视化块(钉住按钮)、codexAnalysis.vue(aside 容器) |
| v2.1.3 结论快照 | utils/codexTextDiff.ts、utils/codexSnapshot.ts、components/codexSnapshotPanel.vue | codexChatToolbar(快照入口)、codexAnalysis.vue |
| v2.1.4 导入导出 | — | codexTemplatePanel(导出 / 导入 + 冲突确认)、codexSessionSidebar(导出 / 导入 + external 标记 + 打开时如实提示)、store(exportSessionsJson / importSessionsJson) |
### 9.2 决策落地(按 8.8 的建议执行)
- D1 运行参数按会话记 + 一份全局默认:会话存 sandbox / approvalPolicy,新会话继承 runDefaults,「设为新会话默认」显式落盘。
- D2 产物 patch 默认折叠,点开才渲染。
- D3 看板放在产物栏上方,折叠时用 v-if 整块不渲染。
- D4 diff 用通用语义:新增绿 +、删除红 −(与股价红涨绿跌不同语境)。
- D5 会话元数据不在本版下沉,排 v2.2.0。
### 9.3 验证结果
| 项 | 命令 | 结果 |
| --- | --- | --- |
| 前端类型 | pnpm type:check | 89 条 = 仓库既有基线,本包 0 报错 |
| 前端构建 | pnpm build | exit=0,产出 codexAnalysis-*.{js,css} |
| 主进程 / 后端 | 本轮未改动 | 沿用上一轮 tsc --noEmit / 91 单测 / build-electron / mvn compile 全绿 |
### 9.4 本轮顺带发现(既有缺陷,非本次引入)
vite-plugin-theme-vite3 生成的暗色主题文件里,自定义属性的 -- 前缀被抹掉了:
dist/assets/app-antd-dark-theme-style.e3b0c442.css
grep -F -- "--codex-bg" → 0 处
grep -F -- "ai-text" → 有(且同样没有 --)
即暗色模式下 --ai-*、--codex-*、--jeesite-* 这些自定义属性都不会被覆盖,
页面在暗色主题下仍然套用浅色 :root 的值(antd 类名那部分是正常的)。
- 影响:暗色主题下自定义 token 不生效 —— 对既有 --ai-* 模块与新的 --codex-* 模块同等影响。
- 是否本次引入:不是。--ai-* 在 v2.1 之前就是这个状态,本次只是把 codex 模块也纳入了同一套机制。
- 修与不修:修它要动构建期的主题插件(build/theme/* + vite-plugin-theme-vite3 的产物处理),
属于构建管线改造,风险与收益不匹配,因此本次只记录、不动手;需要时单独立项。
### 9.5 变更记录
| 时间 | 变更 |
| --- | --- |
| 2026-09-24 晚 | 工作目录改为纯代码决定、界面不可改:删除 codexWorkspacePicker 与 store 的 cwdOverrides / recentCwds / setWorkspaceDir 等,cwd 优先级简化为「会话 cwd → 案件工作空间 → 客户端默认」,界面只读展示;同时修复产物栏「该目录不是本客户端的会话工作目录,已拒绝访问」(requireAllowedRoot 对绝对路径且真实存在的目录自动补登记,解决「还没有会话就列产物」的时序问题) |
| 2026-09-24 晚 | 移除「检索」与「快照」两个功能(用户要求):删除 codexMessageList 的检索条、codexMessageItem 的命中态、codexMarkdownBlock / codexCodeBlock 的关键词高亮透传、工具栏两个按钮,以及 utils/codexHighlight.ts、utils/codexSnapshot.ts、utils/codexTextDiff.ts、components/codexSnapshotPanel.vue 四个文件。v2.0.4 的「会话内检索」与 v2.1.3 的「结论快照」就此下线;保留产物栏自己的文件名筛选、模板库搜索、关系图节点搜索(这些是各自的过滤功能,与被移除的会话检索无关)。包体积 45 → 41 文件 |