npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

hiwork-office

v0.0.4

Published

HiWork 文档办公插件:集成 OnlyOffice Document Server,支持工作区文档(docx/xlsx/pptx 等)的在线预览与编辑,编辑结果自动回写工作区文件。

Downloads

193

Readme

hiwork-office

HiWork 的文档办公插件:把 OnlyOffice Document Server 集成进桌面端,让 DSH 生成的工作区文档(docx / xlsx / pptx 等)可以直接在线预览与编辑,编辑结果由 Document Server 回调并自动回写工作区文件。

两种打开方式,互补而不是二选一:

  • 在线预览 / 编辑:文档嵌在 HiWork 里(中央页 + 右侧栏 tab),无需本机装 Office; 文档怎么到 DS 手里有两条通道,由管理员的网关开关决定(见「在线编辑的两条通道」);
  • 本地预览:交给本机默认应用打开(Word / Excel / WPS / Keynote…),不经过 Document Server、不需要登录,Agent 也能调(工具 office_open_local)。

并且:在线编辑中的文档,Agent 也能读写——见「Agent 桥」(工具 office_document_*), 它需要把三个插件文件装到 Document Server 上(一次性运维步骤,README 里有一行命令)。

  • 包名 / bundle id:hiwork-office
  • client 插件名:hiwork-office-client
  • 中央页 feature:id = office,order = 50(排在定时任务 20、知识库 30、能力中心 40 之后)
  • Agent 工具:office_open_local(把工作区文档推到用户眼前)、 office_document_outline / office_document_read / office_document_read_format / office_document_list_styles(读在线文档)、 office_document_insert_text / office_document_set_cells / office_document_format_text / office_document_format_paragraph / office_document_apply_style / office_document_replace_text / office_document_insert_table / office_document_format_cells 等(写在线文档,带人工确认门)

工作原理

┌────────────────────┐  ① GET /doc/<token>/文件名      ┌───────────────────────────┐
│  hiwork-desktop    │ ◀────────────────────────────── │ OnlyOffice Document Server │
│  ┌──────────────┐  │      (Document Server 拉文档)   │ https://office-suite.     │
│  │ DocsAPI      │  │                                 │        hivery.cn          │
│  │ 编辑器 iframe │──┼──② 加载 api.js + 提交 config ──▶ │ (remote-dev-96 Docker,    │
│  └──────────────┘  │                                 │  经反代出 HTTPS 域名)      │
│  ┌──────────────┐  │  ④ POST /callback/<token>       └────────────┬──────────────┘
│  │ hiwork-office │◀─┼──────────────────────────────────────────────┘
│  │ Host 半边     │  │      (编辑保存回调:从 body.url 下载并覆盖本地文件)
│  │ · 文档扫描    │  │
│  │ · JWT 签发    │  │  ③ RPC /hiwork-office(config / files / session)
│  │ · 文档服务    │◀─┼────────────────────── Web 半边(文件列表 + 编辑器挂载)
│  └──────────────┘  │
└────────────────────┘
  1. 打开文档:Web 半边发 session.open { path, mode };Host 校验路径在工作区内、 按文件内容算 document.key(sha256 截断)、登记随机 token,组装完整 DocsAPI config 并以 HS256 签名(JWT_IN_BODY 约定)返回。
  2. 渲染:client 动态加载 ${serverUrl}/web-apps/apps/api/documents/api.js, new DocsAPI.DocEditor(el, config) 挂进中央内容区。
  3. 拉取:Document Server 从本机文档服务 GET /doc/<token>/文件名 拉文档 (部署侧已开 ALLOW_PRIVATE_IP_ADDRESS,私网地址可达;本机地址自动探测私网 IPv4,也可在 bundle config 里显式指定 advertiseHost)。
  4. 保存:用户保存 / 关闭编辑器时 Document Server 回调 POST /callback/<token> (带 JWT,Host 验签),Host 从回调 body 的 url 下载最新文档并原子覆盖本地 文件,回 {"error":0};文件内容变了,下次打开的 document.key 自动变化, Document Server 侧不会复用旧缓存。

配置与凭据来源

凭据优先级:网关下发(managed)> 本地覆盖(manual)> bundle 默认。

