@klarkxy/dsh-model-hub 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [简体中文](docs/README.zh-CN.md)
6
6
 
7
- See and change the models used by your DeepSeek Harness plugins from one page, manage which models subagents may use, and watch which model and reasoning effort each running subagent is on.
7
+ View and change the models your DeepSeek Harness plugins use, control which models subagents may use, and track the model and reasoning effort of each running subagent — all on one page.
8
8
 
9
9
  ## Install
10
10
 
@@ -18,16 +18,16 @@ Replace `web` with your profile name and restart the profile.
18
18
 
19
19
  Open **Plugins → Model Hub**.
20
20
 
21
- - **Fields**: every model setting exposed by installed plugins, such as Auto Title, Git Commit, and Safe Auto. Search by plugin, purpose, or current model, then pick a new model. Changes are saved by the plugin that owns the setting.
22
- - **Subagent Cast**: turn the subagent model allowlist on or off and add, replace, or remove models. When enabled with at least one model, it guides the agent to discover the models available in the current conversation and explicitly choose one when delegating. For independent reviews and alternative approaches, it encourages a different model when suitable, while allowing the same model when it fits better. You can add your own task tendencies for individual models; they remain optional hints, and no model-specific tendencies are supplied by default. Below the list, a live view shows each running subagent with the model and reasoning effort it is currently using; an effort marked as adapter default comes from the adapter rather than an explicit choice.
21
+ - **Fields**: every model setting exposed by installed plugins, such as Auto Title, Git Commit, and Safe Auto. Search by plugin, purpose, or current model, then pick a new model. The plugin that owns the setting saves the change.
22
+ - **Subagent Cast**: toggle the subagent model allowlist and add, replace, or remove models. When enabled with at least one model, it guides the agent to discover the models available in the current conversation and pick one explicitly when delegating. For independent reviews and alternative approaches it favors a different model when suitable, but allows the same one when it fits better. Per-model task tendencies you add are optional hints; none are supplied by default. Below the list, a live view shows each running subagent with its current model and reasoning effort; an effort marked adapter default comes from the adapter, not an explicit choice.
23
23
 
24
24
  ## Limits
25
25
 
26
26
  - Only plugins that expose model settings appear.
27
27
  - Changes made elsewhere update the page automatically. If an edit conflicts with a newer change, refresh and choose again.
28
- - If the model list cannot load, use **Retry**. The last available list stays visible; warnings identify providers that could not be loaded while other providers remain usable.
29
- - Model selection guidance requires host tools that support choosing a subagent model. Existing conversations retain their saved model lists; start a new conversation to use an updated list.
30
- - Guidance does not force a model choice or add extra subtasks solely for variety.
28
+ - If the model list cannot load, use **Retry**. The last available list stays visible; warnings name providers that failed while others stay usable.
29
+ - Selection guidance needs host tools that support choosing a subagent model. List changes apply to new conversations; existing conversations and their subagents keep their saved lists. Refreshing the settings page does not change a conversation's list. Omitting an explicit model can still inherit the parent model.
30
+ - Guidance never forces a model choice or adds subtasks just for variety.
31
31
  - Remote subagents and finished runs have no readable route; the live list covers only live local subagents.
32
32
  - No usage statistics.
33
33
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  [English](../README.md)
6
6
 
7
- 在一个页面查看并修改各个 DeepSeek Harness 插件使用的模型,管理子代理可用的模型,并查看运行中子代理当前使用的模型与思考强度。
7
+ 在一个页面查看并修改各 DeepSeek Harness 插件使用的模型,管理子代理可用的模型,并跟踪运行中子代理的模型与思考强度。
8
8
 
9
9
  ## 安装
10
10
 
@@ -18,16 +18,16 @@ dsh plugin --profile web add @klarkxy/dsh-model-hub
18
18
 
19
19
  打开「插件 → 模型枢纽」。
20
20
 
