@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.
Files changed (76) hide show
  1. package/README.md +39 -0
  2. package/VERSION +1 -1
  3. package/dist/ccs.js +9 -1
  4. package/dist/ccs.js.map +1 -1
  5. package/dist/cliproxy/account-manager.d.ts.map +1 -1
  6. package/dist/cliproxy/account-manager.js +3 -1
  7. package/dist/cliproxy/account-manager.js.map +1 -1
  8. package/dist/cliproxy/cliproxy-executor.d.ts.map +1 -1
  9. package/dist/cliproxy/cliproxy-executor.js +145 -76
  10. package/dist/cliproxy/cliproxy-executor.js.map +1 -1
  11. package/dist/cliproxy/session-tracker.d.ts +54 -0
  12. package/dist/cliproxy/session-tracker.d.ts.map +1 -0
  13. package/dist/cliproxy/session-tracker.js +228 -0
  14. package/dist/cliproxy/session-tracker.js.map +1 -0
  15. package/dist/cliproxy/stats-fetcher.d.ts +19 -0
  16. package/dist/cliproxy/stats-fetcher.d.ts.map +1 -1
  17. package/dist/cliproxy/stats-fetcher.js +41 -3
  18. package/dist/cliproxy/stats-fetcher.js.map +1 -1
  19. package/dist/config/unified-config-loader.d.ts +33 -0
  20. package/dist/config/unified-config-loader.d.ts.map +1 -1
  21. package/dist/config/unified-config-loader.js +105 -3
  22. package/dist/config/unified-config-loader.js.map +1 -1
  23. package/dist/config/unified-config-types.d.ts +75 -1
  24. package/dist/config/unified-config-types.d.ts.map +1 -1
  25. package/dist/config/unified-config-types.js +21 -1
  26. package/dist/config/unified-config-types.js.map +1 -1
  27. package/dist/ui/assets/{accounts-achdtDUJ.js → accounts-BfRSUzvC.js} +1 -1
  28. package/dist/ui/assets/{analytics-BVlC8Y7-.js → analytics-ClDxRP9x.js} +34 -34
  29. package/dist/ui/assets/api-DyJHhCv0.js +1 -0
  30. package/dist/ui/assets/card-CrGAcUkx.js +1 -0
  31. package/dist/ui/assets/cliproxy-Zr4pFy6O.js +1 -0
  32. package/dist/ui/assets/cliproxy-control-panel-Cu7DgEPx.js +1 -0
  33. package/dist/ui/assets/code-editor-D0YjMRQO.js +2 -0
  34. package/dist/ui/assets/{form-utils-DKkU3nz7.js → form-utils-CKETQmt9.js} +1 -1
  35. package/dist/ui/assets/{health-Xbq8eUat.js → health-Rretog4H.js} +1 -1
  36. package/dist/ui/assets/icons-D6DaLbNh.js +1 -0
  37. package/dist/ui/assets/index-B2PFll-u.js +46 -0
  38. package/dist/ui/assets/index-DTVwRqgB.css +1 -0
  39. package/dist/ui/assets/providers/iflow.png +0 -0
  40. package/dist/ui/assets/{radix-ui-OFtPgiRV.js → radix-ui-Bhyw9pC9.js} +2 -2
  41. package/dist/ui/assets/{react-vendor-CjrBBxxX.js → react-vendor-DadlvKzT.js} +1 -1
  42. package/dist/ui/assets/settings-B7OFU9lZ.js +1 -0
  43. package/dist/ui/assets/shared-qGCa7mu2.js +1 -0
  44. package/dist/ui/assets/{tanstack-DMWkeNzM.js → tanstack-DZ3a6J0N.js} +1 -1
  45. package/dist/ui/index.html +7 -7
  46. package/dist/utils/shell-executor.d.ts.map +1 -1
  47. package/dist/utils/shell-executor.js +6 -1
  48. package/dist/utils/shell-executor.js.map +1 -1
  49. package/dist/utils/websearch-manager.d.ts +197 -0
  50. package/dist/utils/websearch-manager.d.ts.map +1 -0
  51. package/dist/utils/websearch-manager.js +685 -0
  52. package/dist/utils/websearch-manager.js.map +1 -0
  53. package/dist/web-server/health-service.d.ts.map +1 -1
  54. package/dist/web-server/health-service.js +50 -0
  55. package/dist/web-server/health-service.js.map +1 -1
  56. package/dist/web-server/routes.d.ts.map +1 -1
  57. package/dist/web-server/routes.js +169 -1
  58. package/dist/web-server/routes.js.map +1 -1
  59. package/dist/web-server/shutdown.d.ts +4 -4
  60. package/dist/web-server/shutdown.d.ts.map +1 -1
  61. package/dist/web-server/shutdown.js +9 -17
  62. package/dist/web-server/shutdown.js.map +1 -1
  63. package/lib/hooks/block-websearch.cjs +75 -0
  64. package/lib/hooks/websearch-transformer.cjs +600 -0
  65. package/package.json +2 -1
  66. package/scripts/dev-install.sh +57 -5
  67. package/scripts/preinstall.js +59 -0
  68. package/dist/ui/assets/api-BwWsFLoC.js +0 -1
  69. package/dist/ui/assets/cliproxy-DuaxYcVk.js +0 -1
  70. package/dist/ui/assets/cliproxy-control-panel-DTiBzA5u.js +0 -1
  71. package/dist/ui/assets/code-editor-D7CYoILm.js +0 -36
  72. package/dist/ui/assets/icons-Alnq4BWm.js +0 -1
  73. package/dist/ui/assets/index-B1gvMo-b.css +0 -1
  74. package/dist/ui/assets/index-C2RMogI8.js +0 -12
  75. package/dist/ui/assets/settings-95g3F5Gk.js +0 -1
  76. 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;AA2BD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,GAAE,MAA8B,GACnC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAuD/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"}
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 providers from the nested API structure
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: 0, // API doesn't provide input/output breakdown
51
- output: 0,
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":"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"}
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;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,aAAa,GAAG,IAAI,CAuBxD;AA8BD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,aAAa,CAUzD;AAmGD;;;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"}
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