| 配置 | 主要来源 | 备用来源 | 说明 | | --- | --- | --- | --- | | Document Server 地址 | 网关下发(GET /api/me/office-config) | 设置界面 / cordis.patch.yml | 网关下发经 hiwork-core 的登录态自动取得,终端零配置 | | JWT 密钥 | 网关下发(同上) | 设置界面(离线备用) | 网关不可用时才用本地值;密钥永不下发到 Web 半边、不进 npm 包 | | 监听端口 | cordis.patch.yml | — | 本机文档服务端口,0 = 系统分配 | | 通告地址 | cordis.patch.yml | — | 留空自动探测私网 IPv4;Document Server 必须能回连它 |

网关下发怎么走(2026-09-16 起,替代「每台终端手工配密钥」):

hiwork-office Host ──① ctx.get('hiworkOfficeCredentials') ──▶ hiwork-core Host
                                                              │ ② 用网关登录 cookie 拉
                                                              ▼
                        GET https://aigateway.hivery.cn/api/me/office-config
                        (网关集中持有共享密钥,配置见 ai-gateway config.yaml 的 office 段)
  • 站点侧只需在一处配置密钥(网关 config.yaml 的 office.jwt_secret),轮换改这一处;
  • 终端侧:登录企业网关后自动取得,无需任何手工配置;下发值缓存在 Host 内存 (TTL 30 分钟,打开文档 / 刷新探测 / 手动同步都会按 TTL 补齐),失败保留上一次成功值;
  • 未安装 hiwork-core(独立安装)或网关未配置时,回退到本地设置里的地址与密钥;
  • 设置界面显示「密钥来源」(网关下发 / 本地配置 / 未获取)+ 更新时间,并提供 「从网关同步」按钮。

首次使用(已登录网关、网关已配置 office 段):打开「文档」feature 即可用——徽标变绿。 独立安装 / 离线:在「OnlyOffice 服务器设置」里填密钥(部署速查里的值)作为备用。

入口分工(2026-09-17 起:预览 / 编辑默认在右侧栏)

| 入口 | 落地形态 | 说明 | | --- | --- | --- | | 「文档」页点预览 / 编辑 | 当前会话的右侧栏 tab | 与对话并存;右栏自带展开 / 浮动 / 分栏控制就是"看大图"的路径;Agent 桥随之在该 tab 里生效(写工具能驱动它) | | 聊天里的文档链接 | 右侧栏 tab | 与上同——同一份文件共用同一个 document key | | 「文档」页点本地 | 本机默认应用 | 不经过 Document Server、不需要密钥(无头环境禁用) |

中央区没有编辑器、也没有说明位(2026-09-17 起):「文档」页就是一个文件列表(独占整页宽度), 编辑器只活在右栏 tab;同一份文件在右栏打开时,列表里那一行会高亮——这就是"哪份在被编辑"的唯一提示。 「中继同步状态」「通道 / 模式」「AI 可操作」三个徽标都在右栏那一行的上方(编辑器在哪,状态就在哪)。

右栏导航用的是当前 DSH 的根级 ctx.sidebarRight.openTab(kind, {params}):它落在当前显示的 会话的右栏并自动展开,所以中央页不需要会话 id。宿主没有这个面(独立安装 / 旧宿主 / 当前不在 会话里)时,插件静默回落到中央区内嵌编辑器。

目录

