@xrkseek/harness-cli 0.0.3 → 0.0.5

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.
Files changed (128) hide show
  1. package/dist/commands/serve.d.ts.map +1 -1
  2. package/dist/commands/serve.js +20 -9
  3. package/dist/commands/serve.js.map +1 -1
  4. package/dist/parse-args.d.ts.map +1 -1
  5. package/dist/parse-args.js +4 -3
  6. package/dist/parse-args.js.map +1 -1
  7. package/node_modules/@xrkseek/core-agent-loop/dist/index.d.ts.map +1 -1
  8. package/node_modules/@xrkseek/core-agent-loop/dist/index.js +8 -2
  9. package/node_modules/@xrkseek/core-agent-loop/dist/index.js.map +1 -1
  10. package/node_modules/@xrkseek/core-system-prompt/README.md +2 -2
  11. package/node_modules/@xrkseek/core-system-prompt/dist/index.d.ts +1 -1
  12. package/node_modules/@xrkseek/core-system-prompt/dist/index.d.ts.map +1 -1
  13. package/node_modules/@xrkseek/core-system-prompt/dist/index.js +1 -1
  14. package/node_modules/@xrkseek/core-system-prompt/dist/index.js.map +1 -1
  15. package/node_modules/@xrkseek/core-system-prompt/dist/three-layer.d.ts +22 -4
  16. package/node_modules/@xrkseek/core-system-prompt/dist/three-layer.d.ts.map +1 -1
  17. package/node_modules/@xrkseek/core-system-prompt/dist/three-layer.js +21 -8
  18. package/node_modules/@xrkseek/core-system-prompt/dist/three-layer.js.map +1 -1
  19. package/node_modules/@xrkseek/exec-web/dist/fetch-http.js +1 -1
  20. package/node_modules/@xrkseek/exec-web/dist/index.d.ts +5 -1
  21. package/node_modules/@xrkseek/exec-web/dist/index.d.ts.map +1 -1
  22. package/node_modules/@xrkseek/exec-web/dist/index.js +6 -6
  23. package/node_modules/@xrkseek/exec-web/dist/index.js.map +1 -1
  24. package/node_modules/@xrkseek/exec-web/dist/search-providers.d.ts +20 -3
  25. package/node_modules/@xrkseek/exec-web/dist/search-providers.d.ts.map +1 -1
  26. package/node_modules/@xrkseek/exec-web/dist/search-providers.js +67 -28
  27. package/node_modules/@xrkseek/exec-web/dist/search-providers.js.map +1 -1
  28. package/node_modules/@xrkseek/preset-harness/dist/preset.d.ts +4 -0
  29. package/node_modules/@xrkseek/preset-harness/dist/preset.d.ts.map +1 -1
  30. package/node_modules/@xrkseek/preset-harness/dist/preset.js +1 -1
  31. package/node_modules/@xrkseek/preset-harness/dist/preset.js.map +1 -1
  32. package/node_modules/@xrkseek/preset-harness/dist/tsconfig.tsbuildinfo +1 -1
  33. package/node_modules/@xrkseek/preset-minimal/dist/tsconfig.tsbuildinfo +1 -1
  34. package/node_modules/@xrkseek/preset-server/dist/preset.d.ts.map +1 -1
  35. package/node_modules/@xrkseek/preset-server/dist/preset.js +2 -1
  36. package/node_modules/@xrkseek/preset-server/dist/preset.js.map +1 -1
  37. package/node_modules/@xrkseek/preset-server/dist/tsconfig.tsbuildinfo +1 -1
  38. package/node_modules/@xrkseek/protocol/dist/token-usage.d.ts +7 -1
  39. package/node_modules/@xrkseek/protocol/dist/token-usage.d.ts.map +1 -1
  40. package/node_modules/@xrkseek/protocol/dist/token-usage.js +49 -24
  41. package/node_modules/@xrkseek/protocol/dist/token-usage.js.map +1 -1
  42. package/node_modules/@xrkseek/server-config/dist/index.js +1 -1
  43. package/node_modules/@xrkseek/server-face/dist/context.d.ts +6 -5
  44. package/node_modules/@xrkseek/server-face/dist/context.d.ts.map +1 -1
  45. package/node_modules/@xrkseek/server-face/dist/context.js +1 -3
  46. package/node_modules/@xrkseek/server-face/dist/context.js.map +1 -1
  47. package/node_modules/@xrkseek/server-face/dist/face-schema.d.ts +3 -2
  48. package/node_modules/@xrkseek/server-face/dist/face-schema.d.ts.map +1 -1
  49. package/node_modules/@xrkseek/server-face/dist/face-schema.js +16 -4
  50. package/node_modules/@xrkseek/server-face/dist/face-schema.js.map +1 -1
  51. package/node_modules/@xrkseek/server-face/dist/handlers/catalog.d.ts.map +1 -1
  52. package/node_modules/@xrkseek/server-face/dist/handlers/catalog.js +26 -12
  53. package/node_modules/@xrkseek/server-face/dist/handlers/catalog.js.map +1 -1
  54. package/node_modules/@xrkseek/server-face/dist/handlers/session.d.ts.map +1 -1
  55. package/node_modules/@xrkseek/server-face/dist/handlers/session.js +19 -24
  56. package/node_modules/@xrkseek/server-face/dist/handlers/session.js.map +1 -1
  57. package/node_modules/@xrkseek/server-face/dist/index.d.ts +3 -3
  58. package/node_modules/@xrkseek/server-face/dist/index.d.ts.map +1 -1
  59. package/node_modules/@xrkseek/server-face/dist/index.js +3 -3
  60. package/node_modules/@xrkseek/server-face/dist/index.js.map +1 -1
  61. package/node_modules/@xrkseek/server-face/dist/llm-provider-context.d.ts +44 -6
  62. package/node_modules/@xrkseek/server-face/dist/llm-provider-context.d.ts.map +1 -1
  63. package/node_modules/@xrkseek/server-face/dist/llm-provider-context.js +220 -34
  64. package/node_modules/@xrkseek/server-face/dist/llm-provider-context.js.map +1 -1
  65. package/node_modules/@xrkseek/server-face/dist/llm-resolve.d.ts.map +1 -1
  66. package/node_modules/@xrkseek/server-face/dist/llm-resolve.js +4 -7
  67. package/node_modules/@xrkseek/server-face/dist/llm-resolve.js.map +1 -1
  68. package/node_modules/@xrkseek/server-face/dist/model-catalog.d.ts +1 -1
  69. package/node_modules/@xrkseek/server-face/dist/model-catalog.d.ts.map +1 -1
  70. package/node_modules/@xrkseek/server-face/dist/model-catalog.js +23 -26
  71. package/node_modules/@xrkseek/server-face/dist/model-catalog.js.map +1 -1
  72. package/node_modules/@xrkseek/server-face/dist/presets-catalog.d.ts +13 -1
  73. package/node_modules/@xrkseek/server-face/dist/presets-catalog.d.ts.map +1 -1
  74. package/node_modules/@xrkseek/server-face/dist/presets-catalog.js +24 -9
  75. package/node_modules/@xrkseek/server-face/dist/presets-catalog.js.map +1 -1
  76. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts +1 -1
  77. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts.map +1 -1
  78. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js +116 -14
  79. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js.map +1 -1
  80. package/node_modules/@xrkseek/server-face/dist/settings-document.d.ts +1 -1
  81. package/node_modules/@xrkseek/server-face/dist/settings-document.d.ts.map +1 -1
  82. package/node_modules/@xrkseek/server-face/dist/settings-document.js +25 -22
  83. package/node_modules/@xrkseek/server-face/dist/settings-document.js.map +1 -1
  84. package/node_modules/@xrkseek/server-face/dist/settings-layers.d.ts +3 -0
  85. package/node_modules/@xrkseek/server-face/dist/settings-layers.d.ts.map +1 -0
  86. package/node_modules/@xrkseek/server-face/dist/settings-layers.js +19 -0
  87. package/node_modules/@xrkseek/server-face/dist/settings-layers.js.map +1 -0
  88. package/node_modules/@xrkseek/server-face/dist/settings-schemas.d.ts.map +1 -1
  89. package/node_modules/@xrkseek/server-face/dist/settings-schemas.js +18 -2
  90. package/node_modules/@xrkseek/server-face/dist/settings-schemas.js.map +1 -1
  91. package/node_modules/@xrkseek/server-host/dist/index.d.ts +11 -2
  92. package/node_modules/@xrkseek/server-host/dist/index.d.ts.map +1 -1
  93. package/node_modules/@xrkseek/server-host/dist/index.js +67 -16
  94. package/node_modules/@xrkseek/server-host/dist/index.js.map +1 -1
  95. package/node_modules/@xrkseek/server-host/dist/mcp-wire.d.ts +9 -4
  96. package/node_modules/@xrkseek/server-host/dist/mcp-wire.d.ts.map +1 -1
  97. package/node_modules/@xrkseek/server-host/dist/mcp-wire.js +42 -7
  98. package/node_modules/@xrkseek/server-host/dist/mcp-wire.js.map +1 -1
  99. package/package.json +1 -1
  100. package/product-web/boot.json +1 -1
  101. package/product-web/plugins/@xrkseek/client-locale/client.js +3 -3
  102. package/product-web/plugins/@xrkseek/client-ui-agent-preset/client.js +35 -35
  103. package/product-web/plugins/@xrkseek/client-ui-commands/client.js +6 -6
  104. package/product-web/plugins/@xrkseek/client-ui-conversation/client.js +160 -160
  105. package/product-web/plugins/@xrkseek/client-ui-deliverables/client.js +6 -6
  106. package/product-web/plugins/@xrkseek/client-ui-directory-picker-browse/client.js +29 -29
  107. package/product-web/plugins/@xrkseek/client-ui-goal/client.js +6 -6
  108. package/product-web/plugins/@xrkseek/client-ui-input-trigger/client.js +5 -5
  109. package/product-web/plugins/@xrkseek/client-ui-jobs/client.js +7 -7
  110. package/product-web/plugins/@xrkseek/client-ui-layout/client.js +3 -3
  111. package/product-web/plugins/@xrkseek/client-ui-message-feedback/client.js +5 -5
  112. package/product-web/plugins/@xrkseek/client-ui-model-selection/client.js +18 -18
  113. package/product-web/plugins/@xrkseek/client-ui-permission-presets/client.js +2 -2
  114. package/product-web/plugins/@xrkseek/client-ui-plan/client.js +3 -3
  115. package/product-web/plugins/@xrkseek/client-ui-settings/client.js +7 -1
  116. package/product-web/plugins/@xrkseek/client-ui-settings-general/client.js +15 -15
  117. package/product-web/plugins/@xrkseek/client-ui-settings-models/client.js +57 -57
  118. package/product-web/plugins/@xrkseek/client-ui-settings-plugin-inventory/client.js +12 -12
  119. package/product-web/plugins/@xrkseek/client-ui-settings-plugins/client.js +651 -163
  120. package/product-web/plugins/@xrkseek/client-ui-sidebar/client.js +12 -12
  121. package/product-web/plugins/@xrkseek/client-ui-skill/client.js +11 -11
  122. package/product-web/plugins/@xrkseek/client-ui-subagent/client.js +19 -19
  123. package/product-web/plugins/@xrkseek/client-ui-theme/client.js +1 -1
  124. package/product-web/plugins/@xrkseek/client-ui-tool/client.js +37 -37
  125. package/product-web/plugins/@xrkseek/client-ui-trajectory/client.js +143 -143
  126. package/product-web/plugins/@xrkseek/client-ui-user-questions/client.js +26 -26
  127. package/product-web/plugins/@xrkseek/client-ui-workflow-run/client.js +17 -17
  128. package/product-web/plugins/@xrkseek/client-ui-workspace/client.js +55 -55
