From 8805858b79838c4a10629797099021cd0705d35f Mon Sep 17 00:00:00 2001 From: thzxx Date: Sun, 19 Apr 2026 20:48:56 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=AC=AC=E4=B8=89=E6=96=B9?= =?UTF-8?q?=E5=BA=93=E6=9B=BF=E6=8D=A2=20&=20=E4=BB=A3=E7=A0=81=E7=B2=BE?= =?UTF-8?q?=E7=AE=80=20=E2=80=94=20v5.1.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Markdown 解析器:内联正则 → marked 库(完整 GFM 支持) - HTML 净化器:内联 DOM 遍历 → DOMPurify(业界标准) - crypto.ts:删除 sha256js/xorBytes 死代码回退路径 - 消除 5 个文件中 escapeHtml/formatSize 重复定义 - 版本号升级至 5.1.5 --- README.md | 4 +- docs/BUILD.md | 10 +- docs/CHANGELOG.md | 26 +++- docs/DEVELOPMENT.md | 2 +- package-lock.json | 53 ++++++- package.json | 9 +- src/renderer/components/prompt-modal.ts | 6 +- src/renderer/components/tool-confirm-modal.ts | 6 +- src/renderer/components/workspace-panel.ts | 14 +- src/renderer/index.html | 2 +- src/renderer/services/crypto.ts | 145 +++--------------- src/renderer/services/log-service.ts | 6 +- src/renderer/utils/marked-config.ts | 116 +++++--------- src/renderer/utils/sanitizer.ts | 90 +++-------- src/renderer/utils/utils.ts | 4 +- 15 files changed, 183 insertions(+), 310 deletions(-) diff --git a/README.md b/README.md index 0716a92..7e2be3e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ 全离线运行 · 数据本地存储 · 零外部依赖 -[![版本](https://img.shields.io/badge/version-5.1.4-brightgreen?style=flat-square)](https://gitee.com/thzxx/metona-ollama-desktop/releases) +[![版本](https://img.shields.io/badge/version-5.1.5-brightgreen?style=flat-square)](https://gitee.com/thzxx/metona-ollama-desktop/releases) [![平台](https://img.shields.io/badge/platform-Windows%20x64-blue?style=flat-square)](https://gitee.com/thzxx/metona-ollama-desktop/releases) [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-3178c6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/) [![Electron](https://img.shields.io/badge/Electron-33-47848f?style=flat-square&logo=electron&logoColor=white)](https://www.electronjs.org/) @@ -300,7 +300,7 @@ src/ | 文件 | 类型 | |------|------| -| `Metona Ollama Setup 5.1.4.exe` | NSIS 安装包(可选目录、创建快捷方式) | +| `Metona Ollama Setup 5.1.5.exe` | NSIS 安装包(可选目录、创建快捷方式) | > ⚠️ 未签名版本,首次运行 Windows 可能弹出安全警告,点击「仍要运行」即可。 diff --git a/docs/BUILD.md b/docs/BUILD.md index 842202c..0d96ca6 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -14,7 +14,7 @@ # 1. 克隆并安装依赖 git clone https://gitee.com/thzxx/metona-ollama-desktop.git cd metona-ollama-desktop -git checkout metona-ollama-desktop-v5.1.4 +git checkout metona-ollama-desktop-v5.1.5 npm config set registry https://registry.npmmirror.com npm install @@ -176,7 +176,7 @@ electron-builder 会自动处理所有依赖下载(Electron、NSIS、winCodeSi ## 构建日志 -### v5.1.4(2026-04-19) — metona-ollama-desktop 仓库 +### v5.1.5(2026-04-19) — metona-ollama-desktop 仓库 - ♻️ 工具卡片从聊天区域迁移到工作空间面板(新增「🔧 工具」页签) - 工具执行自动切换工具页签,run_command 自动切换终端页签 @@ -186,9 +186,9 @@ electron-builder 会自动处理所有依赖下载(Electron、NSIS、winCodeSi - 🔧 自动记忆优化(禁止自动提取规则、提高提取门槛与质量) - 🔧 工具页签自动切换协调性修复 - 🔧 工作流完整性和协调性修复(清理旧状态、中止保留记录、retry 保存 think) -- 📝 版本号更新至 5.1.4 -- ✅ `Metona Ollama Setup 5.1.4.exe`(82MB) -- ✅ Gitee Release v5.1.4-desktop(ID: 622607) +- 📝 版本号更新至 5.1.5 +- ✅ `Metona Ollama Setup 5.1.5.exe`(82MB) +- ✅ Gitee Release v5.1.5-desktop(ID: 622607) - 构建一次通过,无需代码修复 ### v5.1.3(2026-04-19) — metona-ollama-desktop 仓库 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 793194c..d4100d8 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -3,13 +3,37 @@ ## 分支结构 **桌面版主线**(`master`): -- `metona-ollama-desktop-v3.2.6` → `metona-ollama-desktop-v3.3.4` → `metona-ollama-desktop-v4.0.0` → `metona-ollama-desktop-v5.0.0` → `metona-ollama-desktop-v5.0.1` → `metona-ollama-desktop-v5.1.0` → `metona-ollama-desktop-v5.1.1` → `metona-ollama-desktop-v5.1.2` → `metona-ollama-desktop-v5.1.3` → `metona-ollama-desktop-v5.1.4`(当前发布分支) +- `metona-ollama-desktop-v3.2.6` → `metona-ollama-desktop-v3.3.4` → `metona-ollama-desktop-v4.0.0` → `metona-ollama-desktop-v5.0.0` → `metona-ollama-desktop-v5.0.1` → `metona-ollama-desktop-v5.1.0` → `metona-ollama-desktop-v5.1.1` → `metona-ollama-desktop-v5.1.2` → `metona-ollama-desktop-v5.1.3` → `metona-ollama-desktop-v5.1.4` → `metona-ollama-desktop-v5.1.5`(当前发布分支) **Web 版历史**已独立为 [metona-ollama-web](https://gitee.com/thzxx/metona-ollama-web) 仓库(v1.1.0 ~ v4.0.3)。 --- ## 桌面版(Desktop) +### Desktop v5.1.5 — 第三方库替换 & 代码精简 + +- ♻️ **Markdown 解析器替换:内联实现 → `marked` 库** + - 移除 `marked-config.ts` 中约 80 行正则解析器(仅支持基本 GFM) + - 接入 `marked` 库:完整 GFM 支持(表格、删除线、任务列表、自动链接等) + - 渲染后自动经 DOMPurify 净化,双重安全 + - 链接/图片安全检查保留(阻止 javascript: / vbscript: / file: 等危险协议) +- ♻️ **HTML 净化器替换:内联实现 → `DOMPurify`** + - 移除 `sanitizer.ts` 中约 70 行 DOM 遍历净化器 + - 接入 `DOMPurify`(业界标准 HTML 净化库) + - 保留原有的白名单标签/属性/URI 协议配置 + - 移除不再需要的 `SAFE_URI_SCHEMES` 导出 +- 🧹 **精简 crypto.ts:删除死代码** + - 移除 `sha256js()` 纯 JS SHA-256 回退实现(~60 行) + - 移除 `xorBytes()` 异或加密回退(~10 行) + - 移除 `SECURE` 标志及所有分支判断 + - Electron 环境下 `crypto.subtle` 始终可用,回退代码从未执行 + - 旧版 XOR 加密的 .metona 文件提供明确错误提示 +- 🧹 **消除重复代码** + - `escapeHtml()` 在 5 个文件中重复定义 → 统一从 `utils.ts` 导入 + - `formatSize()` 在 `workspace-panel.ts` 中重复定义 → 统一从 `utils.ts` 导入 + - 消除文件:`log-service.ts`、`prompt-modal.ts`、`tool-confirm-modal.ts`、`workspace-panel.ts` +- 📝 **版本号更新至 5.1.5**(7 个文件同步更新) + ### Desktop v5.1.4 — 工具卡片迁移 & 空闲状态优化 & 工作流修复 - ♻️ **工具卡片从聊天区域迁移到工作空间面板** diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index 49dff82..a8cf5f3 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -1,6 +1,6 @@ # Metona Ollama Desktop — 开发规范 -> 版本: 5.1.4 | 更新: 2026-04-19 | 维护: 项目团队 +> 版本: 5.1.5 | 更新: 2026-04-19 | 维护: 项目团队 --- diff --git a/package-lock.json b/package-lock.json index cf58a10..1959cb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,20 @@ { "name": "metona-ollama-desktop", - "version": "5.1.4", + "version": "5.1.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "metona-ollama-desktop", - "version": "5.1.4", + "version": "5.1.5", "license": "MIT", "dependencies": { + "dompurify": "^3.4.0", + "marked": "^18.0.2", "sql.js": "^1.11.0" }, "devDependencies": { + "@types/dompurify": "^3.0.5", "@types/node": "^20.17.0", "electron": "^33.4.11", "electron-builder": "^25.1.8", @@ -855,7 +858,7 @@ "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.4", + "version": "5.1.5", "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, @@ -1446,6 +1449,16 @@ "@types/ms": "*" } }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmmirror.com/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", @@ -1519,6 +1532,13 @@ "@types/node": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "devOptional": true, + "license": "MIT" + }, "node_modules/@types/verror": { "version": "1.10.11", "resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.11.tgz", @@ -1826,7 +1846,7 @@ } }, "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.4", + "version": "5.1.5", "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, @@ -2898,6 +2918,15 @@ "node": ">=8" } }, + "node_modules/dompurify": { + "version": "3.4.0", + "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.4.0.tgz", + "integrity": "sha512-nolgK9JcaUXMSmW+j1yaSvaEaoXYHwWyGJlkoCTghc97KgGDDSnpoU/PlEnw63Ah+TGKFOyY+X5LnxaWbCSfXg==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz", @@ -4251,7 +4280,7 @@ } }, "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.4", + "version": "5.1.5", "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, @@ -4436,6 +4465,18 @@ "node": ">=12" } }, + "node_modules/marked": { + "version": "18.0.2", + "resolved": "https://registry.npmmirror.com/marked/-/marked-18.0.2.tgz", + "integrity": "sha512-NsmlUYBS/Zg57rgDWMYdnre6OTj4e+qq/JS2ot3KrYLSoHLw+sDu0Nm1ZGpRgYAq6c+b1ekaY5NzVchMCQnzcg==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/matcher/-/matcher-3.0.0.tgz", @@ -4863,7 +4904,7 @@ } }, "node_modules/onetime": { - "version": "5.1.4", + "version": "5.1.5", "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, diff --git a/package.json b/package.json index 8d3a9b0..63fceea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "metona-ollama-desktop", - "version": "5.1.4", + "version": "5.1.5", "description": "Metona Ollama - TypeScript + Electron 桌面 AI 聊天客户端", "main": "dist/main/main.js", "author": "thzxx", @@ -27,7 +27,9 @@ "dist/**/*", "assets/**/*", "!node_modules/**/*", - "node_modules/sql.js/**/*" + "node_modules/sql.js/**/*", + "node_modules/marked/**/*", + "node_modules/dompurify/**/*" ], "extraResources": [ { @@ -59,6 +61,7 @@ } }, "devDependencies": { + "@types/dompurify": "^3.0.5", "@types/node": "^20.17.0", "electron": "^33.4.11", "electron-builder": "^25.1.8", @@ -66,6 +69,8 @@ "vite": "^5.4.0" }, "dependencies": { + "dompurify": "^3.4.0", + "marked": "^18.0.2", "sql.js": "^1.11.0" } } diff --git a/src/renderer/components/prompt-modal.ts b/src/renderer/components/prompt-modal.ts index 9e270dd..96a1b10 100644 --- a/src/renderer/components/prompt-modal.ts +++ b/src/renderer/components/prompt-modal.ts @@ -8,6 +8,8 @@ let titleEl: HTMLElement | null = null; let bodyEl: HTMLElement | null = null; let inputEl: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null = null; let okBtn: HTMLButtonElement | null = null; + +import { escapeHtml } from '../utils/utils.js'; let cancelBtn: HTMLButtonElement | null = null; let resolveFn: ((value: string | null) => void) | null = null; @@ -136,6 +138,4 @@ export function showConfirm(message: string, title = '确认'): Promise }); } -function escapeHtml(text: string): string { - return text.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); -} + diff --git a/src/renderer/components/tool-confirm-modal.ts b/src/renderer/components/tool-confirm-modal.ts index 63384ba..f37c946 100644 --- a/src/renderer/components/tool-confirm-modal.ts +++ b/src/renderer/components/tool-confirm-modal.ts @@ -5,6 +5,7 @@ import type { ToolCall } from '../types.js'; import { getToolIcon, formatToolName } from '../services/tool-registry.js'; import { logDebug, logInfo } from '../services/log-service.js'; +import { escapeHtml } from '../utils/utils.js'; let modalEl: HTMLElement | null = null; let resolveConfirm: ((confirmed: boolean) => void) | null = null; @@ -117,7 +118,4 @@ function cancelConfirm(): void { } } -function escapeHtml(str: string): string { - const map: Record = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; - return str.replace(/[&<>"']/g, c => map[c]); -} + diff --git a/src/renderer/components/workspace-panel.ts b/src/renderer/components/workspace-panel.ts index d6e0271..b6efda7 100644 --- a/src/renderer/components/workspace-panel.ts +++ b/src/renderer/components/workspace-panel.ts @@ -4,6 +4,7 @@ */ import { logInfo, logError, logDebug } from '../services/log-service.js'; +import { escapeHtml, formatSize } from '../utils/utils.js'; // ── 工具卡片类型 ── interface ToolCallRecord { @@ -105,13 +106,6 @@ const ANSI_COLORS: Record = { '94': '#8ec8ff', '95': '#e8a0e8', '96': '#5ee8e8', '97': '#fff', }; -function escapeHtml(text: string): string { - return text - .replace(/&/g, '&') - .replace(//g, '>') - .replace(/"/g, '"'); -} function ansiToHtml(raw: string): string { // 先转义 HTML @@ -759,12 +753,6 @@ function getFileIcon(name: string): string { return iconMap[ext] || '📄'; } -function formatSize(bytes: number): string { - if (bytes < 1024) return bytes + ' B'; - if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; - return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; -} - // ── 工具调用管理 ── /** 是否有命令正在终端中执行 */ diff --git a/src/renderer/index.html b/src/renderer/index.html index 019419c..625b145 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -28,7 +28,7 @@
Metona Ollama - v5.1.4 + v5.1.5