@dsh-workbench/core 1.1.16 → 1.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -50,7 +50,7 @@ dsh-workbench migrate --force # 已经迁过一次、想再补并一次
50
50
 
51
51
  | 要有 | 为什么 |
52
52
  |---|---|
53
- | `dsh` ≥ 0.2.1-rc.2 | 本体。更旧的会被拒绝:`engines.dsh` 声明了下限,老到不认这个字段的 dsh 由启动器当场拒绝并给升级命令 |
53
+ | `dsh` ≥ 0.2.1-rc.5 | 本体。更旧的会被拒绝:`engines.dsh` 声明了下限,老到不认这个字段的 dsh 由启动器当场拒绝并给升级命令 |
54
54
  | Node + pnpm | dsh 的 `plugin` 子命令转发给 pnpm;没有 pnpm 会报 `dsh: pnpm was not found` |
55
55
  | 可选:跑过一次 `dsh web` | 想继承它的设置 / 插件时。只建工作台不需要 |
56
56
 
@@ -93,13 +93,14 @@ dsh-workbench migrate --force # 已经迁过一次、想再补并一次
93
93
  | `dist/types/**` | 类型声明(`exports` 的 `types` 指向这里);构建产物,不进 git |
94
94
  | `client.js` | 浏览器侧 bundle,dsh 客户端按 `dsh.client` 加载 |
95
95
  | `cordis.patch.yml` | 把自己插进 profile 组合图的补丁(装载) |
96
- | `preset/diy.patch.yml` | 「工作台 DIY 模式」的 preset;由 `scripts/gen-diy-preset.mjs` 从 dsh 出厂那份 `standard.patch.yml` 派生(生成后提交,selfcheck 盯过期) |
97
96
  | `profile/` | 出厂 profile 模板:可写根那一行(启动器 `--patch` 用,seed 也抄进 profile) |
98
97
  | `skills/` | 模块 DIY 指引,装好后挂给 agent;漏了不报错,只是 agent 不知道要怎么做模块 |
99
98
  | `bin/` | `dsh-workbench` 启动器、隔离 opencli 的入口 |
100
99
  | `scripts/` | 随包出货的脚本:`seed-profile.sh` / `seed-workshop.sh` / `create-workbench.mjs` / `clone-profile.mjs` / `share-data-root.mjs` / `patch-blocks.mjs` |
101
100
  | `icon.svg` | 插件图标(dsh 插件页用) |
102
101
 
102
+ 「工作台 DIY 模式」不在这个表里:**启动时现场派生**,没有生成物 —— `src/shared/api/host/diy-preset.ts` 从这一轮 dsh 的 `standard` preset 克隆出插件表、叠加三处差分并注册;纯规则在 `../shared/src/host/diy-preset.ts`。dsh 加工具 / 改行时它自动跟上。
103
+
103
104
  ## 数据落在哪
104
105
 
105
106
  | 内容 | 位置 |
@@ -172,7 +173,7 @@ dsh-workbench migrate --force # 已经迁过一次、想再补并一次
172
173
  | 模型列表里只有出厂的几个、没有自己配的供应商 | 新 profile 不带设置。设置 → 工作台设置 → 配置同步 → 勾 `llm-` 那几行 → 同步 |
173
174
  | 配置同步里某行说 `@x 还没装` | 那一行点名的包不在这个 profile 的 `node_modules` 里:`dsh plugin --profile workbench add @x`(或在模块市场装),装完 dsh 会自行重组,它报 `restartReason` 时才重启 |
174
175
  | 启动被拒,说 dsh 太旧 | `npm i -g @deepseek-ai/dsh@latest`,装完重启工作台 |
175
- | 左栏没有「工作台DIY」,模式下拉里也没有「工作台 DIY 模式」 | 多半是 dsh 太旧:DIY preset 从 dsh 0.2.1-rc.2 的 preset 清单派生,旧一代挂不起来,而 dsh 的模式选择器只列挂得起来的 ⇒ 整个不见且不报错。启动体检会把它摆出来并给升级命令;自己核对就看 dsh 的 设置 → 「Agent presets」那一行的红标与原因 |
176
+ | 左栏没有「工作台DIY」,模式下拉里也没有「工作台 DIY 模式」 | DIY preset 是启动时从这一轮 dsh 的 `standard` 现场派生的:dsh 太旧(没有 `loader` / `agentPresets` 的注册口)或 `standard` 的行变了,就派生不出来;dsh 的模式选择器只列挂得起来的 ⇒ 整个不见且不报错。启动体检会把它摆出来并给升级命令;自己核对就看 dsh 的 设置 → 「Agent presets」那一行的红标与原因 |
176
177
  | 在自己项目里开了 DIY,面板却说没找到模块 | 模块跟**这条会话的工作区**走,不跟工坊走:① 那个工作区要有一个在 `package.json` 里声明 `dsh.workbench` 的包;② 从工坊带过去的,把模块目录挪 / 拷进那个仓库;③ 旧截图不迁移(新的落在 `~/.dsh/workbench/artifacts/<工作区>/`)。细节见工作台模块指引 |
177
178
 
178
179
  ## 从源码跑
package/bin/dsh-workbench CHANGED
@@ -152,13 +152,13 @@ fi
152
152
 
153
153
  # ── 硬门禁:dsh 太旧就别起(DIY 模式会整个不见,而且一句错都不报)────────────
154
154
  #
155
- # DIY 模式就是 `preset/diy.patch.yml` 那一行 agent preset,而它是**从 dsh 出厂那份
156
- # `standard.patch.yml` 派生的**(scripts/gen-diy-preset.mjs)—— 所以它跟的是**派生那一刻的
157
- # dsh**。dsh 旧到那份清单里有几个包它根本没有时(实测 0.2.0-rc.2 缺
158
- # `@deepseek-ai/dsh-tool-schedule`),preset 挂不起来;dsh 的模式选择器**只列挂得起来的**
159
- # (healthy presets only),于是「工作台 DIY 模式」在用户面前整个消失,界面与终端都不吭声。
160
- # 同一代 dsh 0.2.0 的 `uiWorkspace.startSession()` 也**不收** `agentPreset`(0.2.1-alpha.3 才收),
161
- # 所以就算 preset 挂上了,「造一个模块」也落不到 DIY 模式 —— 这一档没有"少一把工具"的降级空间。
155
+ # DIY 模式是**启动时现场派生**的(`shared/host/diy-preset` + 宿主的 `diy-preset.ts`):从这一轮
156
+ # dsh 的 `standard` preset 克隆插件表、叠加三处差分,再走 `agentPresets.register()`。所以要两样
157
+ # 东西都在:dsh 的 `loader` 能交出 `preset-standard` 那一行,`agentPresets` 有程序化注册口。
158
+ # 少一样,preset 根本不在名册里;而 dsh 的模式选择器**只列挂得起来的**(healthy presets only),
159
+ # 「工作台 DIY 模式」就在用户面前整个消失,界面与终端都不吭声。
160
+ # 更旧的一代(0.2.0-rc.2)连 `uiWorkspace.startSession()` 都**不收** `agentPreset`(0.2.1-alpha.3 才收),
161
+ # 所以就算派生出来了,「造一个模块」也落不到 DIY 模式 —— 这一档没有"少一把工具"的降级空间。
162
162
  #