@@ -10,7 +10,7 @@ window.__ModuleLoader__.load({
10
10
  let _xrkseek_client_ui_primitives = require("@xrkseek/client-ui-primitives");
11
11
  let _xrkseek_client_runtime_client = require("@xrkseek/client-runtime/client");
12
12
  //#region \0xrk-css:C:\Users\sunflowerss\Desktop\XRKgrocery\XRK-harness\packages\client\ui-settings-plugins\src\client\fields.module.css.mjs
13
- const css$3 = ".MiE2dW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.MiE2dW_field+.MiE2dW_field{border-top:1px solid var(--dsw-alias-border-l2)}.MiE2dW_head{align-items:center;gap:8px;display:flex}.MiE2dW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.MiE2dW_badges{align-items:center;gap:8px;display:inline-flex}.MiE2dW_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.MiE2dW_badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}.MiE2dW_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.MiE2dW_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.MiE2dW_reset:disabled{cursor:default}.MiE2dW_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));background:var(--dsw-alias-bg-layer-1);width:100%;height:32px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 10px;font-size:13px;line-height:1.5}.MiE2dW_input::placeholder{color:var(--dsw-alias-label-dimmed)}.MiE2dW_input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.MiE2dW_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.MiE2dW_input:-webkit-autofill,.MiE2dW_input:-webkit-autofill:hover,.MiE2dW_input:-webkit-autofill:focus{-webkit-text-fill-color:var(--dsw-alias-label-primary);caret-color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));box-shadow:0 0 0 1000px var(--dsw-alias-bg-layer-1) inset;transition:background-color 99999s ease-out}.MiE2dW_select{cursor:pointer;max-width:none;}.MiE2dW_inputInvalid{border-color:var(--dsw-alias-label-error);}.MiE2dW_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.MiE2dW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}";
13
+ const css$3 = ".MiE2dW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.MiE2dW_field+.MiE2dW_field{border-top:1px solid var(--dsw-alias-border-l2)}.MiE2dW_head{align-items:center;gap:8px;display:flex}.MiE2dW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.MiE2dW_badges{align-items:center;gap:8px;display:inline-flex}.MiE2dW_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.MiE2dW_badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}.MiE2dW_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.MiE2dW_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.MiE2dW_reset:disabled{cursor:default}.MiE2dW_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));background:var(--dsw-alias-bg-layer-1);width:100%;height:32px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 10px;font-size:13px;line-height:1.5}.MiE2dW_input::placeholder{color:var(--dsw-alias-label-dimmed)}.MiE2dW_input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.MiE2dW_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.MiE2dW_input:-webkit-autofill,.MiE2dW_input:-webkit-autofill:hover,.MiE2dW_input:-webkit-autofill:focus{-webkit-text-fill-color:var(--dsw-alias-label-primary);caret-color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));box-shadow:0 0 0 1000px var(--dsw-alias-bg-layer-1) inset;transition:background-color 99999s ease-out}.MiE2dW_select{appearance:none;cursor:pointer;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 12px center;background-repeat:no-repeat;background-size:12px 12px;max-width:none;padding-right:32px}.MiE2dW_inputInvalid{border-color:var(--dsw-alias-label-error)}.MiE2dW_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.MiE2dW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}";
14
14
  const tagId$3 = "@xrkseek/client-ui-settings-plugins/fields.module.css";
15
15
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
16
16
  const tag = document.createElement("style");
@@ -21,17 +21,17 @@ window.__ModuleLoader__.load({
21
21
  }
22
22
  var fields_module_css_default = {
23
23
  "label": "MiE2dW_label",
24
+ "reset": "MiE2dW_reset",
24
25
  "input": "MiE2dW_input",
26
+ "inputInvalid": "MiE2dW_inputInvalid",
27
+ "badgeMuted": "MiE2dW_badgeMuted",
25
28
  "invalid": "MiE2dW_invalid",
26
- "badge": "MiE2dW_badge",
27
- "reset": "MiE2dW_reset",
28
29
  "field": "MiE2dW_field",
30
+ "hint": "MiE2dW_hint",
29
31
  "head": "MiE2dW_head",
30
- "badges": "MiE2dW_badges",
31
- "badgeMuted": "MiE2dW_badgeMuted",
32
+ "badge": "MiE2dW_badge",
32
33
  "select": "MiE2dW_select",
33
- "inputInvalid": "MiE2dW_inputInvalid",
34
- "hint": "MiE2dW_hint"
34
+ "badges": "MiE2dW_badges"
35
35
  };
36
36
  //#endregion
37
37
  //#region src/client/fields.tsx
@@ -42,6 +42,36 @@ window.__ModuleLoader__.load({
42
42
  * layer. Nothing here writes: a control reports what the user typed, and the
43
43
  * card's save is the single point where a draft becomes a document mutation.
44
44
  */
45
+ /** Same chrome as PlainField, for a short option list (MCP transport). */
46
+ function SelectField(props) {
47
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
48
+ className: fields_module_css_default.field,
49
+ children: [
50
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
51
+ className: fields_module_css_default.label,
52
+ htmlFor: props.id,
53
+ children: props.label
54
+ }),
55
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
56
+ id: props.id,
57
+ className: `${fields_module_css_default.input} ${fields_module_css_default.select}`,
58
+ value: props.value,
59
+ disabled: props.disabled,
60
+ onChange: (event) => {
61
+ props.onChange(event.target.value);
62
+ },
63
+ children: props.options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
64
+ value: option.value,
65
+ children: option.label
66
+ }, option.value))
67
+ }),
68
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
69
+ className: fields_module_css_default.hint,
70
+ children: props.hint
71
+ })
72
+ ]
73
+ });
74
+ }
45
75
  /**
46
76
  * A staged value field. `numeric` only hints the keypad: which drafts a field
47
77
  * accepts is decided by its spec, so the control never silently rewrites what
@@ -75,7 +105,7 @@ window.__ModuleLoader__.load({
75
105
  }),
76
106
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
77
107
  id: props.id,
78
- className: props.invalid ? fields_module_css_default.inputInvalid : fields_module_css_default.input,
108
+ className: props.invalid ? `${fields_module_css_default.input} ${fields_module_css_default.inputInvalid}` : fields_module_css_default.input,
79
109
  type: "text",
80
110
  ...props.numeric === true ? { inputMode: "numeric" } : {},
81
111
  ...props.invalid ? { "aria-invalid": true } : {},
@@ -93,6 +123,49 @@ window.__ModuleLoader__.load({
93
123
  ]
94
124
  });
95
125
  }
126
+ /**
127
+ * A write-only credential control. The value never rides a response, so the
128
+ * control reports only whether one is configured and starts blank; a blank
129
+ * draft writes nothing, which keeps the stored key rather than clearing it.
130
+ * @param props - the field's copy, its staged text, and the configured state.
131
+ * @returns the labelled control.
132
+ */
133
+ function SecretField(props) {
134
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
135
+ className: fields_module_css_default.field,
136
+ children: [
137
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
138
+ className: fields_module_css_default.head,
139
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
140
+ className: fields_module_css_default.label,
141
+ htmlFor: props.id,
142
+ children: props.label
143
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
144
+ className: fields_module_css_default.badges,
145
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
146
+ className: props.configured ? fields_module_css_default.badge : fields_module_css_default.badgeMuted,
147
+ children: props.stateLabel
148
+ })
149
+ })]
150
+ }),
151
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
152
+ id: props.id,
153
+ className: fields_module_css_default.input,
154
+ type: "password",
155
+ autoComplete: "off",
156
+ value: props.text,
157
+ disabled: props.disabled,
158
+ onChange: (event) => {
159
+ props.onEdit(event.target.value);
160
+ }
161
+ }),
162
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
163
+ className: fields_module_css_default.hint,
164
+ children: props.hint
165
+ })
166
+ ]
167
+ });
168
+ }
96
169
  //#endregion
