@coralai/sps-cli 0.58.7 → 0.58.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agentDaemon.d.ts.map +1 -1
- package/dist/commands/agentDaemon.js +7 -3
- package/dist/commands/agentDaemon.js.map +1 -1
- package/dist/commands/consoleCommand.d.ts.map +1 -1
- package/dist/commands/consoleCommand.js +85 -18
- package/dist/commands/consoleCommand.js.map +1 -1
- package/dist/commands/modelCommand.d.ts +2 -0
- package/dist/commands/modelCommand.d.ts.map +1 -0
- package/dist/commands/modelCommand.js +431 -0
- package/dist/commands/modelCommand.js.map +1 -0
- package/dist/commands/setup.d.ts +4 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/setup.js.map +1 -1
- package/dist/console-assets/assets/{index-DIue2TJq.js → index-CS_Z0d-6.js} +106 -106
- package/dist/console-assets/index.html +1 -1
- package/dist/core/agents/workerModelEnv.d.ts +1 -0
- package/dist/core/agents/workerModelEnv.d.ts.map +1 -1
- package/dist/core/agents/workerModelEnv.js +21 -1
- package/dist/core/agents/workerModelEnv.js.map +1 -1
- package/dist/main.js +21 -3
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentDaemon.d.ts","sourceRoot":"","sources":["../../src/commands/agentDaemon.ts"],"names":[],"mappings":"AAiCA,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"agentDaemon.d.ts","sourceRoot":"","sources":["../../src/commands/agentDaemon.ts"],"names":[],"mappings":"AAiCA,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB5E;AAkGD,mFAAmF;AACnF,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAOrD"}
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* @layer command
|
|
14
14
|
* @boundedContext agent
|
|
15
15
|
*
|
|
16
|
-
* @trigger sps agent daemon <start|stop|status>
|
|
17
|
-
* @inputs 子命令(start/stop/status)
|
|
16
|
+
* @trigger sps agent daemon <start|stop|restart|status>
|
|
17
|
+
* @inputs 子命令(start/stop/restart/status)
|
|
18
18
|
* @outputs daemon 进程状态信息
|
|
19
19
|
* @workflow 1. 解析子命令 → 2. 执行 start/stop/status 操作 → 3. 输出状态
|
|
20
20
|
*/
|
|
@@ -36,11 +36,15 @@ export async function executeDaemonCommand(subcommand) {
|
|
|
36
36
|
case 'stop':
|
|
37
37
|
await daemonStop();
|
|
38
38
|
break;
|
|
39
|
+
case 'restart':
|
|
40
|
+
await daemonStop();
|
|
41
|
+
await daemonStart();
|
|
42
|
+
break;
|
|
39
43
|
case 'status':
|
|
40
44
|
await daemonStatus();
|
|
41
45
|
break;
|
|
42
46
|
default:
|
|
43
|
-
console.error('Usage: sps agent daemon <start|stop|status>');
|
|
47
|
+
console.error('Usage: sps agent daemon <start|stop|restart|status>');
|
|
44
48
|
process.exit(2);
|
|
45
49
|
}
|
|
46
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentDaemon.js","sourceRoot":"","sources":["../../src/commands/agentDaemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,GAAG,MAAM,2BAA2B,CAAC;AAE1D,MAAM,GAAG,GAAG,UAAU,CAAC;AACvB,MAAM,KAAK,GAAG,UAAU,CAAC;AACzB,MAAM,GAAG,GAAG,UAAU,CAAC;AACvB,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,aAAa,CAAC;AAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAEnE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,UAAkB;IAC3D,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,OAAO;YACV,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,MAAM;YACT,MAAM,UAAU,EAAE,CAAC;YACnB,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,YAAY,EAAE,CAAC;YACrB,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"agentDaemon.js","sourceRoot":"","sources":["../../src/commands/agentDaemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,GAAG,MAAM,2BAA2B,CAAC;AAE1D,MAAM,GAAG,GAAG,UAAU,CAAC;AACvB,MAAM,KAAK,GAAG,UAAU,CAAC;AACzB,MAAM,GAAG,GAAG,UAAU,CAAC;AACvB,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,aAAa,CAAC;AAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,CAAC,CAAC;AAEnE,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,UAAkB;IAC3D,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,OAAO;YACV,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,MAAM;YACT,MAAM,UAAU,EAAE,CAAC;YACnB,MAAM;QACR,KAAK,SAAS;YACZ,MAAM,UAAU,EAAE,CAAC;YACnB,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,YAAY,EAAE,CAAC;YACrB,MAAM;QACR;YACE,OAAO,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC;YACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW;IACxB,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,IAAI,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,yBAAyB,KAAK,EAAE,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,MAAM,YAAY,GAAG,OAAO,CAC1B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,8BAA8B,EAAE,EAAE,CAAC,EAClF,QAAQ,EAAE,kBAAkB,CAC7B,CAAC;IAEF,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,4BAA4B,YAAY,GAAG,KAAK,EAAE,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,8CAA8C;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;IAC1E,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE;QACpD,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC;QAC3B,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;KACxB,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,EAAE,CAAC;IAEd,kCAAkC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC7C,IAAI,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,uBAAuB,KAAK,CAAC,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;IACH,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,oCAAoC,KAAK,EAAE,CAAC,CAAC;IACjE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,UAAU;IACvB,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,qBAAqB,KAAK,EAAE,CAAC,CAAC;QAChD,OAAO;IACT,CAAC;IAED,MAAM,MAAM,CAAC,QAAQ,EAAE,CAAC;IAExB,0BAA0B;IAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,iBAAiB,KAAK,EAAE,CAAC,CAAC;YAC9C,OAAO;QACT,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACjE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,sBAAsB,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;IAChC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY;IACzB,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,IAAI,MAAM,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;QAC7B,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,GAAG,SAAS,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC;QAC/D,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,iBAAiB,OAAO,GAAG,KAAK,EAAE,CAAC,CAAC;QAExD,gBAAgB;QAChB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;YACtD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;gBAC7B,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC;oBACvC,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;oBAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;oBAC5C,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,MAAM,OAAO,CAAC,IAAI,MAAM,IAAI,EAAE,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,qBAAqB,KAAK,EAAE,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,IAAI,MAAM,MAAM,CAAC,SAAS,EAAE;QAAE,OAAO,IAAI,CAAC;IAE1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,qBAAqB,KAAK,IAAI,CAAC,CAAC;IAC3D,MAAM,WAAW,EAAE,CAAC;IACpB,OAAO,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consoleCommand.d.ts","sourceRoot":"","sources":["../../src/commands/consoleCommand.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"consoleCommand.d.ts","sourceRoot":"","sources":["../../src/commands/consoleCommand.ts"],"names":[],"mappings":"AAoGA,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA6IlF"}
|
|
@@ -6,13 +6,19 @@
|
|
|
6
6
|
* @layer command
|
|
7
7
|
* @boundedContext console
|
|
8
8
|
*
|
|
9
|
-
* @trigger sps console [--port <n>] [--host <h>] [--no-open] [--dev]
|
|
9
|
+
* @trigger sps console [--port <n>] [--host <h>] [--no-open] [--dev]
|
|
10
|
+
* [--detach|--background] [--stop|--kill] [--restart]
|
|
10
11
|
*
|
|
11
12
|
* 单实例保证:~/.coral/console.lock 记录 pid + port。
|
|
12
|
-
* 已有实例 → 打印 URL 并退出(或 --kill
|
|
13
|
+
* 已有实例 → 打印 URL 并退出(或 --kill/--stop 清理、--restart 重启)
|
|
13
14
|
* 无实例 → acquire lock, 启 server, open browser, 注册 SIGTERM/SIGINT cleanup
|
|
15
|
+
* --detach → 以后台进程重启自身(detached),父进程等锁出现后打印 URL 即退出
|
|
14
16
|
*/
|
|
17
|
+
import { spawn } from 'node:child_process';
|
|
18
|
+
import { openSync } from 'node:fs';
|
|
15
19
|
import { createRequire } from 'node:module';
|
|
20
|
+
import { resolve } from 'node:path';
|
|
21
|
+
import { fileURLToPath } from 'node:url';
|
|
16
22
|
import { startConsoleServer } from '../console/index.js';
|
|
17
23
|
import { acquireLock, detectRunningConsole, releaseLock, } from '../console/lib/lockFile.js';
|
|
18
24
|
import { pickPort } from '../console/lib/portPicker.js';
|
|
@@ -20,24 +26,85 @@ import { Logger } from '../core/logger.js';
|
|
|
20
26
|
const DEFAULT_PORT = 4311;
|
|
21
27
|
const _require = createRequire(import.meta.url);
|
|
22
28
|
const VERSION = _require('../../package.json').version;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
catch {
|
|
36
|
-
/* 进程已死 */
|
|
29
|
+
/** 停掉正在运行的 console 实例并清锁。返回是否确实停掉了一个实例。 */
|
|
30
|
+
async function stopRunningConsole(log) {
|
|
31
|
+
const running = detectRunningConsole();
|
|
32
|
+
if (running) {
|
|
33
|
+
log.warn(`Stopping running console (pid ${running.pid}, port ${running.port})...`);
|
|
34
|
+
try {
|
|
35
|
+
process.kill(running.pid, 'SIGTERM');
|
|
36
|
+
// 给 3 秒优雅退出(超时不阻塞后续 restart)
|
|
37
|
+
for (let i = 0; i < 6; i++) {
|
|
38
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
39
|
+
if (!detectRunningConsole())
|
|
40
|
+
break;
|
|
37
41
|
}
|
|
38
42
|
}
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
catch {
|
|
44
|
+
/* 进程已死 */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
releaseLock();
|
|
48
|
+
return running != null;
|
|
49
|
+
}
|
|
50
|
+
/** 以后台 detached 进程重启自身;父进程等锁出现后打印 URL 并返回。 */
|
|
51
|
+
async function launchDetached(flags, log) {
|
|
52
|
+
const existing = detectRunningConsole();
|
|
53
|
+
if (existing) {
|
|
54
|
+
log.info(`SPS Console already running: http://localhost:${existing.port}`);
|
|
55
|
+
log.info(` run \`sps console --restart --detach\` to restart it in background`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const entry = fileURLToPath(import.meta.url).replace(/[/\\]commands[/\\]consoleCommand\.js$/, '/main.js');
|
|
59
|
+
// 透传可继续生效的 flags(去掉 detach/background/restart/stop/kill,避免递归/误停)
|
|
60
|
+
const childArgs = ['console'];
|
|
61
|
+
if (typeof flags.port === 'string')
|
|
62
|
+
childArgs.push('--port', flags.port);
|
|
63
|
+
if (typeof flags.host === 'string')
|
|
64
|
+
childArgs.push('--host', flags.host);
|
|
65
|
+
if (flags.dev === true)
|
|
66
|
+
childArgs.push('--dev');
|
|
67
|
+
if (flags['no-open'] === true)
|
|
68
|
+
childArgs.push('--no-open');
|
|
69
|
+
const home = process.env.HOME || '/home/coral';
|
|
70
|
+
const logFile = resolve(home, '.coral', 'console.detached.log');
|
|
71
|
+
const out = openSync(logFile, 'a');
|
|
72
|
+
const child = spawn(process.execPath, [entry, ...childArgs], {
|
|
73
|
+
detached: true,
|
|
74
|
+
stdio: ['ignore', out, out],
|
|
75
|
+
env: { ...process.env, SPS_CONSOLE_DETACHED_CHILD: '1' },
|
|
76
|
+
});
|
|
77
|
+
child.unref();
|
|
78
|
+
// 等锁出现(子进程 acquireLock 后即视为就绪)
|
|
79
|
+
for (let i = 0; i < 30; i++) {
|
|
80
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
81
|
+
const lock = detectRunningConsole();
|
|
82
|
+
if (lock) {
|
|
83
|
+
log.ok(`SPS Console started in background (pid ${lock.pid})`);
|
|
84
|
+
log.info(` Local: http://localhost:${lock.port}`);
|
|
85
|
+
log.info(` Logs: ${logFile}`);
|
|
86
|
+
log.info(` run \`sps console --stop\` to stop it`);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
log.error(`Console failed to start within 15s (see ${logFile})`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
export async function executeConsole(flags) {
|
|
94
|
+
const log = new Logger('console', '');
|
|
95
|
+
// --stop / --kill: 停掉运行中实例并清锁,退出
|
|
96
|
+
if (flags.stop || flags.kill) {
|
|
97
|
+
const stopped = await stopRunningConsole(log);
|
|
98
|
+
log.ok(stopped ? 'Console stopped' : 'No running console (lock cleaned)');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// --restart: 先停旧实例,再按下面流程重启(若带 --detach 则后台起)
|
|
102
|
+
if (flags.restart) {
|
|
103
|
+
await stopRunningConsole(log);
|
|
104
|
+
}
|
|
105
|
+
// --detach / --background: 后台起(除非自己就是被 detach 出来的子进程)
|
|
106
|
+
if ((flags.detach || flags.background) && !process.env.SPS_CONSOLE_DETACHED_CHILD) {
|
|
107
|
+
await launchDetached(flags, log);
|
|
41
108
|
return;
|
|
42
109
|
}
|
|
43
110
|
// 检查已有实例
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consoleCommand.js","sourceRoot":"","sources":["../../src/commands/consoleCommand.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"consoleCommand.js","sourceRoot":"","sources":["../../src/commands/consoleCommand.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelCommand.d.ts","sourceRoot":"","sources":["../../src/commands/modelCommand.ts"],"names":[],"mappings":"AAsIA,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,WAAW,EAAE,MAAM,EAAE,EACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,CAuBf"}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modelCommand
|
|
3
|
+
* @description `sps model` —— 配置 worker(claude 底层)的模型来源:多平台预设(GLM/MiniMax/
|
|
4
|
+
* Kimi/DeepSeek/Qwen/OpenRouter/…)+ 本地订阅(claude/codex auth)。API-key 型
|
|
5
|
+
* 写进共享 provider 注册表(providers.json),Auth 型触发本地登录,配好后设为全局默认。
|
|
6
|
+
*
|
|
7
|
+
* @role command
|
|
8
|
+
* @layer command
|
|
9
|
+
* @boundedContext model-config
|
|
10
|
+
*
|
|
11
|
+
* @trigger sps model [list|set|use|auth|rm] [args]
|
|
12
|
+
*
|
|
13
|
+
* 设计:只配 worker(对话/干活的 claude 后端)。reviewer(openai 监工)不在此命令内。
|
|
14
|
+
* 复用现有底座——不新建配置体系:
|
|
15
|
+
* - API-key 平台 → upsertProvider('anthropic', {baseUrl, apiKey, models, extraEnv?})
|
|
16
|
+
* - 设默认 → saveAgentsConfig(worker.{providerId, model})
|
|
17
|
+
* - 认证 → 检测本地订阅;缺则 spawnSync 登录(TTY 透传)
|
|
18
|
+
*/
|
|
19
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
20
|
+
import { createPrompt } from './setup.js';
|
|
21
|
+
import { Logger } from '../core/logger.js';
|
|
22
|
+
import { deleteProvider, getProvider, upsertProvider, } from '../providers/llm/providers.js';
|
|
23
|
+
import { loadAgentsConfig, saveAgentsConfig } from '../core/intel/agentsConfig.js';
|
|
24
|
+
import { detectClaudeSub, CLAUDE_SUB_MODELS } from '../providers/llm/localSubscription.js';
|
|
25
|
+
import { CODEX_PROXY_ID, CODEX_PROXY_CURATED_MODELS, codexProxyBinPath, } from '../core/agents/sidecar/CodexProxyManager.js';
|
|
26
|
+
const GREEN = '\x1b[32m';
|
|
27
|
+
const DIM = '\x1b[90m';
|
|
28
|
+
const CYAN = '\x1b[36m';
|
|
29
|
+
const YELLOW = '\x1b[33m';
|
|
30
|
+
const RESET = '\x1b[0m';
|
|
31
|
+
/** 某个 codex-proxy 后端(codex/kimi/cursor)是否已登录:`claude-code-proxy <backend> auth status` exit 0。 */
|
|
32
|
+
function proxyBackendAuthed(backend) {
|
|
33
|
+
const bin = codexProxyBinPath();
|
|
34
|
+
if (!bin)
|
|
35
|
+
return false;
|
|
36
|
+
return spawnSync(bin, [backend, 'auth', 'status'], { encoding: 'utf-8' }).status === 0;
|
|
37
|
+
}
|
|
38
|
+
/** 由 worker.model 反推它属于哪个 codex-proxy 后端(用于 list 打 ✓)。 */
|
|
39
|
+
function backendOf(model) {
|
|
40
|
+
if (/kimi|^k2/i.test(model))
|
|
41
|
+
return 'kimi';
|
|
42
|
+
if (/cursor|composer/i.test(model))
|
|
43
|
+
return 'cursor';
|
|
44
|
+
return 'codex';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 交互式跑一条认证命令(TTY 透传),**可用 Ctrl+C 取消**。
|
|
48
|
+
* 用异步 spawn(非 spawnSync)——spawnSync 会阻塞 node 事件循环,SIGINT 处理器根本跑不了,
|
|
49
|
+
* 加上设备码子进程可能忽略 SIGINT → 表现为"Ctrl+C 无效卡死"。这里自己接管 SIGINT/SIGTERM,
|
|
50
|
+
* 直接 SIGKILL 子进程;另加超时兜底(设备码通常几分钟过期)。
|
|
51
|
+
* 返回子进程退出码;被取消/超时返回 'cancelled'。
|
|
52
|
+
*/
|
|
53
|
+
function runAuth(cmd, args, timeoutMs = 300_000) {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const child = spawn(cmd, args, { stdio: 'inherit' });
|
|
56
|
+
let done = false;
|
|
57
|
+
let cancelled = false;
|
|
58
|
+
const kill = () => { cancelled = true; try {
|
|
59
|
+
child.kill('SIGKILL');
|
|
60
|
+
}
|
|
61
|
+
catch { /* 已退出 */ } };
|
|
62
|
+
const onSig = () => kill();
|
|
63
|
+
const timer = setTimeout(() => { process.stderr.write('\n认证超时,已取消。\n'); kill(); }, timeoutMs);
|
|
64
|
+
process.on('SIGINT', onSig);
|
|
65
|
+
process.on('SIGTERM', onSig);
|
|
66
|
+
const finish = (v) => {
|
|
67
|
+
if (done)
|
|
68
|
+
return;
|
|
69
|
+
done = true;
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
process.off('SIGINT', onSig);
|
|
72
|
+
process.off('SIGTERM', onSig);
|
|
73
|
+
resolve(v);
|
|
74
|
+
};
|
|
75
|
+
child.on('error', () => finish('cancelled'));
|
|
76
|
+
child.on('exit', (code) => finish(cancelled ? 'cancelled' : (code ?? 0)));
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** 平台预设表 —— 唯一新增的"数据"。模型名会随平台更新,向导始终允许自定义。
|
|
80
|
+
* 三个 *-sub 都复用同一个 codex-proxy(claude-code-proxy),后端由 proxyBackend 选、providerId 均为 codex-proxy。 */
|
|
81
|
+
const PRESETS = [
|
|
82
|
+
{ id: 'claude-auth', name: 'Claude(订阅登录 / claude.ai)', auth: 'oauth-claude', models: CLAUDE_SUB_MODELS },
|
|
83
|
+
{ id: 'claude-api', name: 'Claude API(Anthropic key)', auth: 'key',
|
|
84
|
+
baseUrl: 'https://api.anthropic.com', keyEnv: 'API_KEY', models: [...CLAUDE_SUB_MODELS] },
|
|
85
|
+
{ id: 'codex-auth', name: 'ChatGPT 订阅(codex-proxy,出 GPT)', auth: 'proxy-sub', proxyBackend: 'codex', models: CODEX_PROXY_CURATED_MODELS },
|
|
86
|
+
{ id: 'kimi-sub', name: 'Kimi 订阅(codex-proxy)', auth: 'proxy-sub', proxyBackend: 'kimi', models: ['kimi-k2.6', 'kimi-for-coding'] },
|
|
87
|
+
{ id: 'cursor-sub', name: 'Cursor 订阅(codex-proxy)', auth: 'proxy-sub', proxyBackend: 'cursor', models: ['composer-2.5', 'cursor'] },
|
|
88
|
+
{ id: 'chatgpt-api', name: 'ChatGPT / GPT(API key → 走 OpenRouter)', auth: 'redirect', models: [] },
|
|
89
|
+
{ id: 'glm', name: 'GLM(智谱 / Z.AI)', auth: 'key',
|
|
90
|
+
baseUrl: { cn: 'https://open.bigmodel.cn/api/anthropic', intl: 'https://api.z.ai/api/anthropic' },
|
|
91
|
+
models: ['glm-4.7', 'glm-4.6'] },
|
|
92
|
+
{ id: 'minimax', name: 'MiniMax', auth: 'key',
|
|
93
|
+
baseUrl: { cn: 'https://api.minimaxi.com/anthropic', intl: 'https://api.minimax.io/anthropic' },
|
|
94
|
+
models: ['MiniMax-M2'] },
|
|
95
|
+
{ id: 'openrouter', name: 'OpenRouter', auth: 'key',
|
|
96
|
+
baseUrl: 'https://openrouter.ai/api', models: ['anthropic/claude-sonnet-4.5', 'deepseek/deepseek-chat'],
|
|
97
|
+
extraEnv: { ANTHROPIC_API_KEY: '' }, note: '模型填 OpenRouter 全 id(如 deepseek/deepseek-chat)' },
|
|
98
|
+
{ id: 'kimi', name: 'Kimi(Moonshot)', auth: 'key',
|
|
99
|
+
baseUrl: { cn: 'https://api.moonshot.cn/anthropic', intl: 'https://api.moonshot.ai/anthropic' },
|
|
100
|
+
models: ['kimi-k2.5', 'kimi-k2'] },
|
|
101
|
+
{ id: 'deepseek', name: 'DeepSeek', auth: 'key',
|
|
102
|
+
baseUrl: 'https://api.deepseek.com/anthropic', models: ['deepseek-chat', 'deepseek-reasoner'] },
|
|
103
|
+
{ id: 'qwen', name: 'Qwen / 阿里云百炼(DashScope)', auth: 'key',
|
|
104
|
+
baseUrl: 'https://dashscope.aliyuncs.com/apps/anthropic', models: ['qwen3-coder-plus', 'qwen3-max'] },
|
|
105
|
+
{ id: 'custom', name: '自定义 Anthropic 兼容端点', auth: 'key', models: [] },
|
|
106
|
+
];
|
|
107
|
+
export async function executeModelCommand(subcommand, positionals, _flags) {
|
|
108
|
+
const log = new Logger('model', '');
|
|
109
|
+
switch (subcommand) {
|
|
110
|
+
case null:
|
|
111
|
+
case 'list':
|
|
112
|
+
listModels();
|
|
113
|
+
return;
|
|
114
|
+
case 'set':
|
|
115
|
+
await runWizard(log);
|
|
116
|
+
return;
|
|
117
|
+
case 'use':
|
|
118
|
+
useModel(log, positionals[0], positionals[1]);
|
|
119
|
+
return;
|
|
120
|
+
case 'auth':
|
|
121
|
+
await authPlatform(log, positionals[0]);
|
|
122
|
+
return;
|
|
123
|
+
case 'rm':
|
|
124
|
+
removeModel(log, positionals[0]);
|
|
125
|
+
return;
|
|
126
|
+
default:
|
|
127
|
+
console.error('Usage: sps model <list|set|use|auth|rm> [args]');
|
|
128
|
+
process.exit(2);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// ─── list ──────────────────────────────────────────────────────────
|
|
132
|
+
function listModels() {
|
|
133
|
+
const agents = loadAgentsConfig();
|
|
134
|
+
const w = agents.worker;
|
|
135
|
+
const curPid = w.providerId || 'official';
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log(' 平台 / 模型来源(worker = 对话/干活的 claude 后端)');
|
|
138
|
+
console.log(` ${DIM}当前默认: ${curPid === 'official' ? 'Claude 官方订阅' : curPid} · ${w.model}${RESET}`);
|
|
139
|
+
console.log('');
|
|
140
|
+
for (const p of PRESETS) {
|
|
141
|
+
if (p.id === 'custom' || p.auth === 'redirect')
|
|
142
|
+
continue;
|
|
143
|
+
const st = statusOf(p);
|
|
144
|
+
const isDefault = (p.auth === 'oauth-claude' && curPid === 'official') ||
|
|
145
|
+
(p.auth === 'proxy-sub' && curPid === CODEX_PROXY_ID && backendOf(w.model) === p.proxyBackend) ||
|
|
146
|
+
(p.auth === 'key' && curPid === p.id);
|
|
147
|
+
const mark = isDefault ? `${GREEN}✓${RESET}` : ' ';
|
|
148
|
+
console.log(` ${mark} ${p.name.padEnd(34)} ${st}`);
|
|
149
|
+
}
|
|
150
|
+
console.log('');
|
|
151
|
+
console.log(` ${DIM}sps model set 交互配置 · sps model use <id> <model> 设默认 · sps model auth <id> 登录${RESET}`);
|
|
152
|
+
console.log('');
|
|
153
|
+
}
|
|
154
|
+
/** 一个平台的可用/已配状态徽标。 */
|
|
155
|
+
function statusOf(p) {
|
|
156
|
+
if (p.auth === 'oauth-claude') {
|
|
157
|
+
return detectClaudeSub().available ? `${GREEN}[已登录]${RESET}` : `${DIM}[未登录]${RESET}`;
|
|
158
|
+
}
|
|
159
|
+
if (p.auth === 'proxy-sub') {
|
|
160
|
+
if (!codexProxyBinPath())
|
|
161
|
+
return `${DIM}[未装 proxy]${RESET}`;
|
|
162
|
+
return proxyBackendAuthed(p.proxyBackend) ? `${GREEN}[已登录]${RESET}` : `${YELLOW}[未登录]${RESET}`;
|
|
163
|
+
}
|
|
164
|
+
if (p.auth === 'redirect')
|
|
165
|
+
return `${DIM}[→ OpenRouter]${RESET}`;
|
|
166
|
+
// key 型:看 providers.json 里配没配、有没有 key
|
|
167
|
+
const prov = getProvider(p.id);
|
|
168
|
+
return prov && typeof prov.apiKey === 'string' && prov.apiKey.trim()
|
|
169
|
+
? `${CYAN}[已配 key]${RESET}`
|
|
170
|
+
: `${DIM}[未配]${RESET}`;
|
|
171
|
+
}
|
|
172
|
+
// ─── set(交互向导)─────────────────────────────────────────────────
|
|
173
|
+
async function runWizard(log) {
|
|
174
|
+
const prompt = createPrompt();
|
|
175
|
+
try {
|
|
176
|
+
console.log('\n 选择模型平台:\n');
|
|
177
|
+
const shown = PRESETS;
|
|
178
|
+
shown.forEach((p, i) => {
|
|
179
|
+
console.log(` ${String(i + 1).padStart(2)}. ${p.name.padEnd(34)} ${statusOf(p)}`);
|
|
180
|
+
});
|
|
181
|
+
console.log('');
|
|
182
|
+
const pick = await prompt.ask('输入编号');
|
|
183
|
+
const idx = Number.parseInt(pick, 10) - 1;
|
|
184
|
+
if (Number.isNaN(idx) || idx < 0 || idx >= shown.length) {
|
|
185
|
+
log.error('无效编号');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const preset = shown[idx];
|
|
189
|
+
if (preset.auth === 'oauth-claude') {
|
|
190
|
+
await handleClaudeAuth(log, prompt, preset);
|
|
191
|
+
}
|
|
192
|
+
else if (preset.auth === 'proxy-sub') {
|
|
193
|
+
await handleProxyAuth(log, prompt, preset);
|
|
194
|
+
}
|
|
195
|
+
else if (preset.auth === 'redirect') {
|
|
196
|
+
log.info('用 API key 出 GPT → 选 OpenRouter,模型填 openai/gpt-*(如 openai/gpt-5.4)。');
|
|
197
|
+
log.info(' raine/claude-code-proxy 只认订阅登录、不吃 OpenAI API key,故不走它。');
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
await handleKeyPreset(log, prompt, preset);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
prompt.close();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async function handleKeyPreset(log, prompt, preset) {
|
|
208
|
+
// 自定义:先问 id/name/baseUrl
|
|
209
|
+
let id = preset.id;
|
|
210
|
+
let name = preset.name;
|
|
211
|
+
let baseUrl;
|
|
212
|
+
if (preset.id === 'custom') {
|
|
213
|
+
id = (await prompt.ask('端点 id(小写字母数字/-)')).trim();
|
|
214
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(id)) {
|
|
215
|
+
log.error('id 非法');
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
name = (await prompt.ask('显示名', id)).trim() || id;
|
|
219
|
+
baseUrl = (await prompt.ask('Anthropic 兼容 base URL')).trim().replace(/\/+$/, '');
|
|
220
|
+
if (!baseUrl) {
|
|
221
|
+
log.error('base URL 必填');
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
baseUrl = await resolveBaseUrl(prompt, preset);
|
|
227
|
+
}
|
|
228
|
+
if (preset.note)
|
|
229
|
+
log.info(preset.note);
|
|
230
|
+
// API key
|
|
231
|
+
const existing = getProvider(id);
|
|
232
|
+
const hasOld = existing && typeof existing.apiKey === 'string' && existing.apiKey.trim();
|
|
233
|
+
const key = (await prompt.ask(hasOld ? 'API key(回车保留已有)' : 'API key')).trim();
|
|
234
|
+
const apiKeyFinal = key || (hasOld ? existing.apiKey : '');
|
|
235
|
+
if (!apiKeyFinal) {
|
|
236
|
+
log.error('未填 API key');
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
// 模型
|
|
240
|
+
const model = await pickModel(prompt, preset);
|
|
241
|
+
if (!model) {
|
|
242
|
+
log.error('未选模型');
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
// 组装 provider entry。keyEnv=API_KEY 时 key 放 extraEnv.ANTHROPIC_API_KEY、apiKey 留空(官方 x-api-key)。
|
|
246
|
+
const useApiKeyEnv = preset.keyEnv === 'API_KEY';
|
|
247
|
+
const extraEnv = { ...(preset.extraEnv ?? {}) };
|
|
248
|
+
if (useApiKeyEnv)
|
|
249
|
+
extraEnv.ANTHROPIC_API_KEY = apiKeyFinal;
|
|
250
|
+
const entry = {
|
|
251
|
+
id,
|
|
252
|
+
name,
|
|
253
|
+
baseUrl,
|
|
254
|
+
apiKey: useApiKeyEnv ? '' : apiKeyFinal,
|
|
255
|
+
models: preset.models.length ? preset.models : [model],
|
|
256
|
+
...(Object.keys(extraEnv).length ? { extraEnv } : {}),
|
|
257
|
+
};
|
|
258
|
+
upsertProvider('anthropic', entry);
|
|
259
|
+
setWorkerDefault(id, model);
|
|
260
|
+
log.ok(`已配置 ${name} · 默认模型 ${model}(写入 providers.json + 设为 worker 默认)`);
|
|
261
|
+
log.info(' 新会话 / 新项目即用此模型;存量项目/会话不追溯。');
|
|
262
|
+
}
|
|
263
|
+
/** 有区域(cn/intl)时问一次,否则直接用。 */
|
|
264
|
+
async function resolveBaseUrl(prompt, preset) {
|
|
265
|
+
const b = preset.baseUrl;
|
|
266
|
+
if (typeof b === 'string')
|
|
267
|
+
return b;
|
|
268
|
+
if (!b)
|
|
269
|
+
return '';
|
|
270
|
+
const r = (await prompt.ask('区域 cn/intl', 'cn')).trim().toLowerCase();
|
|
271
|
+
return r === 'intl' ? b.intl : b.cn;
|
|
272
|
+
}
|
|
273
|
+
/** 列 curated 模型 + 允许自定义。 */
|
|
274
|
+
async function pickModel(prompt, preset) {
|
|
275
|
+
if (preset.models.length === 0) {
|
|
276
|
+
return (await prompt.ask('模型名')).trim();
|
|
277
|
+
}
|
|
278
|
+
console.log('');
|
|
279
|
+
preset.models.forEach((m, i) => console.log(` ${i + 1}. ${m}`));
|
|
280
|
+
console.log(` ${preset.models.length + 1}. 自定义…`);
|
|
281
|
+
const ans = (await prompt.ask('选模型编号或直接输入模型名', '1')).trim();
|
|
282
|
+
const n = Number.parseInt(ans, 10);
|
|
283
|
+
if (!Number.isNaN(n) && n >= 1 && n <= preset.models.length)
|
|
284
|
+
return preset.models[n - 1];
|
|
285
|
+
if (!Number.isNaN(n) && n === preset.models.length + 1)
|
|
286
|
+
return (await prompt.ask('模型名')).trim();
|
|
287
|
+
return ans; // 直接输入的模型名
|
|
288
|
+
}
|
|
289
|
+
async function handleClaudeAuth(log, prompt, preset) {
|
|
290
|
+
const sub = detectClaudeSub();
|
|
291
|
+
if (!sub.available) {
|
|
292
|
+
log.warn('未检测到 Claude 订阅登录,拉起 `claude auth login`…(按 Ctrl+C 取消)');
|
|
293
|
+
const code = await runAuth('claude', ['auth', 'login']);
|
|
294
|
+
if (code === 'cancelled') {
|
|
295
|
+
log.warn('已取消认证');
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (code !== 0 && !detectClaudeSub().available) {
|
|
299
|
+
log.error('登录未完成');
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
log.ok(`已登录 Claude 订阅(${sub.detail})`);
|
|
305
|
+
}
|
|
306
|
+
const model = await pickModel(prompt, preset);
|
|
307
|
+
if (!model) {
|
|
308
|
+
log.error('未选模型');
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
setWorkerDefault(undefined, model); // 官方订阅 = 空 providerId
|
|
312
|
+
log.ok(`设为 worker 默认:Claude 官方订阅 · ${model}`);
|
|
313
|
+
}
|
|
314
|
+
/** 三个订阅后端(codex/kimi/cursor)统一:同一 codex-proxy,providerId 均为 codex-proxy,后端由 model 选。 */
|
|
315
|
+
async function handleProxyAuth(log, prompt, preset) {
|
|
316
|
+
const backend = preset.proxyBackend;
|
|
317
|
+
if (!codexProxyBinPath()) {
|
|
318
|
+
log.error('未安装 codex-proxy。先跑:sps codex-proxy install');
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (!proxyBackendAuthed(backend)) {
|
|
322
|
+
log.warn(`未检测到 ${backend} 登录,拉起设备码登录…(按 Ctrl+C 取消)`);
|
|
323
|
+
const code = await runAuth('claude-code-proxy', [backend, 'auth', 'device']);
|
|
324
|
+
if (code === 'cancelled') {
|
|
325
|
+
log.warn('已取消认证');
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (code !== 0 && !proxyBackendAuthed(backend)) {
|
|
329
|
+
log.error('登录未完成');
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
log.ok(`${backend} 订阅已登录`);
|
|
335
|
+
}
|
|
336
|
+
const model = await pickModel(prompt, preset);
|
|
337
|
+
if (!model) {
|
|
338
|
+
log.error('未选模型');
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
setWorkerDefault(CODEX_PROXY_ID, model);
|
|
342
|
+
log.ok(`设为 worker 默认:codex-proxy · ${backend} · ${model}`);
|
|
343
|
+
log.info(' 提示:codex-proxy 会在会话按需保活;确保 sps codex-proxy status 正常。');
|
|
344
|
+
}
|
|
345
|
+
// ─── use(非交互设默认)─────────────────────────────────────────────
|
|
346
|
+
function useModel(log, id, model) {
|
|
347
|
+
if (!id || !model) {
|
|
348
|
+
console.error('Usage: sps model use <id> <model> (id: official | codex-proxy | <已配平台 id>)');
|
|
349
|
+
process.exit(2);
|
|
350
|
+
}
|
|
351
|
+
if (id === 'official' || id === 'claude-auth') {
|
|
352
|
+
setWorkerDefault(undefined, model);
|
|
353
|
+
log.ok(`worker 默认 → Claude 官方订阅 · ${model}`);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (id === CODEX_PROXY_ID || id === 'codex-auth' || id === 'kimi-sub' || id === 'cursor-sub') {
|
|
357
|
+
setWorkerDefault(CODEX_PROXY_ID, model);
|
|
358
|
+
log.ok(`worker 默认 → codex-proxy · ${backendOf(model)} · ${model}`);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (!getProvider(id)) {
|
|
362
|
+
log.error(`未找到已配平台 '${id}'。先 sps model set 配置它,或 sps model list 查看。`);
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
setWorkerDefault(id, model);
|
|
366
|
+
log.ok(`worker 默认 → ${id} · ${model}`);
|
|
367
|
+
}
|
|
368
|
+
// ─── auth(仅触发登录)──────────────────────────────────────────────
|
|
369
|
+
async function authPlatform(log, id) {
|
|
370
|
+
if (id === 'claude' || id === 'claude-auth') {
|
|
371
|
+
if (detectClaudeSub().available) {
|
|
372
|
+
log.ok('Claude 订阅已登录');
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
log.info('(按 Ctrl+C 取消)');
|
|
376
|
+
if ((await runAuth('claude', ['auth', 'login'])) === 'cancelled')
|
|
377
|
+
log.warn('已取消认证');
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
// codex / kimi / cursor 都走同一 codex-proxy
|
|
381
|
+
const backend = id === 'codex' || id === 'codex-auth' || id === CODEX_PROXY_ID ? 'codex'
|
|
382
|
+
: id === 'kimi' || id === 'kimi-sub' ? 'kimi'
|
|
383
|
+
: id === 'cursor' || id === 'cursor-sub' ? 'cursor'
|
|
384
|
+
: null;
|
|
385
|
+
if (backend) {
|
|
386
|
+
if (!codexProxyBinPath()) {
|
|
387
|
+
log.error('未装 codex-proxy。先跑:sps codex-proxy install');
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
if (proxyBackendAuthed(backend)) {
|
|
391
|
+
log.ok(`${backend} 订阅已登录`);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
log.info('(按 Ctrl+C 取消)');
|
|
395
|
+
if ((await runAuth('claude-code-proxy', [backend, 'auth', 'device'])) === 'cancelled')
|
|
396
|
+
log.warn('已取消认证');
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
console.error('Usage: sps model auth <claude|codex|kimi|cursor>');
|
|
400
|
+
process.exit(2);
|
|
401
|
+
}
|
|
402
|
+
// ─── rm ────────────────────────────────────────────────────────────
|
|
403
|
+
function removeModel(log, id) {
|
|
404
|
+
if (!id) {
|
|
405
|
+
console.error('Usage: sps model rm <id>');
|
|
406
|
+
process.exit(2);
|
|
407
|
+
}
|
|
408
|
+
const ok = deleteProvider('anthropic', id);
|
|
409
|
+
if (!ok) {
|
|
410
|
+
log.warn(`providers.json 里没有 '${id}'`);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
// 若正被用作默认 → 回落官方订阅 sonnet,避免悬空。
|
|
414
|
+
const agents = loadAgentsConfig();
|
|
415
|
+
if (agents.worker.providerId === id) {
|
|
416
|
+
setWorkerDefault(undefined, 'sonnet');
|
|
417
|
+
log.info(`'${id}' 曾是 worker 默认 → 已回落 Claude 官方订阅 · sonnet`);
|
|
418
|
+
}
|
|
419
|
+
log.ok(`已删除平台 '${id}'`);
|
|
420
|
+
}
|
|
421
|
+
// ─── 设 worker 默认(唯一写 agents 配置处)─────────────────────────────
|
|
422
|
+
function setWorkerDefault(providerId, model) {
|
|
423
|
+
const agents = loadAgentsConfig();
|
|
424
|
+
const worker = { ...agents.worker, model };
|
|
425
|
+
if (providerId)
|
|
426
|
+
worker.providerId = providerId;
|
|
427
|
+
else
|
|
428
|
+
delete worker.providerId; // 空 = 官方订阅
|
|
429
|
+
saveAgentsConfig({ ...agents, worker });
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=modelCommand.js.map
|