# Task Plan
## Goal
重做客户端“导入招标文件/标书解析”页面:标题显示配置中的文件解析方式;页面主体用 Markdown 渲染上传招标文件直接提取出的内容;三种解析方式参考 `tools/mineru-agent-demo/`、`tools/mineru-accurate-demo/`、`tools/doc2markdown-node/`,优先完整还原 Node 版本地解析链路。
## Phases
- [completed] 1. 调研现有客户端导入页、配置读取、文件解析服务和三个工具示例。
- [completed] 2. 设计 Electron Main 文件解析服务分流:本地解析、MinerU 精准 API、MinerU Agent API。
- [completed] 3. 重做 DocumentAnalysisPage UI:配置标题、导入动作、Markdown 渲染内容。
- [completed] 4. 补齐类型、样式、Toast 错误提示和 Windows 兼容。
- [completed] 5. 运行构建和必要模块验证。
## Decisions
- 不引入降级策略;按用户配置的解析方式调用对应实现。
- 页面不加大标题横幅,只显示核心导入区和 Markdown 内容。
## Errors Encountered
| Error | Attempt | Resolution |
| --- | --- | --- |
| `technicalPlanStorage.load()` 返回值包含 `undefined` 导致 TypeScript 构建失败 | 第一次 `npm run build` | 将返回值归一为 `state || null` |
## Current Task: 技术方案缓存迁移
### Goal
将技术方案流程中用到的缓存从 Renderer `localStorage` 迁移到 Electron Main 侧文件存储,并更新 `client/开发说明.md` 的数据存储约定。
### Phases
- [completed] 1. 梳理现有 IPC、preload、类型声明和技术方案缓存实现。
- [completed] 2. 新增 Main 侧工作区存储服务与 IPC/preload API。
- [completed] 3. 将技术方案 Hook 改为异步读写 Main 侧缓存。
- [completed] 4. 移除技术方案 localStorage 缓存实现,更新开发说明。
- [completed] 5. 运行构建和必要模块验证。
## Current Task: 严格迁移后端目录生成容错机制
### Goal
严格参照 backend `/api/outline/generate-stream` 的 `OutlineService` 和 `OpenAIUtil.collect_json_response()`,降低 client Step03 目录生成失败率。
### Phases
- [completed] 1. 对比 backend 路由、service、prompt、JSON 修复工具和 client 当前目录生成逻辑。
- [completed] 2. 在 client `aiService.cjs` 中迁移生成、解析、校验、修复、重试一体化机制。
- [completed] 3. 在 client `outlineGenerationTask.cjs` 中迁移 backend prompt、标准化 schema 和 validator。
- [completed] 4. 将目录生成每一步改为通过 `collectJsonResponse` 执行修复和重试。
- [completed] 5. 运行模块加载、假 AI 流程和 `npm run build` 验证。
## Current Task: Step04 正文生成与 Word 导出
### Goal
实现客户端 Step04“生成正文”:参考 backend `/api/content/generate-chapter-stream` 为目录叶子章节生成正文;页面左侧显示目录树和生成状态,右侧显示正文内容;展示全局统计;技术方案 toolbar 在 Step04 改为“导出 Word”和“继续扩写”。
### Phases
- [completed] 1. 记录后端契约、旧前端实现和当前 client 架构要点。
- [completed] 2. 新增 Main 侧正文生成后台任务、任务类型、IPC/preload API。
- [completed] 3. 扩展技术方案状态与 Renderer 类型,合并后台正文任务事件。
- [completed] 4. 重做 `ContentEditPage` 为左目录树、右正文阅读器、全局统计和生成入口。
- [completed] 5. 实现独立客户端 Word 导出服务,并接入 Step04 toolbar。
- [completed] 6. 补充样式,运行模块加载、假任务和 `npm run build` 验证。
### Decisions
- 正文生成继续放到 Electron Main 后台任务,Renderer 只启动任务、订阅任务事件并展示状态。
- 仅为叶子节点生成正文,父节点状态由子节点聚合。
- 正文内容直接回写到 `outlineData.outline[*].content`,导出 Word 直接复用这份结构。
- Step04 toolbar 不再出现“下一步”,而是显示“导出 Word”和“继续扩写”。
### Errors Encountered
| Error | Attempt | Resolution |
| --- | --- | --- |
## Current Task: Step04 正文首批体验修正
### Goal
先修复已暴露的正文生成体验问题:规范 `
` 换行、去掉图例中的“AI 生成示意”、图片和图例居中、支持图片全屏查看,并在开发者模式下显示配图统计。
### Phases
- [completed] 1. 生成正文落盘前规范 `
`,并强化 Prompt 禁止随机 Mermaid 和 HTML 换行。
- [completed] 2. 修改图片图例文案为 `图:xxx`,前端和 Word 导出中图片/图例居中。
- [completed] 3. 正文 Markdown 图片支持点击全屏查看。
- [completed] 4. 后台任务写入配图统计,开发者模式下显示悬浮统计框。
- [completed] 5. 运行 `npm run build`、正文任务 smoke test、Word `
` 导出 smoke test 和 `git diff --check`。
### Decisions
- 表格单元格内的 `
` 统一规范为 `
`,前端通过 `rehypeRaw` 渲染换行,Word 导出把 `
` 转为真实 Word 换行。
- 当前批次不接 Mermaid 渲染和 Mermaid 导出,后续再做全局决策、Mermaid 与 AI 图二选一。
### Errors Encountered
| Error | Attempt | Resolution |
| --- | --- | --- |
| `SettingsPage.tsx` 导入 `ImageModelStatus` 时报共享类型入口未导出 | 第一次 `npm run build` | 在 `client/src/shared/types/index.ts` 补导出 `ImageModelStatus` |
## Current Task: Step04 Word 导出 Markdown 完整转换
### Goal
将 Step04 正文导出 Word 从“浅层 Markdown 文本处理”升级为“Markdown AST 到 Word 原生结构转换”,确保图片、表格、加粗、列表等 Markdown 语法在 `.docx` 中真实还原,而不是直接输出 Markdown 源文本。
### Phases
- [completed] 1. 检查现有 `exportService.cjs` 手写 docx XML 和 Markdown 正则解析实现。
- [completed] 2. 接入 `docx`、`unified`、`remark-parse`、`remark-gfm`、`image-size`。
- [completed] 3. 重写导出核心为 Markdown AST 递归转换 Word 段落、表格、列表、链接、图片等对象。
- [completed] 4. 保留现有 `exportWord(payload)` IPC 和保存对话框,不改 Renderer 调用链路。
- [completed] 5. 运行 docx buffer、表格文本、图片 media、`npm run build`、`npm audit` 和 `git diff --check` 验证。
### Decisions
- 不继续扩展正则和手写 Word XML,改用 `docx` 对象模型保证后续排版可控。
- 图片转换在 Electron Main 侧完成,支持 `data:image/*;base64`、`http/https`、`file://`、绝对路径和相对路径。
## Current Task: Step02/Step03 左侧进度块统一
### Goal
统一 Step02/Step03/Step04 左侧进度区域视觉和交互:Step02、Step03 使用 Step04 的 `content-outline-stats` 可折叠结构,并保持任务列表、生成日志和正文区域独立滚动。
### Phases
- [completed] 1. 将 Step02 解析进度迁入左侧任务面板顶部,并改为可折叠 `content-outline-stats`。
- [completed] 2. 将 Step03 生成进度从日志列表中拆出,迁入左侧面板顶部,并改为可折叠 `content-outline-stats`。
- [completed] 3. 调整 CSS 布局,确保 Step02 任务列表、Step02 阅读器、Step03 日志列表独立滚动。
- [completed] 4. 清理旧 `.outline-ai-*`、`.bid-analysis-progress-*` 未引用样式。
- [completed] 5. 运行 `npm run build` 和 `git diff --check` 验证。
| 普通 Node 环境 require `updateService.cjs` 时 `electron-updater` 立即访问 Electron app 并报 `Cannot read properties of undefined (reading 'getVersion')` | 第一次模块加载验证 | 将 `electron-updater` 改为 `setupAutoUpdate()` 内、且 `app.isPackaged` 后懒加载 |
| Windows 本地打包解压 `winCodeSign` 时因当前用户无符号链接权限失败 | 第一次 Windows unpacked 打包验证 | 当前阶段不做签名,关闭 `win.signAndEditExecutable`,避免触发 winCodeSign 资源编辑链路 |
| Actions 成功但 Release 没有产物 | 首次 `v2.0.1` 远程发布验证 | 改为 `electron-builder --publish never` 只构建,再用 `gh release upload --clobber` 显式上传产物,避免 `existingType=release publishingType=draft` 冲突 |
| Release 说明只有 `Full Changelog` | 首次 `v2.0.1` 远程发布验证 | 改为 workflow 用 `git log` 生成提交列表,并在 Release 已存在时用 `gh release edit --notes-file` 更新说明 |
| Actions `Build renderer` 报 `TS2688: Cannot find type definition file for 'plist'` | 修复后手动重跑 `v2.0.1` | 显式安装 `@types/plist`,并在 workflow 中补 `npm install --no-save @types/plist` 兼容旧 tag |
## Current Task: 知识库完整分析流程重构
### Goal
按讨论定版方案重构知识库上传分析:程序预筛并保留 `filtered_blocks.json`,将正文切为 block,AI 两轮抽取知识条目,调试页设置每批匹配条目数,分批用稳定前缀提交全文 block 匹配段落范围,补漏最多两轮,程序回填正文生成最终知识条目、舍弃段落和处理报告。
### Phases
- [completed] 1. 梳理现有知识库 Electron 服务、IPC、前端页面、数据落盘格式和 AI 工具。
- [completed] 2. 设计并实现 block 预处理、筛除日志、条目抽取、补充抽取、分批匹配、补漏和最终回填流程。
- [completed] 3. 扩展 IPC/preload/type,使上传后进入可调试的“待匹配”状态,并支持按用户输入批量继续分析。
- [completed] 4. 重做知识库前端调试页面和详情页面,展示 block/条目/覆盖率/舍弃统计,并触发分批匹配。
- [completed] 5. 补齐进度事件、错误提示、数据兼容处理和处理报告落盘。
- [completed] 6. 运行 CJS 模块检查、关键纯函数 smoke test 和 `npm run build` 验证。
### Decisions
- 不做最小可执行版本,直接实现完整流程。
- 程序直接筛除明显无价值内容,但保存 `filtered_blocks.json` 调试日志。
- AI 不输出正文,只输出条目标题摘要、匹配段落范围、补漏新增条目和舍弃段落。
- 条目 ID 由程序统一生成,AI 只返回标题和摘要。
- 分批匹配提示词采用稳定前缀:固定规则 + 固定全文 block 在前,变量知识条目批次在最后,以利用服务商 prompt cache。
- 分批匹配只要求强相关,不强制覆盖;补漏阶段再要求所有遗漏 block 明确归属为已有条目、新增条目或舍弃。
- 不做冲突检查,先观察实际效果。
### Errors Encountered
| Error | Attempt | Resolution |
| --- | --- | --- |
| planning skill 示例路径 `~/.opencode/.../session-catchup.py` 不存在 | 第一次 catchup | 改用实际路径 `~/.config/opencode/.../session-catchup.py` |
| `git diff --check` 报 `client/doc/知识库设计.md:63: new blank line at EOF` | 收尾检查 | 该文件非本次修改,按工作区保护规则未改动;本次修改文件仅有 LF/CRLF 提示 |
## Current Task: 标书查重目录分析首版
### Goal
在标书查重中新增纯程序目录查重:元数据提取完成后自动开始目录分析;基于已提取 Markdown 目录,不接 AI;招标文件只用于句子白名单,命中的投标目录项不计重复;投标文件之间做多级目录重复和相似度对比。
### Phases
- [completed] 1. 记录方案和现有查重服务接入点。
- [completed] 2. 扩展类型与工作区状态,加入目录分析结果。
- [completed] 3. 实现招标句子白名单、目录提取、多级树构建和重复比对。
- [completed] 4. 接入后台流程:元数据完成后启动目录分析,必要时等待正文提取结果。
- [completed] 5. 重做目录 Tab 展示:概览、相似度矩阵、文件目录树、重复组。
- [completed] 6. 运行 CJS/Preload 检查、构建和 diff 检查。
### Decisions
- 第一版不接 AI,不重新解析原始文件,直接读取 `duplicate-check/contents/*.md`。
- 招标文件不参与投标文件间比对,只拆句作为“不计重复”的白名单。
- 显式目录块优先,其次 Markdown 标题,最后语义标题兜底。
### Errors Encountered
| Error | Attempt | Resolution |
| --- | --- | --- |
| planning skill 示例路径 `~/.opencode/.../session-catchup.py` 不存在 | 第一次 catchup | 改用实际路径 `~/.config/opencode/.../session-catchup.py` |
| `git diff --check` 报 `client/doc/标书查重.md:54 trailing whitespace` | 收尾检查 | 该文件是既有/用户改动,本轮未修改,按工作区保护规则未处理;本轮修改文件仅有 LF/CRLF 提示 |
## Current Task: Analytics 远程公告通道
### Goal
基于 Cloudflare KV 在 `analytics/` 增加可管理的 Markdown 公告通道;客户端与现有 30 分钟版本检查共用轮询,但公告用独立弹窗展示,关闭后同一公告不再显示,除非后台发布新公告。
### Phases
- [completed] 1. 新增 Worker 公告公开读取与管理员读写接口,使用 KV binding `NOTICE_STORE`。
- [completed] 2. 在 Analytics Dashboard 增加公告管理 UI,支持读取、发布和停用最新公告。
- [completed] 3. 在客户端接入远程公告轮询,与版本检查共用定时器但展示互不干扰。
- [completed] 4. 更新 Analytics 部署文档,说明 KV 创建和接口。
- [completed] 5. 运行 Worker 语法检查、Dashboard 脚本检查和客户端构建验证。
### Decisions
- 使用 Cloudflare KV,不使用 D1;只保存每个 projectName 的最新一份公告。
- 客户端公告内容用 Markdown 渲染,并禁用 raw HTML。
- 公告不预置任何内容,只从 Analytics Dashboard 发布。
### Errors Encountered
| Error | Attempt | Resolution |
| --- | --- | --- |
| planning skill 示例路径 `~/.opencode/.../session-catchup.py` 不存在 | 第一次 catchup | 改用实际路径 `~/.config/opencode/.../session-catchup.py` |
| Dashboard 脚本检查命令报 `Unterminated regexp literal` | 第一次 Dashboard 检查 | PowerShell/Node `-e` 中正则字面量转义导致,改用字符串索引提取 `