@xrkseek/harness-cli 0.0.2 → 0.0.4

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 (198) hide show
  1. package/README.md +5 -0
  2. package/dist/commands/restart.d.ts +3 -0
  3. package/dist/commands/restart.d.ts.map +1 -0
  4. package/dist/commands/restart.js +32 -0
  5. package/dist/commands/restart.js.map +1 -0
  6. package/dist/commands/serve.d.ts.map +1 -1
  7. package/dist/commands/serve.js +38 -19
  8. package/dist/commands/serve.js.map +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +3 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/log.d.ts +19 -0
  13. package/dist/log.d.ts.map +1 -0
  14. package/dist/log.js +52 -0
  15. package/dist/log.js.map +1 -0
  16. package/dist/parse-args.d.ts +5 -1
  17. package/dist/parse-args.d.ts.map +1 -1
  18. package/dist/parse-args.js +37 -4
  19. package/dist/parse-args.js.map +1 -1
  20. package/dist/port.d.ts +9 -0
  21. package/dist/port.d.ts.map +1 -0
  22. package/dist/port.js +86 -0
  23. package/dist/port.js.map +1 -0
  24. package/node_modules/@xrkseek/core-agent/dist/index.d.ts +2 -0
  25. package/node_modules/@xrkseek/core-agent/dist/index.d.ts.map +1 -1
  26. package/node_modules/@xrkseek/core-agent/dist/index.js +3 -0
  27. package/node_modules/@xrkseek/core-agent/dist/index.js.map +1 -1
  28. package/node_modules/@xrkseek/core-agent-loop/dist/index.d.ts +5 -0
  29. package/node_modules/@xrkseek/core-agent-loop/dist/index.d.ts.map +1 -1
  30. package/node_modules/@xrkseek/core-agent-loop/dist/index.js +3 -0
  31. package/node_modules/@xrkseek/core-agent-loop/dist/index.js.map +1 -1
  32. package/node_modules/@xrkseek/core-agent-loop/dist/settle-batch.d.ts +5 -0
  33. package/node_modules/@xrkseek/core-agent-loop/dist/settle-batch.d.ts.map +1 -1
  34. package/node_modules/@xrkseek/core-agent-loop/dist/settle-batch.js +22 -2
  35. package/node_modules/@xrkseek/core-agent-loop/dist/settle-batch.js.map +1 -1
  36. package/node_modules/@xrkseek/core-session/dist/compaction.d.ts.map +1 -1
  37. package/node_modules/@xrkseek/core-session/dist/compaction.js.map +1 -1
  38. package/node_modules/@xrkseek/exec-shell/dist/index.d.ts +4 -1
  39. package/node_modules/@xrkseek/exec-shell/dist/index.d.ts.map +1 -1
  40. package/node_modules/@xrkseek/exec-shell/dist/index.js +18 -2
  41. package/node_modules/@xrkseek/exec-shell/dist/index.js.map +1 -1
  42. package/node_modules/@xrkseek/exec-web/dist/fetch-http.js +1 -1
  43. package/node_modules/@xrkseek/exec-web/dist/index.d.ts +9 -2
  44. package/node_modules/@xrkseek/exec-web/dist/index.d.ts.map +1 -1
  45. package/node_modules/@xrkseek/exec-web/dist/index.js +10 -7
  46. package/node_modules/@xrkseek/exec-web/dist/index.js.map +1 -1
  47. package/node_modules/@xrkseek/exec-web/dist/search-duckduckgo.d.ts +14 -0
  48. package/node_modules/@xrkseek/exec-web/dist/search-duckduckgo.d.ts.map +1 -0
  49. package/node_modules/@xrkseek/exec-web/dist/search-duckduckgo.js +139 -0
  50. package/node_modules/@xrkseek/exec-web/dist/search-duckduckgo.js.map +1 -0
  51. package/node_modules/@xrkseek/exec-web/dist/search-mcp-client.d.ts +21 -0
  52. package/node_modules/@xrkseek/exec-web/dist/search-mcp-client.d.ts.map +1 -0
  53. package/node_modules/@xrkseek/exec-web/dist/search-mcp-client.js +175 -0
  54. package/node_modules/@xrkseek/exec-web/dist/search-mcp-client.js.map +1 -0
  55. package/node_modules/@xrkseek/exec-web/dist/search-parallel-free.d.ts +12 -0
  56. package/node_modules/@xrkseek/exec-web/dist/search-parallel-free.d.ts.map +1 -0
  57. package/node_modules/@xrkseek/exec-web/dist/search-parallel-free.js +105 -0
  58. package/node_modules/@xrkseek/exec-web/dist/search-parallel-free.js.map +1 -0
  59. package/node_modules/@xrkseek/exec-web/dist/search-providers.d.ts +28 -3
  60. package/node_modules/@xrkseek/exec-web/dist/search-providers.d.ts.map +1 -1
  61. package/node_modules/@xrkseek/exec-web/dist/search-providers.js +150 -23
  62. package/node_modules/@xrkseek/exec-web/dist/search-providers.js.map +1 -1
  63. package/node_modules/@xrkseek/mcp/dist/client.d.ts.map +1 -1
  64. package/node_modules/@xrkseek/mcp/dist/client.js.map +1 -1
  65. package/node_modules/@xrkseek/mcp/dist/project-content.js +1 -1
  66. package/node_modules/@xrkseek/mcp/dist/project-content.js.map +1 -1
  67. package/node_modules/@xrkseek/preset-harness/dist/preset.d.ts +11 -0
  68. package/node_modules/@xrkseek/preset-harness/dist/preset.d.ts.map +1 -1
  69. package/node_modules/@xrkseek/preset-harness/dist/preset.js +12 -2
  70. package/node_modules/@xrkseek/preset-harness/dist/preset.js.map +1 -1
  71. package/node_modules/@xrkseek/preset-harness/dist/tsconfig.tsbuildinfo +1 -1
  72. package/node_modules/@xrkseek/preset-minimal/dist/tsconfig.tsbuildinfo +1 -1
  73. package/node_modules/@xrkseek/preset-server/dist/preset.d.ts.map +1 -1
  74. package/node_modules/@xrkseek/preset-server/dist/preset.js +4 -1
  75. package/node_modules/@xrkseek/preset-server/dist/preset.js.map +1 -1
  76. package/node_modules/@xrkseek/preset-server/dist/tsconfig.tsbuildinfo +1 -1
  77. package/node_modules/@xrkseek/protocol/dist/token-usage.d.ts +7 -1
  78. package/node_modules/@xrkseek/protocol/dist/token-usage.d.ts.map +1 -1
  79. package/node_modules/@xrkseek/protocol/dist/token-usage.js +49 -24
  80. package/node_modules/@xrkseek/protocol/dist/token-usage.js.map +1 -1
  81. package/node_modules/@xrkseek/server-config/dist/index.js +1 -1
  82. package/node_modules/@xrkseek/server-face/dist/context.d.ts +6 -5
  83. package/node_modules/@xrkseek/server-face/dist/context.d.ts.map +1 -1
  84. package/node_modules/@xrkseek/server-face/dist/context.js +1 -3
  85. package/node_modules/@xrkseek/server-face/dist/context.js.map +1 -1
  86. package/node_modules/@xrkseek/server-face/dist/dispatch.d.ts.map +1 -1
  87. package/node_modules/@xrkseek/server-face/dist/dispatch.js +4 -2
  88. package/node_modules/@xrkseek/server-face/dist/dispatch.js.map +1 -1
  89. package/node_modules/@xrkseek/server-face/dist/face-schema.d.ts +3 -2
  90. package/node_modules/@xrkseek/server-face/dist/face-schema.d.ts.map +1 -1
  91. package/node_modules/@xrkseek/server-face/dist/face-schema.js +16 -4
  92. package/node_modules/@xrkseek/server-face/dist/face-schema.js.map +1 -1
  93. package/node_modules/@xrkseek/server-face/dist/handlers/catalog.d.ts.map +1 -1
  94. package/node_modules/@xrkseek/server-face/dist/handlers/catalog.js +26 -12
  95. package/node_modules/@xrkseek/server-face/dist/handlers/catalog.js.map +1 -1
  96. package/node_modules/@xrkseek/server-face/dist/handlers/session-added.d.ts.map +1 -1
  97. package/node_modules/@xrkseek/server-face/dist/handlers/session-added.js +3 -2
  98. package/node_modules/@xrkseek/server-face/dist/handlers/session-added.js.map +1 -1
  99. package/node_modules/@xrkseek/server-face/dist/handlers/session.d.ts.map +1 -1
  100. package/node_modules/@xrkseek/server-face/dist/handlers/session.js +24 -27
  101. package/node_modules/@xrkseek/server-face/dist/handlers/session.js.map +1 -1
  102. package/node_modules/@xrkseek/server-face/dist/index.d.ts +4 -3
  103. package/node_modules/@xrkseek/server-face/dist/index.d.ts.map +1 -1
  104. package/node_modules/@xrkseek/server-face/dist/index.js +4 -3
  105. package/node_modules/@xrkseek/server-face/dist/index.js.map +1 -1
  106. package/node_modules/@xrkseek/server-face/dist/llm-provider-context.d.ts +44 -6
  107. package/node_modules/@xrkseek/server-face/dist/llm-provider-context.d.ts.map +1 -1
  108. package/node_modules/@xrkseek/server-face/dist/llm-provider-context.js +220 -34
  109. package/node_modules/@xrkseek/server-face/dist/llm-provider-context.js.map +1 -1
  110. package/node_modules/@xrkseek/server-face/dist/llm-resolve.d.ts.map +1 -1
  111. package/node_modules/@xrkseek/server-face/dist/llm-resolve.js +4 -7
  112. package/node_modules/@xrkseek/server-face/dist/llm-resolve.js.map +1 -1
  113. package/node_modules/@xrkseek/server-face/dist/model-catalog.d.ts +1 -1
  114. package/node_modules/@xrkseek/server-face/dist/model-catalog.d.ts.map +1 -1
  115. package/node_modules/@xrkseek/server-face/dist/model-catalog.js +23 -26
  116. package/node_modules/@xrkseek/server-face/dist/model-catalog.js.map +1 -1
  117. package/node_modules/@xrkseek/server-face/dist/presets-catalog.d.ts +13 -1
  118. package/node_modules/@xrkseek/server-face/dist/presets-catalog.d.ts.map +1 -1
  119. package/node_modules/@xrkseek/server-face/dist/presets-catalog.js +24 -9
  120. package/node_modules/@xrkseek/server-face/dist/presets-catalog.js.map +1 -1
  121. package/node_modules/@xrkseek/server-face/dist/session-cwd.d.ts +3 -0
  122. package/node_modules/@xrkseek/server-face/dist/session-cwd.d.ts.map +1 -0
  123. package/node_modules/@xrkseek/server-face/dist/session-cwd.js +19 -0
  124. package/node_modules/@xrkseek/server-face/dist/session-cwd.js.map +1 -0
  125. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts +1 -1
  126. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts.map +1 -1
  127. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js +116 -14
  128. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js.map +1 -1
  129. package/node_modules/@xrkseek/server-face/dist/settings-document.d.ts +1 -1
  130. package/node_modules/@xrkseek/server-face/dist/settings-document.d.ts.map +1 -1
  131. package/node_modules/@xrkseek/server-face/dist/settings-document.js +25 -22
  132. package/node_modules/@xrkseek/server-face/dist/settings-document.js.map +1 -1
  133. package/node_modules/@xrkseek/server-face/dist/settings-layers.d.ts +3 -0
  134. package/node_modules/@xrkseek/server-face/dist/settings-layers.d.ts.map +1 -0
  135. package/node_modules/@xrkseek/server-face/dist/settings-layers.js +19 -0
  136. package/node_modules/@xrkseek/server-face/dist/settings-layers.js.map +1 -0
  137. package/node_modules/@xrkseek/server-face/dist/settings-schemas.d.ts.map +1 -1
  138. package/node_modules/@xrkseek/server-face/dist/settings-schemas.js +18 -11
  139. package/node_modules/@xrkseek/server-face/dist/settings-schemas.js.map +1 -1
  140. package/node_modules/@xrkseek/server-face/dist/workspace-face.d.ts.map +1 -1
  141. package/node_modules/@xrkseek/server-face/dist/workspace-face.js +26 -9
  142. package/node_modules/@xrkseek/server-face/dist/workspace-face.js.map +1 -1
  143. package/node_modules/@xrkseek/server-face/dist/workspace-registry.d.ts +6 -0
  144. package/node_modules/@xrkseek/server-face/dist/workspace-registry.d.ts.map +1 -1
  145. package/node_modules/@xrkseek/server-face/dist/workspace-registry.js +39 -1
  146. package/node_modules/@xrkseek/server-face/dist/workspace-registry.js.map +1 -1
  147. package/node_modules/@xrkseek/server-face/dist/workspace-store.d.ts +4 -0
  148. package/node_modules/@xrkseek/server-face/dist/workspace-store.d.ts.map +1 -1
  149. package/node_modules/@xrkseek/server-face/dist/workspace-store.js +43 -1
  150. package/node_modules/@xrkseek/server-face/dist/workspace-store.js.map +1 -1
  151. package/node_modules/@xrkseek/server-host/dist/index.d.ts +19 -2
  152. package/node_modules/@xrkseek/server-host/dist/index.d.ts.map +1 -1
  153. package/node_modules/@xrkseek/server-host/dist/index.js +150 -23
  154. package/node_modules/@xrkseek/server-host/dist/index.js.map +1 -1
  155. package/node_modules/@xrkseek/server-host/dist/log.d.ts +14 -0
  156. package/node_modules/@xrkseek/server-host/dist/log.d.ts.map +1 -0
  157. package/node_modules/@xrkseek/server-host/dist/log.js +6 -0
  158. package/node_modules/@xrkseek/server-host/dist/log.js.map +1 -0
  159. package/node_modules/@xrkseek/server-host/dist/mcp-wire.d.ts +9 -4
  160. package/node_modules/@xrkseek/server-host/dist/mcp-wire.d.ts.map +1 -1
  161. package/node_modules/@xrkseek/server-host/dist/mcp-wire.js +42 -7
  162. package/node_modules/@xrkseek/server-host/dist/mcp-wire.js.map +1 -1
  163. package/node_modules/@xrkseek/server-host/dist/standing-tools.js +2 -2
  164. package/node_modules/@xrkseek/server-host/dist/standing-tools.js.map +1 -1
  165. package/node_modules/@xrkseek/server-http/dist/index.d.ts +9 -0
  166. package/node_modules/@xrkseek/server-http/dist/index.d.ts.map +1 -1
  167. package/node_modules/@xrkseek/server-http/dist/index.js +9 -0
  168. package/node_modules/@xrkseek/server-http/dist/index.js.map +1 -1
  169. package/package.json +1 -1
  170. package/product-web/boot.json +1 -1
  171. package/product-web/plugins/@xrkseek/client-locale/client.js +3 -3
  172. package/product-web/plugins/@xrkseek/client-ui-agent-preset/client.js +33 -33
  173. package/product-web/plugins/@xrkseek/client-ui-commands/client.js +7 -7
  174. package/product-web/plugins/@xrkseek/client-ui-conversation/client.js +156 -156
  175. package/product-web/plugins/@xrkseek/client-ui-deliverables/client.js +5 -5
  176. package/product-web/plugins/@xrkseek/client-ui-directory-picker-browse/client.js +29 -29
  177. package/product-web/plugins/@xrkseek/client-ui-goal/client.js +6 -6
  178. package/product-web/plugins/@xrkseek/client-ui-input-trigger/client.js +5 -5
  179. package/product-web/plugins/@xrkseek/client-ui-jobs/client.js +10 -10
  180. package/product-web/plugins/@xrkseek/client-ui-layout/client.js +4 -4
  181. package/product-web/plugins/@xrkseek/client-ui-message-feedback/client.js +4 -4
  182. package/product-web/plugins/@xrkseek/client-ui-model-selection/client.js +19 -19
  183. package/product-web/plugins/@xrkseek/client-ui-permission-presets/client.js +4 -4
  184. package/product-web/plugins/@xrkseek/client-ui-plan/client.js +1 -1
  185. package/product-web/plugins/@xrkseek/client-ui-settings/client.js +7 -1
  186. package/product-web/plugins/@xrkseek/client-ui-settings-general/client.js +16 -16
  187. package/product-web/plugins/@xrkseek/client-ui-settings-models/client.js +53 -53
  188. package/product-web/plugins/@xrkseek/client-ui-settings-plugin-inventory/client.js +12 -12
  189. package/product-web/plugins/@xrkseek/client-ui-settings-plugins/client.js +615 -548
  190. package/product-web/plugins/@xrkseek/client-ui-sidebar/client.js +14 -14
  191. package/product-web/plugins/@xrkseek/client-ui-skill/client.js +9 -9
  192. package/product-web/plugins/@xrkseek/client-ui-subagent/client.js +16 -16
  193. package/product-web/plugins/@xrkseek/client-ui-theme/client.js +3 -3
  194. package/product-web/plugins/@xrkseek/client-ui-tool/client.js +37 -37
  195. package/product-web/plugins/@xrkseek/client-ui-trajectory/client.js +144 -144
  196. package/product-web/plugins/@xrkseek/client-ui-user-questions/client.js +30 -30
  197. package/product-web/plugins/@xrkseek/client-ui-workflow-run/client.js +11 -11
  198. package/product-web/plugins/@xrkseek/client-ui-workspace/client.js +53 -53