src/
  index.ts                 Host 入口:OfficeService + RPC + 文档服务 + Agent 工具的生命周期
  service.ts               OfficeService:凭据来源解析(网关下发 > 本地 > bundle)、工作区扫描、会话签发、本地预览、Agent 桥会话
  bridge.ts                Agent 桥的线协议(postMessage 形状、op 白名单、编辑器 config 注入块)
  bridge-host.ts           桥的 Host 运行时:在线会话表 + 命令队列 + 在途命令 + 超时
  docserve.ts              本机文档服务:/doc 下发 + /callback 保存回写(验签)
  local-open.ts            「本地预览」打开器:复用 @deepseek-ai/dsh-native-command(跨平台、shell-free)
  tools.ts                 Agent 工具:office_open_local(本地预览)+ office_document_*(Agent 桥,
                           声明表驱动:加能力 = 插件一个 case + 表一行)
  jwt.ts                   HS256 JWT(node:crypto 手写,host 产物自包含)
  document-types.ts        扩展名白名单 → documentType / MIME
  protocol.ts              /hiwork-office RPC 契约(endpoint + zod schema + 错误码)
  rpc.ts                   RPC Host 实现(loopback authority)
  client/
    index.ts               Web 入口:注册 feature / 设置页降级
    OfficeView.tsx         文档页:左文件栏(预览 / 本地 / 编辑)+ 右编辑器 + 设置弹层
    OfficeSidebarTab.tsx   右侧栏 tab 正文(同一编辑器的第二种入口)
    editor.tsx             api.js 加载器 + DocsAPI.DocEditor 生命周期封装
    bridge.ts              客户端桥:插件握手(event.source 绑定)+ 命令长轮询 + 结果回传
    runtime.ts             RPC 动作集(信封解包 + 哨兵错误)
    locales.ts             命名空间 hiwork-office 的 zh/en 词典
    contracts.ts           宿主 client 能力的结构契约(type-only)
    styles.ts / styles.css 样式注入
assets/
  agent-bridge/            **DS 侧部署件**:插件三件套(config.json / plugin.js / index.html)
scripts/
  host-build.mjs           Host 产物自包含打包(esbuild bundle;官方包一并内联)+ 插件资产拷进 lib/
  client-build.mjs         Client 产物闭包工厂打包(rc.1 契约)
tests/                     JWT / 协议 / 文档服务 / 本地打开 / 工具 / 服务 / RPC / 视图 / 打包门禁

在线编辑的两条通道(中继 / 本机)

在线编辑要求 Document Server 主动回连文档 URL。两条通道的差别就是"那个 URL 在哪":

| | 云端中继(relay) | 本机(local) | | --- | --- | --- | | 文档 URL 在哪 | 网关中继服务(DS 能访问的服务器侧) | 用户电脑上的本机文档服务 | | 对用户网络的要求 | 无——只要能上网就能编辑(家、出差、VPN 均可) | DS 必须能连到用户电脑(同局域网 / 双向可达) | | 谁决定用哪条 | 管理员:网关 office.relay_enabled | 中继不可用时的自动回落 | | 文档去向 | 经服务器短时中转(TTL 12h、关闭即删、只留最新一版) | 不出本机 |

实现要点(设计见 ai-gateway 的 docs/superpowers/specs/2026-09-16-office-document-relay-design.md):

  • 打开文档:读本地文件 → 上传中继 → 编辑器 config 指向中继签发的两条签名 URL (DS 拉取 / 回调),本地不暴露任何端口;
  • 编辑期间:每 3s 轮询中继版本号,有新版本就取回并原子写回工作区文件;
  • 冲突保护:若编辑期间本地文件被外部改动,编辑器版本写成 <名字> (HiWork 编辑冲突 <时间>).<ext> 副本而不是覆盖;
  • 编辑器栏显示通道徽标(云端中继 / 本机)与同步状态行(已同步到第 N 版 / 冲突 / 已过期);
  • 失败不静默:上传失败、会话过期都会在页面给出文案与原因。

document key 掺入打开模式:DS 按 document.key 复用编辑会话,key 只由内容 hash 构成时 「先预览、再编辑」会接到那个只读会话(编辑器不能输入、写命令超时)。因此本地会话的 key 是 内容 hash + 模式,中继会话的 key 由网关按 内容 hash + 模式 生成,view 与 edit 永不共用会话。

一份文件 = 一份在线文档(联动的前提):同一路径 + 同一模式的会话是共享的—— 中央页与右侧栏打开同一份文件时,拿到的是同一个 document.key(中继侧也只上传一次), DS 因此把它们当同一个文档协同:任一处的改动(包括 Agent 的写入)实时出现在另一处。 引用计数管理生命周期:还有视图在看就不拆会话,最后一个视图关掉才停轮询并通知中继清理。 (view 与 edit 不共享:权限不同,在 DS 侧本来就是两份 config。)

Agent 桥(让 Agent 读写在线编辑中的文档)

在 HiWork 里用「编辑」打开的文档,Agent 也能读、也能改(改动同样由编辑器保存链路 回写工作区文件)。十八个工具,按"读现状 → 改 → 读回"分三组:

