dsh-web-search-enhanced 0.2.0 → 0.2.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.cjs CHANGED
@@ -33,7 +33,11 @@ window.__ModuleLoader__.load({
33
33
  const SEARCH = {
34
34
  packageName: "dsh-web-search-enhanced",
35
35
  rowId: "web-search-enhanced",
36
- providerId: "search-enhanced"
36
+ providerId: "search-enhanced",
37
+ tools: {
38
+ action: "web_search_enhanced",
39
+ list: "list_web_search_providers"
40
+ }
37
41
  };
38
42
  /**
39
43
  * Key of a row's configuration page on the Plugins page (`plugins.row.config`).
@@ -151,6 +155,7 @@ window.__ModuleLoader__.load({
151
155
  "version",
152
156
  "defaultConnection",
153
157
  "showSelector",
158
+ "enhancedTools",
154
159
  "defaults",
155
160
  "connections"
156
161
  ];
@@ -193,8 +198,16 @@ window.__ModuleLoader__.load({
193
198
  }
194
199
  return result;
195
200
  }
201
+ /**
202
+ * Operator text shown as one line (a label in menus, error messages and the
203
+ * Agent's provider list): control characters and line or paragraph separators
204
+ * become spaces, runs of whitespace one space, the ends trimmed.
205
+ */
206
+ function singleLine(value) {
207
+ return value.replaceAll(/[\p{Cc}\p{Zl}\p{Zp}]/gu, " ").replaceAll(/\s+/gu, " ").trim();
208
+ }
196
209
  const text = zod.z.string().trim().min(1).max(TEXT_MAX_LENGTH);
197
- const label = zod.z.string().trim().min(1).max(200);
210
+ const label = zod.z.string().transform(singleLine).pipe(zod.z.string().min(1).max(200));
198
211
  const credentialRef = text.regex(CREDENTIAL_REF, "must be a credential reference such as EXA_API_KEY");
199
212
  const endpoint = text.refine(isEndpoint, "must be an absolute http(s) URL without credentials, query or fragment");
200
213
  const options = zod.z.record(zod.z.string(), zod.z.unknown());
@@ -203,6 +216,7 @@ window.__ModuleLoader__.load({
203
216
  version: zod.z.literal(currentVersion).optional(),
204
217
  defaultConnection: zod.z.string().min(1).max(200).optional(),
205
218
  showSelector: zod.z.boolean().optional(),
219
+ enhancedTools: zod.z.boolean().optional(),
206
220
  defaults: defaults.optional(),
207
221
  connections: zod.z.record(zod.z.string().max(200), zod.z.unknown()).refine((value) => Object.keys(value).length <= 200, "must contain at most 200 connections").optional()
208
222
  });
@@ -264,7 +278,7 @@ window.__ModuleLoader__.load({
264
278
  const customSchema = customConnectionSchema(adapterKeys, protocolKeys);
265
279
  const connections = /* @__PURE__ */ new Map();
266
280
  const rejectId = (id, path) => fail(path, "unknown connection id \"" + id + "\"; this release does not read 0.1.x settings; remove the field or use Reset on the settings page");
267
- const resolve = (id, key, override, customEndpoint) => {
281
+ const resolve = (id, key, override, origin) => {
268
282
  const info = catalog[key];
269
283
  const path = "connections." + id;
270
284
  const access = info.kind === "model" ? "api-key" : override.access ?? defaultAccess(info.access);
@@ -276,11 +290,12 @@ window.__ModuleLoader__.load({
276
290
  if (problems.length > 0) fail(path + ".options", problems.join("; ") + "; this release does not read 0.1.x settings; remove the field or use Reset on the settings page");
277
291
  const trustedEndpoint = override.trustedEndpoint ?? false;
278
292
  for (const [name, rule] of Object.entries(info.options)) if (rule.kind === "url" && values[name] !== void 0 && values[name] !== info.endpoint && !trustedEndpoint) fail(path + ".trustedEndpoint", "a non-official " + name + " needs trustedEndpoint: true");
293
+ const disabled = override.disabled ?? (origin.kind === "builtin" ? info.optIn : false);
279
294
  const base = {
280
295
  id,
281
296
  catalogKey: key,
282
297
  label: override.label ?? info.label,
283
- disabled: override.disabled ?? false,
298
+ disabled,
284
299
  remote: info.remote,
285
300
  trustedEndpoint,
286
301
  options: values
@@ -297,7 +312,7 @@ window.__ModuleLoader__.load({
297
312
  };
298
313
  if (info.kind !== "native" && info.kind !== "adapter") return fail(path + ".kind", "unsupported catalog kind");
299
314
  if (!info.access.apiKey || info.endpoint === void 0) return fail(path, "remote catalog entry needs credentials and an endpoint");
300
- const url = customEndpoint ?? info.endpoint;
315
+ const url = origin.kind === "custom" && origin.endpoint !== void 0 ? origin.endpoint : info.endpoint;
301
316
  if (url !== info.endpoint && !trustedEndpoint) fail(path + ".trustedEndpoint", "a custom endpoint needs trustedEndpoint: true");
302
317
  return {
303
318
  ...base,
@@ -318,7 +333,7 @@ window.__ModuleLoader__.load({
318
333
  ]) if (Object.hasOwn(raw, field)) fail("connections." + id + "." + field, "this connection takes its route from the Session model");
319
334
  }
320
335
  const override = raw === void 0 ? {} : parse(builtinOverrideSchema, raw, "connections." + id);
321
- connections.set(id, resolve(id, key, override));
336
+ connections.set(id, resolve(id, key, override, { kind: "builtin" }));
322
337
  }
323
338
  for (const [id, raw] of Object.entries(overrides)) {
324
339
  if (connections.has(id)) continue;
@@ -328,7 +343,10 @@ window.__ModuleLoader__.load({
328
343
  if (custom.kind === "adapter") connections.set(id, resolve(id, custom.adapter, {
329
344
  ...custom,
330
345
  access: "api-key"
331
- }, custom.endpoint));
346
+ }, {
347
+ kind: "custom",
348
+ endpoint: custom.endpoint
349
+ }));
332
350
  else {
333
351
  const info = protocols[custom.protocol];
334
352
  const values = custom.options ?? {};
@@ -359,6 +377,7 @@ window.__ModuleLoader__.load({
359
377
  version: migrations.currentVersion,
360
378
  defaultConnection,
361
379
  showSelector: settings.showSelector ?? true,
380
+ enhancedTools: settings.enhancedTools ?? false,
362
381
  defaults: settings.defaults ?? parse(defaults.schema, {}, "defaults"),
363
382
  connections
364
383
  };
@@ -800,6 +819,7 @@ window.__ModuleLoader__.load({
800
819
  const MODEL_PROTOCOLS = {
801
820
  "anthropic-messages": {
802
821
  label: "Anthropic Messages",
822
+ use: "the model searches and answers",
803
823
  options: {
804
824
  maxTokens,
805
825
  anthropicTool,
@@ -815,6 +835,7 @@ window.__ModuleLoader__.load({
815
835
  },
816
836
  "openai-responses": {
817
837
  label: "OpenAI Responses",
838
+ use: "the model searches and answers",
818
839
  options: {
819
840
  maxTokens,
820
841
  responsesTool,
@@ -828,6 +849,7 @@ window.__ModuleLoader__.load({
828
849
  },
829
850
  "openai-chat-completions": {
830
851
  label: "OpenAI Chat Completions",
852
+ use: "the model searches and answers",
831
853
  options: {
832
854
  maxTokens,
833
855
  searchContextSize,
@@ -847,6 +869,8 @@ window.__ModuleLoader__.load({
847
869
  label: "DeepSeek Messages",
848
870
  kind: "native",
849
871
  remote: true,
872
+ optIn: false,
873
+ use: "answers with a summary and sources",
850
874
  endpoint: "https://api.deepseek.com/anthropic/v1",
851
875
  homepage: "https://platform.deepseek.com",
852
876
  access: nativeAccess,
@@ -877,6 +901,7 @@ window.__ModuleLoader__.load({
877
901
  label: "DeepSeek Search API",
878
902
  kind: "native",
879
903
  remote: true,
904
+ optIn: true,
880
905
  endpoint: "https://api.deepseek.com/v1/tools",
881
906
  homepage: "https://platform.deepseek.com",
882
907
  access: nativeAccess,
@@ -895,6 +920,8 @@ window.__ModuleLoader__.load({
895
920
  label: "Session model",
896
921
  kind: "model",
897
922
  remote: true,
923
+ optIn: false,
924
+ use: "the session model searches and answers",
898
925
  access: {
899
926
  keyless: false,
900
927
  apiKey: false,
@@ -914,6 +941,7 @@ window.__ModuleLoader__.load({
914
941
  },
915
942
  kind: "adapter",
916
943
  remote: true,
944
+ optIn: true,
917
945
  freshness: ["api-key"],
918
946
  homepage: "https://exa.ai",
919
947
  options: { type: {
@@ -936,6 +964,7 @@ window.__ModuleLoader__.load({
936
964
  },
937
965
  kind: "adapter",
938
966
  remote: true,
967
+ optIn: true,
939
968
  freshness: ["keyless", "api-key"],
940
969
  homepage: "https://www.firecrawl.dev",
941
970
  options: {
@@ -961,6 +990,7 @@ window.__ModuleLoader__.load({
961
990
  },
962
991
  kind: "adapter",
963
992
  remote: true,
993
+ optIn: true,
964
994
  freshness: [],
965
995
  homepage: "https://www.tavily.com",
966
996
  options: {
@@ -993,6 +1023,7 @@ window.__ModuleLoader__.load({
993
1023
  },
994
1024
  kind: "adapter",
995
1025
  remote: true,
1026
+ optIn: true,
996
1027
  freshness: [],
997
1028
  homepage: "https://www.tinyfish.ai",
998
1029
  options: {
@@ -1029,8 +1060,10 @@ window.__ModuleLoader__.load({
1029
1060
  },
1030
1061
  kind: "adapter",
1031
1062
  remote: true,
1063
+ optIn: true,
1032
1064
  freshness: [],
1033
1065
  homepage: "https://openalex.org",
1066
+ use: "scholarly works (papers, citations); keyword queries",
1034
1067
  options: {
1035
1068
  sort: {
1036
1069
  kind: "text",
@@ -1059,8 +1092,10 @@ window.__ModuleLoader__.load({
1059
1092
  },
1060
1093
  kind: "adapter",
1061
1094
  remote: true,
1095
+ optIn: true,
1062
1096
  freshness: [],
1063
1097
  homepage: "https://www.semanticscholar.org/product/api",
1098
+ use: "academic papers (citations, TL;DR); keyword queries",
1064
1099
  options: {
1065
1100
  year: {
1066
1101
  kind: "text",
@@ -1106,6 +1141,378 @@ window.__ModuleLoader__.load({
1106
1141
  return (0, react.useSyncExternalStore)(subscribe, getSnapshot);
1107
1142
  }
1108
1143
  //#endregion
1144
+ //#region ../core/src/client/settings/parts.tsx
1145
+ /** Building blocks shared by the settings sections. */
1146
+ function classNames(...args) {
1147
+ return args.flat(Number.POSITIVE_INFINITY).filter(Boolean).map((arg) => {
1148
+ if (typeof arg === "string") return arg;
1149
+ if (typeof arg === "object" && arg !== null) return Object.entries(arg).filter(([, v]) => Boolean(v)).map(([k]) => k).join(" ");
1150
+ return "";
1151
+ }).filter(Boolean).join(" ");
1152
+ }
1153
+ /** A local schema failure whose diagnostic stays out of the translated message. */
1154
+ var SettingsValidationError = class extends Error {};
1155
+ function createSettingsParts({ classes: css, keys }) {
1156
+ /** `titleId` lets a control inside name itself by the section title. */
1157
+ function Section({ title, titleId, actions, children }) {
1158
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1159
+ className: css.section,
1160
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1161
+ className: css.sectionHead,
1162
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
1163
+ id: titleId,
1164
+ className: css.sectionTitle,
1165
+ children: title
1166
+ }), actions]
1167
+ }), children]
1168
+ });
1169
+ }
1170
+ /** Title and hint on the left, one control on the right; wraps under the text on narrow pages. */
1171
+ function SettingRow({ title, hint, children }) {
1172
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1173
+ className: css.settingRow,
1174
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1175
+ className: css.settingText,
1176
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1177
+ className: css.settingTitle,
1178
+ children: title
1179
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1180
+ className: css.hint,
1181
+ children: hint
1182
+ })]
1183
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1184
+ className: css.settingControl,
1185
+ children
1186
+ })]
1187
+ });
1188
+ }
1189
+ /** A dropdown in the settings pill style, built on the shared Menu. */
1190
+ function SelectMenu({ label, title, value, options, disabled, onChange, compact = false }) {
1191
+ const [open, setOpen] = (0, react.useState)(false);
1192
+ const current = options.find((option) => option.id === value);
1193
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
1194
+ open,
1195
+ onClose: () => {
1196
+ setOpen(false);
1197
+ },
1198
+ items: options.map((option) => ({
1199
+ id: option.id,
1200
+ label: option.label
1201
+ })),
1202
+ selectedId: value,
1203
+ onSelect: (id) => {
1204
+ setOpen(false);
1205
+ if (id !== value) onChange(id);
1206
+ },
1207
+ align: "end",
1208
+ portal: true,
1209
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1210
+ type: "button",
1211
+ className: compact ? css.selectCompact : css.select,
1212
+ "aria-label": label,
1213
+ title,
1214
+ "aria-haspopup": "menu",
1215
+ "aria-expanded": open,
1216
+ disabled,
1217
+ onClick: () => {
1218
+ setOpen(!open);
1219
+ },
1220
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1221
+ className: css.selectValue,
1222
+ children: current?.label ?? value
1223
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: css.selectChevron })]
1224
+ })
1225
+ });
1226
+ }
1227
+ /** Pending state and the last failure of one section's writes. */
1228
+ function useWrite(t) {
1229
+ const [state, setState] = (0, react.useState)({
1230
+ busy: false,
1231
+ error: void 0,
1232
+ errorTitle: void 0
1233
+ });
1234
+ const run = async (work) => {
1235
+ setState({
1236
+ busy: true,
1237
+ error: void 0,
1238
+ errorTitle: void 0
1239
+ });
1240
+ try {
1241
+ const accepted = await work();
1242
+ setState({
1243
+ busy: false,
1244
+ error: accepted ? void 0 : t(keys.refused),
1245
+ errorTitle: void 0
1246
+ });
1247
+ return accepted;
1248
+ } catch (error) {
1249
+ const message = error instanceof Error ? error.message : String(error);
1250
+ const invalid = error instanceof SettingsValidationError;
1251
+ setState({
1252
+ busy: false,
1253
+ error: invalid ? t(keys.invalid) : message || t(keys.failed),
1254
+ errorTitle: invalid ? message : void 0
1255
+ });
1256
+ return false;
1257
+ }
1258
+ };
1259
+ return {
1260
+ ...state,
1261
+ run
1262
+ };
1263
+ }
1264
+ function ErrorText({ children, title }) {
1265
+ return children === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1266
+ className: css.error,
1267
+ role: "alert",
1268
+ title,
1269
+ children
1270
+ });
1271
+ }
1272
+ /** Inline confirmation of a destructive action: the question beside cancel and confirm. */
1273
+ function ConfirmRow({ message, confirmLabel, cancelLabel, disabled, onConfirm, onCancel }) {
1274
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1275
+ className: css.confirmRow,
1276
+ role: "group",
1277
+ "aria-label": message,
1278
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1279
+ className: css.confirmText,
1280
+ children: message
1281
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1282
+ className: css.actions,
1283
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1284
+ variant: "ghost",
1285
+ size: "sm",
1286
+ onClick: onCancel,
1287
+ children: cancelLabel
1288
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1289
+ variant: "outline",
1290
+ size: "sm",
1291
+ className: css.danger,
1292
+ disabled,
1293
+ onClick: onConfirm,
1294
+ children: confirmLabel
1295
+ })]
1296
+ })]
1297
+ });
1298
+ }
1299
+ return {
1300
+ Section,
1301
+ SettingRow,
1302
+ SelectMenu,
1303
+ ErrorText,
1304
+ ConfirmRow,
1305
+ useWrite
1306
+ };
1307
+ }
1308
+ function applyOps(user, ops) {
1309
+ const root = structuredClone(user !== null && typeof user === "object" && !Array.isArray(user) ? user : {});
1310
+ for (const op of ops) {
1311
+ if (op.path.length === 0) continue;
1312
+ if (op.op === "set") {
1313
+ let current = root;
1314
+ for (let i = 0; i < op.path.length - 1; i++) {
1315
+ const seg = op.path[i];
1316
+ if (current[seg] === null || typeof current[seg] !== "object" || Array.isArray(current[seg])) current[seg] = {};
1317
+ current = current[seg];
1318
+ }
1319
+ current[op.path.at(-1)] = structuredClone(op.value);
1320
+ } else if (op.op === "unset") {
1321
+ let current = root;
1322
+ for (let i = 0; i < op.path.length - 1; i++) {
1323
+ const seg = op.path[i];
1324
+ if (current[seg] === null || typeof current[seg] !== "object" || Array.isArray(current[seg])) break;
1325
+ current = current[seg];
1326
+ }
1327
+ delete current[op.path.at(-1)];
1328
+ }
1329
+ }
1330
+ return root;
1331
+ }
1332
+ //#endregion
1333
+ //#region ../core/src/client/settings/document.ts
1334
+ /** ConfigForm.value is schema-projected; the raw layers retain unknown fields for validation. */
1335
+ function effectiveDocument(snapshot) {
1336
+ return merge(snapshot.base, snapshot.user);
1337
+ }
1338
+ /** Validate before exposing normal editors; only successful older migrations need writeback. */
1339
+ function editableSettings(raw, layers, writable, resolve, migrations = SETTINGS_MIGRATIONS) {
1340
+ try {
1341
+ const version = documentVersion$2(raw, migrations.currentVersion);
1342
+ const config = migrateDocument(raw, migrations);
1343
+ resolve(config);
1344
+ return {
1345
+ kind: "ready",
1346
+ config,
1347
+ layers,
1348
+ needsWriteback: writable && version.kind === "older"
1349
+ };
1350
+ } catch (error) {
1351
+ return {
1352
+ kind: "invalid",
1353
+ diagnostic: diagnostic(error),
1354
+ layers,
1355
+ needsWriteback: false
1356
+ };
1357
+ }
1358
+ }
1359
+ /** Check the exact recursively overlaid candidate that the settings store will persist. */
1360
+ function settingsOperations(layers, operations, resolve) {
1361
+ try {
1362
+ const candidate = effectiveDocument({
1363
+ base: layers.base,
1364
+ user: applyOps(layers.user, operations)
1365
+ });
1366
+ const result = [...operations];
1367
+ if (result.some((op) => op.op === "set") && candidate.version === void 0) {
1368
+ result.push({
1369
+ op: "set",
1370
+ path: ["version"],
1371
+ value: 2
1372
+ });
1373
+ candidate.version = 2;
1374
+ }
1375
+ resolve(candidate);
1376
+ return result;
1377
+ } catch (error) {
1378
+ throw new SettingsValidationError(diagnostic(error));
1379
+ }
1380
+ }
1381
+ /**
1382
+ * Share validation, revision fencing and automatic future migrations between both pages.
1383
+ * @param snapshot - the settings snapshot the page renders.
1384
+ * @param read - the settings snapshot now, which a write the form accepted has already updated.
1385
+ */
1386
+ function useSettingsDocument(snapshot, read, resolve, mutate, migrations = SETTINGS_MIGRATIONS) {
1387
+ const view = (0, react.useMemo)(() => {
1388
+ if (snapshot.status === "unavailable" || snapshot.value === void 0 || snapshot.revision === void 0) return void 0;
1389
+ const result = editableSettings(effectiveDocument(snapshot), {
1390
+ base: snapshot.base,
1391
+ user: snapshot.user
1392
+ }, snapshot.writable, resolve, migrations);
1393
+ if (snapshot.diagnostic === void 0) return result;
1394
+ return {
1395
+ kind: "invalid",
1396
+ layers: result.layers,
1397
+ needsWriteback: false,
1398
+ diagnostic: result.kind === "invalid" ? result.diagnostic + "; " + snapshot.diagnostic : snapshot.diagnostic
1399
+ };
1400
+ }, [
1401
+ snapshot,
1402
+ resolve,
1403
+ migrations
1404
+ ]);
1405
+ const attemptedRevision = (0, react.useRef)(void 0);
1406
+ const [failure, setFailure] = (0, react.useState)();
1407
+ const revision = snapshot.revision;
1408
+ (0, react.useEffect)(() => {
1409
+ if (view?.kind !== "ready" || !view.needsWriteback || revision === void 0 || attemptedRevision.current === revision) return;
1410
+ attemptedRevision.current = revision;
1411
+ const writeback = async () => {
1412
+ try {
1413
+ const operations = replaceDocumentOperations(view.layers.user, view.config);
1414
+ await mutate(settingsOperations(view.layers, operations, resolve), revision);
1415
+ } catch (error) {
1416
+ setFailure({
1417
+ revision,
1418
+ diagnostic: diagnostic(error)
1419
+ });
1420
+ }
1421
+ };
1422
+ writeback();
1423
+ }, [
1424
+ view,
1425
+ revision,
1426
+ resolve,
1427
+ mutate
1428
+ ]);
1429
+ const queue = (0, react.useRef)(Promise.resolve());
1430
+ const submit = async (change, displayedRevision) => {
1431
+ if (typeof change !== "function") {
1432
+ if (change.length === 0) return true;
1433
+ if (view === void 0 || !snapshot.writable || displayedRevision === void 0) return false;
1434
+ return mutate(settingsOperations(view.layers, change, resolve), displayedRevision);
1435
+ }
1436
+ const current = read();
1437
+ if (current.status !== "ready" || !current.writable || current.revision === void 0) return false;
1438
+ const layers = {
1439
+ base: current.base,
1440
+ user: current.user
1441
+ };
1442
+ const operations = change(layers);
1443
+ if (operations.length === 0) return true;
1444
+ return mutate(settingsOperations(layers, operations, resolve), current.revision);
1445
+ };
1446
+ const write = (change, expectedRevision = revision) => {
1447
+ const task = queue.current.then(() => submit(change, expectedRevision));
1448
+ queue.current = task.then(() => {}, () => {});
1449
+ return task;
1450
+ };
1451
+ return {
1452
+ view,
1453
+ write,
1454
+ migrationError: failure?.revision === revision ? failure?.diagnostic : void 0
1455
+ };
1456
+ }
1457
+ function replaceDocumentOperations(user, document) {
1458
+ const operations = Object.keys(objectOf$1(user)).filter((key) => !Object.hasOwn(document, key)).map((key) => ({
1459
+ op: "unset",
1460
+ path: [key]
1461
+ }));
1462
+ for (const [key, value] of Object.entries(document)) operations.push({
1463
+ op: "set",
1464
+ path: [key],
1465
+ value
1466
+ });
1467
+ return operations;
1468
+ }
1469
+ function diagnostic(error) {
1470
+ return error instanceof Error ? error.message : String(error);
1471
+ }
1472
+ function isObject$1(value) {
1473
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1474
+ }
1475
+ function objectOf$1(value) {
1476
+ return isObject$1(value) ? value : {};
1477
+ }
1478
+ function merge(base, user) {
1479
+ const result = { ...objectOf$1(base) };
1480
+ for (const [key, value] of Object.entries(objectOf$1(user))) Object.defineProperty(result, key, {
1481
+ value: isObject$1(value) && isObject$1(result[key]) ? merge(result[key], value) : value,
1482
+ enumerable: true,
1483
+ writable: true,
1484
+ configurable: true
1485
+ });
1486
+ return result;
1487
+ }
1488
+ //#endregion
1489
+ //#region ../core/src/client/remote-services.ts
1490
+ /** Whether the catalog has remote services and every one of them is off. */
1491
+ function remoteServicesOff(catalog, resolved) {
1492
+ const remote = Object.keys(catalog).filter((key) => catalog[key].optIn);
1493
+ return remote.length > 0 && remote.every((key) => resolved.connections.get(builtinId(key)).disabled);
1494
+ }
1495
+ /** The fact for the current row settings, recomputed only when the settings snapshot changes. */
1496
+ function remoteServicesOffSource(settings, catalog, resolve) {
1497
+ let cached;
1498
+ const compute = (source) => {
1499
+ if (source.value === void 0) return false;
1500
+ const view = editableSettings(effectiveDocument(source), source, false, resolve);
1501
+ return view.kind === "ready" && remoteServicesOff(catalog, resolve(view.config));
1502
+ };
1503
+ return {
1504
+ getSnapshot() {
1505
+ const source = settings.getSnapshot();
1506
+ if (cached === void 0 || cached.source !== source) cached = {
1507
+ source,
1508
+ off: compute(source)
1509
+ };
1510
+ return cached.off;
1511
+ },
1512
+ subscribe: (listener) => settings.subscribe(listener)
1513
+ };
1514
+ }
1515
+ //#endregion
1109
1516
  //#region ../core/src/client/command.ts
1110
1517
  /** Shared ids cannot be shadowed by capability-specific option groups. */
1111
1518
  function parseSelectionCommandOption(id, parseOptions) {
@@ -1505,26 +1912,26 @@ window.__ModuleLoader__.load({
1505
1912
  };
1506
1913
  //#endregion
1507
1914
  //#region ../core/src/client/settings/sparse.ts
1508
- const objectOf$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
1509
- const isObject$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1915
+ const objectOf = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
1916
+ const isObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
1510
1917
  function equal(a, b) {
1511
1918
  if (Object.is(a, b)) return true;
1512
1919
  if (Array.isArray(a) || Array.isArray(b)) return Array.isArray(a) && Array.isArray(b) && a.length === b.length && a.every((value, index) => equal(value, b[index]));
1513
- if (!isObject$1(a) || !isObject$1(b)) return false;
1920
+ if (!isObject(a) || !isObject(b)) return false;
1514
1921
  const keys = Object.keys(a);
1515
1922
  return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && equal(a[key], b[key]));
1516
1923
  }
1517
1924
  /** Remove what an object value shares with its inherited counterpart, key by key. */
1518
1925
  function delta(value, inherited) {
1519
1926
  if (equal(value, inherited)) return void 0;
1520
- if (!isObject$1(value)) return value;
1521
- const base = objectOf$1(inherited);
1927
+ if (!isObject(value)) return value;
1928
+ const base = objectOf(inherited);
1522
1929
  return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, delta(child, base[key])]).filter(([, child]) => child !== void 0));
1523
1930
  }
1524
1931
  function documentVersion$1(layers) {
1525
1932
  return documentVersion$2({
1526
- ...objectOf$1(layers.base),
1527
- ...objectOf$1(layers.user)
1933
+ ...objectOf(layers.base),
1934
+ ...objectOf(layers.user)
1528
1935
  });
1529
1936
  }
1530
1937
  function assertCurrentVersion(layers) {
@@ -1541,240 +1948,53 @@ window.__ModuleLoader__.load({
1541
1948
  const inherited = valueAt(layers.base, path) ?? fallback;
1542
1949
  const user = valueAt(layers.user, path);
1543
1950
  const ops = [];
1544
- if (target === void 0 || equal(target, inherited)) {
1545
- if (user !== void 0) ops.push({
1546
- op: "unset",
1547
- path: prunedPath(layers.user, path)
1548
- });
1549
- } else {
1550
- const sparse = delta(target, inherited);
1551
- if (!equal(sparse, user)) ops.push({
1552
- op: "set",
1553
- path: [...path],
1554
- value: sparse
1555
- });
1556
- }
1557
- if (ops.some((op) => op.op === "set") && objectOf$1(layers.user).version !== spec.version) ops.push({
1558
- op: "set",
1559
- path: ["version"],
1560
- value: spec.version
1561
- });
1562
- return ops;
1563
- }
1564
- function valueAt(root, path) {
1565
- return path.reduce((value, key) => objectOf$1(value)[key], root);
1566
- }
1567
- /**
1568
- * The path to unset so no empty object stays behind: removing the only key of
1569
- * a user-layer object removes that object instead, up to a top-level field.
1570
- */
1571
- function prunedPath(user, path) {
1572
- let end = path.length;
1573
- while (end > 1 && Object.keys(objectOf$1(valueAt(user, path.slice(0, end - 1)))).length === 1) end -= 1;
1574
- return path.slice(0, end);
1575
- }
1576
- /** Unset every field this plugin stores in the user layer; inherited values and credentials stay. */
1577
- function resetSettingsOperations$1(layers) {
1578
- return Object.keys(objectOf$1(layers.user)).map((key) => ({
1579
- op: "unset",
1580
- path: [key]
1581
- }));
1582
- }
1583
- /** Bind the current document version and fields; no predecessor schema is inferred. */
1584
- function createSparseSettings(spec) {
1585
- return {
1586
- documentVersion: (layers) => documentVersion$1(layers),
1587
- sparseSettingOperations: (layers, path, target, fallback) => sparseSettingOperations$1(spec, layers, path, target, fallback),
1588
- resetSettingsOperations: (layers) => resetSettingsOperations$1(layers)
1589
- };
1590
- }
1591
- //#endregion
1592
- //#region ../core/src/client/settings/parts.tsx
1593
- /** Building blocks shared by the settings sections. */
1594
- function classNames(...args) {
1595
- return args.flat(Number.POSITIVE_INFINITY).filter(Boolean).map((arg) => {
1596
- if (typeof arg === "string") return arg;
1597
- if (typeof arg === "object" && arg !== null) return Object.entries(arg).filter(([, v]) => Boolean(v)).map(([k]) => k).join(" ");
1598
- return "";
1599
- }).filter(Boolean).join(" ");
1600
- }
1601
- /** A local schema failure whose diagnostic stays out of the translated message. */
1602
- var SettingsValidationError = class extends Error {};
1603
- function createSettingsParts({ classes: css, keys }) {
1604
- function Section({ title, actions, children }) {
1605
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1606
- className: css.section,
1607
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1608
- className: css.sectionHead,
1609
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
1610
- className: css.sectionTitle,
1611
- children: title
1612
- }), actions]
1613
- }), children]
1614
- });
1615
- }
1616
- /** Title and hint on the left, one control on the right; wraps under the text on narrow pages. */
1617
- function SettingRow({ title, hint, children }) {
1618
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1619
- className: css.settingRow,
1620
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1621
- className: css.settingText,
1622
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1623
- className: css.settingTitle,
1624
- children: title
1625
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1626
- className: css.hint,
1627
- children: hint
1628
- })]
1629
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1630
- className: css.settingControl,
1631
- children
1632
- })]
1633
- });
1634
- }
1635
- /** A dropdown in the settings pill style, built on the shared Menu. */
1636
- function SelectMenu({ label, title, value, options, disabled, onChange, compact = false }) {
1637
- const [open, setOpen] = (0, react.useState)(false);
1638
- const current = options.find((option) => option.id === value);
1639
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
1640
- open,
1641
- onClose: () => {
1642
- setOpen(false);
1643
- },
1644
- items: options.map((option) => ({
1645
- id: option.id,
1646
- label: option.label
1647
- })),
1648
- selectedId: value,
1649
- onSelect: (id) => {
1650
- setOpen(false);
1651
- if (id !== value) onChange(id);
1652
- },
1653
- align: "end",
1654
- portal: true,
1655
- anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1656
- type: "button",
1657
- className: compact ? css.selectCompact : css.select,
1658
- "aria-label": label,
1659
- title,
1660
- "aria-haspopup": "menu",
1661
- "aria-expanded": open,
1662
- disabled,
1663
- onClick: () => {
1664
- setOpen(!open);
1665
- },
1666
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1667
- className: css.selectValue,
1668
- children: current?.label ?? value
1669
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: css.selectChevron })]
1670
- })
1671
- });
1672
- }
1673
- /** Pending state and the last failure of one section's writes. */
1674
- function useWrite(t) {
1675
- const [state, setState] = (0, react.useState)({
1676
- busy: false,
1677
- error: void 0,
1678
- errorTitle: void 0
1679
- });
1680
- const run = async (work) => {
1681
- setState({
1682
- busy: true,
1683
- error: void 0,
1684
- errorTitle: void 0
1685
- });
1686
- try {
1687
- const accepted = await work();
1688
- setState({
1689
- busy: false,
1690
- error: accepted ? void 0 : t(keys.refused),
1691
- errorTitle: void 0
1692
- });
1693
- return accepted;
1694
- } catch (error) {
1695
- const message = error instanceof Error ? error.message : String(error);
1696
- const invalid = error instanceof SettingsValidationError;
1697
- setState({
1698
- busy: false,
1699
- error: invalid ? t(keys.invalid) : message || t(keys.failed),
1700
- errorTitle: invalid ? message : void 0
1701
- });
1702
- return false;
1703
- }
1704
- };
1705
- return {
1706
- ...state,
1707
- run
1708
- };
1709
- }
1710
- function ErrorText({ children, title }) {
1711
- return children === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1712
- className: css.error,
1713
- role: "alert",
1714
- title,
1715
- children
1951
+ if (target === void 0 || equal(target, inherited)) {
1952
+ if (user !== void 0) ops.push({
1953
+ op: "unset",
1954
+ path: prunedPath(layers.user, path)
1716
1955
  });
1717
- }
1718
- /** Inline confirmation of a destructive action: the question beside cancel and confirm. */
1719
- function ConfirmRow({ message, confirmLabel, cancelLabel, disabled, onConfirm, onCancel }) {
1720
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1721
- className: css.confirmRow,
1722
- role: "group",
1723
- "aria-label": message,
1724
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1725
- className: css.confirmText,
1726
- children: message
1727
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1728
- className: css.actions,
1729
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1730
- variant: "ghost",
1731
- size: "sm",
1732
- onClick: onCancel,
1733
- children: cancelLabel
1734
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1735
- variant: "outline",
1736
- size: "sm",
1737
- className: css.danger,
1738
- disabled,
1739
- onClick: onConfirm,
1740
- children: confirmLabel
1741
- })]
1742
- })]
1956
+ } else {
1957
+ const sparse = delta(target, inherited);
1958
+ if (!equal(sparse, user)) ops.push({
1959
+ op: "set",
1960
+ path: [...path],
1961
+ value: sparse
1743
1962
  });
1744
1963
  }
