@deepseek-ai/dsh-client-ui-settings-plugins 0.1.6-alpha.2 → 0.1.7-alpha.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/lib/client.js CHANGED
@@ -7,333 +7,14 @@ window.__ModuleLoader__.load({
7
7
  let _deepseek_ai_dsh_client_ui_slots = require("@deepseek-ai/dsh-client-ui-slots");
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
9
  let react = require("react");
10
- let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
11
- let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
12
- //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-plugins/src/client/fields.module.css.mjs
13
- const css$5 = ".At1oFq_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.At1oFq_field+.At1oFq_field{border-top:.5px solid var(--dsw-alias-border-l2)}.At1oFq_head{align-items:center;gap:8px;display:flex}.At1oFq_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.At1oFq_labelGroup{flex:1;align-items:center;gap:4px;min-width:0;display:flex}.At1oFq_labelGroup>.At1oFq_label{flex:0 auto}.At1oFq_helpButton{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.At1oFq_helpButton:hover,.At1oFq_helpButton[aria-expanded=true]{background:var(--dsw-alias-bg-layer-4);color:var(--dsw-alias-label-secondary)}.At1oFq_helpButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.At1oFq_help{color:var(--dsw-alias-label-secondary);padding:10px 0 0;font-size:12px;line-height:1.6}.At1oFq_help>p{margin:0}.At1oFq_help>p+p{margin-top:8px}.At1oFq_badges{align-items:center;gap:8px;display:inline-flex}.At1oFq_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.At1oFq_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.At1oFq_reset:disabled{cursor:default}.At1oFq_input{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.At1oFq_input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.At1oFq_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.At1oFq_input[aria-invalid=true]{border-color:var(--dsw-alias-state-error-primary)}.At1oFq_invalid{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}.At1oFq_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}";
14
- const tagId$5 = "@deepseek-ai/dsh-client-ui-settings-plugins/fields.module.css";
15
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
16
- const tag = document.createElement("style");
17
- tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-plugins";
18
- tag.dataset.pluginCss = tagId$5;
19
- tag.textContent = css$5;
20
- document.head.appendChild(tag);
21
- }
22
- var fields_module_css_default = {
23
- "badges": "At1oFq_badges",
24
- "field": "At1oFq_field",
25
- "head": "At1oFq_head",
26
- "help": "At1oFq_help",
27
- "helpButton": "At1oFq_helpButton",
28
- "hint": "At1oFq_hint",
29
- "input": "At1oFq_input",
30
- "invalid": "At1oFq_invalid",
31
- "label": "At1oFq_label",
32
- "labelGroup": "At1oFq_labelGroup",
33
- "reset": "At1oFq_reset"
34
- };
35
- //#endregion
36
- //#region lib/types/client/fields.js
37
- /**
38
- * Hand-written controls for the plugin configuration forms. Each renders one
39
- * field's label, its staged text, whether saving would leave an override, and
40
- * — when one stands — the reset that stages a clear back to the composition
41
- * layer. Nothing here writes: a control reports what the user typed, and the
42
- * card's save is the single point where a draft becomes a document mutation.
43
- */
44
- /**
45
- * A staged value field. `numeric` only hints the keypad: which drafts a field
46
- * accepts is decided by its spec, so the control never silently rewrites what
47
- * the user typed.
48
- * @param props - the field's copy, its staged text, and the edit actions.
49
- * @returns the labelled control.
50
- */
51
- function ValueField(props) {
52
- const [helpOpen, setHelpOpen] = (0, react.useState)(false);
53
- const helpId = `${props.id}-help`;
54
- const messageId = `${props.id}-message`;
55
- const hasMessage = props.invalid || Boolean(props.hint);
56
- const description = [hasMessage ? messageId : "", helpOpen ? helpId : ""].filter(Boolean).join(" ");
57
- return (0, react_jsx_runtime.jsxs)("div", {
58
- className: fields_module_css_default.field,
59
- children: [
60
- (0, react_jsx_runtime.jsxs)("div", {
61
- className: fields_module_css_default.head,
62
- children: [(0, react_jsx_runtime.jsxs)("div", {
63
- className: fields_module_css_default.labelGroup,
64
- children: [(0, react_jsx_runtime.jsx)("label", {
65
- className: fields_module_css_default.label,
66
- htmlFor: props.id,
67
- children: props.label
68
- }), props.help !== void 0 ? (0, react_jsx_runtime.jsx)("button", {
69
- type: "button",
70
- className: fields_module_css_default.helpButton,
71
- "aria-label": props.help.label,
72
- "aria-expanded": helpOpen,
73
- "aria-controls": helpId,
74
- onClick: () => {
75
- setHelpOpen(!helpOpen);
76
- },
77
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconInfoOutline14, { size: 12 })
78
- }) : null]
79
- }), props.overridden ? (0, react_jsx_runtime.jsxs)("span", {
80
- className: fields_module_css_default.badges,
81
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
82
- tone: "neutral",
83
- children: props.overriddenLabel
84
- }), (0, react_jsx_runtime.jsx)("button", {
85
- type: "button",
86
- className: fields_module_css_default.reset,
87
- disabled: props.disabled,
88
- onClick: props.onReset,
89
- children: props.resetLabel
90
- })]
91
- }) : null]
92
- }),
93
- (0, react_jsx_runtime.jsx)("input", {
94
- id: props.id,
95
- className: fields_module_css_default.input,
96
- type: "text",
97
- ...props.numeric === true ? { inputMode: "numeric" } : {},
98
- ...props.invalid ? { "aria-invalid": true } : {},
99
- "aria-describedby": description || void 0,
100
- value: props.text,
101
- placeholder: props.placeholder ?? "",
102
- disabled: props.disabled,
103
- onChange: (event) => {
104
- props.onEdit(event.target.value);
105
- }
106
- }),
107
- hasMessage ? (0, react_jsx_runtime.jsx)("p", {
108
- id: messageId,
109
- className: props.invalid ? fields_module_css_default.invalid : fields_module_css_default.hint,
110
- children: props.invalid ? props.invalidLabel : props.hint
111
- }) : null,
112
- props.help !== void 0 && helpOpen ? (0, react_jsx_runtime.jsx)("div", {
113
- id: helpId,
114
- className: fields_module_css_default.help,
115
- role: "region",
116
- "aria-label": props.help.label,
117
- children: props.help.content
118
- }) : null
119
- ]
120
- });
121
- }
122
- /**
123
- * A write-only credential control. The value never rides a response, so the
124
- * control reports only whether one is configured and starts blank; a blank
125
- * draft writes nothing, which keeps the stored key rather than clearing it.
126
- * @param props - the field's copy, its staged text, and the configured state.
127
- * @returns the labelled control.
128
- */
129
- function SecretField(props) {
130
- return (0, react_jsx_runtime.jsxs)("div", {
131
- className: fields_module_css_default.field,
132
- children: [
133
- (0, react_jsx_runtime.jsxs)("div", {
134
- className: fields_module_css_default.head,
135
- children: [(0, react_jsx_runtime.jsx)("label", {
136
- className: fields_module_css_default.label,
137
- htmlFor: props.id,
138
- children: props.label
139
- }), (0, react_jsx_runtime.jsx)("span", {
140
- className: fields_module_css_default.badges,
141
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tag, {
142
- tone: props.configured ? "neutral" : "quiet",
143
- children: props.stateLabel
144
- })
145
- })]
146
- }),
147
- (0, react_jsx_runtime.jsx)("input", {
148
- id: props.id,
149
- className: fields_module_css_default.input,
150
- type: "password",
151
- autoComplete: "off",
152
- value: props.text,
153
- disabled: props.disabled,
154
- onChange: (event) => {
155
- props.onEdit(event.target.value);
156
- }
157
- }),
158
- (0, react_jsx_runtime.jsx)("p", {
159
- className: fields_module_css_default.hint,
160
- children: props.hint
161
- })
162
- ]
163
- });
164
- }
165
- //#endregion
166
- //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-plugins/src/client/PluginConfigForm.module.css.mjs
167
- const css$4 = ".KQZgIq_form{flex-direction:column;display:flex}.KQZgIq_readOnly,.KQZgIq_unavailable{color:var(--dsw-alias-label-tertiary);margin:0 0 12px;font-size:12px;line-height:1.5}.KQZgIq_footer{align-items:center;gap:8px;padding-top:16px;display:flex}.KQZgIq_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.KQZgIq_save{appearance:none;font:inherit;cursor:pointer;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.KQZgIq_save:disabled{opacity:.4;cursor:default}.KQZgIq_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
168
- const tagId$4 = "@deepseek-ai/dsh-client-ui-settings-plugins/PluginConfigForm.module.css";
169
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
170
- const tag = document.createElement("style");
171
- tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-plugins";
172
- tag.dataset.pluginCss = tagId$4;
173
- tag.textContent = css$4;
174
- document.head.appendChild(tag);
175
- }
176
- var PluginConfigForm_module_css_default = {
177
- "failed": "KQZgIq_failed",
178
- "footer": "KQZgIq_footer",
179
- "form": "KQZgIq_form",
180
- "readOnly": "KQZgIq_readOnly",
181
- "save": "KQZgIq_save",
182
- "unavailable": "KQZgIq_unavailable"
183
- };
184
- //#endregion
185
- //#region lib/types/client/PluginConfigForm.js
186
- /**
187
- * One plugin's configuration form as its page on the Plugins page shows it:
188
- * the read-only notice when the deployment stores settings read-only, the
189
- * plugin's controls, and the save that writes every staged edit. The page
190
- * draws the plugin's title and one-liner itself.
191
- *
192
- * Only a save writes. Leaving the page drops every staged edit, so the form
193
- * discards on unmount and offers no discard control. A form whose namespace
194
- * the Host stopped serving says so in place of its controls rather than
195
- * showing fields nothing would accept.
196
- */
197
- /**
198
- * Render one plugin's configuration form.
199
- * @param props - the form state, its controls, and the save and discard actions.
200
- * @returns the form, or the unavailable line while the namespace is not served.
201
- */
202
- function PluginConfigForm(props) {
203
- const { state } = props;
204
- const discard = (0, react.useRef)(props.onDiscard);
205
- discard.current = props.onDiscard;
206
- (0, react.useEffect)(() => () => {
207
- discard.current();
208
- }, []);
209
- if (!state.available) return (0, react_jsx_runtime.jsx)("p", {
210
- className: PluginConfigForm_module_css_default.unavailable,
211
- role: "status",
212
- children: props.t("unavailable")
213
- });
214
- const blocked = !state.dirty || state.invalid || state.saving;
215
- return (0, react_jsx_runtime.jsxs)("div", {
216
- className: PluginConfigForm_module_css_default.form,
217
- children: [
218
- !state.writable ? (0, react_jsx_runtime.jsx)("p", {
219
- className: PluginConfigForm_module_css_default.readOnly,
220
- role: "status",
221
- children: props.t("readOnly")
222
- }) : null,
223
- props.children,
224
- (0, react_jsx_runtime.jsxs)("div", {
225
- className: PluginConfigForm_module_css_default.footer,
226
- children: [state.failed ? (0, react_jsx_runtime.jsx)("p", {
227
- className: PluginConfigForm_module_css_default.failed,
228
- role: "status",
229
- children: props.t("saveFailed")
230
- }) : null, (0, react_jsx_runtime.jsx)("button", {
231
- type: "button",
232
- className: PluginConfigForm_module_css_default.save,
233
- disabled: blocked,
234
- onClick: props.onSave,
235
- children: props.t(state.saving ? "saving" : "save")
236
- })]
237
- })
238
- ]
239
- });
240
- }
241
- //#endregion
242
- //#region lib/types/client/AgentLoopCard.js
243
- /**
244
- * Render the agent loop's one-liner or its configuration form, as the Plugins page asks.
245
- * @param props - the view asked for, locale copy, the form snapshot, and its actions.
246
- * @returns the one-liner, or the form.
247
- */
248
- function AgentLoopCard(props) {
249
- const { t } = props;
250
- const state = props.useAgentLoopCard((snapshot) => snapshot);
251
- if (props.view === "summary") return t("agentLoopDescription");
252
- return (0, react_jsx_runtime.jsx)(PluginConfigForm, {
253
- t,
254
- state,
255
- onSave: props.save,
256
- onDiscard: props.discard,
257
- children: (0, react_jsx_runtime.jsx)(ValueField, {
258
- id: "plugin-config-agent-loop-parallel",
259
- label: t("agentLoopMaxParallel"),
260
- hint: t("agentLoopMaxParallelHint"),
261
- overriddenLabel: t("overridden"),
262
- resetLabel: t("reset"),
263
- invalidLabel: t("invalidNumber"),
264
- numeric: true,
265
- disabled: !state.writable,
266
- ...state.maxParallelToolCalls,
267
- onEdit: (text) => {
268
- props.edit("maxParallelToolCalls", text);
269
- },
270
- onReset: () => {
271
- props.resetField("maxParallelToolCalls");
272
- }
273
- })
274
- });
275
- }
276
- //#endregion
277
- //#region lib/types/client/BashCard.js
278
- /**
279
- * Render the shell plugin's one-liner or its configuration form, as the Plugins page asks.
280
- * @param props - the view asked for, locale copy, the form snapshot, and its actions.
281
- * @returns the one-liner, or the form.
282
- */
283
- function BashCard(props) {
284
- const { t } = props;
285
- const state = props.useBashCard((snapshot) => snapshot);
286
- if (props.view === "summary") return t("bashDescription");
287
- const disabled = !state.writable;
288
- return (0, react_jsx_runtime.jsxs)(PluginConfigForm, {
289
- t,
290
- state,
291
- onSave: props.save,
292
- onDiscard: props.discard,
293
- children: [(0, react_jsx_runtime.jsx)(ValueField, {
294
- id: "plugin-config-bash-timeout",
295
- label: t("bashTimeoutMs"),
296
- hint: t("bashTimeoutMsHint"),
297
- overriddenLabel: t("overridden"),
298
- resetLabel: t("reset"),
299
- invalidLabel: t("invalidNumber"),
300
- numeric: true,
301
- disabled,
302
- ...state.timeoutMs,
303
- onEdit: (text) => {
304
- props.edit("timeoutMs", text);
305
- },
306
- onReset: () => {
307
- props.resetField("timeoutMs");
308
- }
309
- }), (0, react_jsx_runtime.jsx)(ValueField, {
310
- id: "plugin-config-bash-output",
311
- label: t("bashMaxOutputBytes"),
312
- hint: t("bashMaxOutputBytesHint"),
313
- overriddenLabel: t("overridden"),
314
- resetLabel: t("reset"),
315
- invalidLabel: t("invalidNumber"),
316
- numeric: true,
317
- disabled,
318
- ...state.maxOutputBytes,
319
- onEdit: (text) => {
320
- props.edit("maxOutputBytes", text);
321
- },
322
- onReset: () => {
323
- props.resetField("maxOutputBytes");
324
- }
325
- })]
326
- });
327
- }
328
- //#endregion
329
10
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-plugins/src/client/PluginsSettingsSection.module.css.mjs
330
- const css$3 = ".pbvGtq_section{max-width:760px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.pbvGtq_heading{margin:0;font-size:18px;font-weight:600}.pbvGtq_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px}.pbvGtq_tabs{border-bottom:.5px solid var(--dsw-alias-border-l2);align-items:flex-end;gap:22px;margin-top:2px;display:flex}.pbvGtq_tab{color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:0;padding:7px 1px 9px;font-size:13px;line-height:20px;position:relative}.pbvGtq_tab:hover,.pbvGtq_tab[data-active=true]{color:var(--dsw-alias-label-primary)}.pbvGtq_tab[data-active=true]:after,.pbvGtq_tab:focus-visible:after{background:var(--dsw-alias-label-primary);content:\"\";border-radius:2px 2px 0 0;height:2px;position:absolute;bottom:-1px;left:0;right:0}.pbvGtq_tab:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px;color:var(--dsw-alias-label-primary);border-radius:2px}.pbvGtq_panel{min-width:0;padding-top:2px}.pbvGtq_cards{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}.pbvGtq_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px}.pbvGtq_configurable{flex-direction:column;gap:10px;display:flex}.pbvGtq_presetSettings{flex-direction:column;gap:8px;display:flex}.pbvGtq_presetSettingsTitle{margin:0;font-size:15px;font-weight:600;line-height:22px}";
331
- const tagId$3 = "@deepseek-ai/dsh-client-ui-settings-plugins/PluginsSettingsSection.module.css";
332
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
11
+ const css = ".pbvGtq_section{max-width:760px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.pbvGtq_heading{margin:0;font-size:18px;font-weight:600}.pbvGtq_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px}.pbvGtq_tabs{border-bottom:.5px solid var(--dsw-alias-border-l2);align-items:flex-end;gap:22px;margin-top:2px;display:flex}.pbvGtq_tab{color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:0;padding:7px 1px 9px;font-size:13px;line-height:20px;position:relative}.pbvGtq_tab:hover,.pbvGtq_tab[data-active=true]{color:var(--dsw-alias-label-primary)}.pbvGtq_tab[data-active=true]:after,.pbvGtq_tab:focus-visible:after{background:var(--dsw-alias-label-primary);content:\"\";border-radius:2px 2px 0 0;height:2px;position:absolute;bottom:-1px;left:0;right:0}.pbvGtq_tab:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px;color:var(--dsw-alias-label-primary);border-radius:2px}.pbvGtq_panel{min-width:0;padding-top:2px}.pbvGtq_cards{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}.pbvGtq_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px}.pbvGtq_configurable{flex-direction:column;gap:10px;display:flex}.pbvGtq_presetSettings{flex-direction:column;gap:8px;display:flex}.pbvGtq_presetSettingsTitle{margin:0;font-size:15px;font-weight:600;line-height:22px}";
12
+ const tagId = "@deepseek-ai/dsh-client-ui-settings-plugins/PluginsSettingsSection.module.css";
13
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
333
14
  const tag = document.createElement("style");
