@eqman00003/dsh-office-com
COM-driven real Microsoft Office automation for DeepSeek Harness: drives a running Excel/Word instance through OfficeMCP — VBA macros, pivot tables, live formula recalculation, and deep document layout; plus an accounting suite (double-entry journal posting with debit/credit balance check, and SUMIF
Install
dsh plugin --profile web add @eqman00003/dsh-office-com
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-office-com
Windows 本机真实 Office 自动化插件,已完成契约、任务级、故障注入和进程泄漏回归;真实 Office 测试需要在目标机器上执行。
COM 驱动真实 Office 实例的 DeepSeek Harness(DSH)原生插件。区别于列表内所有文件级读写的 Office 插件,本插件通过本机 OfficeMCP 的 COM 通道直接操作运行中的 Excel / Word:VBA 宏、透视表、公式重算、已有文档深度排版,外加一套会计旗舰场景(分录 → 总账 → 透视表 → 三表)。
定位差异
现有 Office 插件 · 本插件
文件级读写(openpyxl/exceljs/docx) · COM 驱动真实实例
写死数值、无法重算 · 活公式链,Application.Calculate 取计算后值
无 VBA / 无透视表 · 真实宏运行 + PivotCache/PivotTable 透视表
工具(29 个)
应用发现 / 启动:office_apps · office_launch
Excel 读写:excel_new(新建工作簿并把 Excel 切到可见,工作簿直接交到用户手上)· excel_open · excel_read_range · excel_write_range
Excel 公式 / 宏:excel_formula_set(Range.Formula 原样写入)· excel_recalc(强制重算取活值)· excel_vba_run(运行已有宏)
透视表:excel_pivot_create(PivotCache/PivotTable)· excel_pivot_refresh
Word:word_open(打开读结构)· word_edit(全文查找替换,真实 Find.Execute + wdReplaceAll,只改文本、保留原文格式)
会计旗舰(底层):excel_journal_post(写分录 + 借贷平衡校验,借≠贷标红)· excel_ledger_gen(日记账 → 科目总账,聚合借贷 + 余额公式)
任务级工具(v0.4,6 个)
底层工具各管一段、各自开关文件。任务级工具把一整套业务步骤收进一次调用——Agent 不必自己编排几十个 COM 步骤,也不会中途留下一个只写了一半的工作簿。
工具 · 干什么
office_generate_accounting_report · 一份交易数据(CSV / 内联数组)→ 日记账 + 借贷平衡 + 科目总账 + 透视表 + 强制重算 + 读回校验 → 落盘。模板永不被改动
office_check_workbook · 动手前的只读体检:抓出所有求值出错的公式、外部链接、被保护的表、未保存改动,给 safe_to_edit 与逐条理由
office_replace_document_terms · Word 多术语批量替换(合同里的甲方乙方、金额日期…)。先全部计数再统一替换,保留原文格式
office_update_monthly_report · 按期间更新月度报告:只替换该期间的行,其他期间一行不动;同期间重跑是替换不是追加
office_apply_template · 把模板的外观(字体/颜色/边框/数字格式/列宽行高/冻结窗格)套到目标工作簿,数据一行不动
office_prepare_management_summary · 从数据表出「管理层摘要」:按维度聚合 + TopN + 占比,有「期间」列时可给上期→本期对比
任务级工具同样遵守执行模式与安全动作约定:都支持 mode=preview(真预演、不落笔),
结果写 output 而不是改你的原文件,覆盖已存在的输出要显式 overwrite:true。
office_check_workbook 是只读的,不暴露 mode——没实现 dry-run 差异的工具暴露 mode 只会误导。
kb_* —— 陌生目录的自建分类仓库(v1.2,8 个)
这一族就是 Office × KnowLP 的组合面。 Office 知道「这是什么文件、能不能真被打开」,KnowLP 知道「它在讲什么」,合起来让 Agent 在陌生环境里登记一棵目录树、自己长出分类体系——不是给 Obsidian vault 加功能。
工具 · 读/写 · 干什么
kb_scan_root · 只读 · 登记任意目录树:扩展名 + magic 双判据分类;认不出的一律进「不分类」桶并显式给原因码(绝不猜)。max_deep>0 时按配额只读开簿深扫 Excel 结构
kb_taxonomy_get / kb_taxonomy_set · 只读 / 变更 · 自长分类学:增 / 改名 / 合并 / 删;每次变更自带漂移审计(重叠 / 环 / 悬空)
kb_classify · 只读 · 按分类学规则归档;use_semantics=true 时走 KnowLP 语义缝(见下)
kb_scheme_propose · 只读 · 影子目录方案(label 链 + 原文件名,重名加指纹前 8 位)——只出方案,不碰任何文件
kb_annotate · 变更 · 写标注(annotations.jsonl);写回原文件默认关,write_back && confirm 双闸
kb_verify · 只读 · 核账:标注可解析 / 源文件指纹吻合 / 影子方案与磁盘一致
kb_write_back_office · 变更 · 对单个 Office 文件写删 kb_* 自定义文档属性——只碰属性面板,绝不碰单元格 / 正文 / 幻灯片
组合面在哪 —— KnowLP 语义缝。 kb_classify(use_semantics=true) 把待归类的资料交给 KnowLP 检索,走三级梯子,每一级都如实回报走到了哪:
approved 经 ctx.tools.execute 审批派发(正路) direct 拿不到审批通道时降级直连(仅降级用) unavailable KnowLP 不可用 → 如实声明 + next_call_suggestion
两处细节值得记住,都是踩出来的:工具名按注册表里的实际名字解析(MCP 接入下是 mcp__<server>__* 形状,写死 knowlp_search 必然查不到);断链 / 失败 / 不可用一律显式降级并带回错误,绝不假装做了语义判断。
还有一条跨仓纪律:指纹公式(sha256(rel_posix \0 size \0 mtime_ns))、词表(本仓 KB_ ↔ KnowLP 侧 pool_scan.)、命名空间(按 root 分域,禁止跨根合并裸条目)——任一边改,同一提交里改另一边。
细节见 [docs/kb.md](docs/kb.md)。
执行模式(v0.3)
14 个会改动文档的工具都接受 mode(8 个底层写工具 + 5 个任务级 + kb_write_back_office)。缺省按有无 path 推断,所以老调用一字不改。
mode · 干什么 · 什么时候用
preview · 真经 COM 打开文件看真实状态,回报拟变更,不落笔 · 动手前先确认「会改成什么样」
managed · 打开 → 修改 → 校验 → 保存 → 关闭 · 有明确文件路径的批量作业
attached · 操作当前运行实例,不主动关闭、不自动覆盖 · 用户正开着工作簿,你想在上面干活
preview 不是参数回显,是真的打开文件读:回报真实工作簿身份、真实目标地址(如 $A$2:$B$2)、
会被盖掉的非空格数量、完整算好的总账、命中次数与首处上下文。跑完文件 mtime 一字未动
(npm run test:leak 用例 D 会断言这一点)。
高风险参数必须显式——默认值一律取安全侧:
参数 · 含义 · 缺省
save · 是否落盘 · managed 为 true,attached 为 false
close · 是否关闭 · managed 为 true(只关自己开的那份);attached 下无效
overwrite · 允许覆盖既有内容 · false,涉及覆盖时不给就返回 OVERWRITE_NOT_CONFIRMED
confirm · 高危动作确认位 · false,excel_vba_run 不给就返回 RISKY_OP_NOT_CONFIRMED
refresh_external_data · 一并刷新外部数据连接 · false(它会走网络)
重点保护:用户正在编辑的工作簿永不被代关、也不被代存——即使你给了 path,只要那份文件已经
被打开,插件会按附着处理并在信封里报 attached_existing_open(否则 Workbooks.Open 拿到的是同一个
对象,收尾时 Close(False) 会把用户的窗口关掉并丢弃其未保存修改)。
重跑语义(v0.3)
会计旗舰链路可以反复跑,第二次不会把工作簿搞坏:
excel_journal_post:拿这批分录与账簿末尾逐条对账,命中同一批默认跳过不重复入账
(idempotent_skip:true,信封如实报 changed:false)。真有两笔一模一样的分录用
on_duplicate:"append";改正上一次入错的分录用 on_duplicate:"replace"(位置覆盖并复位标红)
excel_ledger_gen:总账固定落在默认表「总账」并原地刷新,不会每次新建一张;重算结果与表上
一致时直接跳过。按表头判归属——是工具自己的产物就永不索要 overwrite,是用户数据才要
excel_pivot_create:字段先对着表头校验(缺字段报SOURCE_RANGE_INVALID,且不会留下孤儿工作表);
目标表与表名都取确定性名字,第二次跑复用刷新同一张(idempotent_reuse:true)而不是再堆一张
统一结果协议(v0.2 / v0.3 / v0.4)
所有工具返回同一信封,Agent 只读 ok / error_code / retryable 就能分支,不必解析 21 种各不相同的返回形状。
// 成功
{ "ok": true, "operation": "excel_write_range", "mode": "managed", "preview": false,
"changed": true, "saved": true, "verified": false, "warnings": [],
"output": { "range": "A1:B2", "written": true } }
// 预演
{ "ok": true, "operation": "excel_ledger_gen", "mode": "preview", "preview": true,
"changed": false, "saved": false, "warnings": ["preview:未做任何修改"],
"output": { "rows": [ { "account": "办公费", "debit": 1200, "credit": 0 } ] } }
// 失败
{ "ok": false, "operation": "excel_ledger_gen", "mode": "managed", "preview": false,
"error_code": "OVERWRITE_NOT_CONFIRMED", "error": "…", "retryable": false, "partial_changes": false }
changed/saved/verified分开报:改了 ≠ 落盘了 ≠ 核对过。附着模式(无path)改的是用户在用的工作簿,saved为false- 这三个字段以观测为准:Python 侧知道真实发生了什么(改没改、存没存、还开着没),与声明冲突时一律信观测——信封不会宣称一次实际失败的保存
verified只在有校验步骤的工具上为真:excel_recalc(重算后读回活值)、excel_journal_post(借贷平衡)error_code:CHANNEL_UNAVAILABLE(通道断,可重试)/COM_OBJECT_DEAD(通道里的对象成僵尸,可重试)/SAVE_FAILED(保存失败,可重试)/FILE_LOCKED(文件被占,可重试)/MODE_INVALID/OVERWRITE_NOT_CONFIRMED/ `RIS
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::11,最后更新 2026-10-25