dsh-custom-mode 1.11.0 → 1.11.1

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.i18n.yaml CHANGED
@@ -1,5 +1,5 @@
1
1
  # 双语配对一致性记录:两侧在「上次确认一致」时的 git blob 哈希。
2
2
  # 两份文档权威相同——改完任意一侧,请把另一侧也改掉,然后重新记录:
3
3
  # node tools/verify-translation-pairing.mjs --write
4
- README.md: 4e45a434fa7cfd4a939cda95c8d79d81395df7fe
5
- README.zh.md: 22d9b905b579dab2c35faa095e71ffb211ab46f2
4
+ README.md: 4009df09f4f352850312dbeefb0f4f8729ba1e45
5
+ README.zh.md: dc907b21aa6d277d5ad0f91b2c7acd40d3fd3e42
package/README.md CHANGED
@@ -59,7 +59,7 @@ One command installs everything — the settings-page plugin, and the preset it
59
59
  activation:
60
60
 
61
61
  ```sh
62
- dsh plugin --profile web add dsh-custom-mode@1.11.0 # pin the version to get this one for sure
62
+ dsh plugin --profile web add dsh-custom-mode@1.11.1 # pin the version to get this one for sure
63
63
  # A bare `add dsh-custom-mode` is subject to pnpm's release cooldown (`minimumReleaseAge`, 1 day by
64
64
  # default): for hours after a release it can silently install an OLDER version — measured: a bare
65
65
  # install 38 minutes after 1.3.0 shipped landed on 1.0.3. Check what you got with `npm ls
@@ -107,7 +107,8 @@ Electron shell**, so this plugin's page renders there unchanged. One install pat
107
107
 
108
108
  - **Install from inside the app**: sidebar → **Plugins** → add plugin → search `dsh-custom-mode`.
109
109
  The app runs the shared plugin manager with its own bundled pnpm.
110
- - **Do not try to use the CLI for it — dsh itself refuses** (measured on 0.1.7-rc.2):
110
+ - **Do not try to use a standalone CLI for it — dsh itself refuses** (measured on 0.1.7-rc.2, and again on
111
+ 0.2.0-rc.2):
111
112
  ```
112
113
  $ dsh plugin --profile desktop add .
113
114
  error: profile "desktop" is managed exclusively by the Electron application
@@ -116,8 +117,17 @@ Electron shell**, so this plugin's page renders there unchanged. One install pat
116
117
  and startup recovery renames `cordis.patch.yml`. `install.sh` therefore **refuses** `--profile desktop`
117
118
  too and points you at the app, so the two agree instead of one silently working around the other.
118
119
  (A lab simulation of the profile shape can override it with `DSH_ALLOW_DESKTOP_PROFILE=1`.)
120
+ **The app's own bundled CLI is the exception** — `<install>\resources\runtime\cli\bin\dsh.cmd` is allowed
121
+ to operate on that profile (measured on 1.11.1: `add dsh-custom-mode@1.11.1` → `+ dsh-custom-mode 1.11.1`).
122
+ It is a launcher, not a dsh feature: it starts Electron with `ELECTRON_RUN_AS_NODE=1` and runs the
123
+ desktop-host CLI, so it is the app talking to its own profile rather than something driving from outside.
119
124
  - **Nothing else to do on the preset side**: `$DSH_HOME/.agent-presets/` is product data shared by the
120
125
  desktop app and the CLI, and the preset is seeded by the plugin on first activation.
126
+ - **If the mode does not show up in the picker, open Settings → Custom mode and read the warning.** A preset
127
+ whose rows cannot start on that machine is marked *broken* by the platform and dropped from every picker;
128
+ the settings page names the rows and offers **Fix for this line**. On the desktop line that can take one
129
+ click and then a **restart of the app** — the picker re-reads the registry only at boot (measured on
130
+ 1.11.1, see `docs/MEASUREMENTS.md` section 34).
121
131
  - If a third-party bundle ever keeps the app from starting, the native recovery dialog offers
122
132
  **Disable third-party plugins**; installed packages and the plugin's own data stay on disk.
123
133
 
@@ -420,7 +430,7 @@ installing again — your data is not touched:
420
430
 
421
431
  ```sh
422
432
  # the pinned form: what you ask for is what you get
