sessix-server 0.3.7 → 0.3.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/index.js CHANGED
@@ -2523,6 +2523,8 @@ var ApprovalProxy = class _ApprovalProxy {
2523
2523
  pendingApprovals = /* @__PURE__ */ new Map();
2524
2524
  /** 审批请求回调(通知外部推送到手机) */
2525
2525
  approvalRequestCallbacks = [];
2526
+ /** 审批 resolve 回调(任何来源的 resolve 都会触发,用于 WS 广播清理 */
2527
+ approvalResolvedCallbacks = [];
2526
2528
  /** YOLO 模式状态:sessionId -> enabled */
2527
2529
  yoloSessions = /* @__PURE__ */ new Map();
2528
2530
  /** 内存缓存:已被"始终允许"的工具名(避免每次读 settings.json) */
@@ -2560,6 +2562,30 @@ var ApprovalProxy = class _ApprovalProxy {
2560
2562
  onApprovalRequest(callback) {
2561
2563
  this.approvalRequestCallbacks.push(callback);
2562
2564
  }
2565
+ /**
2566
+ * 注册审批 resolve 回调
2567
+ *
2568
+ * 任何来源的 resolve 都会触发:
2569
+ * - resolveApproval(手机端 approve/reject)
2570
+ * - 5 分钟超时自动 allow
2571
+ * - clearPendingForSession(会话被 kill)
2572
+ * - approveAll(手机全断时自动 allow)
2573
+ *
2574
+ * 用于向所有客户端广播 approval_resolved,清理可能残留的审批 UI。
2575
+ */
2576
+ onApprovalResolved(callback) {
2577
+ this.approvalResolvedCallbacks.push(callback);
2578
+ }
2579
+ /** 通知所有 resolve 回调(内部调用) */
2580
+ notifyApprovalResolved(requestId, decision) {
2581
+ for (const callback of this.approvalResolvedCallbacks) {
2582
+ try {
2583
+ callback(requestId, decision);
2584
+ } catch (err) {
2585
+ console.error("[ApprovalProxy] Approval resolved callback error:", err);
2586
+ }
2587
+ }
2588
+ }
2563
2589
  /** 设置状态信息提供者(用于 /health 端点) */
2564
2590
  setStatusInfoProvider(provider) {
2565
2591
  this.statusInfoProvider = provider;
@@ -2593,6 +2619,7 @@ var ApprovalProxy = class _ApprovalProxy {
2593
2619
  pending.resolve(decision);
2594
2620
  this.pendingApprovals.delete(requestId);
2595
2621
  console.log(`[ApprovalProxy] ${t("approval.requestProcessed", { id: requestId })}: ${decision.decision}`);
2622
+ this.notifyApprovalResolved(requestId, decision);
2596
2623
  return true;
2597
2624
  }
2598
2625
  /** 获取当前待处理的审批数量 */
@@ -2608,9 +2635,11 @@ var ApprovalProxy = class _ApprovalProxy {
2608
2635
  for (const [requestId, pending] of this.pendingApprovals) {
2609
2636
  if (pending.request.sessionId === sessionId) {
2610
2637
  clearTimeout(pending.timer);
2611
- pending.resolve({ decision: "allow" });
2638
+ const decision = { decision: "allow" };
2639
+ pending.resolve(decision);
2612
2640
  this.pendingApprovals.delete(requestId);
2613
2641
  console.log(`[ApprovalProxy] Session ${sessionId} killed, auto-allowed pending approval ${requestId}`);
2642
+ this.notifyApprovalResolved(requestId, decision);
2614
2643
  }
2615
2644
  }
2616
2645
  }
@@ -2698,9 +2727,11 @@ var ApprovalProxy = class _ApprovalProxy {
2698
2727
  const entries = Array.from(this.pendingApprovals.entries());
2699
2728
  for (const [requestId, pending] of entries) {
2700
2729
  clearTimeout(pending.timer);
2701
- pending.resolve({ decision: "allow" });
2730
+ const decision = { decision: "allow" };
2731
+ pending.resolve(decision);
2702
2732
  this.pendingApprovals.delete(requestId);
2703
2733
  console.log(`[ApprovalProxy] ${t("approval.autoAllowed", { id: requestId, reason: reason ? `\uFF08${reason}\uFF09` : "" })}`);
2734
+ this.notifyApprovalResolved(requestId, decision);
2704
2735
  }
2705
2736
  }
2706
2737
  /** 优雅关闭 HTTP 服务 */
@@ -2792,7 +2823,9 @@ var ApprovalProxy = class _ApprovalProxy {
2792
2823
  const timer = setTimeout(() => {
2793
2824
  console.log(`[ApprovalProxy] ${t("approval.timeout", { id: requestId })}`);
2794
2825
  this.pendingApprovals.delete(requestId);
2795
- resolve({ decision: "allow" });
2826
+ const autoDecision = { decision: "allow" };
2827
+ resolve(autoDecision);
2828
+ this.notifyApprovalResolved(requestId, autoDecision);
2796
2829
  }, 325e3);
2797
2830
  this.pendingApprovals.set(requestId, { resolve, timer, request: approvalRequest });
2798
2831
  });
@@ -3284,8 +3317,6 @@ var NotificationService = class {
3284
3317
  latestAssistantText = /* @__PURE__ */ new Map();
3285
3318
  /** 获取全局待审批总数的回调(跨所有会话) */
3286
3319
  globalPendingCountProvider = null;
3287
- /** 获取当前 WS 连接数的回调(用于在线抑制推送) */
3288
- connectionCountProvider = null;
3289
3320
  /** 添加通知渠道(id 唯一,可用于后续动态开关) */
3290
3321
  addChannel(id, channel, enabled = true) {
3291
3322
  this.channelMap.set(id, { channel, enabled });
@@ -3323,10 +3354,6 @@ var NotificationService = class {
3323
3354
  setGlobalPendingCountProvider(provider) {
3324
3355
  this.globalPendingCountProvider = provider;
3325
3356
  }
3326
- /** 设置 WS 连接数提供者(用于 status_change 通知的在线抑制) */
3327
- setConnectionCountProvider(provider) {
3328
- this.connectionCountProvider = provider;
3329
- }
3330
3357
  /** 获取全局待审批总数 */
3331
3358
  getGlobalPendingCount() {
3332
3359
  return this.globalPendingCountProvider?.() ?? 0;
@@ -3469,7 +3496,7 @@ var NotificationService = class {
3469
3496
  isYoloMode,
3470
3497
  updatedAt: Date.now()
3471
3498
  });
3472
- } else if ((this.connectionCountProvider?.() ?? 0) === 0) {
3499
+ } else {
3473
3500
  this.notify({
3474
3501
  title: sessionTitle,
3475
3502
  body,
@@ -3491,7 +3518,7 @@ var NotificationService = class {
3491
3518
  isYoloMode,
3492
3519
  updatedAt: Date.now()
3493
3520
  });
3494
- } else if ((this.connectionCountProvider?.() ?? 0) === 0) {
3521
+ } else {
3495
3522
  this.notify({
3496
3523
  title: sessionTitle,
3497
3524
  body,
@@ -4590,7 +4617,6 @@ async function start(opts = {}) {
4590
4617
  notificationService.setGlobalPendingCountProvider(
4591
4618
  () => approvalProxy.getPendingCount() + sessionManager.getAllPendingQuestions().length + unreadSessionIds.size
4592
4619
  );
4593
- notificationService.setConnectionCountProvider(() => wsBridge.getConnectionCount());
4594
4620
  let cliCapabilities = null;
4595
4621
  parseCliCapabilities().then((caps) => {
4596
4622
  cliCapabilities = caps;
@@ -4962,6 +4988,13 @@ async function start(opts = {}) {
4962
4988
  approvalProxy.approveAll(t("server.phoneDisconnected"));
4963
4989
  }
4964
4990
  });
4991
+ approvalProxy.onApprovalResolved((requestId, decision) => {
4992
+ wsBridge.broadcast({
4993
+ type: "approval_resolved",
4994
+ requestId,
4995
+ decision: decision.decision
4996
+ });
4997
+ });
4965
4998
  approvalProxy.onApprovalRequest((request) => {
4966
4999
  wsBridge.broadcast({ type: "approval_request", request });
4967
5000
  setTimeout(() => {
package/dist/server.js CHANGED
@@ -2528,6 +2528,8 @@ var ApprovalProxy = class _ApprovalProxy {
2528
2528
  pendingApprovals = /* @__PURE__ */ new Map();
2529
2529
  /** 审批请求回调(通知外部推送到手机) */
2530
2530
  approvalRequestCallbacks = [];
2531
+ /** 审批 resolve 回调(任何来源的 resolve 都会触发,用于 WS 广播清理 */
2532
+ approvalResolvedCallbacks = [];
2531
2533
  /** YOLO 模式状态:sessionId -> enabled */
2532
2534
  yoloSessions = /* @__PURE__ */ new Map();
2533
2535
  /** 内存缓存:已被"始终允许"的工具名(避免每次读 settings.json) */
@@ -2565,6 +2567,30 @@ var ApprovalProxy = class _ApprovalProxy {
2565
2567
  onApprovalRequest(callback) {
2566
2568
  this.approvalRequestCallbacks.push(callback);
2567
2569
  }
2570
+ /**
2571
+ * 注册审批 resolve 回调
2572
+ *
2573
+ * 任何来源的 resolve 都会触发:
2574
+ * - resolveApproval(手机端 approve/reject)
2575
+ * - 5 分钟超时自动 allow
2576
+ * - clearPendingForSession(会话被 kill)
2577
+ * - approveAll(手机全断时自动 allow)
2578
+ *
2579
+ * 用于向所有客户端广播 approval_resolved,清理可能残留的审批 UI。
2580
+ */
2581
+ onApprovalResolved(callback) {
2582
+ this.approvalResolvedCallbacks.push(callback);
2583
+ }
2584
+ /** 通知所有 resolve 回调(内部调用) */
2585
+ notifyApprovalResolved(requestId, decision) {
2586
+ for (const callback of this.approvalResolvedCallbacks) {
2587
+ try {
2588
+ callback(requestId, decision);
2589
+ } catch (err) {
2590
+ console.error("[ApprovalProxy] Approval resolved callback error:", err);
2591
+ }
2592
+ }
2593
+ }
2568
2594
  /** 设置状态信息提供者(用于 /health 端点) */
2569
2595
  setStatusInfoProvider(provider) {
2570
2596
  this.statusInfoProvider = provider;
@@ -2598,6 +2624,7 @@ var ApprovalProxy = class _ApprovalProxy {
2598
2624
  pending.resolve(decision);
2599
2625
  this.pendingApprovals.delete(requestId);
2600
2626
  console.log(`[ApprovalProxy] ${t("approval.requestProcessed", { id: requestId })}: ${decision.decision}`);
2627
+ this.notifyApprovalResolved(requestId, decision);
2601
2628
  return true;
2602
2629
  }
2603
2630
  /** 获取当前待处理的审批数量 */
@@ -2613,9 +2640,11 @@ var ApprovalProxy = class _ApprovalProxy {
2613
2640
  for (const [requestId, pending] of this.pendingApprovals) {
2614
2641
  if (pending.request.sessionId === sessionId) {
2615
2642
  clearTimeout(pending.timer);
2616
- pending.resolve({ decision: "allow" });
2643
+ const decision = { decision: "allow" };
2644
+ pending.resolve(decision);
2617
2645
  this.pendingApprovals.delete(requestId);
2618
2646
  console.log(`[ApprovalProxy] Session ${sessionId} killed, auto-allowed pending approval ${requestId}`);
2647
+ this.notifyApprovalResolved(requestId, decision);
2619
2648
  }
2620
2649
  }
2621
2650
  }
@@ -2703,9 +2732,11 @@ var ApprovalProxy = class _ApprovalProxy {
2703
2732
  const entries = Array.from(this.pendingApprovals.entries());
2704
2733
  for (const [requestId, pending] of entries) {
2705
2734
  clearTimeout(pending.timer);
2706
- pending.resolve({ decision: "allow" });
2735
+ const decision = { decision: "allow" };
2736
+ pending.resolve(decision);
2707
2737
  this.pendingApprovals.delete(requestId);
2708
2738
  console.log(`[ApprovalProxy] ${t("approval.autoAllowed", { id: requestId, reason: reason ? `\uFF08${reason}\uFF09` : "" })}`);
2739
+ this.notifyApprovalResolved(requestId, decision);
2709
2740
  }
2710
2741
  }
2711
2742
  /** 优雅关闭 HTTP 服务 */
@@ -2797,7 +2828,9 @@ var ApprovalProxy = class _ApprovalProxy {
2797
2828
  const timer = setTimeout(() => {
2798
2829
  console.log(`[ApprovalProxy] ${t("approval.timeout", { id: requestId })}`);
2799
2830
  this.pendingApprovals.delete(requestId);
2800
- resolve({ decision: "allow" });
2831
+ const autoDecision = { decision: "allow" };
2832
+ resolve(autoDecision);
2833
+ this.notifyApprovalResolved(requestId, autoDecision);
2801
2834
  }, 325e3);
2802
2835
  this.pendingApprovals.set(requestId, { resolve, timer, request: approvalRequest });
2803
2836
  });
@@ -3289,8 +3322,6 @@ var NotificationService = class {
3289
3322
  latestAssistantText = /* @__PURE__ */ new Map();
3290
3323
  /** 获取全局待审批总数的回调(跨所有会话) */
3291
3324
  globalPendingCountProvider = null;
3292
- /** 获取当前 WS 连接数的回调(用于在线抑制推送) */
3293
- connectionCountProvider = null;
3294
3325
  /** 添加通知渠道(id 唯一,可用于后续动态开关) */
3295
3326
  addChannel(id, channel, enabled = true) {
3296
3327
  this.channelMap.set(id, { channel, enabled });
@@ -3328,10 +3359,6 @@ var NotificationService = class {
3328
3359
  setGlobalPendingCountProvider(provider) {
3329
3360
  this.globalPendingCountProvider = provider;
3330
3361
  }
3331
- /** 设置 WS 连接数提供者(用于 status_change 通知的在线抑制) */
3332
- setConnectionCountProvider(provider) {
3333
- this.connectionCountProvider = provider;
3334
- }
3335
3362
  /** 获取全局待审批总数 */
3336
3363
  getGlobalPendingCount() {
3337
3364
  return this.globalPendingCountProvider?.() ?? 0;
@@ -3474,7 +3501,7 @@ var NotificationService = class {
3474
3501
  isYoloMode,
3475
3502
  updatedAt: Date.now()
3476
3503
  });
3477
- } else if ((this.connectionCountProvider?.() ?? 0) === 0) {
3504
+ } else {
3478
3505
  this.notify({
3479
3506
  title: sessionTitle,
3480
3507
  body,
@@ -3496,7 +3523,7 @@ var NotificationService = class {
3496
3523
  isYoloMode,
3497
3524
  updatedAt: Date.now()
3498
3525
  });
3499
- } else if ((this.connectionCountProvider?.() ?? 0) === 0) {
3526
+ } else {
3500
3527
  this.notify({
3501
3528
  title: sessionTitle,
3502
3529
  body,
@@ -4595,7 +4622,6 @@ async function start(opts = {}) {
4595
4622
  notificationService.setGlobalPendingCountProvider(
4596
4623
  () => approvalProxy.getPendingCount() + sessionManager.getAllPendingQuestions().length + unreadSessionIds.size
4597
4624
  );
4598
- notificationService.setConnectionCountProvider(() => wsBridge.getConnectionCount());
4599
4625
  let cliCapabilities = null;
4600
4626
  parseCliCapabilities().then((caps) => {
4601
4627
  cliCapabilities = caps;
@@ -4967,6 +4993,13 @@ async function start(opts = {}) {
4967
4993
  approvalProxy.approveAll(t("server.phoneDisconnected"));
4968
4994
  }
4969
4995
  });
4996
+ approvalProxy.onApprovalResolved((requestId, decision) => {
4997
+ wsBridge.broadcast({
4998
+ type: "approval_resolved",
4999
+ requestId,
5000
+ decision: decision.decision
5001
+ });
5002
+ });
4970
5003
  approvalProxy.onApprovalRequest((request) => {
4971
5004
  wsBridge.broadcast({ type: "approval_request", request });
4972
5005
  setTimeout(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sessix-server",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "bin": {
5
5
  "sessix-server": "dist/index.js"
6
6
  },