@kaitranntt/ccs 7.68.1-dev.2 → 7.68.1-dev.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.
- package/dist/commands/cliproxy/catalog-subcommand.d.ts +6 -0
- package/dist/commands/cliproxy/catalog-subcommand.d.ts.map +1 -1
- package/dist/commands/cliproxy/catalog-subcommand.js +39 -1
- package/dist/commands/cliproxy/catalog-subcommand.js.map +1 -1
- package/dist/commands/cliproxy/help-subcommand.d.ts.map +1 -1
- package/dist/commands/cliproxy/help-subcommand.js +1 -0
- package/dist/commands/cliproxy/help-subcommand.js.map +1 -1
- package/dist/commands/cliproxy/index.d.ts.map +1 -1
- package/dist/commands/cliproxy/index.js +6 -0
- package/dist/commands/cliproxy/index.js.map +1 -1
- package/dist/config/unified-config-loader.d.ts +8 -3
- package/dist/config/unified-config-loader.d.ts.map +1 -1
- package/dist/config/unified-config-loader.js +20 -7
- package/dist/config/unified-config-loader.js.map +1 -1
- package/dist/config/unified-config-types.d.ts +15 -2
- package/dist/config/unified-config-types.d.ts.map +1 -1
- package/dist/config/unified-config-types.js +8 -3
- package/dist/config/unified-config-types.js.map +1 -1
- package/dist/ui/assets/{accounts-DKiswDnO.js → accounts-4Wxzh1pD.js} +1 -1
- package/dist/ui/assets/{alert-dialog-2aL2HMgG.js → alert-dialog-DGxGdNKD.js} +1 -1
- package/dist/ui/assets/{api-0XFpJIwX.js → api-DDTb78NK.js} +1 -1
- package/dist/ui/assets/{auth-section-BGBYw5dp.js → auth-section-r5XbRAUy.js} +1 -1
- package/dist/ui/assets/{backups-section-DuEFBimp.js → backups-section-CfhkSFYu.js} +1 -1
- package/dist/ui/assets/{channels-g_MsyBQd.js → channels-CUNcGH3S.js} +1 -1
- package/dist/ui/assets/{checkbox-D6stHDR5.js → checkbox-Dhabke8C.js} +1 -1
- package/dist/ui/assets/{claude-extension-MmCl67DV.js → claude-extension-B7woSTcR.js} +1 -1
- package/dist/ui/assets/{cliproxy-BFYDC1Qv.js → cliproxy-0UypW7So.js} +1 -1
- package/dist/ui/assets/{cliproxy-ai-providers-CiFdchyE.js → cliproxy-ai-providers-n7M1sRek.js} +1 -1
- package/dist/ui/assets/{cliproxy-control-panel-BnRavAdV.js → cliproxy-control-panel-BfElGwOQ.js} +1 -1
- package/dist/ui/assets/{codex-C_NQb-b_.js → codex-CP1dPOyh.js} +1 -1
- package/dist/ui/assets/{confirm-dialog-Ch-M9Hbx.js → confirm-dialog-vhsQSaZ6.js} +1 -1
- package/dist/ui/assets/{copilot-BjBYvnCs.js → copilot-DUTtEVYH.js} +1 -1
- package/dist/ui/assets/{cursor-L5hSOzMq.js → cursor-ThAyj_tQ.js} +1 -1
- package/dist/ui/assets/{droid-Cgv8qdDe.js → droid-mrP_PnYz.js} +1 -1
- package/dist/ui/assets/{globalenv-section-CCOKhfQR.js → globalenv-section-Gh2BxqVn.js} +1 -1
- package/dist/ui/assets/{health-CcgzRrGn.js → health-TGXaQNZq.js} +1 -1
- package/dist/ui/assets/index-CQIjTCyk.js +1 -0
- package/dist/ui/assets/{index-CBkM-K11.js → index-CRAY9dRC.js} +1 -1
- package/dist/ui/assets/{index-Be5tzS8b.js → index-CaRCgIIp.js} +1 -1
- package/dist/ui/assets/{index-Dqc1e2bT.js → index-DRXqBE1w.js} +1 -1
- package/dist/ui/assets/{index-DpF_8BcK.js → index-DSM3luVm.js} +2 -2
- package/dist/ui/assets/{index-DUbpdx2e.js → index-wYHVuydD.js} +1 -1
- package/dist/ui/assets/{logs-DJtDYnsv.js → logs-5mpClyQ2.js} +1 -1
- package/dist/ui/assets/{masked-input-NRy3dgQf.js → masked-input-DhWU9sNj.js} +1 -1
- package/dist/ui/assets/{proxy-status-widget-D7M56E9T.js → proxy-status-widget-C1IFaC6c.js} +1 -1
- package/dist/ui/assets/{raw-json-settings-editor-panel-qjLoSybO.js → raw-json-settings-editor-panel-tK2P1u12.js} +1 -1
- package/dist/ui/assets/{searchable-select-Bf0WOPIH.js → searchable-select-CNH0YBur.js} +1 -1
- package/dist/ui/assets/{separator-Y87DseSV.js → separator-CJd089R0.js} +1 -1
- package/dist/ui/assets/{shared-Bk0tDwnM.js → shared-DxH1omaN.js} +1 -1
- package/dist/ui/assets/{table-BAO0vhjx.js → table-lWkyktS-.js} +1 -1
- package/dist/ui/assets/{updates-DLNvHqY-.js → updates-nm2PIK8k.js} +1 -1
- package/dist/ui/index.html +1 -1
- package/dist/utils/websearch/hook-env.d.ts.map +1 -1
- package/dist/utils/websearch/hook-env.js +19 -1
- package/dist/utils/websearch/hook-env.js.map +1 -1
- package/dist/utils/websearch/status.d.ts +1 -1
- package/dist/utils/websearch/status.d.ts.map +1 -1
- package/dist/utils/websearch/status.js +33 -12
- package/dist/utils/websearch/status.js.map +1 -1
- package/dist/utils/websearch/types.d.ts +12 -2
- package/dist/utils/websearch/types.d.ts.map +1 -1
- package/dist/utils/websearch/types.js +38 -0
- package/dist/utils/websearch/types.js.map +1 -1
- package/dist/web-server/health/websearch-checks.js +1 -1
- package/dist/web-server/health/websearch-checks.js.map +1 -1
- package/dist/web-server/routes/websearch-routes.d.ts.map +1 -1
- package/dist/web-server/routes/websearch-routes.js +37 -0
- package/dist/web-server/routes/websearch-routes.js.map +1 -1
- package/lib/hooks/websearch-transformer.cjs +136 -0
- package/lib/mcp/ccs-websearch-server.cjs +1 -1
- package/package.json +1 -1
- 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' | '
|
|
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,
|
|
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
|
|
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,
|
|
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;
|
|
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":";AAAA;;GAEG;;AAEH,qCAAoD;AACpD,8EAA6F;AAE7F,qEAAgG;AAChG,6EAKgD;AAChD,mEAAmF;AAEnF,MAAM,MAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;AACxB,MAAM,4BAA4B,GAChC,+EAA+E,CAAC;
|
|
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 +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};
|