334
15
  tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-plugins";
335
- tag.dataset.pluginCss = tagId$3;
336
- tag.textContent = css$3;
16
+ tag.dataset.pluginCss = tagId;
17
+ tag.textContent = css;
337
18
  document.head.appendChild(tag);
338
19
  }
339
20
  var PluginsSettingsSection_module_css_default = {
@@ -447,1288 +128,15 @@ window.__ModuleLoader__.load({
447
128
  });
448
129
  }
449
130
  //#endregion
450
- //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-plugins/src/client/SubagentLimitsFields.module.css.mjs
451
- const css$2 = ".uedTFq_limits{grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:16px;display:grid}.uedTFq_limit{min-width:0}.uedTFq_limit input{font-variant-numeric:tabular-nums;min-width:0}.uedTFq_depthTable{border-collapse:collapse;border-block:.5px solid var(--dsw-alias-border-l2);width:100%;font:inherit;text-align:left;margin:8px 0}.uedTFq_depthTable th,.uedTFq_depthTable td{vertical-align:top;padding:6px 0}.uedTFq_depthTable th{font-variant-numeric:tabular-nums;width:24px;color:var(--dsw-alias-label-primary);padding-right:8px;font-weight:500}.uedTFq_depthTable tr+tr{border-top:.5px solid var(--dsw-alias-border-l2)}";
452
- const tagId$2 = "@deepseek-ai/dsh-client-ui-settings-plugins/SubagentLimitsFields.module.css";
453
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
454
- const tag = document.createElement("style");
455
- tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-plugins";
456
- tag.dataset.pluginCss = tagId$2;
457
- tag.textContent = css$2;
458
- document.head.appendChild(tag);
459
- }
460
- var SubagentLimitsFields_module_css_default = {
461
- "depthTable": "uedTFq_depthTable",
462
- "limit": "uedTFq_limit",
463
- "limits": "uedTFq_limits"
464
- };
465
- //#endregion
466
- //#region lib/types/client/SubagentLimitsFields.js
467
- /**
468
- * Render the depth and capacity fields with their original validation and reset behavior.
469
- * @param props - Locale, staged fields, and edit callbacks.
470
- * @returns Two responsive fields and their application rules.
471
- */
472
- function SubagentLimitsFields(props) {
473
- const { t, state } = props;
474
- return (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: (0, react_jsx_runtime.jsxs)("div", {
475
- className: SubagentLimitsFields_module_css_default.limits,
476
- children: [(0, react_jsx_runtime.jsx)("div", {
477
- className: SubagentLimitsFields_module_css_default.limit,
478
- children: (0, react_jsx_runtime.jsx)(ValueField, {
479
- id: "plugin-config-subagent-depth",
480
- label: t("subagentMaxDepth"),
481
- help: {
482
- label: t("subagentDepthHelpLabel"),
483
- content: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
484
- (0, react_jsx_runtime.jsx)("p", { children: t("subagentDepthHelp") }),
485
- (0, react_jsx_runtime.jsx)("table", {
486
- className: SubagentLimitsFields_module_css_default.depthTable,
487
- "aria-label": t("subagentDepthHelpLabel"),
488
- children: (0, react_jsx_runtime.jsxs)("tbody", { children: [(0, react_jsx_runtime.jsxs)("tr", { children: [(0, react_jsx_runtime.jsx)("th", {
489
- scope: "row",
490
- children: 0
491
- }), (0, react_jsx_runtime.jsx)("td", { children: t("subagentDepthZero") })] }), (0, react_jsx_runtime.jsxs)("tr", { children: [(0, react_jsx_runtime.jsx)("th", {
492
- scope: "row",
493
- children: 1
494
- }), (0, react_jsx_runtime.jsx)("td", { children: t("subagentDepthOne") })] })] })
495
- }),
496
- (0, react_jsx_runtime.jsx)("p", { children: t("subagentDepthOverride") })
497
- ] })
498
- },
499
- overriddenLabel: t("overridden"),
500
- resetLabel: t("reset"),
501
- invalidLabel: t("subagentDepthInvalid"),
502
- numeric: true,
503
- disabled: !state.writable || state.saving,
504
- ...state.maxDepth,
505
- onEdit: (text) => {
506
- props.edit("maxDepth", text);
507
- },
508
- onReset: () => {
509
- props.resetField("maxDepth");
510
- }
511
- })
512
- }), (0, react_jsx_runtime.jsx)("div", {
513
- className: SubagentLimitsFields_module_css_default.limit,
514
- children: (0, react_jsx_runtime.jsx)(ValueField, {
515
- id: "plugin-config-subagent-capacity",
516
- label: t("subagentMaxActive"),
517
- help: {
518
- label: t("subagentCapacityHelpLabel"),
519
- content: (0, react_jsx_runtime.jsx)("p", { children: t("subagentCapacityHelp") })
520
- },
521
- overriddenLabel: t("overridden"),
522
- resetLabel: t("reset"),
523
- invalidLabel: t("subagentCapacityInvalid"),
524
- numeric: true,
525
- disabled: !state.writable || state.saving,
526
- ...state.maxActiveSubagents,
527
- onEdit: (text) => {
528
- props.edit("maxActiveSubagents", text);
529
- },
530
- onReset: () => {
531
- props.resetField("maxActiveSubagents");
532
- }
533
- })
534
- })]
535
- }) });
536
- }
537
- //#endregion
538
- //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-plugins/src/client/SubagentModelSelectionFields.module.css.mjs
539
- const css$1 = "._2QGtya_permission{gap:6px;padding:12px 0;display:grid}._2QGtya_toggleRow{color:var(--dsw-alias-label-primary);justify-content:space-between;align-items:flex-start;gap:16px;font-size:13px;line-height:1.5;display:flex}._2QGtya_toggleLabel{flex:1;min-width:0}._2QGtya_selection{gap:10px;display:grid}._2QGtya_hint,._2QGtya_notice,._2QGtya_invalid,._2QGtya_conflict{margin:0;font-size:12px;line-height:1.5}._2QGtya_hint,._2QGtya_notice{color:var(--dsw-alias-label-tertiary)}._2QGtya_invalid,._2QGtya_conflict{color:var(--dsw-alias-state-error-primary)}._2QGtya_catalogError{color:var(--dsw-alias-state-error-primary);justify-content:space-between;align-items:center;gap:12px;font-size:12px;display:flex}._2QGtya_catalogError button{color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border:0;padding:0}._2QGtya_models{border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}._2QGtya_models legend{color:var(--dsw-alias-label-secondary);padding:0 4px;font-size:12px}._2QGtya_modelGroup{gap:6px;display:grid}._2QGtya_modelGroup+._2QGtya_modelGroup{border-top:.5px solid var(--dsw-alias-border-l3);margin-top:4px;padding-top:10px}._2QGtya_providerName{color:var(--dsw-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}._2QGtya_model{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-width:0;padding:6px;display:grid}._2QGtya_model:hover{background:var(--dsw-alias-bg-layer-4)}._2QGtya_modelName,._2QGtya_route{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}._2QGtya_modelName{color:var(--dsw-alias-label-primary);font-size:13px}._2QGtya_route{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:11px}._2QGtya_unavailable{color:var(--dsw-alias-label-tertiary);font-size:11px}";
540
- const tagId$1 = "@deepseek-ai/dsh-client-ui-settings-plugins/SubagentModelSelectionFields.module.css";
541
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
542
- const tag = document.createElement("style");
543
- tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-plugins";
544
- tag.dataset.pluginCss = tagId$1;
545
- tag.textContent = css$1;
546
- document.head.appendChild(tag);
547
- }
548
- var SubagentModelSelectionFields_module_css_default = {
549
- "catalogError": "_2QGtya_catalogError",
550
- "conflict": "_2QGtya_conflict",
551
- "hint": "_2QGtya_hint",
552
- "invalid": "_2QGtya_invalid",
553
- "model": "_2QGtya_model",
554
- "modelGroup": "_2QGtya_modelGroup",
555
- "modelName": "_2QGtya_modelName",
556
- "models": "_2QGtya_models",
557
- "notice": "_2QGtya_notice",
558
- "permission": "_2QGtya_permission",
559
- "providerName": "_2QGtya_providerName",
560
- "route": "_2QGtya_route",
561
- "selection": "_2QGtya_selection",
562
- "toggleLabel": "_2QGtya_toggleLabel",
563
- "toggleRow": "_2QGtya_toggleRow",
564
- "unavailable": "_2QGtya_unavailable"
565
- };
566
- //#endregion
567
- //#region lib/types/client/SubagentModelSelectionFields.js
568
- /** User control for model-selectable subagent delegation in new sessions. */
569
- /**
570
- * Render the default-off preference and its exact adapter-route choices.
571
- * @param props - locale copy, the card snapshot, and its toggle action.
572
- * @returns the model permission and route choices inside the shared card.
573
- */
574
- function SubagentModelSelectionFields(props) {
575
- const { t, state } = props;
576
- const availableGroups = /* @__PURE__ */ new Map();
577
- const unavailable = [];
578
- for (const candidate of state.candidates) {
579
- if (!candidate.available) {
580
- unavailable.push(candidate);
581
- continue;
582
- }
583
- const group = availableGroups.get(candidate.provider);
584
- if (group === void 0) availableGroups.set(candidate.provider, {
585
- providerName: candidate.providerName,
586
- candidates: [candidate]
587
- });
588
- else group.candidates.push(candidate);
589
- }
590
- const renderCandidate = (candidate) => (0, react_jsx_runtime.jsxs)("label", {
591
- className: SubagentModelSelectionFields_module_css_default.model,
592
- children: [
593
- (0, react_jsx_runtime.jsx)("input", {
594
- type: "checkbox",
595
- checked: candidate.selected,
596
- disabled: !state.writable || state.saving,
597
- onChange: () => {
598
- props.toggleModel(candidate.key);
599
- }
600
- }),
601
- (0, react_jsx_runtime.jsxs)("span", { children: [(0, react_jsx_runtime.jsx)("span", {
602
- className: SubagentModelSelectionFields_module_css_default.modelName,
603
- children: candidate.modelName
604
- }), (0, react_jsx_runtime.jsx)("span", {
605
- className: SubagentModelSelectionFields_module_css_default.route,
606
- children: `${candidate.providerName} · ${candidate.provider}/${candidate.model}`
607
- })] }),
608
- !candidate.available ? (0, react_jsx_runtime.jsx)("span", {
609
- className: SubagentModelSelectionFields_module_css_default.unavailable,
610
- children: t("subagentModelSelectionUnavailable")
611
- }) : null
612
- ]
613
- }, candidate.key);
614
- return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
615
- (0, react_jsx_runtime.jsxs)("div", {
616
- className: SubagentModelSelectionFields_module_css_default.permission,
617
- children: [(0, react_jsx_runtime.jsxs)("div", {
618
- className: SubagentModelSelectionFields_module_css_default.toggleRow,
619
- children: [(0, react_jsx_runtime.jsx)("span", {
620
- className: SubagentModelSelectionFields_module_css_default.toggleLabel,
621
- children: t("subagentModelSelectionToggle")
622
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
623
- checked: state.enabled,
624
- label: t("subagentModelSelectionToggle"),
625
- disabled: !state.writable || state.saving,
626
- onChange: props.toggleEnabled
627
- })]
628
- }), (0, react_jsx_runtime.jsx)("p", {
629
- className: SubagentModelSelectionFields_module_css_default.hint,
630
- children: t(state.enabled ? "subagentModelSelectionChoose" : "subagentModelSelectionOff")
631
- })]
632
- }),
633
- state.enabled ? (0, react_jsx_runtime.jsxs)("div", {
634
- className: SubagentModelSelectionFields_module_css_default.selection,
635
- children: [
636
- state.catalogStatus === "loading" ? (0, react_jsx_runtime.jsx)("p", {
637
- className: SubagentModelSelectionFields_module_css_default.notice,
638
- role: "status",
639
- children: t("subagentModelSelectionLoading")
640
- }) : null,
641
- state.catalogStatus === "error" ? (0, react_jsx_runtime.jsxs)("div", {
642
- className: SubagentModelSelectionFields_module_css_default.catalogError,
643
- role: "alert",
644
- children: [(0, react_jsx_runtime.jsx)("span", { children: t("subagentModelSelectionLoadFailed") }), (0, react_jsx_runtime.jsx)("button", {
645
- type: "button",
646
- disabled: state.saving,
647
- onClick: props.retryCatalog,
648
- children: t("subagentModelSelectionRetry")
649
- })]
650
- }) : null,
651
- state.catalogPartial ? (0, react_jsx_runtime.jsx)("p", {
652
- className: SubagentModelSelectionFields_module_css_default.notice,
653
- children: t("subagentModelSelectionPartial")
654
- }) : null,
655
- state.candidates.length > 0 ? (0, react_jsx_runtime.jsxs)("fieldset", {
656
- className: SubagentModelSelectionFields_module_css_default.models,
657
- children: [
658
- (0, react_jsx_runtime.jsx)("legend", { children: t("subagentModelSelectionAllowed") }),
659
- [...availableGroups].map(([provider, group]) => (0, react_jsx_runtime.jsxs)("div", {
660
- className: SubagentModelSelectionFields_module_css_default.modelGroup,
661
- children: [(0, react_jsx_runtime.jsx)("div", {
662
- className: SubagentModelSelectionFields_module_css_default.providerName,
663
- children: group.providerName
664
- }), group.candidates.map(renderCandidate)]
665
- }, provider)),
666
- unavailable.length > 0 ? (0, react_jsx_runtime.jsxs)("div", {
667
- className: SubagentModelSelectionFields_module_css_default.modelGroup,
668
- children: [(0, react_jsx_runtime.jsx)("div", {
669
- className: SubagentModelSelectionFields_module_css_default.providerName,
670
- children: t("subagentModelSelectionUnavailableGroup")
671
- }), unavailable.map(renderCandidate)]
672
- }) : null
673
- ]
674
- }) : state.catalogStatus === "ready" ? (0, react_jsx_runtime.jsx)("p", {
675
- className: SubagentModelSelectionFields_module_css_default.notice,
676
- children: t("subagentModelSelectionEmpty")
677
- }) : null,
678
- state.invalid ? (0, react_jsx_runtime.jsx)("p", {
679
- className: SubagentModelSelectionFields_module_css_default.invalid,
680
- children: t("subagentModelSelectionRequired")
681
- }) : null
682
- ]
683
- }) : null,
684
- state.conflicted ? (0, react_jsx_runtime.jsx)("p", {
685
- className: SubagentModelSelectionFields_module_css_default.conflict,
686
- role: "status",
687
- children: t("subagentModelSelectionConflict")
688
- }) : null
689
- ] });
690
- }
691
- //#endregion
692
- //#region lib/types/client/subagent-card-controller.js
693
- /** Shared presentation and actions for the two Host-owned Subagent settings sections. */
694
- /**
695
- * Derive the shared card state without duplicating either form's subscriptions.
696
- * @param limits - Current delegation-limit form.
697
- * @param models - Current model-authorization form.
698
- * @returns Availability and settlement across the sections this Host serves.
699
- */
700
- function subagentCardShell(limits, models) {
701
- const sections = [limits, models].filter((section) => section.available);
702
- return {
703
- available: sections.length > 0,
704
- writable: sections.every((section) => section.writable),
705
- dirty: sections.some((section) => section.dirty),
706
- invalid: sections.some((section) => section.invalid) || models.available && models.dirty && models.conflicted,
707
- saving: sections.some((section) => section.saving),
708
- failed: sections.some((section) => section.failed)
709
- };
710
- }
711
- /**
712
- * Compose one card from the existing forms; each write retains its namespace revision fence.
713
- * @param limits - Limit form source and actions.
714
- * @param models - Model form source and actions.
715
- * @returns Framework-bound sources and shared save/discard actions.
716
- */
717
- function subagentCardFace(limits, models) {
718
- return {
719
- hooks: {
720
- ...limits.hooks,
721
- ...models.hooks
722
- },
723
- editLimit: limits.edit,
724
- resetLimit: limits.resetField,
725
- toggleEnabled: models.toggleEnabled,
726
- toggleModel: models.toggleModel,
727
- retryCatalog: models.retryCatalog,
728
- save: () => {
729
- const limitState = limits.hooks.subagentLimitsCard.getSnapshot();
730
- const modelState = models.hooks.subagentModelSelectionCard.getSnapshot();
731
- const state = subagentCardShell(limitState, modelState);
732
- if (!state.available || !state.writable || !state.dirty || state.invalid || state.saving) return;
733
- if (modelState.available && modelState.dirty) models.save();
734
- if (limitState.available && limitState.dirty) limits.save();
735
- },
736
- discard: () => {
737
- if (subagentCardShell(limits.hooks.subagentLimitsCard.getSnapshot(), models.hooks.subagentModelSelectionCard.getSnapshot()).saving) return;
738
- limits.discard();
739
- models.discard();
740
- }
741
- };
742
- }
743
- //#endregion
744
- //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-plugins/src/client/SubagentCard.module.css.mjs
745
- const css = ".UYsYFG_section{min-width:0;padding:16px 0}.UYsYFG_heading{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:1.5}";
746
- const tagId = "@deepseek-ai/dsh-client-ui-settings-plugins/SubagentCard.module.css";
747
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
748
- const tag = document.createElement("style");
749
- tag.dataset.plugin = "@deepseek-ai/dsh-client-ui-settings-plugins";
750
- tag.dataset.pluginCss = tagId;
751
- tag.textContent = css;
752
- document.head.appendChild(tag);
753
- }
754
- var SubagentCard_module_css_default = {
755
- "heading": "UYsYFG_heading",
756
- "section": "UYsYFG_section"
757
- };
758
- //#endregion
759
- //#region lib/types/client/SubagentCard.js
760
- /** One settings card for Subagent delegation limits and model authorization. */
761
- /**
762
- * Render the available Subagent settings with one configuration page and save footer.
763
- * @param props - Locale, both form snapshots, and their shared actions.
764
- * @returns The summary or the available settings form.
765
- */
766
- function SubagentCard(props) {
767
- const { t } = props;
768
- const limits = props.useSubagentLimitsCard((snapshot) => snapshot);
769
- const models = props.useSubagentModelSelectionCard((snapshot) => snapshot);
770
- const headingId = (0, react.useId)();
771
- if (props.view === "summary") return t("subagentDescription");
772
- const state = subagentCardShell(limits, models);
773
- return (0, react_jsx_runtime.jsxs)(PluginConfigForm, {
774
- t,
775
- state,
776
- onSave: props.save,
777
- onDiscard: props.discard,
778
- children: [limits.available ? (0, react_jsx_runtime.jsxs)("section", {
779
- className: SubagentCard_module_css_default.section,
780
- "aria-labelledby": `${headingId}-limits`,
781
- children: [(0, react_jsx_runtime.jsx)("h3", {
782
- className: SubagentCard_module_css_default.heading,
783
- id: `${headingId}-limits`,
784
- children: t("subagentLimitsTitle")
785
- }), (0, react_jsx_runtime.jsx)(SubagentLimitsFields, {
786
- t,
787
- state: {
788
- ...limits,
789
- saving: state.saving
790
- },
791
- edit: props.editLimit,
792
- resetField: props.resetLimit
793
- })]
794
- }) : null, models.available ? (0, react_jsx_runtime.jsxs)("section", {
795
- className: SubagentCard_module_css_default.section,
796
- "aria-labelledby": `${headingId}-models`,
797
- children: [(0, react_jsx_runtime.jsx)("h3", {
798
- className: SubagentCard_module_css_default.heading,
799
- id: `${headingId}-models`,
800
- children: t("subagentModelSelectionTitle")
801
- }), (0, react_jsx_runtime.jsx)(SubagentModelSelectionFields, {
802
- t,
803
- state: {
804
- ...models,
805
- saving: state.saving
806
- },
807
- toggleEnabled: props.toggleEnabled,
808
- toggleModel: props.toggleModel,
809
- retryCatalog: props.retryCatalog
810
- })]
811
- }) : null]
812
- });
813
- }
814
- //#endregion
815
- //#region lib/types/client/card-form.js
816
- /**
817
- * Shared form model behind every plugin card.
818
- *
819
- * A card stages what the user types and writes it only when they save. Each
820
- * settings write is a durable, revision-fenced document mutation, so a control
821
- * that committed as it settled turned one edit into a write the user never
822
- * asked for and could not preview; staged text makes what is on screen exactly
823
- * what a save would store.
824
- *
825
- * A field shows its effective value — the user layer over the composition
826
- * layer over the schema default — and whether the user layer carries it. That
827
- * presence, not a value comparison, is what marks a field overridden: an
828
- * override equal to the composition default is still an override.
829
- */
830
- /**
831
- * A whole-number field. An empty draft clears the field; any other draft that
832
- * is not a finite number blocks the save.
833
- * @param field - field name inside the namespace section.
834
- * @returns the field's conversion spec.
835
- */
836
- function numberField(field) {
837
- return {
838
- field,
839
- format: (value) => typeof value === "number" ? String(value) : "",
840
- parse: (text) => {
841
- const trimmed = text.trim();
842
- if (trimmed === "") return { kind: "clear" };
843
- const parsed = Number(trimmed);
844
- return Number.isFinite(parsed) ? {
845
- kind: "set",
846
- value: parsed
847
- } : void 0;
848
- }
849
- };
850
- }
851
- /**
852
- * A free-text field. An empty draft clears the field, so emptying the control
853
- * and saving is the same gesture as resetting it.
854
- * @param field - field name inside the namespace section.
855
- * @returns the field's conversion spec.
856
- */
857
- function textField(field) {
858
- return {
859
- field,
860
- format: (value) => typeof value === "string" ? value : "",
861
- parse: (text) => {
862
- const trimmed = text.trim();
863
- return trimmed === "" ? { kind: "clear" } : {
864
- kind: "set",
865
- value: trimmed
866
- };
867
- }
868
- };
869
- }
870
- /**
871
- * Stages one card's edits over one settings namespace and writes them on save.
872
- *
873
- * The form publishes through a snapshot store because slot components read
874
- * through a snapshot selector, while both the scope and the local drafts
875
- * change underneath; every projection is rebuilt from the two together.
876
- */
877
- var CardForm = class {
878
- scope;
879
- specs;
880
- secretSpecs;
881
- staged = /* @__PURE__ */ new Map();
882
- listeners = /* @__PURE__ */ new Set();
883
- saving = false;
884
- failed = false;
885
- /**
886
- * @param scope - the bound settings scope for this card's namespace.
887
- * @param specs - the section fields this card edits.
888
- * @param secrets - the card's write-only controls, written outside the section.
889
- */
890
- constructor(scope, specs, secrets = []) {
891
- this.scope = scope;
892
- this.specs = new Map(specs.map((spec) => [spec.field, spec]));
893
- this.secretSpecs = new Map(secrets.map((spec) => [spec.field, spec]));
894
- scope.subscribe(() => {
895
- this.publish();
896
- });
897
- }
898
- /**
899
- * Publish a projection of this form, rebuilt whenever the scope or a draft changes.
900
- * @param project - build the card's state from the form's current reads.
901
- * @returns the store the card's component reads through its bound selector.
902
- */
903
- bind(project) {
904
- const store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(project());
905
- this.listeners.add(() => {
906
- store.set(project());
907
- });
908
- return store;
909
- }
910
- /**
911
- * Read the card-level state: what the Host serves, and what a save would do.
912
- * @returns the form state every card shares.
913
- */
914
- shell() {
915
- const snapshot = this.scope.getSnapshot();
916
- const plan = this.plan();
917
- return {
918
- available: snapshot.status === "ready",
919
- writable: snapshot.writable,
920
- dirty: plan.length > 0,
921
- invalid: plan.some((item) => item.run === void 0),
922
- saving: this.saving,
923
- failed: this.failed
924
- };
925
- }
926
- /**
927
- * Read one control's state.
928
- * @param field - field name of a section field or of a write-only control.
929
- * @returns the draft text, whether a save would leave an override, and whether it is invalid.
930
- */
931
- field(field) {
932
- const staged = this.staged.get(field);
933
- if (this.secretSpecs.has(field)) return {
934
- text: staged?.text ?? "",
935
- overridden: false,
936
- invalid: false
937
- };
938
- const spec = this.spec(field);
939
- if (staged === void 0) return {
940
- text: spec.format(this.sectionValue(field)),
941
- overridden: this.stored(field),
942
- invalid: false
943
- };
944
- const write = staged.clear ? { kind: "clear" } : spec.parse(staged.text);
945
- return {
946
- text: staged.text,
947
- overridden: write?.kind === "set",
948
- invalid: write === void 0
949
- };
950
- }
951
- /**
952
- * Build the edit, reset, save, and discard actions bound to this form.
953
- * @returns the actions a card's slot entry injects.
954
- */
955
- actions() {
956
- return {
957
- edit: (field, text) => {
958
- this.stage(field, {
959
- text,
960
- clear: false
961
- });
962
- },
963
- resetField: (field) => {
964
- this.stage(field, {
965
- text: this.spec(field).format(this.baseValue(field)),
966
- clear: true
967
- });
968
- },
969
- save: () => {
970
- this.save();
971
- },
972
- discard: () => {
973
- if (this.staged.size === 0 && !this.failed) return;
974
- this.staged.clear();
975
- this.failed = false;
976
- this.publish();
977
- }
978
- };
979
- }
980
- /**
981
- * Write every staged edit, then re-seed from what the Host accepted.
982
- *
983
- * The Host is the only authority on whether a value was accepted — its
984
- * validators own the constraints no schema can express — so the outcome is
985
- * read back from the section rather than predicted here. A save that did not
986
- * land keeps its drafts, so the user can correct them instead of retyping.
987
- * @returns settlement after every write and the read-back.
988
- */
989
- async save() {
990
- const plan = this.plan();
991
- const writes = plan.flatMap((item) => item.run === void 0 ? [] : [item.run]);
992
- if (plan.length === 0 || this.saving || writes.length !== plan.length) return;
993
- this.saving = true;
994
- this.failed = false;
995
- this.publish();
996
- let landed = true;
997
- for (const write of writes) landed = await write() && landed;
998
- if (landed) this.staged.clear();
999
- this.saving = false;
1000
- this.failed = !landed;
1001
- this.publish();
1002
- }
1003
- /**
1004
- * Every staged edit a save would write. An entry whose draft is not a value
1005
- * its field accepts carries no write: the form is still dirty, and the save
1006
- * refuses rather than dropping the edit.
1007
- * @returns the planned writes, in the order the fields were staged.
1008
- */
1009
- plan() {
1010
- const plan = [];
1011
- for (const [field, staged] of this.staged) {
1012
- const secret = this.secretSpecs.get(field);
1013
- if (secret !== void 0) {
1014
- const value = staged.text.trim();
1015
- if (value !== "") plan.push({
1016
- field,
1017
- run: () => secret.write(value)
1018
- });
1019
- continue;
1020
- }
1021
- const spec = this.spec(field);
1022
- if (staged.clear) {
1023
- if (this.stored(field)) plan.push({
1024
- field,
1025
- run: () => this.clear(field)
1026
- });
1027
- continue;
1028
- }
1029
- if (staged.text === spec.format(this.sectionValue(field))) continue;
1030
- const write = spec.parse(staged.text);
1031
- if (write === void 0) plan.push({
1032
- field,
1033
- run: void 0
1034
- });
1035
- else if (write.kind === "clear") plan.push({
1036
- field,
1037
- run: () => this.clear(field)
1038
- });
1039
- else plan.push({
1040
- field,
1041
- run: () => this.store(field, write.value)
1042
- });
1043
- }
1044
- return plan;
1045
- }
1046
- async clear(field) {
1047
- await this.scope.unset(field);
1048
- return !this.stored(field);
1049
- }
1050
- async store(field, value) {
1051
- await this.scope.set(field, value);
1052
- return this.userLayer()?.[field] === value;
1053
- }
1054
- stage(field, edit) {
1055
- this.staged.set(field, edit);
1056
- this.failed = false;
1057
- this.publish();
1058
- }
1059
- spec(field) {
1060
- const spec = this.specs.get(field);
1061
- if (spec === void 0) throw new Error(`plugin card has no field ${field}`);
1062
- return spec;
1063
- }
1064
- snapshotOf() {
1065
- return this.scope.getSnapshot();
1066
- }
1067
- sectionValue(field) {
1068
- return this.snapshotOf().value?.[field];
1069
- }
1070
- baseValue(field) {
1071
- return this.snapshotOf().base?.[field];
1072
- }
1073
- userLayer() {
1074
- return this.snapshotOf().user;
1075
- }
1076
- stored(field) {
1077
- const user = this.userLayer();
1078
- return user !== void 0 && Object.hasOwn(user, field);
1079
- }
1080
- publish() {
1081
- for (const listener of this.listeners) listener();
1082
- }
1083
- };
1084
- //#endregion
1085
- //#region lib/types/client/subagent-limits-card-controller.js
1086
- /** Staged delegation limits backed by the Host's subagent settings section. */
1087
- function limitField(field, minimum) {
1088
- const numeric = numberField(field);
1089
- return {
1090
- ...numeric,
1091
- parse: (text) => {
1092
- const write = numeric.parse(text);
1093
- if (write?.kind !== "set") return write;
1094
- const value = write.value;
1095
- return Number.isSafeInteger(value) && value >= minimum && !Object.is(value, -0) ? write : void 0;
1096
- }
1097
- };
1098
- }
1099
- /** Bind two independently resettable limits to one staged settings form. */
1100
- var SubagentLimitsCardController = class {
1101
- form;
1102
- store;
1103
- /** @param scope - The Host's `subagent` settings section. */
1104
- constructor(scope) {
1105
- this.form = new CardForm(scope, [limitField("maxDepth", 0), limitField("maxActiveSubagents", 1)]);
1106
- this.store = this.form.bind(() => ({
1107
- ...this.form.shell(),
1108
- maxDepth: this.form.field("maxDepth"),
1109
- maxActiveSubagents: this.form.field("maxActiveSubagents")
1110
- }));
1111
- }
1112
- /**
1113
- * Bind the limits editor to the slot renderer.
1114
- * @returns The limits snapshot and staged write actions.
1115
- */
1116
- inject() {
1117
- return {
1118
- hooks: { subagentLimitsCard: this.store },
1119
- ...this.form.actions()
1120
- };
1121
- }
1122
- };
1123
- //#endregion
1124
- //#region lib/types/client/WebSearchCard.js
1125
- /**
1126
- * Render the web-search provider's one-liner or its configuration form, as the Plugins page asks.
1127
- * @param props - the view asked for, locale copy, the form snapshot, and its actions.
1128
- * @returns the one-liner, or the form.
1129
- */
1130
- function WebSearchCard(props) {
1131
- const { t } = props;
1132
- const state = props.useWebSearchCard((snapshot) => snapshot);
1133
- if (props.view === "summary") return t("webSearchDescription");
1134
- const disabled = !state.writable;
1135
- return (0, react_jsx_runtime.jsxs)(PluginConfigForm, {
1136
- t,
1137
- state,
1138
- onSave: props.save,
1139
- onDiscard: props.discard,
1140
- children: [
1141
- (0, react_jsx_runtime.jsx)(SecretField, {
1142
- id: "plugin-config-web-search-key",
1143
- label: t("webSearchApiKey"),
1144
- hint: t("webSearchApiKeyHint"),
1145
- disabled: !state.apiKeyWritable,
1146
- text: state.apiKey.text,
1147
- configured: state.apiKeyConfigured,
1148
- stateLabel: state.apiKeyConfigured ? t("webSearchApiKeySet") : t("webSearchApiKeyUnset"),
1149
- onEdit: (text) => {
1150
- props.edit("apiKey", text);
1151
- }
1152
- }),
1153
- (0, react_jsx_runtime.jsx)(ValueField, {
1154
- id: "plugin-config-web-search-endpoint",
1155
- label: t("webSearchBaseUrl"),
1156
- hint: t("webSearchBaseUrlHint"),
1157
- overriddenLabel: t("overridden"),
1158
- resetLabel: t("reset"),
1159
- invalidLabel: t("invalidNumber"),
1160
- disabled,
1161
- ...state.baseURL,
1162
- onEdit: (text) => {
1163
- props.edit("baseURL", text);
1164
- },
1165
- onReset: () => {
1166
- props.resetField("baseURL");
1167
- }
1168
- }),
1169
- (0, react_jsx_runtime.jsx)(ValueField, {
1170
- id: "plugin-config-web-search-max-uses",
1171
- label: t("webSearchMaxUses"),
1172
- hint: t("webSearchMaxUsesHint"),
1173
- overriddenLabel: t("overridden"),
1174
- resetLabel: t("reset"),
1175
- invalidLabel: t("invalidNumber"),
1176
- numeric: true,
1177
- disabled,
1178
- ...state.maxUses,
1179
- onEdit: (text) => {
1180
- props.edit("maxUses", text);
1181
- },
1182
- onReset: () => {
1183
- props.resetField("maxUses");
1184
- }
1185
- })
1186
- ]
1187
- });
1188
- }
1189
- //#endregion
1190
- //#region lib/types/client/agent-loop-card-controller.js
1191
- /** The agent-loop card's staged form over the `agent-loop` settings namespace. */
1192
- /**
1193
- * Namespace of the agent loop's user-owned settings. Spelled here rather than
1194
- * imported: a client package must not depend on a Host package.
1195
- */
1196
- const AGENT_LOOP_NS = "agent-loop";
1197
- /** Bridges the `agent-loop` scope onto the card's staged form. */
1198
- var AgentLoopCardController = class {
1199
- form;
1200
- store;
1201
- /** @param scope - the bound settings scope for the `agent-loop` namespace. */
1202
- constructor(scope) {
1203
- this.form = new CardForm(scope, [numberField("maxParallelToolCalls")]);
1204
- this.store = this.form.bind(() => this.projection());
1205
- }
1206
- projection() {
1207
- return {
1208
- ...this.form.shell(),
1209
- maxParallelToolCalls: this.form.field("maxParallelToolCalls")
1210
- };
1211
- }
1212
- /**
1213
- * Build the face the card's slot registration injects.
1214
- * @returns the card's snapshot and its form actions.
1215
- */
1216
- inject() {
1217
- return {
1218
- hooks: { agentLoopCard: this.store },
1219
- ...this.form.actions()
1220
- };
1221
- }
1222
- };
1223
- //#endregion
1224
- //#region lib/types/client/bash-card-controller.js
1225
- /** The shell card's staged form over the `bash` settings namespace. */
1226
- /**
1227
- * Namespace of the shell capability. Spelled here rather than imported: a
1228
- * client package must not depend on a Host package, and the executor families
1229
- * that own it spell the same value.
1230
- */
1231
- const SHELL_NS = "shell";
1232
- /** Bridges the `bash` scope onto the shell card's staged form. */
1233
- var BashCardController = class {
1234
- form;
1235
- store;
1236
- /** @param scope - the bound settings scope for the `bash` namespace. */
1237
- constructor(scope) {
1238
- this.form = new CardForm(scope, [numberField("timeoutMs"), numberField("maxOutputBytes")]);
1239
- this.store = this.form.bind(() => this.projection());
1240
- }
1241
- projection() {
1242
- return {
1243
- ...this.form.shell(),
1244
- timeoutMs: this.form.field("timeoutMs"),
1245
- maxOutputBytes: this.form.field("maxOutputBytes")
1246
- };
1247
- }
1248
- /**
1249
- * Build the face the card's slot registration injects.
1250
- * @returns the card's snapshot and its form actions.
1251
- */
1252
- inject() {
1253
- return {
1254
- hooks: { bashCard: this.store },
1255
- ...this.form.actions()
1256
- };
1257
- }
1258
- };
1259
- //#endregion
1260
- //#region lib/types/client/subagent-model-selection-card-controller.js
1261
- /** Staged editor for the Host-owned subagent model allowlist. */
1262
- /** Namespace of the Host-owned subagent model-selection preference. */
1263
- const SUBAGENT_MODEL_SELECTION_NS = "subagent-model-selection";
1264
- /**
1265
- * Stable identity for one exact route; callers resolve it by lookup and never parse it.
1266
- * @param route - Provider/model route to identify.
1267
- * @returns Opaque key for lookup within the card.
1268
- */
1269
- function subagentModelKey(route) {
1270
- return `${route.provider}\0${route.model}`;
1271
- }
1272
- /**
1273
- * Join live adapter metadata with stored routes that remain removable after disappearance.
1274
- * @param groups - Current model directory grouped by provider.
1275
- * @param stored - Routes in the effective settings value.
1276
- * @param selected - Opaque route keys selected in the current draft.
1277
- * @returns Candidate rows for the card.
1278
- */
1279
- function subagentModelCandidates(groups, stored, selected) {
1280
- const storedByKey = new Map(stored.map((route) => [subagentModelKey(route), route]));
1281
- const candidates = groups.flatMap((group) => group.models.map((model) => {
1282
- const route = {
1283
- provider: group.id,
1284
- model: model.id
1285
- };
1286
- const key = subagentModelKey(route);
1287
- storedByKey.delete(key);
1288
- return {
1289
- ...route,
1290
- key,
1291
- providerName: group.name,
1292
- modelName: model.name,
1293
- available: true,
1294
- selected: selected.has(key)
1295
- };
1296
- }));
1297
- for (const route of storedByKey.values()) {
1298
- const key = subagentModelKey(route);
1299
- candidates.push({
1300
- ...route,
1301
- key,
1302
- providerName: route.provider,
1303
- modelName: route.model,
1304
- available: false,
1305
- selected: selected.has(key)
1306
- });
1307
- }
1308
- return candidates;
1309
- }
1310
- function sameRoutes(left, right) {
1311
- if (left.length !== right.length) return false;
1312
- const rightKeys = new Set(right.map(subagentModelKey));
1313
- return left.every((route) => rightKeys.has(subagentModelKey(route)));
1314
- }
1315
- /** Bridges one settings scope and the live adapter directory onto a staged card. */
1316
- var SubagentModelSelectionCardController = class {
1317
- scope;
1318
- ctx;
1319
- catalogGroups = [];
1320
- catalogPartial = false;
1321
- catalogStatus = "idle";
1322
- draftEnabled;
1323
- draftRoutes;
1324
- draftRevision;
1325
- saving = false;
1326
- failed = false;
1327
- conflicted = false;
1328
- disposed = false;
1329
- saveGeneration = 0;
1330
- catalogGeneration = 0;
1331
- store;
1332
- unsubscribe;
1333
- /**
1334
- * @param scope - bound `subagent-model-selection` settings scope.
1335
- * @param ctx - the card plugin's context, whose `remote.session` namespace
1336
- * answers the Host model catalog.
1337
- */
1338
- constructor(scope, ctx) {
1339
- this.scope = scope;
1340
- this.ctx = ctx;
1341
- this.store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)(this.projection());
1342
- this.unsubscribe = scope.subscribe(() => {
1343
- if (!this.saving && this.draftRoutes !== void 0 && this.scope.getSnapshot().revision !== this.draftRevision) if (this.currentEnabled() === this.enabled() && sameRoutes(this.currentRoutes(), this.desiredRoutes())) this.clearDraft();
1344
- else this.conflicted = true;
1345
- if (this.enabled() && this.catalogStatus === "idle") this.loadCatalog();
1346
- this.publish();
1347
- });
1348
- if (this.enabled() && this.catalogStatus === "idle") this.loadCatalog();
1349
- }
1350
- /** Stop observing settings and suppress late directory/write settlements. */
1351
- dispose() {
1352
- this.disposed = true;
1353
- this.saveGeneration += 1;
1354
- this.catalogGeneration += 1;
1355
- this.unsubscribe();
1356
- }
1357
- /**
1358
- * Build the renderer face for this card.
1359
- * @returns The snapshot and staged card actions injected into the renderer.
1360
- */
1361
- inject() {
1362
- return {
1363
- hooks: { subagentModelSelectionCard: this.store },
1364
- toggleEnabled: () => {
1365
- this.toggleEnabled();
1366
- },
1367
- toggleModel: (key) => {
1368
- this.toggleModel(key);
1369
- },
1370
- retryCatalog: () => {
1371
- this.loadCatalog();
1372
- },
1373
- save: () => {
1374
- this.save();
1375
- },
1376
- discard: () => {
1377
- this.discard();
1378
- }
1379
- };
1380
- }
1381
- currentRoutes() {
1382
- return this.scope.getSnapshot().value?.allowedModels.map((route) => ({ ...route })) ?? [];
1383
- }
1384
- currentEnabled() {
1385
- return this.scope.getSnapshot().value?.enabled ?? false;
1386
- }
1387
- selected() {
1388
- return new Set(this.draftRoutes?.keys() ?? this.currentRoutes().map(subagentModelKey));
1389
- }
1390
- enabled() {
1391
- return this.draftEnabled ?? this.currentEnabled();
1392
- }
1393
- beginDraft() {
1394
- if (this.draftRoutes === void 0) {
1395
- const snapshot = this.scope.getSnapshot();
1396
- this.draftEnabled = snapshot.value?.enabled ?? false;
1397
- this.draftRoutes = new Map(snapshot.value?.allowedModels.map((route) => [subagentModelKey(route), { ...route }]) ?? []);
1398
- this.draftRevision = snapshot.revision;
1399
- }
1400
- return this.draftRoutes;
1401
- }
1402
- toggleEnabled() {
1403
- const snapshot = this.scope.getSnapshot();
1404
- if (this.disposed || snapshot.status !== "ready" || !snapshot.writable || this.saving) return;
1405
- this.beginDraft();
1406
- this.draftEnabled = !this.draftEnabled;
1407
- this.failed = false;
1408
- if (this.draftEnabled && this.catalogStatus === "idle") this.loadCatalog();
1409
- this.publish();
1410
- }
1411
- toggleModel(key) {
1412
- if (!this.enabled() || this.saving || !this.scope.getSnapshot().writable) return;
1413
- const candidate = this.candidates().find((candidate) => candidate.key === key);
1414
- if (candidate === void 0) return;
1415
- const routes = this.beginDraft();
1416
- if (routes.has(key)) routes.delete(key);
1417
- else routes.set(key, {
1418
- provider: candidate.provider,
1419
- model: candidate.model
1420
- });
1421
- this.failed = false;
1422
- this.publish();
1423
- }
1424
- clearDraft() {
1425
- this.draftEnabled = void 0;
1426
- this.draftRoutes = void 0;
1427
- this.draftRevision = void 0;
1428
- this.failed = false;
1429
- this.conflicted = false;
1430
- }
1431
- discard() {
1432
- if (this.saving) return;
1433
- this.clearDraft();
1434
- this.publish();
1435
- }
1436
- candidates() {
1437
- const retained = new Map(this.currentRoutes().map((route) => [subagentModelKey(route), route]));
1438
- for (const [key, route] of this.draftRoutes ?? []) retained.set(key, route);
1439
- return subagentModelCandidates(this.catalogGroups, [...retained.values()], this.selected());
1440
- }
1441
- desiredRoutes() {
1442
- return [...this.draftRoutes?.values() ?? this.currentRoutes()].map((route) => ({ ...route }));
1443
- }
1444
- async save() {
1445
- const snapshot = this.scope.getSnapshot();
1446
- const desiredEnabled = this.enabled();
1447
- const desired = this.desiredRoutes();
1448
- if (this.disposed || snapshot.status !== "ready" || !snapshot.writable || this.saving || this.currentEnabled() === desiredEnabled && sameRoutes(this.currentRoutes(), desired) || desiredEnabled && desired.length === 0) return;
1449
- if (this.draftRoutes !== void 0 && snapshot.revision !== this.draftRevision) {
1450
- this.conflicted = true;
1451
- this.publish();
1452
- return;
1453
- }
1454
- const generation = this.saveGeneration;
1455
- this.saving = true;
1456
- this.failed = false;
1457
- this.conflicted = false;
1458
- this.publish();
1459
- await this.scope.mutate([{
1460
- op: "set",
1461
- path: ["enabled"],
1462
- value: desiredEnabled
1463
- }, {
1464
- op: "set",
1465
- path: ["allowedModels"],
1466
- value: desired.map((route) => ({
1467
- provider: route.provider,
1468
- model: route.model
1469
- }))
1470
- }], this.draftRevision);
1471
- if (generation !== this.saveGeneration) return;
1472
- const landed = this.currentEnabled() === desiredEnabled && sameRoutes(this.currentRoutes(), desired);
1473
- this.saving = false;
1474
- this.failed = !landed;
1475
- if (landed) this.clearDraft();
1476
- this.publish();
1477
- }
1478
- /** Invalidate and reload model candidates after a Host model input changes. */
1479
- refreshCatalog() {
1480
- if (this.disposed) return;
1481
- this.catalogGeneration += 1;
1482
- this.catalogStatus = "idle";
1483
- this.catalogPartial = false;
1484
- if (this.enabled()) this.loadCatalog();
1485
- else this.publish();
1486
- }
1487
- /** Drop Host-specific candidates and drafts, then reload after reconnecting. */
1488
- resetConnection() {
1489
- if (this.disposed) return;
1490
- this.saveGeneration += 1;
1491
- this.saving = false;
1492
- this.clearDraft();
1493
- this.catalogGroups = [];
1494
- this.refreshCatalog();
1495
- }
1496
- async loadCatalog() {
1497
- if (this.disposed || this.catalogStatus === "loading") return;
1498
- const generation = this.catalogGeneration;
1499
- this.catalogStatus = "loading";
1500
- this.catalogPartial = false;
1501
- this.publish();
1502
- const response = await this.ctx.remote.session.modelCatalog();
1503
- if (generation !== this.catalogGeneration) return;
1504
- if (response.ok) {
1505
- this.catalogGroups = response.value.groups;
1506
- this.catalogPartial = response.value.failures.length > 0;
1507
- this.catalogStatus = "ready";
1508
- } else this.catalogStatus = "error";
1509
- this.publish();
1510
- }
1511
- projection() {
1512
- const snapshot = this.scope.getSnapshot();
1513
- const current = this.currentRoutes();
1514
- const desired = this.desiredRoutes();
1515
- const enabled = this.enabled();
1516
- return {
1517
- available: snapshot.status === "ready",
1518
- writable: snapshot.writable,
1519
- dirty: this.currentEnabled() !== enabled || !sameRoutes(current, desired),
1520
- invalid: enabled && desired.length === 0,
1521
- saving: this.saving,
1522
- failed: this.failed,
1523
- enabled,
1524
- candidates: this.candidates(),
1525
- catalogStatus: this.catalogStatus,
1526
- catalogPartial: this.catalogPartial,
1527
- conflicted: this.conflicted
1528
- };
1529
- }
1530
- publish() {
1531
- this.store.set(this.projection());
1532
- }
1533
- };
1534
- //#endregion
1535
- //#region lib/types/client/web-search-card-controller.js
1536
- /**
1537
- * The web-search card's staged form over the `web-search-deepseek` settings
1538
- * namespace.
1539
- *
1540
- * The key is the one control that does not live in the section: its literal
1541
- * never rides a response, so the card learns only whether one is configured
1542
- * and writes it through the credentials domain, addressed by the reference the
1543
- * section names. It is still staged with the rest of the form, so one save
1544
- * covers everything the card shows.
1545
- */
1546
- /**
1547
- * Namespace of the DeepSeek search provider. Spelled here rather than
1548
- * imported: a client package must not depend on a Host package.
1549
- */
1550
- const WEB_SEARCH_NS = "web-search-deepseek";
1551
- /** Credential reference the provider resolves when the section names none. */
1552
- const DEFAULT_API_KEY_REF = "DEEPSEEK_API_KEY";
1553
- /** Form field the credential control stages under. */
1554
- const API_KEY_FIELD = "apiKey";
1555
- /** Bridges the `web-search-deepseek` scope and the credentials domain onto the card. */
1556
- var WebSearchCardController = class {
1557
- scope;
1558
- ctx;
1559
- form;
1560
- store;
1561
- credential = {
1562
- ref: "",
1563
- configured: false,
1564
- writable: true
1565
- };
1566
- /**
1567
- * @param scope - the bound settings scope for the `web-search-deepseek` namespace.
1568
- * @param ctx - the card plugin's context, whose `remote.credentials` namespace
1569
- * answers for the credential the section references.
1570
- */
1571
- constructor(scope, ctx) {
1572
- this.scope = scope;
1573
- this.ctx = ctx;
1574
- this.form = new CardForm(scope, [textField("baseURL"), numberField("maxUses")], [{
1575
- field: API_KEY_FIELD,
1576
- write: (text) => this.writeKey(text)
1577
- }]);
1578
- this.store = this.form.bind(() => this.projection());
1579
- scope.subscribe(() => {
1580
- this.readCredential();
1581
- });
1582
- this.readCredential();
1583
- }
1584
- projection() {
1585
- return {
1586
- ...this.form.shell(),
1587
- baseURL: this.form.field("baseURL"),
1588
- maxUses: this.form.field("maxUses"),
1589
- apiKey: this.form.field(API_KEY_FIELD),
1590
- apiKeyConfigured: this.credential.configured,
1591
- apiKeyWritable: this.credential.writable
1592
- };
1593
- }
1594
- /**
1595
- * Ask the credentials domain about the reference the section currently names.
1596
- *
1597
- * The answer is stored with the reference it describes: `apiKeyEnv` can
1598
- * change between the request and its response, and two reads can settle out
1599
- * of order, so a response is published only while it still answers for the
1600
- * reference in force.
1601
- */
1602
- async readCredential() {
1603
- const ref = refOf(this.scope.getSnapshot());
1604
- if (ref !== this.credential.ref) {
1605
- this.credential = {
1606
- ref,
1607
- configured: false,
1608
- writable: true
1609
- };
1610
- this.store.set(this.projection());
1611
- }
1612
- const response = await this.ctx.remote.credentials.describe([ref]);
1613
- if (!response.ok || ref !== refOf(this.scope.getSnapshot())) return;
1614
- const view = response.value[ref];
1615
- const next = {
1616
- ref,
1617
- configured: view?.configured ?? false,
1618
- writable: view?.writable ?? true
1619
- };
1620
- if (next.configured === this.credential.configured && next.writable === this.credential.writable) return;
1621
- this.credential = next;
1622
- this.store.set(this.projection());
1623
- }
1624
- /**
1625
- * Re-read after the Host reports a change to the reference this card watches.
1626
- *
1627
- * A key can be written from somewhere else — the Models page addresses the
1628
- * same reference — and the settings section does not change when it is, so
1629
- * without this the badge keeps reporting a state the Host already replaced.
1630
- * @param ref - the reference the Host reports as changed.
1631
- */
1632
- refreshCredential(ref) {
1633
- if (ref !== this.credential.ref) return;
1634
- this.readCredential();
1635
- }
1636
- /**
1637
- * Build the face the card's slot registration injects.
1638
- * @returns the card's snapshot and its form actions.
1639
- */
1640
- inject() {
1641
- return {
1642
- hooks: { webSearchCard: this.store },
1643
- ...this.form.actions()
1644
- };
1645
- }
1646
- /**
1647
- * Write the staged key, then re-read whether the Host now holds one.
1648
- * @param value - the staged credential literal.
1649
- * @returns whether the Host reports a configured credential afterwards.
1650
- */
1651
- async writeKey(value) {
1652
- await this.ctx.remote.credentials.set(refOf(this.scope.getSnapshot()), value);
1653
- await this.readCredential();
1654
- return this.credential.configured;
1655
- }
1656
- };
1657
- /**
1658
- * The credential reference the section names, or the provider's default.
1659
- * @param snapshot - the current scope snapshot.
1660
- * @returns the reference to address.
1661
- */
1662
- function refOf(snapshot) {
1663
- const declared = snapshot.value?.apiKeyEnv;
1664
- return declared !== void 0 && declared.length > 0 ? declared : DEFAULT_API_KEY_REF;
1665
- }
1666
- //#endregion
1667
131
  //#region lib/types/client/locales.js