163
163
  # 为什么门禁写在启动器、而不只写 package.json 的 `engines.dsh`:
164
164
  # engines.dsh 只有 **0.2.1-alpha.4 起**的 dsh 才读(见 HANDOFF §八),而这台机器上那份 dsh
@@ -198,8 +198,8 @@ process.exit(0);
198
198
  ' || DSH_FLOOR_GUARD=$?
199
199
  if [ "${DSH_FLOOR_GUARD:-0}" -eq 1 ]; then
200
200
  echo "dsh-workbench: 这台机器上的 dsh 是 ${DSH_VERSION},这份工作台要 ${DSH_FLOOR}。" >&2
201
- echo " 低于它时 DIY 模式(会话里的「工作台 DIY 模式」)挂不起来,而 dsh 的模式选择器只列挂得起来的" >&2
202
- echo " —— 它会**整个不出现**,不报错。所以这里直接拒绝启动。" >&2
201
+ echo " 低于它时工作台要的那几个注册口(loader / agentPresets / startSession 的 agentPreset)不一定有," >&2
202
+ echo " DIY 模式会**整个不出现**且不报错。所以这里直接拒绝启动。" >&2
203
203
  echo " 升级 dsh(再重启一次工作台): npm i -g @deepseek-ai/dsh@latest" >&2
204
204
  exit 1
205
205
  fi