97
170
  //#region ../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
98
171
  function r(e) {
@@ -120,21 +193,21 @@ window.__ModuleLoader__.load({
120
193
  document.head.appendChild(tag);
121
194
  }
122
195
  var PluginCard_module_css_default = {
123
- "headText": "YRvGva_headText",
124
- "failed": "YRvGva_failed",
125
- "chevronOpen": "YRvGva_chevronOpen",
126
196
  "header": "YRvGva_header",
127
- "save": "YRvGva_save",
128
- "body": "YRvGva_body",
129
- "readOnly": "YRvGva_readOnly",
130
- "name": "YRvGva_name",
131
197
  "card": "YRvGva_card",
132
- "description": "YRvGva_description",
133
- "chevron": "YRvGva_chevron",
134
198
  "discard": "YRvGva_discard",
199
+ "description": "YRvGva_description",
200
+ "save": "YRvGva_save",
201
+ "readOnly": "YRvGva_readOnly",
135
202
  "pending": "YRvGva_pending",
203
+ "chevron": "YRvGva_chevron",
204
+ "footer": "YRvGva_footer",
136
205
  "cardOpen": "YRvGva_cardOpen",
137
- "footer": "YRvGva_footer"
206
+ "name": "YRvGva_name",
207
+ "body": "YRvGva_body",
208
+ "failed": "YRvGva_failed",
209
+ "headText": "YRvGva_headText",
210
+ "chevronOpen": "YRvGva_chevronOpen"
138
211
  };
139
212
  //#endregion
140
213
  //#region src/client/PluginCard.tsx
@@ -329,14 +402,14 @@ window.__ModuleLoader__.load({
329
402
  document.head.appendChild(tag);
330
403
  }
331
404
  var PluginsSettingsSection_module_css_default = {
332
- "tabs": "ha2I9q_tabs",
405
+ "heading": "ha2I9q_heading",
406
+ "empty": "ha2I9q_empty",
333
407
  "tab": "ha2I9q_tab",
408
+ "tabs": "ha2I9q_tabs",
409
+ "intro": "ha2I9q_intro",
334
410
  "cards": "ha2I9q_cards",
335
- "empty": "ha2I9q_empty",
336
411
  "section": "ha2I9q_section",
337
- "heading": "ha2I9q_heading",
338
- "panel": "ha2I9q_panel",
339
- "intro": "ha2I9q_intro"
412
+ "panel": "ha2I9q_panel"
340
413
  };
341
414
  //#endregion
342
415
  //#region src/client/ConfigurablePluginsTab.tsx
@@ -367,7 +440,7 @@ window.__ModuleLoader__.load({
367
440
  }
368
441
  //#endregion
369
442
  //#region \0xrk-css:C:\Users\sunflowerss\Desktop\XRKgrocery\XRK-harness\packages\client\ui-settings-plugins\src\client\McpCard.module.css.mjs
370
- const css = ".FVl50a_block+.FVl50a_block{border-top:1px solid var(--dsw-alias-border-l2);margin-top:4px;padding-top:4px}.FVl50a_heading{color:var(--dsw-alias-label-primary);margin:0;padding:12px 0 4px;font-size:13px;font-weight:600;line-height:1.5}.FVl50a_note{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.FVl50a_empty{border:1px dashed var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));text-align:center;color:var(--dsw-alias-label-tertiary);border-radius:8px;margin:8px 0 0;padding:12px;font-size:12px;line-height:1.5}.FVl50a_invalid{color:var(--dsw-alias-label-error);margin:8px 0 0;font-size:12px;line-height:1.5}.FVl50a_connectedList{flex-direction:column;gap:6px;margin:8px 0 0;padding:0;list-style:none;display:flex}.FVl50a_connectedRow{flex-wrap:wrap;align-items:center;gap:8px;padding:6px 0;display:flex}.FVl50a_connectedName{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500}.FVl50a_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.FVl50a_badgeMuted{color:var(--dsw-alias-label-tertiary);font-weight:400;}.FVl50a_badgeError{color:var(--dsw-alias-label-error);}.FVl50a_list{flex-direction:column;gap:0;margin-top:4px;display:flex}.FVl50a_entry{border:none;border-top:1px solid var(--dsw-alias-border-l2);background:0 0;border-radius:0;padding:4px 0 8px}.FVl50a_entry:first-child{border-top:none;padding-top:0}.FVl50a_entryHead{background:0 0;border:none;justify-content:space-between;align-items:center;gap:8px;padding:8px 0 0;display:flex}.FVl50a_entryTitle{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:1.5;overflow:hidden}.FVl50a_remove{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:inline-flex}.FVl50a_remove:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-error-primary,var(--dsw-alias-label-error))}.FVl50a_remove:disabled{opacity:.4;cursor:default}.FVl50a_entryBody{padding:0}.FVl50a_pasteLabel{color:var(--dsw-alias-label-primary);margin:12px 0 6px;font-size:13px;font-weight:500;line-height:1.5}.FVl50a_paste{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));background:var(--dsw-alias-bg-layer-1);width:100%;min-height:96px;font:inherit;color:var(--dsw-alias-label-primary);resize:vertical;border-radius:8px;padding:8px 10px;font-size:12px;line-height:1.5}.FVl50a_paste::placeholder{color:var(--dsw-alias-label-dimmed)}.FVl50a_paste:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.FVl50a_paste:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.FVl50a_add{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;margin-top:8px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.FVl50a_add:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-module-platform))}.FVl50a_add:disabled{opacity:.4;cursor:default}";
443
+ const css = ".FVl50a_block+.FVl50a_block{border-top:1px solid var(--dsw-alias-border-l2);margin-top:4px;padding-top:4px}.FVl50a_heading{color:var(--dsw-alias-label-primary);margin:0;padding:12px 0 4px;font-size:13px;font-weight:600;line-height:1.5}.FVl50a_note{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.FVl50a_empty{border:1px dashed var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));text-align:center;color:var(--dsw-alias-label-tertiary);border-radius:8px;margin:8px 0 0;padding:12px;font-size:12px;line-height:1.5}.FVl50a_invalid{color:var(--dsw-alias-label-error);margin:8px 0 0;font-size:12px;line-height:1.5}.FVl50a_connectedList{flex-direction:column;gap:6px;margin:8px 0 0;padding:0;list-style:none;display:flex}.FVl50a_connectedRow{flex-wrap:wrap;align-items:center;gap:8px;padding:6px 0;display:flex}.FVl50a_connectedName{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500}.FVl50a_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.FVl50a_badgeMuted{color:var(--dsw-alias-label-tertiary);font-weight:400}.FVl50a_badgeError{color:var(--dsw-alias-label-error)}.FVl50a_badgeOk{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}.FVl50a_badgeWarn{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-tertiary))}.FVl50a_allowRow{color:var(--dsw-alias-label-primary);cursor:pointer;align-items:flex-start;gap:10px;margin:12px 0 4px;font-size:13px;line-height:1.4;display:flex}.FVl50a_allowRow input{margin-top:3px}.FVl50a_allowTitle{font-weight:600;display:block}.FVl50a_allowHint{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:12px;display:block}.FVl50a_entryTitleRow{flex-wrap:wrap;align-items:center;gap:8px;min-width:0;display:flex}.FVl50a_statusDot{background:currentColor;border-radius:50%;flex-shrink:0;width:8px;height:8px;padding:0}.FVl50a_list{flex-direction:column;gap:0;margin-top:4px;display:flex}.FVl50a_entry{border:none;border-top:1px solid var(--dsw-alias-border-l2);background:0 0;border-radius:0;padding:4px 0 8px}.FVl50a_entry:first-child{border-top:none;padding-top:0}.FVl50a_entryHead{background:0 0;border:none;justify-content:space-between;align-items:center;gap:8px;padding:8px 0 0;display:flex}.FVl50a_entryTitle{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:1.5;overflow:hidden}.FVl50a_remove{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:inline-flex}.FVl50a_remove:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-error-primary,var(--dsw-alias-label-error))}.FVl50a_remove:disabled{opacity:.4;cursor:default}.FVl50a_entryBody{padding:0}.FVl50a_pasteLabel{color:var(--dsw-alias-label-primary);margin:12px 0 6px;font-size:13px;font-weight:500;line-height:1.5}.FVl50a_paste{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));background:var(--dsw-alias-bg-layer-1);width:100%;min-height:96px;font:inherit;color:var(--dsw-alias-label-primary);resize:vertical;border-radius:8px;padding:8px 10px;font-size:12px;line-height:1.5}.FVl50a_paste::placeholder{color:var(--dsw-alias-label-dimmed)}.FVl50a_paste:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.FVl50a_paste:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.FVl50a_add{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3,var(--dsw-alias-border-l2));height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;margin-top:8px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.FVl50a_add:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-module-platform))}.FVl50a_add:disabled{opacity:.4;cursor:default}";
371
444
  const tagId = "@xrkseek/client-ui-settings-plugins/McpCard.module.css";
372
445
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
373
446
  const tag = document.createElement("style");
@@ -377,30 +450,37 @@ window.__ModuleLoader__.load({
377
450
  document.head.appendChild(tag);
378
451
  }
379
452
  var McpCard_module_css_default = {
380
- "remove": "FVl50a_remove",
381
- "badgeError": "FVl50a_badgeError",
382
- "entry": "FVl50a_entry",
383
- "entryTitle": "FVl50a_entryTitle",
384
- "paste": "FVl50a_paste",
385
- "badgeMuted": "FVl50a_badgeMuted",
386
- "note": "FVl50a_note",
387
- "block": "FVl50a_block",
388
- "empty": "FVl50a_empty",
389
- "entryHead": "FVl50a_entryHead",
390
- "badge": "FVl50a_badge",
391
- "add": "FVl50a_add",
392
- "invalid": "FVl50a_invalid",
393
- "connectedList": "FVl50a_connectedList",
394
453
  "list": "FVl50a_list",
454
+ "pasteLabel": "FVl50a_pasteLabel",
455
+ "add": "FVl50a_add",
456
+ "empty": "FVl50a_empty",
395
457
  "connectedRow": "FVl50a_connectedRow",
458
+ "entryTitleRow": "FVl50a_entryTitleRow",
396
459
  "connectedName": "FVl50a_connectedName",
460
+ "badgeError": "FVl50a_badgeError",
461
+ "badgeWarn": "FVl50a_badgeWarn",
462
+ "block": "FVl50a_block",
463
+ "note": "FVl50a_note",
464
+ "allowHint": "FVl50a_allowHint",
465
+ "entry": "FVl50a_entry",
397
466
  "heading": "FVl50a_heading",
467
+ "invalid": "FVl50a_invalid",
468
+ "entryHead": "FVl50a_entryHead",
469
+ "badgeMuted": "FVl50a_badgeMuted",
470
+ "badgeOk": "FVl50a_badgeOk",
471
+ "allowTitle": "FVl50a_allowTitle",
472
+ "statusDot": "FVl50a_statusDot",
473
+ "allowRow": "FVl50a_allowRow",
474
+ "entryTitle": "FVl50a_entryTitle",
475
+ "connectedList": "FVl50a_connectedList",
476
+ "remove": "FVl50a_remove",
398
477
  "entryBody": "FVl50a_entryBody",
399
- "pasteLabel": "FVl50a_pasteLabel"
478
+ "badge": "FVl50a_badge",
479
+ "paste": "FVl50a_paste"
400
480
  };
401
481
  //#endregion
402
482
  //#region src/client/McpCard.tsx
403
- /** MCP desired-server card: JSON-block paste only (Cursor / Trae style). */
483
+ /** MCP desired-server card: allow toggle, per-row status, JSON paste. */
404
484
  /**
405
485
  * Render the MCP card.
406
486
  * @param props - locale copy, the card snapshot, and its form actions.
@@ -435,43 +515,23 @@ window.__ModuleLoader__.load({
435
515
  role: "note",
436
516
  children: state.note
437
517
  }) : null,
438
- state.connected.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
439
- className: McpCard_module_css_default.block,
440
- "aria-label": t("mcpConnectedHeading"),
441
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
442
- className: McpCard_module_css_default.heading,
443
- children: t("mcpConnectedHeading")
444
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
445
- className: McpCard_module_css_default.connectedList,
446
- children: state.connected.map((entry) => {
447
- const status = entry.status ?? "connected";
448
- const statusClass = status === "gave-up" ? McpCard_module_css_default.badgeError : status === "reconnecting" ? McpCard_module_css_default.badgeMuted : McpCard_module_css_default.badge;
449
- const statusLabel = status === "gave-up" ? t("mcpStatusGaveUp") : status === "reconnecting" ? t("mcpStatusReconnecting") : t("mcpStatusConnected");
450
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
451
- className: McpCard_module_css_default.connectedRow,
452
- "data-mcp-status": status,
453
- children: [
454
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
455
- className: McpCard_module_css_default.connectedName,
456
- children: entry.serverName
457
- }),
458
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
459
- className: statusClass,
460
- children: statusLabel
461
- }),
462
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
463
- className: McpCard_module_css_default.badgeMuted,
464
- children: [
465
- entry.toolCount,
466
- " ",
467
- t("mcpToolsLabel")
468
- ]
469
- })
470
- ]
471
- }, entry.id);
472
- })
473
- })]
474
- }) : null,
518
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
519
+ className: McpCard_module_css_default.allowRow,
520
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
521
+ type: "checkbox",
522
+ checked: state.allowConnect,
523
+ disabled,
524
+ onChange: (event) => {
525
+ props.setAllowConnect(event.target.checked);
526
+ }
527
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
528
+ className: McpCard_module_css_default.allowTitle,
529
+ children: t("mcpAllowConnect")
530
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
531
+ className: McpCard_module_css_default.allowHint,
532
+ children: t("mcpAllowConnectHint")
533
+ })] })]
534
+ }),
475
535
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
476
536
  className: McpCard_module_css_default.block,
477
537
  "aria-label": t("mcpServersHeading"),
@@ -528,20 +588,69 @@ window.__ModuleLoader__.load({
528
588
  ]
529
589
  });
530
590
  }
591
+ function statusCopy(t, status) {
592
+ switch (status) {
593
+ case "connected": return t("mcpStatusConnected");
594
+ case "reconnecting": return t("mcpStatusReconnecting");
595
+ case "gave-up": return t("mcpStatusGaveUp");
596
+ case "parked": return t("mcpStatusParked");
597
+ case "failed": return t("mcpStatusFailed");
598
+ default: return t("mcpStatusIdle");
599
+ }
600
+ }
601
+ function statusTone(status) {
602
+ if (status === "connected") return McpCard_module_css_default.badgeOk;
603
+ if (status === "failed" || status === "gave-up") return McpCard_module_css_default.badgeError;
604
+ if (status === "parked") return McpCard_module_css_default.badgeWarn;
605
+ return McpCard_module_css_default.badgeMuted;
606
+ }
607
+ function statusBadge(status) {
608
+ return `${McpCard_module_css_default.badge} ${statusTone(status)}`;
609
+ }
531
610
  function ServerSummary({ t, row, disabled, onRemove }) {
532
611
  const summary = row.transport === "http" ? row.url : [row.command, row.args].filter((part) => part.trim()).join(" ");
533
612
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
534
613
  className: McpCard_module_css_default.entry,
535
614
  "aria-label": row.serverName,
615
+ "data-mcp-status": row.status,
536
616
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
537
617
  className: McpCard_module_css_default.entryHead,
538
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
539
- className: McpCard_module_css_default.entryTitle,
540
- children: row.serverName
541
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
542
- className: McpCard_module_css_default.empty,
543
- children: summary || t("mcpServerRow").replace("{index}", "")
544
- })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
618
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
619
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
620
+ className: McpCard_module_css_default.entryTitleRow,
621
+ children: [
622
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
623
+ className: `${McpCard_module_css_default.statusDot} ${statusTone(row.status)}`,
624
+ "aria-hidden": true
625
+ }),
626
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
627
+ className: McpCard_module_css_default.entryTitle,
628
+ children: row.serverName
629
+ }),
630
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
631
+ className: statusBadge(row.status),
632
+ children: statusCopy(t, row.status)
633
+ }),
634
+ row.toolCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
635
+ className: `${McpCard_module_css_default.badge} ${McpCard_module_css_default.badgeMuted}`,
636
+ children: [
637
+ row.toolCount,
638
+ " ",
639
+ t("mcpToolsLabel")
640
+ ]
641
+ }) : null
642
+ ]
643
+ }),
644
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
645
+ className: McpCard_module_css_default.empty,
646
+ children: summary || t("mcpServerRow").replace("{index}", "")
647
+ }),
648
+ row.failureMessage ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
649
+ className: McpCard_module_css_default.invalid,
650
+ role: "status",
651
+ children: row.failureMessage
652
+ }) : null
653
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
545
654
  type: "button",
546
655
  className: McpCard_module_css_default.remove,
547
656
  "aria-label": `${t("mcpRemoveServer")} ${row.serverName}`,
@@ -554,6 +663,100 @@ window.__ModuleLoader__.load({
554
663
  });
555
664
  }
556
665
  //#endregion
666
+ //#region src/client/WebSearchCard.tsx
667
+ /**
668
+ * Render the web-search card.
669
+ * @param props - locale copy, the card snapshot, and its form actions.
670
+ * @returns the card.
671
+ */
672
+ function WebSearchCard(props) {
673
+ const { t } = props;
674
+ const state = props.useWebSearchCard((snapshot) => snapshot);
675
+ const disabled = !state.writable;
676
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(PluginCard, {
677
+ t,
678
+ titleKey: "webSearchTitle",
679
+ descriptionKey: "webSearchDescription",
680
+ state,
681
+ onSave: props.save,
682
+ onDiscard: props.discard,
683
+ children: [
684
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectField, {
685
+ id: "plugin-config-web-search-provider",
686
+ label: t("webSearchProvider"),
687
+ hint: t("webSearchProviderHint"),
688
+ disabled,
689
+ value: state.provider.text || "auto",
690
+ options: [
691
+ {
692
+ value: "auto",
693
+ label: t("webSearchProviderAuto")
694
+ },
695
+ {
696
+ value: "tavily",
697
+ label: t("webSearchProviderTavily")
698
+ },
699
+ {
700
+ value: "brave",
701
+ label: t("webSearchProviderBrave")
702
+ },
703
+ {
704
+ value: "parallel-free",
705
+ label: t("webSearchProviderParallel")
706
+ },
707
+ {
708
+ value: "duckduckgo",
709
+ label: t("webSearchProviderDuckduckgo")
710
+ }
711
+ ],
712
+ onChange: (value) => {
713
+ props.edit("provider", value);
714
+ }
715
+ }),
716
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretField, {
717
+ id: "plugin-config-web-search-tavily",
718
+ label: t("webSearchTavilyKey"),
719
+ hint: t("webSearchTavilyKeyHint"),
720
+ disabled: !state.tavilyWritable,
721
+ text: state.tavilyApiKey.text,
722
+ configured: state.tavilyConfigured,
723
+ stateLabel: state.tavilyConfigured ? t("webSearchKeySet") : t("webSearchKeyUnset"),
724
+ onEdit: (text) => {
725
+ props.edit("tavilyApiKey", text);
726
+ }
727
+ }),
728
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretField, {
729
+ id: "plugin-config-web-search-brave",
730
+ label: t("webSearchBraveKey"),
731
+ hint: t("webSearchBraveKeyHint"),
732
+ disabled: !state.braveWritable,
733
+ text: state.braveApiKey.text,
734
+ configured: state.braveConfigured,
735
+ stateLabel: state.braveConfigured ? t("webSearchKeySet") : t("webSearchKeyUnset"),
736
+ onEdit: (text) => {
737
+ props.edit("braveApiKey", text);
738
+ }
739
+ }),
740
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
741
+ id: "plugin-config-web-search-region",
742
+ label: t("webSearchRegion"),
743
+ hint: t("webSearchRegionHint"),
744
+ overriddenLabel: t("overridden"),
745
+ resetLabel: t("reset"),
746
+ invalidLabel: t("invalidNumber"),
747
+ disabled,
748
+ ...state.region,
749
+ onEdit: (text) => {
750
+ props.edit("region", text);
751
+ },
752
+ onReset: () => {
753
+ props.resetField("region");
754
+ }
755
+ })
756
+ ]
757
+ });
758
+ }
759
+ //#endregion
557
760
  //#region src/client/PluginsSettingsSection.tsx