423
- dsh plugin --profile web add dsh-custom-mode@1.11.0
433
+ dsh plugin --profile web add dsh-custom-mode@1.11.1
424
434
  # then restart the DSH process that serves the web profile
425
435
  ```
426
436
 
package/README.zh.md CHANGED
@@ -48,7 +48,7 @@ base mode / plugin switches / multi-assistant / multi-persona。
48
48
  一条命令装完——设置页插件,以及它在首次激活时自动播种的 preset:
49
49
 
50
50
  ```sh
51
- dsh plugin --profile web add dsh-custom-mode@1.11.0 # 钉版本才能确定拿到这一版
51
+ dsh plugin --profile web add dsh-custom-mode@1.11.1 # 钉版本才能确定拿到这一版
52
52
  # 不带版本号会受 pnpm 的发布冷却期影响(`minimumReleaseAge`,默认一天):发布后数小时内按名安装
53
53
  # 可能**静默装到旧版** —— 实测 1.3.0 发布 38 分钟后按名安装装到了 1.0.3。用 profile 里的
54
54
  # `npm ls dsh-custom-mode` 核对实际装到的版本,或像上面那样钉版本。
@@ -89,7 +89,7 @@ dsh `0.1.6-alpha.2` 起有插件管理页:**侧边栏 → 插件 → 添加插
89
89
  安装只有一条路,就是上面那条:
90
90
 
91
91
  - **在应用里装**:侧栏 → **插件** → 添加插件 → 搜 `dsh-custom-mode`。应用自带 pnpm,走的是同一套插件管理器。
92
- - **不要试着用 CLI 装 —— dsh 自己就会拒绝**(0.1.7-rc.2 实测):
92
+ - **不要试着用独立的 CLI 装 —— dsh 自己就会拒绝**(0.1.7-rc.2 实测,0.2.0-rc.2 复测同样):
93
93
  ```
94
94
  $ dsh plugin --profile desktop add .
95
95
  error: profile "desktop" is managed exclusively by the Electron application
@@ -97,8 +97,15 @@ dsh `0.1.6-alpha.2` 起有插件管理页:**侧边栏 → 插件 → 添加插
97
97
  桌面端独占 `$DSH_HOME/profiles/desktop`:那里的包操作持有 profile 事务锁,启动恢复还会重命名
98
98
  `cordis.patch.yml`。所以 `install.sh` 也**拒绝** `--profile desktop` 并指向应用内安装 —— 两边一致,
99
99
  而不是某一方偷偷绕过去。(只想在本机模拟 profile 形状时可设 `DSH_ALLOW_DESKTOP_PROFILE=1`。)
100
+ **应用自带的捆绑 CLI 是例外**:`<安装目录>\resources\runtime\cli\bin\dsh.cmd` 可以操作那个 profile
101
+ (1.11.1 实测:`add dsh-custom-mode@1.11.1` → `+ dsh-custom-mode 1.11.1`)。它是启动器而不是 dsh 的
102
+ 新功能 —— 它用 `ELECTRON_RUN_AS_NODE=1` 起 Electron 去跑 desktop-host 的 CLI,所以那是**应用在跟自己的
103
+ profile 说话**,不是从外面驱动它。
100
104
  - **预设那一侧不用做任何事**:`$DSH_HOME/.agent-presets/` 是桌面端与 CLI 共享的产品数据,
101
105
  预设由插件首次激活时落盘。
106
+ - **模式没出现在选择器里,就去「设置 → 自定义模式」读那条告警。** 行的启动条件在本机不满足时,平台会把整个
107
+ 预设判为 broken 并**从所有选择器里丢掉**;设置页会点名那几行,并给出**「按本线修复」**。在桌面端那条线上,
108
+ 这通常是一次点击 + **重启应用** —— 选择器只在应用启动时重读注册表(1.11.1 实测,见 `docs/MEASUREMENTS.md` §34)。
102
109
  - 万一某个第三方 bundle 让应用起不来:原生恢复对话框提供**「禁用第三方插件」**,已安装的包与插件数据都留在磁盘上。
103
110
 
104
111
  **兼容性是声明出来的,不是猜的。** dsh 会拿每个插件的 `peerDependencies["@deepseek-ai/dsh"]` 与运行时
@@ -323,7 +330,7 @@ MIT
323
330
 
324
331
  ```sh
