dsh-loopx-plugin
loopx-project/loopxLoopX——面向长周期 Agent 的提供商中立、本地优先状态内核与控制平面:在 DeepSeek Harness 执行层之上持久化 Goal、Todo、门禁、证据、配额、恢复与交接状态;插件负责引导安装 CLI 与技能、准入有界的同会话续跑,并为精确绑定的工作循环提供本地 GoalBar。
将 Office 文档与 PDF(含扫描件)转换为保留结构的 Markdown,采用 CPU 优先的路由 OCR 流水线(RapidOCR/SLANet/FormulaNet)。
将 Office 文档与 PDF(含扫描件)转换为保留结构级排版的 Markdown,基于 MarkItDown 引擎。提供 CLI 命令行与 dsh agent 工具(md_convert)双入口。
| 输入 | 链路 | 说明 |
|---|---|---|
.docx / .xlsx / .pptx | MarkItDown 直转 | 标题/列表/表格/段落保留为 Markdown |
.pdf(含文字层) | MarkItDown 直转 | 文字层为空时自动回退路由 OCR |
.pdf(扫描件) | 路由 OCR(PP-DocLayout-L 版面 + RapidOCR 文字 / SLANet 表格 / FormulaNet 公式) | 标题/正文/表格/公式/印章,纯 CPU、轻量模型 |
.doc / .xls / .ppt | WPS/Office COM(Windows)或 LibreOffice(其余平台)另存为新格式 → MarkItDown | 后端自动探测,可配置 |
.html/.csv/.json/.xml/.ipynb/.md/.txt/... | MarkItDown / 直接读取 | MarkItDown 支持的全部格式 |
"结构级排版" = 标题层级(H1–H6)、列表、表格(管道表格)、段落顺序均保留。 Markdown 本身无法表达字体/字号/颜色/缩进等视觉细节,任何转换器都不会保留它们——这是格式本质。
.doc/.xls/.ppt):Windows 需本机装有 WPS Office 或 Microsoft Office(COM 自动探测);Linux/macOS 需 LibreOffice(apt install libreoffice,自动探测 soffice)PP-DocLayout-L 版面分析(轻量)按区域路由,文字走 RapidOCR(PP-OCRv6 ONNX,最快),表格走 SLANet+RT-DETR,公式走 FormulaNet-Plus-S(轻量);标题层级由版面模型识别。质量有基本保证,但为效率做了取舍(如复杂版面/超小字号可能识别不全)fonts-noto-cjkdsh-md-convert deps 联网下载到本地缓存(~/.paddlex/official_models/,约数百 MB);之后运行完全离线,不做任何网络检查,断网可正常 OCR依赖自动安装(默认开启):首次转换扫描件时,插件自动检测 Python 与 OCR 依赖
(paddlepaddle paddleocr paddlex[ocr] pypdfium2 rapidocr onnxruntime),
有则直接使用,缺则自动 pip install,无需手动操作。可用 --no-auto-install-deps 关闭,或手动预装:
pip install paddlepaddle paddleocr "paddlex[ocr]" pypdfium2 rapidocr onnxruntime
路由 OCR = PP-DocLayout-L 版面分析(阈值 0.3)+ 区域路由:文字→RapidOCR、 表格→SLANet 结构+RT-DETR 单元格+OCR 填格、公式→FormulaNet-S、印章→注释。
dsh plugin --profile web add github:yakoylp/dsh-md-convert
安装后重启 dsh web,agent 获得 md_convert 工具。CLI 命令 dsh-md-convert 随 profile 的 node_modules/.bin 暴露。
git clone https://github.com/yakoylp/dsh-md-convert.git
cd dsh-md-convert
npm install
npm link # 全局获得 dsh-md-convert 命令
# 或直接调用
node lib/cli.js <文件...> -o <输出目录>
# 基本:批量转换
dsh-md-convert a.docx b.pdf -o ./md
# 老格式(自动探测:Windows 用 WPS→Office,Linux/macOS 用 LibreOffice)
dsh-md-convert old.doc old.xls old.ppt -o ./md
# 强制指定老格式后端
dsh-md-convert old.doc -o ./md --legacy-backend wps
# 扫描件:自动走路由 OCR(无需任何 OCR 参数;缺依赖自动安装)
dsh-md-convert scan.pdf -o ./md
# 指定 Python 解释器(多 Python 环境时)
dsh-md-convert scan.pdf -o ./md --ocr-python "C:\path\to\python.exe"
# 检查 / 安装 OCR 依赖与模型
dsh-md-convert check # 只检查状态,不安装
dsh-md-convert deps # 安装缺失依赖并预下载 OCR 模型到本地(需联网一次,之后离线可用)
完整选项见 dsh-md-convert --help。
失败时必定携带稳定错误码,调用方(CLI / agent / 二次开发)可据此分类处理:
| 错误码 | 含义 | 处理 |
|---|---|---|
E_FILE_NOT_FOUND | 源文件不存在 | 检查路径 |
E_UNSUPPORTED_FORMAT | 扩展名不受支持 | 更换格式 |
E_MARKITDOWN | MarkItDown 转换失败 | 多为文件损坏/加密,可重试 |
E_LEGACY_CONVERT | 老格式另存失败(COM/LibreOffice) | Windows 需 WPS/Office、其余平台需 LibreOffice;已内置自动重试 |
E_OCR_DEPS | 缺 OCR 依赖(自动安装失败/已禁用) | 执行 dsh-md-convert deps |
E_OCR_RUN | 路由 OCR 执行失败 | 重试或降低 --ocr-scale |
E_OCR_EMPTY | 扫描件未识别出内容 | 检查扫描质量 |
E_OUTPUT | 输出写入失败 | 检查 outDir 权限/磁盘 |
E_UNKNOWN | 其他错误 | 查看 error 消息 |
CLI 输出格式(批量时每行可定位到具体文件):
✓ markitdown → ./md/a.md
✗ [E_OCR_EMPTY] 扫描件未识别出任何内容 C:\docs\扫描件.pdf
✗ [E_FILE_NOT_FOUND] 文件不存在:... C:\docs\缺失.docx
退出码:0 全部成功 / 1 存在失败(失败行含 [错误码] 与源文件路径)/ 2 参数错误。
安装插件后,agent 可用 md_convert 工具:
md_convert({ file: "报告.docx", outDir: "./md" })
→ { ok: true, output: "./md/报告.md", chain: "markitdown", warnings: [] }
插件配置(cordis.patch.yml):
- insert:
- id: dsh-md-convert
name: dsh-md-convert
config:
outDir: "" # 输出目录;空则用会话工作区
forceOcr: false # 强制 PDF 走 OCR
ocrScale: 2 # PDF 渲染倍率
autoInstallDeps: true # 缺 OCR 依赖时自动 pip 安装
ocr:
python: "" # Python 解释器(运行 OCR 流水线;空则自动探测)
legacy:
backend: "auto" # auto | wps | office | libreoffice(auto:Windows 用 COM,其余平台用 LibreOffice)
markitdown:
mode: "worker" # worker(默认,子进程执行)| in-process(仅诊断;DSH 宿主内会失败)
node: "" # 运行 worker 的解释器;空则自动探测
timeoutMs: 0 # worker 超时毫秒;0 = 不超时
.docx/.xlsx/.pptx 与 PDF 文字层由 MarkItDown 直转,这一步默认在子进程中执行:
process.execPath 启动;在 Electron 宿主(官方桌面版)里自动追加
ELECTRON_RUN_AS_NODE=1,让同一二进制以纯 Node 方式运行 workermarkitdown.node 或环境变量 DSH_MD_CONVERT_NODE 指定解释器E_MARKITDOWN(消息内带退出码与 stderr 尾部)为什么默认子进程:DSH 宿主会给 profile 内模块安装「插件依赖路由层」,它把
pkg/ 形式的模块请求剥成包名后调用 require.resolve.paths(包名);若剥出的名字正好是
Node 内置模块名,该调用返回 null,随后的 for...of 抛 TypeError。MarkItDown 顶层依赖
jsdom,而 jsdom → whatwg-url → tr46 链上有一句 require("punycode/")(为取 npm 版
punycode,而非已废弃的内置模块),正好命中该缺陷,导致在宿主进程内加载 MarkItDown 必然失败。
独立子进程没有这层路由,按 Node 原生规则解析。副作用是好的:jsdom/sharp 等重依赖的加载
与内存开销不再留在长驻宿主进程里。
mode: "in-process" 保留作诊断与「无法 spawn 子进程」的环境的逃生口;在 DSH 0.2.0-rc.2
宿主内它仍会失败,不要用来规避上述缺陷。
.doc/.xls/.ppt 先另存为现代格式再交给 MarkItDown。后端自动按平台选择:
| 平台 | auto 后端 | 实现 |
|---|---|---|
| Windows | WPS → MS Office | COM(PowerShell 脚本);WPS/Office 正在运行时自动重试(不会杀用户进程) |
| Linux / macOS | LibreOffice | soffice --headless --convert-to,需安装 LibreOffice(自动探测 soffice/libreoffice) |
可用 --legacy-backend wps | office | libreoffice 显式指定(如 Windows 无 WPS/Office 但装了 LibreOffice,可强制 --legacy-backend libreoffice)。
%TEMP%/dsh-md-convert-*),结束即删除exit/信号钩子兜底清理,下次运行自动清扫历史残留--keep-temp 保留npm test # 单元测试(后端分流、LibreOffice mock)
node test/run-smoke.mjs # 7 格式冒烟(Windows 需 WPS/Office;Linux 需 LibreOffice)
node test/run-smoke.mjs --all --reference # 全量 8 格式(含扫描件 OCR),并把参考输出写入 test/fixtures/final-out/
FLAGS_use_mkldnn=0 + enable_mkldnn=False),无需手动处理。pkg/ 请求时会剥成包名再调 require.resolve.paths(),剥出的名字若是 Node 内置模块名
(如 require("punycode/") → punycode)则返回 null 并抛 TypeError。插件已通过
「markitdown 走子进程」规避(见上文);同源缺陷会影响任何依赖树里含 jsdom
(→ whatwg-url → tr46)的插件,值得向 DSH 侧反馈。--ocr-scale(如 3)换取精度,耗时相应增加。.pages/.key 等)会明确报"不支持"~/.paddlex/),之后完全离线、秒级加载MIT © 2026 yakoylp