@xiaoso/dsh-tool-plus 0.1.9 → 0.1.10-beta.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.en.md +12 -5
- package/README.md +11 -4
- package/THIRD_PARTY_NOTICES.md +36 -0
- package/lib/client.js +272 -181
- package/lib/index.mjs +875 -1081
- package/lib/{scrapers-mhvFrvjH.mjs → scrapers-DODCPcZW.mjs} +1 -1
- package/lib/types/client/BashPlusCard.d.ts +6 -6
- package/lib/types/client/ToolPlusSection.d.ts +3 -3
- package/lib/types/client/forms.d.ts +6 -6
- package/lib/types/client/index.d.ts +25 -12
- package/lib/types/client/locales.d.ts +1 -1
- package/lib/types/client/preset-panel.d.ts +54 -42
- package/lib/types/config/settings.d.ts +202 -21
- package/lib/types/host/browser-probe-rpc.d.ts +2 -1
- package/lib/types/host/preset-host.d.ts +103 -0
- package/lib/types/host/preset-rpc.d.ts +37 -72
- package/lib/types/presets/compare.d.ts +14 -37
- package/lib/types/presets/conflicts.d.ts +59 -0
- package/lib/types/presets/delta.d.ts +23 -18
- package/lib/types/presets/plan.d.ts +55 -0
- package/lib/types/presets/rows.d.ts +84 -0
- package/lib/types/presets/status.d.ts +56 -47
- package/lib/types/tools/bash/background.d.ts +20 -5
- package/lib/types/tools/bash/streaming-output.d.ts +4 -2
- package/lib/types/tools/shared/browser-rpc-channel.d.ts +84 -42
- package/lib/types/web/client/labels.d.ts +1 -1
- package/lib/types/web/client/row-utils.d.ts +26 -1
- package/lib/{utils-eiUz9n8I.mjs → utils-D80w8vry.mjs} +1 -1
- package/package.json +61 -46
- package/presets/tool-plus-ptc.patch.yml +164 -0
- package/presets/tool-plus-standard.patch.yml +158 -0
- package/lib/types/presets/install.d.ts +0 -44
- package/lib/types/presets/paths.d.ts +0 -41
- package/lib/types/presets/rewrite.d.ts +0 -86
- package/presets/install-presets.mjs +0 -143
- package/presets/package.json +0 -42
- package/presets/tool-plus-ptc/agent.cordis.yml +0 -284
- package/presets/tool-plus-ptc/preset.yml +0 -3
- package/presets/tool-plus-standard/agent.cordis.yml +0 -269
- package/presets/tool-plus-standard/preset.yml +0 -3
package/lib/client.js
CHANGED
|
@@ -992,7 +992,7 @@ window.__ModuleLoader__.load({
|
|
|
992
992
|
"aria-expanded": open,
|
|
993
993
|
disabled,
|
|
994
994
|
onClick: () => onOpenChange(open ? null : control.field),
|
|
995
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: current ? t(current.labelKey) : control.value }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
995
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: current ? t(current.labelKey) : control.value }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: "tp-selectChevron" })]
|
|
996
996
|
})
|
|
997
997
|
})
|
|
998
998
|
]
|
|
@@ -1092,7 +1092,7 @@ window.__ModuleLoader__.load({
|
|
|
1092
1092
|
* (`locale: 'tool-plus'`), which re-renders on a locale switch.
|
|
1093
1093
|
*
|
|
1094
1094
|
* The card edits the FLAT settings surface (OMP `bash*`-style scalar keys) —
|
|
1095
|
-
* the client
|
|
1095
|
+
* the client form only writes scalar fields — grouped as timeouts,
|
|
1096
1096
|
* backgrounding, output, completion truncation (subdivided into byte and line
|
|
1097
1097
|
* settings), and behavior. Field definitions, defaults, and copy keys come
|
|
1098
1098
|
* from the single-source field table (`src/config/fields.ts`), shared with
|
|
@@ -1209,7 +1209,7 @@ window.__ModuleLoader__.load({
|
|
|
1209
1209
|
if (hasStaged) return (staged ?? "").trim() === "" ? String(revertValue$1(snap, field) ?? "") : staged ?? "";
|
|
1210
1210
|
return resolved === void 0 || typeof resolved === "boolean" ? "" : String(resolved);
|
|
1211
1211
|
}
|
|
1212
|
-
/** Stage card edits over the
|
|
1212
|
+
/** Stage card edits over the shared configuration form; only a Save writes the document. */
|
|
1213
1213
|
function useBashPlusForm(scope) {
|
|
1214
1214
|
const [snap, setSnap] = (0, react.useState)(() => scope.getSnapshot());
|
|
1215
1215
|
const [numbers, setNumbers] = (0, react.useState)({});
|
|
@@ -1464,8 +1464,8 @@ window.__ModuleLoader__.load({
|
|
|
1464
1464
|
};
|
|
1465
1465
|
}
|
|
1466
1466
|
function BashPlusCard(props) {
|
|
1467
|
-
const { t,
|
|
1468
|
-
const form = useBashPlusForm(
|
|
1467
|
+
const { t, form: configForm } = props;
|
|
1468
|
+
const form = useBashPlusForm(configForm);
|
|
1469
1469
|
const [open, setOpen] = (0, react.useState)(false);
|
|
1470
1470
|
const [openSelect, setOpenSelect] = (0, react.useState)(null);
|
|
1471
1471
|
(0, react.useEffect)(() => {
|
|
@@ -1474,7 +1474,7 @@ window.__ModuleLoader__.load({
|
|
|
1474
1474
|
}, []);
|
|
1475
1475
|
if (!form.shell.available) return null;
|
|
1476
1476
|
const blocked = !form.shell.dirty || form.shell.invalid || form.shell.saving;
|
|
1477
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
1477
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1478
1478
|
"data-plugin-settings": "tool-plus",
|
|
1479
1479
|
className: "tp-card" + (open ? " tp-open" : ""),
|
|
1480
1480
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
@@ -1703,15 +1703,19 @@ window.__ModuleLoader__.load({
|
|
|
1703
1703
|
/** Endpoint that lists agent presets with their status (roster + conflicts + template diff). */
|
|
1704
1704
|
const PRESET_STATUS_ENDPOINT = "presets/status";
|
|
1705
1705
|
/**
|
|
1706
|
-
* The preset ids this plugin
|
|
1707
|
-
*
|
|
1708
|
-
*
|
|
1709
|
-
*
|
|
1706
|
+
* The preset ids this plugin **declares**. Single source of truth for both
|
|
1707
|
+
* halves: the host picks its own declarations out of the profile's composed
|
|
1708
|
+
* configuration, and the panel uses the list to tell "ours" from everything else.
|
|
1709
|
+
*
|
|
1710
|
+
* They ship as `@deepseek-ai/dsh-agent-preset` declaration rows in this
|
|
1711
|
+
* package's own bundle patches (`presets/<id>.patch.yml`), so installing the
|
|
1712
|
+
* plugin as a profile bundle declares them: no install step, no file copy, and
|
|
1713
|
+
* nothing written at startup.
|
|
1710
1714
|
*/
|
|
1711
1715
|
const BUNDLED_PRESET_IDS = ["tool-plus-standard", "tool-plus-ptc"];
|
|
1712
|
-
/** Endpoint that applies one preset action to
|
|
1716
|
+
/** Endpoint that applies one preset action to the active profile. */
|
|
1713
1717
|
const PRESET_ACTION_ENDPOINT = "presets/apply";
|
|
1714
|
-
/** Endpoint that compares one preset against one of our
|
|
1718
|
+
/** Endpoint that compares one preset against one of our declarations (read-only). */
|
|
1715
1719
|
const PRESET_COMPARE_ENDPOINT = "presets/compare";
|
|
1716
1720
|
//#endregion
|
|
1717
1721
|
//#region src/client/web-connection-rpc.ts
|
|
@@ -1940,8 +1944,8 @@ window.__ModuleLoader__.load({
|
|
|
1940
1944
|
return false;
|
|
1941
1945
|
}
|
|
1942
1946
|
/**
|
|
1943
|
-
* Stage edits over the
|
|
1944
|
-
* @param scope -
|
|
1947
|
+
* Stage edits over the shared configuration form; only a Save writes the document.
|
|
1948
|
+
* @param scope - the `tool-plus` entry's shared configuration form (`ctx.configForms`).
|
|
1945
1949
|
* @param fields - the fields this surface edits (single-source table slice).
|
|
1946
1950
|
* @returns the form state and its write actions.
|
|
1947
1951
|
*/
|
|
@@ -2123,11 +2127,18 @@ window.__ModuleLoader__.load({
|
|
|
2123
2127
|
//#endregion
|
|
2124
2128
|
//#region src/client/preset-panel.ts
|
|
2125
2129
|
/**
|
|
2126
|
-
* 预设面板的纯映射层:把 `presets/status` / `presets/apply`
|
|
2127
|
-
*
|
|
2128
|
-
* `tests/unit/preset-panel.spec.ts` 单独覆盖,UI(`PresetPanel.tsx`)只做渲染。
|
|
2130
|
+
* 预设面板的纯映射层:把 `presets/status` / `presets/apply` / `presets/compare`
|
|
2131
|
+
* 的返回值翻成本地化文案、可用动作与差异摘要。零 React、零 DOM、零 I/O ——
|
|
2132
|
+
* 由 `tests/unit/preset-panel.spec.ts` 单独覆盖,UI(`PresetPanel.tsx`)只做渲染。
|
|
2133
|
+
*
|
|
2134
|
+
* 语义基线(dsh 0.1.7 起,别再按旧目录机制理解):
|
|
2135
|
+
* - 预设是 profile 配置里的一条 `@deepseek-ai/dsh-agent-preset` 声明行;
|
|
2136
|
+
* - "没被改动过" = 这一行在 profile 补丁里**没有** `config`(`customized === false`);
|
|
2137
|
+
* - 三个动作:`upgrade` 只禁冲突行、`align` 用所选模板整份替换 plugins、
|
|
2138
|
+
* `revert` 删掉覆盖回落到随包声明;
|
|
2139
|
+
* - 本插件只**声明**两个预设({@link BUNDLED_PRESET_IDS});别的 preset 归别人,
|
|
2140
|
+
* 面板最多替它修冲突行,不改它的内容。
|
|
2129
2141
|
*
|
|
2130
|
-
* 契约来源:`docs/superpowers/specs/2026-09-17-preset-upgrade-design.md` §4.2/§7。
|
|
2131
2142
|
* 类型与端点名直接取自共享契约模块 `src/tools/shared/browser-rpc-channel.ts`
|
|
2132
2143
|
* (两半同一个来源,客户端这一侧不复制一份会漂移的定义)。
|
|
2133
2144
|
* @module @xiaoso/dsh-tool-plus/client/preset-panel
|
|
@@ -2143,33 +2154,6 @@ window.__ModuleLoader__.load({
|
|
|
2143
2154
|
"tool-fs-search": "presetEntrySearch"
|
|
2144
2155
|
};
|
|
2145
2156
|
/**
|
|
2146
|
-
* 组合文件读不到但形状没问题:`conflicts` 为空、`clean` 为假,且既没被 roster
|
|
2147
|
-
* 标 `broken` 也不是形状无法识别 —— 唯一解释是文件不存在/读不了(例如目录在、
|
|
2148
|
-
* `agent.cordis.yml` 缺)。这不是"与模板一致",要对用户说「未安装」。
|
|
2149
|
-
*/
|
|
2150
|
-
function compositionUnreadable(status) {
|
|
2151
|
-
return status.broken === void 0 && !status.unrecognized && !status.clean && status.conflicts.length === 0;
|
|
2152
|
-
}
|
|
2153
|
-
/**
|
|
2154
|
-
* roster 缺席我们随包的两份时补出「未安装」行(不改变 roster 原有顺序,
|
|
2155
|
-
* 补出的行按 {@link BUNDLED_PRESET_IDS} 顺序排在前面)。
|
|
2156
|
-
*/
|
|
2157
|
-
function mergeBundledPresets(presets) {
|
|
2158
|
-
const present = new Set(presets.map((preset) => preset.id));
|
|
2159
|
-
const missing = BUNDLED_PRESET_IDS.filter((id) => !present.has(id)).map((id) => ({
|
|
2160
|
-
id,
|
|
2161
|
-
source: "ours",
|
|
2162
|
-
path: "",
|
|
2163
|
-
conflicts: [],
|
|
2164
|
-
clean: false,
|
|
2165
|
-
unrecognized: false,
|
|
2166
|
-
installed: false,
|
|
2167
|
-
templatePresent: true,
|
|
2168
|
-
templateDiffers: false
|
|
2169
|
-
}));
|
|
2170
|
-
return missing.length === 0 ? [...presets] : [...missing, ...presets];
|
|
2171
|
-
}
|
|
2172
|
-
/**
|
|
2173
2157
|
* 下拉里一次只看一个预设时的默认选中项:随包的那份({@link BUNDLED_PRESET_IDS}
|
|
2174
2158
|
* 的第一项)在场就选它,否则退清单第一项;空清单返回 undefined。
|
|
2175
2159
|
*/
|
|
@@ -2177,14 +2161,14 @@ window.__ModuleLoader__.load({
|
|
|
2177
2161
|
return BUNDLED_PRESET_IDS.find((id) => presets.some((preset) => preset.id === id)) ?? presets[0]?.id;
|
|
2178
2162
|
}
|
|
2179
2163
|
/**
|
|
2180
|
-
*
|
|
2181
|
-
*
|
|
2164
|
+
* 当前选中项在重拉状态后可能已经消失(声明被移除、roster 变化):仍在场就保留,
|
|
2165
|
+
* 否则回落到 {@link initialPresetId},避免下拉指向一个不存在的选项。
|
|
2182
2166
|
*/
|
|
2183
2167
|
function resolveSelectedPresetId(presets, current) {
|
|
2184
2168
|
if (current !== void 0 && presets.some((preset) => preset.id === current)) return current;
|
|
2185
2169
|
return initialPresetId(presets);
|
|
2186
2170
|
}
|
|
2187
|
-
/** 下拉选项文案:优先展示 name
|
|
2171
|
+
/** 下拉选项文案:优先展示 name(声明里的显示名),缺了就退 id。 */
|
|
2188
2172
|
function presetOptionLabel(preset) {
|
|
2189
2173
|
return preset.name !== void 0 && preset.name !== "" ? preset.name : preset.id;
|
|
2190
2174
|
}
|
|
@@ -2215,7 +2199,7 @@ window.__ModuleLoader__.load({
|
|
|
2215
2199
|
}
|
|
2216
2200
|
/**
|
|
2217
2201
|
* 状态点 ②(完整比较):这份预设的内容与我们选中的模板差多少 ——
|
|
2218
|
-
*
|
|
2202
|
+
* 不只是工具开关,整份插件行列表都算。
|
|
2219
2203
|
* @param t - 文案表。
|
|
2220
2204
|
* @param compare - 当前比较结果;尚未返回时给"正在比较"的黄点。
|
|
2221
2205
|
* @returns 状态点。
|
|
@@ -2239,7 +2223,7 @@ window.__ModuleLoader__.load({
|
|
|
2239
2223
|
};
|
|
2240
2224
|
}
|
|
2241
2225
|
/**
|
|
2242
|
-
* 差异弹窗的行:把比较结果翻成"路径 /
|
|
2226
|
+
* 差异弹窗的行:把比较结果翻成"路径 / 两份各自的值"三列。
|
|
2243
2227
|
* 值缺失或整行差异都给出占位词,让用户一眼看出哪边没有。
|
|
2244
2228
|
* @param t - 文案表。
|
|
2245
2229
|
* @param compare - 当前比较结果。
|
|
@@ -2285,10 +2269,10 @@ window.__ModuleLoader__.load({
|
|
|
2285
2269
|
return template.name !== void 0 && template.name !== "" ? template.name : template.id;
|
|
2286
2270
|
}
|
|
2287
2271
|
/**
|
|
2288
|
-
*
|
|
2289
|
-
* `tool-plus-ptc
|
|
2290
|
-
* `tool-plus-standard`,别按目录名排序撞上 ptc
|
|
2291
|
-
*
|
|
2272
|
+
* 选中的模板:①手动选过且仍在场就用它;②否则选与当前预设**同名**的那份
|
|
2273
|
+
* (`tool-plus-ptc` 就该比 `tool-plus-ptc`);③再退随包的第一份
|
|
2274
|
+
* (`BUNDLED_PRESET_IDS[0]`,即 `tool-plus-standard`,别按目录名排序撞上 ptc);
|
|
2275
|
+
* ④最后退清单第一项。清单为空返回 undefined。
|
|
2292
2276
|
* @param templates - 可选模板清单。
|
|
2293
2277
|
* @param current - 当前选中的模板 id。
|
|
2294
2278
|
* @param presetId - 当前选中的预设 id(同名模板优先)。
|
|
@@ -2300,35 +2284,54 @@ window.__ModuleLoader__.load({
|
|
|
2300
2284
|
return BUNDLED_PRESET_IDS.find((id) => templates.some((template) => template.id === id)) ?? templates[0]?.id;
|
|
2301
2285
|
}
|
|
2302
2286
|
/**
|
|
2303
|
-
*
|
|
2304
|
-
*
|
|
2287
|
+
* 补充说明行:为什么读不到、这个 preset 归谁、以及"你改过它"这件事。
|
|
2288
|
+
* 差异不在这里铺开 —— 它进了「查看差异」弹窗,正文只留状态点与必要解释。
|
|
2305
2289
|
* @param t - 文案表。
|
|
2306
2290
|
* @param status - 该预设的状态。
|
|
2291
|
+
* @param writable - 本部署有没有可编辑的 profile。
|
|
2307
2292
|
* @returns 要渲染的说明行(可能为空)。
|
|
2308
2293
|
*/
|
|
2309
|
-
function presetNotes(t, status) {
|
|
2294
|
+
function presetNotes(t, status, writable = true) {
|
|
2310
2295
|
const notes = [];
|
|
2296
|
+
if (!writable) notes.push(t("presetNoteNoProfile"));
|
|
2311
2297
|
if (status.broken !== void 0) notes.push(t("presetNoteBroken").replace("{reason}", status.broken));
|
|
2312
2298
|
else if (status.unrecognized) notes.push(t("presetNoteUnrecognized"));
|
|
2299
|
+
if (status.source === "ours" && writable && status.entryId === void 0) notes.push(t("presetNoteNoRow"));
|
|
2300
|
+
if (status.source === "other") notes.push(t("presetNoteOther"));
|
|
2301
|
+
else if (status.customized) notes.push(t("presetNoteCustomized"));
|
|
2313
2302
|
return notes;
|
|
2314
2303
|
}
|
|
2315
2304
|
/**
|
|
2316
2305
|
* 该预设可执行的动作,按渲染顺序。
|
|
2317
2306
|
*
|
|
2318
|
-
* -
|
|
2319
|
-
* -
|
|
2320
|
-
*
|
|
2321
|
-
* -
|
|
2307
|
+
* - 本部署没有可编辑 profile(`writable === false`)→ 一个动作都不给;
|
|
2308
|
+
* - 这一行不可寻址(`entryId` 缺席)→ 一个动作都不给(写了也没地方落);
|
|
2309
|
+
* - **别人的** preset → 只给 `upgrade`(我们只该修冲突行,不该替别人重写内容);
|
|
2310
|
+
* - **我们的** preset → `upgrade` + `align`;有覆盖时再加 `revert`;
|
|
2311
|
+
* - 内容不可识别时 `upgrade` 没有意义(它要逐行判定),只给 `align` / `revert`。
|
|
2322
2312
|
* @param status - 该预设的状态。
|
|
2313
|
+
* @param writable - 本部署有没有可编辑的 profile。
|
|
2323
2314
|
* @returns 动作清单。
|
|
2324
2315
|
*/
|
|
2325
|
-
function presetActions(status) {
|
|
2326
|
-
if (status.
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2316
|
+
function presetActions(status, writable = true) {
|
|
2317
|
+
if (!writable || status.entryId === void 0) return [];
|
|
2318
|
+
if (status.source === "other") return status.unrecognized ? [] : ["upgrade"];
|
|
2319
|
+
if (status.unrecognized) return status.customized ? ["align", "revert"] : ["align"];
|
|
2320
|
+
return status.customized ? [
|
|
2321
|
+
"upgrade",
|
|
2322
|
+
"align",
|
|
2323
|
+
"revert"
|
|
2324
|
+
] : ["upgrade", "align"];
|
|
2325
|
+
}
|
|
2326
|
+
/** 动作按钮文案。 */
|
|
2330
2327
|
function presetActionText(t, action) {
|
|
2331
|
-
|
|
2328
|
+
if (action === "align") return t("presetActionAlign");
|
|
2329
|
+
if (action === "revert") return t("presetActionRevert");
|
|
2330
|
+
return t("presetActionUpdate");
|
|
2331
|
+
}
|
|
2332
|
+
/** 需要二次确认的动作:两个会动到用户已有内容的动作。 */
|
|
2333
|
+
function presetActionNeedsConfirm(action) {
|
|
2334
|
+
return action === "align" || action === "revert";
|
|
2332
2335
|
}
|
|
2333
2336
|
/**
|
|
2334
2337
|
* 动作按钮的悬浮说明:讲清这个按钮**具体会做什么**,以及当前状态下有没有意义。
|
|
@@ -2336,7 +2339,7 @@ window.__ModuleLoader__.load({
|
|
|
2336
2339
|
* @param t - 文案表。
|
|
2337
2340
|
* @param action - 该按钮的动作。
|
|
2338
2341
|
* @param status - 该预设状态(决定"要不要更新")。
|
|
2339
|
-
* @param templateLabel -
|
|
2342
|
+
* @param templateLabel - 当前所选模板的显示名(对齐提示里点名它是哪份)。
|
|
2340
2343
|
* @returns 悬浮提示文案。
|
|
2341
2344
|
*/
|
|
2342
2345
|
function presetActionHint(t, action, status, templateLabel) {
|
|
@@ -2345,7 +2348,8 @@ window.__ModuleLoader__.load({
|
|
|
2345
2348
|
for (const [name, value] of Object.entries(values)) text = text.replaceAll(`{${name}}`, value);
|
|
2346
2349
|
return text;
|
|
2347
2350
|
};
|
|
2348
|
-
if (action === "
|
|
2351
|
+
if (action === "align") return fill("presetActionAlignHint", { template: templateLabel });
|
|
2352
|
+
if (action === "revert") return t("presetActionRevertHint");
|
|
2349
2353
|
if (status.conflicts.length === 0) return t("presetActionUpdateNothing");
|
|
2350
2354
|
return fill("presetActionUpdateHint", {
|
|
2351
2355
|
count: String(status.conflicts.length),
|
|
@@ -2360,54 +2364,59 @@ window.__ModuleLoader__.load({
|
|
|
2360
2364
|
});
|
|
2361
2365
|
}
|
|
2362
2366
|
/**
|
|
2363
|
-
*
|
|
2364
|
-
*
|
|
2365
|
-
* 用的是**哪份模板**:重置的来源是用户在「对比模板」里选的那份。
|
|
2367
|
+
* 二次确认文案。两个动作都会动到用户可能已经改过的内容,所以必须说清后果,
|
|
2368
|
+
* 并且**点名写入位置**——这是本插件唯一会改用户 profile 配置的地方。
|
|
2366
2369
|
* @param t - 文案表。
|
|
2367
2370
|
* @param status - 该预设状态。
|
|
2371
|
+
* @param action - 待确认的动作。
|
|
2368
2372
|
* @param templateLabel - 所选模板的显示名。
|
|
2369
2373
|
* @returns 确认文案。
|
|
2370
2374
|
*/
|
|
2371
|
-
function presetConfirmText(t, status, templateLabel) {
|
|
2372
|
-
if (
|
|
2373
|
-
|
|
2375
|
+
function presetConfirmText(t, status, action, templateLabel) {
|
|
2376
|
+
if (action === "revert") return t("presetConfirmRevert");
|
|
2377
|
+
const lines = [t("presetConfirmAlign").replace("{template}", templateLabel)];
|
|
2378
|
+
if (status.customized) lines.push(t("presetConfirmAlignEdits"));
|
|
2379
|
+
return lines.join("\n");
|
|
2374
2380
|
}
|
|
2375
2381
|
/**
|
|
2376
|
-
*
|
|
2377
|
-
*
|
|
2382
|
+
* 执行前摘要:**当前状态**下有什么需要处理的。没事可做时返回 null
|
|
2383
|
+
* (不渲染这一行)——用户明确要求去掉"工具行都已禁用,无需调整。"这种没有
|
|
2384
|
+
* 信息量的状态句。
|
|
2378
2385
|
* @param t - 文案表。
|
|
2379
2386
|
* @param status - 该预设状态。
|
|
2380
2387
|
* @returns 摘要文案,或 null(无需渲染)。
|
|
2381
2388
|
*/
|
|
2382
2389
|
function presetPendingText(t, status) {
|
|
2383
|
-
if (
|
|
2384
|
-
if (status.
|
|
2385
|
-
if (!status.installed || compositionUnreadable(status)) return t("presetPendingInstall");
|
|
2390
|
+
if (status.source === "ours" && status.entryId === void 0) return null;
|
|
2391
|
+
if (status.unrecognized) return t("presetPendingBroken");
|
|
2386
2392
|
if (status.conflicts.length === 0) return null;
|
|
2387
2393
|
const names = presetConflictNames(t, status.conflicts);
|
|
2388
2394
|
return t("presetPendingRows").replace("{count}", String(status.conflicts.length)).replace("{rows}", names.join(t("presetListSeparator")));
|
|
2389
2395
|
}
|
|
2390
2396
|
/**
|
|
2391
|
-
*
|
|
2397
|
+
* 执行后结果:成功(改了几处、改了哪几处)/ 无变化 / 失败原因。
|
|
2392
2398
|
* 多行文本,`\n` 分段;调用方的结果行按 `white-space: pre-wrap` 渲染。
|
|
2393
2399
|
*
|
|
2394
|
-
* `action` 必须传:宿主只在 `upgrade` 时返回逐行改动(`
|
|
2395
|
-
* `changes`
|
|
2396
|
-
* "调整了 0 处"这种假话。
|
|
2400
|
+
* `action` 必须传:宿主只在 `upgrade` 时返回逐行改动(`align` 是整份替换、
|
|
2401
|
+
* `revert` 是删覆盖,两者的 `changes` 恒为空),所以它们不能套用"调整了 N 行"
|
|
2402
|
+
* 的句式 —— 否则会渲染成"调整了 0 处"这种假话。
|
|
2403
|
+
* @param t - 文案表。
|
|
2404
|
+
* @param result - 宿主返回的执行结果。
|
|
2405
|
+
* @param action - 刚执行的动作。
|
|
2406
|
+
* @returns 结果文案。
|
|
2397
2407
|
*/
|
|
2398
2408
|
function presetResultText(t, result, action) {
|
|
2399
2409
|
if (!result.ok) return t("presetResultFailed").replace("{reason}", result.reason ?? t("presetFailUnknown"));
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
lines.push(t("presetResultRows").replace("{rows}", names.join(t("presetListSeparator"))));
|
|
2410
|
+
const lines = [];
|
|
2411
|
+
if (action === "align") lines.push(result.changed ? t("presetResultAlignDone") : t("presetResultAlignNoChange"));
|
|
2412
|
+
else if (action === "revert") lines.push(result.changed ? t("presetResultRevertDone") : t("presetResultRevertNoChange"));
|
|
2413
|
+
else if (!result.changed) lines.push(t("presetResultNoChange"));
|
|
2414
|
+
else {
|
|
2415
|
+
lines.push(t("presetResultDone").replace("{count}", String(result.changes.length)));
|
|
2416
|
+
if (result.changes.length > 0) {
|
|
2417
|
+
const names = presetConflictNames(t, result.changes.map((change) => change.id));
|
|
2418
|
+
lines.push(t("presetResultRows").replace("{rows}", names.join(t("presetListSeparator"))));
|
|
2419
|
+
}
|
|
2411
2420
|
}
|
|
2412
2421
|
if (result.backupPath !== void 0) lines.push(t("presetResultBackup"));
|
|
2413
2422
|
return lines.join("\n");
|
|
@@ -2496,6 +2505,16 @@ window.__ModuleLoader__.load({
|
|
|
2496
2505
|
const [phase, setPhase] = (0, react.useState)("loading");
|
|
2497
2506
|
const [presets, setPresets] = (0, react.useState)([]);
|
|
2498
2507
|
const [templates, setTemplates] = (0, react.useState)([]);
|
|
2508
|
+
/**
|
|
2509
|
+
* 本部署有没有可编辑的 profile(宿主 `configEditor` 是否在场)。没有时面板
|
|
2510
|
+
* 只读 —— 一个动作都不给,说明行会讲清原因。
|
|
2511
|
+
*/
|
|
2512
|
+
const [writable, setWritable] = (0, react.useState)(true);
|
|
2513
|
+
/**
|
|
2514
|
+
* 旧版目录机制留下的 `~/.dsh/.agent-presets`(0.1.7 起没有任何代码读它)。
|
|
2515
|
+
* 只作为"可以安全删除"的提示展示,不参与任何读写。
|
|
2516
|
+
*/
|
|
2517
|
+
const [legacyRoot, setLegacyRoot] = (0, react.useState)(void 0);
|
|
2499
2518
|
const [presetId, setPresetId] = (0, react.useState)(void 0);
|
|
2500
2519
|
const [templateId, setTemplateId] = (0, react.useState)(void 0);
|
|
2501
2520
|
/** 用户手动挑过模板之后就不再自动跟随预设(否则他刚选的会被覆盖掉)。 */
|
|
@@ -2505,7 +2524,8 @@ window.__ModuleLoader__.load({
|
|
|
2505
2524
|
const [openPicker, setOpenPicker] = (0, react.useState)(null);
|
|
2506
2525
|
const [busyId, setBusyId] = (0, react.useState)(null);
|
|
2507
2526
|
const [results, setResults] = (0, react.useState)({});
|
|
2508
|
-
|
|
2527
|
+
/** 待二次确认的动作(动作 + 目标预设);`align` / `revert` 会动到已有内容。 */
|
|
2528
|
+
const [confirming, setConfirming] = (0, react.useState)(null);
|
|
2509
2529
|
/**
|
|
2510
2530
|
* 悬浮说明:portal 到 body 的 fixed 浮层 + 按按钮实时矩形算出的坐标。
|
|
2511
2531
|
* 位置不能像之前那样用绝对定位挂在卡片里:设置面板的滚动容器是 `overflow-y:auto`,
|
|
@@ -2539,8 +2559,10 @@ window.__ModuleLoader__.load({
|
|
|
2539
2559
|
setPhase("unavailable");
|
|
2540
2560
|
return;
|
|
2541
2561
|
}
|
|
2542
|
-
setPresets(
|
|
2562
|
+
setPresets(value.presets);
|
|
2543
2563
|
setTemplates(Array.isArray(value.templates) ? value.templates : []);
|
|
2564
|
+
setWritable(value.writable !== false);
|
|
2565
|
+
setLegacyRoot(typeof value.legacyPresetRoot === "string" && value.legacyPresetRoot.length > 0 ? value.legacyPresetRoot : void 0);
|
|
2544
2566
|
setPhase("ready");
|
|
2545
2567
|
} catch {
|
|
2546
2568
|
setPhase("unavailable");
|
|
@@ -2588,7 +2610,7 @@ window.__ModuleLoader__.load({
|
|
|
2588
2610
|
]);
|
|
2589
2611
|
/** 执行一个动作;成功后重新拉状态与比较(结果行保留,直到下一次动作)。 */
|
|
2590
2612
|
const runAction = (0, react.useCallback)((preset, action) => {
|
|
2591
|
-
|
|
2613
|
+
setConfirming(null);
|
|
2592
2614
|
setBusyId(preset.id);
|
|
2593
2615
|
setResults((prev) => ({
|
|
2594
2616
|
...prev,
|
|
@@ -2679,14 +2701,14 @@ window.__ModuleLoader__.load({
|
|
|
2679
2701
|
"aria-haspopup": "menu",
|
|
2680
2702
|
"aria-expanded": openPicker === key,
|
|
2681
2703
|
onClick: () => setOpenPicker((open) => open === key ? null : key),
|
|
2682
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: current }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2704
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: current }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: "tp-selectChevron" })]
|
|
2683
2705
|
})
|
|
2684
2706
|
})]
|
|
2685
2707
|
});
|
|
2686
2708
|
/** 选中那份的详情:名称/来源 → 动作 → 说明 → 待改 → 二次确认 → 结果。 */
|
|
2687
2709
|
const detail = (preset) => {
|
|
2688
|
-
const notes = presetNotes(t, preset);
|
|
2689
|
-
const actions = presetActions(preset);
|
|
2710
|
+
const notes = presetNotes(t, preset, writable);
|
|
2711
|
+
const actions = presetActions(preset, writable);
|
|
2690
2712
|
const pending = presetPendingText(t, preset);
|
|
2691
2713
|
const result = results[preset.id] ?? null;
|
|
2692
2714
|
const running = busyId === preset.id;
|
|
@@ -2710,20 +2732,20 @@ window.__ModuleLoader__.load({
|
|
|
2710
2732
|
onMouseLeave: () => setHinted(null),
|
|
2711
2733
|
children: actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2712
2734
|
type: "button",
|
|
2713
|
-
className: "tp-actionButton tpp-actionButton" + (action === "
|
|
2735
|
+
className: "tp-actionButton tpp-actionButton" + (action === "align" ? " tpp-danger" : ""),
|
|
2714
2736
|
disabled: running,
|
|
2715
2737
|
"aria-description": presetActionHint(t, action, preset, templateLabel),
|
|
2716
2738
|
onMouseEnter: (event) => showHint(action, event.currentTarget),
|
|
2717
2739
|
onFocus: (event) => showHint(action, event.currentTarget),
|
|
2718
2740
|
onBlur: () => setHinted(null),
|
|
2719
2741
|
onClick: () => {
|
|
2720
|
-
if (action
|
|
2742
|
+
if (presetActionNeedsConfirm(action)) setConfirming({
|
|
2743
|
+
id: preset.id,
|
|
2744
|
+
action
|
|
2745
|
+
});
|
|
2721
2746
|
else runAction(preset, action);
|
|
2722
2747
|
},
|
|
2723
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: running ? t("presetActionWorking") : presetActionText(t, action) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2724
|
-
className: "tpp-helpIcon",
|
|
2725
|
-
"aria-hidden": "true"
|
|
2726
|
-
})]
|
|
2748
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: running ? t("presetActionWorking") : presetActionText(t, action) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconQuestionOutlineRegular, { className: "tpp-helpIcon" })]
|
|
2727
2749
|
}, action))
|
|
2728
2750
|
}) : null]
|
|
2729
2751
|
}),
|
|
@@ -2741,24 +2763,24 @@ window.__ModuleLoader__.load({
|
|
|
2741
2763
|
className: "tpp-state",
|
|
2742
2764
|
children: pending
|
|
2743
2765
|
}) : null,
|
|
2744
|
-
|
|
2766
|
+
confirming !== null && confirming.id === preset.id ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2745
2767
|
className: "tpp-confirm",
|
|
2746
2768
|
role: "group",
|
|
2747
|
-
"aria-label": t("
|
|
2769
|
+
"aria-label": t("presetConfirmTitle"),
|
|
2748
2770
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2749
2771
|
className: "tpp-confirmText",
|
|
2750
|
-
children: presetConfirmText(t, preset, selectedTemplateLabel)
|
|
2772
|
+
children: presetConfirmText(t, preset, confirming.action, selectedTemplateLabel)
|
|
2751
2773
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2752
2774
|
className: "tpp-confirmActions",
|
|
2753
2775
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2754
2776
|
type: "button",
|
|
2755
2777
|
className: "tp-actionButton tpp-danger",
|
|
2756
|
-
onClick: () => runAction(preset,
|
|
2778
|
+
onClick: () => runAction(preset, confirming.action),
|
|
2757
2779
|
children: t("presetConfirmYes")
|
|
2758
2780
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2759
2781
|
type: "button",
|
|
2760
2782
|
className: "tp-actionButton",
|
|
2761
|
-
onClick: () =>
|
|
2783
|
+
onClick: () => setConfirming(null),
|
|
2762
2784
|
children: t("presetConfirmNo")
|
|
2763
2785
|
})]
|
|
2764
2786
|
})]
|
|
@@ -2805,7 +2827,7 @@ window.__ModuleLoader__.load({
|
|
|
2805
2827
|
label: presetOptionLabel(preset)
|
|
2806
2828
|
})), (id) => {
|
|
2807
2829
|
setPresetId(id);
|
|
2808
|
-
|
|
2830
|
+
setConfirming(null);
|
|
2809
2831
|
setDiffOpen(false);
|
|
2810
2832
|
}),
|
|
2811
2833
|
templates.length > 0 ? picker("template", t("presetPickTemplate"), selectedTemplate === void 0 ? t("presetEmpty") : presetTemplateLabel(selectedTemplate), templates.map((template) => ({
|
|
@@ -2845,7 +2867,11 @@ window.__ModuleLoader__.load({
|
|
|
2845
2867
|
}) : null
|
|
2846
2868
|
]
|
|
2847
2869
|
}),
|
|
2848
|
-
selected !== void 0 ? detail(selected) : null
|
|
2870
|
+
selected !== void 0 ? detail(selected) : null,
|
|
2871
|
+
legacyRoot !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2872
|
+
className: "tpp-state",
|
|
2873
|
+
children: t("presetNoteLegacy").replace("{path}", legacyRoot)
|
|
2874
|
+
}) : null
|
|
2849
2875
|
] }) : null
|
|
2850
2876
|
]
|
|
2851
2877
|
}),
|
|
@@ -3118,8 +3144,8 @@ window.__ModuleLoader__.load({
|
|
|
3118
3144
|
}
|
|
3119
3145
|
/** Render the Tool Plus settings section. */
|
|
3120
3146
|
function ToolPlusSection(props) {
|
|
3121
|
-
const { t,
|
|
3122
|
-
const form = useToolForm(
|
|
3147
|
+
const { t, form: configForm } = props;
|
|
3148
|
+
const form = useToolForm(configForm, ALL_FIELDS);
|
|
3123
3149
|
const sectionRef = (0, react.useRef)(null);
|
|
3124
3150
|
const tabsId = (0, react.useRef)(`tps-${Math.random().toString(36).slice(2, 8)}`);
|
|
3125
3151
|
const tabRefs = (0, react.useRef)([]);
|
|
@@ -3129,9 +3155,9 @@ window.__ModuleLoader__.load({
|
|
|
3129
3155
|
const [actionResults, setActionResults] = (0, react.useState)({});
|
|
3130
3156
|
const [rmSafeToast, setRmSafeToast] = (0, react.useState)(null);
|
|
3131
3157
|
const handleSave = (0, react.useCallback)(async () => {
|
|
3132
|
-
const before = Boolean(
|
|
3158
|
+
const before = Boolean(configForm.getSnapshot().value?.rmSafe ?? true);
|
|
3133
3159
|
await form.actions.save();
|
|
3134
|
-
const after = Boolean(
|
|
3160
|
+
const after = Boolean(configForm.getSnapshot().value?.rmSafe ?? true);
|
|
3135
3161
|
if (before === after || !after) return;
|
|
3136
3162
|
try {
|
|
3137
3163
|
const result = await createWebConnectionRpc().call(TOOL_PLUS_RPC_CHANNEL, RM_SAFE_STATUS_ENDPOINT, {});
|
|
@@ -3144,7 +3170,7 @@ window.__ModuleLoader__.load({
|
|
|
3144
3170
|
});
|
|
3145
3171
|
} catch {}
|
|
3146
3172
|
}, [
|
|
3147
|
-
|
|
3173
|
+
configForm,
|
|
3148
3174
|
form,
|
|
3149
3175
|
t
|
|
3150
3176
|
]);
|
|
@@ -3403,7 +3429,7 @@ window.__ModuleLoader__.load({
|
|
|
3403
3429
|
}),
|
|
3404
3430
|
rmSafeToast !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
3405
3431
|
text: rmSafeToast.text,
|
|
3406
|
-
icon: rmSafeToast.ok ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
3432
|
+
icon: rmSafeToast.ok ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
|
|
3407
3433
|
onDone: () => {
|
|
3408
3434
|
setRmSafeToast(null);
|
|
3409
3435
|
}
|
|
@@ -3607,13 +3633,18 @@ window.__ModuleLoader__.load({
|
|
|
3607
3633
|
invalidNumber: "请填写数字;留空表示使用默认值。",
|
|
3608
3634
|
appliesTo: "保存后对新调用生效。",
|
|
3609
3635
|
groupPresets: "预设",
|
|
3610
|
-
presetNoteBroken: "
|
|
3611
|
-
presetNoteUnrecognized: "
|
|
3636
|
+
presetNoteBroken: "无法挂载:{reason}",
|
|
3637
|
+
presetNoteUnrecognized: "插件行列表读不出来,未做任何改动。",
|
|
3638
|
+
presetNoteNoRow: "这个 profile 里没有本插件的声明行——插件不是以 profile bundle 装的。",
|
|
3639
|
+
presetNoteOther: "这个预设由别处声明,本面板只替它修冲突的工具行。",
|
|
3640
|
+
presetNoteCustomized: "这一行在你的 profile 配置里有覆盖;「恢复随包」可撤销。",
|
|
3641
|
+
presetNoteNoProfile: "本部署没有可编辑的 profile,只能查看。",
|
|
3642
|
+
presetNoteLegacy: "检测到旧版预设目录 {path}:0.1.7 起没有任何代码读它,可以安全删除。",
|
|
3612
3643
|
presetPickPreset: "预设",
|
|
3613
3644
|
presetPickTemplate: "对比模板",
|
|
3614
3645
|
presetToolOk: "已接入本插件工具",
|
|
3615
3646
|
presetToolWarn: "还有 {count} 个工具行未处理",
|
|
3616
|
-
presetToolError: "
|
|
3647
|
+
presetToolError: "读不到这份预设的插件行",
|
|
3617
3648
|
presetToolLoading: "正在检查…",
|
|
3618
3649
|
presetCompareOk: "与所选模板一致",
|
|
3619
3650
|
presetCompareWarn: "与所选模板有 {count} 处不同",
|
|
@@ -3630,25 +3661,30 @@ window.__ModuleLoader__.load({
|
|
|
3630
3661
|
presetDiffWholeRow: "(整行)",
|
|
3631
3662
|
presetDiffEmpty: "内容一致,没有可显示的差异。",
|
|
3632
3663
|
presetActionUpdate: "最小更新",
|
|
3633
|
-
presetActionUpdateHint: "
|
|
3634
|
-
presetActionUpdateNothing: "
|
|
3635
|
-
|
|
3636
|
-
|
|
3664
|
+
presetActionUpdateHint: "只把这 {count} 个工具行({rows})关掉,其他内容一个字节都不动。",
|
|
3665
|
+
presetActionUpdateNothing: "当前没有需要关掉的工具行。",
|
|
3666
|
+
presetActionAlign: "对齐模板",
|
|
3667
|
+
presetActionAlignHint: "用所选模板「{template}」整份替换这一行的插件列表。",
|
|
3668
|
+
presetActionRevert: "恢复随包",
|
|
3669
|
+
presetActionRevertHint: "删掉你写在本 profile 配置里的这份预设的覆盖,回落到随包声明。",
|
|
3637
3670
|
presetActionWorking: "处理中…",
|
|
3638
|
-
presetPendingReset: "将用所选模板整份覆盖这份预设,本地改动会被覆盖。",
|
|
3639
|
-
presetPendingInstall: "将写入这份预设:它当前尚未安装。",
|
|
3640
3671
|
presetPendingRows: "工具行将调整这 {count} 处:{rows}",
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3672
|
+
presetPendingBroken: "插件行列表读不出来;「对齐模板」可以整份修好它。",
|
|
3673
|
+
presetConfirmTitle: "确认动作",
|
|
3674
|
+
presetConfirmAlign: "将用模板「{template}」整份替换这份预设的插件列表,并写入本 profile 的配置(cordis.patch.yml)。",
|
|
3675
|
+
presetConfirmAlignEdits: "你在这一行上的改动会被覆盖。",
|
|
3676
|
+
presetConfirmRevert: "将删掉你写在本 profile 配置里的这份预设的覆盖,回落到随包声明。你的改动会丢失。",
|
|
3677
|
+
presetConfirmYes: "确认",
|
|
3644
3678
|
presetConfirmNo: "取消",
|
|
3645
3679
|
presetResultDone: "已调整 {count} 处。",
|
|
3646
3680
|
presetResultRows: "涉及:{rows}",
|
|
3647
3681
|
presetResultNoChange: "没有需要改动的行。",
|
|
3648
|
-
|
|
3649
|
-
|
|
3682
|
+
presetResultAlignDone: "已按所选模板对齐,并写入本 profile 的配置。",
|
|
3683
|
+
presetResultAlignNoChange: "已经与所选模板一致,没有改动。",
|
|
3684
|
+
presetResultRevertDone: "已删掉覆盖,回落到随包声明。",
|
|
3685
|
+
presetResultRevertNoChange: "这一行本来就没有覆盖,没有改动。",
|
|
3686
|
+
presetResultBackup: "改动前的内容已备份(与本 profile 的补丁同目录,.bak-<版本>)。",
|
|
3650
3687
|
presetResultFailed: "操作失败:{reason}",
|
|
3651
|
-
presetResultBackup: "原文件已备份。",
|
|
3652
3688
|
presetFailUnknown: "未知原因",
|
|
3653
3689
|
presetEntryCommand: "命令执行",
|
|
3654
3690
|
presetEntryPwsh: "PowerShell",
|
|
@@ -3853,13 +3889,18 @@ window.__ModuleLoader__.load({
|
|
|
3853
3889
|
invalidNumber: "Enter a number, or leave blank to use the default.",
|
|
3854
3890
|
appliesTo: "Values apply to new calls.",
|
|
3855
3891
|
groupPresets: "Presets",
|
|
3856
|
-
presetNoteBroken: "
|
|
3857
|
-
presetNoteUnrecognized: "
|
|
3892
|
+
presetNoteBroken: "Cannot be mounted: {reason}",
|
|
3893
|
+
presetNoteUnrecognized: "The plugin row list cannot be read; nothing was changed.",
|
|
3894
|
+
presetNoteNoRow: "This profile has no declaration row for the plugin — it is not installed as a profile bundle.",
|
|
3895
|
+
presetNoteOther: "Another bundle declares this preset; this panel only fixes its conflicting tool rows.",
|
|
3896
|
+
presetNoteCustomized: "This row carries an override in your profile configuration; \"Revert to bundled\" removes it.",
|
|
3897
|
+
presetNoteNoProfile: "This deployment has no editable profile, so the panel is read-only.",
|
|
3898
|
+
presetNoteLegacy: "A legacy preset directory was found at {path}: nothing reads it since 0.1.7, so it is safe to delete.",
|
|
3858
3899
|
presetPickPreset: "Preset",
|
|
3859
3900
|
presetPickTemplate: "Compare with template",
|
|
3860
3901
|
presetToolOk: "Plugin tools wired in",
|
|
3861
3902
|
presetToolWarn: "{count} tool rows left",
|
|
3862
|
-
presetToolError: "
|
|
3903
|
+
presetToolError: "Plugin rows for this preset cannot be read",
|
|
3863
3904
|
presetToolLoading: "Checking…",
|
|
3864
3905
|
presetCompareOk: "Matches the selected template",
|
|
3865
3906
|
presetCompareWarn: "{count} differences vs the selected template",
|
|
@@ -3876,25 +3917,30 @@ window.__ModuleLoader__.load({
|
|
|
3876
3917
|
presetDiffWholeRow: "(whole row)",
|
|
3877
3918
|
presetDiffEmpty: "Content matches; nothing to show.",
|
|
3878
3919
|
presetActionUpdate: "Minimal update",
|
|
3879
|
-
presetActionUpdateHint: "Disables only these {count} tool rows ({rows});
|
|
3880
|
-
presetActionUpdateNothing: "No tool rows need
|
|
3881
|
-
|
|
3882
|
-
|
|
3920
|
+
presetActionUpdateHint: "Disables only these {count} tool rows ({rows}); nothing else changes at all.",
|
|
3921
|
+
presetActionUpdateNothing: "No tool rows need disabling.",
|
|
3922
|
+
presetActionAlign: "Align to template",
|
|
3923
|
+
presetActionAlignHint: "Replaces this row whole plugin list with the selected template \"{template}\".",
|
|
3924
|
+
presetActionRevert: "Revert to bundled",
|
|
3925
|
+
presetActionRevertHint: "Deletes the override written in this profile configuration, falling back to the bundled declaration.",
|
|
3883
3926
|
presetActionWorking: "Working…",
|
|
3884
|
-
presetPendingReset: "The whole preset will be replaced with the selected template; local changes will be lost.",
|
|
3885
|
-
presetPendingInstall: "This preset will be written: it is not installed yet.",
|
|
3886
3927
|
presetPendingRows: "Tool rows to adjust: {count} ({rows})",
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3928
|
+
presetPendingBroken: "The plugin row list cannot be read; \"Align to template\" replaces it with a good one.",
|
|
3929
|
+
presetConfirmTitle: "Confirm action",
|
|
3930
|
+
presetConfirmAlign: "The whole plugin list will be replaced with template \"{template}\" and written to this profile configuration (cordis.patch.yml).",
|
|
3931
|
+
presetConfirmAlignEdits: "Your edits to this row will be overwritten.",
|
|
3932
|
+
presetConfirmRevert: "The override written in this profile configuration will be deleted, falling back to the bundled declaration. Your edits will be lost.",
|
|
3933
|
+
presetConfirmYes: "Confirm",
|
|
3890
3934
|
presetConfirmNo: "Cancel",
|
|
3891
3935
|
presetResultDone: "Adjusted {count} entries.",
|
|
3892
3936
|
presetResultRows: "Entries: {rows}",
|
|
3893
3937
|
presetResultNoChange: "Nothing needed changing.",
|
|
3894
|
-
|
|
3895
|
-
|
|
3938
|
+
presetResultAlignDone: "Aligned to the selected template and written to this profile configuration.",
|
|
3939
|
+
presetResultAlignNoChange: "Already matches the selected template; nothing changed.",
|
|
3940
|
+
presetResultRevertDone: "Override removed; the preset falls back to its bundled declaration.",
|
|
3941
|
+
presetResultRevertNoChange: "This row carried no override; nothing changed.",
|
|
3942
|
+
presetResultBackup: "The previous content was backed up beside this profile patch (.bak-<version>).",
|
|
3896
3943
|
presetResultFailed: "Action failed: {reason}",
|
|
3897
|
-
presetResultBackup: "The original file was backed up.",
|
|
3898
3944
|
presetFailUnknown: "unknown reason",
|
|
3899
3945
|
presetEntryCommand: "Command execution",
|
|
3900
3946
|
presetEntryPwsh: "PowerShell",
|
|
@@ -4237,6 +4283,9 @@ window.__ModuleLoader__.load({
|
|
|
4237
4283
|
expandRest: "… 其余 {count} 行",
|
|
4238
4284
|
"files.one": "{count} 个文件",
|
|
4239
4285
|
"files.other": "{count} 个文件",
|
|
4286
|
+
"codeBlock.title": "代码块",
|
|
4287
|
+
"codeBlock.wrap": "自动换行",
|
|
4288
|
+
"codeBlock.unwrap": "取消自动换行",
|
|
4240
4289
|
running: "运行中",
|
|
4241
4290
|
done: "完成",
|
|
4242
4291
|
failed: "失败",
|
|
@@ -4278,6 +4327,7 @@ window.__ModuleLoader__.load({
|
|
|
4278
4327
|
"terminal.failed": "失败",
|
|
4279
4328
|
"terminal.done": "已完成",
|
|
4280
4329
|
"terminal.noOutput": "无输出",
|
|
4330
|
+
"terminal.noExitCode": "未正常退出",
|
|
4281
4331
|
"bash.background": "后台任务 {jobId}",
|
|
4282
4332
|
"image.loading": "加载中",
|
|
4283
4333
|
"image.loadFailed": "加载失败",
|
|
@@ -4301,6 +4351,9 @@ window.__ModuleLoader__.load({
|
|
|
4301
4351
|
expandRest: "… {count} more lines",
|
|
4302
4352
|
"files.one": "{count} file",
|
|
4303
4353
|
"files.other": "{count} files",
|
|
4354
|
+
"codeBlock.title": "Code block",
|
|
4355
|
+
"codeBlock.wrap": "Wrap lines",
|
|
4356
|
+
"codeBlock.unwrap": "Do not wrap lines",
|
|
4304
4357
|
running: "Running",
|
|
4305
4358
|
done: "Done",
|
|
4306
4359
|
failed: "Failed",
|
|
@@ -4342,6 +4395,7 @@ window.__ModuleLoader__.load({
|
|
|
4342
4395
|
"terminal.failed": "Failed",
|
|
4343
4396
|
"terminal.done": "Done",
|
|
4344
4397
|
"terminal.noOutput": "No output",
|
|
4398
|
+
"terminal.noExitCode": "no exit code",
|
|
4345
4399
|
"bash.background": "Background job {jobId}",
|
|
4346
4400
|
"image.loading": "Loading",
|
|
4347
4401
|
"image.loadFailed": "Load failed",
|
|
@@ -4372,6 +4426,22 @@ window.__ModuleLoader__.load({
|
|
|
4372
4426
|
return block.kind === "tool-result";
|
|
4373
4427
|
}
|
|
4374
4428
|
/**
|
|
4429
|
+
* Whether a call already landed as a failed result.
|
|
4430
|
+
*
|
|
4431
|
+
* Only a settled result can be wrong about its work: the union's error state is
|
|
4432
|
+
* `ToolResultNode.isError` alone, and the shipped row model reads it the same
|
|
4433
|
+
* way — settle on the `kind` discriminant (`'kind' in block`) and only then look
|
|
4434
|
+
* at `error`, `isError`. A preparing or dispatched call has no result yet, so it
|
|
4435
|
+
* is never an error; the rows that fall back to the generic shell keep exactly
|
|
4436
|
+
* the criterion they have always had (`isError === true`), stated where the
|
|
4437
|
+
* union still allows it.
|
|
4438
|
+
* @param block - the frozen running-or-settled call node.
|
|
4439
|
+
* @returns whether the call settled as a failure.
|
|
4440
|
+
*/
|
|
4441
|
+
function isErrorResult(block) {
|
|
4442
|
+
return isSettled(block) && block.isError === true;
|
|
4443
|
+
}
|
|
4444
|
+
/**
|
|
4375
4445
|
* The call head paired with a block: a running call is its own head; a settled
|
|
4376
4446
|
* result carries the head backfilled from the in-window `tool/call`, which is
|
|
4377
4447
|
* `null` when window truncation left that event outside.
|
|
@@ -4444,7 +4514,7 @@ window.__ModuleLoader__.load({
|
|
|
4444
4514
|
function cardState(block) {
|
|
4445
4515
|
if (!isSettled(block)) return "running";
|
|
4446
4516
|
if (isRecord$2(block.error) && block.error.code === "interrupted") return "warning";
|
|
4447
|
-
if (block
|
|
4517
|
+
if (isErrorResult(block)) return "error";
|
|
4448
4518
|
const terminal = narrowTerminalCardMeta(cardMeta(block));
|
|
4449
4519
|
if (terminal !== null && terminal.mode === "foreground" && (terminal.timedOut || terminal.aborted)) return "warning";
|
|
4450
4520
|
return "ok";
|
|
@@ -4626,21 +4696,39 @@ window.__ModuleLoader__.load({
|
|
|
4626
4696
|
timedOut
|
|
4627
4697
|
};
|
|
4628
4698
|
}
|
|
4699
|
+
/**
|
|
4700
|
+
* Bind the card dictionary to the shared code-card toolbar labels.
|
|
4701
|
+
*
|
|
4702
|
+
* The toolbar rides every code surface the primitives draw (the diff block, the
|
|
4703
|
+
* read block), and the host's own adapter for it reads the base locale's
|
|
4704
|
+
* `codeBlock.*` wording; this dictionary carries the same three strings, so a
|
|
4705
|
+
* takeover's code cards read exactly as the shipped ones do.
|
|
4706
|
+
* @param t - the card translate seat.
|
|
4707
|
+
* @returns the language fallback and wrapping actions.
|
|
4708
|
+
*/
|
|
4709
|
+
function codeToolbarLabels(t) {
|
|
4710
|
+
return {
|
|
4711
|
+
codeLabel: t("codeBlock.title"),
|
|
4712
|
+
wrapLabel: t("codeBlock.wrap"),
|
|
4713
|
+
unwrapLabel: t("codeBlock.unwrap")
|
|
4714
|
+
};
|
|
4715
|
+
}
|
|
4629
4716
|
/** Bind the card dictionary to the diff primitive's chrome labels. */
|
|
4630
4717
|
function diffBlockLabels(t) {
|
|
4631
4718
|
return {
|
|
4719
|
+
...codeToolbarLabels(t),
|
|
4632
4720
|
copy: t("copy"),
|
|
4633
4721
|
copied: t("copied"),
|
|
4634
4722
|
collapseAria: t("collapseAria"),
|
|
4635
4723
|
expandAria: (count) => t("expandAria", { count }),
|
|
4636
4724
|
collapse: t("collapse"),
|
|
4637
|
-
expand: (count) => t("expandRest", { count })
|
|
4638
|
-
files: (count) => t(count === 1 ? "files.one" : "files.other", { count })
|
|
4725
|
+
expand: (count) => t("expandRest", { count })
|
|
4639
4726
|
};
|
|
4640
4727
|
}
|
|
4641
4728
|
/** Bind the card dictionary to the read primitive's chrome labels. */
|
|
4642
4729
|
function readBlockLabels(t) {
|
|
4643
4730
|
return {
|
|
4731
|
+
...codeToolbarLabels(t),
|
|
4644
4732
|
window: (shown, total) => t("read.window", {
|
|
4645
4733
|
shown,
|
|
4646
4734
|
total
|
|
@@ -4679,6 +4767,7 @@ window.__ModuleLoader__.load({
|
|
|
4679
4767
|
return {
|
|
4680
4768
|
signal: (signal) => t("terminal.signal", { signal }),
|
|
4681
4769
|
exitCode: (exitCode) => t("terminal.exitCode", { code: exitCode }),
|
|
4770
|
+
noExitCode: t("terminal.noExitCode"),
|
|
4682
4771
|
running: t("terminal.running"),
|
|
4683
4772
|
failed: t("terminal.failed"),
|
|
4684
4773
|
done: t("terminal.done"),
|
|
@@ -5038,11 +5127,11 @@ window.__ModuleLoader__.load({
|
|
|
5038
5127
|
*/
|
|
5039
5128
|
/** Leading glyphs (the shipped table): every glyph renders at 14 inside the 16px leading box. */
|
|
5040
5129
|
const LEADING_GLYPHS = {
|
|
5041
|
-
bash: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
5042
|
-
read: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
5043
|
-
edit: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
5044
|
-
search: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
5045
|
-
others: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
5130
|
+
bash: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconApiOutlineRegular, { size: 14 }),
|
|
5131
|
+
read: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBrowseOutlineRegular, { size: 14 }),
|
|
5132
|
+
edit: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineRegular, { size: 14 }),
|
|
5133
|
+
search: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineRegular, { size: 14 }),
|
|
5134
|
+
others: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSparkleRegular, { size: 14 })
|
|
5046
5135
|
};
|
|
5047
5136
|
/**
|
|
5048
5137
|
* The leading mark of one row: the tool's glyph while the call is clean or
|
|
@@ -5363,7 +5452,7 @@ window.__ModuleLoader__.load({
|
|
|
5363
5452
|
const { t, block, cwd, inspect, openFile, title, toolName } = props;
|
|
5364
5453
|
const args = parseCardArgs(block);
|
|
5365
5454
|
const meta = narrowAstEditCardMeta(cardMeta(block));
|
|
5366
|
-
if (isSubCall(block) || block
|
|
5455
|
+
if (isSubCall(block) || isErrorResult(block) || meta === null || meta.preview === "") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GenericCard, {
|
|
5367
5456
|
t,
|
|
5368
5457
|
title,
|
|
5369
5458
|
block,
|
|
@@ -5450,7 +5539,7 @@ window.__ModuleLoader__.load({
|
|
|
5450
5539
|
const args = parseCardArgs(block);
|
|
5451
5540
|
const meta = narrowEditCardMeta(cardMeta(block));
|
|
5452
5541
|
const replaceForm = replaceHunks(args);
|
|
5453
|
-
if (isSubCall(block) || block
|
|
5542
|
+
if (isSubCall(block) || isErrorResult(block) || meta === null && replaceForm === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GenericCard, {
|
|
5454
5543
|
t,
|
|
5455
5544
|
title,
|
|
5456
5545
|
block,
|
|
@@ -5665,7 +5754,7 @@ window.__ModuleLoader__.load({
|
|
|
5665
5754
|
const args = parseCardArgs(block);
|
|
5666
5755
|
const meta = narrowReadCardMeta(cardMeta(block));
|
|
5667
5756
|
const material = (0, react.useMemo)(() => imageCardMaterial(block, cwd), [block, cwd]);
|
|
5668
|
-
if (isSubCall(block) || block
|
|
5757
|
+
if (isSubCall(block) || isErrorResult(block)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GenericCard, {
|
|
5669
5758
|
t,
|
|
5670
5759
|
title,
|
|
5671
5760
|
block,
|
|
@@ -5948,7 +6037,7 @@ window.__ModuleLoader__.load({
|
|
|
5948
6037
|
className: "twc-lightboxClose",
|
|
5949
6038
|
"aria-label": t("image.close"),
|
|
5950
6039
|
onClick: onClose,
|
|
5951
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
6040
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutlineRegular, { size: 16 })
|
|
5952
6041
|
})
|
|
5953
6042
|
]
|
|
5954
6043
|
}), document.body);
|
|
@@ -6030,7 +6119,7 @@ window.__ModuleLoader__.load({
|
|
|
6030
6119
|
const { t, block, cwd, inspect, title, toolName } = props;
|
|
6031
6120
|
const args = parseCardArgs(block);
|
|
6032
6121
|
const meta = narrowSearchCardMeta(cardMeta(block));
|
|
6033
|
-
if (isSubCall(block) || block
|
|
6122
|
+
if (isSubCall(block) || isErrorResult(block) || meta === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GenericCard, {
|
|
6034
6123
|
t,
|
|
6035
6124
|
title,
|
|
6036
6125
|
block,
|
|
@@ -6109,7 +6198,7 @@ window.__ModuleLoader__.load({
|
|
|
6109
6198
|
const meta = narrowTerminalCardMeta(cardMeta(block));
|
|
6110
6199
|
const command = argText(args, "command");
|
|
6111
6200
|
const state = cardState(block);
|
|
6112
|
-
if (block
|
|
6201
|
+
if (isErrorResult(block) || command === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GenericCard, {
|
|
6113
6202
|
t,
|
|
6114
6203
|
title,
|
|
6115
6204
|
block,
|
|
@@ -6197,7 +6286,7 @@ window.__ModuleLoader__.load({
|
|
|
6197
6286
|
const meta = narrowWriteCardMeta(cardMeta(block));
|
|
6198
6287
|
const content = argText(args, "content");
|
|
6199
6288
|
const path = meta?.path ?? argText(args, "path");
|
|
6200
|
-
if (isSubCall(block) || block
|
|
6289
|
+
if (isSubCall(block) || isErrorResult(block) || content === null || path === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GenericCard, {
|
|
6201
6290
|
t,
|
|
6202
6291
|
title,
|
|
6203
6292
|
block,
|
|
@@ -6323,13 +6412,13 @@ window.__ModuleLoader__.load({
|
|
|
6323
6412
|
disposeEntries?.();
|
|
6324
6413
|
disposeEntries = void 0;
|
|
6325
6414
|
};
|
|
6326
|
-
const
|
|
6415
|
+
const form = ctx.configForms.get(SETTINGS_NS);
|
|
6327
6416
|
ctx.effect(() => {
|
|
6328
6417
|
const sync = () => {
|
|
6329
|
-
if (cardsEnabled(
|
|
6418
|
+
if (cardsEnabled(form.getSnapshot().value)) install();
|
|
6330
6419
|
else uninstall();
|
|
6331
6420
|
};
|
|
6332
|
-
const stop =
|
|
6421
|
+
const stop = form.subscribe(sync);
|
|
6333
6422
|
sync();
|
|
6334
6423
|
return stop;
|
|
6335
6424
|
}, "tool-plus: web card switch");
|
|
@@ -6385,14 +6474,14 @@ window.__ModuleLoader__.load({
|
|
|
6385
6474
|
const BASH_PLUS_CLIENT_NS = "tool-plus";
|
|
6386
6475
|
/** Locale dictionary namespace of this package's card copy. */
|
|
6387
6476
|
const BASH_PLUS_LOCALE_NS = "tool-plus";
|
|
6388
|
-
/** Required services (cordis fiber inject): slots + locale + the
|
|
6477
|
+
/** Required services (cordis fiber inject): slots + locale + the shared configuration forms. */
|
|
6389
6478
|
const inject = [
|
|
6390
6479
|
"slots",
|
|
6391
6480
|
"locale",
|
|
6392
|
-
"
|
|
6481
|
+
"configForms"
|
|
6393
6482
|
];
|
|
6394
6483
|
/**
|
|
6395
|
-
* Mount the tool-plus settings
|
|
6484
|
+
* Mount the tool-plus settings surfaces.
|
|
6396
6485
|
* @param ctx - the browser plugin context.
|
|
6397
6486
|
*/
|
|
6398
6487
|
function apply(ctx) {
|
|
@@ -6400,23 +6489,25 @@ window.__ModuleLoader__.load({
|
|
|
6400
6489
|
zh: zh$1,
|
|
6401
6490
|
en: en$1
|
|
6402
6491
|
}), "tool-plus: card dictionaries");
|
|
6403
|
-
const
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6492
|
+
const cardForm = ctx.configForms.get(BASH_PLUS_CLIENT_NS);
|
|
6493
|
+
const sectionForm = ctx.configForms.get(BASH_PLUS_CLIENT_NS);
|
|
6494
|
+
ctx.effect(() => ctx.configForms.whileServed([BASH_PLUS_CLIENT_NS], () => ctx.slots.inject("settings.plugins.tab", () => ctx.slots.register({
|
|
6495
|
+
name: "settings.plugins.tab",
|
|
6496
|
+
id: BASH_PLUS_CLIENT_NS,
|
|
6497
|
+
order: 20,
|
|
6498
|
+
label: () => ctx.locale.bind(BASH_PLUS_LOCALE_NS)("title"),
|
|
6407
6499
|
locale: BASH_PLUS_LOCALE_NS,
|
|
6408
|
-
inject: () => ({
|
|
6409
|
-
}, BashPlusCard));
|
|
6500
|
+
inject: () => ({ form: cardForm })
|
|
6501
|
+
}, BashPlusCard))), "tool-plus: plugins page");
|
|
6410
6502
|
registerToolCards(ctx);
|
|
6411
|
-
|
|
6412
|
-
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
6503
|
+
ctx.effect(() => ctx.configForms.whileServed([BASH_PLUS_CLIENT_NS], () => ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
6413
6504
|
name: "settings.section",
|
|
6414
6505
|
id: "tool-plus",
|
|
6415
6506
|
order: 16,
|
|
6416
6507
|
label: () => ctx.locale.bind(BASH_PLUS_LOCALE_NS)("nav"),
|
|
6417
6508
|
locale: BASH_PLUS_LOCALE_NS,
|
|
6418
|
-
inject: () => ({
|
|
6419
|
-
}, ToolPlusSection));
|
|
6509
|
+
inject: () => ({ form: sectionForm })
|
|
6510
|
+
}, ToolPlusSection))), "tool-plus: settings page");
|
|
6420
6511
|
}
|
|
6421
6512
|
//#endregion
|
|
6422
6513
|
exports.BASH_PLUS_CLIENT_NS = BASH_PLUS_CLIENT_NS;
|