1964
+ if (ops.some((op) => op.op === "set") && objectOf(layers.user).version !== spec.version) ops.push({
1965
+ op: "set",
1966
+ path: ["version"],
1967
+ value: spec.version
1968
+ });
1969
+ return ops;
1970
+ }
1971
+ function valueAt(root, path) {
1972
+ return path.reduce((value, key) => objectOf(value)[key], root);
1973
+ }
1974
+ /**
1975
+ * The path to unset so no empty object stays behind: removing the only key of
1976
+ * a user-layer object removes that object instead, up to a top-level field.
1977
+ */
1978
+ function prunedPath(user, path) {
1979
+ let end = path.length;
1980
+ while (end > 1 && Object.keys(objectOf(valueAt(user, path.slice(0, end - 1)))).length === 1) end -= 1;
1981
+ return path.slice(0, end);
1982
+ }
1983
+ /** Unset every field this plugin stores in the user layer; inherited values and credentials stay. */
1984
+ function resetSettingsOperations$1(layers) {
1985
+ return Object.keys(objectOf(layers.user)).map((key) => ({
1986
+ op: "unset",
1987
+ path: [key]
1988
+ }));
1989
+ }
1990
+ /** Bind the current document version and fields; no predecessor schema is inferred. */
1991
+ function createSparseSettings(spec) {
1745
1992
  return {
1746
- Section,
1747
- SettingRow,
1748
- SelectMenu,
1749
- ErrorText,
1750
- ConfirmRow,
1751
- useWrite
1993
+ documentVersion: (layers) => documentVersion$1(layers),
1994
+ sparseSettingOperations: (layers, path, target, fallback) => sparseSettingOperations$1(spec, layers, path, target, fallback),
1995
+ resetSettingsOperations: (layers) => resetSettingsOperations$1(layers)
1752
1996
  };
1753
1997
  }