21
- - **字段总览**:列出已安装插件提供的模型设置,例如自动标题、Git 提交和安全自动。可以按插件、用途或当前模型搜索,再选择新模型;改动由对应插件保存。
22
- - **子代理阵容**:开关子代理模型白名单,添加、替换或移除模型。开启且至少有一个模型时,会引导智能体发现当前会话可用的模型,并在派发时显式选择。独立复核和方案对比会优先考虑合适的不同模型,同模型更适合时仍可使用。你可以自行填写各模型的「任务倾向」作为可选参考;插件不预置模型专用倾向。页面下方实时列出运行中的子代理及各自当前使用的模型和思考强度;标注「适配器默认」的强度来自适配器而非显式选择。
21
+ - **字段总览**:列出已安装插件提供的模型设置,例如自动标题、Git 提交和安全自动。可按插件、用途或当前模型搜索,再选择新模型;改动由对应插件保存。
22
+ - **子代理阵容**:开关子代理模型白名单,添加、替换或移除模型。开启且至少有一个模型时,会引导智能体发现当前会话可用的模型,并在派发时显式选择。独立复核和方案对比会优先考虑合适的不同模型,同模型更适合时仍可使用。自填的模型「任务倾向」只作可选参考,插件不预置任何倾向。列表下方实时显示运行中的子代理及其当前模型和思考强度;标注「适配器默认」的强度来自适配器,而非显式选择。
23
23
 
24
24
  ## 限制
25
25
 
26
- - 只显示提供了模型设置的插件。
27
- - 设置在别处改动时,页面会自动更新。编辑与较新的改动冲突时,请刷新后重新选择。
28
- - 模型列表读取失败时,点击「重试」。上次可用的列表会保留;部分提供方读取失败时会显示提示,其他提供方仍可使用。
29
- - 选模引导需要宿主工具支持选择子代理模型。已有会话保留各自的模型名单;修改名单后,新建会话才能使用更新后的名单。
30
- - 引导不强制模型选择,也不要求仅为增加模型种类而新增子任务。
26
+ - 只显示提供模型设置的插件。
27
+ - 别处改动设置时页面自动更新;编辑与较新的改动冲突时,刷新后重新选择。
28
+ - 模型列表读取失败时点「重试」。上次可用的列表保留;部分提供方读取失败会显示提示,其余提供方仍可用。
29
+ - 选模引导需要宿主工具支持选择子代理模型。名单修改对新建会话生效,已有会话及其子代理沿用原名单;刷新设置页面不会更新会话名单。不显式指定模型时仍可继承父代理模型。
30
+ - 引导不强制选模,也不为增加模型种类而新增子任务。
31
31
  - 远程子代理和已结束的子代理没有可读取的路由;运行列表只覆盖存活的本地子代理。
32
32
  - 不提供用量统计。
33
33
 
@@ -197,7 +197,14 @@ function groupModelMenuChoices(choices, query) {
197
197
  }
198
198
  //#endregion
199
199
  //#region ../dsh-model-route/src/catalog-ui.tsx
200
- /** Also accepts a mapped state from a caller that owns broader async orchestration. */
200
+ /**
201
+ * Also accepts a mapped state from a caller that owns broader async orchestration.
202
+ *
203
+ * The dsh-ui-* classes carry the styling and resolve through the consuming
204
+ * plugin's own officialUiCss scope (every consumer mounts its root class, so
205
+ * e.g. `.dsh-model-hub .dsh-ui-loading` paints this); dsh-model-catalog-status
206
+ * stays as a structural hook for tests and layout, never a colour source.
207
+ */
201
208
  function ModelCatalogStatus({ state, locale }) {
202
209
  const zh = locale?.toLowerCase().startsWith("zh") === true;
203
210
  const copy = zh ? {
@@ -213,15 +220,17 @@ function ModelCatalogStatus({ state, locale }) {
213
220
  };
214
221
  if (!state.loading && !state.error && state.failures.length === 0) return null;
215
222
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
216
- className: "dsh-model-catalog-status",
223
+ className: "dsh-model-catalog-status dsh-ui-stack",
217
224
  lang: zh ? "zh" : "en",
218
225
  children: [
219
226
  state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
220
227
  role: "status",
228
+ className: "dsh-ui-loading",
221
229
  children: copy.loading
222
230
  }) : null,
223
231
  state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
224
232
  role: "alert",
233
+ className: "dsh-ui-error dsh-ui-wrap",
225
234
  children: [
226
235
  copy.error,
227
236
  ": ",
@@ -230,20 +239,27 @@ function ModelCatalogStatus({ state, locale }) {
230
239
  }) : null,
231
240
  state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
232
241
  role: "status",
233
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
234
- failure.name || failure.id,
235
- ": ",
236
- failure.message
237
- ] }, `${failure.id}:${index}`)) })]
242
+ className: "dsh-ui-meta",
243
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
244
+ className: "dsh-ui-list",
245
+ children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
246
+ failure.name || failure.id,
247
+ ": ",
248
+ failure.message
249
+ ] }, `${failure.id}:${index}`))
250
+ })]
238
251
  }) : null,