@@ -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");
@@ -20,18 +20,18 @@ window.__ModuleLoader__.load({
20
20
  document.head.appendChild(tag);
21
21
  }
22
22
  var fields_module_css_default = {
23
+ "select": "MiE2dW_select",
24
+ "hint": "MiE2dW_hint",
25
+ "reset": "MiE2dW_reset",
23
26
  "badge": "MiE2dW_badge",
24
27
  "badgeMuted": "MiE2dW_badgeMuted",
25
- "field": "MiE2dW_field",
26
- "input": "MiE2dW_input",
27
- "select": "MiE2dW_select",
28
- "inputInvalid": "MiE2dW_inputInvalid",
28
+ "head": "MiE2dW_head",
29
29
  "badges": "MiE2dW_badges",
30
+ "input": "MiE2dW_input",
30
31
  "invalid": "MiE2dW_invalid",
32
+ "field": "MiE2dW_field",
31
33
  "label": "MiE2dW_label",
32
- "reset": "MiE2dW_reset",
33
- "head": "MiE2dW_head",
34
- "hint": "MiE2dW_hint"
34
+ "inputInvalid": "MiE2dW_inputInvalid"
35
35
  };
36
36
  //#endregion
37
37
  //#region src/client/fields.tsx
@@ -42,38 +42,6 @@ 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
- /**
46
- * Label + control + hint without override chrome (list editors, MCP rows).
47
- */
48
- function PlainField(props) {
49
- const invalid = props.invalid === true;
50
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
51
- className: fields_module_css_default.field,
52
- children: [
53
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
54
- className: fields_module_css_default.label,
55
- htmlFor: props.id,
56
- children: props.label
57
- }),
58
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
59
- id: props.id,
60
- className: invalid ? fields_module_css_default.inputInvalid : fields_module_css_default.input,
61
- type: "text",
62
- value: props.value,
63
- placeholder: props.placeholder ?? "",
64
- disabled: props.disabled,
65
- "aria-invalid": invalid || void 0,
66
- onChange: (event) => {
67
- props.onChange(event.target.value);
68
- }
69
- }),
70
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
71
- className: fields_module_css_default.hint,
72
- children: props.hint
73
- })
74
- ]
75
- });
76
- }
77
45
  /** Same chrome as PlainField, for a short option list (MCP transport). */