1754
- function applyOps(user, ops) {
1755
- const root = structuredClone(user !== null && typeof user === "object" && !Array.isArray(user) ? user : {});
1756
- for (const op of ops) {
1757
- if (op.path.length === 0) continue;
1758
- if (op.op === "set") {
1759
- let current = root;
1760
- for (let i = 0; i < op.path.length - 1; i++) {
1761
- const seg = op.path[i];
1762
- if (current[seg] === null || typeof current[seg] !== "object" || Array.isArray(current[seg])) current[seg] = {};
1763
- current = current[seg];
1764
- }
1765
- current[op.path.at(-1)] = structuredClone(op.value);
1766
- } else if (op.op === "unset") {
1767
- let current = root;
1768
- for (let i = 0; i < op.path.length - 1; i++) {
1769
- const seg = op.path[i];
1770
- if (current[seg] === null || typeof current[seg] !== "object" || Array.isArray(current[seg])) break;
1771
- current = current[seg];
1772
- }
1773
- delete current[op.path.at(-1)];
1774
- }
1775
- }
1776
- return root;
1777
- }
1778
1998
  //#endregion
1779
1999
  //#region ../core/src/client/settings/CredentialEditor.tsx
1780
2000
  /** Write-only key entry: the value goes to DSH Credentials and never into settings. */