558
761
  /** Plugins settings section: localized tabs around feature-owned pages. */
559
762
  /** Render one Plugins page whose contents arrive from feature-owned tabs. */
@@ -670,6 +873,25 @@ window.__ModuleLoader__.load({
670
873
  };
671
874
  }
672
875
  /**
876
+ * A free-text field. An empty draft clears the field, so emptying the control
877
+ * and saving is the same gesture as resetting it.
878
+ * @param field - field name inside the namespace section.
879
+ * @returns the field's conversion spec.
880
+ */
881
+ function textField(field) {
882
+ return {
883
+ field,
884
+ format: (value) => typeof value === "string" ? value : "",
885
+ parse: (text) => {
886
+ const trimmed = text.trim();
887
+ return trimmed === "" ? { kind: "clear" } : {
888
+ kind: "set",
889
+ value: trimmed
890
+ };
891
+ }
892
+ };
893
+ }
894
+ /**
673
895
  * Stages one card's edits over one settings namespace and writes them on save.
674
896
  *
675
897
  * The form publishes through a snapshot store because slot components read
@@ -958,6 +1180,9 @@ window.__ModuleLoader__.load({
958
1180
  scope;
959
1181
  store;
960
1182
  rows = [];
1183
+ allowConnect = false;
1184
+ /** True after the user toggles Allow connect (so save respects an explicit park). */
1185
+ allowTouched = false;
961
1186
  seeded = false;
