dsh-edge 0.21.0 → 0.22.0

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.
@@ -0,0 +1,324 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@deepseek-ai/dsh-client-ui-settings-web-search",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
+ //#region lib/types/client/locales.js
10
+ /** Locale bundles for the web-search provider's settings page. */
11
+ /** English copy. */
12
+ const en = {
13
+ title: "Web search",
14
+ description: "Set up the DeepSeek search provider.",
15
+ apiKey: "API key",
16
+ apiKeyHint: "Stored outside the settings file. Leave blank to keep the current key.",
17
+ apiKeySet: "A key is configured.",
18
+ apiKeyUnset: "No key is configured; only conversations using a DeepSeek Account model can search, through the default endpoint.",
19
+ baseUrl: "Endpoint",
20
+ baseUrlHint: "Leave blank to use the provider default.",
21
+ maxUses: "Max searches per request",
22
+ maxUsesHint: "How many times one request may search before it must answer.",
23
+ overridden: "Overridden",
24
+ reset: "Reset to default",
25
+ readOnly: "This deployment stores settings read-only.",
26
+ unavailable: "This plugin is not loaded, so it cannot be configured right now.",
27
+ save: "Save",
28
+ saving: "Saving…",
29
+ saveFailed: "The deployment did not accept these values; they were left for you to correct.",
30
+ invalidNumber: "Enter a number, or leave blank to use the default."
31
+ };
32
+ /** Simplified Chinese copy. */
33
+ const zh = {
34
+ title: "网页搜索",
35
+ description: "设置 DeepSeek 的搜索提供方。",
36
+ apiKey: "API Key",
37
+ apiKeyHint: "不写入设置文件。留空表示保持当前密钥。",
38
+ apiKeySet: "已配置密钥。",
39
+ apiKeyUnset: "未配置密钥;仅使用 DeepSeek 账号模型的对话可以通过默认接口地址搜索。",
40
+ baseUrl: "接口地址",
41
+ baseUrlHint: "留空则使用提供方默认地址。",
42
+ maxUses: "单次请求最多搜索次数",
43
+ maxUsesHint: "一次请求在必须作答前最多可以搜索多少次。",
44
+ overridden: "已覆盖",
45
+ reset: "恢复默认",
46
+ readOnly: "本部署的设置为只读。",
47
+ unavailable: "该插件当前未加载,暂时无法配置。",
48
+ save: "保存",
49
+ saving: "保存中…",
50
+ saveFailed: "本部署没有接受这些值,已保留供你修改。",
51
+ invalidNumber: "请填数字;留空表示使用默认值。"
52
+ };
53
+ /**
54
+ * The form frame's copy, read from this page's dictionary.
55
+ * @param t - the page's locale reader.
56
+ * @returns the labels the shared settings form renders.
57
+ */
58
+ function formLabels(t) {
59
+ return {
60
+ unavailable: t("unavailable"),
61
+ readOnly: t("readOnly"),
62
+ saveFailed: t("saveFailed"),
63
+ save: t("save"),
64
+ saving: t("saving")
65
+ };
66
+ }
67
+ //#endregion
68
+ //#region lib/types/client/WebSearchCard.js
69
+ /**
70
+ * Render the web-search provider's one-liner or its settings form, as the Plugins page asks.
71
+ * @param props - the view asked for, locale copy, the form snapshot, and its actions.
72
+ * @returns the one-liner, or the form.
73
+ */
74
+ function WebSearchCard(props) {
75
+ const { t } = props;
76
+ const state = props.useWebSearchCard((snapshot) => snapshot);
77
+ if (props.view === "summary") return t("description");
78
+ const disabled = !state.writable;
79
+ return (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.SettingsForm, {
80
+ labels: formLabels(t),
81
+ state,
82
+ onSave: props.save,
83
+ onDiscard: props.discard,
84
+ children: [
85
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsSecretField, {
86
+ id: "plugin-config-web-search-key",
87
+ label: t("apiKey"),
88
+ hint: t("apiKeyHint"),
89
+ disabled: !state.apiKeyWritable,
90
+ text: state.apiKey.text,
91
+ configured: state.apiKeyConfigured,
92
+ stateLabel: state.apiKeyConfigured ? t("apiKeySet") : t("apiKeyUnset"),
93
+ onEdit: (text) => {
94
+ props.edit("apiKey", text);
95
+ }
96
+ }),
97
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsValueField, {
98
+ id: "plugin-config-web-search-endpoint",
99
+ label: t("baseUrl"),
100
+ hint: t("baseUrlHint"),
101
+ overriddenLabel: t("overridden"),
102
+ resetLabel: t("reset"),
103
+ invalidLabel: t("invalidNumber"),
104
+ disabled,
105
+ ...state.baseURL,
106
+ onEdit: (text) => {
107
+ props.edit("baseURL", text);
108
+ },
109
+ onReset: () => {
110
+ props.resetField("baseURL");
111
+ }
112
+ }),
113
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SettingsValueField, {
114
+ id: "plugin-config-web-search-max-uses",
115
+ label: t("maxUses"),
116
+ hint: t("maxUsesHint"),
117
+ overriddenLabel: t("overridden"),
118
+ resetLabel: t("reset"),
119
+ invalidLabel: t("invalidNumber"),
120
+ numeric: true,
121
+ disabled,
122
+ ...state.maxUses,
123
+ onEdit: (text) => {
124
+ props.edit("maxUses", text);
125
+ },
126
+ onReset: () => {
127
+ props.resetField("maxUses");
128
+ }
129
+ })
130
+ ]
131
+ });
132
+ }
133
+ //#endregion
134
+ //#region lib/types/client/web-search-card-controller.js
135
+ /**
136
+ * The web-search page's staged form over the `web-search-deepseek` settings
137
+ * namespace.
138
+ *
139
+ * The key is the one control that does not live in the section: its literal
140
+ * never rides a response, so the page learns only whether one is configured
141
+ * and writes it through the credentials domain, addressed by the reference the
142
+ * section names. It is still staged with the rest of the form, so one save
143
+ * covers everything the page shows.
144
+ */
145
+ /**
146
+ * Namespace of the DeepSeek search provider. Spelled here rather than
147
+ * imported: a client package must not depend on a Host package.
148
+ */
149
+ const WEB_SEARCH_NS = "web-search-deepseek";
150
+ /** Credential reference the provider resolves when the section names none. */
151
+ const DEFAULT_API_KEY_REF = "DEEPSEEK_API_KEY";
152
+ /** Form field the credential control stages under. */
153
+ const API_KEY_FIELD = "apiKey";
154
+ /** Bridges the `web-search-deepseek` scope and the credentials domain onto the page. */
155
+ var WebSearchCardController = class {
156
+ scope;
157
+ ctx;
158
+ form;
159
+ store;
160
+ unsubscribe;
161
+ credential = {
162
+ ref: "",
163
+ configured: false,
164
+ writable: true
165
+ };
166
+ /**
167
+ * @param scope - the bound settings scope for the `web-search-deepseek` namespace.
168
+ * @param ctx - the page plugin's context, whose `remote.credentials` namespace
169
+ * answers for the credential the section references.
170
+ */
171
+ constructor(scope, ctx) {
172
+ this.scope = scope;
173
+ this.ctx = ctx;
174
+ this.form = new _deepseek_ai_dsh_client_ui_primitives.SettingsFormModel(scope, [(0, _deepseek_ai_dsh_client_ui_primitives.settingsTextField)("baseURL"), (0, _deepseek_ai_dsh_client_ui_primitives.settingsNumberField)("maxUses")], [{
175
+ field: API_KEY_FIELD,
176
+ write: (text) => this.writeKey(text)
177
+ }]);
178
+ this.store = this.form.bind(() => this.projection());
179
+ this.unsubscribe = scope.subscribe(() => {
180
+ this.readCredential();
181
+ });
182
+ this.readCredential();
183
+ }
184
+ projection() {
185
+ return {
186
+ ...this.form.shell(),
187
+ baseURL: this.form.field("baseURL"),
188
+ maxUses: this.form.field("maxUses"),
189
+ apiKey: this.form.field(API_KEY_FIELD),
190
+ apiKeyConfigured: this.credential.configured,
191
+ apiKeyWritable: this.credential.writable
192
+ };
193
+ }
194
+ /**
195
+ * Ask the credentials domain about the reference the section currently names.
196
+ *
197
+ * The answer is stored with the reference it describes: `apiKeyEnv` can
198
+ * change between the request and its response, and two reads can settle out
199
+ * of order, so a response is published only while it still answers for the
200
+ * reference in force.
201
+ */
202
+ async readCredential() {
203
+ const ref = refOf(this.scope.getSnapshot());
204
+ if (ref !== this.credential.ref) {
205
+ this.credential = {
206
+ ref,
207
+ configured: false,
208
+ writable: true
209
+ };
210
+ this.store.set(this.projection());
211
+ }
212
+ const response = await this.ctx.remote.credentials.describe([ref]);
213
+ if (!response.ok || ref !== refOf(this.scope.getSnapshot())) return;
214
+ const view = response.value[ref];
215
+ const next = {
216
+ ref,
217
+ configured: view?.configured ?? false,
218
+ writable: view?.writable ?? true
219
+ };
220
+ if (next.configured === this.credential.configured && next.writable === this.credential.writable) return;
221
+ this.credential = next;
222
+ this.store.set(this.projection());
223
+ }
224
+ /**
225
+ * Re-read after the Host reports a change to the reference this page watches.
226
+ *
227
+ * A key can be written from somewhere else — the Models page addresses the
228
+ * same reference — and the settings section does not change when it is, so
229
+ * without this the badge keeps reporting a state the Host already replaced.
230
+ * @param ref - the reference the Host reports as changed.
231
+ */
232
+ refreshCredential(ref) {
233
+ if (ref !== this.credential.ref) return;
234
+ this.readCredential();
235
+ }
236
+ /**
237
+ * Build the face the page's slot registration injects.
238
+ * @returns the page's snapshot and its form actions.
239
+ */
240
+ inject() {
241
+ return {
242
+ hooks: { webSearchCard: this.store },
243
+ ...this.form.actions()
244
+ };
245
+ }
246
+ /**
247
+ * Write the staged key, then re-read whether the Host now holds one.
248
+ * @param value - the staged credential literal.
249
+ * @returns whether the Host reports a configured credential afterwards.
250
+ */
251
+ async writeKey(value) {
252
+ await this.ctx.remote.credentials.set(refOf(this.scope.getSnapshot()), value);
253
+ await this.readCredential();
254
+ return this.credential.configured;
255
+ }
256
+ /** Release configuration subscriptions. */
257
+ dispose() {
258
+ this.unsubscribe();
259
+ this.form.dispose();
260
+ }
261
+ };
262
+ /**
263
+ * The credential reference the section names, or the provider's default.
264
+ * @param snapshot - the current scope snapshot.
265
+ * @returns the reference to address.
266
+ */
267
+ function refOf(snapshot) {
268
+ const declared = snapshot.value?.apiKeyEnv;
269
+ return declared !== void 0 && declared.length > 0 ? declared : DEFAULT_API_KEY_REF;
270
+ }
271
+ //#endregion
272
+ //#region lib/types/client/index.js
273
+ /**
274
+ * The web-search provider's settings page, browser half: the key, the
275
+ * endpoint, and the per-request search budget over the `web-search-deepseek`
276
+ * namespace the provider registers. The page registers into the Plugins
277
+ * page's `plugins.item` slot while the Host serves that namespace, so a
278
+ * deployment without the provider shows no trace of it.
279
+ */
280
+ /** Dictionary namespace owned by this plugin. */
281
+ const NS = "settings.webSearch";
282
+ /** Required services (cordis fiber inject). */
283
+ const inject = [
284
+ "slots",
285
+ "locale",
286
+ "remote",
287
+ "remote.credentials",
288
+ "configForms"
289
+ ];
290
+ /**
291
+ * Mount the web-search settings page while the Host serves its namespace.
292
+ * @param ctx - the browser plugin context.
293
+ */
294
+ function apply(ctx) {
295
+ const t = ctx.locale.bind(NS);
296
+ ctx.effect(() => ctx.locale.register(NS, {
297
+ zh,
298
+ en
299
+ }), "ui-settings-web-search: dictionaries");
300
+ const card = new WebSearchCardController(ctx.configForms.get(WEB_SEARCH_NS), ctx);
301
+ ctx.effect(() => () => {
302
+ card.dispose();
303
+ }, "ui-settings-web-search: form subscription");
304
+ ctx.effect(() => ctx.remote.$on("credentials/reference-updated", (ref) => {
305
+ card.refreshCredential(ref);
306
+ }), "ui-settings-web-search: credential invalidations");
307
+ ctx.effect(() => ctx.configForms.whileServed([WEB_SEARCH_NS], () => ctx.slots.inject("plugins.item", () => ctx.slots.register({
308
+ name: "plugins.item",
309
+ id: "web-search",
310
+ order: 40,
311
+ label: () => t("title"),
312
+ locale: NS,
313
+ inject: () => card.inject()
314
+ }, WebSearchCard))), "ui-settings-web-search: page");
315
+ }
316
+ //#endregion
317
+ exports.NS = NS;
318
+ exports.apply = apply;
319
+ exports.inject = inject;
320
+ return module.exports;
321
+ }
322
+ });
323
+
324
+ //# sourceMappingURL=client.js.map
@@ -11,6 +11,7 @@ window.__ModuleLoader__.load({
11
11
  let react = require("react");
12
12
  let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
13
13
  let react_jsx_runtime = require("react/jsx-runtime");
14
+ let _deepseek_ai_dsh_client_ui_slots = require("@deepseek-ai/dsh-client-ui-slots");
14
15
  //#region ../../../packages/client/ui-edge/src/client/run-guards.ts
15
16
  const row = (value) => typeof value === "object" && value !== null ? value : void 0;
16
17
  function installRunGuards(session, transport = fetch) {
@@ -739,7 +740,7 @@ window.__ModuleLoader__.load({
739
740
  };
740
741
  //#endregion
741
742
  //#region \0dsh-edge-css:src/client/EdgeSettingsSection.module.css.mjs
742
- const css = "._68Y4qa_section{gap:20px;max-width:720px;display:grid}._68Y4qa_section header h2,._68Y4qa_card h3{color:var(--dsw-alias-text-primary);margin:0}._68Y4qa_section header p,._68Y4qa_card p{color:var(--dsw-alias-label-secondary)}._68Y4qa_card{border:1px solid var(--dsw-alias-border-subtle);border-radius:12px;padding:18px}._68Y4qa_card dl{margin:12px 0}._68Y4qa_row{border-bottom:1px solid var(--dsw-alias-border-secondary);grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:16px;padding:8px 0;display:grid}._68Y4qa_row:last-child{border-bottom:0}._68Y4qa_row dt{color:var(--dsw-alias-label-secondary)}._68Y4qa_row dd{overflow-wrap:anywhere;color:var(--dsw-alias-text-primary);margin:0}._68Y4qa_actions{flex-wrap:wrap;align-items:center;gap:12px;display:flex}._68Y4qa_actions a{color:var(--dsw-alias-brand-primary)}._68Y4qa_status{align-items:center;gap:8px;display:flex}._68Y4qa_capabilities{margin:0;padding-left:18px}._68Y4qa_notice{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));font-size:13px}._68Y4qa_error{word-break:break-word;overflow-wrap:anywhere;font-size:13px;color:var(--dsw-alias-state-error-primary)!important}._68Y4qa_select{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-background-primary));color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));height:34px;font:inherit;appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23999' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 10px center;background-repeat:no-repeat;border-radius:8px;padding:0 28px 0 10px;font-size:13px;line-height:1.5}._68Y4qa_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}._68Y4qa_input{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-background-primary));color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));height:34px;font:inherit;box-sizing:border-box;border-radius:8px;width:100%;padding:0 12px;font-size:13px;line-height:1.5}._68Y4qa_input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}._68Y4qa_mcpList{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}._68Y4qa_mcpCard{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));background:var(--dsw-alias-bg-layer-3,transparent);border-radius:16px;list-style:none;transition:border-color .16s,background .16s}._68Y4qa_mcpCard:hover{border-color:var(--dsw-alias-label-dimmed,#bbb)}._68Y4qa_mcpCardOpen{background:var(--dsw-alias-bg-layer-2,transparent);border-color:var(--dsw-alias-label-dimmed,#bbb)}._68Y4qa_mcpCardHeader{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}._68Y4qa_mcpCardHeader:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}._68Y4qa_mcpAvatar{background:var(--dsw-alias-brand-background,#eef2fe);width:32px;height:32px;color:var(--dsw-alias-brand-primary);border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:flex}._68Y4qa_mcpCardTitleGroup{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}._68Y4qa_mcpCardName{color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));margin:0;font-size:15px;font-weight:600;line-height:1.4}._68Y4qa_mcpCardSub{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));align-items:center;gap:8px;margin:0;font-size:13px;line-height:1.5;display:flex}._68Y4qa_mcpChevron{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));flex:none;transition:transform .16s}._68Y4qa_mcpChevronOpen{transform:rotate(180deg)}._68Y4qa_mcpChevron svg{display:block}._68Y4qa_mcpBadge{border-radius:4px;padding:1px 6px;font-size:11px;font-weight:500}._68Y4qa_mcpBadge[data-status=connected]{background:var(--dsw-alias-state-success-background,#ecfdf3);color:var(--dsw-alias-state-success-primary,#16a34a)}._68Y4qa_mcpBadge[data-status=error]{background:var(--dsw-alias-state-error-background,#fff0f0);color:var(--dsw-alias-state-error-primary,#dc2626)}._68Y4qa_mcpBadge[data-status=needs_reauth]{background:var(--dsw-alias-state-warning-background,#fff8e6);color:var(--dsw-alias-state-warning-primary,#d97706)}._68Y4qa_mcpBadge[data-status=unknown]{background:var(--dsw-alias-background-secondary,#f3f4f6);color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary))}._68Y4qa_mcpCardBody{border-top:.5px solid var(--dsw-alias-border-l2,var(--dsw-alias-border-secondary));gap:12px;min-width:0;margin:0 16px;padding:12px 0 8px;display:grid}._68Y4qa_mcpFieldRow{grid-template-columns:140px 1fr;align-items:center;gap:12px;display:grid}._68Y4qa_mcpFieldLabel{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));font-size:13px;line-height:1.5}._68Y4qa_mcpFieldValue{color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));font-size:13px;line-height:1.5}._68Y4qa_mcpCardSuccess{color:var(--dsw-alias-state-success-primary,#16a34a);margin:0;padding:4px 0;font-size:12px;line-height:1.4}._68Y4qa_mcpCardError{color:var(--dsw-alias-state-error-primary,#dc2626);margin:0;padding:4px 0;font-size:12px;line-height:1.4}._68Y4qa_mcpCardActions{border-top:.5px solid var(--dsw-alias-border-l2,var(--dsw-alias-border-secondary));justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}._68Y4qa_mcpAddTrigger{appearance:none;width:100%;font:inherit;cursor:pointer;border:.5px dashed var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));background:0 0;border-radius:16px;justify-content:center;align-items:center;gap:6px;padding:14px 16px;font-size:13px;line-height:1.5;transition:border-color .16s,color .16s;display:flex}._68Y4qa_mcpAddTrigger:hover{border-color:var(--dsw-alias-label-dimmed,#bbb);color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary))}._68Y4qa_mcpAddTrigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}._68Y4qa_mcpToolList{flex-direction:column;gap:6px;display:flex}._68Y4qa_mcpToolItems{flex-direction:column;gap:0;min-width:0;max-height:300px;margin:4px 0 0;padding:0;list-style:none;display:flex;overflow-y:auto}._68Y4qa_mcpToolItem{border-bottom:.5px solid var(--dsw-alias-border-l2,var(--dsw-alias-border-secondary));flex-wrap:wrap;align-items:baseline;gap:4px 8px;padding:6px 0;display:flex}._68Y4qa_mcpToolItem:last-child{border-bottom:none}._68Y4qa_mcpToolName{font-family:var(--ds-font-family-code,monospace);color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));font-size:12px}._68Y4qa_mcpToolDesc{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));width:100%;font-size:12px;line-height:1.4}._68Y4qa_mcpAddForm{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));border-radius:16px;gap:14px;padding:16px;display:grid}._68Y4qa_mcpFormRow{grid-template-columns:1fr 1fr;gap:10px;display:grid}._68Y4qa_mcpFormActions{justify-content:flex-end;gap:8px;display:flex}@media (width<=560px){._68Y4qa_row{grid-template-columns:1fr;gap:4px}._68Y4qa_mcpFormRow{grid-template-columns:1fr}._68Y4qa_mcpFieldRow{grid-template-columns:1fr;gap:4px}}";
743
+ const css = "._68Y4qa_section{gap:20px;max-width:720px;display:grid}._68Y4qa_section header h2,._68Y4qa_card h3{color:var(--dsw-alias-text-primary);margin:0}._68Y4qa_section header p,._68Y4qa_card p{color:var(--dsw-alias-label-secondary)}._68Y4qa_card{border:1px solid var(--dsw-alias-border-subtle);border-radius:12px;padding:18px}._68Y4qa_card dl{margin:12px 0}._68Y4qa_row{border-bottom:1px solid var(--dsw-alias-border-secondary);grid-template-columns:minmax(150px,1fr) minmax(0,2fr);gap:16px;padding:8px 0;display:grid}._68Y4qa_row:last-child{border-bottom:0}._68Y4qa_row dt{color:var(--dsw-alias-label-secondary)}._68Y4qa_row dd{overflow-wrap:anywhere;color:var(--dsw-alias-text-primary);margin:0}._68Y4qa_actions{flex-wrap:wrap;align-items:center;gap:12px;display:flex}._68Y4qa_actions a{color:var(--dsw-alias-brand-primary)}._68Y4qa_status{align-items:center;gap:8px;display:flex}._68Y4qa_capabilities{margin:0;padding-left:18px}._68Y4qa_notice{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));font-size:13px}._68Y4qa_error{word-break:break-word;overflow-wrap:anywhere;font-size:13px;color:var(--dsw-alias-state-error-primary)!important}._68Y4qa_select{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-background-primary));color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));height:34px;font:inherit;appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23999' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 10px center;background-repeat:no-repeat;border-radius:8px;padding:0 28px 0 10px;font-size:13px;line-height:1.5}._68Y4qa_select:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}._68Y4qa_input{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-background-primary));color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));height:34px;font:inherit;box-sizing:border-box;border-radius:8px;width:100%;padding:0 12px;font-size:13px;line-height:1.5}._68Y4qa_input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}._68Y4qa_mcpList{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}._68Y4qa_mcpCard{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));background:var(--dsw-alias-bg-layer-3,transparent);border-radius:16px;list-style:none;transition:border-color .16s,background .16s}._68Y4qa_mcpCard:hover{border-color:var(--dsw-alias-label-dimmed,#bbb)}._68Y4qa_mcpCardOpen{background:var(--dsw-alias-bg-layer-2,transparent);border-color:var(--dsw-alias-label-dimmed,#bbb)}._68Y4qa_mcpCardHeader{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}._68Y4qa_mcpCardHeader:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}._68Y4qa_mcpAvatar{background:var(--dsw-alias-brand-background,#eef2fe);width:32px;height:32px;color:var(--dsw-alias-brand-primary);border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;font-size:14px;font-weight:600;display:flex}._68Y4qa_mcpCardTitleGroup{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}._68Y4qa_mcpCardName{color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));margin:0;font-size:15px;font-weight:600;line-height:1.4}._68Y4qa_mcpCardSub{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));align-items:center;gap:8px;margin:0;font-size:13px;line-height:1.5;display:flex}._68Y4qa_mcpChevron{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));flex:none;transition:transform .16s}._68Y4qa_mcpChevronOpen{transform:rotate(180deg)}._68Y4qa_mcpChevron svg{display:block}._68Y4qa_mcpBadge{border-radius:4px;padding:1px 6px;font-size:11px;font-weight:500}._68Y4qa_mcpBadge[data-status=connected]{background:var(--dsw-alias-state-success-background,#ecfdf3);color:var(--dsw-alias-state-success-primary,#16a34a)}._68Y4qa_mcpBadge[data-status=error]{background:var(--dsw-alias-state-error-background,#fff0f0);color:var(--dsw-alias-state-error-primary,#dc2626)}._68Y4qa_mcpBadge[data-status=needs_reauth]{background:var(--dsw-alias-state-warning-background,#fff8e6);color:var(--dsw-alias-state-warning-primary,#d97706)}._68Y4qa_mcpBadge[data-status=unknown]{background:var(--dsw-alias-background-secondary,#f3f4f6);color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary))}._68Y4qa_mcpCardBody{border-top:.5px solid var(--dsw-alias-border-l2,var(--dsw-alias-border-secondary));gap:12px;min-width:0;margin:0 16px;padding:12px 0 8px;display:grid}._68Y4qa_mcpFieldRow{grid-template-columns:140px 1fr;align-items:center;gap:12px;display:grid}._68Y4qa_mcpFieldLabel{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));font-size:13px;line-height:1.5}._68Y4qa_mcpFieldValue{color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));font-size:13px;line-height:1.5}._68Y4qa_mcpCardSuccess{color:var(--dsw-alias-state-success-primary,#16a34a);margin:0;padding:4px 0;font-size:12px;line-height:1.4}._68Y4qa_mcpCardError{color:var(--dsw-alias-state-error-primary,#dc2626);margin:0;padding:4px 0;font-size:12px;line-height:1.4}._68Y4qa_mcpCardActions{border-top:.5px solid var(--dsw-alias-border-l2,var(--dsw-alias-border-secondary));justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}._68Y4qa_mcpAddTrigger{appearance:none;width:100%;font:inherit;cursor:pointer;border:.5px dashed var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));background:0 0;border-radius:16px;justify-content:center;align-items:center;gap:6px;padding:14px 16px;font-size:13px;line-height:1.5;transition:border-color .16s,color .16s;display:flex}._68Y4qa_mcpAddTrigger:hover{border-color:var(--dsw-alias-label-dimmed,#bbb);color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary))}._68Y4qa_mcpAddTrigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}._68Y4qa_mcpToolList{flex-direction:column;gap:6px;display:flex}._68Y4qa_mcpToolItems{flex-direction:column;gap:0;min-width:0;max-height:300px;margin:4px 0 0;padding:0;list-style:none;display:flex;overflow-y:auto}._68Y4qa_mcpToolItem{border-bottom:.5px solid var(--dsw-alias-border-l2,var(--dsw-alias-border-secondary));flex-wrap:wrap;align-items:baseline;gap:4px 8px;padding:6px 0;display:flex}._68Y4qa_mcpToolItem:last-child{border-bottom:none}._68Y4qa_mcpToolName{font-family:var(--ds-font-family-code,monospace);color:var(--dsw-alias-label-primary,var(--dsw-alias-text-primary));font-size:12px}._68Y4qa_mcpToolDesc{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));width:100%;font-size:12px;line-height:1.4}._68Y4qa_mcpAddForm{border:.5px solid var(--dsw-alias-border-l4,var(--dsw-alias-border-subtle));border-radius:16px;gap:14px;padding:16px;display:grid}._68Y4qa_mcpFormRow{grid-template-columns:1fr 1fr;gap:10px;display:grid}._68Y4qa_mcpFormActions{justify-content:flex-end;gap:8px;display:flex}@media (width<=560px){._68Y4qa_row{grid-template-columns:1fr;gap:4px}._68Y4qa_mcpFormRow{grid-template-columns:1fr}._68Y4qa_mcpFieldRow{grid-template-columns:1fr;gap:4px}}._68Y4qa_pluginSettings{gap:16px;max-width:720px;display:grid}._68Y4qa_pluginSettingsEmpty{color:var(--dsw-alias-label-secondary)}";
743
744
  const tagId = "dsh-edge-client-ui/src/client/EdgeSettingsSection.module.css";
744
745
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
745
746
  const tag = document.createElement("style");
@@ -782,6 +783,8 @@ window.__ModuleLoader__.load({
782
783
  "mcpToolList": "_68Y4qa_mcpToolList",
783
784
  "mcpToolName": "_68Y4qa_mcpToolName",
784
785
  "notice": "_68Y4qa_notice",
786
+ "pluginSettings": "_68Y4qa_pluginSettings",
787
+ "pluginSettingsEmpty": "_68Y4qa_pluginSettingsEmpty",
785
788
  "row": "_68Y4qa_row",
786
789
  "section": "_68Y4qa_section",
787
790
  "select": "_68Y4qa_select",
@@ -1589,6 +1592,27 @@ window.__ModuleLoader__.load({
1589
1592
  });
1590
1593
  }
1591
1594
  //#endregion
1595
+ //#region ../../../packages/client/ui-edge/src/client/EdgePluginSettingsTab.tsx
1596
+ function EdgePluginSettingsTab({ t, renderSlot, usePluginSettingsItems }) {
1597
+ const items = usePluginSettingsItems((value) => value);
1598
+ if (items.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1599
+ className: EdgeSettingsSection_module_css_default.pluginSettingsEmpty,
1600
+ children: t("pluginSettingsEmpty")
1601
+ });
1602
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1603
+ className: EdgeSettingsSection_module_css_default.pluginSettings,
1604
+ children: items.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1605
+ className: EdgeSettingsSection_module_css_default.card,
1606
+ "data-plugin-item": item.id,
1607
+ children: [
1608
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: item.label }),
1609
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: renderSlot("plugins.item", { view: "summary" }, { only: item.id }) }),
1610
+ renderSlot("plugins.item", { view: "page" }, { only: item.id })
1611
+ ]
1612
+ }, item.id))
1613
+ });
1614
+ }
1615
+ //#endregion
1592
1616
  //#region ../../../packages/client/ui-edge/src/client/locales.ts