239
- state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
240
- type: "button",
241
- size: "sm",
242
- disabled: state.loading,
243
- onClick: () => {
244
- state.refresh();
245
- },
246
- children: copy.retry
252
+ state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
253
+ className: "dsh-ui-actions",
254
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
255
+ type: "button",
256
+ size: "sm",
257
+ disabled: state.loading,
258
+ onClick: () => {
259
+ state.refresh();
260
+ },
261
+ children: copy.retry
262
+ })
247
263
  }) : null
248
264
  ]
249
265
  });
@@ -263,7 +279,8 @@ function ModelCatalogStatus({ state, locale }) {
263
279
  * Sticky group headings, subsequence ranking, highlight walking and focus
264
280
  * hand-back all match the host. SYNC POINT: when the host's ModelSelect or
265
281
  * ModelSelect.module.css changes, this copy must be re-transcribed; styles
266
- * below may only reference --dsw-* theme tokens, never literal colors.
282
+ * below may only reference allowlisted theme tokens (the --dsw-* set plus the
283
+ * host's --ds-* motion tokens), never literal colors.
267
284
  *
268
285
  * It statically imports the primitives, so only browser clients should load
269
286
  * this entry; host code and node tests use the core entry (`./index.ts`).
@@ -771,7 +788,8 @@ function ModelMenu(props) {
771
788
  * sticky group headings (MenuGroup's own CSS), and the l1-stroke prominent
772
789
  * elevation at portal z-index 1100. The trigger mirrors the composer's 28px
773
790
  * model pill, chevron rotating open. MenuSurface paints fill and backdrop.
774
- * Only --dsw-* theme tokens may appear here — a literal color is a bug.
791
+ * Only allowlisted --dsw- and --ds- theme tokens may appear here — a literal
792
+ * color is a bug.
775
793
  */
776
794
  const modelMenuCss = `
777
795
  .dsh-model-menu-root { min-width: 0; position: relative; display: inline-flex; }
@@ -794,12 +812,14 @@ const modelMenuCss = `
794
812
  display: flex;
795
813
  }
796
814
  .dsh-model-menu-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
797
- .dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
815
+ .dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0 var(--dsw-focus-ring-width) var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
798
816
  .dsh-model-menu-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
799
817
  .dsh-model-menu-triggerLabel { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }
800
818
  .dsh-model-menu-triggerEffort { text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--dsw-alias-label-caption); flex-shrink: 1000; overflow: hidden; }
801
- .dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform 0.12s; }
819
+ .dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform var(--ds-transition-duration) var(--ds-ease-in-out); }
802
820
  .dsh-model-menu-chevronOpen { transform: rotate(180deg); }
