sessix-server 0.3.6 → 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 CHANGED
@@ -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);
@@ -2335,7 +2344,7 @@ var WsBridge = class _WsBridge {
2335
2344
  onConnection(callback) {
2336
2345
  this.connectionCallbacks.push(callback);
2337
2346
  }
2338
- /** 注册断开连接回调(任意客户端断开时触发,传入断开的 ws 对象) */
2347
+ /** 注册断开连接回调(任意客户端断开时触发,可通过 getConnectionCount() 判断是否全部断开) */
2339
2348
  onDisconnect(callback) {
2340
2349
  this.disconnectCallbacks.push(callback);
2341
2350
  }
@@ -2449,7 +2458,7 @@ var WsBridge = class _WsBridge {
2449
2458
  console.log(`[WsBridge] Client disconnected, connections: ${this.getConnectionCount()}`);
2450
2459
  for (const cb of this.disconnectCallbacks) {
2451
2460
  try {
2452
- cb(ws);
2461
+ cb();
2453
2462
  } catch (err) {
2454
2463
  console.error("[WsBridge] Disconnect callback error:", err);
2455
2464
  }
@@ -3318,10 +3327,6 @@ var NotificationService = class {
3318
3327
  setConnectionCountProvider(provider) {
3319
3328
  this.connectionCountProvider = provider;
3320
3329
  }
3321
- /** 移除指定 WebSocket 关联的所有 push token */
3322
- removeTokensByWs(ws) {
3323
- this.expoChannel?.removeTokensByWs(ws);
3324
- }
3325
3330
  /** 获取全局待审批总数 */
3326
3331
  getGlobalPendingCount() {
3327
3332
  return this.globalPendingCountProvider?.() ?? 0;
@@ -3574,17 +3579,6 @@ var ExpoNotificationChannel = class {
3574
3579
  this.soundPreferences.delete(token);
3575
3580
  console.log(`[ExpoNotificationChannel] ${t("notification.tokenRemoved", { count: this.tokens.size })}`);
3576
3581
  }
3577
- /** 移除指定 WebSocket 关联的所有 token(设备断开时调用) */
3578
- removeTokensByWs(ws) {
3579
- for (const [token, tokenWs] of this.tokenWsMap) {
3580
- if (tokenWs === ws) {
3581
- this.tokens.delete(token);
3582
- this.tokenWsMap.delete(token);
3583
- this.soundPreferences.delete(token);
3584
- console.log(`[ExpoNotificationChannel] Token removed on WS disconnect, remaining: ${this.tokens.size}`);
3585
- }
3586
- }
3587
- }
3588
3582
  /** 更新某个 token 的音效偏好 */
3589
3583
  setSoundPreferences(prefs) {
3590
3584
  for (const token of this.tokens) {
@@ -4434,7 +4428,7 @@ var TerminalExecutor = class {
4434
4428
  // src/utils/cliCapabilities.ts
4435
4429
  var import_node_child_process8 = require("child_process");
4436
4430
  var DEFAULT_CAPABILITIES = {
4437
- effortLevels: ["low", "medium", "high", "max"]
4431
+ effortLevels: ["low", "medium", "high", "xhigh", "max"]
4438
4432
  };
4439
4433
  async function parseCliCapabilities() {
4440
4434
  const claudePath = findClaudePath();
@@ -4643,7 +4637,9 @@ async function start(opts = {}) {
4643
4637
  event.permissionMode,
4644
4638
  event.effort,
4645
4639
  event.images,
4646
- event.agentType
4640
+ event.agentType,
4641
+ event.fallbackModel,
4642
+ event.maxBudgetUsd
4647
4643
  );
4648
4644
  wsBridge.broadcast({
4649
4645
  type: "session_list",
@@ -4961,8 +4957,7 @@ async function start(opts = {}) {
4961
4957
  terminalExecutor.onEvent((event) => {
4962
4958
  wsBridge.broadcast(event);
4963
4959
  });
4964
- wsBridge.onDisconnect((ws) => {
4965
- notificationService.removeTokensByWs(ws);
4960
+ wsBridge.onDisconnect(() => {
4966
4961
  if (wsBridge.getConnectionCount() === 0 && approvalProxy.getPendingCount() > 0) {
4967
4962
  approvalProxy.approveAll(t("server.phoneDisconnected"));
4968
4963
  }
package/dist/server.js CHANGED
@@ -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);
@@ -2340,7 +2349,7 @@ var WsBridge = class _WsBridge {
2340
2349
  onConnection(callback) {
2341
2350
  this.connectionCallbacks.push(callback);
2342
2351
  }
2343
- /** 注册断开连接回调(任意客户端断开时触发,传入断开的 ws 对象) */
2352
+ /** 注册断开连接回调(任意客户端断开时触发,可通过 getConnectionCount() 判断是否全部断开) */
2344
2353
  onDisconnect(callback) {
2345
2354
  this.disconnectCallbacks.push(callback);
2346
2355
  }
@@ -2454,7 +2463,7 @@ var WsBridge = class _WsBridge {
2454
2463
  console.log(`[WsBridge] Client disconnected, connections: ${this.getConnectionCount()}`);
2455
2464
  for (const cb of this.disconnectCallbacks) {
2456
2465
  try {
2457
- cb(ws);
2466
+ cb();
2458
2467
  } catch (err) {
2459
2468
  console.error("[WsBridge] Disconnect callback error:", err);
2460
2469
  }
@@ -3323,10 +3332,6 @@ var NotificationService = class {
3323
3332
  setConnectionCountProvider(provider) {
3324
3333
  this.connectionCountProvider = provider;
3325
3334
  }
3326
- /** 移除指定 WebSocket 关联的所有 push token */
3327
- removeTokensByWs(ws) {
3328
- this.expoChannel?.removeTokensByWs(ws);
3329
- }
3330
3335
  /** 获取全局待审批总数 */
3331
3336
  getGlobalPendingCount() {
3332
3337
  return this.globalPendingCountProvider?.() ?? 0;
@@ -3579,17 +3584,6 @@ var ExpoNotificationChannel = class {
3579
3584
  this.soundPreferences.delete(token);
3580
3585
  console.log(`[ExpoNotificationChannel] ${t("notification.tokenRemoved", { count: this.tokens.size })}`);
3581
3586
  }
3582
- /** 移除指定 WebSocket 关联的所有 token(设备断开时调用) */
3583
- removeTokensByWs(ws) {
3584
- for (const [token, tokenWs] of this.tokenWsMap) {
3585
- if (tokenWs === ws) {
3586
- this.tokens.delete(token);
3587
- this.tokenWsMap.delete(token);
3588
- this.soundPreferences.delete(token);
3589
- console.log(`[ExpoNotificationChannel] Token removed on WS disconnect, remaining: ${this.tokens.size}`);
3590
- }
3591
- }
3592
- }
3593
3587
  /** 更新某个 token 的音效偏好 */
3594
3588
  setSoundPreferences(prefs) {
3595
3589
  for (const token of this.tokens) {
@@ -4439,7 +4433,7 @@ var TerminalExecutor = class {
4439
4433
  // src/utils/cliCapabilities.ts
4440
4434
  var import_node_child_process8 = require("child_process");
4441
4435
  var DEFAULT_CAPABILITIES = {
4442
- effortLevels: ["low", "medium", "high", "max"]
4436
+ effortLevels: ["low", "medium", "high", "xhigh", "max"]
4443
4437
  };
4444
4438
  async function parseCliCapabilities() {
4445
4439
  const claudePath = findClaudePath();
@@ -4648,7 +4642,9 @@ async function start(opts = {}) {
4648
4642
  event.permissionMode,
4649
4643
  event.effort,
4650
4644
  event.images,
4651
- event.agentType
4645
+ event.agentType,
4646
+ event.fallbackModel,
4647
+ event.maxBudgetUsd
4652
4648
  );
4653
4649
  wsBridge.broadcast({
4654
4650
  type: "session_list",
@@ -4966,8 +4962,7 @@ async function start(opts = {}) {
4966
4962
  terminalExecutor.onEvent((event) => {
4967
4963
  wsBridge.broadcast(event);
4968
4964
  });
4969
- wsBridge.onDisconnect((ws) => {
4970
- notificationService.removeTokensByWs(ws);
4965
+ wsBridge.onDisconnect(() => {
4971
4966
  if (wsBridge.getConnectionCount() === 0 && approvalProxy.getPendingCount() > 0) {
4972
4967
  approvalProxy.approveAll(t("server.phoneDisconnected"));
4973
4968
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sessix-server",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "bin": {
5
5
  "sessix-server": "dist/index.js"
6
6
  },