静默重试失败请求,截断自动续写,空输入框一键继续
29.7/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/29 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add zchuxi/dsh-restart-task该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · chat
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 39 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件
查看扫描证据(共 4 处,展示前 4 条)
- 读取本地文件restart-task.test.mjs:25
const hostSource = readFileSync(join(root, 'lib', 'index.js'), 'utf8') - 读取本地文件restart-task.test.mjs:26
const clientSource = readFileSync(join(root, 'lib', 'client.js'), 'utf8') - 读取本地文件restart-task.test.mjs:27
const patchSource = readFileSync(join(root, 'cordis.patch.yml'), 'utf8') - 读取本地文件restart-task.test.mjs:28
const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/dsh给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 静默重试失败请求
- 截断自动续写
- 空输入框一键继续
DSH Web 插件:三段式回合恢复(同轮静默重试、输出超限同轮续写、可选新一轮继续),输入框为空时发送键变成「继续」。给 DSH 的中断回合提供三段式恢复策略。
README
由 DeepSeek 最新模型翻译生成description: "DSH Web 插件:把被打断的回合救回来 —— 同一步内静默重试、输出被截断时同轮续写、可选的新一轮继续;输入框为空时发送键本身会变成「继续」。"
kind: "package-reference"
dsh-restart-task
DeepSeek Harness Web profile 插件:输入框里的一个回合恢复控件、它背后的三段式恢复策略,以及一整套设置卡片。
所有设计只服务于一条原则:恢复过的请求不该留下痕迹。
| 层级 | 何时生效 | 对话记录里多出什么 |
| 1. 同一步内重试 | 模型请求失败 | 什么都不多 —— 连一行都没有 |
| 2. 同轮续写(keep-alive) | 回复撞上输出上限 | 不新开回合;续写那一行被隐藏 |
| 3. 新开一轮继续 | 回合已经以失败收场 | 一个回合 + 一条折叠记录(默认隐藏) |
0. 适用版本
展开完整文档(README 剩余 1 节)
description: "DSH Web 插件:把被打断的回合救回来 —— 同一步内静默重试、输出被截断时同轮续写、可选的新一轮继续;输入框为空时发送键本身会变成「继续」。"
kind: "package-reference"
dsh-restart-task
DeepSeek Harness Web profile 插件:输入框里的一个回合恢复控件、它背后的三段式恢复策略,以及一整套设置卡片。
所有设计只服务于一条原则:恢复过的请求不该留下痕迹。
| 层级 | 何时生效 | 对话记录里多出什么 |
| 1. 同一步内重试 | 模型请求失败 | 什么都不多 —— 连一行都没有 |
| 2. 同轮续写(keep-alive) | 回复撞上输出上限 | 不新开回合;续写那一行被隐藏 |
| 3. 新开一轮继续 | 回合已经以失败收场 | 一个回合 + 一条折叠记录(默认隐藏) |
0. 适用版本
针对 DSH 0.1.7-rc.1 及其后的 0.1.x 编写,并且在 loader 会真正校验的地方写明了这一点:peerDependencies["@deepseek-ai/dsh"] 为 >=0.1.7-rc.1 =0.1.8-rc.1 范围为什么要写成两段:node-semver 只有当范围里某个比较符与该版本的 major.minor.patch 元组完全一致、且自身带预发布标签时,才放行预发布版本。写成看着更宽的 >=0.1.7-rc.1 时,0.1.8-rc.1 这类下一条补丁线的 rc 会被静默排除,用户只会撞上 ERESOLVE(或 loader 直接跳过这个 bundle)。所以每个受支持的元组各占一段,并用 「回合即将关闭……提出异议的监听器会 steer(agent.steer(...)),机器重新读取收件箱:新的 steering 会再跑一步,谁都不会关闭回合。」
—— dsh-agent/lib/types/runtime-types.d.ts,agent/turn-stopping
于是轮次数、轨道和历史都不移动。受 maxTurnContinues 约束(每回合),且仅当该步的结束原因真的是 max-tokens 时才触发 —— 这个原因取自实时 agent/assistant-stream 的 finish 帧,比边界早一帧,因此无需翻会话日志。
两条诚实限制:
- 该边界只在正常停止时到达。aborted 与 error 是经 throw 离开循环的,所以第 2 层对它们永不适用。
- 被 steer 的指令仍是一条落盘的 user/message —— 它渲染为一条折叠记录(见 §6),永远不会变成你的发言气泡。
4. 第 3 层 —— 新开一轮继续(默认关,可见)
当回合真的以失败收场时,继续动作会通过 agent.followup 发出一条插件来源的消息:
{ role: 'user',
content: [{ type: 'text', text: '' }],
source: { kind: 'dsh-restart-task', form: 'notice',
summary: '继续上次中断的任务' } }
source.kind !== 'user' 是它不会变成用户气泡的原因:它渲染为一条折叠记录 —— 而且因为这条消息开启了这一轮,产品会把它渲染成「非人类触发」通知而不是上下文行(§6)。这个 kind 必须是本生产者自己的名字:会话格式 v4 要求生产者自有的 source kind,并拒绝已退休的插件命名空间包装(kind: 'plugin' + plugin 字段),后者只会在 v3→v4 转换既有历史时被抬升。写成旧形状会让整个回合失败并报 format v4 message requires a producer-owned source kind,因为继续消息是在该步能运行之前就被追加的。但它仍然是一个新回合,所以对话记录会多出那一行、轮次轨道会多出一格 —— 这正是 autoContinue 默认关闭、并提供手动控件按需使用的原因。
resend(手动、仅发送失败时)是唯一会发出用户文本的路径 —— 一条从未到达宿主的输入不在历史里,重发它是唯一可能有效的做法。它不注册乐观回显,因此不会出现两行。
5. 为什么已结束的回合不能就地继续
这是 agent 循环的结构性约束,不是缺 API。事实如下,备查:
- 新回合号只能是 previous + 1,并且总是以 turn/start 宣告(dsh-agent-loop/lib/index.js,turn())。
- turn/end 在 finally 块里被追加,任何路径都会执行,所以坏掉的回合在任何插件听说它之前就已持久关闭。
- 每一条进入 step 的消息都以 user/message + surfaceOp: 'append' 追加;插件无法为「唤醒循环的那条消息」选择非追加的 surface op。
- 会话事件是只追加的:Session 接缝与持久化层都没有 remove / truncate / rewrite API,因此继续动作无法在事后被剪掉。(dsh-rewind-plugin 也不删除事件 —— 它追加替换 surface,而替换副本只对模型可见。)
- interrupted 标记由崩溃修复路径写入,它在事后关闭一个孤儿回合;循环从不实时发出它,恢复会话也不会唤醒驱动。
所以「能否不新开回合就继续」的完整答案就是第 1、2 层;对已经结束的回合,第 3 层是唯一可能的做法。
6. 隐藏续写行 The records at layers 2 and 3 exist so that the model can read the instructions; they are conduits, and Chat gives them only two forms — neither of which can be selected individually with a stylesheet:
| Form | When | Identified by |
| Collapsed context row | The message did not open that turn (layer 2: steered steps) | A valueless data-context-source attribute, with the producer name as text |
| Non-human trigger notification (data-chat-flow-kind="turn-trigger") | The message opened that turn (layer 3, manual continuation) | Nothing — an unknown source kind cannot even be distinguished from a "request trigger" |
So hideContinueRow (default on) is a small transcript traversal, not a selector: any row that can be attributed to this plugin gets tagged with data-dyn-restart-row="1", and then a conditional style hides this plugin's own markers:
[data-chat-flow-kind="context"][data-dyn-restart-row="1"],
[data-chat-flow-kind="turn-trigger"][data-dyn-restart-row="1"] { display: none !important; }
Attribution has two sources, and never guesses:
1. Context rows whose source label is exactly this plugin's source.kind.
2. Trigger notification rows within turns opened by this plugin — turns come from the live session event window (ownWakingTurns), and the window is published by the input box control of the currently displayed session. A turn's input is appended after its turn/start, never before (the persistent order is turn/start(7) → user/message(kind: dsh-restart-task) → …), so when a message is exactly the first input that falls into its turn, that means the turn was opened by it. Layers 1 and 3 are delivered via the next-turn inbox, which is precisely why their rows become trigger notifications; layer 2's steer is claimed by some step of an already-opened turn, so it is never the first input and never occupies a turn. When the window is not yet ready this rule is skipped, and rule 1 still covers layer 2.
The second source is cumulative, and the third makes attribution cover the entire session. The client only ever holds a paginated window; collapsing a completed turn or loading another slice of history replaces it with a smaller window; a set recomputed only from the current window would forget the turns it had already recognized, and the rail marks would come back until the next slice of history arrives. So:
- Anything either source has said is remembered until the session switches, at which point it is cleared;
- The host half registers a session projection (restartTaskRounds: the same set of rules, but collapsing the entire log rather than one page); the projection seam delivers its value in full to the client, and the browser half then merges it into the set. This is exactly why turns whose "events were never loaded at all" can be attributed — under a paginated transcript (Load earlier), you cannot tell on screen who opened that turn.
Rows from other producers — time context, AGENTS.md, skills, cron, subagent settlement, goal turns — are never tagged and never hidden. The traversal is idempotent (React re-renders do not touch other people's attributes), clears its own markers when the toggle is off or the plugin is unloaded, and does nothing at all for views it cannot understand, rather than hiding a row whose attribution is unknown. Thus "lost attribution" is only a loss in appearance (some row continues to show), and never turns into a wrong guess about someone else's row.
An honest note: the first rule reads product rendering rather than a declarative API, so if some version changes the flow attribute or changes the source label text, the traversal will stop matching (it will not break — that row simply shows again); the second and third only take effect when the host has registered the projection, and assemblies without that seam fall back to pure window attribution (in which case turns that failed to load still cannot be attributed until the history is loaded); also, these rules do not touch the cell of a layer 3 turn on the rail (see §7).
7. Turn rail
A layer 3 continuation is a real turn, so the rail gains an extra cell for it — and because this turn has no human question, that cell's hover card can only degrade into an anonymous "Turn N / Turn N". This degradation is not data the plugin can change: the rail is inline JSX with no extension point, and the session-wide turnOutline projection only accepts question previews with source.kind === 'user' (dsh-session-turn-outline/lib/types/projection.js).
So continuedRailMarks treats it as a presentation problem and offers three modes:
| Mode | Effect |
| hide (default) | That turn's rail mark (along with its hover card) is not shown |
| preview | The mark is kept (still clickable to jump); on hover, "Turn N" is no longer shown, only that turn's answer preview |
| keep | The product's own behavior, with no intervention at all |
Mechanically this is a very small DOM traversal, not a stylesheet trick. Turns come from the set of turns attributed to this plugin by ownWakingTurns (§6) — the turns themselves, not the tagged rows: a layer 2 steer hides a row within "the human's own turn", but that turn's rail mark is absolutely not something this plugin should touch. Each rail mark is matched to a turn via its accessible label (its only per-turn attribute), and then tagged according to the configured mode:
[data-dyn-continued='hide'] { display: none !important; }
nav[data-dyn-continued-preview='1'] [class='_previewPrompt'] { display: none !important; }
This plugin's own turn's mark is tagged hide/preview, while other marks remain exactly as the product made them. Because hide is display: none on the mark itself, the hover card loses its mount target: that turn's "Turn N" hint simply never appears.
Hiding only the mark does half the job. The rail's virtualization reserves space for this turn — it decides the height of the mark container based on its own measurements and never reflows because of hiding; the product itself also writes no per-mark geometry — so a hidden mark leaves a hole in the middle of the rail. The traversal therefore compacts what is on screen: it measures the spacing between the currently rendered marks, moves every mark after a hidden mark up by one spacing, and subtracts the number of hidden turns from the container height. Both of these are only this plugin's own inline overrides, recomputed on every traversal, and removed as soon as there are no marks to hide or the plugin is unloaded, so the rail returns to exactly what the product originally drew. 诚实限制:只能标记并压实视图真正渲染过的轮次(远离已加载窗口的轮次会在滚动到之后被处理);标记是虚拟化的,所以任意时刻只处理轨道自身滚动窗口里的标记;它通过可访问标签匹配,因为标记本身没有轮次属性;轨道的 DOM 在 0.1.7 变了(标记容器里的 button[data-index],没有逐标记位置包装),本遍历读的就是这个;压实是对产品自己会重算的几何做补偿 —— 一次重渲染会把标记放回虚拟化想要的位置,而下一次遍历(隔着一次 DOM 变动)会再次压实。
8. 设置卡片
插件页 → dsh-restart-task(侧边栏里由插件管理器拥有的那一页)。卡片注册进该页的 plugins.bundle.config 席位,键是 bundle 的包名(dsh-restart-task)—— 这是该页自己的契约(「自带配置的 bundle」),也是 0.1.7 重构后唯一保留的席位(旧的 settings.plugin.item 标签页已消失)。只有当宿主提供本插件的设置条目时才会注册,所以从未挂载该行的部署看不到本卡片的任何痕迹。
卡片拥有自己的全部外观:可折叠标题(带实时策略摘要)、四个分组、逐字段的「已自定义 / 恢复默认」,以及带写入状态和「全部恢复默认」的页脚。
设置卡片(上):标题与实时策略摘要、优先级说明、请求失败的原地重试分组、输出超限的同轮续写分组
设置卡片(下):回合已结束后的继续方式、触发条件、继续指令与呈现方式(隐藏折叠记录、轮次导航标记)
| 字段 | 默认 | 含义 |
| retryFailedRequests | true | 在同一个 step 内重试失败的请求(不可见) |
| maxRequestRetries | 3 | 同轮重试次数上限(0 = 不重试) |
| retryForever | false | 忽略预算,重试到成功或中止 |
| retryBaseDelayMs | 2000 | 退避基数:2s、4s、8s… 上限 60s |
| keepAliveOnMaxTokens | true | 让被截断的回合保持开启,在回合内续写 |
| maxTurnContinues | 5 | 单个回合内允许续写几次(0 = 不限) |
| autoContinue | false | 坏掉的回合之后自动开新一轮继续(可见) |
| delayMs | 1500 | 中断之后等待多久再继续 |
| maxConsecutive | 3 | 连续继续的轮数上限(0 = 不限) |
| onAborted | true | 系统取消(父 agent / hook)之后继续;用户主动停止永不继续 |
| onError | true | 模型请求失败之后继续 |
| onInterrupted | true | 崩溃遗留孤儿回合之后继续 |
| sendBecomesContinue | true | 输入框为空时,把继续交给产品发送键(见 §1.1) |
| hideContinueRow | true | 在 Chat 里隐藏本插件自己的折叠行 |
| continuedRailMarks | hide | 轨道如何呈现本插件继续出的轮次(hide / preview / keep) |
| continueText | (内置) | 发给模型的继续指令 |
autoContinue 关闭时,onAborted / onError / onInterrupted 会被禁用,因为它们只描述那一层何时触发。
值是怎么进出的(0.1.7 的配置模型)
设置命名空间已经不存在,所以接线是这样的:
- 宿主半边的 Config 就是表单。 每个字段都标了 .volatile(),这是它能被实时编辑的前提;loader 随后给 apply 每个字段一个引用,config..get() 就是三层策略每次决策时读取的东西。一次写入在下一次中断时生效,无需重启,也不涉及任何插件事件。
- 表单用 profile 条目 id 寻址,即 restart-task —— 本包 cordis.patch.yml 插入的那个 id。它不是包名,而浏览器半边无法 import 宿主半边的常量,所以两半和 patch 文件各写一遍;回归测试会断言三者一致。
- 写入经 configForms.get('restart-task')(浏览器半边为该条目共享的表单):快照给出被服务的表单值加原始用户层,逐字段 set / unset,底下是带版本号的改动队列。被拒绝的写入返回 false,冲突则重新读取宿主而不是覆盖它。
- 宿主不会再生成一个页面:插件在可选的 settings 子上下文里注册 settings.configure({ auto: false }, ctx.fiber)。这个子上下文是刻意可选的 —— 没有设置域的组装仍然能跑三层恢复和输入框控件,只是卡片和两个对话记录遍历不出现。
当客户端与宿主不一致时
浏览器半边可能比正在运行的宿主新 —— 这是插件更新后、profile 重启前的常态。此时条目可能没有被服务,或缺少较新的字段,卡片会说明而不是让写入失败:宿主未提供的字段以只读显示「宿主还是旧版本:重启 DSH 后这一项才会生效」;宿主根本没有提供该条目时提示「宿主没有提供本插件的设置入口」;非回环页面(设置仅在该会话内存中)也会被标注。
结构
- cordis.patch.yml —— profile bundle patch,插入 restart-task 行;这个 id 同时就是设置条目 id,文件里的注释也这么写。
- lib/index.js —— 宿主半边:每个字段都 .volatile() 的 Config、同轮重试、同轮续写、可选的继续回合、continue-task 命令。
- lib/client.js —— 浏览器半边:window.__ModuleLoader__.load bundle,导出 apply + inject(['slots', 'timer'])、输入框控件、插件页卡片(挂在可选的 configForms 子上下文上),以及给本插件自己的行打标、呈现其继续出的轮次、并在输入框为空时把继续交给产品发送键的对话记录遍历。
- restart-task.test.mjs —— 回归测试(见下)。
- screenshots.json —— 市场详情页展示的 1–8 张截图(见 §8);docs/awesome-dsh-plugin-entry.yml —— 提交或更新 awesome-dsh-plugin 收录时复制过去的那一条目。截图刻意放在本仓库:换图只需往这里推一次,不用去那边提 PR、等维护者。
输入框控件的形状刻意用 !important 钉住:它住在产品的 composer 工具行里,那一行有自己的 button/svg 规则。设置卡片使用产品的 --dsw-alias- token,并在不依赖任何东西的前提下匹配其卡片外观(.5px 边框、16px 圆角、14–16px 头部内边距)。两个注入的 标签都带 data-plugin,因为模块系统按该属性归属样式:没有归属的标签会被下一个物化的插件认领,并在那个插件卸载时被删掉。
有三处区域被直接断言 —— lib/index.js 的 auto-logic、lib/client.js 的 core-logic,以及宿主模块自身的导出 —— 所以出厂代码跑的就是被测的决策:
node dsh-restart-task/restart-task.test.mjs # 305 条断言,两半都覆盖
测试分四层,因为移植到 0.1.7 时坏过三种方式,而行/轨道的呈现只能看它对文档的实际效果:
1. 规则 —— 重试预算(确定性 4xx、429、倍增、60s 上限、不限次)、保活门槛(只有 max-tokens、每轮上限)、回合级门槛(坏掉的原因、逐原因开关、连击上限)、对话记录读取(只认人类提问、坏掉与干净的结束)、开轮识别、控件模式选择、头部摘要文案。
2. 接线 —— 所有身份字符串一致(patch 条目 id ↔ 宿主 ENTRY_ID ↔ 客户端 ENTRY_ID,包名 ↔ bundle 席位键 ↔ 生产者 kind),每个 Config 字段都是 volatile 且每个被服务的字段都由卡片渲染,已退休的设置接缝、席位、选择器全部消失,行隐藏规则以本插件自己的标记为键,两个样式标签都写明归属。
3. 宿主行为 —— 真正 import lib/index.js,并用桩 Cordis 上下文驱动:命令只发一条生产者来源的消息;401 被委派而 500 等待后原地重试;等待中被停止则委派;被截断的一步在回合内 steer,而完成的一步不会;回合级继续只在开启时发生,且永不发生在用户停止之后,也永不越过连击上限。
4. 对话记录、轨道与发送键(桩 DOM) —— 加载浏览器半边并应用到一份假 document 上:里面有一个本插件开的轮次、一个人类开的轮次(其中带着本插件的同轮 steer)、别的生产者的上下文行与触发通知,以及一个主按钮初始为禁用的输入框。结果是:本插件自己的行被打标而别人的没有;steer 行只靠来源标签就能认出,而触发通知需要会话窗口;本插件那一轮的轨道标记在 hide 模式下被隐藏、preview 模式下被标记,而人类那一轮与外部轮次的标记永不被动;发送键被接管、被点击(点击在产品看到之前就被截停,改由圆形控件执行)、在输入框有内容时不被接管、开关关闭后被交还;窗口缩小时(折叠/分页)不会把已经认出的轮次收回。事件夹具抄自真实的 session.v4.jsonl,包括决定归属的 turn/start → 消息顺序。
延伸阅读
下面这些页面是本插件依赖的接缝,方便逐条对照它声明的版本核对:
- DeepSeek Harness —— 运行时、插件契约,以及全文引用的各包:dsh-agent(Agent 外观与 agent/request-error / agent/turn-stopping 分发)、dsh-agent-loop(回合与 step 边界)、dsh-settings(配置表单)、dsh-session-format(v4 来源规则)、dsh-client-ui-conversation(输入框及其席位)、dsh-client-ui-chat(flow 行与轮次轨道)。
- dsh-client-shortcuts —— 本插件刻意不改绑的固定输入动作(fixed.send = Enter、fixed.newline = Shift+Enter、fixed.complementary = Ctrl/Cmd+Enter);「忙时回车」到底是排队还是插话,是 ui-conversation 设置里的 busyEnter。
- dsh-llm-retry —— 挂在本插件上游、耗尽自身策略后委派给它的产品重试执行器。
- dsh-client-ui-plugin-manager —— 拥有 plugins.bundle.config 席位(本卡片注册的地方)的插件页。
模型体验
分层的模型可见性:
- 第 1 层不可见:被重试的请求用同一段持久历史重建同一个 step,没有任何重试事件、延迟或提供方错误到达模型。
- 第 2 层多出一条 user/message,其 source.kind 是本插件名:模型读到指令,人类读到一条折叠记录(默认隐藏)。
- 第 3 层是一个新回合,唯一输入就是这条生产者来源的消息。因此模型看到的是一句「接着做」的指令,绝不会是用户原话的第二份拷贝。
KV Cache 影响
被重试与被继续的请求都会重建与它所恢复的那次尝试相同的前缀,因此在该提供方的规则下缓存复用得以保留。插件本身不贡献 token:不加工具 schema、不加系统提示词文本,除了第 2、3 层真正需要的那一条继续指令之外不加任何上下文。
开发说明
- 测试就是规格。 restart-task.test.mjs 从出厂源码里切出纯函数区域,并真正驱动宿主模块,所以某条规则不可能在这里通过而出厂代码另做一套。
- 事件夹具取自真实日志。 决定归属的 turn/start → 消息顺序,是从一份真实 session.v4.jsonl(每批追加一个 zstd 帧)里读出来的 —— 在这之前,规则的第一版假设了相反的顺序,于是静默地什么都认不出来。
- 通过 DOM 遍历读取产品渲染是刻意的,因为产品没有为它们所作用的那些东西提供席位(折叠上下文行的来源是文本,触发通知没有任何来源属性,轮次轨道是 inline JSX,输入框主按钮也是 inline JSX)。每一处都被写成「读不懂就什么都不做」而不是猜,各自的边界都写在它旁边。
安装 / 移除
直接从本仓库安装(无需 registry):
dsh plugin --profile web add github:zchuxi/dsh-restart-task
或:dsh plugin --profile web add https://github.com/zchuxi/dsh-restart-task 或从本地 checkout:dsh plugin --profile web add link: 然后重启 profile(宿主 + 页面):宿主半边变了
dsh plugin --profile web remove dsh-restart-task
desktop 是 Electron 专属的 profile 名,CLI 会拒绝它;请改在插件管理器里用同一个 git 地址安装。
bundle 通过其 dsh.bundle.patch 清单字段加入 dsh.profile.bundles;移除依赖后,下一次启动就不再插入那一行。
本地 checkout 请放在不含空格的路径下。dsh plugin 会把参数经 shell 转发,含空格的路径会被拆成若干个错误依赖。
环境要求。 DSH >=0.1.7-rc.1 =0.1.8-rc.1 =24,以及一个运行时依赖 —— @deepseek-ai/schemastery ^3.18.4(第一个 schema 能 .volatile() 的版本)。开发用 checkout 请用 npm install --legacy-peer-deps 安装:@deepseek-ai/dsh 这个 peer 是插件运行所在的宿主,不该作为构建依赖被拖下来。
浏览器半边是热重载的:dsh-client-hmr 会轮询每个客户端 bundle 的修改时间,把重建后的版本换进正在运行的页面,所以编辑 lib/client.js 保存即生效。宿主半边需要重启 profile —— agent/turn-stopping 和新的设置键都要等 lib/index.js 重新加载后才存在。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
zchuxi/dsh-restart-task
静默重试失败请求,截断自动续写,空输入框一键继续
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,489已汉化DSH
73.1
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,918已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,453已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
Download DS Bot for Windows 10/11 64-bit / 下载 Windows…
★ 5,293已汉化DSH
71.2
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,797已汉化DSH
71.1
这是你的仓库?认领条目