@@ -2217,14 +2437,25 @@ window.__ModuleLoader__.load({
2217
2437
  function adapterKeys(catalog) {
2218
2438
  return Object.entries(catalog).filter(([, info]) => info.kind === "adapter").map(([key]) => key);
2219
2439
  }
2440
+ /** A built-in entry's override as stored, its label on one line as the grammar reads it. */
2220
2441
  function builtinOverride(config, key) {
2221
2442
  const stored = config.connections === void 0 ? void 0 : config.connections[builtinId(key)];
2222
- return stored === void 0 ? {} : stored;
2443
+ if (stored === void 0) return {};
2444
+ return stored.label === void 0 ? stored : {
2445
+ ...stored,
2446
+ label: singleLine(stored.label)
2447
+ };
2223
2448
  }
2224
- /** Custom connections in document order; the document has passed the capability's validation. */
2449
+ /** Custom connections in document order, labels on one line; the document has passed the capability's validation. */
2225
2450
  function customConnections(config) {
2226
2451
  if (config.connections === void 0) return [];
2227
- return Object.entries(config.connections).filter(([id]) => CUSTOM_CONNECTION_ID.test(id)).map(([id, connection]) => [id, connection]);
2452
+ return Object.entries(config.connections).filter(([id]) => CUSTOM_CONNECTION_ID.test(id)).map(([id, stored]) => {
2453
+ const connection = stored;
2454
+ return [id, {
2455
+ ...connection,
2456
+ label: singleLine(connection.label)
2457
+ }];
2458
+ });
2228
2459
  }
2229
2460
  /** Built-in connections default to the anonymous route where one exists. */
2230
2461
  function builtinAccess(info, override) {
@@ -2560,15 +2791,19 @@ window.__ModuleLoader__.load({
2560
2791
  });
2561
2792
  function ServicesSection(props) {
2562
2793
  const catalogKeys = Object.keys(catalog);
2563
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Section, {
2794
+ const optIn = catalogKeys.some((key) => catalog[key].optIn);
2795
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
2564
2796
  title: props.t(keys["services.title"]),
2565
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
2797
+ children: [optIn ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2798
+ className: css.note,
2799
+ children: props.t(keys["services.optInNotice"])
2800
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
2566
2801
  className: css.list,
2567
2802
  children: catalogKeys.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ServiceRow, {
2568
2803
  catalogKey: key,
2569
2804
  ...props
2570
2805
  }, key))
2571
- })
2806
+ })]
2572
2807
  });
2573
2808
  }
2574
2809
  function ServiceRow({ catalogKey, doc, write, credentials, saveCredential, t }) {
@@ -2584,18 +2819,18 @@ window.__ModuleLoader__.load({
2584
2819
  const credential = builtinCredential(info, override);
2585
2820
  const credentialRef = credential === void 0 ? void 0 : credential.ref;
2586
2821
  const credentialStatus = credentialRef === void 0 ? void 0 : credentials[credentialRef];
2587
- const enabled = override.disabled !== true;
2822
+ const enabled = !(override.disabled ?? info.optIn);
2588
2823
  const disabled = !doc.editable || action.busy;
2589
- const operations = (path, target, fallback) => sparse.sparseSettingOperations(doc.layers, [
2824
+ const operations = (layers, path, target, fallback) => sparse.sparseSettingOperations(layers, [
2590
2825
  "connections",
2591
2826
  connectionId,
2592
2827
  ...path
2593
2828
  ], target, fallback);
2594
- const save = (path, target, fallback) => action.run(() => write(operations(path, target, fallback)));
2829
+ const save = (path, target, fallback) => action.run(() => write((layers) => operations(layers, path, target, fallback)));
2595
2830
  const stored = override.options === void 0 ? {} : override.options;
2596
- const saveOptions = (changes) => action.run(() => {
2597
- let layers = doc.layers;
2598
- return write(Object.entries(changes).flatMap(([option, value]) => {
2831
+ const saveOptions = (changes) => action.run(() => write((initial) => {
2832
+ let layers = initial;
2833
+ return Object.entries(changes).flatMap(([option, value]) => {
2599
2834
  const next = sparse.sparseSettingOperations(layers, [
2600
2835
  "connections",
2601
2836
  connectionId,
@@ -2607,15 +2842,22 @@ window.__ModuleLoader__.load({
2607
2842
  user: applyOps(layers.user, next)
2608
2843
  };
2609
2844
  return next;
2610
- }));
2611
- });
2612
- /** The keyless route takes only the options it accepts; the rest go in the same write. */
2845
+ });
2846
+ }));
2847
+ /**
2848
+ * The keyless route takes only the options it accepts; the rest go in the
2849
+ * same write. Which ones those are is read from the layers the write runs
2850
+ * on: options changed while it waited stay as they are now.
2851
+ */
2613
2852
  const switchAccess = (next) => {
2614
2853
  if (next === "api-key") return save(["access"], next, "keyless");
2615
- const rejected = keylessRejected(info.options, stored);
2616
- const kept = Object.fromEntries(Object.entries(stored).filter(([option]) => !rejected.includes(option)));
2617
- const optionOps = rejected.length === 0 ? [] : operations(["options"], Object.keys(kept).length === 0 ? void 0 : kept);
2618
- return action.run(() => write([...operations(["access"], next, "keyless"), ...optionOps]));
2854
+ return action.run(() => write((layers) => {
2855
+ const current = builtinOverride(effectiveDocument(layers), catalogKey).options;
2856
+ const options = current === void 0 ? {} : current;
2857
+ const rejected = keylessRejected(info.options, options);
2858
+ const kept = Object.fromEntries(Object.entries(options).filter(([option]) => !rejected.includes(option)));
2859
+ return [...operations(layers, ["access"], next, "keyless"), ...rejected.length === 0 ? [] : operations(layers, ["options"], Object.keys(kept).length === 0 ? void 0 : kept)];
2860
+ }));
2619
2861
  };
2620
2862
  const note = notes[catalogKey];
2621
2863
  const extra = extras[catalogKey];
@@ -2665,7 +2907,7 @@ window.__ModuleLoader__.load({
2665
2907
  checked: enabled,
2666
2908
  label: t(keys["services.enable"], { name }),
2667
2909
  disabled,
2668
- onChange: (next) => void save(["disabled"], !next, false)
2910
+ onChange: (next) => void save(["disabled"], !next, info.optIn)
2669
2911
  })]
2670
2912
  })
2671
2913
  ]
@@ -2890,7 +3132,7 @@ window.__ModuleLoader__.load({
2890
3132
  const action = useWrite(t);
2891
3133
  const disabled = !doc.editable || action.busy;
2892
3134
  const save = (path, target, fallback) => {
2893
- action.run(() => write(sparse.sparseSettingOperations(doc.layers, path, target, fallback)));
3135
+ action.run(() => write((layers) => sparse.sparseSettingOperations(layers, path, target, fallback)));
2894
3136
  };
2895
3137
  const missing = defaultConnection !== void 0 && !choices.some((choice) => choice.id === defaultConnection);
2896
3138
  const warning = missing ? t(keys.connectionMissing, { id: defaultConnection }) : defaultAvailability && (defaultAvailability.disabled || configurationState(true, defaultAvailability.access, defaultAvailability.credentialStatus) === "warning") ? defaultAvailability.warning : void 0;
@@ -2937,6 +3179,53 @@ window.__ModuleLoader__.load({
2937
3179
  };
2938
3180
  }
2939
3181
  //#endregion
3182
+ //#region ../core/src/client/settings/EnhancedToolsSection.tsx
3183
+ /**
3184
+ * The row's Enhanced tools switch (docs/design.md, "开关与同意"): what turning
3185
+ * it on lets the Agent do, and what the operator agrees to by doing so.
3186
+ */
3187
+ function createEnhancedToolsSection({ classes: css, parts: { Section, ErrorText, useWrite }, sparse, keys }) {
3188
+ return function EnhancedToolsSection({ doc, write, t }) {
3189
+ const id = (0, react.useId)();
3190
+ const action = useWrite(t);
3191
+ const enabled = doc.config.enhancedTools ?? false;
3192
+ const save = (next) => action.run(() => write((layers) => sparse.sparseSettingOperations(layers, ["enhancedTools"], next, false)));
3193
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
3194
+ title: t(keys.title),
3195
+ titleId: id + "-title",
3196
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3197
+ className: css.settingRow,
3198
+ role: "group",
3199
+ "aria-labelledby": id + "-title",
3200
+ "aria-describedby": id + "-description " + id + "-consent",
3201
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3202
+ className: css.settingText,
3203
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3204
+ id: id + "-description",
3205
+ className: css.settingLead,
3206
+ children: t(keys.description)
3207
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3208
+ id: id + "-consent",
3209
+ className: css.hint,
3210
+ children: t(keys.consent)
3211
+ })]
3212
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3213
+ className: css.settingControl,
3214
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
3215
+ checked: enabled,
3216
+ label: t(keys.title),
3217
+ disabled: !doc.editable || action.busy,
3218
+ onChange: (next) => void save(next)
3219
+ })
3220
+ })]
3221
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorText, {
3222
+ title: action.errorTitle,
3223
+ children: action.error
3224
+ })]
3225
+ });
3226
+ };
3227
+ }
3228
+ //#endregion
2940
3229
  //#region ../core/src/client/settings/ResetSection.tsx