package/client.js CHANGED
@@ -5484,6 +5484,7 @@ window.__ModuleLoader__.load({
5484
5484
  latest,
5485
5485
  ...blocked === void 0 ? {} : { blocked },
5486
5486
  ...module.market === void 0 ? {} : { market: module.market },
5487
+ ...module.versions === void 0 ? {} : { versions: module.versions },
5487
5488
  pkg: module.pkg,
5488
5489
  ...module.spec === void 0 ? {} : { spec: module.spec },
5489
5490
  ...module.registry === void 0 ? {} : { registry: module.registry }
@@ -16314,7 +16315,6 @@ window.__ModuleLoader__.load({
16314
16315
  }
16315
16316
  function SessionRow({ node, active, onOpen, renderSlot, t }) {
16316
16317
  const [menuOpen, setMenuOpen] = (0, react.useState)(false);
16317
- const menuState = (0, react.useMemo)(() => [menuOpen, setMenuOpen], [menuOpen]);
16318
16318
  const statuses = sessionStatuses(node, t);
16319
16319
  const label = node.blank ? t("session.new") : node.title;
16320
16320
  const titleRef = (0, react.useRef)(null);
@@ -16365,7 +16365,7 @@ window.__ModuleLoader__.load({
16365
16365
  }
16366
16366
  }, /* @__PURE__ */ (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutlineRegular, { size: 16 })),
16367
16367
  onClose: () => setMenuOpen(false)
16368
- }, renderSlot("sidebar.workspaces.session.menu.item", owner, { hookContext: menuState })), renderSlot("sidebar.workspaces.session.row.action", owner))),
16368
+ }), renderSlot("sidebar.workspaces.session.row.action", owner))),
16369
16369
  content: /* @__PURE__ */ (0, react.createElement)(SessionHoverContent, {
16370
16370
  node,
16371
16371
  statuses,
@@ -17178,7 +17178,7 @@ window.__ModuleLoader__.load({
17178
17178
  name: "sidebar",
17179
17179
  priority: -1,
17180
17180
  locale: LOCALE_NS,
17181
- children: sidebarChildren(ctx),
17181
+ children: sidebarChildren(),
17182
17182
  inject: () => ({
17183
17183
  listPanels: () => readPanels(ctx),
17184
17184
  subscribePanels: (callback) => ctx.slots.subscribe("sidebar.panellist", callback),
@@ -17282,7 +17282,7 @@ window.__ModuleLoader__.load({
17282
17282
  inject: () => ({ t: ctx.locale.bind(LOCALE_NS) })
17283
17283
  }, WorkbenchSettingsSection));
17284
17284
  }
17285
- function sidebarChildren(ctx) {
17285
+ function sidebarChildren() {
17286
17286
  return {
17287
17287
  "sidebar.brand.mark": {
17288
17288
  kind: "single",
@@ -17308,14 +17308,6 @@ window.__ModuleLoader__.load({
17308
17308
  kind: "list",
17309
17309
  scope: "root"
17310
17310
  },
17311
- "sidebar.workspaces.session.menu.item": {
17312
- kind: "list",
17313
- scope: "root",
17314
- inject: { hooks: {
17315
- menuOpenState: menuOpenStateFactory,
17316
- shortcuts: ctx.shortcuts.catalog
17317
- } }
17318
- },
17319
17311
  "sidebar.workspaces.session.row.action": {
17320
17312
  kind: "list",
17321
17313
  scope: "root"
@@ -17330,9 +17322,6 @@ window.__ModuleLoader__.load({
17330
17322
  }
17331
17323
  };
17332
17324
  }
17333
- function menuOpenStateFactory(_standard, state) {
17334
- return () => state;
17335
- }
17336
17325
  //#endregion
17337
17326
  exports.apply = apply;
17338
17327
  exports.inject = inject;
package/cordis.patch.yml CHANGED
@@ -21,6 +21,11 @@
21
21
  # **独占 claim**,两个 entry 声明同一批座位会抛错;而运行时只给声明了 children 的
22
22
  # entry 发 `renderSlot`。所以两套左栏不能同时在场,只能按组合层二选一。
23
23
  # 证据:内部设计记录 §3。
24
+ #
25
+ # 0.2.2 起 `sidebar.workspaces.session.menu.item` 由 dsh 的 ui-workspace(Session menu
26
+ # adapter,挂在 contextMenu.content 下)声明;自定义左栏**既不声明、也不 renderSlot 它** ——
27
+ # 声明会抛 `already declared`,而由没有声明它的 entry 去 renderSlot 会抛
28
+ # `not declared by this entry's children`,两条都会让整条左栏被 slot 边界摘掉 ⇒ 左栏消失。
24
29
 
25
30
  # ── 权限预设:多给一档「全盘写 + 保留审批」 ────────────────────────────
26
31
  # dsh 出厂只有「工作区内修改」(workspace-write + ask)与「完全权限」
@@ -5477,6 +5477,7 @@ function installedRows(modules, manifests, listed, names, defaults = /* @__PURE_
5477
5477
  latest,
5478
5478
  ...blocked === void 0 ? {} : { blocked },
5479
5479
  ...module.market === void 0 ? {} : { market: module.market },
5480
+ ...module.versions === void 0 ? {} : { versions: module.versions },
5480
5481
  pkg: module.pkg,
5481
5482
  ...module.spec === void 0 ? {} : { spec: module.spec },
5482
5483
  ...module.registry === void 0 ? {} : { registry: module.registry }
@@ -16307,7 +16308,6 @@ function SessionHoverContent({ node, statuses, renderSlot, t }) {
16307
16308
  }
16308
16309
  function SessionRow({ node, active, onOpen, renderSlot, t }) {
16309
16310
  const [menuOpen, setMenuOpen] = (0, react.useState)(false);
16310
- const menuState = (0, react.useMemo)(() => [menuOpen, setMenuOpen], [menuOpen]);
16311
16311
  const statuses = sessionStatuses(node, t);
16312
16312
  const label = node.blank ? t("session.new") : node.title;
16313
16313
  const titleRef = (0, react.useRef)(null);
@@ -16358,7 +16358,7 @@ function SessionRow({ node, active, onOpen, renderSlot, t }) {
16358
16358
  }
16359
16359
  }, /* @__PURE__ */ (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutlineRegular, { size: 16 })),
16360
16360
  onClose: () => setMenuOpen(false)
16361
- }, renderSlot("sidebar.workspaces.session.menu.item", owner, { hookContext: menuState })), renderSlot("sidebar.workspaces.session.row.action", owner))),
16361
+ }), renderSlot("sidebar.workspaces.session.row.action", owner))),
16362
16362
  content: /* @__PURE__ */ (0, react.createElement)(SessionHoverContent, {
16363
16363
  node,
16364
16364
  statuses,
@@ -17171,7 +17171,7 @@ function mount(ctx) {
17171
17171
  name: "sidebar",
17172
17172
  priority: -1,
17173
17173
  locale: LOCALE_NS,
17174
- children: sidebarChildren(ctx),
17174
+ children: sidebarChildren(),
17175
17175
  inject: () => ({
17176
17176
  listPanels: () => readPanels(ctx),
17177
17177
  subscribePanels: (callback) => ctx.slots.subscribe("sidebar.panellist", callback),
@@ -17275,7 +17275,7 @@ function registerWorkbenchSettingsSection(ctx) {
17275
17275
  inject: () => ({ t: ctx.locale.bind(LOCALE_NS) })
17276
17276
  }, WorkbenchSettingsSection));
17277
17277
  }
17278
- function sidebarChildren(ctx) {
17278
+ function sidebarChildren() {
17279
17279
  return {
17280
17280
  "sidebar.brand.mark": {
17281
17281
  kind: "single",
@@ -17301,14 +17301,6 @@ function sidebarChildren(ctx) {
17301
17301
  kind: "list",
17302
17302
  scope: "root"
17303
17303
  },
17304
- "sidebar.workspaces.session.menu.item": {
17305
- kind: "list",
17306
- scope: "root",
17307
- inject: { hooks: {
17308
- menuOpenState: menuOpenStateFactory,
17309
- shortcuts: ctx.shortcuts.catalog
17310
- } }
17311
- },
17312
17304
  "sidebar.workspaces.session.row.action": {
17313
17305
  kind: "list",
17314
17306
  scope: "root"
@@ -17323,9 +17315,6 @@ function sidebarChildren(ctx) {
17323
17315
  }
17324
17316
  };
17325
17317
  }
17326
- function menuOpenStateFactory(_standard, state) {
17327
- return () => state;
17328
- }
17329
17318
  //#endregion
17330
17319
  exports.apply = apply;
17331
17320
  exports.inject = inject;
@@ -5480,6 +5480,7 @@ function installedRows(modules, manifests, listed, names, defaults = /* @__PURE_
5480
5480
  latest,
5481
5481
  ...blocked === void 0 ? {} : { blocked },
5482
5482
  ...module.market === void 0 ? {} : { market: module.market },
5483
+ ...module.versions === void 0 ? {} : { versions: module.versions },
5483
5484
  pkg: module.pkg,
5484
5485
  ...module.spec === void 0 ? {} : { spec: module.spec },
5485
5486
  ...module.registry === void 0 ? {} : { registry: module.registry }
@@ -16310,7 +16311,6 @@ function SessionHoverContent({ node, statuses, renderSlot, t }) {
16310
16311
  }
16311
16312
  function SessionRow({ node, active, onOpen, renderSlot, t }) {
16312
16313
  const [menuOpen, setMenuOpen] = useState(false);
16313
- const menuState = useMemo(() => [menuOpen, setMenuOpen], [menuOpen]);
16314
16314
  const statuses = sessionStatuses(node, t);
16315
16315
  const label = node.blank ? t("session.new") : node.title;
16316
16316
  const titleRef = useRef(null);
@@ -16361,7 +16361,7 @@ function SessionRow({ node, active, onOpen, renderSlot, t }) {
16361
16361
  }
16362
16362
  }, /* @__PURE__ */ createElement(IconEllipsisOutlineRegular, { size: 16 })),
16363
16363
  onClose: () => setMenuOpen(false)
16364
- }, renderSlot("sidebar.workspaces.session.menu.item", owner, { hookContext: menuState })), renderSlot("sidebar.workspaces.session.row.action", owner))),
16364
+ }), renderSlot("sidebar.workspaces.session.row.action", owner))),
16365
16365
  content: /* @__PURE__ */ createElement(SessionHoverContent, {
16366
16366
  node,
16367
16367
  statuses,
@@ -17174,7 +17174,7 @@ function mount(ctx) {
17174
17174
  name: "sidebar",
17175
17175
  priority: -1,
17176
17176
  locale: LOCALE_NS,
17177
- children: sidebarChildren(ctx),
17177
+ children: sidebarChildren(),
17178
17178
  inject: () => ({
17179
17179
  listPanels: () => readPanels(ctx),
17180
17180
  subscribePanels: (callback) => ctx.slots.subscribe("sidebar.panellist", callback),
@@ -17278,7 +17278,7 @@ function registerWorkbenchSettingsSection(ctx) {
17278
17278
  inject: () => ({ t: ctx.locale.bind(LOCALE_NS) })
17279
17279
  }, WorkbenchSettingsSection));
17280
17280
  }
17281
- function sidebarChildren(ctx) {
17281
+ function sidebarChildren() {
17282
17282
  return {
17283
17283
  "sidebar.brand.mark": {
17284
17284
  kind: "single",
@@ -17304,14 +17304,6 @@ function sidebarChildren(ctx) {
17304
17304
  kind: "list",
17305
17305
  scope: "root"
17306
17306
  },
17307
- "sidebar.workspaces.session.menu.item": {
17308
- kind: "list",
17309
- scope: "root",
17310
- inject: { hooks: {
17311
- menuOpenState: menuOpenStateFactory,
17312
- shortcuts: ctx.shortcuts.catalog
17313
- } }
17314
- },
17315
17307
  "sidebar.workspaces.session.row.action": {
17316
17308
  kind: "list",
17317
17309
  scope: "root"
@@ -17326,8 +17318,5 @@ function sidebarChildren(ctx) {
17326
17318
  }
17327
17319
  };
17328
17320
  }
17329
- function menuOpenStateFactory(_standard, state) {
17330
- return () => state;
17331
- }
17332
17321
  //#endregion
17333
17322
  export { apply, inject, kit };
@@ -2726,6 +2726,107 @@ function createDebugStore() {
2726
2726
  }
2727
2727
  };
2728
2728
  }
2729
+ //#endregion
2730
+ //#region ../shared/dist/contract/protocol/diy.js
2731
+ var DIY_PRESET_ID = "workbench-diy";
2732
+ var WORKSHOP_TITLE = "工作台DIY";
2733
+ //#endregion
2734
+ //#region ../shared/dist/host/diy-preset.js
2735
+ var AGENT_PRESET_PLUGIN = "@deepseek-ai/dsh-agent-preset";
2736
+ var STANDARD_PRESET_ID = "standard";
2737
+ /** DIY preset 在模式菜单里的名字。 */
2738
+ var DIY_PRESET_NAME = "工作台 DIY 模式";
2739
+ /** DIY preset 在模式菜单里的说明。 */
2740
+ var DIY_PRESET_DESCRIPTION = "看 / 调这个工作区的面板,或者给它造一块新内容 —— 用大白话说就行。任何工作区都能用(空项目也算);agent 会看面板、抓请求,必要时把模块造出来装上。不用写代码。";
2741
+ /** 这一轮 dsh 的 standard preset 没法派生时抛的错:带上哪一段锚点变了。 */
2742
+ var DiyPresetSourceError = class extends Error {
2743
+ constructor(message) {
2744
+ super(message);
2745
+ this.name = "DiyPresetSourceError";
2746
+ }
2747
+ };
2748
+ function isRow(value) {
2749
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2750
+ }
2751
+ function rowAt(value, at) {
2752
+ if (!isRow(value)) throw new DiyPresetSourceError(`${at} 不是一行插件配置`);
2753
+ return value;
2754
+ }
2755
+ function standardConfigOf(value) {
2756
+ const standard = rowAt(value, "dsh 的 standard preset");
2757
+ if (!Array.isArray(standard.plugins)) throw new DiyPresetSourceError("dsh 的 standard preset 没有 plugins 表 —— 派生不出 DIY 那一份");
2758
+ return standard;
2759
+ }
2760
+ function clonedPluginsOf(standard) {
2761
+ let cloned;
2762
+ try {
2763
+ cloned = structuredClone(standard);
2764
+ } catch (error) {
2765
+ throw new DiyPresetSourceError(`dsh 的 standard preset 配置复制不了:${String(error)}`);
2766
+ }
2767
+ const rows = rowAt(cloned, "dsh 的 standard preset").plugins;
2768
+ if (!Array.isArray(rows)) throw new DiyPresetSourceError("dsh 的 standard preset 没有 plugins 表 —— 派生不出 DIY 那一份");
2769
+ return rows.map((row, index) => {
2770
+ const parsed = rowAt(row, `dsh 的 standard preset 第 ${index + 1} 行`);
2771
+ if (typeof parsed.name !== "string" || parsed.name === "") throw new DiyPresetSourceError(`dsh 的 standard preset 第 ${index + 1} 行没有插件名`);
2772
+ return parsed;
2773
+ });
2774
+ }
2775
+ function takeRow(plugins, id) {
2776
+ const index = plugins.findIndex((row) => row.id === id);
2777
+ if (index < 0) throw new DiyPresetSourceError(`dsh 的 standard preset 里找不到 \`${id}\` 那一行 —— DIY 的差分锚点变了`);
2778
+ return plugins.splice(index, 1)[0];
2779
+ }
2780
+ /**
2781
+ * 从这一轮 dsh 的 `standard` preset 配置派生 `workbench-diy`。
2782
+ *
2783
+ * 差分只有三处:`skill-filesystem` 与 `tool-skill` 一起搬到末尾(前者加 `customSkillDirs` 指向工作台的
2784
+ * `skills/`)、末尾补 `tool-cordis`、`tool-plugin-manager` 打开(工作台只活在 profile 里)。
2785
+ * 其余行原样跟着 dsh 走,所以 dsh 加工具 / 改 config 时不需要重新生成任何文件。
2786
+ * @param standard dsh loader 里 `preset-standard` 那一行收到的 config。
2787
+ * @param skillsDir 工作台的 `skills/` 绝对路径。
2788
+ */
2789
+ function diyPresetFrom(standard, skillsDir) {
2790
+ const plugins = clonedPluginsOf(standardConfigOf(standard));
2791
+ const skillFilesystem = takeRow(plugins, "skill-filesystem");
2792
+ const toolSkill = takeRow(plugins, "tool-skill");
2793
+ skillFilesystem.config = {
2794
+ ...isRow(skillFilesystem.config) ? skillFilesystem.config : {},
2795
+ customSkillDirs: [skillsDir]
2796
+ };
2797
+ const manager = plugins.find((row) => row.id === "tool-plugin-manager");
2798
+ if (manager !== void 0) manager.disabled = false;
2799
+ if (!plugins.some((row) => row.id === "tool-cordis")) plugins.push({
2800
+ id: "tool-cordis",
2801
+ name: "@deepseek-ai/dsh-tool-cordis"
2802
+ });
2803
+ plugins.push(skillFilesystem, toolSkill);
2804
+ const seen = /* @__PURE__ */ new Set();
2805
+ for (const row of plugins) {
2806
+ if (typeof row.id !== "string" || row.id === "") continue;
2807
+ if (seen.has(row.id)) throw new DiyPresetSourceError(`dsh 的 standard preset 里出现重复的 id:${row.id}`);
2808
+ seen.add(row.id);
2809
+ }
2810
+ return {
2811
+ id: DIY_PRESET_ID,
2812
+ name: DIY_PRESET_NAME,
2813
+ description: DIY_PRESET_DESCRIPTION,
2814
+ order: 9,
2815
+ plugins
2816
+ };
2817
+ }
2818
+ /**
2819
+ * 在 loader 的行里找这一轮 dsh 的 `standard` preset 配置;没有(或那一行被关掉)就算不知道。
2820
+ * @param entries loader 的 `entries()`(递归给全部行)。
2821
+ */
2822
+ function standardPresetConfigOf(entries) {
2823
+ for (const entry of entries) {
2824
+ if (entry.disabled === true) continue;
2825
+ if (entry.options?.name !== AGENT_PRESET_PLUGIN) continue;
2826
+ const config = entry.options.config;
2827
+ if (isRow(config) && config.id === STANDARD_PRESET_ID) return config;
2828
+ }
2829
+ }
2729
2830
  /**
2730
2831
  * 把工具入参收成人话动作。
2731
2832
  * @param raw - 任意入参值。
@@ -7634,12 +7735,16 @@ function moduleVersionsHandler(ctx, seam, running, selfUpdate) {
7634
7735
  const fromRegistry = module.fromRegistry !== false;
7635
7736
  const registry = fromRegistry ? module.registry ?? fallback : void 0;
7636
7737
  const spec = dependencyOf(module.pkg);
7637
- const latest = local || !fromRegistry || !check || seam === void 0 || registry === void 0 ? void 0 : await supply.latestVersion({
7738
+ const probed = local || !fromRegistry || !check || seam === void 0 || registry === void 0 ? void 0 : await supply.latestVersion({
7638
7739
  seam,
7639
7740
  name: module.pkg,
7640
7741
  registry,
7641
7742
  force
7642
7743
  });
7744
+ const list = !local && fromRegistry && check && force && seam !== void 0 && registry !== void 0 && probed !== void 0 && supply.isNewerVersion(probed, module.version) && manager.listVersions !== void 0 ? await manager.listVersions(module.pkg, registry).catch(() => null) : null;
7745
+ const listed = list?.status === "listed" ? list.versions : [];
7746
+ const newest = listed[0]?.version;
7747
+ const latest = newest === void 0 ? probed : probed === void 0 || supply.isNewerVersion(newest, probed) ? newest : probed;
7643
7748
  const raw = supply.moduleDeclarationOf(dir, module.pkg);
7644
7749
  const declared = raw === void 0 ? [] : declarationProblemsOf(module.pkg, raw);
7645
7750
  const title = titleOf(raw);
@@ -7650,7 +7755,9 @@ function moduleVersionsHandler(ctx, seam, running, selfUpdate) {
7650
7755
  registry,
7651
7756
  force
7652
7757
  });
7653
- const latestBlocked = latestRaw === void 0 ? void 0 : updateBlockOf(latestRaw, declarationProblemsOf(module.pkg, latestRaw));
7758
+ const peerBlocked = latestRaw === void 0 ? void 0 : updateBlockOf(latestRaw, declarationProblemsOf(module.pkg, latestRaw));
7759
+ const incompatible = listed.find((entry) => entry.version === latest)?.incompatible;
7760
+ const latestBlocked = peerBlocked ?? (incompatible === void 0 ? void 0 : "incompatible");
7654
7761
  if (refused === void 0) refusalLog.delete(module.pkg);
7655
7762
  else {
7656
7763
  const line = refused.join(";");
@@ -7671,6 +7778,7 @@ function moduleVersionsHandler(ctx, seam, running, selfUpdate) {
7671
7778
  latestUnavailable: "local"
7672
7779
  } : latest !== void 0 ? {} : !fromRegistry ? { latestUnavailable: "not-registry" } : registry === void 0 ? { latestUnavailable: "no-registry" } : check ? { latestUnavailable: "probe-failed" } : {},
7673
7780
  ...refused === void 0 ? {} : { refused },
7781
+ ...list === null ? {} : { versions: list },
7674
7782
  ...spec === void 0 ? {} : { spec },
7675
7783
  ...registry === void 0 ? {} : { registry }
7676
7784
  };
@@ -7857,7 +7965,6 @@ function createHostRoutes(input) {
7857
7965
  [MODULE_VERSIONS_ROUTE]: moduleVersionsHandler(ctx, seamOf(ctx), running, () => profile.selfUpdateView(dshHome(), basename(profile.dirOf(ctx) ?? "")))
7858
7966
  };
7859
7967
  }
7860
- var WORKSHOP_TITLE = "工作台DIY";
7861
7968
  //#endregion
7862
7969
  //#region src/shared/api/host/diy.ts
7863
7970
  function workshopPathOf(_ctx) {
@@ -14698,25 +14805,35 @@ async function updateModuleBundle(unit, deps) {
14698
14805
  if (declared !== void 0 && supply.declarationRefusalOf(pkg, declared).length > 0) throw new Error("源上的新版和当前这一版工作台不匹配 —— 先升级工作台,再更新这个模块。");
14699
14806
  }
14700
14807
  const spec = latest === void 0 ? pkg : `${pkg}@${latest}`;
14701
- const outcome = await replaceDshBundle(deps.routeDeps, spec, { ...registry === void 0 ? {} : { registry } });
14808
+ const delegated = latest !== void 0 && registry !== void 0 && found.fromRegistry !== false && deps.manager.updateBundle !== void 0 ? await deps.manager.updateBundle(pkg, latest, { registry }).catch(() => null) : null;
14809
+ const forwarded = delegated !== null && delegated.change.errorCode !== "invalid-spec" ? delegated : null;
14810
+ const base = forwarded === null ? await replaceDshBundle(deps.routeDeps, spec, { ...registry === void 0 ? {} : { registry } }) : {
14811
+ change: forwarded.change,
14812
+ module: deps.installed?.(pkg) ?? {
14813
+ kind: "unknown",
14814
+ pkg
14815
+ },
14816
+ supply: { state: "no-needs" },
14817
+ ...forwarded.restore?.version === void 0 ? {} : { restored: forwarded.restore.version }
14818
+ };
14702
14819
  await deps.sweep();
14703
14820
  const restored = (deps.installed?.(pkg) ?? {
14704
14821
  kind: "unknown",
14705
14822
  pkg
14706
- }).kind === "module" ? void 0 : await restoreRemovedBundle(pkg, before, registry, deps);
14823
+ }).kind === "module" ? base.restored : base.restored ?? await restoreRemovedBundle(pkg, before, registry, deps);
14707
14824
  let after = deps.installed?.(pkg) ?? {
14708
14825
  kind: "unknown",
14709
14826
  pkg
14710
14827
  };
14711
14828
  const verified = verifyBundleUpdate({
14712
- change: outcome.change,
14829
+ change: base.change,
14713
14830
  before,
14714
14831
  after,
14715
14832
  ...restored === void 0 ? {} : { restored }
14716
14833
  });
14717
14834
  let change = verified.change;
14718
14835
  let restoredVersion = verified.restored;
14719
- const swap = stillStuck(change, after, before) && before !== void 0 && deps.dshHome !== void 0 && deps.profileName !== void 0 ? await swapExternally({
14836
+ const swap = !(forwarded !== null && forwarded.step === "check") && stillStuck(change, after, before) && before !== void 0 && deps.dshHome !== void 0 && deps.profileName !== void 0 ? await swapExternally({
14720
14837
  supply,
14721
14838
  installed: deps.installed,
14722
14839
  dshHome: deps.dshHome,
@@ -14746,7 +14863,7 @@ async function updateModuleBundle(unit, deps) {
14746
14863
  await deps.refreshSupply(unit).catch(() => void 0);
14747
14864
  const remedy = stillStuck(change, after, before) ? remedyOf(deps, change, before, after.kind === "module" ? after.version : void 0, spec) : void 0;
14748
14865
  return {
14749
- ...outcome,
14866
+ ...base,
14750
14867
  change,
14751
14868
  module: after,
14752
14869
  ...restoredVersion === void 0 ? {} : { restored: restoredVersion },
@@ -19478,6 +19595,86 @@ function createApprovalGate(deps) {
19478
19595
  };
19479
19596
  }
19480
19597
  //#endregion
19598
+ //#region src/shared/api/host/diy-preset.ts
19599
+ var RETRY_MS = 250;
19600
+ var DEADLINE_MS = 15e3;
19601
+ function skillsDirOf() {
19602
+ try {
19603
+ const manifest = createRequire(import.meta.url).resolve("@dsh-workbench/core/package.json");
19604
+ return join(dirname(manifest), "skills");
19605
+ } catch (error) {
19606
+ return null;
19607
+ }
19608
+ }
19609
+ function registerDiyPreset(ctx) {
19610
+ const skillsDir = skillsDirOf();
19611
+ if (skillsDir === null) {
19612
+ ctx.logger?.warn?.("[dsh-workbench] 读不到自己的包根:DIY 的 skills 目录定不下来,这一轮不注册「工作台 DIY 模式」");
19613
+ return;
19614
+ }
19615
+ const dir = skillsDir;
19616
+ let timer;
19617
+ let stopped = false;
19618
+ let gaveUp = false;
19619
+ let unregister;
19620
+ const until = now() + DEADLINE_MS;
19621
+ function schedule() {
19622
+ if (stopped || gaveUp) return;
19623
+ if (now() >= until) {
19624
+ gaveUp = true;
19625
+ ctx.logger?.warn?.(`[dsh-workbench] 等了 ${DEADLINE_MS}ms 仍没拿到 dsh 的 standard preset —— 这一轮不注册「工作台 DIY 模式」(dsh 的 loader 里没有 preset-standard?)`);
19626
+ return;
19627
+ }
19628
+ timer = setTimeout(attempt, RETRY_MS);
19629
+ }
19630
+ function attempt() {
19631
+ if (stopped || gaveUp) return;
19632
+ const registry = ctx.get("agentPresets");
19633
+ const loader = ctx.get("loader");
19634
+ if (registry?.register === void 0 || loader === void 0) {
19635
+ schedule();
19636
+ return;
19637
+ }
19638
+ let standard;
19639
+ try {
19640
+ standard = standardPresetConfigOf(loader.entries());
19641
+ } catch (error) {
19642
+ ctx.logger?.warn?.(`[dsh-workbench] 读 dsh 的 loader 行失败:${String(error)}`);
19643
+ schedule();
19644
+ return;
19645
+ }
19646
+ if (standard === void 0) {
19647
+ schedule();
19648
+ return;
19649
+ }
19650
+ let definition;
19651
+ try {
19652
+ definition = diyPresetFrom(standard, dir);
19653
+ } catch (error) {
19654
+ ctx.logger?.warn?.(`[dsh-workbench] DIY 模式派生失败:${String(error)}`);
19655
+ return;
19656
+ }
19657
+ registry.register(definition).then((off) => {
19658
+ if (stopped) {
19659
+ off();
19660
+ return;
19661
+ }
19662
+ unregister = off;
19663
+ ctx.logger?.info?.(`[dsh-workbench] 「工作台 DIY 模式」从这一轮 dsh 的 standard 现场派生(${definition.plugins.length} 行)`);
19664
+ }, (error) => {
19665
+ ctx.logger?.warn?.(`[dsh-workbench] 注册「工作台 DIY 模式」失败:${String(error)}`);
19666
+ });
19667
+ }
19668
+ ctx.effect(() => {
19669
+ attempt();
19670
+ return () => {
19671
+ stopped = true;
19672
+ if (timer !== void 0) clearTimeout(timer);
19673
+ if (unregister !== void 0) unregister();
19674
+ };
19675
+ }, "dsh-workbench: DIY 模式从这一轮 dsh 的 standard 现场派生(没有生成物)");
19676
+ }
19677
+ //#endregion
19481
19678
  //#region src/shared/api/host/long-task-notice.ts
19482
19679
  var LONG_TASK_NOTICE_KIND = "workbench-long-task";
19483
19680
  function longTaskStopNotice(unit, change) {
@@ -19507,6 +19704,7 @@ var inject = ["webServer"];
19507
19704
  async function apply(ctx, config) {
19508
19705
  const seam = provideWorkbenchSeam(ctx);
19509
19706
  if (seam !== void 0) provideGitProcessSeam(seam);
19707
+ registerDiyPreset(ctx);
19510
19708
  const facts = createFactLog();
19511
19709
  const values = createValueHandoff();
19512
19710
  const panelState = createPanelStateStore();
@@ -1,4 +1,4 @@
1
- import type { ModuleUpdateBlock } from '../../../kernel/contract/bundle-install';
1
+ import type { BundleVersionList, ModuleUpdateBlock } from '../../../kernel/contract/bundle-install';
2
2
  import type { MarketInstalledModule } from '../../../kernel/contract/market-index';
3
3
  import type { InstallFailure } from '@dsh-workbench/shared';
4
4
  import type { FailureCardModel } from './failure-card-text';
@@ -22,6 +22,7 @@ export interface ModuleUpdate {
22
22
  readonly local?: boolean;
23
23
  readonly blocked?: ModuleUpdateBlock;
24
24
  readonly market?: MarketInstalledModule;
25
+ readonly versions?: BundleVersionList;
25
26
  readonly pkg?: string;
26
27
  readonly spec?: string;
27
28
  readonly registry?: string;
@@ -1,4 +1,4 @@
1
- import type { LatestUnavailable, ModuleUpdateBlock, ModuleVersion } from '../../../kernel/contract/bundle-install';
1
+ import type { BundleVersionList, LatestUnavailable, ModuleUpdateBlock, ModuleVersion } from '../../../kernel/contract/bundle-install';
2
2
  import type { MarketInstalledModule } from '../../../kernel/contract/market-index';
3
3
  import type { Translate, UnitManifest, UnitTitle } from '@dsh-workbench/shared';
4
4
  import type { InstalledPlugin } from '../../../shared/api/installed-plugins';
@@ -25,6 +25,7 @@ export interface InstalledWorkbenchModule {
25
25
  readonly refused?: readonly string[] | undefined;
26
26
  readonly clientRefused?: readonly string[] | undefined;
27
27
  readonly market?: MarketInstalledModule | undefined;
28
+ readonly versions?: BundleVersionList | undefined;
28
29
  readonly spec?: string | undefined;
29
30
  readonly registry?: string | undefined;
30
31
  }
@@ -1,2 +1,2 @@
1
1
  export { BUNDLE_REGISTRIES_ROUTE, BUNDLE_INSPECT_ROUTE, BUNDLE_REGISTRY_DEFAULT, MODULE_VERSIONS_ROUTE, SELF_UPDATE_STATES, RESTART_REASONS } from '@dsh-workbench/shared/contract/protocol/bundle-install';
2
- export type { BundleRegistry, BundleRegistries, BundleInspectProblem, BundleSpecKind, BundleInspectionAccepted, BundleInspectionRefused, BundleInspectionPlugin, BundleInspection, BundleRegistriesPayload, BundleInspectionPayload, BundleApplication, SelfUpdateState, WorkbenchSelfUpdate, RestartReason, BundleChangeStage, BundleFailureKind, BundlePackageResult, BundleChange, BundleInstallRequest, BundleCancellation, BundleSupplyState, BundleModulePayload, BundleSupplyPayload, BundleInstalledPlugin, BundleInstallPayload, BundleRemovePayload, BundleCancellationPayload, LatestUnavailable, ModuleVersion, ModuleUpdateBlock, WorkbenchVersion, ModuleVersionsPayload } from '@dsh-workbench/shared/contract/protocol/bundle-install';
2
+ export type { BundleRegistry, BundleRegistries, BundleInspectProblem, BundleSpecKind, BundleInspectionAccepted, BundleInspectionRefused, BundleInspectionPlugin, BundleInspection, BundleRegistriesPayload, BundleInspectionPayload, BundleApplication, SelfUpdateState, WorkbenchSelfUpdate, RestartReason, BundleChangeStage, BundleFailureKind, BundlePackageResult, BundleChange, BundleIncompatible, BundleInstallRequest, BundleCancellation, BundleVersionProblem, BundleRegistryAttempt, BundleVersionEntry, BundleVersionList, BundleVersionListListed, BundleVersionListRefused, BundleUpdateStep, BundleUpdateOutcome, BundleUpdateRequest, BundleSupplyState, BundleModulePayload, BundleSupplyPayload, BundleInstalledPlugin, BundleInstallPayload, BundleRemovePayload, BundleCancellationPayload, LatestUnavailable, ModuleVersion, ModuleUpdateBlock, WorkbenchVersion, ModuleVersionsPayload } from '@dsh-workbench/shared/contract/protocol/bundle-install';
@@ -0,0 +1,2 @@
1
+ import type { DshHostContext } from '@dsh-workbench/shared';
2
+ export declare function registerDiyPreset(ctx: DshHostContext): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dsh-workbench/core",
3
- "version": "1.1.16",
3
+ "version": "1.1.17",
4
4
  "description": "个人工作台:Agent 工作台(左栏 + 常驻对话 + 自研右侧数据面板)。",
5
5
  "type": "module",
6
6
  "icon": "./icon.svg",
@@ -32,7 +32,6 @@
32
32
  "icon.svg",
33
33
  "bin",
34
34
  "skills",
35
- "preset",
36
35
  "scripts/create-workbench.mjs",
37
36
  "scripts/clone-profile.mjs",
38
37
  "scripts/patch-blocks.mjs",
@@ -48,8 +47,7 @@
48
47
  "dsh": {
49
48
  "bundle": {
50
49
  "patch": [
51
- "./cordis.patch.yml",
52
- "./preset/diy.patch.yml"
50
+ "./cordis.patch.yml"
53
51
  ]
54
52
  },
55
53
  "client": {
@@ -64,7 +62,7 @@
64
62
  }
65
63
  },
66
64
  "engines": {
67
- "dsh": ">=0.2.1-rc.2"
65
+ "dsh": ">=0.2.1-rc.5"
68
66
  },
69
67
  "peerDependencies": {
70
68
  "react": "*"
@@ -76,7 +74,7 @@
76
74
  },
77
75
  "devDependencies": {
78
76
  "@arch-guard/core": "^0.11.3",
79
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.2",
77
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.5",
80
78
  "@types/node": "^24.19.0",
81
79
  "@types/proper-lockfile": "^4.1.4",
82
80
  "@types/react": "^19.3.0",
@@ -97,8 +95,8 @@
97
95
  "proper-lockfile": "^4.1.2",
98
96
  "which": "^7.0.0",
99
97
  "write-file-atomic": "^8.0.0",
100
- "@dsh-workbench/adapters-default": "1.1.16",
101
- "@dsh-workbench/shared": "1.1.16"
98
+ "@dsh-workbench/adapters-default": "1.1.17",
99
+ "@dsh-workbench/shared": "1.1.17"
102
100
  },
103
101
  "license": "MIT",
104
102
  "repository": {
@@ -1,138 +0,0 @@
1
- # Agent preset workbench-diy:DIY 模式。**这个文件是生成的**,别手改 ——
2
- # 改 packages/core/scripts/gen-diy-preset.mjs 再重跑它。
3
- #
4
- # 它从 dsh 出厂那份 standard.patch.yml 派生(整表 plugins 归 dsh 管,手抄会漂),
5
- # 只叠加三处差分:DIY skill 目录、tool-cordis、plugin-manager 打开。
6
- # 派生逻辑与差分理由写在生成器开头。
7
- - insert:
8
- - id: preset-workbench-diy
9
- name: '@deepseek-ai/dsh-agent-preset'
10
- config:
11
- id: workbench-diy
12
- name: 工作台 DIY 模式
13
- description: 看 / 调这个工作区的面板,或者给它造一块新内容 —— 用大白话说就行。任何工作区都能用(空项目也算);agent 会看面板、抓请求,必要时把模块造出来装上。不用写代码。
14
- order: 9
15
- plugins:
16
- - id: persona
17
- name: '@deepseek-ai/dsh-persona'
18
- config:
19
- prefix: You are a coding agent powered by the {{model}} model.
20
- - id: agent-instructions
21
- name: '@deepseek-ai/dsh-agent-instructions'
22
- config:
23
- maxBytes: 65536
24
- - id: time-context
25
- name: '@deepseek-ai/dsh-time-context'
26
- - id: tool-bash
27
- name: '@deepseek-ai/dsh-tool-bash'
28
- disabled: !!js process.platform === 'win32'
29
- - id: tool-pwsh
30
- name: '@deepseek-ai/dsh-tool-pwsh'
31
- disabled: !!js process.platform !== 'win32'
32
- - id: tool-fs
33
- name: '@deepseek-ai/dsh-tool-fs'
34
- - id: tool-fs-search
35
- name: '@deepseek-ai/dsh-tool-fs-search'
36
- config:
37
- sampleOverCapGlobResults: false
38
- - id: tool-jobs
39
- name: '@deepseek-ai/dsh-tool-jobs'
40
- - id: tool-schedule
41
- name: '@deepseek-ai/dsh-tool-schedule'
42
- - id: command-goal
43
- name: '@deepseek-ai/dsh-command-goal'
44
- - id: tool-goal
45
- name: '@deepseek-ai/dsh-tool-goal'
46
- - id: planning
47
- name: cordis:group
48
- group: true
49
- isolate:
50
- planMode: true
51
- config:
52
- - id: plan-mode
53
- name: '@deepseek-ai/dsh-plan-mode'
54
- config:
55
- section: |
56
- You are in plan mode. Stay in plan mode until the user approves your plan through exit_plan_mode or switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
57
-
58
- Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
59
-
60
- The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
61
-
62
- Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
63
-
64
- Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
65
-
66
- When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
67
- - id: compaction
68
- name: cordis:group
69
- group: true
70
- isolate:
71
- compaction: true
72
- toolResultPruner: true
73
- config:
74
- - id: compaction-basic
75
- name: '@deepseek-ai/dsh-compaction-basic'
76
- - id: command-compact
77
- name: '@deepseek-ai/dsh-command-compact'
78
- - id: tool-result-pruner
79
- name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
80
- config:
81
- thresholdChars: 8192
82
- headChars: 4096
83
- tailChars: 1024
84
- - id: delegation
85
- name: cordis:group
86
- group: true
87
- isolate:
88
- workflowEngine: true
89
- config:
90
- - id: tool-subagent-control
91
- name: '@deepseek-ai/dsh-tool-subagent-control'
92
- - id: tool-subagent-list-agents
93
- name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
94
- - id: tool-subagent
95
- name: '@deepseek-ai/dsh-tool-subagent'
96
- config:
97
- provider: spawn
98
- toolName: subagent
99
- modelSelectionSettings: true
100
- - id: tool-subagent-fork
101
- name: '@deepseek-ai/dsh-tool-subagent'
102
- config:
103
- provider: fork
104
- toolName: subagent_fork
105
- - id: workflow-ptc
106
- name: '@deepseek-ai/dsh-workflow-ptc'
107
- config:
108
- provider: spawn
109
- - id: tool-workflow
110
- name: '@deepseek-ai/dsh-tool-workflow'
111
- - id: tool-ask-user
112
- name: '@deepseek-ai/dsh-tool-ask-user'
113
- - id: tool-todo
114
- name: '@deepseek-ai/dsh-tool-todo'
115
- config:
116
- allowParallelInProgress: true
117
- - id: tool-web
118
- name: '@deepseek-ai/dsh-tool-web'
119
- config:
120
- fetch: true
121
- searchTimeoutMs: 60000
122
- - id: present
123
- name: '@deepseek-ai/dsh-tool-present'
124
- - id: tool-plugin-manager
125
- name: '@deepseek-ai/dsh-plugin-manager/tools'
126
- disabled: !!js "!ctx.get('profileContext')"
127
- - id: tool-plugin-market
128
- name: '@deepseek-ai/dsh-plugin-market/tools'
129
- disabled: true
130
- - id: tool-cordis
131
- name: '@deepseek-ai/dsh-tool-cordis'
132
- - id: skill-filesystem
133
- name: '@deepseek-ai/dsh-skill-filesystem'
134
- config:
135
- customSkillDirs:
136
- - !!js process.getBuiltinModule('node:path').join(process.getBuiltinModule('node:path').dirname(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('@dsh-workbench/core/package.json')), 'skills')
137
- - id: tool-skill
138
- name: '@deepseek-ai/dsh-tool-skill'