962
1187
  saving = false;
963
1188
  failed = false;
@@ -979,11 +1204,13 @@ window.__ModuleLoader__.load({
979
1204
  return;
980
1205
  }
981
1206
  if (!this.seeded || force && !this.dirty()) {
982
- this.rows = serversOf(snapshot).map(rowToUi);
1207
+ this.rows = serversOf(snapshot).map((draft) => rowToUi(draft, snapshot));
1208
+ this.allowConnect = allowOf(snapshot);
1209
+ this.allowTouched = false;
983
1210
  this.seeded = true;
984
1211
  this.failed = false;
985
1212
  this.showErrors = false;
986
- }
1213
+ } else this.rows = this.rows.map((row) => enrichRowStatus(row, snapshot));
987
1214
  this.publish();
988
1215
  }
989
1216
  projection() {
@@ -999,7 +1226,7 @@ window.__ModuleLoader__.load({
999
1226
  saving: this.saving,
1000
1227
  failed: this.failed,
1001
1228
  rows: this.rows,
1002
- connected: connectedOf(snapshot),
1229
+ allowConnect: this.allowConnect,
1003
1230
  note: noteOf(snapshot)
1004
1231
  };
1005
1232
  }
@@ -1007,6 +1234,7 @@ window.__ModuleLoader__.load({
1007
1234
  if (!this.seeded) return false;
1008
1235
  const snapshot = this.scope.getSnapshot();
1009
1236
  if (snapshot.status !== "ready") return false;
1237
+ if (this.allowConnect !== allowOf(snapshot)) return true;
1010
1238
  return JSON.stringify(this.rows.map(rowFromUi)) !== JSON.stringify(serversOf(snapshot));
1011
1239
  }
1012
1240
  publish() {
@@ -1023,6 +1251,9 @@ window.__ModuleLoader__.load({
1023
1251
  removeRow: (index) => {
1024
1252
  this.removeRow(index);
1025
1253
  },
1254
+ setAllowConnect: (allow) => {
1255
+ this.setAllowConnect(allow);
1256
+ },
1026
1257
  edit: () => {},
1027
1258
  resetField: () => {},
1028
1259
  save: () => {
@@ -1033,6 +1264,12 @@ window.__ModuleLoader__.load({
1033
1264
  }
1034
1265
  };
1035
1266
  }
1267
+ setAllowConnect(allow) {
1268
+ this.allowConnect = allow;
1269
+ this.allowTouched = true;
1270
+ this.failed = false;
1271
+ this.publish();
1272
+ }
1036
1273
  editRow(index, patch) {
1037
1274
  const row = this.rows[index];
1038
1275
  if (row === void 0) return;
@@ -1059,7 +1296,9 @@ window.__ModuleLoader__.load({
1059
1296
  if (!raw) return "empty";
1060
1297
  const imported = rowsFromMcpPaste(raw);
1061
1298
  if (imported.length === 0) return "invalid";
1062
- this.rows = mergeRowsByName(this.rows, imported);
1299
+ const snapshot = this.scope.getSnapshot();
1300
+ this.rows = mergeRowsByName(this.rows, imported).map((row) => enrichRowStatus(row, snapshot));
1301
+ this.allowConnect = true;
1063
1302
  this.failed = false;
1064
1303
  this.publish();
1065
1304
  return "ok";
@@ -1067,6 +1306,10 @@ window.__ModuleLoader__.load({
1067
1306
  removeRow(index) {
1068
1307
  if (index < 0 || index >= this.rows.length) return;
1069
1308
  this.rows = this.rows.toSpliced(index, 1);
1309
+ if (this.rows.length === 0) {
1310
+ this.allowConnect = false;
1311
+ this.allowTouched = false;
1312
+ }
1070
1313
  this.failed = false;
1071
1314
  if (!this.rows.some((r) => validateRow(r) !== void 0)) this.showErrors = false;
1072
1315
  this.publish();
@@ -1074,7 +1317,9 @@ window.__ModuleLoader__.load({
1074
1317
  discard() {
1075
1318
  const snapshot = this.scope.getSnapshot();
1076
1319
  if (snapshot.status !== "ready") return;
1077
- this.rows = serversOf(snapshot).map(rowToUi);
1320
+ this.rows = serversOf(snapshot).map((draft) => rowToUi(draft, snapshot));
1321
+ this.allowConnect = allowOf(snapshot);
1322
+ this.allowTouched = false;
1078
1323
  this.failed = false;
1079
1324
  this.showErrors = false;
1080
1325
  this.publish();
@@ -1093,12 +1338,20 @@ window.__ModuleLoader__.load({
1093
1338
  this.showErrors = false;
1094
1339
  this.publish();
1095
1340
  const payload = this.rows.map(rowFromUi);
1341
+ const wantAllow = payload.length === 0 ? false : this.allowTouched ? this.allowConnect : true;
1342
+ this.allowConnect = wantAllow;
1343
+ await this.scope.set("allowConnect", wantAllow);
1096
1344
  await this.scope.set("servers", payload);
1097
1345
  const after = this.scope.getSnapshot();
1098
- const landed = after.status === "ready" && JSON.stringify(serversOf(after)) === JSON.stringify(payload);
1346
+ const landed = after.status === "ready" && allowOf(after) === wantAllow && JSON.stringify(serversOf(after)) === JSON.stringify(payload);
1099
1347
  this.saving = false;
1100
1348
  this.failed = !landed;
1101
- if (landed) this.seeded = true;
1349
+ if (landed) {
1350
+ this.seeded = true;
1351
+ this.allowTouched = false;
1352
+ this.rows = serversOf(after).map((draft) => rowToUi(draft, after));
1353
+ this.allowConnect = allowOf(after);
1354
+ }
1102
1355
  this.publish();
1103
1356
  }
1104
1357
  };
@@ -1106,36 +1359,94 @@ window.__ModuleLoader__.load({
1106
1359
  const raw = snapshot.value?.servers;
1107
1360
  return Array.isArray(raw) ? raw.map(normalizeStoredRow) : [];
1108
1361
  }
1109
- function connectedOf(snapshot) {
1110
- const raw = snapshot.value?.connected;
1111
- if (!Array.isArray(raw)) return [];
1112
- return raw.filter(isConnectedEntry);
1362
+ function allowOf(snapshot) {
1363
+ return snapshot.value?.allowConnect === true;
1113
1364
  }
1114
1365
  function noteOf(snapshot) {
1115
- return typeof snapshot.value?.note === "string" ? snapshot.value.note : "";
1366
+ const note = snapshot.value?.note;
1367
+ return typeof note === "string" ? note : "";
1368
+ }
1369
+ function connectedMap(snapshot) {
1370
+ const map = /* @__PURE__ */ new Map();
1371
+ const raw = snapshot.value?.connected;
1372
+ if (!Array.isArray(raw)) return map;
1373
+ for (const entry of raw) if (isConnectedEntry(entry)) map.set(entry.serverName, entry);
1374
+ return map;
1375
+ }
1376
+ function failureMap(snapshot) {
1377
+ const map = /* @__PURE__ */ new Map();
1378
+ const raw = snapshot.value?.connectFailures;
1379
+ if (!Array.isArray(raw)) return map;
1380
+ for (const entry of raw) {
1381
+ if (!entry || typeof entry !== "object") continue;
1382
+ const name = entry.serverName;
1383
+ const message = entry.message;
1384
+ if (typeof name === "string" && name && typeof message === "string") map.set(name, message);
1385
+ }
1386
+ return map;
1387
+ }
1388
+ function parkedSet(snapshot) {
1389
+ const raw = snapshot.value?.parked;
1390
+ return new Set(Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : []);
1391
+ }
1392
+ function resolveRowStatus(serverName, snapshot) {
1393
+ const live = connectedMap(snapshot).get(serverName);
1394
+ if (live) return {
1395
+ status: live.status ?? "connected",
1396
+ toolCount: live.toolCount
1397
+ };
1398
+ const failure = failureMap(snapshot).get(serverName);
1399
+ if (failure !== void 0) return {
1400
+ status: "failed",
1401
+ toolCount: 0,
1402
+ failureMessage: failure
1403
+ };
1404
+ if (!allowOf(snapshot) || parkedSet(snapshot).has(serverName)) return {
1405
+ status: "parked",
1406
+ toolCount: 0
1407
+ };
1408
+ return {
1409
+ status: "idle",
1410
+ toolCount: 0
1411
+ };
1412
+ }
1413
+ function enrichRowStatus(row, snapshot) {
1414
+ const resolved = resolveRowStatus(row.serverName, snapshot);
1415
+ return {
1416
+ ...row,
1417
+ ...resolved
1418
+ };
1116
1419
  }
1117
1420
  function isConnectedEntry(value) {
1118
- return value !== null && typeof value === "object" && typeof value.serverName === "string";
1421
+ if (!value || typeof value !== "object") return false;
1422
+ const row = value;
1423
+ return typeof row.id === "string" && typeof row.serverName === "string" && typeof row.kind === "string" && typeof row.toolCount === "number";
1119
1424
  }
1120
- function normalizeStoredRow(row) {
1121
- const url = typeof row.url === "string" ? row.url.trim() : "";
1122
- const command = typeof row.command === "string" ? row.command.trim() : "";
1425
+ function normalizeStoredRow(raw) {
1426
+ const serverName = typeof raw.serverName === "string" ? raw.serverName.trim() : "";
1427
+ const url = typeof raw.url === "string" ? raw.url.trim() : "";
1428
+ const command = typeof raw.command === "string" ? raw.command.trim() : "";
1429
+ const cwd = typeof raw.cwd === "string" ? raw.cwd.trim() : "";
1430
+ const args = Array.isArray(raw.args) ? raw.args.filter((part) => typeof part === "string") : void 0;
1123
1431
  return {
1124
- serverName: String(row.serverName ?? "").trim(),
1125
- ...url ? { url } : command ? { command } : {},
1126
- ...Array.isArray(row.args) && row.args.length > 0 ? { args: row.args.map(String) } : {},
1127
- ...typeof row.cwd === "string" && row.cwd.trim() ? { cwd: row.cwd.trim() } : {}
1432
+ serverName,
1433
+ ...url ? { url } : {},
1434
+ ...command ? { command } : {},
1435
+ ...args && args.length > 0 ? { args } : {},
1436
+ ...cwd ? { cwd } : {}
1128
1437
  };
1129
1438
  }
1130
- function rowToUi(row) {
1131
- const url = typeof row.url === "string" ? row.url : "";
1439
+ function rowToUi(draft, snapshot) {
1440
+ const transport = draft.url ? "http" : "stdio";
1441
+ const resolved = resolveRowStatus(draft.serverName, snapshot);
1132
1442
  return {
1133
- serverName: row.serverName,
1134
- transport: url ? "http" : "stdio",
1135
- command: typeof row.command === "string" ? row.command : "",
1136
- url,
1137
- args: Array.isArray(row.args) ? row.args.join(", ") : "",
1138
- cwd: typeof row.cwd === "string" ? row.cwd : ""
1443
+ serverName: draft.serverName,
1444
+ transport,
1445
+ command: draft.command ?? "",
1446
+ url: draft.url ?? "",
1447
+ args: (draft.args ?? []).join(", "),
1448
+ cwd: draft.cwd ?? "",
1449
+ ...resolved
1139
1450
  };
1140
1451
  }
1141
1452
  function rowFromUi(row) {
@@ -1144,7 +1455,7 @@ window.__ModuleLoader__.load({
1144
1455
  serverName,
1145
1456
  url: row.url.trim()
1146
1457
  };
1147
- const args = row.args.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
1458
+ const args = row.args.split(",").map((part) => part.trim()).filter(Boolean);
1148
1459
  const cwd = row.cwd.trim();
1149
1460
  return {
1150
1461
  serverName,
@@ -1153,34 +1464,17 @@ window.__ModuleLoader__.load({
1153
1464
  ...cwd ? { cwd } : {}
1154
1465
  };
1155
1466
  }
1156
- /** Upsert imported rows by `serverName` (later paste wins). */
1467
+ function validateRow(row) {
1468
+ if (!row.serverName.trim()) return "name";
1469
+ if (row.transport === "http") return row.url.trim() ? void 0 : "url";
1470
+ return row.command.trim() ? void 0 : "command";
1471
+ }
1157
1472
  function mergeRowsByName(existing, imported) {
1158
1473
  const byName = new Map(existing.map((row) => [row.serverName, row]));
1159
1474
  for (const row of imported) byName.set(row.serverName, row);
1160
- const order = [];
1161
- for (const row of existing) if (!order.includes(row.serverName)) order.push(row.serverName);
1162
- for (const row of imported) if (!order.includes(row.serverName)) order.push(row.serverName);
1163
- return order.map((name) => byName.get(name)).filter(Boolean);
1164
- }
1165
- function namedRowToUi(name, row) {
1166
- const serverName = name.trim();
1167
- if (!serverName) return void 0;
1168
- const url = typeof row.url === "string" ? row.url.trim() : "";
1169
- const command = typeof row.command === "string" ? row.command.trim() : "";
1170
- if (!url && !command) return void 0;
1171
- return {
1172
- serverName,
1173
- transport: url ? "http" : "stdio",
1174
- command,
1175
- url,
1176
- args: Array.isArray(row.args) ? row.args.map(String).join(", ") : "",
1177
- cwd: typeof row.cwd === "string" ? row.cwd : ""
1178
- };
1475
+ return [...byName.values()];
1179
1476
  }
1180
- /**
1181
- * Cursor / Trae / Claude Desktop paste: `{ "mcpServers": { "name": { "command", "args" } } }`.
1182
- * Also accepts a bare name map or a Face array of `{ serverName, command }`.
1183
- */
1477
+ /** Parse Cursor/Trae `{ mcpServers: { name: { command|url, args? } } }` into rows. */
1184
1478
  function rowsFromMcpPaste(raw) {
1185
1479
  let parsed;
1186
1480
  try {
@@ -1188,32 +1482,169 @@ window.__ModuleLoader__.load({
1188
1482
  } catch {
1189
1483
  return [];
1190
1484
  }
1191
- if (Array.isArray(parsed)) {
1192
- const out = [];
1193
- for (const row of parsed) {
1194
- if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1195
- const o = row;
1196
- const mapped = namedRowToUi(String(o.serverName ?? ""), o);
1197
- if (mapped) out.push(mapped);
1198
- }
1199
- return out;
1200
- }
1201
- if (!parsed || typeof parsed !== "object") return [];
1485
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return [];
1202
1486
  const root = parsed;
1203
- const map = root.mcpServers && typeof root.mcpServers === "object" && !Array.isArray(root.mcpServers) ? root.mcpServers : root;
1204
- const out = [];
1205
- for (const [name, row] of Object.entries(map)) {
1206
- if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1207
- const mapped = namedRowToUi(name, row);
1208
- if (mapped) out.push(mapped);
1487
+ const block = root.mcpServers ?? root.servers;
1488
+ if (!block || typeof block !== "object" || Array.isArray(block)) return [];
1489
+ const rows = [];
1490
+ for (const [name, value] of Object.entries(block)) {
1491
+ const serverName = name.trim();
1492
+ if (!serverName || !value || typeof value !== "object" || Array.isArray(value)) continue;
1493
+ const entry = value;
1494
+ const url = typeof entry.url === "string" ? entry.url.trim() : "";
1495
+ const command = typeof entry.command === "string" ? entry.command.trim() : "";
1496
+ const cwd = typeof entry.cwd === "string" ? entry.cwd.trim() : "";
1497
+ const argsList = Array.isArray(entry.args) ? entry.args.filter((part) => typeof part === "string") : [];
1498
+ if (url) {
1499
+ rows.push({
1500
+ serverName,
1501
+ transport: "http",
1502
+ command: "",
1503
+ url,
1504
+ args: "",
1505
+ cwd: "",
1506
+ status: "idle",
1507
+ toolCount: 0
1508
+ });
1509
+ continue;
1510
+ }
1511
+ if (!command) continue;
1512
+ rows.push({
1513
+ serverName,
1514
+ transport: "stdio",
1515
+ command,
1516
+ url: "",
1517
+ args: argsList.join(", "),
1518
+ cwd,
1519
+ status: "idle",
1520
+ toolCount: 0
1521
+ });
1209
1522
  }
1210
- return out;
1523
+ return rows;
1211
1524
  }
1212
- function validateRow(row) {
1213
- if (!row.serverName.trim()) return "serverName";
1214
- if (row.transport === "http") return row.url.trim() ? void 0 : "url";
1215
- return row.command.trim() ? void 0 : "command";
1525
+ //#endregion
1526
+ //#region src/client/web-search-card-controller.ts
1527
+ /** Namespace Host serves for web_search provider preference. */
1528
+ const WEB_SEARCH_NS = "web-search";
1529
+ /** Credential refs Face emits on `credentials/updated` (envVar of the slot). */
1530
+ const WEB_SEARCH_TAVILY_REF = "XRK_TAVILY_API_KEY";
1531
+ const WEB_SEARCH_BRAVE_REF = "XRK_BRAVE_SEARCH_API_KEY";
1532
+ const TAVILY_FIELD = "tavilyApiKey";
1533
+ const BRAVE_FIELD = "braveApiKey";
1534
+ const PROVIDERS = [
1535
+ "auto",
1536
+ "tavily",
1537
+ "brave",
1538
+ "parallel-free",
1539
+ "duckduckgo"
1540
+ ];
1541
+ function providerField() {
1542
+ return {
1543
+ field: "provider",
1544
+ format: (value) => typeof value === "string" && value ? value : "auto",
1545
+ parse: (text) => {
1546
+ const trimmed = text.trim() || "auto";
1547
+ if (!PROVIDERS.includes(trimmed)) return void 0;
1548
+ return {
1549
+ kind: "set",
1550
+ value: trimmed
1551
+ };
1552
+ }
1553
+ };
1216
1554
  }
1555
+ /** Bridges the `web-search` scope and Tavily/Brave credentials onto the card. */
1556
+ var WebSearchCardController = class {
1557
+ api;
1558
+ form;
1559
+ store;
1560
+ tavily = {
1561
+ configured: false,
1562
+ writable: true
1563
+ };
1564
+ brave = {
1565
+ configured: false,
1566
+ writable: true
1567
+ };
1568
+ /**
1569
+ * @param scope - the bound settings scope for the `web-search` namespace.
1570
+ * @param api - wire face for Credentials (keys never ride settings).
1571
+ */
1572
+ constructor(scope, api) {
1573
+ this.api = api;
1574
+ this.form = new CardForm(scope, [providerField(), textField("region")], [{
1575
+ field: TAVILY_FIELD,
1576
+ write: (text) => this.writeKey(WEB_SEARCH_TAVILY_REF, text)
1577
+ }, {
1578
+ field: BRAVE_FIELD,
1579
+ write: (text) => this.writeKey(WEB_SEARCH_BRAVE_REF, text)
1580
+ }]);
1581
+ this.store = this.form.bind(() => this.projection());
1582
+ this.readCredentials();
1583
+ }
1584
+ projection() {
1585
+ return {
1586
+ ...this.form.shell(),
1587
+ provider: this.form.field("provider"),
1588
+ region: this.form.field("region"),
1589
+ tavilyApiKey: this.form.field(TAVILY_FIELD),
1590
+ braveApiKey: this.form.field(BRAVE_FIELD),
1591
+ tavilyConfigured: this.tavily.configured,
1592
+ tavilyWritable: this.tavily.writable,
1593
+ braveConfigured: this.brave.configured,
1594
+ braveWritable: this.brave.writable
1595
+ };
1596
+ }
1597
+ /** Ask the credentials domain about Tavily + Brave slots. */
1598
+ async readCredentials() {
1599
+ let response;
1600
+ try {
1601
+ response = await this.api.credentials.describe({ refs: [WEB_SEARCH_TAVILY_REF, WEB_SEARCH_BRAVE_REF] });
1602
+ } catch {
1603
+ return;
1604
+ }
1605
+ if (!response.result.ok) return;
1606
+ const map = response.result.value.credentials;
1607
+ const nextTavily = {
1608
+ configured: map["XRK_TAVILY_API_KEY"]?.configured ?? false,
1609
+ writable: map["XRK_TAVILY_API_KEY"]?.writable ?? true
1610
+ };
1611
+ const nextBrave = {
1612
+ configured: map["XRK_BRAVE_SEARCH_API_KEY"]?.configured ?? false,
1613
+ writable: map["XRK_BRAVE_SEARCH_API_KEY"]?.writable ?? true
1614
+ };
1615
+ if (nextTavily.configured === this.tavily.configured && nextTavily.writable === this.tavily.writable && nextBrave.configured === this.brave.configured && nextBrave.writable === this.brave.writable) return;
1616
+ this.tavily = nextTavily;
1617
+ this.brave = nextBrave;
1618
+ this.store.set(this.projection());
1619
+ }
1620
+ /**
1621
+ * Re-read when Host reports a watched credential changed (e.g. Credentials page).
1622
+ * @param ref - envVar / slot ref from `credentials/updated`.
1623
+ */
1624
+ refreshCredential(ref) {
1625
+ if (ref !== "XRK_TAVILY_API_KEY" && ref !== "XRK_BRAVE_SEARCH_API_KEY") return;
1626
+ this.readCredentials();
1627
+ }
1628
+ /** @returns the card's snapshot and its form actions. */
1629
+ inject() {
1630
+ return {
1631
+ hooks: { webSearchCard: this.store },
1632
+ ...this.form.actions()
1633
+ };
1634
+ }
1635
+ async writeKey(ref, value) {
1636
+ try {
1637
+ await this.api.credentials.set({
1638
+ ref,
1639
+ value
1640
+ });
1641
+ } catch {}
1642
+ await this.readCredentials();
1643
+ if (ref === "XRK_TAVILY_API_KEY") return this.tavily.configured;
1644
+ if (ref === "XRK_BRAVE_SEARCH_API_KEY") return this.brave.configured;
1645
+ return false;
1646
+ }
1647
+ };
1217
1648
  //#endregion
1218
1649
  //#region src/client/tab-store.ts
1219
1650
  /** Reads the served namespaces and pairs them with the cards that claim them. */
@@ -1319,7 +1750,7 @@ window.__ModuleLoader__.load({
1319
1750
  agentLoopMaxParallel: "Parallel tool calls",
1320
1751
  agentLoopMaxParallelHint: "Upper bound on parallel-safe calls running at once within one step.",
1321
1752
  mcpTitle: "MCP servers",
1322
- mcpDescription: "Paste Cursor / Trae style JSON blocks one at a time. Each paste merges servers by name; save remounts when Host uses the settings file.",
1753
+ mcpDescription: "Paste Cursor / Trae style JSON, then save servers mount on save (no separate env step).",
1323
1754
  mcpConnectedHeading: "Connected now",
1324
1755
  mcpServersHeading: "Servers",
1325
1756
  mcpServersEmpty: "No servers yet. Paste a JSON block below and add.",
@@ -1346,9 +1777,31 @@ window.__ModuleLoader__.load({
1346
1777
  mcpCwdHint: "Optional. Leave blank to use the Host default.",
1347
1778
  mcpRowInvalid: "Each server needs a name and a command or URL.",
1348
1779
  mcpToolsLabel: "tools",
1780
+ mcpAllowConnect: "Allow connect",
1781
+ mcpAllowConnectHint: "Saving a non-empty list connects automatically. Turn off and save to keep the list without mounting tools.",
1349
1782
  mcpStatusConnected: "Connected",
1350
1783
  mcpStatusReconnecting: "Reconnecting",
1351
- mcpStatusGaveUp: "Gave up"
1784
+ mcpStatusGaveUp: "Gave up",
1785
+ mcpStatusParked: "Parked",
1786
+ mcpStatusFailed: "Failed",
1787
+ mcpStatusIdle: "Not connected",
1788
+ webSearchTitle: "Web search",
1789
+ webSearchDescription: "Provider and keys for the web_search tool. Keys save through Credentials, not settings.yaml.",
1790
+ webSearchProvider: "Provider",
1791
+ webSearchProviderHint: "Auto picks Tavily or Brave when a key is set, otherwise parallel-free → DuckDuckGo.",
1792
+ webSearchProviderAuto: "Auto",
1793
+ webSearchProviderTavily: "Tavily",
1794
+ webSearchProviderBrave: "Brave",
1795
+ webSearchProviderParallel: "Parallel free",
1796
+ webSearchProviderDuckduckgo: "DuckDuckGo",
1797
+ webSearchRegion: "DuckDuckGo region",
1798
+ webSearchRegionHint: "Optional kl region (for example us-en). Used when DuckDuckGo runs.",
1799
+ webSearchTavilyKey: "Tavily API key",
1800
+ webSearchTavilyKeyHint: "Required when provider is Tavily (or Auto with this key set). Leave blank to keep the stored key.",
1801
+ webSearchBraveKey: "Brave Search API key",
1802
+ webSearchBraveKeyHint: "Required when provider is Brave (or Auto with this key set). Leave blank to keep the stored key.",
1803
+ webSearchKeySet: "Configured",
1804
+ webSearchKeyUnset: "Not set"
1352
1805
  };
1353
1806
  /** Simplified Chinese copy. */
1354
1807
  const zh = {
@@ -1380,7 +1833,7 @@ window.__ModuleLoader__.load({
1380
1833
  agentLoopMaxParallel: "并行工具调用数",
1381
1834
  agentLoopMaxParallelHint: "同一步内最多同时运行多少个可并行的调用。",
1382
1835
  mcpTitle: "MCP 服务器",
1383
- mcpDescription: " Trae / Cursor 一样每次粘贴一段 mcpServers JSON;按名称合并进列表,保存后热挂载。",
1836
+ mcpDescription: "粘贴 Trae / Cursor 风格 mcpServers JSON,保存后会挂载(不必再先开环境变量)。",
1384
1837
  mcpConnectedHeading: "当前已连接",
1385
1838
  mcpServersHeading: "服务器",
1386
1839
  mcpServersEmpty: "还没有服务器。在下方粘贴 JSON 块后点添加。",
@@ -1407,9 +1860,31 @@ window.__ModuleLoader__.load({
1407
1860
  mcpCwdHint: "可选。留空使用 Host 默认。",
1408
1861
  mcpRowInvalid: "每条服务器需要名称,以及命令或 URL。",
1409
1862
  mcpToolsLabel: "个工具",
1863
+ mcpAllowConnect: "允许连接",
1864
+ mcpAllowConnectHint: "列表非空时保存会自动连接。关掉此项再保存可只保留列表、不挂载工具。",
1410
1865
  mcpStatusConnected: "已连接",
1411
1866
  mcpStatusReconnecting: "重连中",
1412
- mcpStatusGaveUp: "已放弃"
1867
+ mcpStatusGaveUp: "已放弃",
1868
+ mcpStatusParked: "已停放",
1869
+ mcpStatusFailed: "失败",
1870
+ mcpStatusIdle: "未连接",
1871
+ webSearchTitle: "网页搜索",
1872
+ webSearchDescription: "web_search 工具的提供方与密钥。密钥经「凭据」落盘,不写入 settings.yaml。",
1873
+ webSearchProvider: "提供方",
1874
+ webSearchProviderHint: "自动:有密钥用 Tavily/Brave,否则 parallel-free → DuckDuckGo。",
1875
+ webSearchProviderAuto: "自动",
1876
+ webSearchProviderTavily: "Tavily",
1877
+ webSearchProviderBrave: "Brave",
1878
+ webSearchProviderParallel: "Parallel 免费",
1879
+ webSearchProviderDuckduckgo: "DuckDuckGo",
1880
+ webSearchRegion: "DuckDuckGo 区域",
1881
+ webSearchRegionHint: "可选 kl 区域(如 us-en),仅 DuckDuckGo 时生效。",
1882
+ webSearchTavilyKey: "Tavily API 密钥",
1883
+ webSearchTavilyKeyHint: "提供方为 Tavily(或自动且已配置此密钥)时需要。留空表示保留已存密钥。",
1884
+ webSearchBraveKey: "Brave Search API 密钥",
1885
+ webSearchBraveKeyHint: "提供方为 Brave(或自动且已配置此密钥)时需要。留空表示保留已存密钥。",
1886
+ webSearchKeySet: "已配置",
1887
+ webSearchKeyUnset: "未设置"
1413
1888
  };
1414
1889
  //#endregion
1415
1890
  //#region src/client/index.ts
@@ -1437,6 +1912,7 @@ window.__ModuleLoader__.load({
1437
1912
  const bash = new BashCardController(ctx.settingsScope.bind({ namespace: SHELL_NS }));
1438
1913
  const agentLoop = new AgentLoopCardController(ctx.settingsScope.bind({ namespace: AGENT_LOOP_NS }));
1439
1914
  const mcp = new McpCardController(ctx.settingsScope.bind({ namespace: "mcp" }));
1915
+ const webSearch = new WebSearchCardController(ctx.settingsScope.bind({ namespace: WEB_SEARCH_NS }), api);
1440
1916
  const configurable = new ConfigurablePluginsTabController(api, () => ctx.slots.entries("settings.plugin.item"));
1441
1917
  ctx.effect(() => () => {
1442
1918
  configurable.dispose();
@@ -1447,6 +1923,9 @@ window.__ModuleLoader__.load({
1447
1923
  ctx.effect(() => ctx.on("connection/reset", () => {
1448
1924
  configurable.load();
1449
1925
  }), "ui-settings-plugins: served-namespace reconnect");
1926
+ ctx.effect(() => ctx.remote.$on("credentials/updated", (ref) => {
1927
+ if (ref === "XRK_TAVILY_API_KEY" || ref === "XRK_BRAVE_SEARCH_API_KEY") webSearch.refreshCredential(ref);
1928
+ }), "ui-settings-plugins: web-search credential invalidations");
1450
1929
  ctx.effect(() => ctx.slots.subscribe("settings.plugin.item", () => {
1451
1930
  configurable.refresh();
1452
1931
  }), "ui-settings-plugins: card ledger");
@@ -1510,6 +1989,12 @@ window.__ModuleLoader__.load({
1510
1989
  locale: NS,
1511
1990
  inject: () => mcp.inject()
1512
1991
  }, McpCard);
1992
+ yield ctx.slots.register({
1993
+ name: "settings.plugin.item",
1994
+ key: WEB_SEARCH_NS,
1995
+ locale: NS,
1996
+ inject: () => webSearch.inject()
1997
+ }, WebSearchCard);
1513
1998
  yield ctx.slots.register({
1514
1999
  name: "settings.plugin.item",
1515
2000
  key: SHELL_NS,
@@ -1525,6 +2010,9 @@ window.__ModuleLoader__.load({
1525
2010
  });
1526
2011
  }
1527
2012
  //#endregion
2013
+ exports.WEB_SEARCH_BRAVE_REF = WEB_SEARCH_BRAVE_REF;
2014
+ exports.WEB_SEARCH_NS = WEB_SEARCH_NS;
2015
+ exports.WEB_SEARCH_TAVILY_REF = WEB_SEARCH_TAVILY_REF;
1528
2016
  exports.apply = apply;
1529
2017
  exports.inject = inject;
1530
2018
  return module.exports;