@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 +4 -3
- package/bin/dsh-workbench +9 -9
- package/client.js +4 -15
- package/cordis.patch.yml +5 -0
- package/dist/client/client.body.js +4 -15
- package/dist/client/index.js +4 -15
- package/dist/host/index.js +206 -8
- package/dist/types/app/layouts/rightbar/market-row-types.d.ts +2 -1
- package/dist/types/app/layouts/rightbar/market-rows.d.ts +2 -1
- package/dist/types/kernel/contract/bundle-install.d.ts +1 -1
- package/dist/types/shared/api/host/diy-preset.d.ts +2 -0
- package/package.json +6 -8
- package/preset/diy.patch.yml +0 -138
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ dsh-workbench migrate --force # 已经迁过一次、想再补并一次
|
|
|
50
50
|
|
|
51
51
|
| 要有 | 为什么 |
|
|
52
52
|
|---|---|
|
|
53
|
-
| `dsh` ≥ 0.2.1-rc.
|
|
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 模式」 |
|
|
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
|
|
156
|
-
# `standard
|
|
157
|
-
# dsh
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
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 "
|
|
202
|
-
echo "
|
|
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
|
-
}
|
|
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(
|
|
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(
|
|
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
|
-
}
|
|
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(
|
|
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(
|
|
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;
|
package/dist/client/index.js
CHANGED
|
@@ -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
|
-
}
|
|
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(
|
|
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(
|
|
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 };
|
package/dist/host/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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" ?
|
|
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:
|
|
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
|
-
...
|
|
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';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-workbench/core",
|
|
3
|
-
"version": "1.1.
|
|
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.
|
|
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.
|
|
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.
|
|
101
|
-
"@dsh-workbench/shared": "1.1.
|
|
98
|
+
"@dsh-workbench/adapters-default": "1.1.17",
|
|
99
|
+
"@dsh-workbench/shared": "1.1.17"
|
|
102
100
|
},
|
|
103
101
|
"license": "MIT",
|
|
104
102
|
"repository": {
|
package/preset/diy.patch.yml
DELETED
|
@@ -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'
|