2941
3230
  function createResetSection({ classes: css, keys, parts: { ConfirmRow, ErrorText, useWrite }, sparse }) {
2942
3231
  return function ResetSection({ doc, write, t }) {
@@ -2970,175 +3259,40 @@ window.__ModuleLoader__.load({
2970
3259
  disabled,
2971
3260
  onClick: () => {
2972
3261
  setConfirming(true);
2973
- },
2974
- children: t(keys["reset.button"])
2975
- })]
2976
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorText, {
2977
- title: action.errorTitle,
2978
- children: action.error
2979
- })]
2980
- });
2981
- };
2982
- }
2983
- //#endregion
2984
- //#region ../core/src/client/settings/RouteNotice.tsx
2985
- function createRouteNotice({ classes: css, keys, other }) {
2986
- return function RouteNotice({ route, t }) {
2987
- let text;
2988
- switch (route.kind) {
2989
- case "this": return null;
2990
- case "unknown":
2991
- text = t(keys.unknown);
2992
- break;
2993
- case "auto":
2994
- text = t(keys.auto, { id: route.providerId });
2995
- break;
2996
- case "other": text = other?.(route, t) ?? t(keys.other, {
2997
- provider: route.provider,
2998
- id: route.providerId
2999
- });
3000
- }
3001
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3002
- className: css.warning,
3003
- role: "status",
3004
- children: text
3005
- });
3006
- };
3007
- }
3008
- //#endregion
3009
- //#region ../core/src/client/settings/document.ts
3010
- /** ConfigForm.value is schema-projected; the raw layers retain unknown fields for validation. */
3011
- function effectiveDocument(snapshot) {
3012
- return merge(snapshot.base, snapshot.user);
3013
- }
3014
- /** Validate before exposing normal editors; only successful older migrations need writeback. */
3015
- function editableSettings(raw, layers, writable, resolve, migrations = SETTINGS_MIGRATIONS) {
3016
- try {
3017
- const version = documentVersion$2(raw, migrations.currentVersion);
3018
- const config = migrateDocument(raw, migrations);
3019
- resolve(config);
3020
- return {
3021
- kind: "ready",
3022
- config,
3023
- layers,
3024
- needsWriteback: writable && version.kind === "older"
3025
- };
3026
- } catch (error) {
3027
- return {
3028
- kind: "invalid",
3029
- diagnostic: diagnostic(error),
3030
- layers,
3031
- needsWriteback: false
3032
- };
3033
- }
3034
- }
3035
- /** Check the exact recursively overlaid candidate that the settings store will persist. */
3036
- function settingsOperations(layers, operations, resolve) {
3037
- try {
3038
- const candidate = effectiveDocument({
3039
- base: layers.base,
3040
- user: applyOps(layers.user, operations)
3041
- });
3042
- const result = [...operations];
3043
- if (result.some((op) => op.op === "set") && candidate.version === void 0) {
3044
- result.push({
3045
- op: "set",
3046
- path: ["version"],
3047
- value: 2
3048
- });
3049
- candidate.version = 2;
3050
- }
3051
- resolve(candidate);
3052
- return result;
3053
- } catch (error) {
3054
- throw new SettingsValidationError(diagnostic(error));
3055
- }
3056
- }
3057
- /** Share validation, revision fencing and automatic future migrations between both pages. */
3058
- function useSettingsDocument(snapshot, resolve, mutate, migrations = SETTINGS_MIGRATIONS) {
3059
- const view = (0, react.useMemo)(() => {
3060
- if (snapshot.status === "unavailable" || snapshot.value === void 0 || snapshot.revision === void 0) return void 0;
3061
- const result = editableSettings(effectiveDocument(snapshot), {
3062
- base: snapshot.base,
3063
- user: snapshot.user
3064
- }, snapshot.writable, resolve, migrations);
3065
- if (snapshot.diagnostic === void 0) return result;
3066
- return {
3067
- kind: "invalid",
3068
- layers: result.layers,
3069
- needsWriteback: false,
3070
- diagnostic: result.kind === "invalid" ? result.diagnostic + "; " + snapshot.diagnostic : snapshot.diagnostic
3071
- };
3072
- }, [
3073
- snapshot,
3074
- resolve,
3075
- migrations
3076
- ]);
3077
- const attemptedRevision = (0, react.useRef)(void 0);
3078
- const [failure, setFailure] = (0, react.useState)();
3079
- const revision = snapshot.revision;
3080
- (0, react.useEffect)(() => {
3081
- if (view?.kind !== "ready" || !view.needsWriteback || revision === void 0 || attemptedRevision.current === revision) return;
3082
- attemptedRevision.current = revision;
3083
- const writeback = async () => {
3084
- try {
3085
- const operations = replaceDocumentOperations(view.layers.user, view.config);
3086
- await mutate(settingsOperations(view.layers, operations, resolve), revision);
3087
- } catch (error) {
3088
- setFailure({
3089
- revision,
3090
- diagnostic: diagnostic(error)
3091
- });
3092
- }
3093
- };
3094
- writeback();
3095
- }, [
3096
- view,
3097
- revision,
3098
- resolve,
3099
- mutate
3100
- ]);
3101
- const write = async (operations, expectedRevision = revision) => {
3102
- if (operations.length === 0) return true;
3103
- if (view === void 0 || !snapshot.writable || expectedRevision === void 0) return false;
3104
- return mutate(settingsOperations(view.layers, operations, resolve), expectedRevision);
3105
- };
3106
- return {
3107
- view,
3108
- write,
3109
- migrationError: failure?.revision === revision ? failure?.diagnostic : void 0
3262
+ },
3263
+ children: t(keys["reset.button"])
3264
+ })]
3265
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorText, {
3266
+ title: action.errorTitle,
3267
+ children: action.error
3268
+ })]
3269
+ });
3110
3270
  };
3111
3271
  }
3112
- function replaceDocumentOperations(user, document) {
3113
- const operations = Object.keys(objectOf(user)).filter((key) => !Object.hasOwn(document, key)).map((key) => ({
3114
- op: "unset",
3115
- path: [key]
3116
- }));
3117
- for (const [key, value] of Object.entries(document)) operations.push({
3118
- op: "set",
3119
- path: [key],
3120
- value
3121
- });
3122
- return operations;
3123
- }
3124
- function diagnostic(error) {
3125
- return error instanceof Error ? error.message : String(error);
3126
- }
3127
- function isObject(value) {
3128
- return value !== null && typeof value === "object" && !Array.isArray(value);
3129
- }
3130
- function objectOf(value) {
3131
- return isObject(value) ? value : {};
3132
- }
3133
- function merge(base, user) {
3134
- const result = { ...objectOf(base) };
3135
- for (const [key, value] of Object.entries(objectOf(user))) Object.defineProperty(result, key, {
3136
- value: isObject(value) && isObject(result[key]) ? merge(result[key], value) : value,
3137
- enumerable: true,
3138
- writable: true,
3139
- configurable: true
3140
- });
3141
- return result;
3272
+ //#endregion
3273
+ //#region ../core/src/client/settings/RouteNotice.tsx
3274
+ function createRouteNotice({ classes: css, keys, other }) {
3275
+ return function RouteNotice({ route, t }) {
3276
+ let text;
3277
+ switch (route.kind) {
3278
+ case "this": return null;
3279
+ case "unknown":
3280
+ text = t(keys.unknown);
3281
+ break;
3282
+ case "auto":
3283
+ text = t(keys.auto, { id: route.providerId });
3284
+ break;
3285
+ case "other": text = other?.(route, t) ?? t(keys.other, {
3286
+ provider: route.provider,
3287
+ id: route.providerId
3288
+ });
3289
+ }
3290
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3291
+ className: css.warning,
3292
+ role: "status",
3293
+ children: text
3294
+ });
3295
+ };
3142
3296
  }
3143
3297
  //#endregion
3144
3298
  //#region ../core/src/client/settings/secret-diagnostics.ts
