sessix-server 0.3.5 → 0.3.7
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/index.js +81 -15
- package/dist/server.js +79 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_node_os8 = require("os");
|
|
28
28
|
var import_node_fs4 = require("fs");
|
|
29
29
|
var import_node_path7 = require("path");
|
|
30
|
-
var
|
|
30
|
+
var import_node_child_process10 = require("child_process");
|
|
31
31
|
|
|
32
32
|
// src/i18n/locales/zh.ts
|
|
33
33
|
var zh = {
|
|
@@ -306,7 +306,7 @@ var import_uuid6 = require("uuid");
|
|
|
306
306
|
var import_promises4 = require("fs/promises");
|
|
307
307
|
var import_node_os7 = require("os");
|
|
308
308
|
var import_node_path6 = require("path");
|
|
309
|
-
var
|
|
309
|
+
var import_node_child_process9 = require("child_process");
|
|
310
310
|
var import_node_util = require("util");
|
|
311
311
|
|
|
312
312
|
// src/providers/ProcessProvider.ts
|
|
@@ -403,7 +403,7 @@ var ProcessProvider = class {
|
|
|
403
403
|
* 并开始监听 stdout 的 NDJSON 输出。
|
|
404
404
|
*/
|
|
405
405
|
async startSession(opts) {
|
|
406
|
-
const { projectPath, message, sessionId: existingSessionId, model, permissionMode, effort, images } = opts;
|
|
406
|
+
const { projectPath, message, sessionId: existingSessionId, model, permissionMode, effort, images, fallbackModel, maxBudgetUsd } = opts;
|
|
407
407
|
const sessionId = existingSessionId ?? (0, import_uuid.v4)();
|
|
408
408
|
if (this.activeSessions.has(sessionId)) {
|
|
409
409
|
await this.killSession(sessionId);
|
|
@@ -419,10 +419,10 @@ var ProcessProvider = class {
|
|
|
419
419
|
summary: message.slice(0, 80)
|
|
420
420
|
};
|
|
421
421
|
const resume = opts.resume ?? !!existingSessionId;
|
|
422
|
-
const proc = this.spawnClaudeProcess(sessionId, projectPath, resume, model, permissionMode, effort);
|
|
422
|
+
const proc = this.spawnClaudeProcess(sessionId, projectPath, resume, model, permissionMode, effort, fallbackModel, maxBudgetUsd);
|
|
423
423
|
this.writeUserMessage(proc, message, sessionId, images);
|
|
424
424
|
session.pid = proc.pid;
|
|
425
|
-
this.activeSessions.set(sessionId, { session, process: proc, model, permissionMode, effort });
|
|
425
|
+
this.activeSessions.set(sessionId, { session, process: proc, model, permissionMode, effort, fallbackModel, maxBudgetUsd });
|
|
426
426
|
proc.on("error", (err) => {
|
|
427
427
|
console.error(`[ProcessProvider] Session ${sessionId} process error:`, err.message);
|
|
428
428
|
this.activeSessions.delete(sessionId);
|
|
@@ -494,7 +494,7 @@ var ProcessProvider = class {
|
|
|
494
494
|
}
|
|
495
495
|
const savedPendingQuestion = entry.pendingQuestion;
|
|
496
496
|
const newMode = permissionMode ?? entry.permissionMode;
|
|
497
|
-
const proc = this.spawnClaudeProcess(sessionId, entry.session.projectPath, true, entry.model, newMode, entry.effort);
|
|
497
|
+
const proc = this.spawnClaudeProcess(sessionId, entry.session.projectPath, true, entry.model, newMode, entry.effort, entry.fallbackModel, entry.maxBudgetUsd);
|
|
498
498
|
this.writeUserMessage(proc, message, sessionId, images);
|
|
499
499
|
entry.session.status = "running";
|
|
500
500
|
entry.session.lastActiveAt = Date.now();
|
|
@@ -544,14 +544,15 @@ var ProcessProvider = class {
|
|
|
544
544
|
/**
|
|
545
545
|
* 启动 claude CLI 进程(持久模式,stdin 保持开放接收多条消息)
|
|
546
546
|
*/
|
|
547
|
-
spawnClaudeProcess(sessionId, projectPath, resume = false, model, permissionMode, effort) {
|
|
547
|
+
spawnClaudeProcess(sessionId, projectPath, resume = false, model, permissionMode, effort, fallbackModel, maxBudgetUsd) {
|
|
548
548
|
const args = [
|
|
549
549
|
"--input-format",
|
|
550
550
|
"stream-json",
|
|
551
551
|
"--output-format",
|
|
552
552
|
"stream-json",
|
|
553
553
|
"--verbose",
|
|
554
|
-
"--include-partial-messages"
|
|
554
|
+
"--include-partial-messages",
|
|
555
|
+
"--include-hook-events"
|
|
555
556
|
];
|
|
556
557
|
if (resume) {
|
|
557
558
|
args.push("--resume", sessionId);
|
|
@@ -567,6 +568,12 @@ var ProcessProvider = class {
|
|
|
567
568
|
if (effort) {
|
|
568
569
|
args.push("--effort", effort);
|
|
569
570
|
}
|
|
571
|
+
if (fallbackModel) {
|
|
572
|
+
args.push("--fallback-model", fallbackModel);
|
|
573
|
+
}
|
|
574
|
+
if (maxBudgetUsd != null) {
|
|
575
|
+
args.push("--max-budget-usd", String(maxBudgetUsd));
|
|
576
|
+
}
|
|
570
577
|
const env = { ...process.env, SESSIX_SESSION_ID: sessionId };
|
|
571
578
|
delete env.CLAUDECODE;
|
|
572
579
|
const proc = (0, import_child_process.spawn)(CLAUDE_PATH, args, {
|
|
@@ -1677,7 +1684,7 @@ var SessionManager = class {
|
|
|
1677
1684
|
* 调用 provider.startSession(),订阅事件流,
|
|
1678
1685
|
* 将 ClaudeStreamEvent 包装为 ServerEvent 转发。
|
|
1679
1686
|
*/
|
|
1680
|
-
async createSession(projectPath, message, resumeSessionId, newSessionId, model, permissionMode, effort, images, agentType) {
|
|
1687
|
+
async createSession(projectPath, message, resumeSessionId, newSessionId, model, permissionMode, effort, images, agentType, fallbackModel, maxBudgetUsd) {
|
|
1681
1688
|
let resolvedAgentType = agentType ?? "claude-code";
|
|
1682
1689
|
if (!agentType && resumeSessionId && this.providerFactory) {
|
|
1683
1690
|
const codexProvider = this.providerFactory.getProvider("codex");
|
|
@@ -1694,7 +1701,9 @@ var SessionManager = class {
|
|
|
1694
1701
|
model,
|
|
1695
1702
|
permissionMode,
|
|
1696
1703
|
effort,
|
|
1697
|
-
images
|
|
1704
|
+
images,
|
|
1705
|
+
fallbackModel,
|
|
1706
|
+
maxBudgetUsd
|
|
1698
1707
|
});
|
|
1699
1708
|
this.sessionAgentType.set(session.id, resolvedAgentType);
|
|
1700
1709
|
this.lastBroadcastStatus.set(session.id, session.status);
|
|
@@ -3275,6 +3284,8 @@ var NotificationService = class {
|
|
|
3275
3284
|
latestAssistantText = /* @__PURE__ */ new Map();
|
|
3276
3285
|
/** 获取全局待审批总数的回调(跨所有会话) */
|
|
3277
3286
|
globalPendingCountProvider = null;
|
|
3287
|
+
/** 获取当前 WS 连接数的回调(用于在线抑制推送) */
|
|
3288
|
+
connectionCountProvider = null;
|
|
3278
3289
|
/** 添加通知渠道(id 唯一,可用于后续动态开关) */
|
|
3279
3290
|
addChannel(id, channel, enabled = true) {
|
|
3280
3291
|
this.channelMap.set(id, { channel, enabled });
|
|
@@ -3312,6 +3323,10 @@ var NotificationService = class {
|
|
|
3312
3323
|
setGlobalPendingCountProvider(provider) {
|
|
3313
3324
|
this.globalPendingCountProvider = provider;
|
|
3314
3325
|
}
|
|
3326
|
+
/** 设置 WS 连接数提供者(用于 status_change 通知的在线抑制) */
|
|
3327
|
+
setConnectionCountProvider(provider) {
|
|
3328
|
+
this.connectionCountProvider = provider;
|
|
3329
|
+
}
|
|
3315
3330
|
/** 获取全局待审批总数 */
|
|
3316
3331
|
getGlobalPendingCount() {
|
|
3317
3332
|
return this.globalPendingCountProvider?.() ?? 0;
|
|
@@ -3454,7 +3469,7 @@ var NotificationService = class {
|
|
|
3454
3469
|
isYoloMode,
|
|
3455
3470
|
updatedAt: Date.now()
|
|
3456
3471
|
});
|
|
3457
|
-
} else {
|
|
3472
|
+
} else if ((this.connectionCountProvider?.() ?? 0) === 0) {
|
|
3458
3473
|
this.notify({
|
|
3459
3474
|
title: sessionTitle,
|
|
3460
3475
|
body,
|
|
@@ -3476,7 +3491,7 @@ var NotificationService = class {
|
|
|
3476
3491
|
isYoloMode,
|
|
3477
3492
|
updatedAt: Date.now()
|
|
3478
3493
|
});
|
|
3479
|
-
} else {
|
|
3494
|
+
} else if ((this.connectionCountProvider?.() ?? 0) === 0) {
|
|
3480
3495
|
this.notify({
|
|
3481
3496
|
title: sessionTitle,
|
|
3482
3497
|
body,
|
|
@@ -4410,10 +4425,50 @@ var TerminalExecutor = class {
|
|
|
4410
4425
|
}
|
|
4411
4426
|
};
|
|
4412
4427
|
|
|
4428
|
+
// src/utils/cliCapabilities.ts
|
|
4429
|
+
var import_node_child_process8 = require("child_process");
|
|
4430
|
+
var DEFAULT_CAPABILITIES = {
|
|
4431
|
+
effortLevels: ["low", "medium", "high", "xhigh", "max"]
|
|
4432
|
+
};
|
|
4433
|
+
async function parseCliCapabilities() {
|
|
4434
|
+
const claudePath = findClaudePath();
|
|
4435
|
+
const [helpText, version] = await Promise.all([
|
|
4436
|
+
runCli(claudePath, ["--help"]),
|
|
4437
|
+
runCli(claudePath, ["--version"])
|
|
4438
|
+
]);
|
|
4439
|
+
const capabilities = { ...DEFAULT_CAPABILITIES };
|
|
4440
|
+
if (version) {
|
|
4441
|
+
capabilities.version = version.trim();
|
|
4442
|
+
}
|
|
4443
|
+
if (helpText) {
|
|
4444
|
+
const effortMatch = helpText.match(/--effort\s.*?\(([^)]+)\)/);
|
|
4445
|
+
if (effortMatch) {
|
|
4446
|
+
const levels = effortMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
4447
|
+
if (levels.length > 0) {
|
|
4448
|
+
capabilities.effortLevels = levels;
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4452
|
+
console.log(`[CliCapabilities] version=${capabilities.version ?? "unknown"}, effort=[${capabilities.effortLevels.join(", ")}]`);
|
|
4453
|
+
return capabilities;
|
|
4454
|
+
}
|
|
4455
|
+
function runCli(path2, args) {
|
|
4456
|
+
return new Promise((resolve) => {
|
|
4457
|
+
(0, import_node_child_process8.execFile)(path2, args, { timeout: 5e3 }, (err, stdout) => {
|
|
4458
|
+
if (err) {
|
|
4459
|
+
console.warn(`[CliCapabilities] Failed to run ${path2} ${args.join(" ")}:`, err.message);
|
|
4460
|
+
resolve(null);
|
|
4461
|
+
} else {
|
|
4462
|
+
resolve(stdout);
|
|
4463
|
+
}
|
|
4464
|
+
});
|
|
4465
|
+
});
|
|
4466
|
+
}
|
|
4467
|
+
|
|
4413
4468
|
// src/server.ts
|
|
4414
4469
|
var WS_PORT = 3745;
|
|
4415
4470
|
var HTTP_PORT = 3746;
|
|
4416
|
-
var execAsync = (0, import_node_util.promisify)(
|
|
4471
|
+
var execAsync = (0, import_node_util.promisify)(import_node_child_process9.exec);
|
|
4417
4472
|
async function killPortProcess(port) {
|
|
4418
4473
|
try {
|
|
4419
4474
|
if (isWindows) {
|
|
@@ -4535,6 +4590,12 @@ async function start(opts = {}) {
|
|
|
4535
4590
|
notificationService.setGlobalPendingCountProvider(
|
|
4536
4591
|
() => approvalProxy.getPendingCount() + sessionManager.getAllPendingQuestions().length + unreadSessionIds.size
|
|
4537
4592
|
);
|
|
4593
|
+
notificationService.setConnectionCountProvider(() => wsBridge.getConnectionCount());
|
|
4594
|
+
let cliCapabilities = null;
|
|
4595
|
+
parseCliCapabilities().then((caps) => {
|
|
4596
|
+
cliCapabilities = caps;
|
|
4597
|
+
}).catch(() => {
|
|
4598
|
+
});
|
|
4538
4599
|
const broadcastUnreadSessions = () => {
|
|
4539
4600
|
wsBridge.broadcast({ type: "unread_sessions", sessionIds: Array.from(unreadSessionIds) });
|
|
4540
4601
|
};
|
|
@@ -4556,6 +4617,9 @@ async function start(opts = {}) {
|
|
|
4556
4617
|
if (unreadSessionIds.size > 0) {
|
|
4557
4618
|
wsBridge.send(ws, { type: "unread_sessions", sessionIds: Array.from(unreadSessionIds) });
|
|
4558
4619
|
}
|
|
4620
|
+
if (cliCapabilities) {
|
|
4621
|
+
wsBridge.send(ws, { type: "cli_info", effortLevels: cliCapabilities.effortLevels, version: cliCapabilities.version });
|
|
4622
|
+
}
|
|
4559
4623
|
});
|
|
4560
4624
|
wsBridge.onClientEvent(async (event, ws) => {
|
|
4561
4625
|
try {
|
|
@@ -4573,7 +4637,9 @@ async function start(opts = {}) {
|
|
|
4573
4637
|
event.permissionMode,
|
|
4574
4638
|
event.effort,
|
|
4575
4639
|
event.images,
|
|
4576
|
-
event.agentType
|
|
4640
|
+
event.agentType,
|
|
4641
|
+
event.fallbackModel,
|
|
4642
|
+
event.maxBudgetUsd
|
|
4577
4643
|
);
|
|
4578
4644
|
wsBridge.broadcast({
|
|
4579
4645
|
type: "session_list",
|
|
@@ -5076,7 +5142,7 @@ async function autoUpdateIfNeeded() {
|
|
|
5076
5142
|
console.log(` \u{1F4E6} ${t("startup.autoUpdating", { current: PKG_VERSION, latest })}`);
|
|
5077
5143
|
console.log();
|
|
5078
5144
|
try {
|
|
5079
|
-
(0,
|
|
5145
|
+
(0, import_node_child_process10.execFileSync)("npx", [`sessix-server@${latest}`], {
|
|
5080
5146
|
stdio: "inherit",
|
|
5081
5147
|
env: { ...process.env, __SESSIX_UPDATED: "1" }
|
|
5082
5148
|
});
|
package/dist/server.js
CHANGED
|
@@ -311,7 +311,7 @@ var import_uuid6 = require("uuid");
|
|
|
311
311
|
var import_promises4 = require("fs/promises");
|
|
312
312
|
var import_node_os7 = require("os");
|
|
313
313
|
var import_node_path6 = require("path");
|
|
314
|
-
var
|
|
314
|
+
var import_node_child_process9 = require("child_process");
|
|
315
315
|
var import_node_util = require("util");
|
|
316
316
|
|
|
317
317
|
// src/providers/ProcessProvider.ts
|
|
@@ -408,7 +408,7 @@ var ProcessProvider = class {
|
|
|
408
408
|
* 并开始监听 stdout 的 NDJSON 输出。
|
|
409
409
|
*/
|
|
410
410
|
async startSession(opts) {
|
|
411
|
-
const { projectPath, message, sessionId: existingSessionId, model, permissionMode, effort, images } = opts;
|
|
411
|
+
const { projectPath, message, sessionId: existingSessionId, model, permissionMode, effort, images, fallbackModel, maxBudgetUsd } = opts;
|
|
412
412
|
const sessionId = existingSessionId ?? (0, import_uuid.v4)();
|
|
413
413
|
if (this.activeSessions.has(sessionId)) {
|
|
414
414
|
await this.killSession(sessionId);
|
|
@@ -424,10 +424,10 @@ var ProcessProvider = class {
|
|
|
424
424
|
summary: message.slice(0, 80)
|
|
425
425
|
};
|
|
426
426
|
const resume = opts.resume ?? !!existingSessionId;
|
|
427
|
-
const proc = this.spawnClaudeProcess(sessionId, projectPath, resume, model, permissionMode, effort);
|
|
427
|
+
const proc = this.spawnClaudeProcess(sessionId, projectPath, resume, model, permissionMode, effort, fallbackModel, maxBudgetUsd);
|
|
428
428
|
this.writeUserMessage(proc, message, sessionId, images);
|
|
429
429
|
session.pid = proc.pid;
|
|
430
|
-
this.activeSessions.set(sessionId, { session, process: proc, model, permissionMode, effort });
|
|
430
|
+
this.activeSessions.set(sessionId, { session, process: proc, model, permissionMode, effort, fallbackModel, maxBudgetUsd });
|
|
431
431
|
proc.on("error", (err) => {
|
|
432
432
|
console.error(`[ProcessProvider] Session ${sessionId} process error:`, err.message);
|
|
433
433
|
this.activeSessions.delete(sessionId);
|
|
@@ -499,7 +499,7 @@ var ProcessProvider = class {
|
|
|
499
499
|
}
|
|
500
500
|
const savedPendingQuestion = entry.pendingQuestion;
|
|
501
501
|
const newMode = permissionMode ?? entry.permissionMode;
|
|
502
|
-
const proc = this.spawnClaudeProcess(sessionId, entry.session.projectPath, true, entry.model, newMode, entry.effort);
|
|
502
|
+
const proc = this.spawnClaudeProcess(sessionId, entry.session.projectPath, true, entry.model, newMode, entry.effort, entry.fallbackModel, entry.maxBudgetUsd);
|
|
503
503
|
this.writeUserMessage(proc, message, sessionId, images);
|
|
504
504
|
entry.session.status = "running";
|
|
505
505
|
entry.session.lastActiveAt = Date.now();
|
|
@@ -549,14 +549,15 @@ var ProcessProvider = class {
|
|
|
549
549
|
/**
|
|
550
550
|
* 启动 claude CLI 进程(持久模式,stdin 保持开放接收多条消息)
|
|
551
551
|
*/
|
|
552
|
-
spawnClaudeProcess(sessionId, projectPath, resume = false, model, permissionMode, effort) {
|
|
552
|
+
spawnClaudeProcess(sessionId, projectPath, resume = false, model, permissionMode, effort, fallbackModel, maxBudgetUsd) {
|
|
553
553
|
const args = [
|
|
554
554
|
"--input-format",
|
|
555
555
|
"stream-json",
|
|
556
556
|
"--output-format",
|
|
557
557
|
"stream-json",
|
|
558
558
|
"--verbose",
|
|
559
|
-
"--include-partial-messages"
|
|
559
|
+
"--include-partial-messages",
|
|
560
|
+
"--include-hook-events"
|
|
560
561
|
];
|
|
561
562
|
if (resume) {
|
|
562
563
|
args.push("--resume", sessionId);
|
|
@@ -572,6 +573,12 @@ var ProcessProvider = class {
|
|
|
572
573
|
if (effort) {
|
|
573
574
|
args.push("--effort", effort);
|
|
574
575
|
}
|
|
576
|
+
if (fallbackModel) {
|
|
577
|
+
args.push("--fallback-model", fallbackModel);
|
|
578
|
+
}
|
|
579
|
+
if (maxBudgetUsd != null) {
|
|
580
|
+
args.push("--max-budget-usd", String(maxBudgetUsd));
|
|
581
|
+
}
|
|
575
582
|
const env = { ...process.env, SESSIX_SESSION_ID: sessionId };
|
|
576
583
|
delete env.CLAUDECODE;
|
|
577
584
|
const proc = (0, import_child_process.spawn)(CLAUDE_PATH, args, {
|
|
@@ -1682,7 +1689,7 @@ var SessionManager = class {
|
|
|
1682
1689
|
* 调用 provider.startSession(),订阅事件流,
|
|
1683
1690
|
* 将 ClaudeStreamEvent 包装为 ServerEvent 转发。
|
|
1684
1691
|
*/
|
|
1685
|
-
async createSession(projectPath, message, resumeSessionId, newSessionId, model, permissionMode, effort, images, agentType) {
|
|
1692
|
+
async createSession(projectPath, message, resumeSessionId, newSessionId, model, permissionMode, effort, images, agentType, fallbackModel, maxBudgetUsd) {
|
|
1686
1693
|
let resolvedAgentType = agentType ?? "claude-code";
|
|
1687
1694
|
if (!agentType && resumeSessionId && this.providerFactory) {
|
|
1688
1695
|
const codexProvider = this.providerFactory.getProvider("codex");
|
|
@@ -1699,7 +1706,9 @@ var SessionManager = class {
|
|
|
1699
1706
|
model,
|
|
1700
1707
|
permissionMode,
|
|
1701
1708
|
effort,
|
|
1702
|
-
images
|
|
1709
|
+
images,
|
|
1710
|
+
fallbackModel,
|
|
1711
|
+
maxBudgetUsd
|
|
1703
1712
|
});
|
|
1704
1713
|
this.sessionAgentType.set(session.id, resolvedAgentType);
|
|
1705
1714
|
this.lastBroadcastStatus.set(session.id, session.status);
|
|
@@ -3280,6 +3289,8 @@ var NotificationService = class {
|
|
|
3280
3289
|
latestAssistantText = /* @__PURE__ */ new Map();
|
|
3281
3290
|
/** 获取全局待审批总数的回调(跨所有会话) */
|
|
3282
3291
|
globalPendingCountProvider = null;
|
|
3292
|
+
/** 获取当前 WS 连接数的回调(用于在线抑制推送) */
|
|
3293
|
+
connectionCountProvider = null;
|
|
3283
3294
|
/** 添加通知渠道(id 唯一,可用于后续动态开关) */
|
|
3284
3295
|
addChannel(id, channel, enabled = true) {
|
|
3285
3296
|
this.channelMap.set(id, { channel, enabled });
|
|
@@ -3317,6 +3328,10 @@ var NotificationService = class {
|
|
|
3317
3328
|
setGlobalPendingCountProvider(provider) {
|
|
3318
3329
|
this.globalPendingCountProvider = provider;
|
|
3319
3330
|
}
|
|
3331
|
+
/** 设置 WS 连接数提供者(用于 status_change 通知的在线抑制) */
|
|
3332
|
+
setConnectionCountProvider(provider) {
|
|
3333
|
+
this.connectionCountProvider = provider;
|
|
3334
|
+
}
|
|
3320
3335
|
/** 获取全局待审批总数 */
|
|
3321
3336
|
getGlobalPendingCount() {
|
|
3322
3337
|
return this.globalPendingCountProvider?.() ?? 0;
|
|
@@ -3459,7 +3474,7 @@ var NotificationService = class {
|
|
|
3459
3474
|
isYoloMode,
|
|
3460
3475
|
updatedAt: Date.now()
|
|
3461
3476
|
});
|
|
3462
|
-
} else {
|
|
3477
|
+
} else if ((this.connectionCountProvider?.() ?? 0) === 0) {
|
|
3463
3478
|
this.notify({
|
|
3464
3479
|
title: sessionTitle,
|
|
3465
3480
|
body,
|
|
@@ -3481,7 +3496,7 @@ var NotificationService = class {
|
|
|
3481
3496
|
isYoloMode,
|
|
3482
3497
|
updatedAt: Date.now()
|
|
3483
3498
|
});
|
|
3484
|
-
} else {
|
|
3499
|
+
} else if ((this.connectionCountProvider?.() ?? 0) === 0) {
|
|
3485
3500
|
this.notify({
|
|
3486
3501
|
title: sessionTitle,
|
|
3487
3502
|
body,
|
|
@@ -4415,10 +4430,50 @@ var TerminalExecutor = class {
|
|
|
4415
4430
|
}
|
|
4416
4431
|
};
|
|
4417
4432
|
|
|
4433
|
+
// src/utils/cliCapabilities.ts
|
|
4434
|
+
var import_node_child_process8 = require("child_process");
|
|
4435
|
+
var DEFAULT_CAPABILITIES = {
|
|
4436
|
+
effortLevels: ["low", "medium", "high", "xhigh", "max"]
|
|
4437
|
+
};
|
|
4438
|
+
async function parseCliCapabilities() {
|
|
4439
|
+
const claudePath = findClaudePath();
|
|
4440
|
+
const [helpText, version] = await Promise.all([
|
|
4441
|
+
runCli(claudePath, ["--help"]),
|
|
4442
|
+
runCli(claudePath, ["--version"])
|
|
4443
|
+
]);
|
|
4444
|
+
const capabilities = { ...DEFAULT_CAPABILITIES };
|
|
4445
|
+
if (version) {
|
|
4446
|
+
capabilities.version = version.trim();
|
|
4447
|
+
}
|
|
4448
|
+
if (helpText) {
|
|
4449
|
+
const effortMatch = helpText.match(/--effort\s.*?\(([^)]+)\)/);
|
|
4450
|
+
if (effortMatch) {
|
|
4451
|
+
const levels = effortMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
|
|
4452
|
+
if (levels.length > 0) {
|
|
4453
|
+
capabilities.effortLevels = levels;
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
console.log(`[CliCapabilities] version=${capabilities.version ?? "unknown"}, effort=[${capabilities.effortLevels.join(", ")}]`);
|
|
4458
|
+
return capabilities;
|
|
4459
|
+
}
|
|
4460
|
+
function runCli(path2, args) {
|
|
4461
|
+
return new Promise((resolve) => {
|
|
4462
|
+
(0, import_node_child_process8.execFile)(path2, args, { timeout: 5e3 }, (err, stdout) => {
|
|
4463
|
+
if (err) {
|
|
4464
|
+
console.warn(`[CliCapabilities] Failed to run ${path2} ${args.join(" ")}:`, err.message);
|
|
4465
|
+
resolve(null);
|
|
4466
|
+
} else {
|
|
4467
|
+
resolve(stdout);
|
|
4468
|
+
}
|
|
4469
|
+
});
|
|
4470
|
+
});
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4418
4473
|
// src/server.ts
|
|
4419
4474
|
var WS_PORT = 3745;
|
|
4420
4475
|
var HTTP_PORT = 3746;
|
|
4421
|
-
var execAsync = (0, import_node_util.promisify)(
|
|
4476
|
+
var execAsync = (0, import_node_util.promisify)(import_node_child_process9.exec);
|
|
4422
4477
|
async function killPortProcess(port) {
|
|
4423
4478
|
try {
|
|
4424
4479
|
if (isWindows) {
|
|
@@ -4540,6 +4595,12 @@ async function start(opts = {}) {
|
|
|
4540
4595
|
notificationService.setGlobalPendingCountProvider(
|
|
4541
4596
|
() => approvalProxy.getPendingCount() + sessionManager.getAllPendingQuestions().length + unreadSessionIds.size
|
|
4542
4597
|
);
|
|
4598
|
+
notificationService.setConnectionCountProvider(() => wsBridge.getConnectionCount());
|
|
4599
|
+
let cliCapabilities = null;
|
|
4600
|
+
parseCliCapabilities().then((caps) => {
|
|
4601
|
+
cliCapabilities = caps;
|
|
4602
|
+
}).catch(() => {
|
|
4603
|
+
});
|
|
4543
4604
|
const broadcastUnreadSessions = () => {
|
|
4544
4605
|
wsBridge.broadcast({ type: "unread_sessions", sessionIds: Array.from(unreadSessionIds) });
|
|
4545
4606
|
};
|
|
@@ -4561,6 +4622,9 @@ async function start(opts = {}) {
|
|
|
4561
4622
|
if (unreadSessionIds.size > 0) {
|
|
4562
4623
|
wsBridge.send(ws, { type: "unread_sessions", sessionIds: Array.from(unreadSessionIds) });
|
|
4563
4624
|
}
|
|
4625
|
+
if (cliCapabilities) {
|
|
4626
|
+
wsBridge.send(ws, { type: "cli_info", effortLevels: cliCapabilities.effortLevels, version: cliCapabilities.version });
|
|
4627
|
+
}
|
|
4564
4628
|
});
|
|
4565
4629
|
wsBridge.onClientEvent(async (event, ws) => {
|
|
4566
4630
|
try {
|
|
@@ -4578,7 +4642,9 @@ async function start(opts = {}) {
|
|
|
4578
4642
|
event.permissionMode,
|
|
4579
4643
|
event.effort,
|
|
4580
4644
|
event.images,
|
|
4581
|
-
event.agentType
|
|
4645
|
+
event.agentType,
|
|
4646
|
+
event.fallbackModel,
|
|
4647
|
+
event.maxBudgetUsd
|
|
4582
4648
|
);
|
|
4583
4649
|
wsBridge.broadcast({
|
|
4584
4650
|
type: "session_list",
|