1593
1617
  /** English copy is the key-set source of truth for the Edge settings page. */
1594
1618
  const en = {
@@ -1696,7 +1720,9 @@ window.__ModuleLoader__.load({
1696
1720
  mcpProbing: "Refreshing…",
1697
1721
  mcpToolsLabel: "Tools",
1698
1722
  mcpRead: "read",
1699
- mcpWrite: "write"
1723
+ mcpWrite: "write",
1724
+ pluginSettingsTab: "Settings",
1725
+ pluginSettingsEmpty: "No built-in plugin offers settings on this deployment."
1700
1726
  };
1701
1727
  /** Simplified Chinese copy for the Edge settings page. */
1702
1728
  const zh = {
@@ -1804,10 +1830,41 @@ window.__ModuleLoader__.load({
1804
1830
  mcpProbing: "刷新中…",
1805
1831
  mcpToolsLabel: "工具",
1806
1832
  mcpRead: "读取",
1807
- mcpWrite: "写入"
1833
+ mcpWrite: "写入",
1834
+ pluginSettingsTab: "设置",
1835
+ pluginSettingsEmpty: "本部署没有可配置的内置插件。"
1808
1836
  };
1809
1837
  //#endregion
1810
1838
  //#region ../../../packages/client/ui-edge/src/client/index.ts
1839
+ /** The `plugins.item` cards as the settings tab lists them, re-read when the slot ledger or locale moves. */
1840
+ function pluginSettingsItems(ctx, slots) {
1841
+ let version = -1;
1842
+ let revision;
1843
+ let items = [];
1844
+ return {
1845
+ getSnapshot: () => {
1846
+ const nextVersion = slots.getVersion("plugins.item");
1847
+ const nextRevision = ctx.locale.getSnapshot().revision;
1848
+ if (nextVersion !== version || nextRevision !== revision) {
1849
+ version = nextVersion;
1850
+ revision = nextRevision;
1851
+ items = slots.entries("plugins.item").map((entry) => ({
1852
+ id: entry.options.id ?? "",
1853
+ label: (0, _deepseek_ai_dsh_client_ui_slots.resolveSlotLabel)(entry.options.label) ?? ""
1854
+ }));
1855
+ }
1856
+ return items;
1857
+ },
1858
+ subscribe: (listener) => {
1859
+ const offSlots = slots.subscribe("plugins.item", listener);
1860
+ const offLocale = ctx.locale.subscribe(listener);
1861
+ return () => {
1862
+ offSlots();
1863
+ offLocale();
1864
+ };
1865
+ }
1866
+ };
1867
+ }
1811
1868
  const inject = ["slots", "locale"];
1812
1869
  function apply(ctx) {
1813
1870
  const slots = ctx.slots;
@@ -1852,6 +1909,19 @@ window.__ModuleLoader__.load({
1852
1909
  locale: "settings.edge",
1853
1910
  inject: edgeInjected
1854
1911
  }, EdgeSettingsSection));
1912
+ const pluginSettingsInjected = () => ({ hooks: { pluginSettingsItems: pluginSettingsItems(ctx, slots) } });
1913
+ slots.inject("settings.plugins.tab", () => slots.register({
1914
+ name: "settings.plugins.tab",
1915
+ id: "edge-plugin-settings",
1916
+ order: 20,
1917
+ label: () => ctx.locale.bind("settings.edge")("pluginSettingsTab"),
1918
+ locale: "settings.edge",
1919
+ inject: pluginSettingsInjected,
1920
+ children: { "plugins.item": {
1921
+ kind: "list",
1922
+ scope: "root"
1923
+ } }
1924
+ }, EdgePluginSettingsTab));
1855
1925
  slots.inject("settings.section", () => slots.register({
1856
1926
  name: "settings.section",
1857
1927
  id: "mcp-connectors",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-edge",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Your DeepSeek Harness, anywhere — deploy a persistent personal coding agent to Cloudflare Workers in one command",
5
5
  "author": "pawaca",
6
6
  "license": "MIT",
@@ -79,6 +79,8 @@
79
79
  "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2",
80
80
  "@deepseek-ai/dsh-client-ui-settings-general": "0.2.0-rc.2",
81
81
  "@deepseek-ai/dsh-client-ui-theme": "0.2.0-rc.2",
82
+ "@deepseek-ai/dsh-command-compact": "0.2.0-rc.2",
83
+ "@deepseek-ai/dsh-command-goal": "0.2.0-rc.2",
82
84
  "@deepseek-ai/dsh-commands": "0.2.0-rc.2",
83
85
  "@deepseek-ai/dsh-compaction": "0.2.0-rc.2",
84
86
  "@deepseek-ai/dsh-compaction-basic": "0.2.0-rc.2",
@@ -119,6 +121,7 @@
119
121
  "@deepseek-ai/dsh-session-persistence": "0.2.0-rc.2",
120
122
  "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2",
121
123
  "@deepseek-ai/dsh-session-projection-cache": "0.2.0-rc.2",
124
+ "@deepseek-ai/dsh-session-stats": "0.2.0-rc.2",
122
125
  "@deepseek-ai/dsh-session-query": "0.2.0-rc.2",
123
126
  "@deepseek-ai/dsh-session-reference": "0.2.0-rc.2",
124
127
  "@deepseek-ai/dsh-session-title": "0.2.0-rc.2",
@@ -144,6 +147,7 @@
144
147
  "@deepseek-ai/dsh-tool-jobs": "0.2.0-rc.2",
145
148
  "@deepseek-ai/dsh-tool-skill": "0.2.0-rc.2",
146
149
  "@deepseek-ai/dsh-tool-subagent": "0.2.0-rc.2",
150
+ "@deepseek-ai/dsh-tool-present": "0.2.0-rc.2",
147
151
  "@deepseek-ai/dsh-tool-todo": "0.2.0-rc.2",
148
152
  "@deepseek-ai/dsh-tool-web": "0.2.0-rc.2",
149
153
  "@deepseek-ai/dsh-tool-workflow": "0.2.0-rc.2",