@kaitranntt/ccs 5.15.0-dev.2 → 5.15.0-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/VERSION +1 -1
- package/dist/cliproxy/account-manager.d.ts.map +1 -1
- package/dist/cliproxy/account-manager.js +35 -0
- package/dist/cliproxy/account-manager.js.map +1 -1
- package/dist/cliproxy/config-generator.d.ts +21 -0
- package/dist/cliproxy/config-generator.d.ts.map +1 -1
- package/dist/cliproxy/config-generator.js +122 -16
- package/dist/cliproxy/config-generator.js.map +1 -1
- package/dist/cliproxy/index.d.ts +7 -1
- package/dist/cliproxy/index.d.ts.map +1 -1
- package/dist/cliproxy/index.js +20 -2
- package/dist/cliproxy/index.js.map +1 -1
- package/dist/cliproxy/openai-compat-manager.d.ts +46 -0
- package/dist/cliproxy/openai-compat-manager.d.ts.map +1 -0
- package/dist/cliproxy/openai-compat-manager.js +191 -0
- package/dist/cliproxy/openai-compat-manager.js.map +1 -0
- package/dist/cliproxy/service-manager.d.ts +43 -0
- package/dist/cliproxy/service-manager.d.ts.map +1 -0
- package/dist/cliproxy/service-manager.js +220 -0
- package/dist/cliproxy/service-manager.js.map +1 -0
- package/dist/cliproxy/stats-fetcher.d.ts +59 -0
- package/dist/cliproxy/stats-fetcher.d.ts.map +1 -0
- package/dist/cliproxy/stats-fetcher.js +134 -0
- package/dist/cliproxy/stats-fetcher.js.map +1 -0
- package/dist/commands/config-command.d.ts +1 -0
- package/dist/commands/config-command.d.ts.map +1 -1
- package/dist/commands/config-command.js +24 -1
- package/dist/commands/config-command.js.map +1 -1
- package/dist/management/doctor.d.ts.map +1 -1
- package/dist/management/doctor.js +21 -7
- package/dist/management/doctor.js.map +1 -1
- package/dist/types/config.d.ts +13 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/dist/ui/assets/accounts-Bl9qfu_d.js +1 -0
- package/dist/ui/assets/analytics-BHnr8pTE.js +64 -0
- package/dist/ui/assets/{api-LYILKXgM.js → api-DoPJHgqb.js} +1 -1
- package/dist/ui/assets/cliproxy-DRxRpTJv.js +1 -0
- package/dist/ui/assets/cliproxy-control-panel-CNpMpeWs.js +1 -0
- package/dist/ui/assets/{code-editor-HkboCFlD.js → code-editor-ek-uxeLN.js} +11 -11
- package/dist/ui/assets/health-DBc3-gE9.js +1 -0
- package/dist/ui/assets/icons-CqXn5eV0.js +1 -0
- package/dist/ui/assets/index-D-zCRwmw.js +12 -0
- package/dist/ui/assets/index-DMEwxqAV.css +1 -0
- package/dist/ui/assets/providers/agy.png +0 -0
- package/dist/ui/assets/providers/gemini-color.svg +1 -0
- package/dist/ui/assets/providers/openai.svg +1 -0
- package/dist/ui/assets/providers/qwen-color.svg +1 -0
- package/dist/ui/assets/{radix-ui-CgfZoNEt.js → radix-ui-OFtPgiRV.js} +1 -1
- package/dist/ui/assets/{settings-DUCWbKbP.js → settings-Dh8DSszQ.js} +1 -1
- package/dist/ui/assets/{shared-Da5f_jsc.js → shared-n31ZWpeq.js} +1 -1
- package/dist/ui/assets/{tanstack-BgSYOn90.js → tanstack-DMWkeNzM.js} +1 -1
- package/dist/ui/index.html +5 -5
- package/dist/web-server/routes.d.ts.map +1 -1
- package/dist/web-server/routes.js +329 -4
- package/dist/web-server/routes.js.map +1 -1
- package/package.json +1 -1
- package/scripts/verify-bundle.js +11 -4
- package/dist/ui/assets/accounts-CTh48XsV.js +0 -1
- package/dist/ui/assets/analytics-CeU8ZE3O.js +0 -64
- package/dist/ui/assets/cliproxy-Cy2Bjv-c.js +0 -1
- package/dist/ui/assets/health-DyAiAnv0.js +0 -1
- package/dist/ui/assets/icons-CRbZgamU.js +0 -1
- package/dist/ui/assets/index-BIVAVDH5.js +0 -10
- package/dist/ui/assets/index-vojI8oaQ.css +0 -1
- package/dist/ui/assets/table-BCRYixSo.js +0 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI Compatibility Layer Manager
|
|
4
|
+
*
|
|
5
|
+
* Manages OpenAI-compatible providers (OpenRouter, Together, etc.)
|
|
6
|
+
* in CLIProxyAPI's config.yaml.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
25
|
+
if (mod && mod.__esModule) return mod;
|
|
26
|
+
var result = {};
|
|
27
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
28
|
+
__setModuleDefault(result, mod);
|
|
29
|
+
return result;
|
|
30
|
+
};
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.TOGETHER_TEMPLATE = exports.OPENROUTER_TEMPLATE = exports.removeOpenAICompatProvider = exports.updateOpenAICompatProvider = exports.addOpenAICompatProvider = exports.getOpenAICompatProvider = exports.listOpenAICompatProviders = void 0;
|
|
33
|
+
const fs = __importStar(require("fs"));
|
|
34
|
+
const yaml = __importStar(require("js-yaml"));
|
|
35
|
+
const config_generator_1 = require("./config-generator");
|
|
36
|
+
/**
|
|
37
|
+
* Load current config.yaml
|
|
38
|
+
*/
|
|
39
|
+
function loadConfig() {
|
|
40
|
+
const configPath = (0, config_generator_1.getConfigPath)();
|
|
41
|
+
if (!fs.existsSync(configPath)) {
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const content = fs.readFileSync(configPath, 'utf-8');
|
|
46
|
+
return yaml.load(content) || {};
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Save config.yaml with proper formatting
|
|
54
|
+
*/
|
|
55
|
+
function saveConfig(config) {
|
|
56
|
+
const configPath = (0, config_generator_1.getConfigPath)();
|
|
57
|
+
const content = yaml.dump(config, {
|
|
58
|
+
lineWidth: -1, // Disable line wrapping
|
|
59
|
+
quotingType: '"',
|
|
60
|
+
forceQuotes: false,
|
|
61
|
+
});
|
|
62
|
+
fs.writeFileSync(configPath, content, { mode: 0o600 });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* List all configured OpenAI-compatible providers
|
|
66
|
+
*/
|
|
67
|
+
function listOpenAICompatProviders() {
|
|
68
|
+
const config = loadConfig();
|
|
69
|
+
const providers = config['openai-compatibility'] || [];
|
|
70
|
+
return providers.map((p) => ({
|
|
71
|
+
name: p.name,
|
|
72
|
+
baseUrl: p['base-url'],
|
|
73
|
+
apiKey: p['api-key-entries']?.[0]?.['api-key'] || '',
|
|
74
|
+
models: (p.models || []).map((m) => ({
|
|
75
|
+
name: m.name,
|
|
76
|
+
alias: m.alias,
|
|
77
|
+
})),
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
exports.listOpenAICompatProviders = listOpenAICompatProviders;
|
|
81
|
+
/**
|
|
82
|
+
* Get a specific provider by name
|
|
83
|
+
*/
|
|
84
|
+
function getOpenAICompatProvider(name) {
|
|
85
|
+
const providers = listOpenAICompatProviders();
|
|
86
|
+
return providers.find((p) => p.name === name) || null;
|
|
87
|
+
}
|
|
88
|
+
exports.getOpenAICompatProvider = getOpenAICompatProvider;
|
|
89
|
+
/**
|
|
90
|
+
* Add a new OpenAI-compatible provider
|
|
91
|
+
* @throws Error if provider with same name already exists
|
|
92
|
+
*/
|
|
93
|
+
function addOpenAICompatProvider(provider) {
|
|
94
|
+
const config = loadConfig();
|
|
95
|
+
// Initialize array if not exists
|
|
96
|
+
if (!config['openai-compatibility']) {
|
|
97
|
+
config['openai-compatibility'] = [];
|
|
98
|
+
}
|
|
99
|
+
// Check for duplicate
|
|
100
|
+
const existing = config['openai-compatibility'].find((p) => p.name === provider.name);
|
|
101
|
+
if (existing) {
|
|
102
|
+
throw new Error(`Provider '${provider.name}' already exists`);
|
|
103
|
+
}
|
|
104
|
+
// Add new provider
|
|
105
|
+
config['openai-compatibility'].push({
|
|
106
|
+
name: provider.name,
|
|
107
|
+
'base-url': provider.baseUrl,
|
|
108
|
+
'api-key-entries': [{ 'api-key': provider.apiKey }],
|
|
109
|
+
models: provider.models.map((m) => ({
|
|
110
|
+
name: m.name,
|
|
111
|
+
alias: m.alias,
|
|
112
|
+
})),
|
|
113
|
+
});
|
|
114
|
+
saveConfig(config);
|
|
115
|
+
}
|
|
116
|
+
exports.addOpenAICompatProvider = addOpenAICompatProvider;
|
|
117
|
+
/**
|
|
118
|
+
* Update an existing provider
|
|
119
|
+
* @throws Error if provider doesn't exist
|
|
120
|
+
*/
|
|
121
|
+
function updateOpenAICompatProvider(name, updates) {
|
|
122
|
+
const config = loadConfig();
|
|
123
|
+
if (!config['openai-compatibility']) {
|
|
124
|
+
throw new Error(`Provider '${name}' not found`);
|
|
125
|
+
}
|
|
126
|
+
const index = config['openai-compatibility'].findIndex((p) => p.name === name);
|
|
127
|
+
if (index === -1) {
|
|
128
|
+
throw new Error(`Provider '${name}' not found`);
|
|
129
|
+
}
|
|
130
|
+
const provider = config['openai-compatibility'][index];
|
|
131
|
+
// Apply updates
|
|
132
|
+
if (updates.baseUrl) {
|
|
133
|
+
provider['base-url'] = updates.baseUrl;
|
|
134
|
+
}
|
|
135
|
+
if (updates.apiKey) {
|
|
136
|
+
provider['api-key-entries'] = [{ 'api-key': updates.apiKey }];
|
|
137
|
+
}
|
|
138
|
+
if (updates.models) {
|
|
139
|
+
provider.models = updates.models.map((m) => ({
|
|
140
|
+
name: m.name,
|
|
141
|
+
alias: m.alias,
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
if (updates.name && updates.name !== name) {
|
|
145
|
+
provider.name = updates.name;
|
|
146
|
+
}
|
|
147
|
+
saveConfig(config);
|
|
148
|
+
}
|
|
149
|
+
exports.updateOpenAICompatProvider = updateOpenAICompatProvider;
|
|
150
|
+
/**
|
|
151
|
+
* Remove a provider
|
|
152
|
+
* @returns true if removed, false if not found
|
|
153
|
+
*/
|
|
154
|
+
function removeOpenAICompatProvider(name) {
|
|
155
|
+
const config = loadConfig();
|
|
156
|
+
if (!config['openai-compatibility']) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
const index = config['openai-compatibility'].findIndex((p) => p.name === name);
|
|
160
|
+
if (index === -1) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
config['openai-compatibility'].splice(index, 1);
|
|
164
|
+
// Remove empty array
|
|
165
|
+
if (config['openai-compatibility'].length === 0) {
|
|
166
|
+
delete config['openai-compatibility'];
|
|
167
|
+
}
|
|
168
|
+
saveConfig(config);
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
exports.removeOpenAICompatProvider = removeOpenAICompatProvider;
|
|
172
|
+
/** Pre-configured OpenRouter template */
|
|
173
|
+
exports.OPENROUTER_TEMPLATE = {
|
|
174
|
+
name: 'openrouter',
|
|
175
|
+
baseUrl: 'https://openrouter.ai/api/v1',
|
|
176
|
+
models: [
|
|
177
|
+
{ name: 'anthropic/claude-3.5-sonnet', alias: 'claude-sonnet' },
|
|
178
|
+
{ name: 'anthropic/claude-3-opus', alias: 'claude-opus' },
|
|
179
|
+
{ name: 'google/gemini-pro-1.5', alias: 'gemini-pro' },
|
|
180
|
+
],
|
|
181
|
+
};
|
|
182
|
+
/** Pre-configured Together template */
|
|
183
|
+
exports.TOGETHER_TEMPLATE = {
|
|
184
|
+
name: 'together',
|
|
185
|
+
baseUrl: 'https://api.together.xyz/v1',
|
|
186
|
+
models: [
|
|
187
|
+
{ name: 'meta-llama/Llama-3-70b-chat-hf', alias: 'llama-70b' },
|
|
188
|
+
{ name: 'mistralai/Mixtral-8x7B-Instruct-v0.1', alias: 'mixtral' },
|
|
189
|
+
],
|
|
190
|
+
};
|
|
191
|
+
//# sourceMappingURL=openai-compat-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compat-manager.js","sourceRoot":"","sources":["../../src/cliproxy/openai-compat-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLIProxy Service Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages CLIProxyAPI as a background service for the CCS dashboard.
|
|
5
|
+
* Ensures the proxy is running when needed for:
|
|
6
|
+
* - Control Panel integration (management.html)
|
|
7
|
+
* - Stats fetching
|
|
8
|
+
* - OAuth flows
|
|
9
|
+
*
|
|
10
|
+
* Unlike cliproxy-executor.ts which runs proxy per-session,
|
|
11
|
+
* this module manages a persistent background instance.
|
|
12
|
+
*/
|
|
13
|
+
export interface ServiceStartResult {
|
|
14
|
+
started: boolean;
|
|
15
|
+
alreadyRunning: boolean;
|
|
16
|
+
port: number;
|
|
17
|
+
configRegenerated?: boolean;
|
|
18
|
+
error?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Ensure CLIProxy service is running
|
|
22
|
+
*
|
|
23
|
+
* If proxy is already running, returns immediately.
|
|
24
|
+
* If not, spawns a new background instance.
|
|
25
|
+
*
|
|
26
|
+
* @param port CLIProxy port (default: 8317)
|
|
27
|
+
* @param verbose Show debug output
|
|
28
|
+
* @returns Result indicating success and whether it was already running
|
|
29
|
+
*/
|
|
30
|
+
export declare function ensureCliproxyService(port?: number, verbose?: boolean): Promise<ServiceStartResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Stop the managed CLIProxy service
|
|
33
|
+
*/
|
|
34
|
+
export declare function stopCliproxyService(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Get service status
|
|
37
|
+
*/
|
|
38
|
+
export declare function getServiceStatus(port?: number): Promise<{
|
|
39
|
+
running: boolean;
|
|
40
|
+
managedByUs: boolean;
|
|
41
|
+
port: number;
|
|
42
|
+
}>;
|
|
43
|
+
//# sourceMappingURL=service-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-manager.d.ts","sourceRoot":"","sources":["../../src/cliproxy/service-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA6EH,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,GAAE,MAA8B,EACpC,OAAO,GAAE,OAAe,GACvB,OAAO,CAAC,kBAAkB,CAAC,CA4G7B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAO7C;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,GAAE,MAA8B,GAAG,OAAO,CAAC;IACpF,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC,CAKD"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLIProxy Service Manager
|
|
4
|
+
*
|
|
5
|
+
* Manages CLIProxyAPI as a background service for the CCS dashboard.
|
|
6
|
+
* Ensures the proxy is running when needed for:
|
|
7
|
+
* - Control Panel integration (management.html)
|
|
8
|
+
* - Stats fetching
|
|
9
|
+
* - OAuth flows
|
|
10
|
+
*
|
|
11
|
+
* Unlike cliproxy-executor.ts which runs proxy per-session,
|
|
12
|
+
* this module manages a persistent background instance.
|
|
13
|
+
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.getServiceStatus = exports.stopCliproxyService = exports.ensureCliproxyService = void 0;
|
|
39
|
+
const child_process_1 = require("child_process");
|
|
40
|
+
const net = __importStar(require("net"));
|
|
41
|
+
const binary_manager_1 = require("./binary-manager");
|
|
42
|
+
const config_generator_1 = require("./config-generator");
|
|
43
|
+
const stats_fetcher_1 = require("./stats-fetcher");
|
|
44
|
+
/** Background proxy process reference */
|
|
45
|
+
let proxyProcess = null;
|
|
46
|
+
/** Cleanup registered flag */
|
|
47
|
+
let cleanupRegistered = false;
|
|
48
|
+
/**
|
|
49
|
+
* Wait for TCP port to become available
|
|
50
|
+
*/
|
|
51
|
+
async function waitForPort(port, timeout = 5000, pollInterval = 100) {
|
|
52
|
+
const start = Date.now();
|
|
53
|
+
while (Date.now() - start < timeout) {
|
|
54
|
+
try {
|
|
55
|
+
await new Promise((resolve, reject) => {
|
|
56
|
+
const socket = net.createConnection({ port, host: '127.0.0.1' }, () => {
|
|
57
|
+
socket.destroy();
|
|
58
|
+
resolve();
|
|
59
|
+
});
|
|
60
|
+
socket.on('error', (err) => {
|
|
61
|
+
socket.destroy();
|
|
62
|
+
reject(err);
|
|
63
|
+
});
|
|
64
|
+
socket.setTimeout(500, () => {
|
|
65
|
+
socket.destroy();
|
|
66
|
+
reject(new Error('Connection timeout'));
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
return true; // Connection successful
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Register cleanup handlers to stop proxy on process exit
|
|
79
|
+
*/
|
|
80
|
+
function registerCleanup() {
|
|
81
|
+
if (cleanupRegistered)
|
|
82
|
+
return;
|
|
83
|
+
const cleanup = () => {
|
|
84
|
+
if (proxyProcess && !proxyProcess.killed) {
|
|
85
|
+
proxyProcess.kill('SIGTERM');
|
|
86
|
+
proxyProcess = null;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
process.once('exit', cleanup);
|
|
90
|
+
process.once('SIGTERM', cleanup);
|
|
91
|
+
process.once('SIGINT', cleanup);
|
|
92
|
+
cleanupRegistered = true;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Ensure CLIProxy service is running
|
|
96
|
+
*
|
|
97
|
+
* If proxy is already running, returns immediately.
|
|
98
|
+
* If not, spawns a new background instance.
|
|
99
|
+
*
|
|
100
|
+
* @param port CLIProxy port (default: 8317)
|
|
101
|
+
* @param verbose Show debug output
|
|
102
|
+
* @returns Result indicating success and whether it was already running
|
|
103
|
+
*/
|
|
104
|
+
async function ensureCliproxyService(port = config_generator_1.CLIPROXY_DEFAULT_PORT, verbose = false) {
|
|
105
|
+
const log = (msg) => {
|
|
106
|
+
if (verbose) {
|
|
107
|
+
console.error(`[cliproxy-service] ${msg}`);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
// Check if already running (from another process or previous start)
|
|
111
|
+
log(`Checking if CLIProxy is running on port ${port}...`);
|
|
112
|
+
const running = await (0, stats_fetcher_1.isCliproxyRunning)(port);
|
|
113
|
+
// Check if config needs update (even if running)
|
|
114
|
+
let configRegenerated = false;
|
|
115
|
+
if ((0, config_generator_1.configNeedsRegeneration)()) {
|
|
116
|
+
log('Config outdated, regenerating...');
|
|
117
|
+
(0, config_generator_1.regenerateConfig)(port);
|
|
118
|
+
configRegenerated = true;
|
|
119
|
+
}
|
|
120
|
+
if (running) {
|
|
121
|
+
log('CLIProxy already running');
|
|
122
|
+
if (configRegenerated) {
|
|
123
|
+
log('Config was updated - running instance will use new config on next restart');
|
|
124
|
+
}
|
|
125
|
+
return { started: true, alreadyRunning: true, port, configRegenerated };
|
|
126
|
+
}
|
|
127
|
+
// Need to start new instance
|
|
128
|
+
log('CLIProxy not running, starting background instance...');
|
|
129
|
+
// 1. Ensure binary exists
|
|
130
|
+
let binaryPath;
|
|
131
|
+
try {
|
|
132
|
+
binaryPath = await (0, binary_manager_1.ensureCLIProxyBinary)(verbose);
|
|
133
|
+
log(`Binary ready: ${binaryPath}`);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const err = error;
|
|
137
|
+
return {
|
|
138
|
+
started: false,
|
|
139
|
+
alreadyRunning: false,
|
|
140
|
+
port,
|
|
141
|
+
error: `Failed to prepare binary: ${err.message}`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// 2. Ensure/regenerate config if needed
|
|
145
|
+
let configPath;
|
|
146
|
+
if ((0, config_generator_1.configNeedsRegeneration)()) {
|
|
147
|
+
log('Config needs regeneration, updating...');
|
|
148
|
+
configPath = (0, config_generator_1.regenerateConfig)(port);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
// generateConfig only creates if doesn't exist
|
|
152
|
+
configPath = (0, config_generator_1.generateConfig)('gemini', port); // Provider doesn't matter for unified config
|
|
153
|
+
}
|
|
154
|
+
log(`Config ready: ${configPath}`);
|
|
155
|
+
// 3. Spawn background process
|
|
156
|
+
const proxyArgs = ['--config', configPath];
|
|
157
|
+
log(`Spawning: ${binaryPath} ${proxyArgs.join(' ')}`);
|
|
158
|
+
proxyProcess = (0, child_process_1.spawn)(binaryPath, proxyArgs, {
|
|
159
|
+
stdio: ['ignore', verbose ? 'pipe' : 'ignore', verbose ? 'pipe' : 'ignore'],
|
|
160
|
+
detached: true, // Allow process to run independently
|
|
161
|
+
});
|
|
162
|
+
// Forward output in verbose mode
|
|
163
|
+
if (verbose) {
|
|
164
|
+
proxyProcess.stdout?.on('data', (data) => {
|
|
165
|
+
process.stderr.write(`[cliproxy] ${data.toString()}`);
|
|
166
|
+
});
|
|
167
|
+
proxyProcess.stderr?.on('data', (data) => {
|
|
168
|
+
process.stderr.write(`[cliproxy-err] ${data.toString()}`);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// Don't let this process prevent parent from exiting
|
|
172
|
+
proxyProcess.unref();
|
|
173
|
+
// Handle spawn errors
|
|
174
|
+
proxyProcess.on('error', (error) => {
|
|
175
|
+
log(`Spawn error: ${error.message}`);
|
|
176
|
+
});
|
|
177
|
+
// Register cleanup handlers
|
|
178
|
+
registerCleanup();
|
|
179
|
+
// 4. Wait for proxy to be ready
|
|
180
|
+
log(`Waiting for CLIProxy on port ${port}...`);
|
|
181
|
+
const ready = await waitForPort(port, 5000);
|
|
182
|
+
if (!ready) {
|
|
183
|
+
// Kill failed process
|
|
184
|
+
if (proxyProcess && !proxyProcess.killed) {
|
|
185
|
+
proxyProcess.kill('SIGTERM');
|
|
186
|
+
proxyProcess = null;
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
started: false,
|
|
190
|
+
alreadyRunning: false,
|
|
191
|
+
port,
|
|
192
|
+
error: `CLIProxy failed to start within 5s on port ${port}`,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
log(`CLIProxy service started on port ${port}`);
|
|
196
|
+
return { started: true, alreadyRunning: false, port };
|
|
197
|
+
}
|
|
198
|
+
exports.ensureCliproxyService = ensureCliproxyService;
|
|
199
|
+
/**
|
|
200
|
+
* Stop the managed CLIProxy service
|
|
201
|
+
*/
|
|
202
|
+
function stopCliproxyService() {
|
|
203
|
+
if (proxyProcess && !proxyProcess.killed) {
|
|
204
|
+
proxyProcess.kill('SIGTERM');
|
|
205
|
+
proxyProcess = null;
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
exports.stopCliproxyService = stopCliproxyService;
|
|
211
|
+
/**
|
|
212
|
+
* Get service status
|
|
213
|
+
*/
|
|
214
|
+
async function getServiceStatus(port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
|
|
215
|
+
const running = await (0, stats_fetcher_1.isCliproxyRunning)(port);
|
|
216
|
+
const managedByUs = proxyProcess !== null && !proxyProcess.killed;
|
|
217
|
+
return { running, managedByUs, port };
|
|
218
|
+
}
|
|
219
|
+
exports.getServiceStatus = getServiceStatus;
|
|
220
|
+
//# sourceMappingURL=service-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-manager.js","sourceRoot":"","sources":["../../src/cliproxy/service-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLIProxyAPI Stats Fetcher
|
|
3
|
+
*
|
|
4
|
+
* Fetches usage statistics from CLIProxyAPI's management API.
|
|
5
|
+
* Requires usage-statistics-enabled: true in config.yaml.
|
|
6
|
+
*/
|
|
7
|
+
/** Usage statistics from CLIProxyAPI */
|
|
8
|
+
export interface CliproxyStats {
|
|
9
|
+
/** Total number of requests processed */
|
|
10
|
+
totalRequests: number;
|
|
11
|
+
/** Token counts */
|
|
12
|
+
tokens: {
|
|
13
|
+
input: number;
|
|
14
|
+
output: number;
|
|
15
|
+
total: number;
|
|
16
|
+
};
|
|
17
|
+
/** Requests grouped by model */
|
|
18
|
+
requestsByModel: Record<string, number>;
|
|
19
|
+
/** Requests grouped by provider */
|
|
20
|
+
requestsByProvider: Record<string, number>;
|
|
21
|
+
/** Number of quota exceeded (429) events */
|
|
22
|
+
quotaExceededCount: number;
|
|
23
|
+
/** Number of request retries */
|
|
24
|
+
retryCount: number;
|
|
25
|
+
/** Timestamp of stats collection */
|
|
26
|
+
collectedAt: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Fetch usage statistics from CLIProxyAPI management API
|
|
30
|
+
* @param port CLIProxyAPI port (default: 8317)
|
|
31
|
+
* @returns Stats object or null if unavailable
|
|
32
|
+
*/
|
|
33
|
+
export declare function fetchCliproxyStats(port?: number): Promise<CliproxyStats | null>;
|
|
34
|
+
/** OpenAI-compatible model object from /v1/models endpoint */
|
|
35
|
+
export interface CliproxyModel {
|
|
36
|
+
id: string;
|
|
37
|
+
object: string;
|
|
38
|
+
created: number;
|
|
39
|
+
owned_by: string;
|
|
40
|
+
}
|
|
41
|
+
/** Categorized models response for UI */
|
|
42
|
+
export interface CliproxyModelsResponse {
|
|
43
|
+
models: CliproxyModel[];
|
|
44
|
+
byCategory: Record<string, CliproxyModel[]>;
|
|
45
|
+
totalCount: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Fetch available models from CLIProxyAPI /v1/models endpoint
|
|
49
|
+
* @param port CLIProxyAPI port (default: 8317)
|
|
50
|
+
* @returns Categorized models or null if unavailable
|
|
51
|
+
*/
|
|
52
|
+
export declare function fetchCliproxyModels(port?: number): Promise<CliproxyModelsResponse | null>;
|
|
53
|
+
/**
|
|
54
|
+
* Check if CLIProxyAPI is running and responsive
|
|
55
|
+
* @param port CLIProxyAPI port (default: 8317)
|
|
56
|
+
* @returns true if proxy is running
|
|
57
|
+
*/
|
|
58
|
+
export declare function isCliproxyRunning(port?: number): Promise<boolean>;
|
|
59
|
+
//# sourceMappingURL=stats-fetcher.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLIProxyAPI Stats Fetcher
|
|
4
|
+
*
|
|
5
|
+
* Fetches usage statistics from CLIProxyAPI's management API.
|
|
6
|
+
* Requires usage-statistics-enabled: true in config.yaml.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.isCliproxyRunning = exports.fetchCliproxyModels = exports.fetchCliproxyStats = void 0;
|
|
10
|
+
const config_generator_1 = require("./config-generator");
|
|
11
|
+
/**
|
|
12
|
+
* Fetch usage statistics from CLIProxyAPI management API
|
|
13
|
+
* @param port CLIProxyAPI port (default: 8317)
|
|
14
|
+
* @returns Stats object or null if unavailable
|
|
15
|
+
*/
|
|
16
|
+
async function fetchCliproxyStats(port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
|
|
17
|
+
try {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timeoutId = setTimeout(() => controller.abort(), 3000); // 3s timeout
|
|
20
|
+
const response = await fetch(`http://127.0.0.1:${port}/v0/management/usage`, {
|
|
21
|
+
signal: controller.signal,
|
|
22
|
+
headers: {
|
|
23
|
+
Accept: 'application/json',
|
|
24
|
+
Authorization: `Bearer ${config_generator_1.CCS_CONTROL_PANEL_SECRET}`,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
clearTimeout(timeoutId);
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const data = (await response.json());
|
|
32
|
+
const usage = data.usage;
|
|
33
|
+
// Extract models and providers from the nested API structure
|
|
34
|
+
const requestsByModel = {};
|
|
35
|
+
const requestsByProvider = {};
|
|
36
|
+
if (usage?.apis) {
|
|
37
|
+
for (const [provider, providerData] of Object.entries(usage.apis)) {
|
|
38
|
+
requestsByProvider[provider] = providerData.total_requests ?? 0;
|
|
39
|
+
if (providerData.models) {
|
|
40
|
+
for (const [model, modelData] of Object.entries(providerData.models)) {
|
|
41
|
+
requestsByModel[model] = modelData.total_requests ?? 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Normalize the response to our interface
|
|
47
|
+
return {
|
|
48
|
+
totalRequests: usage?.total_requests ?? 0,
|
|
49
|
+
tokens: {
|
|
50
|
+
input: 0, // API doesn't provide input/output breakdown
|
|
51
|
+
output: 0,
|
|
52
|
+
total: usage?.total_tokens ?? 0,
|
|
53
|
+
},
|
|
54
|
+
requestsByModel,
|
|
55
|
+
requestsByProvider,
|
|
56
|
+
quotaExceededCount: usage?.failure_count ?? data.failed_requests ?? 0,
|
|
57
|
+
retryCount: 0, // API doesn't track retries separately
|
|
58
|
+
collectedAt: new Date().toISOString(),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// CLIProxyAPI not running or stats endpoint not available
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.fetchCliproxyStats = fetchCliproxyStats;
|
|
67
|
+
/**
|
|
68
|
+
* Fetch available models from CLIProxyAPI /v1/models endpoint
|
|
69
|
+
* @param port CLIProxyAPI port (default: 8317)
|
|
70
|
+
* @returns Categorized models or null if unavailable
|
|
71
|
+
*/
|
|
72
|
+
async function fetchCliproxyModels(port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
|
|
73
|
+
try {
|
|
74
|
+
const controller = new AbortController();
|
|
75
|
+
const timeoutId = setTimeout(() => controller.abort(), 3000);
|
|
76
|
+
const response = await fetch(`http://127.0.0.1:${port}/v1/models`, {
|
|
77
|
+
signal: controller.signal,
|
|
78
|
+
headers: {
|
|
79
|
+
Accept: 'application/json',
|
|
80
|
+
// Use the internal API key for /v1 endpoints
|
|
81
|
+
Authorization: 'Bearer ccs-internal-managed',
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
clearTimeout(timeoutId);
|
|
85
|
+
if (!response.ok) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const data = (await response.json());
|
|
89
|
+
// Group models by owned_by field
|
|
90
|
+
const byCategory = {};
|
|
91
|
+
for (const model of data.data) {
|
|
92
|
+
const category = model.owned_by || 'other';
|
|
93
|
+
if (!byCategory[category]) {
|
|
94
|
+
byCategory[category] = [];
|
|
95
|
+
}
|
|
96
|
+
byCategory[category].push(model);
|
|
97
|
+
}
|
|
98
|
+
// Sort models within each category alphabetically
|
|
99
|
+
for (const category of Object.keys(byCategory)) {
|
|
100
|
+
byCategory[category].sort((a, b) => a.id.localeCompare(b.id));
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
models: data.data,
|
|
104
|
+
byCategory,
|
|
105
|
+
totalCount: data.data.length,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.fetchCliproxyModels = fetchCliproxyModels;
|
|
113
|
+
/**
|
|
114
|
+
* Check if CLIProxyAPI is running and responsive
|
|
115
|
+
* @param port CLIProxyAPI port (default: 8317)
|
|
116
|
+
* @returns true if proxy is running
|
|
117
|
+
*/
|
|
118
|
+
async function isCliproxyRunning(port = config_generator_1.CLIPROXY_DEFAULT_PORT) {
|
|
119
|
+
try {
|
|
120
|
+
const controller = new AbortController();
|
|
121
|
+
const timeoutId = setTimeout(() => controller.abort(), 1000); // 1s timeout
|
|
122
|
+
// Use root endpoint - CLIProxyAPI returns server info at /
|
|
123
|
+
const response = await fetch(`http://127.0.0.1:${port}/`, {
|
|
124
|
+
signal: controller.signal,
|
|
125
|
+
});
|
|
126
|
+
clearTimeout(timeoutId);
|
|
127
|
+
return response.ok;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.isCliproxyRunning = isCliproxyRunning;
|
|
134
|
+
//# sourceMappingURL=stats-fetcher.js.map
|