325
332
  # 钉版本的写法:要哪版就是哪版
326
- dsh plugin --profile web add dsh-custom-mode@1.11.0
333
+ dsh plugin --profile web add dsh-custom-mode@1.11.1
327
334
  # 然后重启为该 profile 提供服务的 DSH 进程
328
335
  ```
329
336
 
package/client.js CHANGED
@@ -142,8 +142,8 @@ try {
142
142
  "api.selfCheckFailed": "生成结果自检失败,已放弃写入:{detail}",
143
143
  "api.internalError": "宿主内部错误:{detail}",
144
144
  "api.bodyTooLarge": "请求体过大(上限 {max} 字节)",
145
- "api.repairNotNeeded": "这个助手在本机没有无法解析的行,无需修复。",
146
- "api.repaired": "已按本机这条 dsh 线关闭 {count} 个无法解析的行({ids})。现在这个模式能重新出现在选择器里。",
145
+ "api.repairNotNeeded": "这个助手在本机没有起不来的行,无需修复。",
146
+ "api.repaired": "已按本机这条 dsh 线关闭 {count} 个起不来的行({ids})。现在这个模式能重新出现在选择器里。",
147
147
  "api.badAssistantId": "助手标识不合法:{id}(只能用 a-z、0-9 与连字符)",
148
148
  "api.seedFailed": "复制模式模板失败:{detail}",
149
149
  "api.metaWriteFailed": "写入 preset.yml 失败:{detail}",
@@ -157,6 +157,7 @@ try {
157
157
  "api.baseCompositionUnavailable": "本机取不到基础模式「{mode}」的出厂组成,无法改动插件开关或基础模式(系统提示词可以单独保存)。",
158
158
  "warn.approvalGateMissing": "审批闸门未启用:本机这个 DSH 版本没有 tools/pre-execute 事件,会话内改写系统提示词不会弹审批。见「详情」。",
159
159
  "warn.unresolvableRows": "有行在本机这条 DSH 线上无法解析:平台会把整个模式判为 broken,并从新会话的选择器里**静默丢弃**。点右侧的「按本线修复」即可(只关掉那几行,其它选择不动)。",
160
+ "warn.presetBroken": "平台把这个模式判为 broken,它会**从新会话的选择器里消失** —— 而上面的「无法解析」检查解释不了为什么(多半是某一行依赖的服务/引擎没起来)。点右侧的「按本线修复」把那几行关掉即可。宿主给的原因见「详情」。",
160
161
  "warn.exclusiveRowsActive": "两条互斥的壳同时开着(它们注册同名工具):平台会把整个模式判为 broken,并从新会话的选择器里**静默丢弃**。把其中一条关掉即可 —— 在设置页保存一次也会自动避让。",
161
162
  "warn.baseCompositionUnavailable": "取不到本机这条 DSH 线的出厂组成:基础模式与插件开关暂时不能改(系统提示词不受影响,照常可保存)。已尝试的途径写在宿主日志里。",
162
163
  "warn.approvalGateMissing.label": "审批闸门未启用",
@@ -360,8 +361,8 @@ try {
360
361
  "api.selfCheckFailed": "The generated composition failed its self-check, so nothing was written: {detail}",
361
362
  "api.internalError": "Unexpected host error: {detail}",
362
363
  "api.bodyTooLarge": "Request body too large (limit {max} bytes)",
363
- "api.repairNotNeeded": "Nothing to repair — no row of this assistant is unresolvable on this machine.",
364
- "api.repaired": "Disabled {count} row(s) this dsh line cannot resolve ({ids}). The mode can appear in the pickers again.",
364
+ "api.repairNotNeeded": "Nothing to repair — every row of this assistant can start on this machine.",
365
+ "api.repaired": "Disabled {count} row(s) this dsh line cannot start ({ids}). The mode can appear in the pickers again.",
365
366
  "api.badAssistantId": "Invalid assistant id: {id} (a-z, 0-9 and hyphens only)",
366
367
  "api.seedFailed": "Copying the mode template failed: {detail}",
367
368
  "api.metaWriteFailed": "Writing preset.yml failed: {detail}",
@@ -378,6 +379,7 @@ try {
378
379
  "warn.noDescription": "No description: the new-session mode picker will show it as \"no description yet\".",
379
380
  "warn.approvalGateMissing": "The approval gate is off: this DSH build has no tools/pre-execute event, so in-session prompt rewrites do not ask for approval. See the details.",
380
381
  "warn.unresolvableRows": "Some rows cannot be resolved on this DSH line: the platform marks the whole mode broken and silently drops it from the new-session picker. Click Fix for this line — it only turns those rows off and leaves your other choices alone.",
382
+ "warn.presetBroken": "The platform marks this mode broken, so it **disappears from the new-session picker** — and the \"unresolvable\" check above cannot explain why (usually a row whose service or engine never started). Click Fix for this line to turn those rows off. The host's own reason is in Details.",
381
383
  "warn.exclusiveRowsActive": "Both shells are on, and they register the same tool names: the platform marks the whole mode broken and silently drops it from the new-session picker. Turn one of them off — saving from the settings page also resolves it automatically.",
382
384
  "warn.approvalGateMissing.label": "Approval gate is off",
383
385
  "warn.approvalGateMissing.hint": "This DSH build has no tools/pre-execute event, so in-session prompt rewrites do NOT ask for approval. The settings page is unaffected; upgrade DSH or turn the custom_prompt tool row off to restore the gate.",
@@ -2031,8 +2033,13 @@ try {
2031
2033
  "div",
2032
2034
  { key: code, className: "cpfe-warn-row" },
2033
2035
  react.createElement("p", { className: "cpfe-warn" }, "⚠ " + t("warn." + code)),
2034
- // 本线无法解析的行可以一键修(只关掉那几行;用户创建它的那个版本可能早于播种改为派生的版本)。
2035
- code === "unresolvableRows"
2036
+ // 本线起不来的行可以一键修(只关掉那几行;用户创建它的那个版本可能早于播种改为派生的版本)。
2037
+ //
2038
+ // ★ 两个 code 都要给按钮:`presetBroken` 说的是"平台判它 broken,而『无法解析』解释不了"
2039
+ // —— 那正是**修复按钮唯一还帮得上的时候**。原先只认 `unresolvableRows`,于是
2040
+ // 第一轮修复之后 `unresolvable` 变空、按钮消失,而告警文案还在叫用户"点右侧的
2041
+ // 按本线修复"。实测(2026-10-01,桌面端)就是卡在这一步:能看见病,没有药。
2042
+ code === "unresolvableRows" || code === "presetBroken"
2036
2043
  ? react.createElement(
2037
2044
  A.Button,
2038
2045
  { disabled: busy, onClick: repairRowsNow },
package/index.mjs CHANGED
@@ -290,6 +290,32 @@ export function configWarnings(text, prompt, meta) {
290
290
  return warnings
291
291
  }
292
292
 
293
+ /**
294
+ * 从宿主给的那条 `broken` 里抠出**行 id**。
295
+ *
296
+ * 平台把"这个预设为什么起不来"写成一行行 `<rowId> (<module>): <reason>`,例如
297
+ *
298
+ * workflow-worker-thread (@deepseek-ai/dsh-workflow-worker-thread): never started
299
+ * tool-workflow (@deepseek-ai/dsh-tool-workflow): waiting for workflowEngine
300
+ *
301
+ * 这是**唯一**能知道"是哪一行害的"的来源:`unresolvableRows()` 只答"模块装没装",答不了
302
+ * "上游服务等不到"。实测(2026-10-01,官方桌面端 0.2.0-rc.2):关掉那个装不上的引擎行之后
303
+ * `unresolvable` 变空、页面**全绿**,而预设**仍然 broken**(依赖引擎的两个工具在等它)——
304
+ * 于是用户再也走不到可用状态,模式一直不出现。见 docs/MEASUREMENTS.md §34。
305
+ *
306
+ * @param {unknown} message - the roster row's `broken` string.
307
+ * @returns {string[]} row ids, de-duplicated, in the order they appear.
308
+ */
309
+ export function brokenRowIds(message) {
310
+ if (typeof message !== 'string') return []
311
+ const ids = []
312
+ for (const line of message.split('\n')) {
313
+ const match = /^\s*([A-Za-z0-9][A-Za-z0-9_-]*)\s+\(/.exec(line)
314
+ if (match !== null) ids.push(match[1])
315
+ }
316
+ return [...new Set(ids)]
317
+ }
318
+
293
319
  export function readState(rows, id, options = {}) {
294
320
  const directory = assistantDir(rows, id)
295
321
  if (directory === undefined) return unknownAssistant(id)
@@ -326,6 +352,15 @@ export function readState(rows, id, options = {}) {
326
352
  if (!isBaseCompositionUnavailable(error)) throw error
327
353
  baseUnavailable = { code: error.code, params: { mode, detail: describe(error) } }
328
354
  }
355
+ // 宿主给的那条 broken(若这条线上有)。**必须在 return 之前算**:warnings 要用它。
356
+ const selfRow = Array.isArray(rows) ? rows.find((item) => item !== null && typeof item === 'object' && item.id === id) : undefined
357
+ const hostBroken = typeof selfRow?.broken === 'string' ? selfRow.broken.trim() : ''
358
+ const unresolvable = unresolvableRows(text)
359
+ const knownUnresolvable = new Set(unresolvable.map((row) => row.id))
360
+ const hostBrokenIds = brokenRowIds(hostBroken)
361
+ // 宿主说坏了,而我们**解释不了**(不是"模块装不上")—— 那就要单独点名,否则页面全绿、
362
+ // 模式却在选择器里不出现。抠不出行 id 时(宿主换了措辞)也照样点名:宁可笼统,不可沉默。
363
+ const unexplainedBroken = hostBroken !== '' && (hostBrokenIds.length === 0 || hostBrokenIds.some((rowId) => knownUnresolvable.has(rowId) === false))
329
364
  return {
330
365
  ok: true,
331
366
  id,
@@ -349,7 +384,10 @@ export function readState(rows, id, options = {}) {
349
384
  history: listHistory(directory),
350
385
  // 本插件版本 + 本机装的那条 dsh 线上无法解析的行(页面据此显示版本与"按本线修复")。
351
386
  version: PLUGIN_VERSION,
352
- unresolvable: unresolvableRows(text),
387
+ unresolvable,
388
+ // 宿主自己给的「这个预设为什么起不来」原文。它比 `unresolvable` 宽:除了"模块装不上",
389
+ // 还包括"上游服务等不到"这类**装配期**失败。页面据此点名,而不是在坏着的时候显示全绿。
390
+ broken: hostBroken === '' ? null : hostBroken,
353
391
  // 「配置了却不生效」的告警码(文案在页面侧按语言渲染)。
354
392
  warnings: [
355
393
  ...configWarnings(text, prompt.ok === true ? prompt.text : '', meta),
@@ -357,7 +395,11 @@ export function readState(rows, id, options = {}) {
357
395
  // 诚实地把它变成页面上的告警,而不是只留在 console.error 里。
358
396
  ...(existsSync(join(directory, 'approval-gate-missing')) ? ['approvalGateMissing'] : []),
359
397
  // 本线无法解析的启用行 = 平台会把整个预设判为 broken 并从选择器里丢掉(曾经的 P0)。
360
- ...(unresolvableRows(text).length > 0 ? ['unresolvableRows'] : []),
398
+ ...(unresolvable.length > 0 ? ['unresolvableRows'] : []),
399
+ // ★ 宿主报了 broken,而**我们自己的检查解释不了**(不是"模块装不上",而是"服务等不到"之类)。
400
+ // 不点名的话,页面上 `unresolvable` 空、告警空 —— 一切看起来正常,而模式**根本没出现在
401
+ // 选择器里**。这正是本仓记录过两次的那种"静默失败",只是换了个触发面。
402
+ ...(unexplainedBroken ? ['presetBroken'] : []),
361
403
  // 出厂组成取不到:提示词能改,基础模式与插件开关不能。
362
404
  ...(baseUnavailable === null ? [] : ['baseCompositionUnavailable']),
363
405
  ],
@@ -762,9 +804,30 @@ export function repairComposition(rows, input) {
762
804
  const file = compositionFile(directory)
763
805
  if (!existsSync(file)) return { ok: false, code: 'compositionMissing', params: { path: file }, error: '找不到组成文件:' + file }
764
806
  const text = readFileSync(file, 'utf8')
765
- const bad = unresolvableRows(text)
807
+ // 两类"这一行在本机起不来",必须**都**关掉:
808
+ // ① 模块装不上 —— 我们自己在 node_modules 里查得出来(`unresolvableRows`);
809
+ // ② 装配期失败("服务等不到"之类)—— 只有宿主知道,写在它给的 `broken` 里。
810
+ // 只修 ① 会留下一个**页面全绿、预设却仍然 broken**的状态(桌面端实测,见 brokenRowIds 的注释):
811
+ // `unresolvable` 变空 ⇒ 告警消失 ⇒ 用户以为修好了,而模式始终没出现在选择器里。
812
+ const selfRow = Array.isArray(rows) ? rows.find((item) => item !== null && typeof item === 'object' && item.id === id) : undefined
813
+ // 只关**这份文本里真的有**的行:宿主报的可能是别处的行,而 `disableRowsInPlace` 对不存在的 id
814
+ // 是无操作 —— 计数会因此说谎(说关了 3 个其实只关了 1 个)。
815
+ const present = new Set()
816
+ const collectIds = (list) => {
817
+ for (const row of list) {
818
+ present.add(row.id)
819
+ if (Array.isArray(row.children)) collectIds(row.children)
820
+ }
821
+ }
822
+ try {
823
+ collectIds(collectRows(text))
824
+ } catch {
825
+ /* 文本解析不了就只按 unresolvableRows 走(它自己会兜底) */
826
+ }
827
+ const wanted = [...new Set([...unresolvableRows(text).map((row) => row.id), ...brokenRowIds(selfRow?.broken)])]
828
+ const bad = wanted.map((rowId) => ({ id: rowId })).filter((row) => present.has(row.id))
766
829
  if (bad.length === 0) {
767
- return { ok: true, id, code: 'repairNotNeeded', note: '这个助手在本机没有无法解析的行,无需修复。' }
830
+ return { ok: true, id, code: 'repairNotNeeded', note: '这个助手在本机没有起不来的行,无需修复。' }
768
831
  }
769
832
  // **就地**关闭那几行,不重渲染:重渲染会顺手丢掉 base 之外的自有行,而用户的数据不该被这样动。
770
833
  const rendered = disableRowsInPlace(text, bad.map((row) => row.id))
@@ -782,7 +845,7 @@ export function repairComposition(rows, input) {
782
845
  // 草稿,否则下一次保存会按草稿重渲染,把刚才的修复原样撤销(issue #8 实测:
783
846
  // 修复写进了磁盘,但草稿里那几行仍是启用的,于是保存后 ghost 行又回来了)。
784
847
  params: { count: bad.length, ids, repairedIds: bad.map((row) => row.id) },
785
- note: '已按本机这条 dsh 线关闭 ' + String(bad.length) + ' 个无法解析的行(' + ids + ')。现在这个模式能重新出现在选择器里。',
848
+ note: '已按本机这条 dsh 线关闭 ' + String(bad.length) + ' 个起不来的行(' + ids + ')。现在这个模式能重新出现在选择器里。',
786
849
  }
787
850
  }
788
851
 
package/locales.mjs CHANGED
@@ -102,8 +102,8 @@ export const zh = {
102
102
  'api.selfCheckFailed': '生成结果自检失败,已放弃写入:{detail}',
103
103
  'api.internalError': '宿主内部错误:{detail}',
104
104
  'api.bodyTooLarge': '请求体过大(上限 {max} 字节)',
105
- 'api.repairNotNeeded': '这个助手在本机没有无法解析的行,无需修复。',
106
- 'api.repaired': '已按本机这条 dsh 线关闭 {count} 个无法解析的行({ids})。现在这个模式能重新出现在选择器里。',
105
+ 'api.repairNotNeeded': '这个助手在本机没有起不来的行,无需修复。',
106
+ 'api.repaired': '已按本机这条 dsh 线关闭 {count} 个起不来的行({ids})。现在这个模式能重新出现在选择器里。',
107
107
  'api.badAssistantId': '助手标识不合法:{id}(只能用 a-z、0-9 与连字符)',
108
108
  'api.seedFailed': '复制模式模板失败:{detail}',
109
109
  'api.metaWriteFailed': '写入 preset.yml 失败:{detail}',
@@ -117,6 +117,7 @@ export const zh = {
117
117
  'api.baseCompositionUnavailable': '本机取不到基础模式「{mode}」的出厂组成,无法改动插件开关或基础模式(系统提示词可以单独保存)。',
118
118
  'warn.approvalGateMissing': '审批闸门未启用:本机这个 DSH 版本没有 tools/pre-execute 事件,会话内改写系统提示词不会弹审批。见「详情」。',
119
119
  'warn.unresolvableRows': '有行在本机这条 DSH 线上无法解析:平台会把整个模式判为 broken,并从新会话的选择器里**静默丢弃**。点右侧的「按本线修复」即可(只关掉那几行,其它选择不动)。',
120
+ 'warn.presetBroken': '平台把这个模式判为 broken,它会**从新会话的选择器里消失** —— 而上面的「无法解析」检查解释不了为什么(多半是某一行依赖的服务/引擎没起来)。点右侧的「按本线修复」把那几行关掉即可。宿主给的原因见「详情」。',
120
121
  'warn.exclusiveRowsActive': '两条互斥的壳同时开着(它们注册同名工具):平台会把整个模式判为 broken,并从新会话的选择器里**静默丢弃**。把其中一条关掉即可 —— 在设置页保存一次也会自动避让。',
121
122
  'warn.baseCompositionUnavailable': '取不到本机这条 DSH 线的出厂组成:基础模式与插件开关暂时不能改(系统提示词不受影响,照常可保存)。已尝试的途径写在宿主日志里。',
122
123
  'warn.approvalGateMissing.label': '审批闸门未启用',
@@ -338,8 +339,8 @@ export const en = {
338
339
  'api.selfCheckFailed': 'The generated composition failed its self-check, so nothing was written: {detail}',
339
340
  'api.internalError': 'Unexpected host error: {detail}',
340
341
  'api.bodyTooLarge': 'Request body too large (limit {max} bytes)',
341
- 'api.repairNotNeeded': 'Nothing to repair — no row of this assistant is unresolvable on this machine.',
342
- 'api.repaired': 'Disabled {count} row(s) this dsh line cannot resolve ({ids}). The mode can appear in the pickers again.',
342
+ 'api.repairNotNeeded': 'Nothing to repair — every row of this assistant can start on this machine.',
343
+ 'api.repaired': 'Disabled {count} row(s) this dsh line cannot start ({ids}). The mode can appear in the pickers again.',
343
344
  'api.badAssistantId': 'Invalid assistant id: {id} (a-z, 0-9 and hyphens only)',
344
345
  'api.seedFailed': 'Copying the mode template failed: {detail}',
345
346
  'api.metaWriteFailed': 'Writing preset.yml failed: {detail}',
@@ -356,6 +357,7 @@ export const en = {
356
357
  'warn.noDescription': 'No description: the new-session mode picker will show it as "no description yet".',
357
358
  'warn.approvalGateMissing': 'The approval gate is off: this DSH build has no tools/pre-execute event, so in-session prompt rewrites do not ask for approval. See the details.',
358
359
  'warn.unresolvableRows': 'Some rows cannot be resolved on this DSH line: the platform marks the whole mode broken and silently drops it from the new-session picker. Click Fix for this line — it only turns those rows off and leaves your other choices alone.',
360
+ 'warn.presetBroken': 'The platform marks this mode broken, so it **disappears from the new-session picker** — and the "unresolvable" check above cannot explain why (usually a row whose service or engine never started). Click Fix for this line to turn those rows off. The host\'s own reason is in Details.',
359
361
  'warn.exclusiveRowsActive': 'Both shells are on, and they register the same tool names: the platform marks the whole mode broken and silently drops it from the new-session picker. Turn one of them off — saving from the settings page also resolves it automatically.',
360
362
  'warn.approvalGateMissing.label': 'Approval gate is off',
361
363
  'warn.approvalGateMissing.hint': 'This DSH build has no tools/pre-execute event, so in-session prompt rewrites do NOT ask for approval. The settings page is unaffected; upgrade DSH or turn the custom_prompt tool row off to restore the gate.',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-custom-mode",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "Custom modes and custom prompts for DeepSeek Harness (dsh): edit a mode's system prompt on the settings page (it takes effect on the next model step), pick its base mode, switch plugin rows one by one, and keep several assistants side by side — coding, chat or roleplay (RP) personas (multi-mode / multi-agent).",
5
5
  "license": "MIT",
6
6
  "type": "module",