🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

侧栏网页对话 Ckarefulon/dsh-deepseek-webchat

DeepSeek Harness
Ckarefulon14 天前有提交已提供中文文档扫描:含敏感能力

一个 DSH 侧边栏插件,把真正的 chat.deepseek.com 网页应用显示在会话旁边,为每个 DSH…

30.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/18 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add Ckarefulon/dsh-deepseek-webchat
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · ui
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 14 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 28 处,展示前 24 条)
  • 读取本地文件
    lib/index.js:143
    if (!existsSync(file)) return null
  • 读取本地文件
    lib/index.js:144
    const parsed = JSON.parse(readFileSync(file, 'utf8'))
  • 写入本地文件
    lib/index.js:160
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/index.js:162
    writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
  • 写入本地文件
    lib/index.js:163
    renameSync(temporary, file)
  • 发起网络请求
    lib/client.js:483
    void fetch(ROUTES.diag, {
  • 发起网络请求
    lib/client.js:798
    const response = await fetch(ROUTES.sessionRestore, { method: 'POST' })
  • 发起网络请求
    lib/client.js:889
    await fetch(ROUTES.sessionSave, {
  • 发起网络请求
    lib/client.js:924
    const response = await fetch(ROUTES.binding, {
  • 发起网络请求
    lib/client.js:972
    const response = await fetch(
  • 发起网络请求
    lib/client.js:1109
    const response = await fetch(
  • 写入剪贴板
    lib/client.js:2086
    await navigator.clipboard.writeText(preview)
  • 发起网络请求
    src/client/index.js:483
    void fetch(ROUTES.diag, {
  • 发起网络请求
    src/client/index.js:798
    const response = await fetch(ROUTES.sessionRestore, { method: 'POST' })
  • 发起网络请求
    src/client/index.js:889
    await fetch(ROUTES.sessionSave, {
  • 发起网络请求
    src/client/index.js:924
    const response = await fetch(ROUTES.binding, {
  • 发起网络请求
    src/client/index.js:972
    const response = await fetch(
  • 发起网络请求
    src/client/index.js:1109
    const response = await fetch(
  • 写入剪贴板
    src/client/index.js:2086
    await navigator.clipboard.writeText(preview)
  • 读取本地文件
    src/index.js:143
    if (!existsSync(file)) return null
  • 读取本地文件
    src/index.js:144
    const parsed = JSON.parse(readFileSync(file, 'utf8'))
  • 写入本地文件
    src/index.js:160
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    src/index.js:162
    writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, 'utf8')
  • 写入本地文件
    src/index.js:163
    renameSync(temporary, file)
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

README

由 DeepSeek 最新模型翻译生成
dsh-deepseek-webchat 一个 DSH 侧边栏插件,把真正的 chat.deepseek.com 网页应用显示在会话旁边,为每个 DSH 会话绑定一个 DeepSeek 对话,并让你把选中的消息以引用块形式推入 DeepSeek 输入框——然后由你自己发送。 不需要 API key,不需要代理,也不做抓取。它通过桌面外壳的原生浏览器 guest 嵌入真实网站,走的通道和 DSH 内置侧边卡片浏览器相同。 - 功能 - 安装 - 使用 - 隐私 - 已知限制 - 工作原理 - 开发 - 发布 功能 | 真实网页应用 | 就是 chat.deepseek.com 本身,放在侧边栏标签页里。不是 iframe,也不是 API。 | | 登录状态保留 | 登录一次,之后启动时插件会恢复你的会话。 | | 每个 DSH 会话一个对话 | 每个 DSH 会话都有自己的 DeepSeek 对话,按 id 记住。 | | 跟随你切换的会话 | 切换 DSH 会话时,侧边栏跟着切到该会话的对话。 | | 手动推送上下文 | 勾选行,加一个问题,预览,然后填入并发送。 | | 包含提问 | 智能体向你提的问题、选项和你的回答也可以引用。 | | 包含待办列表 | 智能体的待办列表无需开启任何开关即可引用。
展开完整文档(README 剩余 1 节)
dsh-deepseek-webchat

一个 DSH 侧边栏插件,把真正的 chat.deepseek.com 网页应用显示在会话旁边,为每个 DSH 会话绑定一个 DeepSeek 对话,并让你把选中的消息以引用块形式推入 DeepSeek 输入框——然后由你自己发送。

不需要 API key,不需要代理,也不做抓取。它通过桌面外壳的原生浏览器 guest 嵌入真实网站,走的通道和 DSH 内置侧边卡片浏览器相同。

- 功能
- 安装
- 使用
- 隐私
- 已知限制
- 工作原理
- 开发
- 发布

功能

| 真实网页应用 | 就是 chat.deepseek.com 本身,放在侧边栏标签页里。不是 iframe,也不是 API。 |
| 登录状态保留 | 登录一次,之后启动时插件会恢复你的会话。 |
| 每个 DSH 会话一个对话 | 每个 DSH 会话都有自己的 DeepSeek 对话,按 id 记住。 |
| 跟随你切换的会话 | 切换 DSH 会话时,侧边栏跟着切到该会话的对话。 |
| 手动推送上下文 | 勾选行,加一个问题,预览,然后填入并发送。 |
| 包含提问 | 智能体向你提的问题、选项和你的回答也可以引用。 |
| 包含待办列表 | 智能体的待办列表无需开启任何开关即可引用。 |
| 一键发送 | 「填入并发送」会填入输入框并提交;「仅填入」只填入不发送。 |
| 批量选择 | 一键全选、清空,或取最后 5/10/20/50 行。 |
| 高级选项需主动开启 | 一个开关会显示思考过程、工具调用和结果——默认关闭。 |
| 上下文说明 | 可选的一段说明会告诉 DeepSeek 这些引用是什么、来自哪里。 |
| 无回流 | DeepSeek 的回答永远不会写回你的 DSH 会话。 |

安装

需要 DSH Desktop 0.2.0-rc.1 或更新版本,以及一个已初始化的配置档(desktop 配置档由应用在首次运行时创建)。

dsh plugin --profile desktop add dsh-deepseek-webchat

然后重启 DSH Desktop。标签页会出现在侧边栏列的引导里,会话标题栏的聊天图标可直接打开它。

lib/ 是有意提交到本仓库的,也没有 prepare 脚本,所以安装不需要构建步骤,也不需要 pnpm 的 allowBuilds 批准。

改为从本地克隆安装

git clone https://github.com/Ckarefulon/dsh-deepseek-webchat
dsh plugin --profile desktop add /absolute/path/to/dsh-deepseek-webchat

卸载

dsh plugin --profile desktop remove dsh-deepseek-webchat

你的绑定和已保存的登录信息存放在 ~/.dsh/dsh-deepseek-webchat/,会保留在原处;删除该目录即可一并清除。

故障排查:安装后 DSH 无法启动

DSH 弹出 「The application could not start or stopped unexpectedly」,打不开。崩溃日志(路径在对话框里给出,位于 %APPDATA%\@deepseek-ai\dsh-desktop\logs\ 下)里有 client-modules: client bundle not found。

这说明已安装副本的 exports["./client"] 没有指向真实文件。解决办法:从一个采用扁平布局的 commit 重新安装插件:

dsh plugin --profile desktop remove dsh-deepseek-webchat
dsh plugin --profile desktop add dsh-deepseek-webchat

重启前,先到已安装的包目录里确认布局:

node -e "const p=require('./package.json');const r=p.exports['./client'].default;console.log(r, require('fs').existsSync(r))"

必须打印 ./lib/client.js true。如果打印 false,别重启 DSH——启动还会再次中止。

对话框里的 「Disable third-party plugins, back up profile patch, and restart」 按钮同样管用:它会卸载第三方插件后启动 DSH,并把你的配置档补丁另存为 cordis.patch.yml.bak-<timestamp>。这份备份是你的配置,不是插件,留着。

使用方法

1. 打开标签页。 点会话标题栏的聊天图标,或从侧边栏的引导里选「DeepSeek 网页版」。
2. 首次登录 DeepSeek。就是面板里的普通浏览器登录。
3. 在 DeepSeek 页面发一条消息。 DeepSeek 会延迟创建会话,所以这一刻它的 id 才存在——插件会察觉,并把它绑定到当前 DSH 会话。工具栏圆点变绿。
4. 引用上下文。 按「引用上下文」。列表打开时会滚动到最新几行。勾选你要的内容——或用「全选」「清除」,或用数字框加「选末尾」一次取最后几条——可选地输入问题或指令,再检查预览。列表里有你的发言、助手的回复、智能体的待办列表、它问你的问题(连同给出的选项),以及你对这些问题的回答。
5. 按「填入并发送」。 文本会进入 DeepSeek 的输入框并替你提交;面板回到页面,选择清空,下一次推送从干净状态开始。想先在输入框里读一遍,就改用「仅填入」。
6. 这就是发送。 插件会盯着输入框确认消息发出,并告诉你结果——或者直说没发出去,你可以自己在那边按 Enter。

工具栏还有「刷新」(重载页面)和「解除绑定」(忘掉本会话的对话,下次访问开新对话)。

切换到别的 DSH 会话时,面板会自动移到那个会话的对话。

发送什么,怎么发

每次推送仍然是你主动要求的:只有你点「填入并发送」时,插件才填入输入框并提交。没有定时器,没有后台上传,而且不会仅仅因为面板打开就发送任何内容。

发送走的是 DeepSeek 自己的 composer 处理器,而不是这里自造的合成快捷键。它的 composer 运行一个 onKeyDown,对普通 Enter 会调用与发送按钮相同的函数——所以插件在 textarea 上派发一个冒泡的 Enter,剩下的交给 DeepSeek。(它的按钮类名是构建时哈希,猜它会在任何重新构建后失效。)

合成按键原则上可能被忽略,所以插件不假设它一定生效。发送被接受后 DeepSeek 会清空 textarea,因此插件回读 composer:清空即已发送。如果里面仍有文本,插件退回到点击 DeepSeek 自己的发送按钮;如果这也失败,它会如实说明,而不是假装成功——把文本留在 composer 里让你手动发送。

「附上说明」(默认开启)会在引用的行前面加一段简短说明:

以下是我在另一个 AI 助手(DSH)里的对话片段,引用给你作为背景参考。以「> 」开头的行是原文,【】里标出的是这段内容属于谁…

关掉它,DeepSeek 收到的就是一堆引用和【】标签,没有任何解释说明它们是什么。如果你更想发送原始引用,就关掉它。

高级开关

默认情况下,选择器按人阅读对话的方式列出会话,外加智能体的待办列表。勾选 「高级:包含思考过程与工具调用」 后,还会列出背后的机制:模型的推理块、工具调用、工具结果、斜杠命令和压缩摘要——包括可能含有文件内容的工具输出。每次打开时它都是关闭的,过滤由宿主完成,所以除非你主动要求,高级行根本不会发送到浏览器。

每行都标有来自 shell 自带图标集的图标和一个短标签,这样引用的回答和引用的工具结果在引用块里仍可区分:

【提问】Confirm:Which layout?
· Sidebar — right column
· Center 【回答】Sidebar, please
【待办】[x] write the picker
[~] test it

隐私

这个插件的设计原则是:除非你按下按钮,否则什么都不会离开你的机器;而且你最不想泄露的东西根本不会被提供。

发送什么,何时发送。 只发送你勾选的行,且只在你点击「填入并发送」(或「仅填入」,它停在 composer)时发送。两者都是显式操作;插件没有定时器,也没有后台上传。

永远不会提供的内容。 宿主端在会话日志到达选择器之前就做过滤,两种模式下都会丢弃:

- system/message 和 developer/message 事件,
- 注入的 user/message 事件——智能体指令、技能目录、目标轮次、时间上下文、压缩检查点、团队与 webhook 投递,DSH 把它们记录为用户消息,但你从未输入过。只有 source.kind 为 user(你的轮次)或 user-question-reply(你对智能体的回答)的事件才被当作你的内容,
- 审批记录、请求头、模型与沙箱选择。
默认关闭的内容。 模型的私有推理块、工具调用和工具结果不会提供,除非你打开高级开关。打开后请记住:工具结果可能包含智能体读过的文件内容——这正是默认设置要挡在外面的东西,而开关就是你的明确许可。待办列表是例外:它是智能体自己的计划,你已经在屏幕上读到了,所以默认提供。

因此,系统提示词、环境里的 API key,或智能体读过的文件,都不会被意外引用。

本地存储的内容。 ~/.dsh/dsh-deepseek-webchat/ 下有两个 JSON 文件:

- bindings.json —— DSH Session id → DeepSeek 会话 id 的映射。永远不含消息内容。
- session.json —— 访客的 DeepSeek 登录状态(站点存储和 non-HttpOnly cookie 字符串),让你保持登录。这是一份凭据;像对待浏览器配置档一样对待这个文件。写入权限与你用户创建的其他文件相同。

无遥测。 插件自身不发任何网络请求。唯一的流量是 DeepSeek 网页应用在自己的访客里与 DeepSeek 通信。

页面在沙箱中运行。 桌面外壳用 nodeIntegration: false、contextIsolation: true、sandbox: true 和 webSecurity: true 批准访客,并拒绝所有权限请求。页面无法触及你的文件或 DSH 进程。

已知限制

这些限制真实存在,依赖插件之前值得了解。

HttpOnly cookie 无法恢复。 DSH Host 作为独立的 Node 子进程运行,不在 Electron 内,所以插件够不到 Electron 的 cookie 存储。它只能从访客内部读取 document.cookie,而 HttpOnly cookie 按设计在那里不可见。实践中 DeepSeek 把凭据放在 localStorage.userToken 里,作为 bearer token 发送,所以重放站点存储就能恢复登录——但如果 DeepSeek 哪天把凭据挪到 HttpOnly cookie,这个插件就会在每次重启后要求你重新登录。

访客分区按次运行。 外壳分配的是进程生命周期的会话分区,插件无法申请别的分区。因此登录能存活靠的是上面的快照与重放,而不是持久的浏览器配置档。

一个 DeepSeek 登录,共享。 每个 DSH Session 共享同一个 DeepSeek 账号和浏览器会话;按 Session 拆分的是会话,不是登录。不同的 DSH Session 不会拿到不同的 DeepSeek 账号。

绑定发生在第一条消息。 DeepSeek 只在你发送内容时才创建会话,所以 DSH Session 在你于页面里至少发一条消息之前保持未绑定。在此之前,工具栏圆点是空心的。

超长会话只列出较新的行。 选择器从最新的行向前翻页,而超过约 2 MB 文本的回复不值得搬运通过 HTTP 路由进入 React 列表,因此宿主会丢弃最旧的行,列表会说明丢弃了多少行。这只影响行数上千的会话(开启高级后,还会影响工具输出达到几十 MB 的会话)。单行也限制在 4000 字符以内——选择器的一行只有一行高,而异常值是 40–50 KB 的工具结果。

DeepSeek 可能改版。 填充输入框的目标是 textarea.ds-textarea__textarea,会话 id 从 DeepSeek 的 /a/<agent>/s/<id> 路由读取。如果 DeepSeek 重新设计其中任何一个,填充或绑定就会失效,直到本插件更新。插件的其余部分——嵌入、登录、按会话分标签页——不受影响。

仅限桌面端。 嵌入页面需要桌面浏览器的 guest 通道。在普通的 dsh web 配置档中,面板会说明这一点,而不会回退到 iframe(DeepSeek 本来也会通过 frame-ancestors 'none' 拒绝)。

每个 DSH 会话一个 DeepSeek 标签页。 标签页类型是单实例的,所以你不能为同一个会话并排打开两个 DeepSeek 面板。

工作原理

架构

和 DSH 插件一样,分两半:

宿主半边(lib/index.js,导出 .)运行在 DSH 宿主进程中,在 /api/dsh-deepseek-webchat/ 下提供五个路由:

| 路由 | 用途 |
| state | 面板描述自身所需的信息。 |
| messages?sessionId=[&advanced=1] | 会话中可引用的行,已过滤。 |
| binding | 读取/写入/遗忘 DSH→DeepSeek 会话映射。 |
| session/restore | 交回保存的登录状态。 |
| session/save | 存储 guest 的登录状态。 |

它通过 ctx.sessionQuery.readSession() 读取消息,优先使用实时数据,并用 harness 自身相同的文本提取规则精简原始事件日志。

这次读取开销很大——要解码并解析整个日志——所以提取出的行会被缓存,并用一个廉价的 token 重新校验。对于实时会话,token 是内存中的 seq(ctx.sessions.get()),它精确且包含尚未刷盘的事件;对于冷会话,token 是 ctx.sessionPersistence.stat() 的修订号,它只读取存储的头部和大小,不解码任何内容。token 未变时直接返回缓存的行,完全不调用 readSession。在一个真实会话上实测(10.7 MB zstd 日志,7176 帧,12 188 个事件):读取本身约 1.2 秒的直线 CPU 时间,而重新校验后的重新打开只是一次 token 读取加一次 JSON 写入。

响应有上限:单行最多 4000 字符,一次回复的文本上限约 2 MB,超出时丢弃最旧的行(它们会以 dropped 回报),因为列表打开时显示的是最新的行。

advanced 标志在宿主侧生效,所以默认响应根本不会包含推理行或工具行——浏览器半边不可能意外泄露它从未拿到的内容。开关切换时,选择器会重新请求列表,而不是在本地过滤。
行上除了 role 还带一个 kind:对话用 user 和 assistant,智能体的提问和你的回复用 question 和 answer(默认),然后是 reasoning、tool-call、tool-result、todo、command 和 summary(高级)。question 行从 tool/call 事件读取,条件是 name === 'ask_user_question',解析时用的 questionsOf 结构与 harness 自带的用户提问服务一致;答案以普通 user/message 到达,带 source.kind === 'user-question-reply' 标记,否则会被普通的人类消息过滤器丢掉。

浏览器部分(lib/client.js,导出 ./client)注册侧边栏标签类型、它的主体,以及一个头部入口。

guest 为什么不是 iframe。 chat.deepseek.com 会发送 Content-Security-Policy: frame-ancestors 'none',所以页面拒绝 。于是 bundle 向 globalThis.dshDesktop.browser.acquire(...) 申请一个预留,并挂上一个 <webview>,其 src 为 about:blank#<lease>,partition 用签发的那一个。shell 的 will-attach-webview 匹配 lease,应用加固后的偏好设置,然后放行这次导航。

guest 为什么放在 React 之外。 <webview> 一旦离开文档就会被销毁,所以由插槽持有的 guest 会在每次切换标签时重新加载——丢掉打了一半的问题。因此这个元素放在插件自己持有的容器里,位于文档根节点,面板主体只测量自己的区域;标签显示时把 guest 定位到那个矩形上,不显示时隐藏。标签类型声明了 keepMounted: true,主体才能在切换后存活。

会话 URL 为什么能用。 DeepSeek 自己的路由是 /a/:agentId/s/:sessionId,默认智能体是 chat,所以一个会话可以寻址为 https://chat.deepseek.com/a/chat/s/<id>——重新打开会话不需要页面内 JavaScript。

开发

纯 JavaScript ESM。没有 TypeScript,没有打包器,没有依赖。

npm run build # copy src/ -> lib/
npm test # node --test

lib/ 是 src/ 的逐字节副本,并且已提交,因为托管在 git 上的插件安装时不能需要构建步骤。npm test 会断言两者仍然一致,所以它们不会漂移。

改完 src/ 后,运行 npm run build 并提交两棵目录树。

src/index.js host half -> lib/index.js
src/client/index.js browser half -> lib/client.js (note: flat, not lib/client/index.js)
scripts/build.mjs the copy
test/index.test.js host: urls, message filtering, bindings, snapshot, mirror
test/routes.test.js host: every HTTP route, driven through apply()
test/client.test.js browser: bundle load, registrations, fill + send, row icons

重启前值得跑的两个检查

manifest 坏了不会在构建时大声报错——它会中止 Host 启动,于是 DSH 干脆打不开。两个检查都是独立的:没有依赖,没有 node_modules,什么都不用装。

npm run check:bundle # this repo
node scripts/check-client-bundle.mjs <packageRoot> # any DSH plugin
node scripts/check-profile-patch.mjs <patch.yml>

check-client-bundle.mjs 原样复刻 @deepseek-ai/dsh-client-modules 里的 resolveMeta():把 exports["./client"] 拼到包根目录上,对结果调用 statSync,不补扩展名,也不回退到目录索引。文件缺失就抛 MissingClientBundleError,而 modules 是必需插件,整个 Host 启动会因此中止。它还会检查相邻的几条不变量——bundle 要声明自己的 module/exports(加载器只传 require)、要返回 module.exports、要注册自己的 id。旧 lib/client/index.js 布局下启动中止的问题,就是这条检查复现出来的。

check-profile-patch.mjs 按加载器必须采用的方式解析配置档的 cordis.patch.yml:把带 !!js 自定义标签的 YAML 当作不透明标量处理。它会打印每个条目 id,方便在信任补丁之前先审一遍——DSH 的崩溃对话框把完整补丁换成最小补丁之后,你正需要这一步。js-yaml 不是本仓库的依赖;它从已安装的 DSH 配置档里解析,或者用 DSH_JS_YAML 指向一份。

浏览器端为什么是 lib/client.js 而不是 lib/client/index.js

这一点是承重的,弄错会让 DSH 根本起不来。

DSH 解析包的浏览器端时,把 exports["./client"] 拼到包根目录上,再把结果当作精确文件路径读取——不补扩展名,也不回退到目录索引。如果清单写的是 ./lib/client.js,而构建产物写的是 ./lib/client/index.js,客户端模块注册表会在 Host 启动期间抛 MissingClientBundleError;这个注册表又是必需插件,整个启动就此中止。窗口显示「The application could not start or stopped unexpectedly」,并指出 client-hmr 在等 clientModules;崩溃日志报告:

client-modules: client bundle not found; run pnpm run build before launch:
package: <name>
path: .../lib/client.js

DSH 发布的每个包都用扁平的 ./lib/client.js 形式。npm test 会断言 exports 里每条路径都存在且是普通文件,所以这个问题不会回归。

如果你撞上那个对话框,说明你装的副本是旧的。拉取修复后的提交后重新安装(见安装)。

发布

本包以 dsh-deepseek-webchat 的名字发布到 npm。package.json 里带了 publishConfig(access: public、registry: https://registry.npmjs.org/),所以直接 npm publish 就会发到正确的 registry,不用加额外参数——即使本地 ~/.npmrc 可能指向镜像。

发布是自动的。推送到 main,.github/workflows/publish.yml 会跑测试套件,然后发布——但前提是 package.json 的 version 是 registry 里还没有的版本。所以整个发布流程就是:
1. 修改 package.json 里的 version。
2. 运行 npm run build,把 src/ 和 lib/ 一起提交(两者不一致时 npm test 会失败),然后推送到 main。

这次运行要么发布该版本,要么报告该版本已上线并成功退出。只推送、不升版本是空操作,不算失败 —— 所以每个需要发布的改动都得自己升一次版本。只改文档的提交照样会触发工作流,也照样是空操作。

认证走 npm Trusted Publishing(OIDC):GitHub 为这次任务签发一个短期 token,npm 拿它换一个发布 token,作用域仅限这一个包。任何地方都没有 NPM_TOKEN secret。工作流刻意不用 actions/setup-node 的 registry-url 输入 —— 它会往 ~/.npmrc 写入 //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN},而该变量没定义时,占位符会原样留下,npm 就把它当 token 发出去。registry 已经由 publishConfig.registry 指定了。

一次性设置:绑定受信任发布者

受信任发布者只能绑定到注册表上已存在的包,所以第一次发布是手动完成的(在检出目录里执行 npm publish);从第二次起由工作流接手。在 npmjs.com 上:package → Settings → Trusted Publisher → GitHub Actions,然后

| 字段 | 值 |
| Repository | Ckarefulon/dsh-deepseek-webchat |
| Workflow filename | publish.yml |
| Environment | (留空) |

文件名必须完全一致 —— npm 把授权绑定在它上面,不一致会表现为发布失败并报 ENEEDAUTH。

License

MIT。见 LICENSE。

与 DeepSeek 无隶属关系。"DeepSeek" 是其所有者的商标。
预览分享卡片长什么样 ↓Ckarefulon/dsh-deepseek-webchat
分享 · DeepSeek Harness Hub
Ckarefulon/dsh-deepseek-webchat

一个 DSH 侧边栏插件,把真正的 chat.deepseek.com 网页应用显示在会话旁边,为每个 DSH…

回到顶部