@kaitranntt/ccs 7.68.1-dev.2 → 7.68.1-dev.3

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 (62) hide show
  1. package/dist/config/unified-config-loader.d.ts +8 -3
  2. package/dist/config/unified-config-loader.d.ts.map +1 -1
  3. package/dist/config/unified-config-loader.js +20 -7
  4. package/dist/config/unified-config-loader.js.map +1 -1
  5. package/dist/config/unified-config-types.d.ts +15 -2
  6. package/dist/config/unified-config-types.d.ts.map +1 -1
  7. package/dist/config/unified-config-types.js +8 -3
  8. package/dist/config/unified-config-types.js.map +1 -1
  9. package/dist/ui/assets/{accounts-DKiswDnO.js → accounts-4Wxzh1pD.js} +1 -1
  10. package/dist/ui/assets/{alert-dialog-2aL2HMgG.js → alert-dialog-DGxGdNKD.js} +1 -1
  11. package/dist/ui/assets/{api-0XFpJIwX.js → api-DDTb78NK.js} +1 -1
  12. package/dist/ui/assets/{auth-section-BGBYw5dp.js → auth-section-r5XbRAUy.js} +1 -1
  13. package/dist/ui/assets/{backups-section-DuEFBimp.js → backups-section-CfhkSFYu.js} +1 -1
  14. package/dist/ui/assets/{channels-g_MsyBQd.js → channels-CUNcGH3S.js} +1 -1
  15. package/dist/ui/assets/{checkbox-D6stHDR5.js → checkbox-Dhabke8C.js} +1 -1
  16. package/dist/ui/assets/{claude-extension-MmCl67DV.js → claude-extension-B7woSTcR.js} +1 -1
  17. package/dist/ui/assets/{cliproxy-BFYDC1Qv.js → cliproxy-0UypW7So.js} +1 -1
  18. package/dist/ui/assets/{cliproxy-ai-providers-CiFdchyE.js → cliproxy-ai-providers-n7M1sRek.js} +1 -1
  19. package/dist/ui/assets/{cliproxy-control-panel-BnRavAdV.js → cliproxy-control-panel-BfElGwOQ.js} +1 -1
  20. package/dist/ui/assets/{codex-C_NQb-b_.js → codex-CP1dPOyh.js} +1 -1
  21. package/dist/ui/assets/{confirm-dialog-Ch-M9Hbx.js → confirm-dialog-vhsQSaZ6.js} +1 -1
  22. package/dist/ui/assets/{copilot-BjBYvnCs.js → copilot-DUTtEVYH.js} +1 -1
  23. package/dist/ui/assets/{cursor-L5hSOzMq.js → cursor-ThAyj_tQ.js} +1 -1
  24. package/dist/ui/assets/{droid-Cgv8qdDe.js → droid-mrP_PnYz.js} +1 -1
  25. package/dist/ui/assets/{globalenv-section-CCOKhfQR.js → globalenv-section-Gh2BxqVn.js} +1 -1
  26. package/dist/ui/assets/{health-CcgzRrGn.js → health-TGXaQNZq.js} +1 -1
  27. package/dist/ui/assets/index-CQIjTCyk.js +1 -0
  28. package/dist/ui/assets/{index-CBkM-K11.js → index-CRAY9dRC.js} +1 -1
  29. package/dist/ui/assets/{index-Be5tzS8b.js → index-CaRCgIIp.js} +1 -1
  30. package/dist/ui/assets/{index-Dqc1e2bT.js → index-DRXqBE1w.js} +1 -1
  31. package/dist/ui/assets/{index-DpF_8BcK.js → index-DSM3luVm.js} +2 -2
  32. package/dist/ui/assets/{index-DUbpdx2e.js → index-wYHVuydD.js} +1 -1
  33. package/dist/ui/assets/{logs-DJtDYnsv.js → logs-5mpClyQ2.js} +1 -1
  34. package/dist/ui/assets/{masked-input-NRy3dgQf.js → masked-input-DhWU9sNj.js} +1 -1
  35. package/dist/ui/assets/{proxy-status-widget-D7M56E9T.js → proxy-status-widget-C1IFaC6c.js} +1 -1
  36. package/dist/ui/assets/{raw-json-settings-editor-panel-qjLoSybO.js → raw-json-settings-editor-panel-tK2P1u12.js} +1 -1
  37. package/dist/ui/assets/{searchable-select-Bf0WOPIH.js → searchable-select-CNH0YBur.js} +1 -1
  38. package/dist/ui/assets/{separator-Y87DseSV.js → separator-CJd089R0.js} +1 -1
  39. package/dist/ui/assets/{shared-Bk0tDwnM.js → shared-DxH1omaN.js} +1 -1
  40. package/dist/ui/assets/{table-BAO0vhjx.js → table-lWkyktS-.js} +1 -1
  41. package/dist/ui/assets/{updates-DLNvHqY-.js → updates-nm2PIK8k.js} +1 -1
  42. package/dist/ui/index.html +1 -1
  43. package/dist/utils/websearch/hook-env.d.ts.map +1 -1
  44. package/dist/utils/websearch/hook-env.js +19 -1
  45. package/dist/utils/websearch/hook-env.js.map +1 -1
  46. package/dist/utils/websearch/status.d.ts +1 -1
  47. package/dist/utils/websearch/status.d.ts.map +1 -1
  48. package/dist/utils/websearch/status.js +33 -12
  49. package/dist/utils/websearch/status.js.map +1 -1
  50. package/dist/utils/websearch/types.d.ts +12 -2
  51. package/dist/utils/websearch/types.d.ts.map +1 -1
  52. package/dist/utils/websearch/types.js +38 -0
  53. package/dist/utils/websearch/types.js.map +1 -1
  54. package/dist/web-server/health/websearch-checks.js +1 -1
  55. package/dist/web-server/health/websearch-checks.js.map +1 -1
  56. package/dist/web-server/routes/websearch-routes.d.ts.map +1 -1
  57. package/dist/web-server/routes/websearch-routes.js +37 -0
  58. package/dist/web-server/routes/websearch-routes.js.map +1 -1
  59. package/lib/hooks/websearch-transformer.cjs +136 -0
  60. package/lib/mcp/ccs-websearch-server.cjs +1 -1
  61. package/package.json +1 -1
  62. package/dist/ui/assets/index-B8BM0x4w.js +0 -1
@@ -28,7 +28,7 @@ export type WebSearchReadiness = 'ready' | 'needs_setup' | 'unavailable';
28
28
  /**
29
29
  * WebSearch provider identifier
30
30
  */
31
- export type WebSearchProviderId = 'exa' | 'tavily' | 'duckduckgo' | 'brave' | 'gemini' | 'grok' | 'opencode';
31
+ export type WebSearchProviderId = 'exa' | 'tavily' | 'brave' | 'searxng' | 'duckduckgo' | 'gemini' | 'grok' | 'opencode';
32
32
  /**
33
33
  * Provider execution class.
34
34
  */