78
46
  function SelectField(props) {
79
47
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -86,7 +54,7 @@ window.__ModuleLoader__.load({
86
54
  }),
87
55
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
88
56
  id: props.id,
89
- className: fields_module_css_default.select,
57
+ className: `${fields_module_css_default.input} ${fields_module_css_default.select}`,
90
58
  value: props.value,
91
59
  disabled: props.disabled,
92
60
  onChange: (event) => {
@@ -137,7 +105,7 @@ window.__ModuleLoader__.load({
137
105
  }),
138
106
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
139
107
  id: props.id,
140
- 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,
141
109
  type: "text",
142
110
  ...props.numeric === true ? { inputMode: "numeric" } : {},
143
111
  ...props.invalid ? { "aria-invalid": true } : {},
@@ -225,21 +193,21 @@ window.__ModuleLoader__.load({
225
193
  document.head.appendChild(tag);
226
194
  }
227
195
  var PluginCard_module_css_default = {
196
+ "name": "YRvGva_name",
197
+ "failed": "YRvGva_failed",
198
+ "readOnly": "YRvGva_readOnly",
199
+ "chevronOpen": "YRvGva_chevronOpen",
200
+ "pending": "YRvGva_pending",
228
201
  "headText": "YRvGva_headText",
229
202
  "header": "YRvGva_header",
230
- "readOnly": "YRvGva_readOnly",
203
+ "chevron": "YRvGva_chevron",
204
+ "discard": "YRvGva_discard",
231
205
  "save": "YRvGva_save",
232
- "description": "YRvGva_description",
206
+ "body": "YRvGva_body",
233
207
  "footer": "YRvGva_footer",
234
- "card": "YRvGva_card",
235
208
  "cardOpen": "YRvGva_cardOpen",
236
- "discard": "YRvGva_discard",
237
- "pending": "YRvGva_pending",
238
- "name": "YRvGva_name",
239
- "body": "YRvGva_body",
240
- "chevron": "YRvGva_chevron",
241
- "failed": "YRvGva_failed",
242
- "chevronOpen": "YRvGva_chevronOpen"
209
+ "card": "YRvGva_card",
210
+ "description": "YRvGva_description"
243
211
  };
244
212
  //#endregion
245
213
  //#region src/client/PluginCard.tsx
@@ -434,14 +402,14 @@ window.__ModuleLoader__.load({
434
402
  document.head.appendChild(tag);
435
403
  }
436
404
  var PluginsSettingsSection_module_css_default = {
437
- "intro": "ha2I9q_intro",
405
+ "section": "ha2I9q_section",
406
+ "cards": "ha2I9q_cards",
438
407
  "empty": "ha2I9q_empty",
439
408
  "heading": "ha2I9q_heading",
440
409
  "panel": "ha2I9q_panel",
441
- "tab": "ha2I9q_tab",
442
- "section": "ha2I9q_section",
443
- "cards": "ha2I9q_cards",
444
- "tabs": "ha2I9q_tabs"
410
+ "tabs": "ha2I9q_tabs",
411
+ "intro": "ha2I9q_intro",
412
+ "tab": "ha2I9q_tab"
445
413
  };
446
414
  //#endregion
447
415
  //#region src/client/ConfigurablePluginsTab.tsx
@@ -472,7 +440,7 @@ window.__ModuleLoader__.load({
472
440
  }
473
441
  //#endregion
474
442
  //#region \0xrk-css:C:\Users\sunflowerss\Desktop\XRKgrocery\XRK-harness\packages\client\ui-settings-plugins\src\client\McpCard.module.css.mjs
475
- 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}";
476
444
  const tagId = "@xrkseek/client-ui-settings-plugins/McpCard.module.css";
477
445
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
478
446
  const tag = document.createElement("style");
@@ -482,35 +450,37 @@ window.__ModuleLoader__.load({
482
450
  document.head.appendChild(tag);
483
451
  }
484
452
  var McpCard_module_css_default = {
485
- "connectedRow": "FVl50a_connectedRow",
486
453
  "badgeMuted": "FVl50a_badgeMuted",
487
- "add": "FVl50a_add",
488
- "badgeError": "FVl50a_badgeError",
489
- "paste": "FVl50a_paste",
490
454
  "entryTitle": "FVl50a_entryTitle",
491
- "invalid": "FVl50a_invalid",
492
- "entryBody": "FVl50a_entryBody",
493
- "block": "FVl50a_block",
494
455
  "note": "FVl50a_note",
495
- "badge": "FVl50a_badge",
496
- "remove": "FVl50a_remove",
497
- "connectedName": "FVl50a_connectedName",
456
+ "badgeWarn": "FVl50a_badgeWarn",
457
+ "allowTitle": "FVl50a_allowTitle",
458
+ "statusDot": "FVl50a_statusDot",
498
459
  "empty": "FVl50a_empty",
499
- "heading": "FVl50a_heading",
460
+ "badgeError": "FVl50a_badgeError",
461
+ "allowRow": "FVl50a_allowRow",
462
+ "connectedName": "FVl50a_connectedName",
463
+ "entryTitleRow": "FVl50a_entryTitleRow",
464
+ "entry": "FVl50a_entry",
500
465
  "entryHead": "FVl50a_entryHead",
501
466
  "connectedList": "FVl50a_connectedList",
502
- "entry": "FVl50a_entry",
467
+ "remove": "FVl50a_remove",
468
+ "badgeOk": "FVl50a_badgeOk",
469
+ "connectedRow": "FVl50a_connectedRow",
470
+ "heading": "FVl50a_heading",
471
+ "invalid": "FVl50a_invalid",
472
+ "allowHint": "FVl50a_allowHint",
503
473
  "list": "FVl50a_list",
504
- "pasteLabel": "FVl50a_pasteLabel"
474
+ "entryBody": "FVl50a_entryBody",
475
+ "paste": "FVl50a_paste",
476
+ "add": "FVl50a_add",
477
+ "block": "FVl50a_block",
478
+ "pasteLabel": "FVl50a_pasteLabel",
479
+ "badge": "FVl50a_badge"
505
480
  };
506
481
  //#endregion
507
482
  //#region src/client/McpCard.tsx
508
- /** MCP desired-server card: edit draft servers; connected overlay stays read-only.
509
- *
510
- * Same vertical field stack as Agent / Bash (label + control + hint). All of
511
- * name / transport / command / args / cwd stay visible so they read alike —
512
- * no launch-line merge, no buried “advanced” cwd.
513
- */
483
+ /** MCP desired-server card: allow toggle, per-row status, JSON paste. */
514
484
  /**
515
485
  * Render the MCP card.
516
486
  * @param props - locale copy, the card snapshot, and its form actions.
@@ -521,10 +491,16 @@ window.__ModuleLoader__.load({
521
491
  const state = props.useMcpCard((snapshot) => snapshot);
522
492
  const disabled = !state.writable;
523
493
  const pasteRef = (0, react.useRef)(null);
524
- const addFromPasteOrBlank = () => {
494
+ const [pasteHint, setPasteHint] = (0, react.useState)();
495
+ const addFromPaste = () => {
525
496
  const pasted = pasteRef.current?.value ?? "";
526
- props.addRow(pasted);
527
- if (pasteRef.current) pasteRef.current.value = "";
497
+ const result = props.addRow(pasted);
498
+ if (result === "ok") {
499
+ if (pasteRef.current) pasteRef.current.value = "";
500
+ setPasteHint(void 0);
501
+ return;
502
+ }
503
+ setPasteHint(result === "empty" ? t("mcpPasteEmpty") : t("mcpPasteInvalid"));
528
504
  };
529
505
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(PluginCard, {
530
506
  t,
@@ -539,43 +515,23 @@ window.__ModuleLoader__.load({
539
515
  role: "note",
540
516
  children: state.note
541
517
  }) : null,
542
- state.connected.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
543
- className: McpCard_module_css_default.block,
544
- "aria-label": t("mcpConnectedHeading"),
545
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
546
- className: McpCard_module_css_default.heading,
547
- children: t("mcpConnectedHeading")
548
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
549
- className: McpCard_module_css_default.connectedList,
550
- children: state.connected.map((entry) => {
551
- const status = entry.status ?? "connected";
552
- const statusClass = status === "gave-up" ? McpCard_module_css_default.badgeError : status === "reconnecting" ? McpCard_module_css_default.badgeMuted : McpCard_module_css_default.badge;
553
- const statusLabel = status === "gave-up" ? t("mcpStatusGaveUp") : status === "reconnecting" ? t("mcpStatusReconnecting") : t("mcpStatusConnected");
554
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
555
- className: McpCard_module_css_default.connectedRow,
556
- "data-mcp-status": status,
557
- children: [
558
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
559
- className: McpCard_module_css_default.connectedName,
560
- children: entry.serverName
561
- }),
562
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
563
- className: statusClass,
564
- children: statusLabel
565
- }),
566
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
567
- className: McpCard_module_css_default.badgeMuted,
568
- children: [
569
- entry.toolCount,
570
- " ",
571
- t("mcpToolsLabel")
572
- ]
573
- })
574
- ]
575
- }, entry.id);
576
- })
577
- })]
578
- }) : 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
+ }),
579
535
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
580
536
  className: McpCard_module_css_default.block,
581
537
  "aria-label": t("mcpServersHeading"),
@@ -587,19 +543,16 @@ window.__ModuleLoader__.load({
587
543
  state.rows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
588
544
  className: McpCard_module_css_default.empty,
589
545
  children: t("mcpServersEmpty")
590
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
546
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
591
547
  className: McpCard_module_css_default.list,
592
- children: state.rows.map((row, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ServerEntry, {
548
+ children: state.rows.map((row, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ServerSummary, {
593
549
  t,
594
- index,
595
550
  row,
596
551
  disabled,
597
- showErrors: state.showErrors,
598
- onEdit: props.editRow,
599
552
  onRemove: () => {
600
553
  props.removeRow(index);
601
554
  }
602
- }, `mcp-row-${String(index)}`))
555
+ }, `mcp-row-${row.serverName}-${String(index)}`))
603
556
  }),
604
557
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
605
558
  className: McpCard_module_css_default.pasteLabel,
@@ -612,124 +565,195 @@ window.__ModuleLoader__.load({
612
565
  className: McpCard_module_css_default.paste,
613
566
  disabled,
614
567
  placeholder: t("mcpPasteHint"),
615
- rows: 5,
616
- spellCheck: false
568
+ rows: 8,
569
+ spellCheck: false,
570
+ onChange: () => {
571
+ if (pasteHint) setPasteHint(void 0);
572
+ }
617
573
  }),
618
574
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
619
575
  type: "button",
620
576
  className: McpCard_module_css_default.add,
621
577
  disabled,
622
- onClick: addFromPasteOrBlank,
578
+ onClick: addFromPaste,
623
579
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_xrkseek_client_ui_primitives.IconPlusOutline16, { size: 14 }), t("mcpAddServer")]
624
580
  }),
625
- state.showErrors ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
581
+ pasteHint ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
626
582
  className: McpCard_module_css_default.invalid,
627
583
  role: "status",
628
- children: t("mcpRowInvalid")
584
+ children: pasteHint
629
585
  }) : null
630
586
  ]
631
587
  })
632
588
  ]
633
589
  });
634
590
  }
635
- function ServerEntry({ t, index, row, disabled, showErrors, onEdit, onRemove }) {
636
- const n = String(index + 1);
637
- const title = row.serverName.trim() || t("mcpServerRow").replace("{index}", n);
638
- const nameInvalid = showErrors && row.serverName.trim() === "";
639
- const endpointInvalid = showErrors && (row.transport === "http" ? row.url.trim() === "" : row.command.trim() === "");
640
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
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
+ }
610
+ function ServerSummary({ t, row, disabled, onRemove }) {
611
+ const summary = row.transport === "http" ? row.url : [row.command, row.args].filter((part) => part.trim()).join(" ");
612
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
641
613
  className: McpCard_module_css_default.entry,
642
- "aria-label": title,
643
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
614
+ "aria-label": row.serverName,
615
+ "data-mcp-status": row.status,
616
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
644
617
  className: McpCard_module_css_default.entryHead,
645
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
646
- className: McpCard_module_css_default.entryTitle,
647
- children: title
648
- }), /* @__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", {
649
654
  type: "button",
650
655
  className: McpCard_module_css_default.remove,
651
- "aria-label": `${t("mcpRemoveServer")} ${n}`,
656
+ "aria-label": `${t("mcpRemoveServer")} ${row.serverName}`,
652
657
  title: t("mcpRemoveServer"),
653
658
  disabled,
654
659
  onClick: onRemove,
655
660
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_xrkseek_client_ui_primitives.IconTrashOutline16, { size: 14 })
656
661
  })]
657
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
658
- className: McpCard_module_css_default.entryBody,
659
- children: [
660
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlainField, {
661
- id: `plugin-config-mcp-name-${String(index)}`,
662
- label: t("mcpServerName"),
663
- hint: t("mcpServerNameHint"),
664
- value: row.serverName,
665
- invalid: nameInvalid,
666
- disabled,
667
- onChange: (value) => {
668
- onEdit(index, { serverName: value });
669
- }
670
- }),
671
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectField, {
672
- id: `plugin-config-mcp-transport-${String(index)}`,
673
- label: t("mcpTransport"),
674
- hint: t("mcpTransportHint"),
675
- value: row.transport,
676
- disabled,
677
- options: [{
678
- value: "stdio",
679
- label: t("mcpTransportStdio")
680
- }, {
681
- value: "http",
682
- label: t("mcpTransportHttp")
683
- }],
684
- onChange: (value) => {
685
- onEdit(index, { transport: value });
686
- }
687
- }),
688
- row.transport === "http" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlainField, {
689
- id: `plugin-config-mcp-url-${String(index)}`,
690
- label: t("mcpUrl"),
691
- hint: t("mcpUrlHint"),
692
- value: row.url,
693
- invalid: endpointInvalid,
694
- disabled,
695
- onChange: (value) => {
696
- onEdit(index, { url: value });
662
+ })
663
+ });
664
+ }
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")
697
710
  }
698
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
699
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlainField, {
700
- id: `plugin-config-mcp-command-${String(index)}`,
701
- label: t("mcpCommand"),
702
- hint: t("mcpCommandHint"),
703
- value: row.command,
704
- invalid: endpointInvalid,
705
- disabled,
706
- onChange: (value) => {
707
- onEdit(index, { command: value });
708
- }
709
- }),
710
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlainField, {
711
- id: `plugin-config-mcp-args-${String(index)}`,
712
- label: t("mcpArgs"),
713
- hint: t("mcpArgsHint"),
714
- value: row.args,
715
- disabled,
716
- onChange: (value) => {
717
- onEdit(index, { args: value });
718
- }
719
- }),
720
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlainField, {
721
- id: `plugin-config-mcp-cwd-${String(index)}`,
722
- label: t("mcpCwd"),
723
- hint: t("mcpCwdHint"),
724
- value: row.cwd,
725
- disabled,
726
- onChange: (value) => {
727
- onEdit(index, { cwd: value });
728
- }
729
- })
730
- ] })
731
- ]
732
- })]
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
+ ]
733
757
  });
734
758
  }
735
759
  //#endregion
@@ -826,73 +850,6 @@ window.__ModuleLoader__.load({
826
850
  });
827
851
  }
828
852
  //#endregion
829
- //#region src/client/WebSearchCard.tsx
830
- /**
831
- * Render the web-search card.
832
- * @param props - locale copy, the card snapshot, and its form actions.
833
- * @returns the card.
834
- */
835
- function WebSearchCard(props) {
836
- const { t } = props;
837
- const state = props.useWebSearchCard((snapshot) => snapshot);
838
- const disabled = !state.writable;
839
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(PluginCard, {
840
- t,
841
- titleKey: "webSearchTitle",
842
- descriptionKey: "webSearchDescription",
843
- state,
844
- onSave: props.save,
845
- onDiscard: props.discard,
846
- children: [
847
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretField, {
848
- id: "plugin-config-web-search-key",
849
- label: t("webSearchApiKey"),
850
- hint: t("webSearchApiKeyHint"),
851
- disabled: !state.apiKeyWritable,
852
- text: state.apiKey.text,
853
- configured: state.apiKeyConfigured,
854
- stateLabel: state.apiKeyConfigured ? t("webSearchApiKeySet") : t("webSearchApiKeyUnset"),
855
- onEdit: (text) => {
856
- props.edit("apiKey", text);
857
- }
858
- }),
859
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
860
- id: "plugin-config-web-search-endpoint",
861
- label: t("webSearchBaseUrl"),
862
- hint: t("webSearchBaseUrlHint"),
863
- overriddenLabel: t("overridden"),
864
- resetLabel: t("reset"),
865
- invalidLabel: t("invalidNumber"),
866
- disabled,
867
- ...state.baseURL,
868
- onEdit: (text) => {
869
- props.edit("baseURL", text);
870
- },
871
- onReset: () => {
872
- props.resetField("baseURL");
873
- }
874
- }),
875
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
876
- id: "plugin-config-web-search-max-uses",
877
- label: t("webSearchMaxUses"),
878
- hint: t("webSearchMaxUsesHint"),
879
- overriddenLabel: t("overridden"),
880
- resetLabel: t("reset"),
881
- invalidLabel: t("invalidNumber"),
882
- numeric: true,
883
- disabled,
884
- ...state.maxUses,
885
- onEdit: (text) => {
886
- props.edit("maxUses", text);
887
- },
888
- onReset: () => {
889
- props.resetField("maxUses");
890
- }
891
- })
892
- ]
893
- });
894
- }
895
- //#endregion
896
853
  //#region src/client/card-form.ts