1668
- /** Locale bundles for the built-in plugins settings section and the plugin configuration pages. */
132
+ /** Locale bundles for the built-in plugins settings section. */
1669
133
  /** English copy. */
1670
134
  const en = {
1671
135
  nav: "Built-in plugins",
1672
136
  title: "Built-in plugins",
1673
137
  intro: "Inspect the plugins this deployment ships.",
1674
138
  tabs: "Plugin views",
1675
- empty: "This deployment exposes no plugin views.",
1676
- overridden: "Overridden",
1677
- reset: "Reset to default",
1678
- readOnly: "This deployment stores settings read-only.",
1679
- unavailable: "This plugin is not loaded, so it cannot be configured right now.",
1680
- save: "Save",
1681
- saving: "Saving…",
1682
- saveFailed: "The deployment did not accept these values; they were left for you to correct.",
1683
- invalidNumber: "Enter a number, or leave blank to use the default.",
1684
- bashTitle: "Shell",
1685
- bashDescription: "Limits every command the agent runs.",
1686
- bashTimeoutMs: "Command timeout (ms)",
1687
- bashTimeoutMsHint: "How long one command may run before it is terminated.",
1688
- bashMaxOutputBytes: "Output cap per stream (bytes)",
1689
- bashMaxOutputBytesHint: "Output beyond this spills to a temporary file rather than being lost.",
1690
- agentLoopTitle: "Agent loop",
1691
- agentLoopDescription: "How the agent dispatches tool calls.",
1692
- agentLoopMaxParallel: "Parallel tool calls",
1693
- agentLoopMaxParallelHint: "Upper bound on parallel-safe calls running at once within one step.",
1694
- webSearchTitle: "Web search",
1695
- webSearchDescription: "The DeepSeek search provider.",
1696
- webSearchApiKey: "API key",
1697
- webSearchApiKeyHint: "Stored outside the settings file. Leave blank to keep the current key.",
1698
- webSearchApiKeySet: "A key is configured.",
1699
- webSearchApiKeyUnset: "No key is configured; search is unavailable until one is.",
1700
- webSearchBaseUrl: "Endpoint",
1701
- webSearchBaseUrlHint: "Leave blank to use the provider default.",
1702
- webSearchMaxUses: "Max searches per request",
1703
- webSearchMaxUsesHint: "How many times one request may search before it must answer.",
1704
- subagentTitle: "Subagent",
1705
- subagentDescription: "Set Subagent recursion depth, count, and models.",
1706
- subagentLimitsTitle: "Limits",
1707
- subagentMaxDepth: "Maximum recursion depth",
1708
- subagentDepthHelpLabel: "About maximum recursion depth",
1709
- subagentDepthHelp: "Limits how many levels of Subagents an Agent can create.",
1710
- subagentDepthZero: "Disable Subagents",
1711
- subagentDepthOne: "Only the main Agent can create Subagents",
1712
- subagentDepthOverride: "If a tool defines its own maximum recursion depth, that setting takes precedence.",
1713
- subagentMaxActive: "Subagent parallelism limit",
1714
- subagentCapacityHelpLabel: "About the Subagent parallelism limit",
1715
- subagentCapacityHelp: "Total live Subagents under the same main Agent, across all recursion levels. The main Agent is excluded. New start requests are rejected when the limit is reached.",
1716
- subagentDepthInvalid: "Enter a whole number of 0 or more.",
1717
- subagentCapacityInvalid: "Enter a whole number of 1 or more.",
1718
- subagentModelSelectionTitle: "Model selection",
1719
- subagentModelSelectionToggle: "Allow agents to choose models for Subagents",
1720
- subagentModelSelectionChoose: "When enabled, agents can choose a provider, model, and reasoning effort for each Subagent from the authorized models below. Applies only to new sessions.",
1721
- subagentModelSelectionAllowed: "Models agents may choose",
1722
- subagentModelSelectionLoading: "Loading models…",
1723
- subagentModelSelectionLoadFailed: "Models could not be loaded.",
1724
- subagentModelSelectionRetry: "Retry",
1725
- subagentModelSelectionPartial: "Some model providers could not be loaded; saved choices remain removable.",
1726
- subagentModelSelectionUnavailable: "Currently unavailable",
1727
- subagentModelSelectionUnavailableGroup: "Saved but currently unavailable",
1728
- subagentModelSelectionEmpty: "No model provider currently advertises a model.",
1729
- subagentModelSelectionRequired: "Select at least one model before saving.",
1730
- subagentModelSelectionConflict: "Settings changed elsewhere. Discard your draft and try again.",
1731
- subagentModelSelectionOff: "Subagents use configured defaults or inherit the parent agent's model. Saved model choices are retained."
139
+ empty: "This deployment exposes no plugin views."
1732
140
  };