@@ -80,6 +80,7 @@ export interface WebSearchProviderConfig {
80
80
  model?: string;
81
81
  timeout?: number;
82
82
  max_results?: number;
83
+ url?: string;
83
84
  }
84
85
  /**
85
86
  * WebSearch configuration from config.yaml
@@ -89,11 +90,20 @@ export interface WebSearchConfig {
89
90
  providers?: {
90
91
  exa?: WebSearchProviderConfig;
91
92
  tavily?: WebSearchProviderConfig;
92
- duckduckgo?: WebSearchProviderConfig;
93
93
  brave?: WebSearchProviderConfig;
94
+ searxng?: WebSearchProviderConfig;
95
+ duckduckgo?: WebSearchProviderConfig;
94
96
  gemini?: WebSearchProviderConfig;
95
97
  opencode?: WebSearchProviderConfig;
96
98
  grok?: WebSearchProviderConfig;
97
99
  };
98
100
  }
101
+ /**
102
+ * Normalize a SearXNG base URL so runtime code can safely append `/search`.
103
+ *
104
+ * Accepts optional subpaths (for reverse-proxy deployments), strips a trailing
105
+ * `/search` endpoint suffix, and rejects query/hash-bearing URLs because the
106
+ * runtime owns the request path and query params.
107
+ */
108
+ export declare function normalizeSearxngBaseUrl(url: string | undefined): string | null;
99
109
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/websearch/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,eAAe,CAAC;AAE5C;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B,KAAK,GACL,QAAQ,GACR,YAAY,GACZ,OAAO,GACP,QAAQ,GACR,MAAM,GACN,UAAU,CAAC;AAEf;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,YAAY,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB;IAClB,EAAE,EAAE,mBAAmB,CAAC;IACxB,4BAA4B;IAC5B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,SAAS,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,cAAc,EAAE,OAAO,CAAC;IACxB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,kBAAkB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE;QACV,GAAG,CAAC,EAAE,uBAAuB,CAAC;QAC9B,MAAM,CAAC,EAAE,uBAAuB,CAAC;QACjC,UAAU,CAAC,EAAE,uBAAuB,CAAC;QACrC,KAAK,CAAC,EAAE,uBAAuB,CAAC;QAChC,MAAM,CAAC,EAAE,uBAAuB,CAAC;QACjC,QAAQ,CAAC,EAAE,uBAAuB,CAAC;QACnC,IAAI,CAAC,EAAE,uBAAuB,CAAC;KAChC,CAAC;CACH"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/utils/websearch/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC;AAE9C;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,eAAe,CAAC;AAE5C;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAEhD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAC3B,KAAK,GACL,QAAQ,GACR,OAAO,GACP,SAAS,GACT,YAAY,GACZ,QAAQ,GACR,MAAM,GACN,UAAU,CAAC;AAEf;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,YAAY,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB;IAClB,EAAE,EAAE,mBAAmB,CAAC;IACxB,4BAA4B;IAC5B,IAAI,EAAE,qBAAqB,CAAC;IAC5B,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,8CAA8C;IAC9C,SAAS,EAAE,OAAO,CAAC;IACnB,gCAAgC;IAChC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,cAAc,EAAE,OAAO,CAAC;IACxB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,kBAAkB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE;QACV,GAAG,CAAC,EAAE,uBAAuB,CAAC;QAC9B,MAAM,CAAC,EAAE,uBAAuB,CAAC;QACjC,KAAK,CAAC,EAAE,uBAAuB,CAAC;QAChC,OAAO,CAAC,EAAE,uBAAuB,CAAC;QAClC,UAAU,CAAC,EAAE,uBAAuB,CAAC;QACrC,MAAM,CAAC,EAAE,uBAAuB,CAAC;QACjC,QAAQ,CAAC,EAAE,uBAAuB,CAAC;QACnC,IAAI,CAAC,EAAE,uBAAuB,CAAC;KAChC,CAAC;CACH;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAiC9E"}
@@ -7,4 +7,42 @@
7
7
  * @module utils/websearch/types
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.normalizeSearxngBaseUrl = void 0;
11
+ /**
12
+ * Normalize a SearXNG base URL so runtime code can safely append `/search`.
13
+ *
14
+ * Accepts optional subpaths (for reverse-proxy deployments), strips a trailing
15
+ * `/search` endpoint suffix, and rejects query/hash-bearing URLs because the
16
+ * runtime owns the request path and query params.
17
+ */
18
+ function normalizeSearxngBaseUrl(url) {
19
+ const normalized = String(url || '').trim();
20
+ if (!normalized) {
21
+ return '';
22
+ }
23
+ try {
24
+ const parsed = new URL(normalized);
25
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
26
+ return null;
27
+ }
28
+ if (parsed.username || parsed.password) {
29
+ return null;
30
+ }
31
+ if (parsed.search || parsed.hash) {
32
+ return null;
33
+ }
34
+ let pathname = parsed.pathname.replace(/\/+$/, '');
35
+ if (pathname.toLowerCase().endsWith('/search')) {
36
+ pathname = pathname.slice(0, -'/search'.length);
37
+ }
38
+ parsed.pathname = pathname || '/';
39
+ parsed.search = '';
40
+ parsed.hash = '';
41
+ return parsed.toString().replace(/\/+$/, '');
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ exports.normalizeSearxngBaseUrl = normalizeSearxngBaseUrl;
10
48
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/websearch/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/utils/websearch/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAkHH;;;;;;GAMG;AACH,SAAgB,uBAAuB,CAAC,GAAuB;IAC7D,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QACnC,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAChE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACnD,IAAI,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/C,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,CAAC,QAAQ,GAAG,QAAQ,IAAI,GAAG,CAAC;QAClC,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;QACnB,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QAEjB,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAjCD,0DAiCC"}
@@ -41,7 +41,7 @@ function checkWebSearchClis() {
41
41
  name: 'WebSearch Status',
42
42
  status: 'warning',
43
43
  message: 'No ready provider',
44
- fix: 'Enable DuckDuckGo or set EXA_API_KEY, TAVILY_API_KEY, or BRAVE_API_KEY',
44
+ fix: 'Enable DuckDuckGo, configure SearXNG URL, or set EXA_API_KEY/TAVILY_API_KEY/BRAVE_API_KEY',
45
45
  details: 'Third-party profiles need a local WebSearch backend.',
46
46
  });
