@kaitranntt/ccs 5.20.0 → 6.0.0-dev.2
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/README.md +39 -0
- package/VERSION +1 -1
- package/dist/ccs.js +9 -1
- package/dist/ccs.js.map +1 -1
- package/dist/cliproxy/account-manager.d.ts.map +1 -1
- package/dist/cliproxy/account-manager.js +3 -1
- package/dist/cliproxy/account-manager.js.map +1 -1
- package/dist/cliproxy/cliproxy-executor.d.ts.map +1 -1
- package/dist/cliproxy/cliproxy-executor.js +145 -76
- package/dist/cliproxy/cliproxy-executor.js.map +1 -1
- package/dist/cliproxy/session-tracker.d.ts +54 -0
- package/dist/cliproxy/session-tracker.d.ts.map +1 -0
- package/dist/cliproxy/session-tracker.js +228 -0
- package/dist/cliproxy/session-tracker.js.map +1 -0
- package/dist/cliproxy/stats-fetcher.d.ts +19 -0
- package/dist/cliproxy/stats-fetcher.d.ts.map +1 -1
- package/dist/cliproxy/stats-fetcher.js +41 -3
- package/dist/cliproxy/stats-fetcher.js.map +1 -1
- package/dist/config/unified-config-loader.d.ts +33 -0
- package/dist/config/unified-config-loader.d.ts.map +1 -1
- package/dist/config/unified-config-loader.js +105 -3
- package/dist/config/unified-config-loader.js.map +1 -1
- package/dist/config/unified-config-types.d.ts +75 -1
- package/dist/config/unified-config-types.d.ts.map +1 -1
- package/dist/config/unified-config-types.js +21 -1
- package/dist/config/unified-config-types.js.map +1 -1
- package/dist/ui/assets/{accounts-achdtDUJ.js → accounts-BfRSUzvC.js} +1 -1
- package/dist/ui/assets/{analytics-BVlC8Y7-.js → analytics-ClDxRP9x.js} +34 -34
- package/dist/ui/assets/api-DyJHhCv0.js +1 -0
- package/dist/ui/assets/card-CrGAcUkx.js +1 -0
- package/dist/ui/assets/cliproxy-Zr4pFy6O.js +1 -0
- package/dist/ui/assets/cliproxy-control-panel-Cu7DgEPx.js +1 -0
- package/dist/ui/assets/code-editor-D0YjMRQO.js +2 -0
- package/dist/ui/assets/{form-utils-DKkU3nz7.js → form-utils-CKETQmt9.js} +1 -1
- package/dist/ui/assets/{health-Xbq8eUat.js → health-Rretog4H.js} +1 -1
- package/dist/ui/assets/icons-D6DaLbNh.js +1 -0
- package/dist/ui/assets/index-B2PFll-u.js +46 -0
- package/dist/ui/assets/index-DTVwRqgB.css +1 -0
- package/dist/ui/assets/providers/iflow.png +0 -0
- package/dist/ui/assets/{radix-ui-OFtPgiRV.js → radix-ui-Bhyw9pC9.js} +2 -2
- package/dist/ui/assets/{react-vendor-CjrBBxxX.js → react-vendor-DadlvKzT.js} +1 -1
- package/dist/ui/assets/settings-B7OFU9lZ.js +1 -0
- package/dist/ui/assets/shared-qGCa7mu2.js +1 -0
- package/dist/ui/assets/{tanstack-DMWkeNzM.js → tanstack-DZ3a6J0N.js} +1 -1
- package/dist/ui/index.html +7 -7
- package/dist/utils/shell-executor.d.ts.map +1 -1
- package/dist/utils/shell-executor.js +6 -1
- package/dist/utils/shell-executor.js.map +1 -1
- package/dist/utils/websearch-manager.d.ts +197 -0
- package/dist/utils/websearch-manager.d.ts.map +1 -0
- package/dist/utils/websearch-manager.js +685 -0
- package/dist/utils/websearch-manager.js.map +1 -0
- package/dist/web-server/health-service.d.ts.map +1 -1
- package/dist/web-server/health-service.js +50 -0
- package/dist/web-server/health-service.js.map +1 -1
- package/dist/web-server/routes.d.ts.map +1 -1
- package/dist/web-server/routes.js +169 -1
- package/dist/web-server/routes.js.map +1 -1
- package/dist/web-server/shutdown.d.ts +4 -4
- package/dist/web-server/shutdown.d.ts.map +1 -1
- package/dist/web-server/shutdown.js +9 -17
- package/dist/web-server/shutdown.js.map +1 -1
- package/lib/hooks/block-websearch.cjs +75 -0
- package/lib/hooks/websearch-transformer.cjs +600 -0
- package/package.json +2 -1
- package/scripts/dev-install.sh +57 -5
- package/scripts/preinstall.js +59 -0
- package/dist/ui/assets/api-BwWsFLoC.js +0 -1
- package/dist/ui/assets/cliproxy-DuaxYcVk.js +0 -1
- package/dist/ui/assets/cliproxy-control-panel-DTiBzA5u.js +0 -1
- package/dist/ui/assets/code-editor-D7CYoILm.js +0 -36
- package/dist/ui/assets/icons-Alnq4BWm.js +0 -1
- package/dist/ui/assets/index-B1gvMo-b.css +0 -1
- package/dist/ui/assets/index-C2RMogI8.js +0 -12
- package/dist/ui/assets/settings-95g3F5Gk.js +0 -1
- package/dist/ui/assets/shared-Cg5XjdQM.js +0 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Tracker for CLIProxy Multi-Instance Support
|
|
3
|
+
*
|
|
4
|
+
* Manages reference counting for shared CLIProxy instances.
|
|
5
|
+
* Multiple CCS sessions can share a single proxy on the same port.
|
|
6
|
+
* Proxy only terminates when ALL sessions exit (count reaches 0).
|
|
7
|
+
*
|
|
8
|
+
* Lock file format: ~/.ccs/cliproxy/sessions.json
|
|
9
|
+
* {
|
|
10
|
+
* "port": 8317,
|
|
11
|
+
* "pid": 12345, // CLIProxy process PID
|
|
12
|
+
* "sessions": ["abc123", "def456"], // Active session IDs
|
|
13
|
+
* "startedAt": "2024-01-01T00:00:00Z"
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
/** Session lock file structure */
|
|
17
|
+
interface SessionLock {
|
|
18
|
+
port: number;
|
|
19
|
+
pid: number;
|
|
20
|
+
sessions: string[];
|
|
21
|
+
startedAt: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Check if there's an existing proxy running that we can reuse.
|
|
25
|
+
* Returns the existing lock if proxy is healthy, null otherwise.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getExistingProxy(port: number): SessionLock | null;
|
|
28
|
+
/**
|
|
29
|
+
* Register a new session with the proxy.
|
|
30
|
+
* Call this when starting a new CCS session that will use an existing proxy.
|
|
31
|
+
* @returns Session ID for this session
|
|
32
|
+
*/
|
|
33
|
+
export declare function registerSession(port: number, proxyPid: number): string;
|
|
34
|
+
/**
|
|
35
|
+
* Unregister a session from the proxy.
|
|
36
|
+
* @returns true if this was the last session (proxy should be killed)
|
|
37
|
+
*/
|
|
38
|
+
export declare function unregisterSession(sessionId: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Get current session count for the proxy.
|
|
41
|
+
*/
|
|
42
|
+
export declare function getSessionCount(): number;
|
|
43
|
+
/**
|
|
44
|
+
* Check if proxy has any active sessions.
|
|
45
|
+
* Used to determine if a "zombie" proxy should be killed.
|
|
46
|
+
*/
|
|
47
|
+
export declare function hasActiveSessions(): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Clean up orphaned sessions (when proxy crashes).
|
|
50
|
+
* Called on startup to ensure clean state.
|
|
51
|
+
*/
|
|
52
|
+
export declare function cleanupOrphanedSessions(port: number): void;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=session-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-tracker.d.ts","sourceRoot":"","sources":["../../src/cliproxy/session-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,kCAAkC;AAClC,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAoED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAmBjE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAoBtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAuB5D;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAMxC;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAa3C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAe1D"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Session Tracker for CLIProxy Multi-Instance Support
|
|
4
|
+
*
|
|
5
|
+
* Manages reference counting for shared CLIProxy instances.
|
|
6
|
+
* Multiple CCS sessions can share a single proxy on the same port.
|
|
7
|
+
* Proxy only terminates when ALL sessions exit (count reaches 0).
|
|
8
|
+
*
|
|
9
|
+
* Lock file format: ~/.ccs/cliproxy/sessions.json
|
|
10
|
+
* {
|
|
11
|
+
* "port": 8317,
|
|
12
|
+
* "pid": 12345, // CLIProxy process PID
|
|
13
|
+
* "sessions": ["abc123", "def456"], // Active session IDs
|
|
14
|
+
* "startedAt": "2024-01-01T00:00:00Z"
|
|
15
|
+
* }
|
|
16
|
+
*/
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.cleanupOrphanedSessions = exports.hasActiveSessions = exports.getSessionCount = exports.unregisterSession = exports.registerSession = exports.getExistingProxy = void 0;
|
|
42
|
+
const fs = __importStar(require("fs"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const crypto = __importStar(require("crypto"));
|
|
45
|
+
const config_generator_1 = require("./config-generator");
|
|
46
|
+
/** Generate unique session ID */
|
|
47
|
+
function generateSessionId() {
|
|
48
|
+
return crypto.randomBytes(8).toString('hex');
|
|
49
|
+
}
|
|
50
|
+
/** Get path to session lock file */
|
|
51
|
+
function getSessionLockPath() {
|
|
52
|
+
return path.join((0, config_generator_1.getCliproxyDir)(), 'sessions.json');
|
|
53
|
+
}
|
|
54
|
+
/** Read session lock file (returns null if not exists or invalid) */
|
|
55
|
+
function readSessionLock() {
|
|
56
|
+
const lockPath = getSessionLockPath();
|
|
57
|
+
try {
|
|
58
|
+
if (!fs.existsSync(lockPath)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const content = fs.readFileSync(lockPath, 'utf-8');
|
|
62
|
+
const lock = JSON.parse(content);
|
|
63
|
+
// Validate structure
|
|
64
|
+
if (typeof lock.port !== 'number' ||
|
|
65
|
+
typeof lock.pid !== 'number' ||
|
|
66
|
+
!Array.isArray(lock.sessions)) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return lock;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/** Write session lock file */
|
|
76
|
+
function writeSessionLock(lock) {
|
|
77
|
+
const lockPath = getSessionLockPath();
|
|
78
|
+
const dir = path.dirname(lockPath);
|
|
79
|
+
if (!fs.existsSync(dir)) {
|
|
80
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
81
|
+
}
|
|
82
|
+
fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2), { mode: 0o600 });
|
|
83
|
+
}
|
|
84
|
+
/** Delete session lock file */
|
|
85
|
+
function deleteSessionLock() {
|
|
86
|
+
const lockPath = getSessionLockPath();
|
|
87
|
+
try {
|
|
88
|
+
if (fs.existsSync(lockPath)) {
|
|
89
|
+
fs.unlinkSync(lockPath);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Ignore errors on cleanup
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Check if a PID is still running */
|
|
97
|
+
function isProcessRunning(pid) {
|
|
98
|
+
try {
|
|
99
|
+
// Sending signal 0 checks if process exists without killing it
|
|
100
|
+
process.kill(pid, 0);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if there's an existing proxy running that we can reuse.
|
|
109
|
+
* Returns the existing lock if proxy is healthy, null otherwise.
|
|
110
|
+
*/
|
|
111
|
+
function getExistingProxy(port) {
|
|
112
|
+
const lock = readSessionLock();
|
|
113
|
+
if (!lock) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
// Verify port matches
|
|
117
|
+
if (lock.port !== port) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
// Verify proxy process is still running
|
|
121
|
+
if (!isProcessRunning(lock.pid)) {
|
|
122
|
+
// Proxy crashed - clean up stale lock
|
|
123
|
+
deleteSessionLock();
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
return lock;
|
|
127
|
+
}
|
|
128
|
+
exports.getExistingProxy = getExistingProxy;
|
|
129
|
+
/**
|
|
130
|
+
* Register a new session with the proxy.
|
|
131
|
+
* Call this when starting a new CCS session that will use an existing proxy.
|
|
132
|
+
* @returns Session ID for this session
|
|
133
|
+
*/
|
|
134
|
+
function registerSession(port, proxyPid) {
|
|
135
|
+
const sessionId = generateSessionId();
|
|
136
|
+
const existingLock = readSessionLock();
|
|
137
|
+
if (existingLock && existingLock.port === port && existingLock.pid === proxyPid) {
|
|
138
|
+
// Add to existing sessions
|
|
139
|
+
existingLock.sessions.push(sessionId);
|
|
140
|
+
writeSessionLock(existingLock);
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// Create new lock (first session for this proxy)
|
|
144
|
+
const newLock = {
|
|
145
|
+
port,
|
|
146
|
+
pid: proxyPid,
|
|
147
|
+
sessions: [sessionId],
|
|
148
|
+
startedAt: new Date().toISOString(),
|
|
149
|
+
};
|
|
150
|
+
writeSessionLock(newLock);
|
|
151
|
+
}
|
|
152
|
+
return sessionId;
|
|
153
|
+
}
|
|
154
|
+
exports.registerSession = registerSession;
|
|
155
|
+
/**
|
|
156
|
+
* Unregister a session from the proxy.
|
|
157
|
+
* @returns true if this was the last session (proxy should be killed)
|
|
158
|
+
*/
|
|
159
|
+
function unregisterSession(sessionId) {
|
|
160
|
+
const lock = readSessionLock();
|
|
161
|
+
if (!lock) {
|
|
162
|
+
// No lock file - assume we're the only session
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
// Remove this session from the list
|
|
166
|
+
const index = lock.sessions.indexOf(sessionId);
|
|
167
|
+
if (index !== -1) {
|
|
168
|
+
lock.sessions.splice(index, 1);
|
|
169
|
+
}
|
|
170
|
+
// Check if any sessions remain
|
|
171
|
+
if (lock.sessions.length === 0) {
|
|
172
|
+
// Last session - clean up lock file
|
|
173
|
+
deleteSessionLock();
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
// Other sessions still active - keep proxy running
|
|
177
|
+
writeSessionLock(lock);
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
exports.unregisterSession = unregisterSession;
|
|
181
|
+
/**
|
|
182
|
+
* Get current session count for the proxy.
|
|
183
|
+
*/
|
|
184
|
+
function getSessionCount() {
|
|
185
|
+
const lock = readSessionLock();
|
|
186
|
+
if (!lock) {
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
|
189
|
+
return lock.sessions.length;
|
|
190
|
+
}
|
|
191
|
+
exports.getSessionCount = getSessionCount;
|
|
192
|
+
/**
|
|
193
|
+
* Check if proxy has any active sessions.
|
|
194
|
+
* Used to determine if a "zombie" proxy should be killed.
|
|
195
|
+
*/
|
|
196
|
+
function hasActiveSessions() {
|
|
197
|
+
const lock = readSessionLock();
|
|
198
|
+
if (!lock) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
// Verify proxy is still running
|
|
202
|
+
if (!isProcessRunning(lock.pid)) {
|
|
203
|
+
deleteSessionLock();
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
return lock.sessions.length > 0;
|
|
207
|
+
}
|
|
208
|
+
exports.hasActiveSessions = hasActiveSessions;
|
|
209
|
+
/**
|
|
210
|
+
* Clean up orphaned sessions (when proxy crashes).
|
|
211
|
+
* Called on startup to ensure clean state.
|
|
212
|
+
*/
|
|
213
|
+
function cleanupOrphanedSessions(port) {
|
|
214
|
+
const lock = readSessionLock();
|
|
215
|
+
if (!lock) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
// If port doesn't match, this lock is for a different proxy
|
|
219
|
+
if (lock.port !== port) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
// If proxy is dead, clean up lock
|
|
223
|
+
if (!isProcessRunning(lock.pid)) {
|
|
224
|
+
deleteSessionLock();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
exports.cleanupOrphanedSessions = cleanupOrphanedSessions;
|
|
228
|
+
//# sourceMappingURL=session-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-tracker.js","sourceRoot":"","sources":["../../src/cliproxy/session-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,10 +4,27 @@
|
|
|
4
4
|
* Fetches usage statistics from CLIProxyAPI's management API.
|
|
5
5
|
* Requires usage-statistics-enabled: true in config.yaml.
|
|
6
6
|
*/
|
|
7
|
+
/** Per-account usage statistics */
|
|
8
|
+
export interface AccountUsageStats {
|
|
9
|
+
/** Account email or identifier */
|
|
10
|
+
source: string;
|
|
11
|
+
/** Number of successful requests */
|
|
12
|
+
successCount: number;
|
|
13
|
+
/** Number of failed requests */
|
|
14
|
+
failureCount: number;
|
|
15
|
+
/** Total tokens used */
|
|
16
|
+
totalTokens: number;
|
|
17
|
+
/** Last request timestamp */
|
|
18
|
+
lastUsedAt?: string;
|
|
19
|
+
}
|
|
7
20
|
/** Usage statistics from CLIProxyAPI */
|
|
8
21
|
export interface CliproxyStats {
|
|
9
22
|
/** Total number of requests processed */
|
|
10
23
|
totalRequests: number;
|
|
24
|
+
/** Total successful requests */
|
|
25
|
+
successCount: number;
|
|
26
|
+
/** Total failed requests */
|
|
27
|
+
failureCount: number;
|
|
11
28
|
/** Token counts */
|
|
12
29
|
tokens: {
|
|
13
30
|
input: number;
|
|
@@ -18,6 +35,8 @@ export interface CliproxyStats {
|
|
|
18
35
|
requestsByModel: Record<string, number>;
|
|
19
36
|
/** Requests grouped by provider */
|
|
20
37
|
requestsByProvider: Record<string, number>;
|
|
38
|
+
/** Per-account usage breakdown */
|
|
39
|
+
accountStats: Record<string, AccountUsageStats>;
|
|
21
40
|
/** Number of quota exceeded (429) events */
|
|
22
41
|
quotaExceededCount: number;
|
|
23
42
|
/** Number of request retries */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats-fetcher.d.ts","sourceRoot":"","sources":["../../src/cliproxy/stats-fetcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB;IACnB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,gCAAgC;IAChC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,mCAAmC;IACnC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,4CAA4C;IAC5C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"stats-fetcher.d.ts","sourceRoot":"","sources":["../../src/cliproxy/stats-fetcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,mCAAmC;AACnC,MAAM,WAAW,iBAAiB;IAChC,kCAAkC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wCAAwC;AACxC,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB;IACnB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,gCAAgC;IAChC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,mCAAmC;IACnC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IAChD,4CAA4C;IAC5C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,WAAW,EAAE,MAAM,CAAC;CACrB;AA2CD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,GAAE,MAA8B,GACnC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAiG/B;AAED,8DAA8D;AAC9D,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAQD,yCAAyC;AACzC,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,GAAE,MAA8B,GACnC,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CA6CxC;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,GAAE,MAA8B,GAAG,OAAO,CAAC,OAAO,CAAC,CAe9F"}
|
|
@@ -30,15 +30,50 @@ async function fetchCliproxyStats(port = config_generator_1.CLIPROXY_DEFAULT_POR
|
|
|
30
30
|
}
|
|
31
31
|
const data = (await response.json());
|
|
32
32
|
const usage = data.usage;
|
|
33
|
-
// Extract models and
|
|
33
|
+
// Extract models, providers, and per-account stats from the nested API structure
|
|
34
34
|
const requestsByModel = {};
|
|
35
35
|
const requestsByProvider = {};
|
|
36
|
+
const accountStats = {};
|
|
37
|
+
let totalSuccessCount = 0;
|
|
38
|
+
let totalFailureCount = 0;
|
|
39
|
+
let totalInputTokens = 0;
|
|
40
|
+
let totalOutputTokens = 0;
|
|
36
41
|
if (usage?.apis) {
|
|
37
42
|
for (const [provider, providerData] of Object.entries(usage.apis)) {
|
|
38
43
|
requestsByProvider[provider] = providerData.total_requests ?? 0;
|
|
39
44
|
if (providerData.models) {
|
|
40
45
|
for (const [model, modelData] of Object.entries(providerData.models)) {
|
|
41
46
|
requestsByModel[model] = modelData.total_requests ?? 0;
|
|
47
|
+
// Aggregate per-account stats from request details
|
|
48
|
+
if (modelData.details) {
|
|
49
|
+
for (const detail of modelData.details) {
|
|
50
|
+
const source = detail.source || 'unknown';
|
|
51
|
+
// Initialize account stats if not exists
|
|
52
|
+
if (!accountStats[source]) {
|
|
53
|
+
accountStats[source] = {
|
|
54
|
+
source,
|
|
55
|
+
successCount: 0,
|
|
56
|
+
failureCount: 0,
|
|
57
|
+
totalTokens: 0,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// Update account stats
|
|
61
|
+
if (detail.failed) {
|
|
62
|
+
accountStats[source].failureCount++;
|
|
63
|
+
totalFailureCount++;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
accountStats[source].successCount++;
|
|
67
|
+
totalSuccessCount++;
|
|
68
|
+
}
|
|
69
|
+
const tokens = detail.tokens?.total_tokens ?? 0;
|
|
70
|
+
accountStats[source].totalTokens += tokens;
|
|
71
|
+
accountStats[source].lastUsedAt = detail.timestamp;
|
|
72
|
+
// Aggregate token breakdowns
|
|
73
|
+
totalInputTokens += detail.tokens?.input_tokens ?? 0;
|
|
74
|
+
totalOutputTokens += detail.tokens?.output_tokens ?? 0;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
42
77
|
}
|
|
43
78
|
}
|
|
44
79
|
}
|
|
@@ -46,13 +81,16 @@ async function fetchCliproxyStats(port = config_generator_1.CLIPROXY_DEFAULT_POR
|
|
|
46
81
|
// Normalize the response to our interface
|
|
47
82
|
return {
|
|
48
83
|
totalRequests: usage?.total_requests ?? 0,
|
|
84
|
+
successCount: totalSuccessCount,
|
|
85
|
+
failureCount: totalFailureCount,
|
|
49
86
|
tokens: {
|
|
50
|
-
input:
|
|
51
|
-
output:
|
|
87
|
+
input: totalInputTokens,
|
|
88
|
+
output: totalOutputTokens,
|
|
52
89
|
total: usage?.total_tokens ?? 0,
|
|
53
90
|
},
|
|
54
91
|
requestsByModel,
|
|
55
92
|
requestsByProvider,
|
|
93
|
+
accountStats,
|
|
56
94
|
quotaExceededCount: usage?.failure_count ?? data.failed_requests ?? 0,
|
|
57
95
|
retryCount: 0, // API doesn't track retries separately
|
|
58
96
|
collectedAt: new Date().toISOString(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats-fetcher.js","sourceRoot":"","sources":["../../src/cliproxy/stats-fetcher.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,yDAAqF;
|
|
1
|
+
{"version":3,"file":"stats-fetcher.js","sourceRoot":"","sources":["../../src/cliproxy/stats-fetcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,6 +31,7 @@ export declare function getConfigFormat(): 'yaml' | 'json' | 'none';
|
|
|
31
31
|
/**
|
|
32
32
|
* Load unified config from YAML file.
|
|
33
33
|
* Returns null if file doesn't exist or format check fails.
|
|
34
|
+
* Auto-upgrades config if version is outdated (regenerates comments).
|
|
34
35
|
*/
|
|
35
36
|
export declare function loadUnifiedConfig(): UnifiedConfig | null;
|
|
36
37
|
/**
|
|
@@ -53,4 +54,36 @@ export declare function updateUnifiedConfig(updates: Partial<UnifiedConfig>): Un
|
|
|
53
54
|
*/
|
|
54
55
|
export declare function getDefaultProfile(): string | undefined;
|
|
55
56
|
export declare function setDefaultProfile(name: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Gemini CLI WebSearch configuration
|
|
59
|
+
*/
|
|
60
|
+
export interface GeminiWebSearchInfo {
|
|
61
|
+
enabled: boolean;
|
|
62
|
+
model: string;
|
|
63
|
+
timeout: number;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get websearch configuration.
|
|
67
|
+
* Returns defaults if not configured.
|
|
68
|
+
* Supports Gemini CLI, OpenCode, and Grok CLI providers.
|
|
69
|
+
*/
|
|
70
|
+
export declare function getWebSearchConfig(): {
|
|
71
|
+
enabled: boolean;
|
|
72
|
+
providers?: {
|
|
73
|
+
gemini?: GeminiWebSearchInfo;
|
|
74
|
+
opencode?: {
|
|
75
|
+
enabled?: boolean;
|
|
76
|
+
model?: string;
|
|
77
|
+
timeout?: number;
|
|
78
|
+
};
|
|
79
|
+
grok?: {
|
|
80
|
+
enabled?: boolean;
|
|
81
|
+
timeout?: number;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
gemini?: {
|
|
85
|
+
enabled?: boolean;
|
|
86
|
+
timeout?: number;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
56
89
|
//# sourceMappingURL=unified-config-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unified-config-loader.d.ts","sourceRoot":"","sources":["../../src/config/unified-config-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACL,aAAa,EAId,MAAM,wBAAwB,CAAC;AAMhC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,MAAM,GAAG,MAAM,CAK1D;AAED
|
|
1
|
+
{"version":3,"file":"unified-config-loader.d.ts","sourceRoot":"","sources":["../../src/config/unified-config-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACL,aAAa,EAId,MAAM,wBAAwB,CAAC;AAMhC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,MAAM,GAAG,MAAM,CAK1D;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,aAAa,GAAG,IAAI,CAuCxD;AAyDD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,aAAa,CAUzD;AAiID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAiC7D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa,CAKlF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,SAAS,CAGtD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,mBAAmB,CAAC;QAC7B,QAAQ,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,OAAO,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QACnE,IAAI,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,OAAO,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAChD,CAAC;IAEF,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAClD,CAqCA"}
|
|
@@ -29,7 +29,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
29
29
|
return result;
|
|
30
30
|
};
|
|
31
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
-
exports.setDefaultProfile = exports.getDefaultProfile = exports.updateUnifiedConfig = exports.saveUnifiedConfig = exports.loadOrCreateUnifiedConfig = exports.loadUnifiedConfig = exports.getConfigFormat = exports.hasLegacyConfig = exports.hasUnifiedConfig = exports.getConfigJsonPath = exports.getConfigYamlPath = void 0;
|
|
32
|
+
exports.getWebSearchConfig = exports.setDefaultProfile = exports.getDefaultProfile = exports.updateUnifiedConfig = exports.saveUnifiedConfig = exports.loadOrCreateUnifiedConfig = exports.loadUnifiedConfig = exports.getConfigFormat = exports.hasLegacyConfig = exports.hasUnifiedConfig = exports.getConfigJsonPath = exports.getConfigYamlPath = void 0;
|
|
33
33
|
const fs = __importStar(require("fs"));
|
|
34
34
|
const path = __importStar(require("path"));
|
|
35
35
|
const yaml = __importStar(require("js-yaml"));
|
|
@@ -85,6 +85,7 @@ exports.getConfigFormat = getConfigFormat;
|
|
|
85
85
|
/**
|
|
86
86
|
* Load unified config from YAML file.
|
|
87
87
|
* Returns null if file doesn't exist or format check fails.
|
|
88
|
+
* Auto-upgrades config if version is outdated (regenerates comments).
|
|
88
89
|
*/
|
|
89
90
|
function loadUnifiedConfig() {
|
|
90
91
|
const yamlPath = getConfigYamlPath();
|
|
@@ -99,6 +100,22 @@ function loadUnifiedConfig() {
|
|
|
99
100
|
console.error(`[!] Invalid config format in ${yamlPath}`);
|
|
100
101
|
return null;
|
|
101
102
|
}
|
|
103
|
+
// Auto-upgrade if version is outdated (regenerates YAML with new comments and fields)
|
|
104
|
+
if ((parsed.version ?? 1) < unified_config_types_1.UNIFIED_CONFIG_VERSION) {
|
|
105
|
+
// Merge with defaults to add new fields (e.g., model for websearch providers)
|
|
106
|
+
const upgraded = mergeWithDefaults(parsed);
|
|
107
|
+
upgraded.version = unified_config_types_1.UNIFIED_CONFIG_VERSION;
|
|
108
|
+
try {
|
|
109
|
+
saveUnifiedConfig(upgraded);
|
|
110
|
+
if (process.env.CCS_DEBUG) {
|
|
111
|
+
console.error(`[i] Config upgraded to v${unified_config_types_1.UNIFIED_CONFIG_VERSION}`);
|
|
112
|
+
}
|
|
113
|
+
return upgraded;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// Ignore save errors during upgrade - config still works
|
|
117
|
+
}
|
|
118
|
+
}
|
|
102
119
|
return parsed;
|
|
103
120
|
}
|
|
104
121
|
catch (err) {
|
|
@@ -132,6 +149,31 @@ function mergeWithDefaults(partial) {
|
|
|
132
149
|
...defaults.preferences,
|
|
133
150
|
...partial.preferences,
|
|
134
151
|
},
|
|
152
|
+
websearch: {
|
|
153
|
+
enabled: partial.websearch?.enabled ?? defaults.websearch?.enabled ?? true,
|
|
154
|
+
providers: {
|
|
155
|
+
gemini: {
|
|
156
|
+
enabled: partial.websearch?.providers?.gemini?.enabled ??
|
|
157
|
+
partial.websearch?.gemini?.enabled ?? // Legacy fallback
|
|
158
|
+
true,
|
|
159
|
+
model: partial.websearch?.providers?.gemini?.model ?? 'gemini-2.5-flash',
|
|
160
|
+
timeout: partial.websearch?.providers?.gemini?.timeout ??
|
|
161
|
+
partial.websearch?.gemini?.timeout ?? // Legacy fallback
|
|
162
|
+
55,
|
|
163
|
+
},
|
|
164
|
+
opencode: {
|
|
165
|
+
enabled: partial.websearch?.providers?.opencode?.enabled ?? false,
|
|
166
|
+
model: partial.websearch?.providers?.opencode?.model ?? 'opencode/grok-code',
|
|
167
|
+
timeout: partial.websearch?.providers?.opencode?.timeout ?? 90,
|
|
168
|
+
},
|
|
169
|
+
grok: {
|
|
170
|
+
enabled: partial.websearch?.providers?.grok?.enabled ?? false,
|
|
171
|
+
timeout: partial.websearch?.providers?.grok?.timeout ?? 55,
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
// Legacy fields (keep for backwards compatibility during read)
|
|
175
|
+
gemini: partial.websearch?.gemini,
|
|
176
|
+
},
|
|
135
177
|
};
|
|
136
178
|
}
|
|
137
179
|
/**
|
|
@@ -164,8 +206,7 @@ function generateYamlHeader() {
|
|
|
164
206
|
#
|
|
165
207
|
# To customize a profile:
|
|
166
208
|
# 1. Edit the *.settings.json file directly (e.g., ~/.ccs/glm.settings.json)
|
|
167
|
-
# 2. The file format matches Claude's settings.json: { "env": { ... } }
|
|
168
|
-
#
|
|
209
|
+
# 2. The file format matches Claude's settings.json: { "env": { ... } }\n#
|
|
169
210
|
# Structure:
|
|
170
211
|
# ┌─────────────────────────────────────────────────────────────────────────────┐
|
|
171
212
|
# │ profiles - References to *.settings.json files for API providers │
|
|
@@ -227,6 +268,30 @@ function generateYamlWithComments(config) {
|
|
|
227
268
|
.dump({ preferences: config.preferences }, { indent: 2, lineWidth: -1, quotingType: '"' })
|
|
228
269
|
.trim());
|
|
229
270
|
lines.push('');
|
|
271
|
+
// WebSearch section
|
|
272
|
+
if (config.websearch) {
|
|
273
|
+
lines.push('# ----------------------------------------------------------------------------');
|
|
274
|
+
lines.push('# WebSearch: CLI-based web search for third-party profiles');
|
|
275
|
+
lines.push('# Dashboard (`ccs config`) is the source of truth for provider selection.');
|
|
276
|
+
lines.push('#');
|
|
277
|
+
lines.push('# Third-party providers (gemini, codex, agy, etc.) do not have access to');
|
|
278
|
+
lines.push("# Anthropic's WebSearch tool. These CLI tools provide fallback web search.");
|
|
279
|
+
lines.push('#');
|
|
280
|
+
lines.push('# Fallback chain: Gemini -> OpenCode -> Grok (tries in order until success)');
|
|
281
|
+
lines.push('#');
|
|
282
|
+
lines.push('# Gemini models: gemini-2.5-flash (default), gemini-2.5-pro, gemini-2.5-flash-lite');
|
|
283
|
+
lines.push('# OpenCode models: opencode/grok-code (default), opencode/gpt-4o, opencode/claude-3.5-sonnet');
|
|
284
|
+
lines.push('#');
|
|
285
|
+
lines.push('# Install commands:');
|
|
286
|
+
lines.push('# gemini: npm i -g @google/gemini-cli (FREE - 1000 req/day)');
|
|
287
|
+
lines.push('# opencode: curl -fsSL https://opencode.ai/install | bash (FREE via Zen)');
|
|
288
|
+
lines.push('# grok: npm i -g @vibe-kit/grok-cli (requires GROK_API_KEY)');
|
|
289
|
+
lines.push('# ----------------------------------------------------------------------------');
|
|
290
|
+
lines.push(yaml
|
|
291
|
+
.dump({ websearch: config.websearch }, { indent: 2, lineWidth: -1, quotingType: '"' })
|
|
292
|
+
.trim());
|
|
293
|
+
lines.push('');
|
|
294
|
+
}
|
|
230
295
|
return lines.join('\n');
|
|
231
296
|
}
|
|
232
297
|
/**
|
|
@@ -288,4 +353,41 @@ function setDefaultProfile(name) {
|
|
|
288
353
|
updateUnifiedConfig({ default: name });
|
|
289
354
|
}
|
|
290
355
|
exports.setDefaultProfile = setDefaultProfile;
|
|
356
|
+
/**
|
|
357
|
+
* Get websearch configuration.
|
|
358
|
+
* Returns defaults if not configured.
|
|
359
|
+
* Supports Gemini CLI, OpenCode, and Grok CLI providers.
|
|
360
|
+
*/
|
|
361
|
+
function getWebSearchConfig() {
|
|
362
|
+
const config = loadOrCreateUnifiedConfig();
|
|
363
|
+
// Build provider configs
|
|
364
|
+
const geminiConfig = {
|
|
365
|
+
enabled: config.websearch?.providers?.gemini?.enabled ?? config.websearch?.gemini?.enabled ?? true,
|
|
366
|
+
model: config.websearch?.providers?.gemini?.model ?? 'gemini-2.5-flash',
|
|
367
|
+
timeout: config.websearch?.providers?.gemini?.timeout ?? config.websearch?.gemini?.timeout ?? 55,
|
|
368
|
+
};
|
|
369
|
+
const opencodeConfig = {
|
|
370
|
+
enabled: config.websearch?.providers?.opencode?.enabled ?? false,
|
|
371
|
+
model: config.websearch?.providers?.opencode?.model ?? 'opencode/grok-code',
|
|
372
|
+
timeout: config.websearch?.providers?.opencode?.timeout ?? 90,
|
|
373
|
+
};
|
|
374
|
+
const grokConfig = {
|
|
375
|
+
enabled: config.websearch?.providers?.grok?.enabled ?? false,
|
|
376
|
+
timeout: config.websearch?.providers?.grok?.timeout ?? 55,
|
|
377
|
+
};
|
|
378
|
+
// Auto-enable master switch if ANY provider is enabled
|
|
379
|
+
const anyProviderEnabled = geminiConfig.enabled || opencodeConfig.enabled || grokConfig.enabled;
|
|
380
|
+
const enabled = anyProviderEnabled && (config.websearch?.enabled ?? true);
|
|
381
|
+
return {
|
|
382
|
+
enabled,
|
|
383
|
+
providers: {
|
|
384
|
+
gemini: geminiConfig,
|
|
385
|
+
opencode: opencodeConfig,
|
|
386
|
+
grok: grokConfig,
|
|
387
|
+
},
|
|
388
|
+
// Legacy field for backwards compatibility
|
|
389
|
+
gemini: config.websearch?.gemini,
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
exports.getWebSearchConfig = getWebSearchConfig;
|
|
291
393
|
//# sourceMappingURL=unified-config-loader.js.map
|