897
854
  /**
898
855
  * A whole-number field. An empty draft clears the field; any other draft that
@@ -1184,11 +1141,11 @@ window.__ModuleLoader__.load({
1184
1141
  //#endregion
1185
1142
  //#region src/client/bash-card-controller.ts
1186
1143
  /**
1187
- * Namespace of the shell capability. Spelled here rather than imported: a
1188
- * client package must not depend on a Host package, and the executor families
1189
- * that own it spell the same value.
1144
+ * Namespace of the bash/terminal capability. Must match Face
1145
+ * `FACE_PRODUCT_SETTINGS_NAMESPACES` (`bash`) or the Plugins tab never
1146
+ * dispatches this card (Host serves `bash`, not `shell`).
1190
1147
  */
1191
- const SHELL_NS = "shell";
1148
+ const SHELL_NS = "bash";
1192
1149
  /** Bridges the `bash` scope onto the shell card's staged form. */
1193
1150
  var BashCardController = class {
1194
1151
  form;
@@ -1223,6 +1180,9 @@ window.__ModuleLoader__.load({
1223
1180
  scope;
1224
1181
  store;
1225
1182
  rows = [];
1183
+ allowConnect = false;
1184
+ /** True after the user toggles Allow connect (so save respects an explicit park). */
1185
+ allowTouched = false;
1226
1186
  seeded = false;
1227
1187
  saving = false;
1228
1188
  failed = false;
@@ -1244,11 +1204,13 @@ window.__ModuleLoader__.load({
1244
1204
  return;
1245
1205
  }
1246
1206
  if (!this.seeded || force && !this.dirty()) {
1247
- 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;
1248
1210
  this.seeded = true;
1249
1211
  this.failed = false;
1250
1212
  this.showErrors = false;
1251
- }
1213
+ } else this.rows = this.rows.map((row) => enrichRowStatus(row, snapshot));
1252
1214
  this.publish();
1253
1215
  }
1254
1216
  projection() {
@@ -1264,7 +1226,7 @@ window.__ModuleLoader__.load({
1264
1226
  saving: this.saving,
1265
1227
  failed: this.failed,
1266
1228
  rows: this.rows,
1267
- connected: connectedOf(snapshot),
1229
+ allowConnect: this.allowConnect,
1268
1230
  note: noteOf(snapshot)
1269
1231
  };
1270
1232
  }
@@ -1272,6 +1234,7 @@ window.__ModuleLoader__.load({
1272
1234
  if (!this.seeded) return false;
1273
1235
  const snapshot = this.scope.getSnapshot();
1274
1236
  if (snapshot.status !== "ready") return false;
1237
+ if (this.allowConnect !== allowOf(snapshot)) return true;
1275
1238
  return JSON.stringify(this.rows.map(rowFromUi)) !== JSON.stringify(serversOf(snapshot));
1276
1239
  }
1277
1240
  publish() {
@@ -1284,12 +1247,13 @@ window.__ModuleLoader__.load({
1284
1247
  editRow: (index, patch) => {
1285
1248
  this.editRow(index, patch);
1286
1249
  },
1287
- addRow: (paste) => {
1288
- this.addRow(paste);
1289
- },
1250
+ addRow: (paste) => this.addRow(paste),
1290
1251
  removeRow: (index) => {
1291
1252
  this.removeRow(index);
1292
1253
  },
1254
+ setAllowConnect: (allow) => {
1255
+ this.setAllowConnect(allow);
1256
+ },
1293
1257
  edit: () => {},
1294
1258
  resetField: () => {},
1295
1259
  save: () => {
@@ -1300,6 +1264,12 @@ window.__ModuleLoader__.load({
1300
1264
  }
1301
1265
  };
1302
1266
  }
1267
+ setAllowConnect(allow) {
1268
+ this.allowConnect = allow;
1269
+ this.allowTouched = true;
1270
+ this.failed = false;
1271
+ this.publish();
1272
+ }
1303
1273
  editRow(index, patch) {
1304
1274
  const row = this.rows[index];
1305
1275
  if (row === void 0) return;
@@ -1322,14 +1292,24 @@ window.__ModuleLoader__.load({
1322
1292
  this.publish();
1323
1293
  }
1324
1294
  addRow(paste) {
1325
- const imported = paste ? rowsFromMcpPaste(paste) : [];
1326
- this.rows = imported.length > 0 ? [...this.rows, ...imported] : [...this.rows, emptyRow()];
1295
+ const raw = typeof paste === "string" ? paste.trim() : "";
1296
+ if (!raw) return "empty";
1297
+ const imported = rowsFromMcpPaste(raw);
1298
+ if (imported.length === 0) return "invalid";
1299
+ const snapshot = this.scope.getSnapshot();
1300
+ this.rows = mergeRowsByName(this.rows, imported).map((row) => enrichRowStatus(row, snapshot));
1301
+ this.allowConnect = true;
1327
1302
  this.failed = false;
1328
1303
  this.publish();
1304
+ return "ok";
1329
1305
  }
1330
1306
  removeRow(index) {
1331
1307
  if (index < 0 || index >= this.rows.length) return;
1332
1308
  this.rows = this.rows.toSpliced(index, 1);
1309
+ if (this.rows.length === 0) {
1310
+ this.allowConnect = false;
1311
+ this.allowTouched = false;
1312
+ }
1333
1313
  this.failed = false;
1334
1314
  if (!this.rows.some((r) => validateRow(r) !== void 0)) this.showErrors = false;
1335
1315
  this.publish();
@@ -1337,7 +1317,9 @@ window.__ModuleLoader__.load({
1337
1317
  discard() {
1338
1318
  const snapshot = this.scope.getSnapshot();
1339
1319
  if (snapshot.status !== "ready") return;
1340
- 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;
1341
1323
  this.failed = false;
1342
1324
  this.showErrors = false;
1343
1325
  this.publish();
@@ -1356,12 +1338,20 @@ window.__ModuleLoader__.load({
1356
1338
  this.showErrors = false;
1357
1339
  this.publish();
1358
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);
1359
1344
  await this.scope.set("servers", payload);
1360
1345
  const after = this.scope.getSnapshot();
1361
- 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);
1362
1347
  this.saving = false;
1363
1348
  this.failed = !landed;
1364
- 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
+ }
1365
1355
  this.publish();
1366
1356
  }
1367
1357
  };
@@ -1369,36 +1359,94 @@ window.__ModuleLoader__.load({
1369
1359
  const raw = snapshot.value?.servers;
1370
1360
  return Array.isArray(raw) ? raw.map(normalizeStoredRow) : [];
1371
1361
  }
1372
- function connectedOf(snapshot) {
1373
- const raw = snapshot.value?.connected;
1374
- if (!Array.isArray(raw)) return [];
1375
- return raw.filter(isConnectedEntry);
1362
+ function allowOf(snapshot) {
1363
+ return snapshot.value?.allowConnect === true;
1376
1364
  }
1377
1365
  function noteOf(snapshot) {
1378
- 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
+ };
1379
1419
  }
1380
1420
  function isConnectedEntry(value) {
1381
- 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";
1382
1424
  }
1383
- function normalizeStoredRow(row) {
1384
- const url = typeof row.url === "string" ? row.url.trim() : "";
1385
- 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;
1386
1431
  return {
1387
- serverName: String(row.serverName ?? "").trim(),
1388
- ...url ? { url } : command ? { command } : {},
1389
- ...Array.isArray(row.args) && row.args.length > 0 ? { args: row.args.map(String) } : {},
1390
- ...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 } : {}
1391
1437
  };
1392
1438
  }
1393
- function rowToUi(row) {
1394
- 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);
1395
1442
  return {
1396
- serverName: row.serverName,
1397
- transport: url ? "http" : "stdio",
1398
- command: typeof row.command === "string" ? row.command : "",
1399
- url,
1400
- args: Array.isArray(row.args) ? row.args.join(", ") : "",
1401
- 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
1402
1450
  };
1403
1451
  }
1404
1452
  function rowFromUi(row) {
@@ -1407,7 +1455,7 @@ window.__ModuleLoader__.load({
1407
1455
  serverName,
1408
1456
  url: row.url.trim()
1409
1457
  };
1410
- 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);
1411
1459
  const cwd = row.cwd.trim();
1412
1460
  return {
1413
1461
  serverName,
@@ -1416,35 +1464,17 @@ window.__ModuleLoader__.load({
1416
1464
  ...cwd ? { cwd } : {}
1417
1465
  };
1418
1466
  }
1419
- function emptyRow() {
1420
- return {
1421
- serverName: "",
1422
- transport: "stdio",
1423
- command: "",
1424
- url: "",
1425
- args: "",
1426
- cwd: ""
1427
- };
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";
1428
1471
  }
1429
- function namedRowToUi(name, row) {
1430
- const serverName = name.trim();
1431
- if (!serverName) return void 0;
1432
- const url = typeof row.url === "string" ? row.url.trim() : "";
1433
- const command = typeof row.command === "string" ? row.command.trim() : "";
1434
- if (!url && !command) return void 0;
1435
- return {
1436
- serverName,
1437
- transport: url ? "http" : "stdio",
1438
- command,
1439
- url,
1440
- args: Array.isArray(row.args) ? row.args.map(String).join(", ") : "",
1441
- cwd: typeof row.cwd === "string" ? row.cwd : ""
1442
- };
1472
+ function mergeRowsByName(existing, imported) {
1473
+ const byName = new Map(existing.map((row) => [row.serverName, row]));
1474
+ for (const row of imported) byName.set(row.serverName, row);
1475
+ return [...byName.values()];
1443
1476
  }
1444
- /**
1445
- * Cursor / Claude Desktop paste: `{ "mcpServers": { "12306-mcp": { "command": "npx", "args": ["-y", "12306-mcp"] } } }`.
1446
- * Also accepts a bare name map or a Face array of `{ serverName, command }`.
1447
- */
1477
+ /** Parse Cursor/Trae `{ mcpServers: { name: { command|url, args? } } }` into rows. */
1448
1478
  function rowsFromMcpPaste(raw) {
1449
1479
  let parsed;
1450
1480
  try {
@@ -1452,32 +1482,169 @@ window.__ModuleLoader__.load({
1452
1482
  } catch {
1453
1483
  return [];
1454
1484
  }
1455
- if (Array.isArray(parsed)) {
1456
- const out = [];
1457
- for (const row of parsed) {
1458
- if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1459
- const o = row;
1460
- const mapped = namedRowToUi(String(o.serverName ?? ""), o);
1461
- if (mapped) out.push(mapped);
1462
- }
1463
- return out;
1464
- }
1465
- if (!parsed || typeof parsed !== "object") return [];
1485
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return [];
1466
1486
  const root = parsed;
1467
- const map = root.mcpServers && typeof root.mcpServers === "object" && !Array.isArray(root.mcpServers) ? root.mcpServers : root;
1468
- const out = [];
1469
- for (const [name, row] of Object.entries(map)) {
1470
- if (!row || typeof row !== "object" || Array.isArray(row)) continue;
1471
- const mapped = namedRowToUi(name, row);
1472
- 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
+ });
1473
1522
  }
1474
- return out;
1523
+ return rows;
1475
1524
  }
1476
- function validateRow(row) {
1477
- if (!row.serverName.trim()) return "serverName";
1478
- if (row.transport === "http") return row.url.trim() ? void 0 : "url";
1479
- 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
+ };
1480
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
+ };
1481
1648
  //#endregion
1482
1649
  //#region src/client/tab-store.ts
1483
1650
  /** Reads the served namespaces and pairs them with the cards that claim them. */
@@ -1552,137 +1719,6 @@ window.__ModuleLoader__.load({
1552
1719
  }
1553
1720
  };
1554
1721
  //#endregion
1555
- //#region src/client/web-search-card-controller.ts
1556
- /**
1557
- * Namespace of the DeepSeek search provider. Spelled here rather than
1558
- * imported: a client package must not depend on a Host package.
1559
- */
1560
- const WEB_SEARCH_NS = "web-search-deepseek";
1561
- /** Credential reference the provider resolves when the section names none. */
1562
- const DEFAULT_API_KEY_REF = "DEEPSEEK_API_KEY";
1563
- /** Form field the credential control stages under. */
1564
- const API_KEY_FIELD = "apiKey";
1565
- /** Bridges the `web-search-deepseek` scope and the credentials domain onto the card. */
1566
- var WebSearchCardController = class {
1567
- scope;
1568
- api;
1569
- form;
1570
- store;
1571
- credential = {
1572
- ref: "",
1573
- configured: false,
1574
- writable: true
1575
- };
1576
- /**
1577
- * @param scope - the bound settings scope for the `web-search-deepseek` namespace.
1578
- * @param api - wire face used for the credential the section references.
1579
- */
1580
- constructor(scope, api) {
1581
- this.scope = scope;
1582
- this.api = api;
1583
- this.form = new CardForm(scope, [textField("baseURL"), numberField("maxUses")], [{
1584
- field: API_KEY_FIELD,
1585
- write: (text) => this.writeKey(text)
1586
- }]);
1587
- this.store = this.form.bind(() => this.projection());
1588
- scope.subscribe(() => {
1589
- this.readCredential();
1590
- });
1591
- this.readCredential();
1592
- }
1593
- projection() {
1594
- return {
1595
- ...this.form.shell(),
1596
- baseURL: this.form.field("baseURL"),
1597
- maxUses: this.form.field("maxUses"),
1598
- apiKey: this.form.field(API_KEY_FIELD),
1599
- apiKeyConfigured: this.credential.configured,
1600
- apiKeyWritable: this.credential.writable
1601
- };
1602
- }
1603
- /**
1604
- * Ask the credentials domain about the reference the section currently names.
1605
- *
1606
- * The answer is stored with the reference it describes: `apiKeyEnv` can
1607
- * change between the request and its response, and two reads can settle out
1608
- * of order, so a response is published only while it still answers for the
1609
- * reference in force.
1610
- */
1611
- async readCredential() {
1612
- const ref = refOf(this.scope.getSnapshot());
1613
- if (ref !== this.credential.ref) {
1614
- this.credential = {
1615
- ref,
1616
- configured: false,
1617
- writable: true
1618
- };
1619
- this.store.set(this.projection());
1620
- }
1621
- let response;
1622
- try {
1623
- response = await this.api.credentials.describe({ refs: [ref] });
1624
- } catch (_credentialReadFailure) {
1625
- return;
1626
- }
1627
- if (!response.result.ok || ref !== refOf(this.scope.getSnapshot())) return;
1628
- const view = response.result.value.credentials[ref];
1629
- const next = {
1630
- ref,
1631
- configured: view?.configured ?? false,
1632
- writable: view?.writable ?? true
1633
- };
1634
- if (next.configured === this.credential.configured && next.writable === this.credential.writable) return;
1635
- this.credential = next;
1636
- this.store.set(this.projection());
1637
- }
1638
- /**
1639
- * Re-read after the Host reports a change to the reference this card watches.
1640
- *
1641
- * A key can be written from somewhere else — the Models page addresses the
1642
- * same reference — and the settings section does not change when it is, so
1643
- * without this the badge keeps reporting a state the Host already replaced.
1644
- * @param ref - the reference the Host reports as changed.
1645
- */
1646
- refreshCredential(ref) {
1647
- if (ref !== this.credential.ref) return;
1648
- this.readCredential();
1649
- }
1650
- /**
1651
- * Build the face the card's slot registration injects.
1652
- * @returns the card's snapshot and its form actions.
1653
- */
1654
- inject() {
1655
- return {
1656
- hooks: { webSearchCard: this.store },
1657
- ...this.form.actions()
1658
- };
1659
- }
1660
- /**
1661
- * Write the staged key, then re-read whether the Host now holds one.
1662
- * @param value - the staged credential literal.
1663
- * @returns whether the Host reports a configured credential afterwards.
1664
- */
1665
- async writeKey(value) {
1666
- try {
1667
- await this.api.credentials.set({
1668
- ref: refOf(this.scope.getSnapshot()),
1669
- value
1670
- });
1671
- } catch (_credentialWriteFailure) {}
1672
- await this.readCredential();
1673
- return this.credential.configured;
1674
- }
1675
- };
1676
- /**
1677
- * The credential reference the section names, or the provider's default.
1678
- * @param snapshot - the current scope snapshot.
1679
- * @returns the reference to address.
1680
- */
1681
- function refOf(snapshot) {
1682
- const declared = snapshot.value?.apiKeyEnv;
1683
- return declared !== void 0 && declared.length > 0 ? declared : DEFAULT_API_KEY_REF;
1684
- }
1685
- //#endregion
1686
1722
  //#region src/client/locales.ts
1687
1723
  /** English copy. */
1688
1724
  const en = {
@@ -1713,25 +1749,17 @@ window.__ModuleLoader__.load({
1713
1749
  agentLoopDescription: "How the agent dispatches tool calls.",
1714
1750
  agentLoopMaxParallel: "Parallel tool calls",
1715
1751
  agentLoopMaxParallelHint: "Upper bound on parallel-safe calls running at once within one step.",
1716
- webSearchTitle: "Web search",
1717
- webSearchDescription: "The XRK search provider.",
1718
- webSearchApiKey: "API key",
1719
- webSearchApiKeyHint: "Stored outside the settings file. Leave blank to keep the current key.",
1720
- webSearchApiKeySet: "A key is configured.",
1721
- webSearchApiKeyUnset: "No key is configured; search is unavailable until one is.",
1722
- webSearchBaseUrl: "Endpoint",
1723
- webSearchBaseUrlHint: "Leave blank to use the provider default.",
1724
- webSearchMaxUses: "Max searches per request",
1725
- webSearchMaxUsesHint: "How many times one request may search before it must answer.",
1726
1752
  mcpTitle: "MCP servers",
1727
- mcpDescription: "Add local commands or remote URLs. Saved list remounts live when Host uses the settings file (empty XRK_MCP_SERVERS). Allow policy still required to connect.",
1753
+ mcpDescription: "Paste Cursor / Trae style JSON, then save servers mount on save (no separate env step).",
1728
1754
  mcpConnectedHeading: "Connected now",
1729
1755
  mcpServersHeading: "Servers",
1730
- mcpServersEmpty: "No servers yet. Add one, save, and Host remounts.",
1731
- mcpAddServer: "Add server",
1756
+ mcpServersEmpty: "No servers yet. Paste a JSON block below and add.",
1757
+ mcpAddServer: "Add from JSON",
1732
1758
  mcpRemoveServer: "Remove",
1733
- mcpPaste: "Paste JSON",
1734
- mcpPasteHint: "{ \"mcpServers\": { \"12306-mcp\": { \"command\": \"npx\", \"args\": [\"-y\", \"12306-mcp\"] } } }",
1759
+ mcpPaste: "Paste JSON block",
1760
+ mcpPasteHint: "{ \"mcpServers\": { \"demo\": { \"command\": \"npx\", \"args\": [\"-y\", \"demo-mcp\"] } } }",
1761
+ mcpPasteEmpty: "Paste a JSON block first.",
1762
+ mcpPasteInvalid: "Could not find mcpServers entries in that JSON.",
1735
1763
  mcpServerRow: "Server {index}",
1736
1764
  mcpServerName: "Name",
1737
1765
  mcpServerNameHint: "Short id in tool names (mcp__name__…).",
@@ -1749,9 +1777,31 @@ window.__ModuleLoader__.load({
1749
1777
  mcpCwdHint: "Optional. Leave blank to use the Host default.",
1750
1778
  mcpRowInvalid: "Each server needs a name and a command or URL.",
1751
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.",
1752
1782
  mcpStatusConnected: "Connected",
1753
1783
  mcpStatusReconnecting: "Reconnecting",
1754
- 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"
1755
1805
  };
1756
1806
  /** Simplified Chinese copy. */
1757
1807
  const zh = {
@@ -1782,25 +1832,17 @@ window.__ModuleLoader__.load({
1782
1832
  agentLoopDescription: "Agent 如何派发工具调用。",
1783
1833
  agentLoopMaxParallel: "并行工具调用数",
1784
1834
  agentLoopMaxParallelHint: "同一步内最多同时运行多少个可并行的调用。",
1785
- webSearchTitle: "网页搜索",
1786
- webSearchDescription: "XRK 搜索提供方。",
1787
- webSearchApiKey: "API Key",
1788
- webSearchApiKeyHint: "不写入设置文件。留空表示保持当前密钥。",
1789
- webSearchApiKeySet: "已配置密钥。",
1790
- webSearchApiKeyUnset: "未配置密钥;配置之前搜索不可用。",
1791
- webSearchBaseUrl: "接口地址",
1792
- webSearchBaseUrlHint: "留空则使用提供方默认地址。",
1793
- webSearchMaxUses: "单次请求最多搜索次数",
1794
- webSearchMaxUsesHint: "一次请求在必须作答前最多可以搜索多少次。",
1795
1835
  mcpTitle: "MCP 服务器",
1796
- mcpDescription: "添加本地命令或远程 URL。设置文件为真源(空 XRK_MCP_SERVERS)时保存后热挂载;连接仍需 allow 策略。",
1836
+ mcpDescription: "粘贴 Trae / Cursor 风格 mcpServers JSON,保存后会挂载(不必再先开环境变量)。",
1797
1837
  mcpConnectedHeading: "当前已连接",
1798
1838
  mcpServersHeading: "服务器",
1799
- mcpServersEmpty: "还没有服务器。添加一条并保存即可热挂载。",
1800
- mcpAddServer: "添加服务器",
1839
+ mcpServersEmpty: "还没有服务器。在下方粘贴 JSON 块后点添加。",
1840
+ mcpAddServer: "从 JSON 添加",
1801
1841
  mcpRemoveServer: "移除",
1802
- mcpPaste: "粘贴 JSON",
1803
- mcpPasteHint: "{ \"mcpServers\": { \"12306-mcp\": { \"command\": \"npx\", \"args\": [\"-y\", \"12306-mcp\"] } } }",
1842
+ mcpPaste: "粘贴 JSON",
1843
+ mcpPasteHint: "{ \"mcpServers\": { \"demo\": { \"command\": \"npx\", \"args\": [\"-y\", \"demo-mcp\"] } } }",
1844
+ mcpPasteEmpty: "请先粘贴一段 JSON。",
1845
+ mcpPasteInvalid: "这段 JSON 里没有可用的 mcpServers 条目。",
1804
1846
  mcpServerRow: "服务器 {index}",
1805
1847
  mcpServerName: "名称",
1806
1848
  mcpServerNameHint: "工具名里的短 id(mcp__name__…)。",
@@ -1818,9 +1860,31 @@ window.__ModuleLoader__.load({
1818
1860
  mcpCwdHint: "可选。留空使用 Host 默认。",
1819
1861
  mcpRowInvalid: "每条服务器需要名称,以及命令或 URL。",
1820
1862
  mcpToolsLabel: "个工具",
1863
+ mcpAllowConnect: "允许连接",
1864
+ mcpAllowConnectHint: "列表非空时保存会自动连接。关掉此项再保存可只保留列表、不挂载工具。",
1821
1865
  mcpStatusConnected: "已连接",
1822
1866
  mcpStatusReconnecting: "重连中",
1823
- 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: "未设置"
1824
1888
  };
1825
1889
  //#endregion
1826
1890
  //#region src/client/index.ts
@@ -1847,11 +1911,8 @@ window.__ModuleLoader__.load({
1847
1911
  }), "ui-settings-plugins: section dictionaries");
1848
1912
  const bash = new BashCardController(ctx.settingsScope.bind({ namespace: SHELL_NS }));
1849
1913
  const agentLoop = new AgentLoopCardController(ctx.settingsScope.bind({ namespace: AGENT_LOOP_NS }));
1850
- const webSearch = new WebSearchCardController(ctx.settingsScope.bind({ namespace: WEB_SEARCH_NS }), api);
1851
1914
  const mcp = new McpCardController(ctx.settingsScope.bind({ namespace: "mcp" }));
1852
- ctx.effect(() => ctx.remote.$on("credentials/updated", (ref) => {
1853
- webSearch.refreshCredential(ref);
1854
- }), "ui-settings-plugins: credential invalidations");
1915
+ const webSearch = new WebSearchCardController(ctx.settingsScope.bind({ namespace: WEB_SEARCH_NS }), api);
1855
1916
  const configurable = new ConfigurablePluginsTabController(api, () => ctx.slots.entries("settings.plugin.item"));
1856
1917
  ctx.effect(() => () => {
1857
1918
  configurable.dispose();
@@ -1862,6 +1923,9 @@ window.__ModuleLoader__.load({
1862
1923
  ctx.effect(() => ctx.on("connection/reset", () => {
1863
1924
  configurable.load();
1864
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");
1865
1929
  ctx.effect(() => ctx.slots.subscribe("settings.plugin.item", () => {
1866
1930
  configurable.refresh();
1867
1931
  }), "ui-settings-plugins: card ledger");
@@ -1921,16 +1985,10 @@ window.__ModuleLoader__.load({
1921
1985
  ctx.slots.inject("settings.plugin.item", function* () {
1922
1986
  yield ctx.slots.register({
1923
1987
  name: "settings.plugin.item",
1924
- key: SHELL_NS,
1925
- locale: NS,
1926
- inject: () => bash.inject()
1927
- }, BashCard);
1928
- yield ctx.slots.register({
1929
- name: "settings.plugin.item",
1930
- key: AGENT_LOOP_NS,
1988
+ key: "mcp",
1931
1989
  locale: NS,
1932
- inject: () => agentLoop.inject()
1933
- }, AgentLoopCard);
1990
+ inject: () => mcp.inject()
1991
+ }, McpCard);
1934
1992
  yield ctx.slots.register({
1935
1993
  name: "settings.plugin.item",
1936
1994
  key: WEB_SEARCH_NS,
@@ -1939,13 +1997,22 @@ window.__ModuleLoader__.load({
1939
1997
  }, WebSearchCard);
1940
1998
  yield ctx.slots.register({
1941
1999
  name: "settings.plugin.item",
1942
- key: "mcp",
2000
+ key: SHELL_NS,
1943
2001
  locale: NS,
1944
- inject: () => mcp.inject()
1945
- }, McpCard);
2002
+ inject: () => bash.inject()
2003
+ }, BashCard);
2004
+ yield ctx.slots.register({
2005
+ name: "settings.plugin.item",
2006
+ key: AGENT_LOOP_NS,
2007
+ locale: NS,
2008
+ inject: () => agentLoop.inject()
2009
+ }, AgentLoopCard);
1946
2010
  });
1947
2011
  }
1948
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;
1949
2016
  exports.apply = apply;
1950
2017
  exports.inject = inject;
1951
2018
  return module.exports;