47
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"websearch-checks.js","sourceRoot":"","sources":["../../../src/web-server/health/websearch-checks.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,qEAA6F;AAG7F;;GAEG;AACH,SAAgB,kBAAkB;IAChC,MAAM,SAAS,GAAG,IAAA,4CAAwB,GAAE,CAAC;IAC7C,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,aAAa,QAAQ,CAAC,EAAE,EAAE;gBAC9B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,QAAQ,CAAC,MAAM;gBACxB,OAAO,EAAE,QAAQ,CAAC,WAAW;aAC9B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,aAAa,QAAQ,CAAC,EAAE,EAAE;gBAC9B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU;gBACxD,GAAG,EAAE,QAAQ,CAAC,cAAc;gBAC5B,OAAO,EAAE,QAAQ,CAAC,WAAW;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,IAAI,CAAC,IAAA,sCAAkB,GAAE,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,mBAAmB;YACvB,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,mBAAmB;YAC5B,GAAG,EAAE,wEAAwE;YAC7E,OAAO,EAAE,sDAAsD;SAChE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAtCD,gDAsCC"}
1
+ {"version":3,"file":"websearch-checks.js","sourceRoot":"","sources":["../../../src/web-server/health/websearch-checks.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,qEAA6F;AAG7F;;GAEG;AACH,SAAgB,kBAAkB;IAChC,MAAM,SAAS,GAAG,IAAA,4CAAwB,GAAE,CAAC;IAC7C,MAAM,MAAM,GAAkB,EAAE,CAAC;IAEjC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,aAAa,QAAQ,CAAC,EAAE,EAAE;gBAC9B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,QAAQ,CAAC,MAAM;gBACxB,OAAO,EAAE,QAAQ,CAAC,WAAW;aAC9B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,aAAa,QAAQ,CAAC,EAAE,EAAE;gBAC9B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU;gBACxD,GAAG,EAAE,QAAQ,CAAC,cAAc;gBAC5B,OAAO,EAAE,QAAQ,CAAC,WAAW;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,IAAI,CAAC,IAAA,sCAAkB,GAAE,EAAE,CAAC;QAC1B,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,mBAAmB;YACvB,IAAI,EAAE,kBAAkB;YACxB,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,mBAAmB;YAC5B,GAAG,EAAE,2FAA2F;YAChG,OAAO,EAAE,sDAAsD;SAChE,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAtCD,gDAsCC"}
@@ -1 +1 @@
1
- {"version":3,"file":"websearch-routes.d.ts","sourceRoot":"","sources":["../../../src/web-server/routes/websearch-routes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAcH,QAAA,MAAM,MAAM,4CAAW,CAAC;AA+MxB,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"websearch-routes.d.ts","sourceRoot":"","sources":["../../../src/web-server/routes/websearch-routes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,QAAA,MAAM,MAAM,4CAAW,CAAC;AAkQxB,eAAe,MAAM,CAAC"}
@@ -7,12 +7,20 @@ const express_1 = require("express");
7
7
  const unified_config_loader_1 = require("../../config/unified-config-loader");
8
8
  const websearch_manager_1 = require("../../utils/websearch-manager");
9
9
  const provider_secrets_1 = require("../../utils/websearch/provider-secrets");
10
+ const types_1 = require("../../utils/websearch/types");
10
11
  const auth_middleware_1 = require("../middleware/auth-middleware");
11
12
  const router = (0, express_1.Router)();
12
13
  const WEBSEARCH_LOCAL_ACCESS_ERROR = 'WebSearch endpoints require localhost access when dashboard auth is disabled.';
14
+ const DEFAULT_WEBSEARCH_MAX_RESULTS = 5;
15
+ const MAX_WEBSEARCH_MAX_RESULTS = 10;
13
16
  function isWebSearchApiKeyProviderId(value) {
14
17
  return Object.prototype.hasOwnProperty.call(provider_secrets_1.WEBSEARCH_API_KEY_PROVIDERS, value);
15
18
  }
19
+ function clampWebSearchMaxResults(value, fallback) {
20
+ const candidate = Number.isFinite(value) ? value : fallback;
21
+ const normalized = Number.isFinite(candidate) ? candidate : DEFAULT_WEBSEARCH_MAX_RESULTS;
22
+ return Math.max(1, Math.min(MAX_WEBSEARCH_MAX_RESULTS, Math.floor(normalized)));
23
+ }
16
24
  router.use((req, res, next) => {
17
25
  if ((0, auth_middleware_1.requireLocalAccessWhenAuthDisabled)(req, res, WEBSEARCH_LOCAL_ACCESS_ERROR)) {
18
26
  next();
@@ -58,6 +66,27 @@ router.put('/', (req, res) => {
58
66
  res.status(400).json({ error: 'Invalid value for providers. Must be an object.' });
59
67
  return;
60
68
  }
69
+ if (providers?.searxng?.url !== undefined && typeof providers.searxng.url !== 'string') {
70
+ res.status(400).json({ error: 'Invalid value for providers.searxng.url. Must be a string.' });
71
+ return;
72
+ }
73
+ const normalizedSearxngUrl = providers?.searxng?.url !== undefined
74
+ ? (0, types_1.normalizeSearxngBaseUrl)(providers.searxng.url)
75
+ : undefined;
76
+ if (providers?.searxng?.url !== undefined && normalizedSearxngUrl === null) {
77
+ res.status(400).json({
78
+ error: 'Invalid value for providers.searxng.url. Must be an http(s) base URL without credentials, query, or hash.',
79
+ });
80
+ return;
81
+ }
82
+ if (providers?.searxng?.max_results !== undefined &&
83
+ (typeof providers.searxng.max_results !== 'number' ||
84
+ !Number.isFinite(providers.searxng.max_results))) {
85
+ res.status(400).json({
86
+ error: 'Invalid value for providers.searxng.max_results. Must be a number.',
87
+ });
88
+ return;
89
+ }
61
90
  if (apiKeys !== undefined &&
62
91
  (apiKeys === null || Array.isArray(apiKeys) || typeof apiKeys !== 'object')) {
63
92
  res.status(400).json({ error: 'Invalid value for apiKeys. Must be an object.' });
@@ -77,6 +106,7 @@ router.put('/', (req, res) => {
77
106
  }
78
107
  try {
79
108
  (0, unified_config_loader_1.mutateUnifiedConfig)((config) => {
109
+ const existingSearxngUrl = (0, types_1.normalizeSearxngBaseUrl)(config.websearch?.providers?.searxng?.url) ?? '';
80
110
  config.websearch = {
81
111
  enabled: enabled ?? config.websearch?.enabled ?? true,
82
112
  providers: providers
@@ -107,6 +137,13 @@ router.put('/', (req, res) => {
107
137
  config.websearch?.providers?.brave?.max_results ??
108
138
  5,
109
139
  },
140
+ searxng: {
141
+ enabled: providers.searxng?.enabled ??
142
+ config.websearch?.providers?.searxng?.enabled ??
143
+ false,
144
+ url: normalizedSearxngUrl ?? existingSearxngUrl,
145
+ max_results: clampWebSearchMaxResults(providers.searxng?.max_results, config.websearch?.providers?.searxng?.max_results ?? DEFAULT_WEBSEARCH_MAX_RESULTS),
146
+ },
110
147
  gemini: {
111
148
  enabled: providers.gemini?.enabled ??
112
149
  config.websearch?.providers?.gemini?.enabled ??
@@ -1 +1 @@
1
- {"version":3,"file":"websearch-routes.js","sourceRoot":"","sources":["../../../src/web-server/routes/websearch-routes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websearch-routes.js","sourceRoot":"","sources":["../../../src/web-server/routes/websearch-routes.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@
6
6
  * - Exa Search API
7
7
  * - Tavily Search API
8
8
  * - Brave Search API
9
+ * - SearXNG JSON API
9
10
  * - DuckDuckGo HTML search
10
11
  *
11
12
  * Legacy compatibility fallback:
@@ -369,6 +370,36 @@ function getResultCount(provider) {
369
370
  return Number.isFinite(parsed) && parsed > 0 ? Math.min(parsed, 10) : DEFAULT_RESULT_COUNT;
370
371
  }
371
372
 
373
+ function getSearxngBaseUrl() {
374
+ const raw = (process.env.CCS_WEBSEARCH_SEARXNG_URL || '').trim();
375
+ if (!raw) {
376
+ return '';
377
+ }
378
+
379
+ try {
380
+ const parsed = new URL(raw);
381
+ if (!['http:', 'https:'].includes(parsed.protocol) || parsed.search || parsed.hash) {
382
+ return '';
383
+ }
384
+
385
+ if (parsed.username || parsed.password) {
386
+ return '';
387
+ }
388
+
389
+ let pathname = parsed.pathname.replace(/\/+$/, '');
390
+ if (pathname.toLowerCase().endsWith('/search')) {
391
+ pathname = pathname.slice(0, -'/search'.length);
392
+ }
393
+
394
+ parsed.pathname = pathname || '/';
395
+ parsed.search = '';
396
+ parsed.hash = '';
397
+ return parsed.toString().replace(/\/+$/, '');
398
+ } catch {
399
+ return '';
400
+ }
401
+ }
402
+
372
403
  function buildPrompt(providerId, query) {
373
404
  const config = PROVIDER_CONFIG[providerId];
374
405
  const parts = [
@@ -569,6 +600,104 @@ async function tryBraveSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) {
569
600
  }
570
601
  }
571
602
 
603
+ async function trySearxngSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) {
604
+ const baseUrl = getSearxngBaseUrl();
605
+ if (!baseUrl) {
606
+ return { success: false, error: 'SearXNG URL is invalid or not configured' };
607
+ }
608
+
609
+ const params = new URLSearchParams({
610
+ q: query,
611
+ format: 'json',
612
+ });
613
+
614
+ try {
615
+ const response = await fetchWithTimeout(
616
+ `${baseUrl}/search?${params.toString()}`,
617
+ {
618
+ headers: {
619
+ Accept: 'application/json',
620
+ 'User-Agent': USER_AGENT,
621
+ },
622
+ },
623
+ timeoutSec * 1000
624
+ );
625
+
626
+ if (!response.ok) {
627
+ const body = await response.text();
628
+ if (
629
+ response.status === 403 &&
630
+ /format(?:=|\s*)json|json[^\n]{0,40}disabled|disabled[^\n]{0,40}json/i.test(body)
631
+ ) {
632
+ return {
633
+ success: false,
634
+ error: 'SearXNG returned 403: format=json is disabled on this instance',
635
+ statusCode: response.status,
636
+ retryAfterSec: parseRetryAfterSeconds(readHeaderValue(response.headers, 'retry-after')),
637
+ };
638
+ }
639
+
640
+ return {
641
+ success: false,
642
+ error: `SearXNG returned ${response.status}: ${body.slice(0, 160)}`,
643
+ statusCode: response.status,
644
+ retryAfterSec: parseRetryAfterSeconds(readHeaderValue(response.headers, 'retry-after')),
645
+ };
646
+ }
647
+
648
+ let body;
649
+ try {
650
+ body = await response.json();
651
+ } catch {
652
+ return {
653
+ success: false,
654
+ error: 'SearXNG returned malformed JSON payload',
655
+ };
656
+ }
657
+
658
+ if (!body || typeof body !== 'object' || !Array.isArray(body.results)) {
659
+ return {
660
+ success: false,
661
+ error: 'SearXNG JSON response is missing results[]',
662
+ };
663
+ }
664
+
665
+ const count = getResultCount('searxng');
666
+ const results = body.results.slice(0, count).map((entry) => {
667
+ const result = entry && typeof entry === 'object' ? entry : {};
668
+ const url = typeof result.url === 'string' ? result.url : '';
669
+ const titleSource =
670
+ typeof result.title === 'string' && result.title.trim().length > 0
671
+ ? result.title
672
+ : url || 'Untitled';
673
+ const descriptionSource =
674
+ typeof result.content === 'string'
675
+ ? result.content
676
+ : typeof result.description === 'string'
677
+ ? result.description
678
+ : typeof result.snippet === 'string'
679
+ ? result.snippet
680
+ : '';
681
+
682
+ return {
683
+ title: compactText(titleSource, 120),
684
+ url,
685
+ description: compactText(descriptionSource, 240),
686
+ };
687
+ });
688
+
689
+ return {
690
+ success: true,
691
+ content: formatStructuredSearchResults(query, 'SearXNG', results),
692
+ };
693
+ } catch (error) {
694
+ return {
695
+ success: false,
696
+ error: error.name === 'AbortError' ? 'SearXNG timed out' : error.message,
697
+ };
698
+ }
699
+ }
700
+
572
701
  async function tryExaSearch(query, timeoutSec = DEFAULT_TIMEOUT_SEC) {
573
702
  const apiKey = getProviderApiKey('exa');
574
703
  if (!apiKey) {
@@ -892,6 +1021,12 @@ function getConfiguredProviders() {
892
1021
  available: () => isProviderEnabled('brave') && Boolean(getProviderApiKey('brave')),
893
1022
  fn: tryBraveSearch,
894
1023
  },
1024
+ {
1025
+ name: 'SearXNG',
1026
+ id: 'searxng',
1027
+ available: () => isProviderEnabled('searxng') && Boolean(getSearxngBaseUrl()),
1028
+ fn: trySearxngSearch,
1029
+ },
895
1030
  {
896
1031
  name: 'DuckDuckGo',
897
1032
  id: 'duckduckgo',
@@ -1280,4 +1415,5 @@ module.exports = {
1280
1415
  tryTavilySearch,
1281
1416
  tryDuckDuckGoSearch,
1282
1417
  tryBraveSearch,
1418
+ trySearxngSearch,
1283
1419
  };
@@ -16,7 +16,7 @@ const SERVER_VERSION = '1.0.0';
16
16
  const TOOL_NAME = 'WebSearch';
17
17
  const TOOL_ALIASES = ['search'];
18
18
  const TOOL_DESCRIPTION =
19
- 'Third-party WebSearch replacement for CCS-managed Claude launches. Use this instead of Bash/curl/http fetches for web lookups. Provider order: Exa, Tavily, Brave Search, DuckDuckGo, then optional legacy CLI fallback.';
19
+ 'Third-party WebSearch replacement for CCS-managed Claude launches. Use this instead of Bash/curl/http fetches for web lookups. Provider order: Exa, Tavily, Brave Search, SearXNG, DuckDuckGo, then optional legacy CLI fallback.';
20
20
 
21
21
  function isSupportedToolName(name) {
22
22
  return name === TOOL_NAME || TOOL_ALIASES.includes(name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaitranntt/ccs",
3
- "version": "7.68.1-dev.2",
3
+ "version": "7.68.1-dev.3",
4
4
  "description": "Claude Code Switch - Instant profile switching between Claude, GLM, Kimi, and more",
5
5
  "keywords": [
6
6
  "cli",
@@ -1 +0,0 @@
1
- import{j as e}from"./radix-ui-Zb8sVEtn.js";import{r as y}from"./react-vendor-CNOkPC89.js";import{bt as te,bu as se,c as u,aF as re,L as ne,I as le,a as de,bv as ie,be as oe,bg as ce,n as be,d as D}from"./index-DpF_8BcK.js";import{M as ue}from"./masked-input-NRy3dgQf.js";import{p as me,R as V,w as ge,x as xe,u as M,n as fe,t as he,s as pe}from"./icons-KVCk4_U8.js";import"./tanstack-CrmUhA7Z.js";import"./notifications-B2HqRBj7.js";import"./utils-CzKF5WmX.js";import"./form-utils-Bcoyqxpq.js";import"./code-highlight-BRUf_pqB.js";function ye(){const{state:s}=te(),t=se(),x=y.useCallback(async()=>{try{t.setWebSearchLoading(!0),t.setWebSearchError(null);const d=await fetch("/api/websearch");if(!d.ok)throw new Error("Failed to load WebSearch config");const b=await d.json();t.setWebSearchConfig(b)}catch(d){t.setWebSearchError(d.message)}finally{t.setWebSearchLoading(!1)}},[t]),i=y.useCallback(async()=>{try{t.setWebSearchStatusLoading(!0);const d=await fetch("/api/websearch/status");if(!d.ok)throw new Error("Failed to load status");const b=await d.json();t.setWebSearchStatus(b)}catch{}finally{t.setWebSearchStatusLoading(!1)}},[t]),k=y.useCallback(async d=>{const b=s.webSearchConfig;if(!b)return!1;const m={...b,...d,providers:{...b.providers,...d.providers},apiKeys:b.apiKeys};t.setWebSearchConfig(m);try{t.setWebSearchSaving(!0),t.setWebSearchError(null);const f={enabled:m.enabled,providers:m.providers};d.apiKeys&&(f.apiKeys=d.apiKeys);const h=await fetch("/api/websearch",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)});if(!h.ok){const g=await h.json();throw new Error(g.error||"Failed to save")}const v=await h.json();return t.setWebSearchConfig(v.websearch),await i(),t.setWebSearchSuccess(!0),setTimeout(()=>t.setWebSearchSuccess(!1),1500),!0}catch(f){return t.setWebSearchConfig(b),t.setWebSearchError(f.message),!1}finally{t.setWebSearchSaving(!1)}},[s.webSearchConfig,t,i]);return{config:s.webSearchConfig,status:s.webSearchStatus,loading:s.webSearchLoading,statusLoading:s.webSearchStatusLoading,saving:s.webSearchSaving,error:s.webSearchError,success:s.webSearchSuccess,fetchConfig:x,fetchStatus:i,saveConfig:k}}const ke={green:{accent:"from-emerald-500 via-lime-400 to-transparent",badge:"border-emerald-500/25 bg-emerald-500/10 text-emerald-800 dark:text-emerald-200",glow:"bg-emerald-500/18 dark:bg-emerald-500/22",surface:"border-emerald-500/30 bg-gradient-to-br from-emerald-500/10 via-background to-background dark:from-emerald-500/14",switchFrame:"border-emerald-500/20 bg-emerald-500/10"},blue:{accent:"from-sky-500 via-blue-500 to-transparent",badge:"border-sky-500/25 bg-sky-500/10 text-sky-800 dark:text-sky-200",glow:"bg-sky-500/18 dark:bg-sky-500/22",surface:"border-sky-500/30 bg-gradient-to-br from-sky-500/10 via-background to-background dark:from-sky-500/14",switchFrame:"border-sky-500/20 bg-sky-500/10"},amber:{accent:"from-amber-500 via-orange-500 to-transparent",badge:"border-amber-500/25 bg-amber-500/10 text-amber-800 dark:text-amber-200",glow:"bg-amber-500/18 dark:bg-amber-500/22",surface:"border-amber-500/30 bg-gradient-to-br from-amber-500/10 via-background to-background dark:from-amber-500/14",switchFrame:"border-amber-500/20 bg-amber-500/10"},cyan:{accent:"from-cyan-500 via-teal-400 to-transparent",badge:"border-cyan-500/25 bg-cyan-500/10 text-cyan-800 dark:text-cyan-200",glow:"bg-cyan-500/18 dark:bg-cyan-500/22",surface:"border-cyan-500/30 bg-gradient-to-br from-cyan-500/10 via-background to-background dark:from-cyan-500/14",switchFrame:"border-cyan-500/20 bg-cyan-500/10"},slate:{accent:"from-slate-500 via-slate-400 to-transparent",badge:"border-slate-500/20 bg-slate-500/10 text-slate-700 dark:text-slate-300",glow:"bg-slate-500/18 dark:bg-slate-500/22",surface:"border-slate-400/30 bg-gradient-to-br from-slate-500/8 via-background to-background dark:from-slate-500/12",switchFrame:"border-slate-400/20 bg-slate-500/10"}};function ve(s){switch(s){case"ready":return{chip:"border-emerald-500/25 bg-emerald-500/10 text-emerald-800 dark:text-emerald-200",dot:"bg-emerald-500"};case"setup":return{chip:"border-amber-500/25 bg-amber-500/10 text-amber-800 dark:text-amber-200",dot:"bg-amber-500"};case"idle":return{chip:"border-border/80 bg-muted/60 text-muted-foreground",dot:"bg-muted-foreground/70"}}}function Y({title:s,description:t,detail:x,badge:i,badgeTone:k,statusLabel:d,statusTone:b,enabled:m,saving:f,onToggle:h,fields:v=[],docsUrl:g,installCommand:N,footerNote:S,children:C}){const j=ke[k],L=ve(b);return e.jsxs("div",{className:u("group relative overflow-hidden rounded-2xl border px-4 py-4 shadow-sm transition-all duration-200",m?j.surface:"border-border/70 bg-gradient-to-br from-background via-background to-muted/25",m&&"shadow-[0_18px_40px_-28px_rgba(15,23,42,0.55)]"),children:[e.jsx("div",{className:u("absolute inset-x-0 top-0 h-px bg-gradient-to-r",j.accent)}),e.jsx("div",{className:u("pointer-events-none absolute -right-6 -top-8 h-28 w-28 rounded-full blur-3xl",j.glow)}),e.jsx("div",{className:"pointer-events-none absolute inset-0 opacity-[0.045]",style:{backgroundImage:"radial-gradient(circle at 1px 1px, currentColor 1px, transparent 0)",backgroundSize:"22px 22px"}}),e.jsxs("div",{className:"relative flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"min-w-0 space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2.5",children:[e.jsx("p",{className:"text-sm font-semibold tracking-tight",children:s}),e.jsx("span",{className:u("rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.18em]",j.badge),children:i}),e.jsxs("span",{className:u("inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-[10px] font-medium",L.chip),children:[e.jsx("span",{className:u("h-1.5 w-1.5 rounded-full",L.dot)}),d]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx("p",{className:"text-sm leading-6 text-foreground/90",children:t}),x&&e.jsx("p",{className:"text-xs leading-5 text-muted-foreground",children:x})]})]}),e.jsx("div",{className:u("flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border bg-background/75 backdrop-blur-sm",m?j.switchFrame:"border-border/70"),children:e.jsx(re,{checked:m,onCheckedChange:h,disabled:f})})]}),m&&v.length>0&&e.jsx("div",{className:"relative mt-4 rounded-xl border border-border/65 bg-background/70 p-3 shadow-[inset_0_1px_0_rgba(255,255,255,0.35)] backdrop-blur-sm",children:e.jsx("div",{className:"grid gap-3 md:grid-cols-2",children:v.map(o=>e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx(ne,{htmlFor:o.id,className:"text-[11px] font-medium text-muted-foreground",children:o.label}),o.saved&&e.jsx("span",{className:"text-[11px] font-medium text-emerald-600 dark:text-emerald-400",children:"Saved"})]}),e.jsx(le,{id:o.id,value:o.value,type:o.type??"text",placeholder:o.placeholder,onBlur:o.onBlur,onChange:P=>o.onChange(P.target.value),onKeyDown:o.onKeyDown,className:"h-8 border-border/70 bg-background/80 text-sm",disabled:f}),o.helpText&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:o.helpText})]},o.id))})}),m&&C&&e.jsx("div",{className:"relative mt-4 rounded-xl border border-border/65 bg-background/70 p-3 shadow-[inset_0_1px_0_rgba(255,255,255,0.35)] backdrop-blur-sm",children:C}),(S||N||g)&&e.jsxs("div",{className:"relative mt-4 space-y-2 rounded-xl border border-border/65 bg-muted/30 p-3",children:[S&&e.jsx("p",{className:"text-xs text-muted-foreground",children:S}),N&&e.jsx("code",{className:"block rounded-lg border border-border/60 bg-background/85 px-2.5 py-2 text-[11px] text-muted-foreground",children:N}),g&&e.jsxs("a",{href:g,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline",children:[e.jsx(me,{className:"h-3 w-3"}),"View docs"]})]})]})}const B=[{id:"exa",title:"Exa",defaultEnabled:!1},{id:"tavily",title:"Tavily",defaultEnabled:!1},{id:"brave",title:"Brave",defaultEnabled:!1},{id:"duckduckgo",title:"DuckDuckGo",defaultEnabled:!0},{id:"legacy",title:"Legacy CLI",defaultEnabled:!1}],z=[{id:"exa",title:"Exa",description:"Highest-priority API backend when enabled. Best for strong relevance and extracted text.",badge:"EXA_API_KEY",badgeTone:"amber",defaultEnabled:!1,fallbackDetail:"Set EXA_API_KEY",footerNote:"Runs before every other provider in the chain when enabled and ready.",fields:[{key:"max_results",label:"Max results",type:"number",placeholder:"5",helpText:"Clamp between 1 and 10 results.",defaultValue:5,min:1,max:10}]},{id:"tavily",title:"Tavily",description:"Agent-oriented API backend with concise web result content.",badge:"TAVILY_API_KEY",badgeTone:"cyan",defaultEnabled:!1,fallbackDetail:"Set TAVILY_API_KEY",footerNote:"Runs after Exa and before Brave when enabled and ready.",fields:[{key:"max_results",label:"Max results",type:"number",placeholder:"5",helpText:"Clamp between 1 and 10 results.",defaultValue:5,min:1,max:10}]},{id:"brave",title:"Brave Search",description:"API-backed search with clean metadata and broad web coverage.",badge:"BRAVE_API_KEY",badgeTone:"blue",defaultEnabled:!1,fallbackDetail:"Set BRAVE_API_KEY",footerNote:"Runs after Exa and Tavily, before DuckDuckGo.",fields:[{key:"max_results",label:"Max results",type:"number",placeholder:"5",helpText:"Clamp between 1 and 10 results.",defaultValue:5,min:1,max:10}]},{id:"duckduckgo",title:"DuckDuckGo",description:"Zero-setup floor. Keep this on unless you want no built-in fallback at all.",badge:"DEFAULT",badgeTone:"green",defaultEnabled:!0,fallbackDetail:"Built-in",footerNote:"Last real backend in the chain. No API key needed.",fields:[{key:"max_results",label:"Max results",type:"number",placeholder:"5",helpText:"Clamp between 1 and 10 results.",defaultValue:5,min:1,max:10}]}],I=[{id:"gemini",title:"Gemini CLI",description:"Optional legacy LLM fallback. Used only if every enabled real backend fails.",badge:"LEGACY",badgeTone:"slate",defaultEnabled:!1,fallbackDetail:"Optional fallback",footerNote:"Legacy path. Useful for compatibility, not the preferred search backend.",fields:[{key:"model",label:"Model",type:"text",placeholder:"gemini-2.5-flash",helpText:"CLI model passed to Gemini when this fallback runs.",defaultValue:"gemini-2.5-flash"},{key:"timeout",label:"Timeout (seconds)",type:"number",placeholder:"55",helpText:"Clamp between 5 and 300 seconds.",defaultValue:55,min:5,max:300}]},{id:"opencode",title:"OpenCode",description:"Optional legacy LLM fallback via OpenCode.",badge:"LEGACY",badgeTone:"slate",defaultEnabled:!1,fallbackDetail:"Optional fallback",footerNote:"Legacy path. Runs after Gemini in the fallback portion of the chain.",fields:[{key:"model",label:"Model",type:"text",placeholder:"opencode/grok-code",helpText:"OpenCode model passed to the CLI runner.",defaultValue:"opencode/grok-code"},{key:"timeout",label:"Timeout (seconds)",type:"number",placeholder:"90",helpText:"Clamp between 5 and 300 seconds.",defaultValue:90,min:5,max:300}]},{id:"grok",title:"Grok CLI",description:"Optional legacy xAI fallback. Requires the Grok CLI and GROK_API_KEY.",badge:"LEGACY",badgeTone:"slate",defaultEnabled:!1,fallbackDetail:"Optional fallback",footerNote:"Last step in the full fallback chain.",fields:[{key:"timeout",label:"Timeout (seconds)",type:"number",placeholder:"55",helpText:"Clamp between 5 and 300 seconds.",defaultValue:55,min:5,max:300}]}];function _(s,t){return t&&s?.available?"ready":t?"setup":"idle"}function R(s,t){return t&&s?.available?"Ready":t?"Needs setup":"Disabled"}function je(s){switch(s){case"ready":return"border-emerald-500/25 bg-emerald-500/10 text-emerald-800 dark:text-emerald-200";case"setup":return"border-amber-500/25 bg-amber-500/10 text-amber-800 dark:text-amber-200";case"idle":return"border-border/80 bg-background/85 text-muted-foreground"}}function we(s){switch(s){case"ready":return"bg-emerald-500";case"setup":return"bg-amber-500";case"idle":return"bg-border"}}function U(s){switch(s){case"ready":return"bg-emerald-500 shadow-[0_0_0_6px_rgba(16,185,129,0.12)]";case"setup":return"bg-amber-500 shadow-[0_0_0_6px_rgba(245,158,11,0.12)]";case"idle":return"bg-border"}}function q(s){switch(s){case"ready":return"bg-gradient-to-b from-emerald-500/55 to-border";case"setup":return"bg-gradient-to-b from-amber-500/55 to-border";case"idle":return"bg-border"}}function Ne(s,t){if(s.type==="number"){const i=Number.parseInt(t.trim(),10);if(!Number.isFinite(i))return s.defaultValue;const k=s.min??i,d=s.max??i;return Math.min(d,Math.max(k,i))}return t.trim()||String(s.defaultValue)}function H(s,t,x){const i=s?.[t]?.[x.key];return String(i??x.defaultValue)}function Se(s){return s==="exa"||s==="tavily"||s==="brave"}function Ce(s){if(!s?.configured)return"Not stored";if(!s.available&&s.source==="global_env")return"Stored in dashboard, but Global Env is disabled";switch(s.source){case"global_env":return"Stored in dashboard";case"process_env":return"Detected from shell env";case"both":return"Stored in dashboard + shell env";case"none":return"Not stored"}}function Re(){const{t:s}=de(),{config:t,status:x,loading:i,statusLoading:k,saving:d,error:b,success:m,fetchConfig:f,fetchStatus:h,saveConfig:v}=ye(),{fetchRawConfig:g}=ie(),[N,S]=y.useState({}),[C,j]=y.useState({}),[L,o]=y.useState(null),[P,A]=y.useState(null),[W,X]=y.useState(!1);y.useEffect(()=>{f(),h(),g()},[f,h,g]);const E=y.useMemo(()=>new Map((x?.providers??[]).map(a=>[a.id,a])),[x?.providers]),w=I.filter(a=>t?.providers?.[a.id]?.enabled??a.defaultEnabled),J=w.some(a=>E.get(a.id)?.available),F=w.length===0?"Off":w.length===1?`${w[0].title} enabled`:`${w.length} enabled`,O=async(a,l)=>{const r=t?.providers??{};await v({providers:{...r,[a]:{...r[a],enabled:!l}}})&&await g()},Z=(a,l,r)=>{S(n=>({...n,[`${a}.${l}`]:r}))},Q=async(a,l)=>{if(!t)return;const r=`${a}.${l.key}`,n=t.providers??{},p=n[a]??{},c=p[l.key]??l.defaultValue,T=Ne(l,N[r]??H(n,a,l));if(S(K=>({...K,[r]:String(T)})),String(c)===String(T))return;await v({providers:{...n,[a]:{...p,[l.key]:T}}})&&(await g(),o(r),setTimeout(()=>{o(K=>K===r?null:K)},1200))},ee=async a=>{const l=C[a]?.trim()??"";if(!l)return;await v({apiKeys:{[a]:l}})&&(await g(),j(n=>({...n,[a]:""})),A(a),setTimeout(()=>{A(n=>n===a?null:n)},1200))},ae=async a=>{await v({apiKeys:{[a]:""}})&&(await g(),j(r=>({...r,[a]:""})),A(a),setTimeout(()=>{A(r=>r===a?null:r)},1200))},$=a=>(a.fields??[]).map(l=>{const r=`${a.id}.${l.key}`;return{id:r,label:l.label,value:N[r]??H(t?.providers??{},a.id,l),placeholder:l.placeholder,type:l.type,helpText:l.helpText,saved:L===r,onChange:n=>Z(a.id,l.key,n),onBlur:()=>{Q(a.id,l)},onKeyDown:n=>{n.key==="Enter"&&n.currentTarget.blur()}}});return i?e.jsx("div",{className:"flex flex-1 items-center justify-center",children:e.jsxs("div",{className:"flex items-center gap-3 text-muted-foreground",children:[e.jsx(V,{className:"h-5 w-5 animate-spin"}),e.jsx("span",{children:s("settings.loading")})]})}):e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:`absolute left-5 right-5 top-20 z-10 transition-all duration-200 ease-out ${b||m?"translate-y-0 opacity-100":"pointer-events-none -translate-y-2 opacity-0"}`,children:[b&&e.jsxs(oe,{variant:"destructive",className:"py-2 shadow-lg",children:[e.jsx(ge,{className:"h-4 w-4"}),e.jsx(ce,{children:b})]}),m&&e.jsxs("div",{className:"flex items-center gap-2 rounded-md border border-green-200 bg-green-50 px-3 py-2 text-green-700 shadow-lg dark:border-green-900/50 dark:bg-green-900/90 dark:text-green-300",children:[e.jsx(xe,{className:"h-4 w-4 shrink-0"}),e.jsx("span",{className:"text-sm font-medium",children:s("settings.saved")})]})]}),e.jsx(be,{className:"flex-1",children:e.jsxs("div",{className:"space-y-6 p-5",children:[e.jsxs("div",{className:"relative overflow-hidden rounded-2xl border bg-gradient-to-br from-background via-background to-muted/30 p-4 shadow-sm",children:[e.jsx("div",{className:"absolute inset-x-0 top-0 h-px bg-gradient-to-r from-primary/70 via-primary/20 to-transparent"}),e.jsx("div",{className:"pointer-events-none absolute inset-0 opacity-[0.035]",style:{backgroundImage:"repeating-linear-gradient(0deg, transparent, transparent 2px, currentColor 2px, currentColor 3px)"}}),e.jsxs("div",{className:"relative",children:[e.jsxs("div",{className:"mb-3 flex items-center justify-between gap-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"inline-flex h-8 w-8 items-center justify-center rounded-xl border border-primary/20 bg-primary/8 text-primary",children:e.jsx(M,{className:"h-4 w-4"})}),e.jsx("p",{className:"text-sm font-semibold tracking-tight",children:"Execution chain"})]}),e.jsx("p",{className:"text-sm text-muted-foreground",children:k?s("settingsWebsearch.checking"):x?.readiness.message})]}),e.jsx(D,{variant:"ghost",size:"sm",onClick:h,disabled:k,children:e.jsx(V,{className:`h-4 w-4 ${k?"animate-spin":""}`})})]}),e.jsx("div",{className:"flex flex-wrap items-center gap-2",children:B.map((a,l)=>{const r=a.id==="legacy"?w.length>0:t?.providers?.[a.id]?.enabled??a.defaultEnabled,n=a.id==="legacy"?J?"ready":w.length>0?"setup":"idle":_(E.get(a.id),r),p=a.id==="legacy"?F:R(E.get(a.id),r);return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("div",{className:u("inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-[11px] font-medium",je(n)),children:[e.jsx("span",{className:u("h-1.5 w-1.5 rounded-full",we(n))}),e.jsxs("span",{children:[a.title," · ",p]})]}),l<B.length-1&&e.jsx("span",{className:"h-px w-4 rounded-full bg-border/80"})]},a.id)})})]})]}),e.jsxs("div",{className:"relative overflow-hidden rounded-2xl border bg-gradient-to-br from-background via-background to-muted/25 p-4 shadow-sm",children:[e.jsx("div",{className:"absolute inset-x-0 top-0 h-px bg-gradient-to-r from-sky-500/70 via-emerald-500/25 to-transparent"}),e.jsxs("div",{className:"relative space-y-4",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border border-sky-500/20 bg-sky-500/10 text-sky-700 dark:text-sky-300",children:e.jsx(M,{className:"h-4 w-4"})}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-base font-semibold tracking-tight",children:"Primary backends"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Real backends run top-down before any legacy CLI fallback."})]})]}),e.jsx("div",{className:"space-y-3",children:z.map((a,l)=>{const r=E.get(a.id),n=t?.providers?.[a.id]?.enabled??a.defaultEnabled,p=_(r,n),c=Se(a.id)?a.id:null;return e.jsxs("div",{className:"grid grid-cols-[20px_minmax(0,1fr)] items-start gap-3",children:[e.jsx("div",{className:"flex h-full justify-center",children:e.jsxs("div",{className:"flex h-full flex-col items-center",children:[e.jsx("span",{className:u("mt-5 h-3 w-3 rounded-full ring-4 ring-background",U(p))}),l<z.length-1&&e.jsx("span",{className:u("mt-1 w-px flex-1",q(p))})]})}),e.jsx(Y,{title:a.title,description:a.description,detail:r?.detail??a.fallbackDetail,badge:a.badge,badgeTone:a.badgeTone,statusLabel:R(r,n),statusTone:_(r,n),enabled:n,saving:d,onToggle:()=>{O(a.id,n)},fields:$(a),children:c&&e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground",children:"API Key"}),e.jsx("p",{className:"mt-1 text-sm text-foreground/90",children:Ce(t?.apiKeys?.[c])}),e.jsx("p",{className:"mt-1 text-xs text-muted-foreground",children:t?.apiKeys?.[c]?.maskedValue?`${t.apiKeys[c]?.envVar} ${t.apiKeys[c]?.maskedValue}`:`Store ${a.badge} here so the backend is ready immediately after you enable it.`})]}),P===a.id&&e.jsx("span",{className:"text-[11px] font-medium text-emerald-600 dark:text-emerald-400",children:"Saved"})]}),e.jsx(ue,{id:`${a.id}.api-key`,value:C[c]??"",onChange:T=>j(G=>({...G,[c]:T.target.value})),placeholder:t?.apiKeys?.[c]?.configured?"Enter a new key to rotate the stored secret":`Paste ${a.badge}`,className:"bg-background/80 font-mono text-sm",disabled:d}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(D,{size:"sm",onClick:()=>{ee(c)},disabled:d||!(C[c]?.trim()??"").length,children:t?.apiKeys?.[c]?.configured?"Update key":"Save key"}),(t?.apiKeys?.[c]?.source==="global_env"||t?.apiKeys?.[c]?.source==="both")&&e.jsx(D,{variant:"outline",size:"sm",onClick:()=>{ae(c)},disabled:d,children:"Remove stored key"})]})]})})]},a.id)})})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("button",{type:"button",onClick:()=>X(a=>!a),className:u("flex w-full items-center justify-between gap-3 rounded-xl px-1 py-1 text-left transition-colors","hover:bg-muted/10"),children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border border-slate-400/20 bg-slate-500/10 text-slate-700 dark:text-slate-300",children:e.jsx(fe,{className:"h-4 w-4"})}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-base font-semibold tracking-tight",children:"Legacy CLI fallbacks"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Runs only after every enabled real backend fails."})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"rounded-full border border-border/80 bg-background/85 px-2.5 py-1 text-[11px] font-medium text-muted-foreground",children:F}),W?e.jsx(he,{className:"h-4 w-4 text-muted-foreground"}):e.jsx(pe,{className:"h-4 w-4 text-muted-foreground"})]})]}),W&&e.jsxs("div",{className:"relative overflow-hidden rounded-2xl border bg-gradient-to-br from-background via-background to-muted/20 p-3 shadow-sm",children:[e.jsx("div",{className:"absolute inset-x-0 top-0 h-px bg-gradient-to-r from-slate-500/60 via-slate-400/18 to-transparent"}),e.jsx("div",{className:"relative space-y-3",children:I.map((a,l)=>{const r=E.get(a.id),n=t?.providers?.[a.id]?.enabled??a.defaultEnabled,p=_(r,n);return e.jsxs("div",{className:"grid grid-cols-[20px_minmax(0,1fr)] items-start gap-3",children:[e.jsx("div",{className:"flex h-full justify-center",children:e.jsxs("div",{className:"flex h-full flex-col items-center",children:[e.jsx("span",{className:u("mt-5 h-3 w-3 rounded-full ring-4 ring-background",U(p))}),l<I.length-1&&e.jsx("span",{className:u("mt-1 w-px flex-1",q(p))})]})}),e.jsx(Y,{title:a.title,description:a.description,detail:r?.detail??a.fallbackDetail,badge:a.badge,badgeTone:a.badgeTone,statusLabel:R(r,n),statusTone:_(r,n),enabled:n,saving:d,onToggle:()=>{O(a.id,n)},fields:$(a),docsUrl:r?.docsUrl,installCommand:r?.installCommand,footerNote:a.footerNote})]},a.id)})})]})]})]})}),e.jsx("div",{className:"border-t bg-background p-4",children:e.jsxs(D,{variant:"outline",size:"sm",onClick:()=>{f(),h(),g()},disabled:i||d,className:"w-full",children:[e.jsx(V,{className:`mr-2 h-4 w-4 ${i?"animate-spin":""}`}),s("settings.refresh")]})})]})}export{Re as default};