| 工具 | 类型 | 作用 | | --- | --- | --- | | office_document_outline | 读 | 文档结构(Word 段落数 + 前几段;表格工作表名 + 已用区域) | | office_document_read | 读 | 按段落区间 / 单元格区域读内容(超 64KB 截断并标 truncated) | | office_document_read_format | 读 | 读某一处的当前格式(字符 + 段落 + 具名样式),改之前先看现状 | | office_document_list_styles | 读 | 列出文档里可用的具名样式(套样式前先确认名字怎么写) | | office_document_insert_text | 写 | 向 Word 文末追加一个段落 | | office_document_format_text | 写 | 字符格式:加粗/倾斜/下划线/删除线/字色/字体/字号/大小写/上下标/字间距 | | office_document_format_paragraph | 写 | 段落格式:对齐/缩进/段前后距/行距/段中不分页/与下段同页/段前分页/大纲级别 | | office_document_apply_style | 写 | 套具名样式(「标题 1」「正文」…)——做标题层级与目录结构用这个 | | office_document_replace_text | 写 | 全文查找替换(回报改前命中几处、改完还剩几处) | | office_document_insert_table | 写 | 在文末插入表格并可填内容 | | office_document_format_table | 写 | 调已有表格的样式 / 水平对齐 | | office_document_set_cells | 写 | 写表格单元格(values 是二维数组的 JSON) | | office_document_format_cells | 写 | 单元格格式:字体/底色/边框/数字格式/对齐/自动换行 | | office_document_merge_cells | 写 | 合并 / 取消合并单元格 | | office_document_conditional_format | 写 | 条件格式:数据条/色阶/图标集/前 N 项/高于平均/唯一值/单元格规则 | | office_document_data_validation | 写 | 数据校验(限制能填什么,常用于下拉列表) | | office_document_insert_pivot | 写 | 插入透视表(行/列/筛选/数值字段) |

Word 侧"改哪儿"有四种目标(format_text / format_paragraph / apply_style / read_format 共用):selection(用户当前选中处)、search(按文本找)、 paragraphs(from_index + count,必须给 from_index)、all(全文)。 三个改格式的工具把 target 设成必填——不给就等于"改哪儿都行",那是另一回事。

长度/间距单位是缇(twip):1 磅 = 20 缇,1 厘米 ≈ 567 缇(首行缩进 2 字符 ≈ 480 缇)。 read_format 读回来的也是缇,可以直接照抄回 format_paragraph。

写工具走人工确认门(与 hiwork-automation 同构,tools/pre-execute 升级成 ask), 确认卡片会把完整改动摊开(文档 + 操作对象 + 要改成什么);读工具不审批,但编辑器栏会显示 「AI 可操作」徽标,让用户对"Agent 能看/能改这份文档"有明确预期。

能力边界:这套 op 全部落在官方 Office API 里——callCommand 的沙箱边界恰好就是它 (2026-09-17 对着 DS 上部署的 9.4.0 核实:Word 140 个 Api.* 工厂 / 1505 个类方法, 表格 168 / 2404)。仍然没有"执行任意脚本"的通道,也没有把 callCommand 透传给模型。 调研过程、能力清单与后续可扩展方向见 docs/superpowers/specs/2026-09-17-office-api-surface-research.md。

右栏是 AI 协作的主场:在聊天里点一份 docx/xlsx,右栏 tab 直接打开编辑器,顶部状态条 显示桥的状态——「AI 可操作」→「AI 正在写入…」(琥珀呼吸)→「AI 已更新」(绿,8 秒后回落)。 AI 的改动同时经 DS 协同实时出现在中央页的同名编辑器里(同一个 document.key); 中央页的文件列表也会在 AI 写完后再刷一次(中继写回有几秒延迟,会补刷第二次)。

已知限制:插件的 ready 只带文档标题(DS 不给插件传 key),因此两个同名不同目录的 文件同时开着编辑器时,桥可能把命令认到另一份上;工具侧仍要求工作区内的绝对路径。 日常(一次只开一份同名文件)不受影响。

安装(一次性运维步骤,必需)