1733
141
  /** Simplified Chinese copy. */
1734
142
  const zh = {
@@ -1736,89 +144,24 @@ window.__ModuleLoader__.load({
1736
144
  title: "内置插件",
1737
145
  intro: "查看内置部署的插件列表",
1738
146
  tabs: "插件视图",
1739
- empty: "本部署没有开放任何插件视图。",
1740
- overridden: "已覆盖",
1741
- reset: "恢复默认",
1742
- readOnly: "本部署的设置为只读。",
1743
- unavailable: "该插件当前未加载,暂时无法配置。",
1744
- save: "保存",
1745
- saving: "保存中…",
1746
- saveFailed: "本部署没有接受这些值,已保留供你修改。",
1747
- invalidNumber: "请填数字;留空表示使用默认值。",
1748
- bashTitle: "终端",
1749
- bashDescription: "限制 agent 运行的每一条命令。",
1750
- bashTimeoutMs: "命令超时(毫秒)",
1751
- bashTimeoutMsHint: "单条命令允许运行多久,超时即终止。",
1752
- bashMaxOutputBytes: "单流输出上限(字节)",
1753
- bashMaxOutputBytesHint: "超出部分会转存到临时文件,而不是被丢弃。",
1754
- agentLoopTitle: "Agent 循环",
1755
- agentLoopDescription: "Agent 如何派发工具调用。",
1756
- agentLoopMaxParallel: "并行工具调用数",
1757
- agentLoopMaxParallelHint: "同一步内最多同时运行多少个可并行的调用。",
1758
- webSearchTitle: "网页搜索",
1759
- webSearchDescription: "DeepSeek 搜索提供方。",
1760
- webSearchApiKey: "API Key",
1761
- webSearchApiKeyHint: "不写入设置文件。留空表示保持当前密钥。",
1762
- webSearchApiKeySet: "已配置密钥。",
1763
- webSearchApiKeyUnset: "未配置密钥;配置之前搜索不可用。",
1764
- webSearchBaseUrl: "接口地址",
1765
- webSearchBaseUrlHint: "留空则使用提供方默认地址。",
1766
- webSearchMaxUses: "单次请求最多搜索次数",
1767
- webSearchMaxUsesHint: "一次请求在必须作答前最多可以搜索多少次。",
1768
- subagentTitle: "Subagent",
1769
- subagentDescription: "设置 Subagent 的递归层级、数量和模型。",
1770
- subagentLimitsTitle: "运行限制",
1771
- subagentMaxDepth: "最大递归深度",
1772
- subagentDepthHelpLabel: "最大递归深度说明",
1773
- subagentDepthHelp: "限制 Agent 创建 Subagent 的递归层级。",
1774
- subagentDepthZero: "禁用 Subagent",
1775
- subagentDepthOne: "仅允许主 Agent 创建 Subagent",
1776
- subagentDepthOverride: "如果某个工具单独设置了最大递归深度,以该工具的设置为准。",
1777
- subagentMaxActive: "Subagent 并行数量上限",
1778
- subagentCapacityHelpLabel: "Subagent 并行数量上限说明",
1779
- subagentCapacityHelp: "同一主 Agent 下,所有递归层级同时存活的 Subagent 总数,主 Agent 不计入。达到上限时,新的启动请求会被拒绝。",
1780
- subagentDepthInvalid: "请输入不小于 0 的整数。",
1781
- subagentCapacityInvalid: "请输入不小于 1 的整数。",
1782
- subagentModelSelectionTitle: "模型选择",
1783
- subagentModelSelectionToggle: "允许 Agent 为 Subagent 选择模型",
1784
- subagentModelSelectionChoose: "开启后,Agent 可以从下方授权模型中,为每个 Subagent 选择提供方、模型和推理强度。仅影响新会话。",
1785
- subagentModelSelectionAllowed: "Agent 可选择的模型",
1786
- subagentModelSelectionLoading: "正在加载模型…",
1787
- subagentModelSelectionLoadFailed: "无法加载模型。",
1788
- subagentModelSelectionRetry: "重试",
1789
- subagentModelSelectionPartial: "部分模型提供方暂时无法加载;已保存的选择仍可移除。",
1790
- subagentModelSelectionUnavailable: "当前不可用",
1791
- subagentModelSelectionUnavailableGroup: "已保存但当前不可用",
1792
- subagentModelSelectionEmpty: "当前没有模型提供方公布模型。",
1793
- subagentModelSelectionRequired: "保存前请至少选择一个模型。",
1794
- subagentModelSelectionConflict: "设置已在其他位置更新。请放弃修改后重试。",
1795
- subagentModelSelectionOff: "关闭后,Subagent 使用配置的默认模型或继承父 Agent 的模型;已选模型会保留。"
147
+ empty: "本部署没有开放任何插件视图。"
1796
148
  };
1797
149
  //#endregion
1798
150
  //#region lib/types/client/index.js
1799
151
  /**
1800
- * Built-in plugins settings surface and the official plugin configuration
1801
- * pages, browser half. The Settings section is the shell around the
152
+ * Built-in plugins settings section, browser half: the shell around the
1802
153
  * feature-owned tabs registered into `settings.plugins.tab` (the read-only
1803
- * inventory ships one); the configuration pages this package ships register
1804
- * into the Plugins page's `plugins.item` slot, for the host-plane namespaces
1805
- * the deployment exposes, and appear in the page's Official group. Each form
1806
- * binds its namespace through the client settings scope, which keeps the
1807
- * pages unaware of one another and of the section.
154
+ * inventory ships one). The configuration pages of the host-plane plugins
155
+ * live in their own companion packages, which register into the Plugins
156
+ * page; this section owns the Settings navigation entry and the tab chrome
157
+ * only.
1808
158
  */
1809
159
  /** Dictionary namespace owned by this plugin. */
1810
160
  const NS = "settings.plugins";
1811
161
  /** Required services (cordis fiber inject). */
1812
- const inject = [
1813
- "slots",
1814
- "locale",
1815
- "remote",
1816
- "remote.credentials",
1817
- "remote.session",
1818
- "settingsScope"
1819
- ];
162
+ const inject = ["slots", "locale"];
1820
163
  /**
1821
- * Mount the built-in plugins section and the configuration pages this package ships.
164
+ * Mount the built-in plugins section.
1822
165
  * @param ctx - the browser plugin context.
1823
166
  */
1824
167
  function apply(ctx) {
@@ -1827,87 +170,6 @@ window.__ModuleLoader__.load({
1827
170
  zh,
1828
171
  en
1829
172
  }), "ui-settings-plugins: section dictionaries");
1830
- const bash = new BashCardController(ctx.settingsScope.bind({ namespace: SHELL_NS }));
1831
- const agentLoop = new AgentLoopCardController(ctx.settingsScope.bind({ namespace: AGENT_LOOP_NS }));
1832
- const webSearch = new WebSearchCardController(ctx.settingsScope.bind({ namespace: WEB_SEARCH_NS }), ctx);
1833
- const subagentLimits = new SubagentLimitsCardController(ctx.settingsScope.bind({ namespace: "subagent" }));
1834
- const subagentModelSelection = new SubagentModelSelectionCardController(ctx.settingsScope.bind({ namespace: SUBAGENT_MODEL_SELECTION_NS }), ctx);
1835
- const subagentLimitsFace = subagentLimits.inject();
1836
- const subagentModelsFace = subagentModelSelection.inject();
1837
- ctx.effect(() => ctx.remote.$on("credentials/reference-updated", (ref) => {
1838
- webSearch.refreshCredential(ref);
1839
- }), "ui-settings-plugins: credential invalidations");
1840
- ctx.effect(() => ctx.remote.$on("llm/adapters-updated", () => {
1841
- subagentModelSelection.refreshCatalog();
1842
- }), "ui-settings-plugins: subagent adapter invalidations");
1843
- ctx.effect(() => ctx.remote.$on("settings/document-updated", () => {
1844
- subagentModelSelection.refreshCatalog();
1845
- }), "ui-settings-plugins: subagent settings invalidations");
1846
- ctx.effect(() => ctx.on("connection/reset", () => {
1847
- subagentModelSelection.resetConnection();
1848
- }), "ui-settings-plugins: subagent connection generation");
1849
- ctx.effect(() => () => {
1850
- subagentModelSelection.dispose();
1851
- }, "ui-settings-plugins: subagent preference");
1852
- const pages = [
1853
- [[SHELL_NS], () => ctx.slots.inject("plugins.item", () => ctx.slots.register({
1854
- name: "plugins.item",
1855
- id: "bash",
1856
- order: 10,
1857
- label: () => t("bashTitle"),
1858
- locale: NS,
1859
- inject: () => bash.inject()
1860
- }, BashCard))],
1861
- [[AGENT_LOOP_NS], () => ctx.slots.inject("plugins.item", () => ctx.slots.register({
1862
- name: "plugins.item",
1863
- id: "agent-loop",
1864
- order: 20,
1865
- label: () => t("agentLoopTitle"),
1866
- locale: NS,
1867
- inject: () => agentLoop.inject()
1868
- }, AgentLoopCard))],
1869
- [["subagent", SUBAGENT_MODEL_SELECTION_NS], () => ctx.slots.inject("plugins.item", () => ctx.slots.register({
1870
- name: "plugins.item",
1871
- id: "subagent",
1872
- order: 30,
1873
- label: () => t("subagentTitle"),
1874
- locale: NS,
1875
- inject: () => subagentCardFace(subagentLimitsFace, subagentModelsFace)
1876
- }, SubagentCard))],
1877
- [[WEB_SEARCH_NS], () => ctx.slots.inject("plugins.item", () => ctx.slots.register({
1878
- name: "plugins.item",
1879
- id: "web-search",
1880
- order: 40,
1881
- label: () => t("webSearchTitle"),
1882
- locale: NS,
1883
- inject: () => webSearch.inject()
1884
- }, WebSearchCard))]
1885
- ];
1886
- const describeFace = ctx.settingsScope.describe();
1887
- ctx.effect(() => {
1888
- const registered = /* @__PURE__ */ new Map();
1889
- const sync = () => {
1890
- const served = new Set(describeFace.getSnapshot().view?.namespaces.map((view) => view.ns) ?? []);
1891
- for (const [namespaces, register] of pages) {
1892
- const namespace = namespaces[0];
1893
- const available = namespaces.some((namespace) => served.has(namespace));
1894
- const off = registered.get(namespace);
1895
- if (available && off === void 0) registered.set(namespace, register());
1896
- else if (!available && off !== void 0) {
1897
- off();
1898
- registered.delete(namespace);
1899
- }
1900
- }
1901
- };
1902
- const unsubscribe = describeFace.subscribe(sync);
1903
- describeFace.ensure();
1904
- sync();
1905
- return () => {
1906
- unsubscribe();
1907
- for (const off of registered.values()) off();
1908
- registered.clear();
1909
- };
1910
- }, "ui-settings-plugins: configuration pages");
1911
173
  let tabsVersion = -1;
1912
174
  let tabsRevision = -1;
1913
175
  let tabs = [];