@@ -3248,7 +3402,7 @@ window.__ModuleLoader__.load({
3248
3402
  const options = connection.options === void 0 ? {} : connection.options;
3249
3403
  const fields = {
3250
3404
  id,
3251
- label: connection.label,
3405
+ label: singleLine(connection.label),
3252
3406
  credentialRef: connection.credentialRef,
3253
3407
  endpoint: connection.endpoint === void 0 ? "" : connection.endpoint,
3254
3408
  options: Object.fromEntries(Object.entries(options).map(([name, value]) => [name, fieldText(value)]))
@@ -3322,7 +3476,7 @@ window.__ModuleLoader__.load({
3322
3476
  const form = {
3323
3477
  ...input,
3324
3478
  id: input.id.trim(),
3325
- label: input.label.trim(),
3479
+ label: singleLine(input.label),
3326
3480
  credentialRef: input.credentialRef.trim(),
3327
3481
  endpoint: input.endpoint.trim()
3328
3482
  };
@@ -3841,7 +3995,7 @@ window.__ModuleLoader__.load({
3841
3995
  const disabled = !doc.editable || action.busy;
3842
3996
  const userConnections = doc.layers.user?.connections;
3843
3997
  const removable = userConnections !== void 0 && Object.hasOwn(userConnections, id);
3844
- const save = (path, target, fallback) => action.run(() => write(sparse.sparseSettingOperations(doc.layers, [
3998
+ const save = (path, target, fallback) => action.run(() => write((layers) => sparse.sparseSettingOperations(layers, [
3845
3999
  "connections",
3846
4000
  id,
3847
4001
  ...path
@@ -3973,6 +4127,49 @@ window.__ModuleLoader__.load({
3973
4127
  "searchContextSize"
3974
4128
  ];
3975
4129
  //#endregion
4130
+ //#region src/settings/resolve.ts
4131
+ const defaultsSchema = zod.z.strictObject({ freshness: zod.z.enum(FRESHNESS).default("auto") });
4132
+ /** Pure sparse resolution shared by Host and browser. */
4133
+ function resolveSettings(document = {}) {
4134
+ const resolved = resolveDocument({
4135
+ catalog: CATALOG,
4136
+ protocols: MODEL_PROTOCOLS,
4137
+ document,
4138
+ retiredFields: RETIRED_FIELDS,
4139
+ defaults: {
4140
+ schema: defaultsSchema,
4141
+ defaultConnection: DEFAULT_CONNECTION
4142
+ },
4143
+ capabilityLabel: "search"
4144
+ });
4145
+ const connections = /* @__PURE__ */ new Map();
4146
+ for (const [id, connection] of resolved.connections) {
4147
+ const { catalogKey, ...base } = connection;
4148
+ switch (base.kind) {
4149
+ case "local": throw new Error("search catalog cannot contain a local connection");
4150
+ case "model":
4151
+ connections.set(id, base);
4152
+ break;
4153
+ case "native":
4154
+ connections.set(id, {
4155
+ ...base,
4156
+ kind: "native",
4157
+ native: catalogKey
4158
+ });
4159
+ break;
4160
+ case "adapter": connections.set(id, {
4161
+ ...base,
4162
+ kind: "adapter",
4163
+ adapter: catalogKey
4164
+ });
4165
+ }
4166
+ }
4167
+ return {
4168
+ ...resolved,
4169
+ connections
4170
+ };
4171
+ }
4172
+ //#endregion
3976
4173
  //#region src/client/connections.ts
3977
4174
  /** The Session-model connection keeps its catalog name only until the operator renames it; that name is localized. */
3978
4175
  function connectionLabel(connection, t) {
@@ -4134,49 +4331,6 @@ window.__ModuleLoader__.load({
4134
4331
  });
4135
4332
  }
4136
4333
  //#endregion
4137
- //#region src/settings/resolve.ts
4138
- const defaultsSchema = zod.z.strictObject({ freshness: zod.z.enum(FRESHNESS).default("auto") });
4139
- /** Pure sparse resolution shared by Host and browser. */
4140
- function resolveSettings(document = {}) {
4141
- const resolved = resolveDocument({
4142
- catalog: CATALOG,
4143
- protocols: MODEL_PROTOCOLS,
4144
- document,
4145
- retiredFields: RETIRED_FIELDS,
4146
- defaults: {
4147
- schema: defaultsSchema,
4148
- defaultConnection: DEFAULT_CONNECTION
4149
- },
4150
- capabilityLabel: "search"
4151
- });
4152
- const connections = /* @__PURE__ */ new Map();
4153
- for (const [id, connection] of resolved.connections) {
4154
- const { catalogKey, ...base } = connection;
4155
- switch (base.kind) {
4156
- case "local": throw new Error("search catalog cannot contain a local connection");
4157
- case "model":
4158
- connections.set(id, base);
4159
- break;
4160
- case "native":
4161
- connections.set(id, {
4162
- ...base,
4163
- kind: "native",
4164
- native: catalogKey
4165
- });
4166
- break;
4167
- case "adapter": connections.set(id, {
4168
- ...base,
4169
- kind: "adapter",
4170
- adapter: catalogKey
4171
- });
4172
- }
4173
- }
4174
- return {
4175
- ...resolved,
4176
- connections
4177
- };
4178
- }
4179
- //#endregion
4180
4334
  //#region src/client/credentials.ts
4181
4335
  /** The DSH credential a connection names; the Session-model connection uses the Session route's own. */
4182
4336
  function credentialRefsOf(connection) {
@@ -4275,6 +4429,10 @@ window.__ModuleLoader__.load({
4275
4429
  "defaults.showSelectorHint": "When hidden, switch the current conversation with /setup-search.",
4276
4430
  "defaults.freshnessKeyOnly": "{name} (personal key)",
4277
4431
  "services.title": "Search connections",
4432
+ "services.optInNotice": "Remote services are off by default.",
4433
+ "enhanced.title": "Enhanced tools",
4434
+ "enhanced.description": "Lets the Agent pick which enabled service runs a search with web_search_enhanced, and see the choices with list_web_search_providers. Applies to conversations started afterwards.",
4435
+ "enhanced.consent": "Turning this on means you agree that when the Agent picks a service, the query is sent to that service.",
4278
4436
  "services.enable": "Enable {name}",
4279
4437
  "services.configure": "Configure",
4280
4438
  "services.configureLabel": "Configure {name}",
@@ -4488,7 +4646,7 @@ window.__ModuleLoader__.load({
4488
4646
  "freshness.auto": "自动",
4489
4647
  "freshness.fresh": "24 小时内",
4490
4648
  "freshness.realtime": "实时",
4491
- "status.disabled": "{name} 已在设置中停用。",
4649
+ "status.disabled": "{name} 未在设置中启用。",
4492
4650
  "status.needsCredential": "需要 API Key",
4493
4651
  "status.needsAccount": "需要 DeepSeek 账号或 API Key",
4494
4652
  "status.unsupported": "本版本不支持 {name}。",
@@ -4501,7 +4659,7 @@ window.__ModuleLoader__.load({
4501
4659
  "selector.freshnessIgnored": "{name} 不支持此偏好,选择不会生效。",
4502
4660
  "selector.offRow": "关闭",
4503
4661
  "write.conflict": "搜索设置已在别处更改,菜单已显示最新选择。",
4504
- "write.unavailable": "该连接已停用或已移除。",
4662
+ "write.unavailable": "该连接未启用或已移除。",
4505
4663
  "write.failed": "保存失败,请重试。",
4506
4664
  "command.label": "搜索连接",
4507
4665
  "command.description": "切换当前会话的搜索连接与内容实时性",
@@ -4532,10 +4690,14 @@ window.__ModuleLoader__.load({
4532
4690
  "defaults.showSelectorHint": "隐藏后可用 /setup-search 切换当前会话。",
4533
4691
  "defaults.freshnessKeyOnly": "{name}(个人密钥)",
4534
4692
  "services.title": "搜索连接",
4693
+ "services.optInNotice": "远程服务默认关闭。",
4694
+ "enhanced.title": "增强工具",
4695
+ "enhanced.description": "让 Agent 用 web_search_enhanced 在已启用的服务中自行选择本次搜索用哪个,并用 list_web_search_providers 查看可选项。只影响之后新建的会话。",
4696
+ "enhanced.consent": "打开即表示同意:Agent 选用某个服务时,查询会发送给该服务。",
4535
4697
  "services.enable": "启用 {name}",
4536
4698
  "services.configure": "配置",
4537
4699
  "services.configureLabel": "配置 {name}",
4538
- "services.off": "已停用",
4700
+ "services.off": "未启用",
4539
4701
  "services.keyless": "无需密钥",
4540
4702
  "services.personalKey": "个人密钥 {ref}",
4541
4703
  "services.account": "DeepSeek 账号或 {ref}",
@@ -4741,15 +4903,15 @@ window.__ModuleLoader__.load({
4741
4903
  document.head.appendChild(style);
4742
4904
  }
4743
4905
  var Section_module_css_default = {
4744
- "container": "La6KHG_container",
4745
4906
  "caption": "La6KHG_caption",
4907
+ "container": "La6KHG_container",
4746
4908
  "segmented": "La6KHG_segmented",
4747
4909
  "error": "La6KHG_error",
4748
4910
  "label": "La6KHG_label"
4749
4911
  };
4750
4912
  //#endregion
4751
4913
  //#region src/client/section.ts
4752
- function searchSection(selection, settings, t) {
4914
+ function searchSection(selection, settings, remoteServicesOff, t) {
4753
4915
  function Options({ sessionId }) {
4754
4916
  const state = useObservable(selection.source(sessionId));
4755
4917
  const [error, setError] = (0, react.useState)("");
@@ -4787,6 +4949,7 @@ window.__ModuleLoader__.load({
4787
4949
  title: () => t("section.title"),
4788
4950
  selection,
4789
4951
  settings,
4952
+ remoteServicesOff,
4790
4953
  Options,
4791
4954
  describe: (connection) => describe(connection, t),
4792
4955
  sourceText: (view) => sourceText(view, t),
@@ -4802,7 +4965,7 @@ window.__ModuleLoader__.load({
4802
4965
  };
4803
4966
  //#endregion
4804
4967
  //#region \0dsh-css-module:/home/runner/work/dsh-tool-web-enhanced/dsh-tool-web-enhanced/packages/search-enhanced/src/client/settings/Settings.module.css.mjs
4805
- const css = ".o9fCSq_page{min-width:0;color:var(--dsw-alias-label-primary);flex-direction:column;gap:28px;display:flex;container-type:inline-size}.o9fCSq_intro{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:20px}.o9fCSq_status{color:var(--dsw-alias-label-tertiary);align-items:center;gap:6px;margin:0;font-size:13px;line-height:20px;display:flex}.o9fCSq_warning{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-state-warn-label);margin:0;padding:8px 12px;font-size:12px;line-height:18px}.o9fCSq_section{flex-direction:column;gap:4px;min-width:0;display:flex}.o9fCSq_sectionHead{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px;min-height:28px;display:flex}.o9fCSq_sectionTitle{margin:0;font-size:14px;font-weight:500;line-height:20px}.o9fCSq_sectionActions{flex-wrap:wrap;gap:4px;display:flex}.o9fCSq_hint,.o9fCSq_note{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.o9fCSq_panel .o9fCSq_hint,.o9fCSq_editor .o9fCSq_hint{color:var(--dsw-alias-label-secondary)}.o9fCSq_hint [role=status]{color:var(--dsw-alias-label-secondary);align-items:baseline;gap:6px;margin-top:4px;display:flex}.o9fCSq_note{color:var(--dsw-alias-label-secondary)}.o9fCSq_error,.o9fCSq_success,.o9fCSq_fieldError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.o9fCSq_success{color:var(--dsw-alias-state-success-primary)}.o9fCSq_settingRow{border-bottom:.5px solid var(--dsw-alias-border-l2);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 24px;padding:14px 2px;display:flex}.o9fCSq_settingRow:last-of-type{border-bottom:0}.o9fCSq_settingText{flex-direction:column;flex:200px;gap:2px;min-width:0;display:flex}.o9fCSq_settingTitle{font-size:13.5px;font-weight:500;line-height:20px}.o9fCSq_settingControl{flex:0 auto;justify-content:flex-end;min-width:0;max-width:100%;display:flex}.o9fCSq_selectAnchor{min-width:0;max-width:100%}.o9fCSq_select,.o9fCSq_selectCompact{box-sizing:border-box;border-radius:var(--dsw-radius-md);min-width:0;max-width:100%;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;align-items:center;gap:8px;font-size:13px;line-height:20px;display:inline-flex}.o9fCSq_select{background:var(--dsw-alias-bg-module-platform);height:36px;padding:0 12px 0 14px}.o9fCSq_selectCompact{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);justify-content:space-between;width:100%;height:36px;padding:0 10px 0 12px}.o9fCSq_select:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.o9fCSq_select:disabled,.o9fCSq_selectCompact:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.o9fCSq_select:focus-visible,.o9fCSq_selectCompact:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}.o9fCSq_selectValue{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.o9fCSq_selectChevron{color:var(--dsw-alias-label-tertiary);flex:none}.o9fCSq_list{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.o9fCSq_row{border-bottom:.5px solid var(--dsw-alias-border-l2);padding:12px 2px}.o9fCSq_row:last-child{border-bottom:0}.o9fCSq_rowLine{align-items:center;gap:8px 12px;min-width:0;display:flex}.o9fCSq_rowMain{flex-direction:column;flex:1 1 0;gap:2px;min-width:0;display:flex}.o9fCSq_rowTitle{flex-wrap:wrap;align-items:center;gap:6px;font-size:13.5px;font-weight:500;line-height:20px;display:inline-flex}.o9fCSq_rowMeta{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:12px;line-height:18px}.o9fCSq_rowMeta code,.o9fCSq_optionKey{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);font-size:11.5px}.o9fCSq_rowActions{box-sizing:border-box;flex-wrap:wrap;flex:none;align-items:center;gap:4px;display:flex}@container (width<=560px){.o9fCSq_rowLine:has(.o9fCSq_rowActions){flex-wrap:wrap}.o9fCSq_rowActions{flex-basis:100%;order:3;padding-left:10px}}.o9fCSq_segmented{align-self:flex-start;max-width:100%}.o9fCSq_disclosure{color:var(--dsw-alias-label-secondary)}.o9fCSq_disclosureIcon{flex:none;width:12px;height:12px;transition:transform .12s}.o9fCSq_disclosureOpen{transform:rotate(180deg)}@media (prefers-reduced-motion:reduce){.o9fCSq_disclosureIcon{transition:none}}.o9fCSq_danger{color:var(--dsw-alias-state-error-primary)}.o9fCSq_panel,.o9fCSq_editor{border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:16px;margin:12px 0 2px;padding:16px;display:flex}.o9fCSq_field,.o9fCSq_formField{flex-direction:column;gap:6px;min-width:0;display:flex}.o9fCSq_fieldHead{align-items:center;gap:8px;display:flex}.o9fCSq_fieldLabel{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.o9fCSq_fieldState{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.o9fCSq_inline{flex-wrap:wrap;gap:8px;display:flex}.o9fCSq_inline>.o9fCSq_input{flex:160px}.o9fCSq_input{box-sizing:border-box;min-width:0;height:36px}.o9fCSq_input:has(input[aria-invalid=true]){border-color:var(--dsw-alias-state-error-primary)}.o9fCSq_link{color:var(--dsw-alias-link);align-self:flex-start;align-items:center;gap:2px;font-size:12px;font-weight:500;line-height:18px;text-decoration:none;display:inline-flex}.o9fCSq_link:hover,.o9fCSq_link:focus-visible{text-underline-offset:3px;text-decoration:underline dotted}.o9fCSq_optionGrid{grid-template-columns:repeat(auto-fill,minmax(min(100%,200px),1fr));gap:12px 16px;display:grid}.o9fCSq_option{flex-direction:column;gap:4px;min-width:0;display:flex}.o9fCSq_optionName{min-width:0;color:var(--dsw-alias-label-secondary);align-items:baseline;gap:6px;font-size:12px;line-height:18px;display:flex}.o9fCSq_optionKey{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);overflow:hidden}.o9fCSq_actions{flex-wrap:wrap;justify-content:flex-end;gap:8px;display:flex}.o9fCSq_empty{color:var(--dsw-alias-label-tertiary);margin:0;padding:8px 2px;font-size:13px;line-height:20px}.o9fCSq_editorTitle{margin:0;font-size:13.5px;font-weight:500;line-height:20px}.o9fCSq_formGrid{grid-template-columns:repeat(2,minmax(0,1fr));align-items:start;gap:14px 16px;display:grid}.o9fCSq_formWide{grid-column:1/-1}@container (width<=760px){.o9fCSq_optionGrid{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (width<=480px){.o9fCSq_optionGrid{grid-template-columns:minmax(0,1fr)}.o9fCSq_settingControl{flex-basis:100%;justify-content:flex-start}.o9fCSq_panel{padding:12px}}@container (width<=520px){.o9fCSq_formGrid{grid-template-columns:minmax(0,1fr)}}.o9fCSq_prefixed{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);align-items:center;height:36px;padding:0 8px 0 10px;display:flex}.o9fCSq_prefixed:focus-within{border-color:var(--dsw-alias-state-business-primary)}.o9fCSq_prefixedDisabled{color:var(--dsw-alias-label-tertiary)}.o9fCSq_prefix{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-tertiary);flex:none;font-size:13px;line-height:22px}.o9fCSq_prefixedInput{min-width:0;font:inherit;color:var(--dsw-alias-label-primary);background:0 0;border:none;outline:none;flex:1;padding:0;font-size:14px;line-height:22px}.o9fCSq_prefixedInput::placeholder{color:var(--dsw-alias-label-dimmed)}.o9fCSq_reset{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding-top:16px;display:flex}.o9fCSq_confirmRow{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 24px;display:flex}.o9fCSq_row .o9fCSq_confirmRow{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-module-platform);margin-top:10px;padding:8px 12px}.o9fCSq_confirmText{min-width:0;color:var(--dsw-alias-label-secondary);flex:240px;font-size:12px;line-height:18px}.o9fCSq_optionWide{grid-column:1/-1}.o9fCSq_textarea{box-sizing:border-box;resize:vertical;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);width:100%;min-width:0;min-height:72px;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);padding:8px 10px;font-size:12px;line-height:20px}.o9fCSq_textarea:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.o9fCSq_textarea::placeholder{color:var(--dsw-alias-label-dimmed)}.o9fCSq_textarea[aria-invalid=true]{border-color:var(--dsw-alias-state-error-primary)}.o9fCSq_textarea:disabled{cursor:not-allowed;opacity:.5}.o9fCSq_optionGroup{border-top:.5px solid var(--dsw-alias-border-l4);flex-direction:column;gap:8px;padding-top:12px;display:flex}.o9fCSq_optionGroup:first-child,.o9fCSq_fieldHead+.o9fCSq_optionGroup{border-top:0;padding-top:0}.o9fCSq_optionGroupTitle{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500;line-height:18px}.o9fCSq_trust{border:.5px solid var(--dsw-alias-state-warn-primary);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);padding:10px 12px}.o9fCSq_trust .o9fCSq_trustCheck{align-items:flex-start}.o9fCSq_trust .o9fCSq_trustCheck input{margin-top:2px}.o9fCSq_actions>.o9fCSq_hint{flex:auto;align-self:center}";
4968
+ const css = ".o9fCSq_page{min-width:0;color:var(--dsw-alias-label-primary);flex-direction:column;gap:28px;display:flex;container-type:inline-size}.o9fCSq_intro{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:20px}.o9fCSq_status{color:var(--dsw-alias-label-tertiary);align-items:center;gap:6px;margin:0;font-size:13px;line-height:20px;display:flex}.o9fCSq_warning{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-state-warn-label);margin:0;padding:8px 12px;font-size:12px;line-height:18px}.o9fCSq_section{flex-direction:column;gap:4px;min-width:0;display:flex}.o9fCSq_sectionHead{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px;min-height:28px;display:flex}.o9fCSq_sectionTitle{margin:0;font-size:14px;font-weight:500;line-height:20px}.o9fCSq_sectionActions{flex-wrap:wrap;gap:4px;display:flex}.o9fCSq_hint,.o9fCSq_note{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.o9fCSq_panel .o9fCSq_hint,.o9fCSq_editor .o9fCSq_hint{color:var(--dsw-alias-label-secondary)}.o9fCSq_hint [role=status]{color:var(--dsw-alias-label-secondary);align-items:baseline;gap:6px;margin-top:4px;display:flex}.o9fCSq_note{color:var(--dsw-alias-label-secondary)}.o9fCSq_error,.o9fCSq_success,.o9fCSq_fieldError{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.o9fCSq_success{color:var(--dsw-alias-state-success-primary)}.o9fCSq_settingRow{border-bottom:.5px solid var(--dsw-alias-border-l2);flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 24px;padding:14px 2px;display:flex}.o9fCSq_settingRow:last-of-type{border-bottom:0}.o9fCSq_settingText{flex-direction:column;flex:200px;gap:2px;min-width:0;display:flex}.o9fCSq_settingTitle{font-size:13.5px;font-weight:500;line-height:20px}.o9fCSq_settingLead{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:400;line-height:20px}.o9fCSq_settingControl{flex:0 auto;justify-content:flex-end;min-width:0;max-width:100%;display:flex}.o9fCSq_selectAnchor{min-width:0;max-width:100%}.o9fCSq_select,.o9fCSq_selectCompact{box-sizing:border-box;border-radius:var(--dsw-radius-md);min-width:0;max-width:100%;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;align-items:center;gap:8px;font-size:13px;line-height:20px;display:inline-flex}.o9fCSq_select{background:var(--dsw-alias-bg-module-platform);height:36px;padding:0 12px 0 14px}.o9fCSq_selectCompact{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);justify-content:space-between;width:100%;height:36px;padding:0 10px 0 12px}.o9fCSq_select:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.o9fCSq_select:disabled,.o9fCSq_selectCompact:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.o9fCSq_select:focus-visible,.o9fCSq_selectCompact:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:1px}.o9fCSq_selectValue{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.o9fCSq_selectChevron{color:var(--dsw-alias-label-tertiary);flex:none}.o9fCSq_list{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.o9fCSq_row{border-bottom:.5px solid var(--dsw-alias-border-l2);padding:12px 2px}.o9fCSq_row:last-child{border-bottom:0}.o9fCSq_rowLine{align-items:center;gap:8px 12px;min-width:0;display:flex}.o9fCSq_rowMain{flex-direction:column;flex:1 1 0;gap:2px;min-width:0;display:flex}.o9fCSq_rowTitle{flex-wrap:wrap;align-items:center;gap:6px;font-size:13.5px;font-weight:500;line-height:20px;display:inline-flex}.o9fCSq_rowMeta{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:12px;line-height:18px}.o9fCSq_rowMeta code,.o9fCSq_optionKey{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);font-size:11.5px}.o9fCSq_rowActions{box-sizing:border-box;flex-wrap:wrap;flex:none;align-items:center;gap:4px;display:flex}@container (width<=560px){.o9fCSq_rowLine:has(.o9fCSq_rowActions){flex-wrap:wrap}.o9fCSq_rowActions{flex-basis:100%;order:3;padding-left:10px}}.o9fCSq_segmented{align-self:flex-start;max-width:100%}.o9fCSq_disclosure{color:var(--dsw-alias-label-secondary)}.o9fCSq_disclosureIcon{flex:none;width:12px;height:12px;transition:transform .12s}.o9fCSq_disclosureOpen{transform:rotate(180deg)}@media (prefers-reduced-motion:reduce){.o9fCSq_disclosureIcon{transition:none}}.o9fCSq_danger{color:var(--dsw-alias-state-error-primary)}.o9fCSq_panel,.o9fCSq_editor{border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:16px;margin:12px 0 2px;padding:16px;display:flex}.o9fCSq_field,.o9fCSq_formField{flex-direction:column;gap:6px;min-width:0;display:flex}.o9fCSq_fieldHead{align-items:center;gap:8px;display:flex}.o9fCSq_fieldLabel{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.o9fCSq_fieldState{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.o9fCSq_inline{flex-wrap:wrap;gap:8px;display:flex}.o9fCSq_inline>.o9fCSq_input{flex:160px}.o9fCSq_input{box-sizing:border-box;min-width:0;height:36px}.o9fCSq_input:has(input[aria-invalid=true]){border-color:var(--dsw-alias-state-error-primary)}.o9fCSq_link{color:var(--dsw-alias-link);align-self:flex-start;align-items:center;gap:2px;font-size:12px;font-weight:500;line-height:18px;text-decoration:none;display:inline-flex}.o9fCSq_link:hover,.o9fCSq_link:focus-visible{text-underline-offset:3px;text-decoration:underline dotted}.o9fCSq_optionGrid{grid-template-columns:repeat(auto-fill,minmax(min(100%,200px),1fr));gap:12px 16px;display:grid}.o9fCSq_option{flex-direction:column;gap:4px;min-width:0;display:flex}.o9fCSq_optionName{min-width:0;color:var(--dsw-alias-label-secondary);align-items:baseline;gap:6px;font-size:12px;line-height:18px;display:flex}.o9fCSq_optionKey{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);overflow:hidden}.o9fCSq_actions{flex-wrap:wrap;justify-content:flex-end;gap:8px;display:flex}.o9fCSq_empty{color:var(--dsw-alias-label-tertiary);margin:0;padding:8px 2px;font-size:13px;line-height:20px}.o9fCSq_editorTitle{margin:0;font-size:13.5px;font-weight:500;line-height:20px}.o9fCSq_formGrid{grid-template-columns:repeat(2,minmax(0,1fr));align-items:start;gap:14px 16px;display:grid}.o9fCSq_formWide{grid-column:1/-1}@container (width<=760px){.o9fCSq_optionGrid{grid-template-columns:repeat(2,minmax(0,1fr))}}@container (width<=480px){.o9fCSq_optionGrid{grid-template-columns:minmax(0,1fr)}.o9fCSq_settingControl{flex-basis:100%;justify-content:flex-start}.o9fCSq_panel{padding:12px}}@container (width<=520px){.o9fCSq_formGrid{grid-template-columns:minmax(0,1fr)}}.o9fCSq_prefixed{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);align-items:center;height:36px;padding:0 8px 0 10px;display:flex}.o9fCSq_prefixed:focus-within{border-color:var(--dsw-alias-state-business-primary)}.o9fCSq_prefixedDisabled{color:var(--dsw-alias-label-tertiary)}.o9fCSq_prefix{font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-tertiary);flex:none;font-size:13px;line-height:22px}.o9fCSq_prefixedInput{min-width:0;font:inherit;color:var(--dsw-alias-label-primary);background:0 0;border:none;outline:none;flex:1;padding:0;font-size:14px;line-height:22px}.o9fCSq_prefixedInput::placeholder{color:var(--dsw-alias-label-dimmed)}.o9fCSq_reset{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding-top:16px;display:flex}.o9fCSq_confirmRow{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px 24px;display:flex}.o9fCSq_row .o9fCSq_confirmRow{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-module-platform);margin-top:10px;padding:8px 12px}.o9fCSq_confirmText{min-width:0;color:var(--dsw-alias-label-secondary);flex:240px;font-size:12px;line-height:18px}.o9fCSq_optionWide{grid-column:1/-1}.o9fCSq_textarea{box-sizing:border-box;resize:vertical;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);width:100%;min-width:0;min-height:72px;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-mono,ui-monospace, SFMono-Regular, Menlo, monospace);padding:8px 10px;font-size:12px;line-height:20px}.o9fCSq_textarea:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.o9fCSq_textarea::placeholder{color:var(--dsw-alias-label-dimmed)}.o9fCSq_textarea[aria-invalid=true]{border-color:var(--dsw-alias-state-error-primary)}.o9fCSq_textarea:disabled{cursor:not-allowed;opacity:.5}.o9fCSq_optionGroup{border-top:.5px solid var(--dsw-alias-border-l4);flex-direction:column;gap:8px;padding-top:12px;display:flex}.o9fCSq_optionGroup:first-child,.o9fCSq_fieldHead+.o9fCSq_optionGroup{border-top:0;padding-top:0}.o9fCSq_optionGroupTitle{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500;line-height:18px}.o9fCSq_trust{border:.5px solid var(--dsw-alias-state-warn-primary);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-1);padding:10px 12px}.o9fCSq_trust .o9fCSq_trustCheck{align-items:flex-start}.o9fCSq_trust .o9fCSq_trustCheck input{margin-top:2px}.o9fCSq_actions>.o9fCSq_hint{flex:auto;align-self:center}";
4806
4969
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify("dsh-web-search-enhanced/src/client/settings/Settings.module.css") + "]") === null) {
4807
4970
  const style = document.createElement("style");
4808
4971
  style.dataset.plugin = "dsh-web-search-enhanced";
@@ -4811,72 +4974,73 @@ window.__ModuleLoader__.load({
4811
4974
  document.head.appendChild(style);
4812
4975
  }
4813
4976
  var Settings_module_css_default = {
4814
- "panel": "o9fCSq_panel",
4815
- "inline": "o9fCSq_inline",
4977
+ "optionGroup": "o9fCSq_optionGroup",
4978
+ "selectCompact": "o9fCSq_selectCompact",
4816
4979
  "hint": "o9fCSq_hint",
4817
- "rowMain": "o9fCSq_rowMain",
4818
- "optionGroupTitle": "o9fCSq_optionGroupTitle",
4819
- "warning": "o9fCSq_warning",
4820
- "list": "o9fCSq_list",
4821
4980
  "actions": "o9fCSq_actions",
4981
+ "editorTitle": "o9fCSq_editorTitle",
4982
+ "section": "o9fCSq_section",
4983
+ "prefix": "o9fCSq_prefix",
4984
+ "error": "o9fCSq_error",
4985
+ "disclosure": "o9fCSq_disclosure",
4986
+ "fieldHead": "o9fCSq_fieldHead",
4987
+ "page": "o9fCSq_page",
4988
+ "rowActions": "o9fCSq_rowActions",
4989
+ "segmented": "o9fCSq_segmented",
4990
+ "settingLead": "o9fCSq_settingLead",
4991
+ "optionGroupTitle": "o9fCSq_optionGroupTitle",
4992
+ "rowTitle": "o9fCSq_rowTitle",
4993
+ "formField": "o9fCSq_formField",
4994
+ "intro": "o9fCSq_intro",
4995
+ "settingText": "o9fCSq_settingText",
4996
+ "prefixedDisabled": "o9fCSq_prefixedDisabled",
4997
+ "settingControl": "o9fCSq_settingControl",
4822
4998
  "trustCheck": "o9fCSq_trustCheck",
4999
+ "prefixed": "o9fCSq_prefixed",
5000
+ "sectionHead": "o9fCSq_sectionHead",
5001
+ "select": "o9fCSq_select",
5002
+ "fieldError": "o9fCSq_fieldError",
5003
+ "inline": "o9fCSq_inline",
5004
+ "link": "o9fCSq_link",
5005
+ "field": "o9fCSq_field",
5006
+ "option": "o9fCSq_option",
5007
+ "textarea": "o9fCSq_textarea",
5008
+ "sectionActions": "o9fCSq_sectionActions",
5009
+ "sectionTitle": "o9fCSq_sectionTitle",
5010
+ "rowMeta": "o9fCSq_rowMeta",
5011
+ "empty": "o9fCSq_empty",
4823
5012
  "fieldState": "o9fCSq_fieldState",
4824
5013
  "row": "o9fCSq_row",
5014
+ "note": "o9fCSq_note",
5015
+ "settingRow": "o9fCSq_settingRow",
4825
5016
  "selectChevron": "o9fCSq_selectChevron",
4826
- "optionKey": "o9fCSq_optionKey",
4827
- "textarea": "o9fCSq_textarea",
4828
- "formGrid": "o9fCSq_formGrid",
5017
+ "list": "o9fCSq_list",
5018
+ "trust": "o9fCSq_trust",
4829
5019
  "status": "o9fCSq_status",
4830
- "option": "o9fCSq_option",
5020
+ "input": "o9fCSq_input",
5021
+ "confirmRow": "o9fCSq_confirmRow",
5022
+ "fieldLabel": "o9fCSq_fieldLabel",
5023
+ "danger": "o9fCSq_danger",
5024
+ "formGrid": "o9fCSq_formGrid",
4831
5025
  "selectAnchor": "o9fCSq_selectAnchor",
4832
- "confirmText": "o9fCSq_confirmText",
4833
- "editor": "o9fCSq_editor",
4834
- "trust": "o9fCSq_trust",
4835
- "settingTitle": "o9fCSq_settingTitle",
5026
+ "formWide": "o9fCSq_formWide",
4836
5027
  "success": "o9fCSq_success",
4837
- "fieldError": "o9fCSq_fieldError",
4838
- "confirmRow": "o9fCSq_confirmRow",
4839
- "formField": "o9fCSq_formField",
4840
- "rowMeta": "o9fCSq_rowMeta",
4841
- "optionGrid": "o9fCSq_optionGrid",
4842
- "sectionTitle": "o9fCSq_sectionTitle",
4843
- "input": "o9fCSq_input",
4844
- "prefixedInput": "o9fCSq_prefixedInput",
5028
+ "editor": "o9fCSq_editor",
5029
+ "panel": "o9fCSq_panel",
5030
+ "disclosureOpen": "o9fCSq_disclosureOpen",
4845
5031
  "reset": "o9fCSq_reset",
4846
- "optionWide": "o9fCSq_optionWide",
4847
- "intro": "o9fCSq_intro",
4848
- "page": "o9fCSq_page",
4849
- "link": "o9fCSq_link",
4850
- "error": "o9fCSq_error",
4851
- "editorTitle": "o9fCSq_editorTitle",
4852
- "disclosure": "o9fCSq_disclosure",
5032
+ "prefixedInput": "o9fCSq_prefixedInput",
5033
+ "optionKey": "o9fCSq_optionKey",
4853
5034
  "optionName": "o9fCSq_optionName",
4854
- "settingText": "o9fCSq_settingText",
4855
- "segmented": "o9fCSq_segmented",
4856
- "danger": "o9fCSq_danger",
4857
- "sectionActions": "o9fCSq_sectionActions",
4858
- "settingControl": "o9fCSq_settingControl",
4859
- "select": "o9fCSq_select",
4860
5035
  "selectValue": "o9fCSq_selectValue",
5036
+ "rowMain": "o9fCSq_rowMain",
5037
+ "confirmText": "o9fCSq_confirmText",
5038
+ "optionWide": "o9fCSq_optionWide",
5039
+ "warning": "o9fCSq_warning",
5040
+ "settingTitle": "o9fCSq_settingTitle",
4861
5041
  "rowLine": "o9fCSq_rowLine",
4862
- "prefixed": "o9fCSq_prefixed",
4863
- "disclosureOpen": "o9fCSq_disclosureOpen",
4864
- "prefix": "o9fCSq_prefix",
4865
- "empty": "o9fCSq_empty",
4866
- "sectionHead": "o9fCSq_sectionHead",
4867
- "disclosureIcon": "o9fCSq_disclosureIcon",
4868
- "settingRow": "o9fCSq_settingRow",
4869
- "fieldLabel": "o9fCSq_fieldLabel",
4870
- "field": "o9fCSq_field",
4871
- "section": "o9fCSq_section",
4872
- "fieldHead": "o9fCSq_fieldHead",
4873
- "optionGroup": "o9fCSq_optionGroup",
4874
- "rowActions": "o9fCSq_rowActions",
4875
- "note": "o9fCSq_note",
4876
- "formWide": "o9fCSq_formWide",
4877
- "prefixedDisabled": "o9fCSq_prefixedDisabled",
4878
- "rowTitle": "o9fCSq_rowTitle",
4879
- "selectCompact": "o9fCSq_selectCompact"
5042
+ "optionGrid": "o9fCSq_optionGrid",
5043
+ "disclosureIcon": "o9fCSq_disclosureIcon"
4880
5044
  };
4881
5045
  //#endregion
4882
5046
  //#region src/client/settings/CredentialEditor.tsx
@@ -5317,6 +5481,18 @@ window.__ModuleLoader__.load({
5317
5481
  });
5318
5482
  }
5319
5483
  //#endregion
5484
+ //#region src/client/settings/EnhancedToolsSection.tsx
5485
+ const EnhancedToolsSection = createEnhancedToolsSection({
5486
+ classes: Settings_module_css_default,
5487
+ parts: settingsParts,
5488
+ sparse: sparse_exports,
5489
+ keys: {
5490
+ title: "enhanced.title",
5491
+ description: "enhanced.description",
5492
+ consent: "enhanced.consent"
5493
+ }
5494
+ });
5495
+ //#endregion
5320
5496
  //#region src/client/settings/PairingsSection.tsx
5321
5497
  const PairingsSection = createPairingsSection({
5322
5498
  classes: Settings_module_css_default,
@@ -5350,6 +5526,7 @@ window.__ModuleLoader__.load({
5350
5526
  optionGroups: { "session-model": SESSION_MODEL_GROUPS },
5351
5527
  keys: {
5352
5528
  "services.title": "services.title",
5529
+ "services.optInNotice": "services.optInNotice",
5353
5530
  "options.hint": "options.hint",
5354
5531
  "options.keylessMore": "options.keylessMore",
5355
5532
  "options.invalid": "options.invalid",
@@ -5385,12 +5562,12 @@ window.__ModuleLoader__.load({
5385
5562
  * Controls write immediately as sparse operations against the revision the
5386
5563
  * page shows; credentials go to DSH Credentials only.
5387
5564
  */
5388
- function SettingsPage({ useSettings, useCredentials, useRoute, usePairings, mutate, saveCredential, forgetPairing, t }) {
5565
+ function SettingsPage({ useSettings, useCredentials, useRoute, usePairings, readSettings, mutate, saveCredential, forgetPairing, t }) {
5389
5566
  const snapshot = useSettings((value) => value);
5390
5567
  const credentials = useCredentials((value) => value);
5391
5568
  const route = useRoute((value) => value);
5392
5569
  const pairings = usePairings((value) => value);
5393
- const { view, write, migrationError } = useSettingsDocument(snapshot, resolveSettings, mutate);
5570
+ const { view, write, migrationError } = useSettingsDocument(snapshot, readSettings, resolveSettings, mutate);
5394
5571
  if (snapshot.status === "unavailable") return null;
5395
5572
  if (snapshot.value === void 0 || snapshot.revision === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
5396
5573
  className: Settings_module_css_default.status,
@@ -5455,6 +5632,11 @@ window.__ModuleLoader__.load({
5455
5632
  credentials,
5456
5633
  t
5457
5634
  }),
5635
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnhancedToolsSection, {
5636
+ doc,
5637
+ write,
5638
+ t
5639
+ }),
5458
5640
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ServicesSection, {
5459
5641
  doc,
5460
5642
  write,
@@ -5554,6 +5736,7 @@ window.__ModuleLoader__.load({
5554
5736
  route: route.source,
5555
5737
  pairings: pairings.source
5556
5738
  },
5739
+ readSettings: () => settings.getSnapshot(),
5557
5740
  async mutate(ops, revision) {
5558
5741
  return settings.mutate(ops, revision);
5559
5742
  },
@@ -5572,7 +5755,7 @@ window.__ModuleLoader__.load({
5572
5755
  locale: NS,
5573
5756
  inject: () => page
5574
5757
  }, SettingsPage))), "search: settings page");
5575
- const section = searchSection(selection, navigation, t);
5758
+ const section = searchSection(selection, navigation, remoteServicesOffSource(settings, CATALOG, resolveSettings), t);
5576
5759
  scope.inject(["webConnections"], (ui) => {
5577
5760
  ui.effect(() => ui.webConnections.registerRoute("search", route), "search: route facts");
5578
5761
  ui.effect(() => {