桥的插件是 Document Server 侧的部署件:必须与编辑器 iframe 同源才会被加载, 指向用户电脑的地址(127.0.0.1 / 私网 IP)时浏览器会拦掉,插件根本不启动 (2026-09-17 spike 实测,见 docs/superpowers/specs/2026-09-16-office-agent-bridge-design.md §8.1)。

# 插件资产随 npm 包分发:node_modules/hiwork-office/lib/agent-bridge/
# 装到 DS 容器(三个文件都要,index.html 不能少);目录名 = hiwork-bridge-<资产版本>
docker cp node_modules/hiwork-office/lib/agent-bridge/. \
  onlyoffice-documentserver:/var/www/onlyoffice/documentserver/sdkjs-plugins/hiwork-bridge-0.3.1/
docker exec -w /var/www/onlyoffice/documentserver/sdkjs-plugins/hiwork-bridge-0.3.1 onlyoffice-documentserver \
  sh -c 'gzip -kf *.json *.js *.html; chown -R ds:ds .; chmod 644 *'

目录名必须带资产版本:DS 给 sdkjs-plugins/** 下发 Cache-Control: max-age=31536000, immutable (实测),插件窗口的 index.html 也被强缓存——只换文件内容、不换 URL,浏览器会一直用旧插件。 发布插件时把 assets/agent-bridge/config.json 的 version 与 src/bridge.ts 的 BRIDGE_PLUGIN_DIR 一起改(tests/packaging.spec.ts 会卡住漂移),然后清掉旧目录、装新目录。 协议有变化时同理换目录名——DS 还会按文档 key 缓存会话配置,同名目录容易被旧资产掩盖。

通道(没有网络面)

编辑器插件 ──postMessage──▶ 宿主页面(本插件 client) ──loopback RPC──▶ Host(OfficeService)
   ▲  只认 Document Server 源            │                              命令队列 / 在途命令
   └──────── postMessage(定向 event.source)◀── 长轮询 bridge.pull ─────┘
  • 插件不访问任何网络端点:无监听端口、无 URL 里的凭据、无 CORS/PNA 头要维护—— 上下行都走 postMessage(event.source 定向发送,跨域成立);
  • Host 推不动客户端(DSH 的 connection.rpc 在 Host 侧只有 handle),所以命令靠客户端 长轮询取走(无命令时挂起 ≤25s,命令入队即刻唤醒);
  • 命令白名单就是上面那张表(src/bridge.ts 的 OFFICE_BRIDGE_OPS,17 个 op), 没有"执行任意脚本"的通道;写操作在插件里改 + 独立读回(插入后回段落数、 写单元格后回读区域、改格式后回读属性),不信任静默失败。 读回那一趟绝不能再改一次:建表、加条件格式这类非幂等操作在插件里由 whenApplying() 闸住(写这段逻辑时踩过:工具报"成功"而用户看到两张表);
  • 回读文本先归一化再比较:ApiParagraph.GetText() 返回的是结构化文本,段尾那个 \r\n 是段落标记自身(不是内容),拿它跟调用方传进来的纯文本做等值判断永远不成立 (2026-09-17 反馈 #6:insert_text 明明写进去了却恒定报失败)。归一化只去尾部换行, 不能用 trim() —— 有意保留的首尾空格是内容。文本类判据还要配一条"段数确实增加": 只查"文字存在"时,文档里本来就有同样一段的话,写入被吞掉也会报成功;
  • 会话关闭 / 组件卸载 → 在途命令立刻以"编辑器已关闭"结束,不用等超时。

只读(预览)会话:预览模式不注入插件,Agent 的工具也会立刻给出针对性提示 (写操作:"文档当前以预览(只读)方式打开,无法写入…"),不会拖到 30 秒超时。要 AI 读写, 请用「编辑」打开。

写入后自动保存:DS 即使配了 autosave: true 也不会定时写存储(保存只发生在用户关闭 文档或有人请求强制保存时),所以 AI 写完会由 Host 向 DS 的 CommandService 发一次 forcesave(去抖 1.5s、失败只记日志)——工作区文件因此不需要用户手动保存就更新。

排障:编辑器栏显示「AI 可操作」= 插件已握手;显示「AI 暂不可用」= 插件没起来 (多半是上面那步没做,或 DS 侧目录名/index.html 不对)。Host 日志会打出资产目录。

升级插件时注意两层缓存:DS 静态资源会被浏览器缓存,所以 index.html 里的 plugin.js 带版本查询串(改版本号即可);协议有变化时换目录名(hiwork-bridge-v2)并同步改 src/bridge.ts 的 BRIDGE_PLUGIN_DIR——DS 还会按文档 key 缓存会话配置。

本地预览(Agent 也能调)

文件列表每行有「预览 / 本地 / 编辑」三个动作;本地用本机默认应用打开,与在线 预览是两条独立路径:

| | 在线预览 / 编辑 | 本地预览 | | --- | --- | --- | | 打开方式 | HiWork 内嵌 OnlyOffice | 本机默认应用(Word / WPS / …) | | 需要 Document Server | 是 | 否 | | 需要登录 / 密钥 | 是 | 否(离线可用) | | Agent 可用 | 是(Agent 桥,office_document_*;仅 edit 模式,需 DS 侧装插件) | 是(工具 office_open_local) |

实现复用 DSH 的 @deepseek-ai/dsh-native-command(macOS open / Windows PowerShell Invoke-Item / Linux xdg-open,WSL 自动转换路径;全部 execFile 无 shell 解释),host 产物由 esbuild 内联。files.list 会回 localOpenAvailable, 无头环境(容器 / 无显示服务器)里按钮禁用并说明原因。

门禁与在线预览一致:只接受工作区内、白名单扩展名的文档。白名单在这条路径上是 安全边界而非能力边界——open 会连「可执行关联」一起执行(macOS 的 .command、 Windows 的 .bat),只放行文档类型才没有「让 agent 顺手执行仓库脚本」的口子。

安全模型

  • JWT 密钥只在 Host 内存(网关下发路径)与用户本机 storageDomain(本地备用路径), 不进 npm 包、不下发 Web;网关会话 cookie 全程留在 hiwork-core 的 Host 半边;
  • 文档 URL 与回调 URL 都以不可猜测的随机 token(32 hex)为路径段,文档服务 本身不接受任意路径;未知 token 一律 404;
  • session.open 做工作区包含校验(realpath 双侧对齐,防 .. 与符号链接逃逸), 工作区外的文件打不开;
  • 保存回调验签(JWT_IN_BODY),伪造回调无法覆盖文件;覆盖先写临时文件再 rename;
  • 本地预览与在线预览同一套门禁(工作区包含校验 + 扩展名白名单),且打开走 execFile 而非 shell:路径里的空格 / 引号 / 分号都不会变成命令(见 local-open.ts);
  • 回调加固(本机 docserve 与网关中继同一套四道校验):URL 签名 + DS 的 JWT + JWT payload 与 body 逐字绑定(只验签名的话,截获一张合法 token 再改 url 就能让服务去拉任意地址)+ 拉取 host 白名单(拒绝回环与链路本地/云元数据地址);
  • Agent 桥的准入:只接受配置里那个 Document Server 源发来的插件消息 (event.origin 校验),并把插件窗口 event.source 与该会话绑定一次,之后只认它; 命令只从宿主页面定向发出(event.source 不可伪造)。插件侧只认 OFFICE_BRIDGE_OPS 的白名单, 没有任意脚本通道;命令参数经 Asc.scope 传递,不拼代码。

独立安装降级

  • 凭据:没有 hiwork-core / 网关未配置下发时,用本地设置的地址与密钥(界面会 标注「本地配置」);设置分区 settings.section#office 也相应保留;
  • 入口:没有 hiwork-core 时(或它尚未加载),本插件注册设置页分区 settings.section#office;hiwork-core 后到时立刻撤下该分区并切成中央 feature;
  • 本地预览:与 hiwork-core / 网关完全无关,任何环境下都可用(无头环境除外—— 按钮会禁用)。

命名词汇(用户可见文案)

用户看到的品牌名统一是 HiWork Office;OnlyOffice / Document Server 只出现在 技术语境里(代码标识符、注释、文档、以及管理员要填的配置项)。

| 语境 | 用词 | 例 | | --- | --- | --- | | 界面标题 / 按钮 / 引导 | HiWork Office | settings.title = 「HiWork Office 设置」 | | 界面里的功能描述 | 在线编辑器 / 本机默认应用 | file.preview.title = 「在线预览:用 HiWork Office 在线编辑器打开」 | | 配置项(管理员要填的事实) | Document Server / JWT 密钥 | settings.serverUrl = 「Document Server 地址」 | | 代码标识符与注释 | OnlyOffice(准确的技术名) | OnlyOfficeEditorFrame、loadOnlyOfficeApi |

同一个功能在 hiwork-core(hiworkOfficeCredentials 的消息文案)与 ai-gateway (GET /api/me/office-config 的 503 文案)各有一份用户可见文案,改这条链上的文案时 三处要同步。

client bundle 纯度

src/client/** 对 @deepseek-ai/* 只允许 import type(打包时被擦除),运行时只 import react / react/jsx-runtime。tests/packaging.spec.ts 会在构建后扫描 lib/client.js 的 require 说明符,越界即失败。

网络要求(部署侧事实,2026-09-16 验证)

  • Document Server 必须能回连本机(拉文档 + 回调):本机需有私网 IPv4,或显式配置 advertiseHost;
  • 浏览器(桌面端 Web UI,http://127.0.0.1)必须能访问 Document Server (https://office-suite.hivery.cn,HTTPS 域名经反代提供;http 页面嵌 https iframe 不构成混合内容,且未来桌面 UI 升级 HTTPS 后也不受影响);
  • 部署侧 JWT_ENABLED=true、JWT_IN_BODY=true、ALLOW_PRIVATE_IP_ADDRESS=true;
  • Agent 桥不引入任何新的入向要求:插件与宿主页面只在浏览器进程内 postMessage, 用户电脑不需要被 Document Server 之外的任何东西访问到(云端中继 + 桥的组合也可用)。

命令

| 命令 | 作用 | | --- | --- | | pnpm typecheck | 严格类型检查 | | pnpm build | 构建 lib/index.js(Host)与 lib/client.js(Web) | | pnpm test | Vitest(DOM 用例首行 // @vitest-environment jsdom) | | pnpm verify | typecheck → build → test,提交前跑这个 | | pnpm pack | 产出 hiwork-office-<version>.tgz |

桌面端集成

本地迭代按工作区约定走 Web profile file: 安装(pnpm build && pnpm pack 后在 profile 目录 pnpm install),不必发版。要让 CI 打包 / 分发给同事时: npm publish → 更新 hiwork-desktop/src/bundled-plugins.ts 的 BUNDLED_PLUGINS 锁定版本 → 重新打包桌面端。

让改动在已装的 HiWork 里生效(2026-09-16 踩过的坑)

重启 HiWork 不会自动升级本插件:桌面端的补种只升级它自己目录 (src/bundled-plugins.ts)里的插件,office 不在其中——它是 profile 里手工加的 file: 依赖,会一直停在那个 tarball 的版本上(曾出现"改了源码、重启没效果", 因为 profile 还指着 hiwork-office-0.1.0.tgz)。

更新已装 HiWork 的正确姿势(两个 profile:~/.hiwork/profiles/web 是桌面端的, ~/.dsh/profiles/web 是 dsh web 的):

# 必须用桌面端自带的 pnpm 11(系统 pnpm 10 会因 store 版本不同报 UNEXPECTED_STORE)
NODE="/Applications/HiWork.app/Contents/Resources/node/node"
PNPM="/Applications/HiWork.app/Contents/Resources/node/pnpm-package/bin/pnpm.cjs"

pnpm build && pnpm pack     # 在本仓库产出 hiwork-office-<version>.tgz
"$NODE" "$PNPM" add file:$PWD/hiwork-office-0.3.0.tgz \
  --dir=/Users/$USER/.hiwork/profiles/web \
  --config.node-linker=hoisted --config.auto-install-peers=false \
  --config.minimumReleaseAge=0 --save-exact --registry=https://registry.npmjs.org/

装完退出并重启 HiWork 即可(插件在 Host 启动时加载,不能热替换)。要回到 registry 版本:把 profile 的 package.json 改回 "hiwork-office": "<版本>" 后用同一条命令 (或直接 add hiwork-office@<版本>)。

分支流程

按工作区约定(2026-09-09 起):先在 dev 分支开发(remote gitlab),验证通过后 合并到 master;master 只放可发布状态。