coding-tool-x 3.4.4 → 3.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/web/assets/{Analytics-_Byi9M6y.js → Analytics-DFWyPf5C.js} +1 -1
- package/dist/web/assets/{ConfigTemplates-DIwosdtG.js → ConfigTemplates-BFE7hmKd.js} +1 -1
- package/dist/web/assets/{Home-DdNMuQ9c.js → Home-DZUuCrxk.js} +1 -1
- package/dist/web/assets/{PluginManager-iuY24cnW.js → PluginManager-WyGY2BQN.js} +1 -1
- package/dist/web/assets/{ProjectList-DSkMulzL.js → ProjectList-CBc0QawN.js} +1 -1
- package/dist/web/assets/{SessionList-B6pGquIr.js → SessionList-CdPR7QLq.js} +1 -1
- package/dist/web/assets/{SkillManager-CHtQX5r8.js → SkillManager-B5-DxQOS.js} +1 -1
- package/dist/web/assets/{WorkspaceManager-gNPs-VaI.js → WorkspaceManager-C7yqFjpi.js} +1 -1
- package/dist/web/assets/index-BDsmoSfO.js +2 -0
- package/dist/web/assets/{index-pMqqe9ei.css → index-C1pzEgmj.css} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +2 -2
- package/src/server/api/claude-hooks.js +1 -0
- package/src/server/api/plugins.js +161 -14
- package/src/server/api/skills.js +62 -7
- package/src/server/codex-proxy-server.js +10 -2
- package/src/server/gemini-proxy-server.js +10 -2
- package/src/server/opencode-proxy-server.js +10 -2
- package/src/server/proxy-server.js +10 -2
- package/src/server/services/codex-channels.js +64 -21
- package/src/server/services/codex-env-manager.js +44 -28
- package/src/server/services/plugins-service.js +1060 -235
- package/src/server/services/proxy-runtime.js +129 -5
- package/src/server/services/server-shutdown.js +79 -0
- package/src/server/services/skill-service.js +142 -17
- package/dist/web/assets/index-DGjGCo37.js +0 -2
package/dist/web/index.html
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
<link rel="icon" href="/favicon.ico">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<title>CC-TOOL - ClaudeCode增强工作助手</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-BDsmoSfO.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/markdown-DyTJGI4N.js">
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vue-vendor-3bf-fPGP.js">
|
|
11
11
|
<link rel="modulepreload" crossorigin href="/assets/vendors-CKPV1OAU.js">
|
|
12
12
|
<link rel="modulepreload" crossorigin href="/assets/naive-ui-Bdxp09n2.js">
|
|
13
13
|
<link rel="modulepreload" crossorigin href="/assets/icons-B5Pl4lrD.js">
|
|
14
14
|
<link rel="stylesheet" crossorigin href="/assets/markdown-BfC0goYb.css">
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-C1pzEgmj.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="app"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coding-tool-x",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.5",
|
|
4
4
|
"description": "Vibe Coding 增强工作助手 - 智能会话管理、动态渠道切换、全局搜索、实时监控",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node bin/ctx.js",
|
|
11
11
|
"test": "npm run test:basic && npm run test:api && npm run test:codex-agents && npm run test:skills && npm run test:plugins-market",
|
|
12
|
-
"test:basic": "node scripts/test-basic.js",
|
|
12
|
+
"test:basic": "node scripts/test-basic.js && npm run test:unit",
|
|
13
13
|
"test:api": "node scripts/test-api-consistency.js",
|
|
14
14
|
"test:codex-agents": "node scripts/test-codex-agents.js",
|
|
15
15
|
"test:skills": "node scripts/test-skill-providers.js",
|
|
@@ -543,6 +543,7 @@ router.post('/test', (req, res) => {
|
|
|
543
543
|
const command = generateSystemNotificationCommand(type || 'notification');
|
|
544
544
|
const { execSync } = require('child_process');
|
|
545
545
|
execSync(command, { stdio: 'ignore', windowsHide: true });
|
|
546
|
+
res.json({ success: true, message: '系统测试通知已发送' });
|
|
546
547
|
}
|
|
547
548
|
} catch (error) {
|
|
548
549
|
console.error('Error testing notification:', error);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const express = require('express');
|
|
8
8
|
const { PluginsService } = require('../services/plugins-service');
|
|
9
|
+
const { maskToken } = require('../services/oauth-utils');
|
|
9
10
|
|
|
10
11
|
const router = express.Router();
|
|
11
12
|
const SUPPORTED_PLATFORMS = ['claude', 'opencode'];
|
|
@@ -27,6 +28,41 @@ function getPluginsService(req) {
|
|
|
27
28
|
return { platform, service: pluginServices.get(platform) };
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
function extractRepoPayload(source = {}) {
|
|
32
|
+
const repo = source.repo && typeof source.repo === 'object' ? source.repo : source;
|
|
33
|
+
return {
|
|
34
|
+
id: repo.id || source.repoId || '',
|
|
35
|
+
provider: repo.provider || source.provider || '',
|
|
36
|
+
host: repo.host || source.host || '',
|
|
37
|
+
owner: repo.owner || source.owner || '',
|
|
38
|
+
name: repo.name || source.name || '',
|
|
39
|
+
branch: repo.branch || source.branch || 'main',
|
|
40
|
+
directory: repo.directory || source.directory || '',
|
|
41
|
+
projectPath: repo.projectPath || source.projectPath || '',
|
|
42
|
+
localPath: repo.localPath || source.localPath || '',
|
|
43
|
+
repoUrl: repo.repoUrl || repo.url || source.repoUrl || source.url || '',
|
|
44
|
+
token: repo.token || source.token || ''
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function sanitizeRepo(repo = {}) {
|
|
49
|
+
const token = String(repo.token || '').trim();
|
|
50
|
+
const sanitized = {
|
|
51
|
+
...repo,
|
|
52
|
+
hasToken: Boolean(token),
|
|
53
|
+
tokenPreview: token ? maskToken(token) : ''
|
|
54
|
+
};
|
|
55
|
+
delete sanitized.token;
|
|
56
|
+
return sanitized;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function sanitizeRepos(service, repos = []) {
|
|
60
|
+
if (typeof service.getReposForClient === 'function') {
|
|
61
|
+
return service.getReposForClient(repos);
|
|
62
|
+
}
|
|
63
|
+
return (Array.isArray(repos) ? repos : []).map(sanitizeRepo);
|
|
64
|
+
}
|
|
65
|
+
|
|
30
66
|
/**
|
|
31
67
|
* 获取插件列表
|
|
32
68
|
* GET /api/plugins
|
|
@@ -93,7 +129,7 @@ router.post('/install', async (req, res) => {
|
|
|
93
129
|
if (source) {
|
|
94
130
|
installUrl = source;
|
|
95
131
|
} else if (directory && repo) {
|
|
96
|
-
installUrl =
|
|
132
|
+
installUrl = '';
|
|
97
133
|
} else if (gitUrl) {
|
|
98
134
|
installUrl = gitUrl;
|
|
99
135
|
} else {
|
|
@@ -103,7 +139,15 @@ router.post('/install', async (req, res) => {
|
|
|
103
139
|
});
|
|
104
140
|
}
|
|
105
141
|
|
|
106
|
-
const result = await service.installPlugin(
|
|
142
|
+
const result = await service.installPlugin(
|
|
143
|
+
installUrl,
|
|
144
|
+
directory && repo
|
|
145
|
+
? {
|
|
146
|
+
...extractRepoPayload({ repo }),
|
|
147
|
+
directory
|
|
148
|
+
}
|
|
149
|
+
: null
|
|
150
|
+
);
|
|
107
151
|
|
|
108
152
|
if (!result.success) {
|
|
109
153
|
return res.status(400).json({
|
|
@@ -140,7 +184,7 @@ router.get('/repos', (req, res) => {
|
|
|
140
184
|
res.json({
|
|
141
185
|
success: true,
|
|
142
186
|
platform,
|
|
143
|
-
repos
|
|
187
|
+
repos: sanitizeRepos(service, repos)
|
|
144
188
|
});
|
|
145
189
|
} catch (err) {
|
|
146
190
|
console.error('[Plugins API] Get repos error:', err);
|
|
@@ -159,12 +203,13 @@ router.get('/repos', (req, res) => {
|
|
|
159
203
|
router.post('/repos', (req, res) => {
|
|
160
204
|
try {
|
|
161
205
|
const { platform, service } = getPluginsService(req);
|
|
162
|
-
const repo = req.body;
|
|
206
|
+
const repo = extractRepoPayload(req.body);
|
|
207
|
+
repo.enabled = req.body.enabled !== false;
|
|
163
208
|
|
|
164
|
-
if (!repo || !repo.
|
|
209
|
+
if (!repo.localPath && !repo.projectPath && (!repo.owner || !repo.name) && !repo.repoUrl) {
|
|
165
210
|
return res.status(400).json({
|
|
166
211
|
success: false,
|
|
167
|
-
message: '
|
|
212
|
+
message: 'Missing repo info'
|
|
168
213
|
});
|
|
169
214
|
}
|
|
170
215
|
|
|
@@ -173,7 +218,7 @@ router.post('/repos', (req, res) => {
|
|
|
173
218
|
res.json({
|
|
174
219
|
success: true,
|
|
175
220
|
platform,
|
|
176
|
-
repos,
|
|
221
|
+
repos: sanitizeRepos(service, repos),
|
|
177
222
|
message: 'Repository added successfully'
|
|
178
223
|
});
|
|
179
224
|
} catch (err) {
|
|
@@ -185,6 +230,54 @@ router.post('/repos', (req, res) => {
|
|
|
185
230
|
}
|
|
186
231
|
});
|
|
187
232
|
|
|
233
|
+
router.delete('/repos', (req, res) => {
|
|
234
|
+
try {
|
|
235
|
+
const { platform, service } = getPluginsService(req);
|
|
236
|
+
const { id = '', owner = '', name = '' } = req.query;
|
|
237
|
+
const repos = service.removeRepo(owner, name, id);
|
|
238
|
+
|
|
239
|
+
res.json({
|
|
240
|
+
success: true,
|
|
241
|
+
platform,
|
|
242
|
+
repos: sanitizeRepos(service, repos)
|
|
243
|
+
});
|
|
244
|
+
} catch (err) {
|
|
245
|
+
console.error('[Plugins API] Remove repo error:', err);
|
|
246
|
+
res.status(500).json({
|
|
247
|
+
success: false,
|
|
248
|
+
message: err.message
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
router.put('/repos/toggle', (req, res) => {
|
|
254
|
+
try {
|
|
255
|
+
const { platform, service } = getPluginsService(req);
|
|
256
|
+
const { id = '', owner = '', name = '', enabled } = req.body;
|
|
257
|
+
|
|
258
|
+
if (typeof enabled !== 'boolean') {
|
|
259
|
+
return res.status(400).json({
|
|
260
|
+
success: false,
|
|
261
|
+
message: 'enabled must be a boolean'
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const repos = service.toggleRepo(owner, name, enabled, id);
|
|
266
|
+
|
|
267
|
+
res.json({
|
|
268
|
+
success: true,
|
|
269
|
+
platform,
|
|
270
|
+
repos: sanitizeRepos(service, repos)
|
|
271
|
+
});
|
|
272
|
+
} catch (err) {
|
|
273
|
+
console.error('[Plugins API] Toggle repo error:', err);
|
|
274
|
+
res.status(500).json({
|
|
275
|
+
success: false,
|
|
276
|
+
message: err.message
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
188
281
|
/**
|
|
189
282
|
* 删除插件仓库
|
|
190
283
|
* DELETE /api/plugins/repos/:owner/:name
|
|
@@ -193,13 +286,14 @@ router.delete('/repos/:owner/:name', (req, res) => {
|
|
|
193
286
|
try {
|
|
194
287
|
const { platform, service } = getPluginsService(req);
|
|
195
288
|
const { owner, name } = req.params;
|
|
289
|
+
const { id = '' } = req.query;
|
|
196
290
|
|
|
197
|
-
const repos = service.removeRepo(owner, name);
|
|
291
|
+
const repos = service.removeRepo(owner, name, id);
|
|
198
292
|
|
|
199
293
|
res.json({
|
|
200
294
|
success: true,
|
|
201
295
|
platform,
|
|
202
|
-
repos,
|
|
296
|
+
repos: sanitizeRepos(service, repos),
|
|
203
297
|
message: 'Repository removed successfully'
|
|
204
298
|
});
|
|
205
299
|
} catch (err) {
|
|
@@ -220,7 +314,7 @@ router.put('/repos/:owner/:name/toggle', (req, res) => {
|
|
|
220
314
|
try {
|
|
221
315
|
const { platform, service } = getPluginsService(req);
|
|
222
316
|
const { owner, name } = req.params;
|
|
223
|
-
const { enabled } = req.body;
|
|
317
|
+
const { enabled, id = '' } = req.body;
|
|
224
318
|
|
|
225
319
|
if (typeof enabled !== 'boolean') {
|
|
226
320
|
return res.status(400).json({
|
|
@@ -229,12 +323,12 @@ router.put('/repos/:owner/:name/toggle', (req, res) => {
|
|
|
229
323
|
});
|
|
230
324
|
}
|
|
231
325
|
|
|
232
|
-
const repos = service.toggleRepo(owner, name, enabled);
|
|
326
|
+
const repos = service.toggleRepo(owner, name, enabled, id);
|
|
233
327
|
|
|
234
328
|
res.json({
|
|
235
329
|
success: true,
|
|
236
330
|
platform,
|
|
237
|
-
repos,
|
|
331
|
+
repos: sanitizeRepos(service, repos),
|
|
238
332
|
message: `Repository ${enabled ? 'enabled' : 'disabled'} successfully`
|
|
239
333
|
});
|
|
240
334
|
} catch (err) {
|
|
@@ -246,6 +340,40 @@ router.put('/repos/:owner/:name/toggle', (req, res) => {
|
|
|
246
340
|
}
|
|
247
341
|
});
|
|
248
342
|
|
|
343
|
+
router.put('/repos/auth', (req, res) => {
|
|
344
|
+
try {
|
|
345
|
+
const { platform, service } = getPluginsService(req);
|
|
346
|
+
const {
|
|
347
|
+
id = '',
|
|
348
|
+
owner = '',
|
|
349
|
+
name = '',
|
|
350
|
+
token = '',
|
|
351
|
+
clearToken = false
|
|
352
|
+
} = req.body;
|
|
353
|
+
|
|
354
|
+
if (!clearToken && !String(token || '').trim()) {
|
|
355
|
+
return res.status(400).json({
|
|
356
|
+
success: false,
|
|
357
|
+
message: 'Missing token'
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const repos = service.updateRepoAuth(owner, name, token, clearToken, id);
|
|
362
|
+
|
|
363
|
+
res.json({
|
|
364
|
+
success: true,
|
|
365
|
+
platform,
|
|
366
|
+
repos: sanitizeRepos(service, repos)
|
|
367
|
+
});
|
|
368
|
+
} catch (err) {
|
|
369
|
+
console.error('[Plugins API] Update repo auth error:', err);
|
|
370
|
+
res.status(500).json({
|
|
371
|
+
success: false,
|
|
372
|
+
message: err.message
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
249
377
|
/**
|
|
250
378
|
* 同步仓库到 Claude Code marketplace
|
|
251
379
|
* POST /api/plugins/repos/sync
|
|
@@ -303,16 +431,35 @@ router.get('/:name/readme', async (req, res) => {
|
|
|
303
431
|
try {
|
|
304
432
|
const { platform, service } = getPluginsService(req);
|
|
305
433
|
const { name } = req.params;
|
|
306
|
-
const {
|
|
434
|
+
const {
|
|
435
|
+
repoId,
|
|
436
|
+
repoProvider,
|
|
437
|
+
repoHost,
|
|
438
|
+
repoOwner,
|
|
439
|
+
repoName,
|
|
440
|
+
repoBranch,
|
|
441
|
+
directory,
|
|
442
|
+
source,
|
|
443
|
+
repoUrl,
|
|
444
|
+
repoProjectPath,
|
|
445
|
+
repoLocalPath,
|
|
446
|
+
installPath
|
|
447
|
+
} = req.query;
|
|
307
448
|
|
|
308
449
|
const pluginInfo = {
|
|
309
450
|
name,
|
|
451
|
+
repoId,
|
|
452
|
+
repoProvider,
|
|
453
|
+
repoHost,
|
|
310
454
|
repoOwner,
|
|
311
455
|
repoName,
|
|
312
456
|
repoBranch,
|
|
313
457
|
directory,
|
|
314
458
|
source,
|
|
315
|
-
repoUrl
|
|
459
|
+
repoUrl,
|
|
460
|
+
repoProjectPath,
|
|
461
|
+
repoLocalPath,
|
|
462
|
+
installPath
|
|
316
463
|
};
|
|
317
464
|
|
|
318
465
|
const readme = await service.getPluginReadme(pluginInfo);
|
package/src/server/api/skills.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
const express = require('express');
|
|
6
6
|
const { SkillService } = require('../services/skill-service');
|
|
7
|
+
const { maskToken } = require('../services/oauth-utils');
|
|
7
8
|
|
|
8
9
|
const router = express.Router();
|
|
9
10
|
const SUPPORTED_PLATFORMS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
@@ -37,10 +38,29 @@ function extractRepoPayload(source = {}) {
|
|
|
37
38
|
directory: repo.directory || source.directory || '',
|
|
38
39
|
projectPath: repo.projectPath || source.projectPath || '',
|
|
39
40
|
localPath: repo.localPath || source.localPath || '',
|
|
40
|
-
repoUrl: repo.repoUrl || source.repoUrl || ''
|
|
41
|
+
repoUrl: repo.repoUrl || source.repoUrl || '',
|
|
42
|
+
token: repo.token || source.token || ''
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
function sanitizeRepo(repo = {}) {
|
|
47
|
+
const token = String(repo.token || '').trim();
|
|
48
|
+
const sanitized = {
|
|
49
|
+
...repo,
|
|
50
|
+
hasToken: Boolean(token),
|
|
51
|
+
tokenPreview: token ? maskToken(token) : ''
|
|
52
|
+
};
|
|
53
|
+
delete sanitized.token;
|
|
54
|
+
return sanitized;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function sanitizeRepos(service, repos = []) {
|
|
58
|
+
if (typeof service.getReposForClient === 'function') {
|
|
59
|
+
return service.getReposForClient(repos);
|
|
60
|
+
}
|
|
61
|
+
return (Array.isArray(repos) ? repos : []).map(sanitizeRepo);
|
|
62
|
+
}
|
|
63
|
+
|
|
44
64
|
/**
|
|
45
65
|
* 获取技能列表
|
|
46
66
|
* GET /api/skills
|
|
@@ -290,7 +310,7 @@ router.get('/repos', (req, res) => {
|
|
|
290
310
|
res.json({
|
|
291
311
|
success: true,
|
|
292
312
|
platform,
|
|
293
|
-
repos
|
|
313
|
+
repos: sanitizeRepos(service, repos)
|
|
294
314
|
});
|
|
295
315
|
} catch (err) {
|
|
296
316
|
console.error('[Skills API] Get repos error:', err);
|
|
@@ -325,7 +345,7 @@ router.post('/repos', (req, res) => {
|
|
|
325
345
|
res.json({
|
|
326
346
|
success: true,
|
|
327
347
|
platform,
|
|
328
|
-
repos
|
|
348
|
+
repos: sanitizeRepos(service, repos)
|
|
329
349
|
});
|
|
330
350
|
} catch (err) {
|
|
331
351
|
console.error('[Skills API] Add repo error:', err);
|
|
@@ -345,7 +365,7 @@ router.delete('/repos', (req, res) => {
|
|
|
345
365
|
res.json({
|
|
346
366
|
success: true,
|
|
347
367
|
platform,
|
|
348
|
-
repos
|
|
368
|
+
repos: sanitizeRepos(service, repos)
|
|
349
369
|
});
|
|
350
370
|
} catch (err) {
|
|
351
371
|
console.error('[Skills API] Remove repo error:', err);
|
|
@@ -366,7 +386,7 @@ router.put('/repos/toggle', (req, res) => {
|
|
|
366
386
|
res.json({
|
|
367
387
|
success: true,
|
|
368
388
|
platform,
|
|
369
|
-
repos
|
|
389
|
+
repos: sanitizeRepos(service, repos)
|
|
370
390
|
});
|
|
371
391
|
} catch (err) {
|
|
372
392
|
console.error('[Skills API] Toggle repo error:', err);
|
|
@@ -377,6 +397,41 @@ router.put('/repos/toggle', (req, res) => {
|
|
|
377
397
|
}
|
|
378
398
|
});
|
|
379
399
|
|
|
400
|
+
router.put('/repos/auth', (req, res) => {
|
|
401
|
+
try {
|
|
402
|
+
const { platform, service } = getSkillService(req);
|
|
403
|
+
const {
|
|
404
|
+
id = '',
|
|
405
|
+
owner = '',
|
|
406
|
+
name = '',
|
|
407
|
+
directory = '',
|
|
408
|
+
token = '',
|
|
409
|
+
clearToken = false
|
|
410
|
+
} = req.body;
|
|
411
|
+
|
|
412
|
+
if (!clearToken && !String(token || '').trim()) {
|
|
413
|
+
return res.status(400).json({
|
|
414
|
+
success: false,
|
|
415
|
+
message: 'Missing token'
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const repos = service.updateRepoAuth(owner, name, directory, token, clearToken, id);
|
|
420
|
+
|
|
421
|
+
res.json({
|
|
422
|
+
success: true,
|
|
423
|
+
platform,
|
|
424
|
+
repos: sanitizeRepos(service, repos)
|
|
425
|
+
});
|
|
426
|
+
} catch (err) {
|
|
427
|
+
console.error('[Skills API] Update repo auth error:', err);
|
|
428
|
+
res.status(500).json({
|
|
429
|
+
success: false,
|
|
430
|
+
message: err.message
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
|
|
380
435
|
/**
|
|
381
436
|
* 删除仓库
|
|
382
437
|
* DELETE /api/skills/repos/:owner/:name
|
|
@@ -392,7 +447,7 @@ router.delete('/repos/:owner/:name', (req, res) => {
|
|
|
392
447
|
res.json({
|
|
393
448
|
success: true,
|
|
394
449
|
platform,
|
|
395
|
-
repos
|
|
450
|
+
repos: sanitizeRepos(service, repos)
|
|
396
451
|
});
|
|
397
452
|
} catch (err) {
|
|
398
453
|
console.error('[Skills API] Remove repo error:', err);
|
|
@@ -420,7 +475,7 @@ router.put('/repos/:owner/:name/toggle', (req, res) => {
|
|
|
420
475
|
res.json({
|
|
421
476
|
success: true,
|
|
422
477
|
platform,
|
|
423
|
-
repos
|
|
478
|
+
repos: sanitizeRepos(service, repos)
|
|
424
479
|
});
|
|
425
480
|
} catch (err) {
|
|
426
481
|
console.error('[Skills API] Toggle repo error:', err);
|
|
@@ -15,6 +15,7 @@ const { getEffectiveApiKey } = require('./services/codex-channels');
|
|
|
15
15
|
const { persistProxyRequestSnapshot } = require('./services/request-logger');
|
|
16
16
|
const { publishUsageLog, publishFailureLog } = require('./services/proxy-log-helper');
|
|
17
17
|
const { redirectModel, resolveTargetUrl } = require('./services/base/proxy-utils');
|
|
18
|
+
const { attachServerShutdownHandling, expediteServerShutdown } = require('./services/server-shutdown');
|
|
18
19
|
|
|
19
20
|
let proxyServer = null;
|
|
20
21
|
let proxyApp = null;
|
|
@@ -519,6 +520,7 @@ async function startCodexProxyServer(options = {}) {
|
|
|
519
520
|
|
|
520
521
|
// 启动服务器
|
|
521
522
|
proxyServer = http.createServer(proxyApp);
|
|
523
|
+
attachServerShutdownHandling(proxyServer);
|
|
522
524
|
|
|
523
525
|
return new Promise((resolve, reject) => {
|
|
524
526
|
proxyServer.listen(port, '127.0.0.1', () => {
|
|
@@ -559,8 +561,13 @@ async function stopCodexProxyServer(options = {}) {
|
|
|
559
561
|
|
|
560
562
|
requestMetadata.clear();
|
|
561
563
|
|
|
564
|
+
const shutdownTimer = expediteServerShutdown(proxyServer);
|
|
565
|
+
|
|
562
566
|
return new Promise((resolve) => {
|
|
563
567
|
proxyServer.close(() => {
|
|
568
|
+
if (shutdownTimer) {
|
|
569
|
+
clearTimeout(shutdownTimer);
|
|
570
|
+
}
|
|
564
571
|
console.log('Codex proxy server stopped');
|
|
565
572
|
|
|
566
573
|
// 清除代理启动时间(仅当明确要求时)
|
|
@@ -580,8 +587,9 @@ async function stopCodexProxyServer(options = {}) {
|
|
|
580
587
|
// 获取代理服务器状态
|
|
581
588
|
function getCodexProxyStatus() {
|
|
582
589
|
const config = loadConfig();
|
|
583
|
-
const
|
|
584
|
-
const
|
|
590
|
+
const allowRecovery = !!proxyServer;
|
|
591
|
+
const startTime = getProxyStartTime('codex', { allowRecovery });
|
|
592
|
+
const runtime = getProxyRuntime('codex', { allowRecovery });
|
|
585
593
|
|
|
586
594
|
return {
|
|
587
595
|
running: !!proxyServer,
|
|
@@ -15,6 +15,7 @@ const { getEffectiveApiKey } = require('./services/gemini-channels');
|
|
|
15
15
|
const { persistProxyRequestSnapshot } = require('./services/request-logger');
|
|
16
16
|
const { publishUsageLog, publishFailureLog } = require('./services/proxy-log-helper');
|
|
17
17
|
const { redirectModel: redirectModelBase, resolveTargetUrl } = require('./services/base/proxy-utils');
|
|
18
|
+
const { attachServerShutdownHandling, expediteServerShutdown } = require('./services/server-shutdown');
|
|
18
19
|
|
|
19
20
|
let proxyServer = null;
|
|
20
21
|
let proxyApp = null;
|
|
@@ -512,6 +513,7 @@ async function startGeminiProxyServer(options = {}) {
|
|
|
512
513
|
|
|
513
514
|
// 启动服务器
|
|
514
515
|
proxyServer = http.createServer(proxyApp);
|
|
516
|
+
attachServerShutdownHandling(proxyServer);
|
|
515
517
|
|
|
516
518
|
return new Promise((resolve, reject) => {
|
|
517
519
|
proxyServer.listen(port, '127.0.0.1', () => {
|
|
@@ -552,8 +554,13 @@ async function stopGeminiProxyServer(options = {}) {
|
|
|
552
554
|
|
|
553
555
|
requestMetadata.clear();
|
|
554
556
|
|
|
557
|
+
const shutdownTimer = expediteServerShutdown(proxyServer);
|
|
558
|
+
|
|
555
559
|
return new Promise((resolve) => {
|
|
556
560
|
proxyServer.close(() => {
|
|
561
|
+
if (shutdownTimer) {
|
|
562
|
+
clearTimeout(shutdownTimer);
|
|
563
|
+
}
|
|
557
564
|
console.log('Gemini proxy server stopped');
|
|
558
565
|
|
|
559
566
|
// 清除代理启动时间(仅当明确要求时)
|
|
@@ -573,8 +580,9 @@ async function stopGeminiProxyServer(options = {}) {
|
|
|
573
580
|
// 获取代理服务器状态
|
|
574
581
|
function getGeminiProxyStatus() {
|
|
575
582
|
const config = loadConfig();
|
|
576
|
-
const
|
|
577
|
-
const
|
|
583
|
+
const allowRecovery = !!proxyServer;
|
|
584
|
+
const startTime = getProxyStartTime('gemini', { allowRecovery });
|
|
585
|
+
const runtime = getProxyRuntime('gemini', { allowRecovery });
|
|
578
586
|
|
|
579
587
|
return {
|
|
580
588
|
running: !!proxyServer,
|
|
@@ -22,6 +22,7 @@ const { persistProxyRequestSnapshot, loadClaudeRequestTemplate } = require('./se
|
|
|
22
22
|
const { probeModelAvailability, fetchModelsFromProvider } = require('./services/model-detector');
|
|
23
23
|
const { publishUsageLog, publishFailureLog } = require('./services/proxy-log-helper');
|
|
24
24
|
const { redirectModel, resolveTargetUrl } = require('./services/base/proxy-utils');
|
|
25
|
+
const { attachServerShutdownHandling, expediteServerShutdown } = require('./services/server-shutdown');
|
|
25
26
|
|
|
26
27
|
let proxyServer = null;
|
|
27
28
|
let proxyApp = null;
|
|
@@ -4650,6 +4651,7 @@ async function startOpenCodeProxyServer(options = {}) {
|
|
|
4650
4651
|
|
|
4651
4652
|
// 启动服务器
|
|
4652
4653
|
proxyServer = http.createServer(proxyApp);
|
|
4654
|
+
attachServerShutdownHandling(proxyServer);
|
|
4653
4655
|
|
|
4654
4656
|
return new Promise((resolve, reject) => {
|
|
4655
4657
|
proxyServer.listen(port, '127.0.0.1', () => {
|
|
@@ -4692,8 +4694,13 @@ async function stopOpenCodeProxyServer(options = {}) {
|
|
|
4692
4694
|
|
|
4693
4695
|
requestMetadata.clear();
|
|
4694
4696
|
|
|
4697
|
+
const shutdownTimer = expediteServerShutdown(proxyServer);
|
|
4698
|
+
|
|
4695
4699
|
return new Promise((resolve) => {
|
|
4696
4700
|
proxyServer.close(() => {
|
|
4701
|
+
if (shutdownTimer) {
|
|
4702
|
+
clearTimeout(shutdownTimer);
|
|
4703
|
+
}
|
|
4697
4704
|
console.log('OpenCode proxy server stopped');
|
|
4698
4705
|
|
|
4699
4706
|
// 清除代理启动时间(仅当明确要求时)
|
|
@@ -4713,8 +4720,9 @@ async function stopOpenCodeProxyServer(options = {}) {
|
|
|
4713
4720
|
// 获取代理服务器状态
|
|
4714
4721
|
function getOpenCodeProxyStatus() {
|
|
4715
4722
|
const config = loadConfig();
|
|
4716
|
-
const
|
|
4717
|
-
const
|
|
4723
|
+
const allowRecovery = !!proxyServer;
|
|
4724
|
+
const startTime = getProxyStartTime('opencode', { allowRecovery });
|
|
4725
|
+
const runtime = getProxyRuntime('opencode', { allowRecovery });
|
|
4718
4726
|
|
|
4719
4727
|
return {
|
|
4720
4728
|
running: !!proxyServer,
|
|
@@ -20,6 +20,7 @@ const { getEffectiveApiKey } = require('./services/channels');
|
|
|
20
20
|
const { persistProxyRequestSnapshot, persistClaudeRequestTemplate } = require('./services/request-logger');
|
|
21
21
|
const { publishUsageLog, publishFailureLog } = require('./services/proxy-log-helper');
|
|
22
22
|
const { redirectModel } = require('./services/base/proxy-utils');
|
|
23
|
+
const { attachServerShutdownHandling, expediteServerShutdown } = require('./services/server-shutdown');
|
|
23
24
|
|
|
24
25
|
let proxyServer = null;
|
|
25
26
|
let proxyApp = null;
|
|
@@ -541,6 +542,7 @@ async function startProxyServer(options = {}) {
|
|
|
541
542
|
});
|
|
542
543
|
|
|
543
544
|
proxyServer = http.createServer(proxyApp);
|
|
545
|
+
attachServerShutdownHandling(proxyServer);
|
|
544
546
|
|
|
545
547
|
return new Promise((resolve, reject) => {
|
|
546
548
|
proxyServer.listen(port, '127.0.0.1', () => {
|
|
@@ -580,8 +582,13 @@ async function stopProxyServer(options = {}) {
|
|
|
580
582
|
|
|
581
583
|
requestMetadata.clear();
|
|
582
584
|
|
|
585
|
+
const shutdownTimer = expediteServerShutdown(proxyServer);
|
|
586
|
+
|
|
583
587
|
return new Promise((resolve) => {
|
|
584
588
|
proxyServer.close(() => {
|
|
589
|
+
if (shutdownTimer) {
|
|
590
|
+
clearTimeout(shutdownTimer);
|
|
591
|
+
}
|
|
585
592
|
console.log('[OK] Proxy server stopped');
|
|
586
593
|
if (clearStartTime) {
|
|
587
594
|
clearProxyStartTime('claude');
|
|
@@ -599,8 +606,9 @@ async function stopProxyServer(options = {}) {
|
|
|
599
606
|
// 获取代理服务器状态
|
|
600
607
|
function getProxyStatus() {
|
|
601
608
|
const config = loadConfig();
|
|
602
|
-
const
|
|
603
|
-
const
|
|
609
|
+
const allowRecovery = !!proxyServer;
|
|
610
|
+
const startTime = getProxyStartTime('claude', { allowRecovery });
|
|
611
|
+
const runtime = getProxyRuntime('claude', { allowRecovery });
|
|
604
612
|
|
|
605
613
|
return {
|
|
606
614
|
running: !!proxyServer,
|