821
+ /* Portal overlay: the host publishes no z-index token, so the card keeps the
822
+ * native menu layer's 1100 verbatim. */
803
823
  .dsh-model-menu-menu {
804
824
  z-index: 1100;
805
825
  --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
@@ -825,6 +845,8 @@ const modelMenuCss = `
825
845
  .dsh-model-menu-searchWithQuery { padding-right: 34px; }
826
846
  .dsh-model-menu-searchRow .dsh-model-menu-search input { padding: 0; font-size: 12px; line-height: normal; }
827
847
  .dsh-model-menu-searchRow .dsh-model-menu-search input::placeholder { color: var(--dsw-alias-label-caption); }
848
+ /* The clear button is a circle by geometry (border-radius: 50%), a shape the
849
+ * radius token scale does not describe. */
828
850
  .dsh-model-menu-searchClear {
829
851
  width: 24px;
830
852
  height: 24px;
@@ -1072,6 +1094,17 @@ ${scope} {
1072
1094
  /* --- Layout scaffolding. --- */
1073
1095
  & .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }
1074
1096
  & .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }
1097
+ /* Plugin detail pages share one reading column. These are layout recipes;
1098
+ * controls keep their own primitive styles. Form spacing follows the host's
1099
+ * settings-form/fields.module.css and SettingsForm.module.css. */
1100
+ & .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }
1101
+ & .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }
1102
+ &.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }
1103
+ & .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }
1104
+ & .dsh-ui-fields-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; min-width: 0; margin: 0; padding: 0; border: 0; }
1105
+ @media (max-width: 560px) {
1106
+ & .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }
1107
+ }
1075
1108
  & .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
1076
1109
  & .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
1077
1110
  & .dsh-ui-spacer { flex: 1; min-width: 0; }
@@ -1099,6 +1132,9 @@ ${scope} {
1099
1132
  * official primitive, so this only owns the vertical rhythm. --- */
1100
1133
  & .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
1101
1134
  & .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }
1135
+ /* Grid fields share a row, so the stacked-field divider must not win later in
1136
+ * the cascade. Reset it here, after the field recipe. */
1137
+ & .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }
1102
1138
  & .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }
1103
1139
  & .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
1104
1140
  & .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }
@@ -1289,7 +1325,7 @@ ${scope} {
1289
1325
  & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
1290
1326
  }
1291
1327
  }
1292
- `.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className) => `&${className}, & ${className}`);
1328
+ `.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?=\s*\{)/gm, (_match, className) => `&${className}, & ${className}`);
1293
1329
  }
1294
1330
  //#endregion
1295
1331
  //#region ../dsh-plugin-kit/src/contracts.ts
@@ -1660,12 +1696,12 @@ const TEXT$1 = {
1660
1696
  zh: {
1661
1697
  title: "子代理阵容",
1662
1698
  enabledLabel: "启用子代理阵容",
1663
- enabledHint: "启用后,主智能体显式为子代理选择模型时须使用此列表;不指定模型时仍继承父会话。任务倾向供委派时参考。",
1699
+ enabledHint: "此名单限制子代理的显式选模;不指定模型时仍可继承父会话。名单修改对新建会话生效,已有会话及其子代理沿用原名单。任务倾向供委派时参考。",
1664
1700
  loading: "正在读取…",
1665
1701
  failed: (message) => `读取失败:${message}`,
1666
1702
  syncFailed: (message) => `自动同步不可用:${message}`,
1667
1703
  writeFailed: (message) => `未保存:${message}。请刷新后重试。`,
1668
- saved: "已保存,正在刷新…",
1704
+ saved: "已保存。名单修改对新建会话生效。",
1669
1705
  savedRefreshFailed: (message) => `已保存;阵容刷新失败:${message}。请刷新以读取最新设置。`,
1670
1706
  conflict: "阵容设置已在别处修改,当前输入保留。请刷新核对后重试。",
1671
1707
  tendencyFailed: (message) => `任务倾向不可用:${message}。原文件已保留;修复后刷新。`,
@@ -1697,12 +1733,12 @@ const TEXT$1 = {
1697
1733
  en: {
1698
1734
  title: "Subagent Cast",
1699
1735
  enabledLabel: "Enable subagent cast",
1700
- enabledHint: "When enabled, explicit model selection for a subagent must use this list; omitting a model still inherits the parent session. The main agent consults task tendencies when delegating.",
1736
+ enabledHint: "This list limits explicit subagent model choices; omitting a model can still inherit the parent session. List changes apply to new conversations. Existing conversations and their subagents keep their saved lists. Task tendencies guide delegation.",
1701
1737
  loading: "Loading…",
1702
1738
  failed: (message) => `Load failed: ${message}`,
1703
1739
  syncFailed: (message) => `Live sync unavailable: ${message}`,
1704
1740
  writeFailed: (message) => `Not saved: ${message}. Refresh, then try again.`,
1705
- saved: "Saved; refreshing…",
1741
+ saved: "Saved. List changes apply to new conversations.",
1706
1742
  savedRefreshFailed: (message) => `Saved; cast refresh failed: ${message}. Refresh to read the latest settings.`,
1707
1743
  conflict: "Cast settings changed elsewhere; your draft is preserved. Refresh, review, then try again.",
1708
1744
  tendencyFailed: (message) => `Task tendencies unavailable: ${message}. The original file is preserved; repair it, then refresh.`,
@@ -1991,7 +2027,7 @@ function CastPage({ api, locale }) {
1991
2027
  refresh: refreshNow
1992
2028
  };
1993
2029
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1994
- className: "cast-root dsh-ui-stack",
2030
+ className: "cast-root dsh-model-hub dsh-ui-stack",
1995
2031
  "aria-label": t("title"),
1996
2032
  "aria-busy": saving !== "" || refreshing,
1997
2033
  children: [
@@ -2421,7 +2457,7 @@ function HubPage({ view, api, locale, initialEntries = null, initialCatalog = nu
2421
2457
  refresh: refreshNow
2422
2458
  };
2423
2459
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2424
- className: "dsh-model-hub dsh-ui-stack",
2460
+ className: "dsh-model-hub dsh-ui-page",
2425
2461
  lang: t.language,
2426
2462
  "aria-label": t("title"),
2427
2463
  "aria-busy": writing !== "" || refreshing,