sessix-server 0.1.4 → 0.2.1
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/approval/ApprovalProxy.d.ts +0 -10
- package/dist/approval/ApprovalProxy.d.ts.map +1 -1
- package/dist/approval/ApprovalProxy.js +6 -44
- package/dist/approval/ApprovalProxy.js.map +1 -1
- package/dist/hooks/HookInstaller.d.ts +7 -11
- package/dist/hooks/HookInstaller.d.ts.map +1 -1
- package/dist/hooks/HookInstaller.js +49 -96
- package/dist/hooks/HookInstaller.js.map +1 -1
- package/dist/index.js +326 -20
- package/dist/notification/ExpoNotificationChannel.d.ts.map +1 -1
- package/dist/notification/ExpoNotificationChannel.js +1 -9
- package/dist/notification/ExpoNotificationChannel.js.map +1 -1
- package/dist/notification/NotificationService.d.ts +1 -1
- package/dist/notification/NotificationService.d.ts.map +1 -1
- package/dist/notification/NotificationService.js +5 -13
- package/dist/notification/NotificationService.js.map +1 -1
- package/dist/providers/ExecutionProvider.d.ts +2 -8
- package/dist/providers/ExecutionProvider.d.ts.map +1 -1
- package/dist/providers/ProcessProvider.d.ts +2 -2
- package/dist/providers/ProcessProvider.d.ts.map +1 -1
- package/dist/providers/ProcessProvider.js +15 -49
- package/dist/providers/ProcessProvider.js.map +1 -1
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +306 -18
- package/dist/server.js.map +1 -1
- package/dist/session/ProjectReader.js +1 -1
- package/dist/session/ProjectReader.js.map +1 -1
- package/dist/session/SessionManager.d.ts +3 -7
- package/dist/session/SessionManager.d.ts.map +1 -1
- package/dist/session/SessionManager.js +5 -45
- package/dist/session/SessionManager.js.map +1 -1
- package/dist/ws/WsBridge.js +4 -4
- package/dist/ws/WsBridge.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -43,6 +43,8 @@ var zh = {
|
|
|
43
43
|
autoDiscoveryOn: " \u{1F4A1} \u81EA\u52A8\u53D1\u73B0\u5DF2\u542F\u7528\uFF0C\u540C\u7F51\u6BB5\u624B\u673A\u53EF\u81EA\u52A8\u8FDE\u63A5",
|
|
44
44
|
autoDiscoveryHint: " \u5982\u5728\u516C\u5171\u7F51\u7EDC\uFF0C\u5EFA\u8BAE\u5173\u95ED: SESSIX_AUTO_CONNECT=false npx sessix-server",
|
|
45
45
|
autoDiscoveryOff: " \u2139\uFE0F \u81EA\u52A8\u53D1\u73B0\u5DF2\u5173\u95ED\uFF0C\u624B\u673A\u9700\u624B\u52A8\u8F93\u5165\u5730\u5740\u8FDE\u63A5",
|
|
46
|
+
pairingOpen: " \u{1F513} \u914D\u5BF9\u6A21\u5F0F\u5DF2\u5F00\u542F\uFF085 \u5206\u949F\u5185\u6709\u6548\uFF09\u2014 \u6309 p \u91CD\u65B0\u5F00\u542F",
|
|
47
|
+
pairingReopened: "\u{1F513} \u914D\u5BF9\u6A21\u5F0F\u5DF2\u91CD\u65B0\u5F00\u542F\uFF085 \u5206\u949F\uFF09",
|
|
46
48
|
receivedSignal: "\u6536\u5230 {{signal}}\uFF0C\u6B63\u5728\u4F18\u96C5\u5173\u95ED...",
|
|
47
49
|
goodbye: "\u6240\u6709\u670D\u52A1\u5DF2\u5173\u95ED\uFF0C\u518D\u89C1\uFF01",
|
|
48
50
|
shutdownError: "\u5173\u95ED\u8FC7\u7A0B\u51FA\u9519:",
|
|
@@ -69,7 +71,8 @@ var zh = {
|
|
|
69
71
|
restarting: "\u91CD\u65B0\u542F\u52A8 {{label}}...",
|
|
70
72
|
activityPushEnabled: "ActivityKit Push \u5DF2\u542F\u7528",
|
|
71
73
|
activityPushFailed: "ActivityKit Push \u521D\u59CB\u5316\u5931\u8D25:",
|
|
72
|
-
activityPushContinue: "\u7EE7\u7EED\u542F\u52A8\uFF08Live Activity \u540E\u53F0\u63A8\u9001\u4E0D\u53EF\u7528\uFF09"
|
|
74
|
+
activityPushContinue: "\u7EE7\u7EED\u542F\u52A8\uFF08Live Activity \u540E\u53F0\u63A8\u9001\u4E0D\u53EF\u7528\uFF09",
|
|
75
|
+
noActiveLoginProcess: "\u6CA1\u6709\u6D3B\u8DC3\u7684\u767B\u5F55\u8FDB\u7A0B"
|
|
73
76
|
},
|
|
74
77
|
ws: {
|
|
75
78
|
started: "WebSocket \u670D\u52A1\u5DF2\u542F\u52A8\uFF0C\u7AEF\u53E3 {{port}}",
|
|
@@ -144,6 +147,8 @@ var en = {
|
|
|
144
147
|
autoDiscoveryOn: " Auto-discovery enabled, phones on the same network can connect automatically",
|
|
145
148
|
autoDiscoveryHint: " On public networks, disable with: SESSIX_AUTO_CONNECT=false npx sessix-server",
|
|
146
149
|
autoDiscoveryOff: " Auto-discovery disabled, phone must enter address manually",
|
|
150
|
+
pairingOpen: " \u{1F513} Pairing mode open (5 min) \u2014 press p to reopen",
|
|
151
|
+
pairingReopened: "\u{1F513} Pairing mode reopened (5 min)",
|
|
147
152
|
receivedSignal: "Received {{signal}}, graceful shutdown...",
|
|
148
153
|
goodbye: "All services closed, goodbye!",
|
|
149
154
|
shutdownError: "Shutdown error:",
|
|
@@ -170,7 +175,8 @@ var en = {
|
|
|
170
175
|
restarting: "Restarting {{label}}...",
|
|
171
176
|
activityPushEnabled: "ActivityKit Push enabled",
|
|
172
177
|
activityPushFailed: "ActivityKit Push init failed:",
|
|
173
|
-
activityPushContinue: "Continuing startup (Live Activity background push unavailable)"
|
|
178
|
+
activityPushContinue: "Continuing startup (Live Activity background push unavailable)",
|
|
179
|
+
noActiveLoginProcess: "No active login process"
|
|
174
180
|
},
|
|
175
181
|
ws: {
|
|
176
182
|
started: "WebSocket server started on port {{port}}",
|
|
@@ -283,11 +289,14 @@ var import_node_child_process2 = require("child_process");
|
|
|
283
289
|
var import_node_util = require("util");
|
|
284
290
|
|
|
285
291
|
// src/providers/ProcessProvider.ts
|
|
286
|
-
var
|
|
292
|
+
var import_child_process2 = require("child_process");
|
|
287
293
|
var import_readline = require("readline");
|
|
288
294
|
var import_events = require("events");
|
|
289
295
|
var import_node_os = require("os");
|
|
290
296
|
var import_uuid = require("uuid");
|
|
297
|
+
|
|
298
|
+
// src/utils/claudePath.ts
|
|
299
|
+
var import_child_process = require("child_process");
|
|
291
300
|
function findClaudePath() {
|
|
292
301
|
try {
|
|
293
302
|
return (0, import_child_process.execSync)("which claude", { encoding: "utf-8" }).trim();
|
|
@@ -307,6 +316,8 @@ function findClaudePath() {
|
|
|
307
316
|
return "claude";
|
|
308
317
|
}
|
|
309
318
|
}
|
|
319
|
+
|
|
320
|
+
// src/providers/ProcessProvider.ts
|
|
310
321
|
var CLAUDE_PATH = findClaudePath();
|
|
311
322
|
var ProcessProvider = class {
|
|
312
323
|
/** 活跃会话映射表:sessionId -> { session, process } */
|
|
@@ -499,7 +510,7 @@ var ProcessProvider = class {
|
|
|
499
510
|
}
|
|
500
511
|
const env = { ...process.env, SESSIX_SESSION_ID: sessionId };
|
|
501
512
|
delete env.CLAUDECODE;
|
|
502
|
-
const proc = (0,
|
|
513
|
+
const proc = (0, import_child_process2.spawn)(CLAUDE_PATH, args, {
|
|
503
514
|
cwd: projectPath,
|
|
504
515
|
env,
|
|
505
516
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -706,7 +717,7 @@ ${context}`;
|
|
|
706
717
|
return new Promise((resolve, reject) => {
|
|
707
718
|
const env = { ...process.env };
|
|
708
719
|
delete env.CLAUDECODE;
|
|
709
|
-
const proc = (0,
|
|
720
|
+
const proc = (0, import_child_process2.spawn)(CLAUDE_PATH, ["-p", prompt, "--output-format", "text"], {
|
|
710
721
|
cwd: (0, import_node_os.homedir)(),
|
|
711
722
|
env,
|
|
712
723
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -1617,6 +1628,7 @@ var ApprovalProxy = class _ApprovalProxy {
|
|
|
1617
1628
|
alwaysAllowedTools = /* @__PURE__ */ new Set();
|
|
1618
1629
|
/** 获取状态信息的回调(由外部注入) */
|
|
1619
1630
|
statusInfoProvider = null;
|
|
1631
|
+
pairingManager = null;
|
|
1620
1632
|
constructor(options) {
|
|
1621
1633
|
this.token = options.token;
|
|
1622
1634
|
this.port = options.port;
|
|
@@ -1651,6 +1663,10 @@ var ApprovalProxy = class _ApprovalProxy {
|
|
|
1651
1663
|
setStatusInfoProvider(provider) {
|
|
1652
1664
|
this.statusInfoProvider = provider;
|
|
1653
1665
|
}
|
|
1666
|
+
/** 设置配对管理器 */
|
|
1667
|
+
setPairingManager(manager) {
|
|
1668
|
+
this.pairingManager = manager;
|
|
1669
|
+
}
|
|
1654
1670
|
/** 设置会话的 YOLO 模式(服务端拦截,即使手机断连也生效) */
|
|
1655
1671
|
setYoloMode(sessionId, enabled) {
|
|
1656
1672
|
this.yoloSessions.set(sessionId, enabled);
|
|
@@ -1811,6 +1827,8 @@ var ApprovalProxy = class _ApprovalProxy {
|
|
|
1811
1827
|
const pathname = url.pathname;
|
|
1812
1828
|
if (req.method === "POST" && pathname === "/hook/approval") {
|
|
1813
1829
|
this.handleApprovalHook(req, res);
|
|
1830
|
+
} else if (req.method === "POST" && pathname === "/pair") {
|
|
1831
|
+
this.handlePair(req, res);
|
|
1814
1832
|
} else if (req.method === "GET" && pathname === "/health") {
|
|
1815
1833
|
this.handleHealth(req, res);
|
|
1816
1834
|
} else if (req.method === "GET" && pathname === "/token") {
|
|
@@ -1881,6 +1899,23 @@ var ApprovalProxy = class _ApprovalProxy {
|
|
|
1881
1899
|
activeSessions: info.activeSessions
|
|
1882
1900
|
});
|
|
1883
1901
|
}
|
|
1902
|
+
/** 配对端点:配对窗口开放时返回 token */
|
|
1903
|
+
handlePair(_req, res) {
|
|
1904
|
+
if (!this.pairingManager) {
|
|
1905
|
+
this.sendJson(res, 503, { error: "pairing_unavailable" });
|
|
1906
|
+
return;
|
|
1907
|
+
}
|
|
1908
|
+
const result = this.pairingManager.tryPair();
|
|
1909
|
+
if (result) {
|
|
1910
|
+
console.log("[ApprovalProxy] Device paired successfully");
|
|
1911
|
+
this.sendJson(res, 200, result);
|
|
1912
|
+
} else {
|
|
1913
|
+
this.sendJson(res, 403, {
|
|
1914
|
+
error: "pairing_closed",
|
|
1915
|
+
message: "Pairing window is closed. Restart server or press p to reopen."
|
|
1916
|
+
});
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1884
1919
|
/** 返回连接 token(仅本机访问) */
|
|
1885
1920
|
handleToken(req, res) {
|
|
1886
1921
|
const remoteAddress = req.socket.remoteAddress;
|
|
@@ -1951,12 +1986,12 @@ var MdnsService = class {
|
|
|
1951
1986
|
wsPort;
|
|
1952
1987
|
httpPort;
|
|
1953
1988
|
version;
|
|
1954
|
-
|
|
1989
|
+
pairing;
|
|
1955
1990
|
constructor(options) {
|
|
1956
1991
|
this.wsPort = options.wsPort;
|
|
1957
1992
|
this.httpPort = options.httpPort;
|
|
1958
1993
|
this.version = options.version ?? "0.1.0";
|
|
1959
|
-
this.
|
|
1994
|
+
this.pairing = options.pairing ?? "closed";
|
|
1960
1995
|
}
|
|
1961
1996
|
/**
|
|
1962
1997
|
* 启动 mDNS 广播
|
|
@@ -1974,7 +2009,8 @@ var MdnsService = class {
|
|
|
1974
2009
|
txt: {
|
|
1975
2010
|
version: this.version,
|
|
1976
2011
|
httpPort: String(this.httpPort),
|
|
1977
|
-
|
|
2012
|
+
wsPort: String(this.wsPort),
|
|
2013
|
+
pairing: this.pairing
|
|
1978
2014
|
}
|
|
1979
2015
|
});
|
|
1980
2016
|
console.log(`[MdnsService] ${t("mdns.started", { port: this.wsPort })}`);
|
|
@@ -1995,6 +2031,29 @@ var MdnsService = class {
|
|
|
1995
2031
|
}
|
|
1996
2032
|
console.log(`[MdnsService] ${t("mdns.closed")}`);
|
|
1997
2033
|
}
|
|
2034
|
+
/**
|
|
2035
|
+
* 更新配对状态(重新发布 mDNS 服务)
|
|
2036
|
+
*/
|
|
2037
|
+
updatePairingState(state) {
|
|
2038
|
+
this.pairing = state;
|
|
2039
|
+
if (!this.bonjour) return;
|
|
2040
|
+
if (this.service) {
|
|
2041
|
+
this.service.stop?.(() => {
|
|
2042
|
+
});
|
|
2043
|
+
this.service = null;
|
|
2044
|
+
}
|
|
2045
|
+
this.service = this.bonjour.publish({
|
|
2046
|
+
name: "Sessix",
|
|
2047
|
+
type: "sessix",
|
|
2048
|
+
port: this.wsPort,
|
|
2049
|
+
txt: {
|
|
2050
|
+
version: this.version,
|
|
2051
|
+
httpPort: String(this.httpPort),
|
|
2052
|
+
wsPort: String(this.wsPort),
|
|
2053
|
+
pairing: state
|
|
2054
|
+
}
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
1998
2057
|
};
|
|
1999
2058
|
|
|
2000
2059
|
// src/hooks/HookInstaller.ts
|
|
@@ -2240,8 +2299,8 @@ var NotificationService = class {
|
|
|
2240
2299
|
if (entry) entry.enabled = enabled;
|
|
2241
2300
|
}
|
|
2242
2301
|
/** 注册手机 push token(连接建立时由 WsBridge 调用) */
|
|
2243
|
-
addPushToken(token) {
|
|
2244
|
-
this.expoChannel?.addToken(token);
|
|
2302
|
+
addPushToken(token, ws) {
|
|
2303
|
+
this.expoChannel?.addToken(token, ws);
|
|
2245
2304
|
}
|
|
2246
2305
|
/** 移除手机 push token(断线时或手机主动注销时调用) */
|
|
2247
2306
|
removePushToken(token) {
|
|
@@ -2481,17 +2540,21 @@ var MacNotificationChannel = class {
|
|
|
2481
2540
|
var EXPO_PUSH_API = "https://exp.host/--/api/v2/push/send";
|
|
2482
2541
|
var ExpoNotificationChannel = class {
|
|
2483
2542
|
tokens = /* @__PURE__ */ new Set();
|
|
2543
|
+
/** push token → WebSocket 连接映射,用于前台抑制 */
|
|
2544
|
+
tokenWsMap = /* @__PURE__ */ new Map();
|
|
2484
2545
|
/** per-token 通知音效偏好 */
|
|
2485
2546
|
soundPreferences = /* @__PURE__ */ new Map();
|
|
2486
2547
|
isAvailable() {
|
|
2487
2548
|
return this.tokens.size > 0;
|
|
2488
2549
|
}
|
|
2489
|
-
addToken(token) {
|
|
2550
|
+
addToken(token, ws) {
|
|
2490
2551
|
this.tokens.add(token);
|
|
2552
|
+
if (ws) this.tokenWsMap.set(token, ws);
|
|
2491
2553
|
console.log(`[ExpoNotificationChannel] ${t("notification.tokenRegistered", { count: this.tokens.size })}`);
|
|
2492
2554
|
}
|
|
2493
2555
|
removeToken(token) {
|
|
2494
2556
|
this.tokens.delete(token);
|
|
2557
|
+
this.tokenWsMap.delete(token);
|
|
2495
2558
|
this.soundPreferences.delete(token);
|
|
2496
2559
|
console.log(`[ExpoNotificationChannel] ${t("notification.tokenRemoved", { count: this.tokens.size })}`);
|
|
2497
2560
|
}
|
|
@@ -2504,7 +2567,12 @@ var ExpoNotificationChannel = class {
|
|
|
2504
2567
|
}
|
|
2505
2568
|
async send(payload) {
|
|
2506
2569
|
if (this.tokens.size === 0) return;
|
|
2507
|
-
const
|
|
2570
|
+
const offlineTokens = Array.from(this.tokens).filter((token) => {
|
|
2571
|
+
const ws = this.tokenWsMap.get(token);
|
|
2572
|
+
return !ws || ws.readyState !== ws.OPEN;
|
|
2573
|
+
});
|
|
2574
|
+
if (offlineTokens.length === 0) return;
|
|
2575
|
+
const messages = offlineTokens.map((to) => {
|
|
2508
2576
|
let sound = payload.sound ?? "default";
|
|
2509
2577
|
const prefs = this.soundPreferences.get(to);
|
|
2510
2578
|
if (prefs) {
|
|
@@ -2524,7 +2592,7 @@ var ExpoNotificationChannel = class {
|
|
|
2524
2592
|
};
|
|
2525
2593
|
});
|
|
2526
2594
|
try {
|
|
2527
|
-
console.log(`[ExpoNotificationChannel] ${t("notification.sendingPush")}
|
|
2595
|
+
console.log(`[ExpoNotificationChannel] ${t("notification.sendingPush")} (${offlineTokens.length}/${this.tokens.size} devices)`, offlineTokens);
|
|
2528
2596
|
const res = await fetch(EXPO_PUSH_API, {
|
|
2529
2597
|
method: "POST",
|
|
2530
2598
|
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
@@ -3027,6 +3095,180 @@ async function countJsonlFilesWithMtime(dirPath) {
|
|
|
3027
3095
|
}
|
|
3028
3096
|
}
|
|
3029
3097
|
|
|
3098
|
+
// src/pairing/PairingManager.ts
|
|
3099
|
+
var PairingManager = class {
|
|
3100
|
+
_state = "closed";
|
|
3101
|
+
timer = null;
|
|
3102
|
+
deadline = 0;
|
|
3103
|
+
token;
|
|
3104
|
+
serverName;
|
|
3105
|
+
version;
|
|
3106
|
+
defaultDuration;
|
|
3107
|
+
onStateChange;
|
|
3108
|
+
constructor(opts) {
|
|
3109
|
+
this.token = opts.token;
|
|
3110
|
+
this.serverName = opts.serverName;
|
|
3111
|
+
this.version = opts.version;
|
|
3112
|
+
this.defaultDuration = opts.defaultDuration ?? 3e5;
|
|
3113
|
+
this.onStateChange = opts.onStateChange;
|
|
3114
|
+
}
|
|
3115
|
+
get state() {
|
|
3116
|
+
return this._state;
|
|
3117
|
+
}
|
|
3118
|
+
open(duration) {
|
|
3119
|
+
const ms = duration ?? this.defaultDuration;
|
|
3120
|
+
if (this.timer) clearTimeout(this.timer);
|
|
3121
|
+
this._state = "open";
|
|
3122
|
+
this.deadline = Date.now() + ms;
|
|
3123
|
+
this.timer = setTimeout(() => this.close(), ms);
|
|
3124
|
+
this.onStateChange("open");
|
|
3125
|
+
}
|
|
3126
|
+
close() {
|
|
3127
|
+
if (this.timer) {
|
|
3128
|
+
clearTimeout(this.timer);
|
|
3129
|
+
this.timer = null;
|
|
3130
|
+
}
|
|
3131
|
+
if (this._state === "closed") return;
|
|
3132
|
+
this._state = "closed";
|
|
3133
|
+
this.deadline = 0;
|
|
3134
|
+
this.onStateChange("closed");
|
|
3135
|
+
}
|
|
3136
|
+
tryPair() {
|
|
3137
|
+
if (this._state !== "open") return null;
|
|
3138
|
+
const result = { token: this.token, serverName: this.serverName, version: this.version };
|
|
3139
|
+
this.close();
|
|
3140
|
+
return result;
|
|
3141
|
+
}
|
|
3142
|
+
getRemainingSeconds() {
|
|
3143
|
+
if (this._state !== "open") return 0;
|
|
3144
|
+
return Math.max(0, Math.ceil((this.deadline - Date.now()) / 1e3));
|
|
3145
|
+
}
|
|
3146
|
+
destroy() {
|
|
3147
|
+
if (this.timer) {
|
|
3148
|
+
clearTimeout(this.timer);
|
|
3149
|
+
this.timer = null;
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
};
|
|
3153
|
+
|
|
3154
|
+
// src/auth/AuthManager.ts
|
|
3155
|
+
var import_child_process3 = require("child_process");
|
|
3156
|
+
var import_child_process4 = require("child_process");
|
|
3157
|
+
var import_util = require("util");
|
|
3158
|
+
var import_events2 = require("events");
|
|
3159
|
+
var execFileAsync = (0, import_util.promisify)(import_child_process4.execFile);
|
|
3160
|
+
var CLAUDE_PATH2 = findClaudePath();
|
|
3161
|
+
var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
3162
|
+
var AuthManager = class extends import_events2.EventEmitter {
|
|
3163
|
+
loginProcess = null;
|
|
3164
|
+
loginTimeout = null;
|
|
3165
|
+
urlSent = false;
|
|
3166
|
+
/** 检查当前 Claude CLI 认证状态(异步,不阻塞事件循环) */
|
|
3167
|
+
async checkAuth() {
|
|
3168
|
+
try {
|
|
3169
|
+
const { stdout } = await execFileAsync(CLAUDE_PATH2, ["auth", "status"], {
|
|
3170
|
+
timeout: 1e4
|
|
3171
|
+
});
|
|
3172
|
+
const parsed = JSON.parse(stdout.trim());
|
|
3173
|
+
return {
|
|
3174
|
+
loggedIn: !!parsed.loggedIn,
|
|
3175
|
+
email: parsed.email,
|
|
3176
|
+
authMethod: parsed.authMethod
|
|
3177
|
+
};
|
|
3178
|
+
} catch {
|
|
3179
|
+
return { loggedIn: false };
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
3182
|
+
/** 启动登录流程,捕获 URL 并通过事件推送 */
|
|
3183
|
+
async startLogin() {
|
|
3184
|
+
if (this.loginProcess) {
|
|
3185
|
+
this.loginProcess.kill();
|
|
3186
|
+
this.loginProcess = null;
|
|
3187
|
+
}
|
|
3188
|
+
this.clearLoginTimeout();
|
|
3189
|
+
this.urlSent = false;
|
|
3190
|
+
const proc = (0, import_child_process3.spawn)(CLAUDE_PATH2, ["auth", "login"], {
|
|
3191
|
+
env: { ...process.env, BROWSER: "echo" },
|
|
3192
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
3193
|
+
});
|
|
3194
|
+
this.loginProcess = proc;
|
|
3195
|
+
const handleOutput = (data) => {
|
|
3196
|
+
const text = data.toString();
|
|
3197
|
+
console.log(`[AuthManager] login output: ${text.trim()}`);
|
|
3198
|
+
if (!this.urlSent) {
|
|
3199
|
+
const url = this.extractUrl(text);
|
|
3200
|
+
if (url) {
|
|
3201
|
+
this.urlSent = true;
|
|
3202
|
+
console.log(`[AuthManager] \u6355\u83B7\u5230\u767B\u5F55 URL: ${url}`);
|
|
3203
|
+
this.emit("login_url", url);
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
};
|
|
3207
|
+
proc.stdout?.on("data", handleOutput);
|
|
3208
|
+
proc.stderr?.on("data", handleOutput);
|
|
3209
|
+
proc.on("exit", (code) => {
|
|
3210
|
+
console.log(`[AuthManager] login process exited with code ${code}`);
|
|
3211
|
+
this.loginProcess = null;
|
|
3212
|
+
this.clearLoginTimeout();
|
|
3213
|
+
this.checkAuth().then((status) => {
|
|
3214
|
+
if (status.loggedIn) {
|
|
3215
|
+
this.emit("login_result", { success: true });
|
|
3216
|
+
} else if (code !== 0) {
|
|
3217
|
+
this.emit("login_result", { success: false, error: `Exit code: ${code}` });
|
|
3218
|
+
}
|
|
3219
|
+
});
|
|
3220
|
+
});
|
|
3221
|
+
proc.on("error", (err) => {
|
|
3222
|
+
console.error(`[AuthManager] login process error:`, err.message);
|
|
3223
|
+
this.loginProcess = null;
|
|
3224
|
+
this.clearLoginTimeout();
|
|
3225
|
+
this.emit("login_result", { success: false, error: err.message });
|
|
3226
|
+
});
|
|
3227
|
+
this.loginTimeout = setTimeout(() => {
|
|
3228
|
+
if (this.loginProcess) {
|
|
3229
|
+
console.warn("[AuthManager] login process timed out, killing");
|
|
3230
|
+
this.loginProcess.kill();
|
|
3231
|
+
this.loginProcess = null;
|
|
3232
|
+
this.emit("login_result", { success: false, error: "Login timed out" });
|
|
3233
|
+
}
|
|
3234
|
+
}, LOGIN_TIMEOUT_MS);
|
|
3235
|
+
}
|
|
3236
|
+
/** 提交授权码到登录进程的 stdin */
|
|
3237
|
+
submitCode(code) {
|
|
3238
|
+
if (!this.loginProcess?.stdin?.writable) {
|
|
3239
|
+
console.warn("[AuthManager] No active login process");
|
|
3240
|
+
return false;
|
|
3241
|
+
}
|
|
3242
|
+
console.log(`[AuthManager] \u63D0\u4EA4\u6388\u6743\u7801`);
|
|
3243
|
+
this.loginProcess.stdin.write(code + "\n");
|
|
3244
|
+
return true;
|
|
3245
|
+
}
|
|
3246
|
+
/** 是否有登录进程在运行 */
|
|
3247
|
+
get isLoginInProgress() {
|
|
3248
|
+
return this.loginProcess !== null;
|
|
3249
|
+
}
|
|
3250
|
+
/** 清理资源 */
|
|
3251
|
+
destroy() {
|
|
3252
|
+
this.clearLoginTimeout();
|
|
3253
|
+
if (this.loginProcess) {
|
|
3254
|
+
this.loginProcess.kill();
|
|
3255
|
+
this.loginProcess = null;
|
|
3256
|
+
}
|
|
3257
|
+
this.removeAllListeners();
|
|
3258
|
+
}
|
|
3259
|
+
clearLoginTimeout() {
|
|
3260
|
+
if (this.loginTimeout) {
|
|
3261
|
+
clearTimeout(this.loginTimeout);
|
|
3262
|
+
this.loginTimeout = null;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
/** 从文本中提取 URL */
|
|
3266
|
+
extractUrl(text) {
|
|
3267
|
+
const match = text.match(/https?:\/\/[^\s"'<>]+/);
|
|
3268
|
+
return match ? match[0] : null;
|
|
3269
|
+
}
|
|
3270
|
+
};
|
|
3271
|
+
|
|
3030
3272
|
// src/server.ts
|
|
3031
3273
|
var import_promises5 = require("fs/promises");
|
|
3032
3274
|
var WS_PORT = 3745;
|
|
@@ -3105,9 +3347,32 @@ async function start(opts = {}) {
|
|
|
3105
3347
|
HTTP_PORT,
|
|
3106
3348
|
() => ApprovalProxy.create({ port: HTTP_PORT, token })
|
|
3107
3349
|
);
|
|
3350
|
+
let mdnsService = null;
|
|
3351
|
+
const pairingManager = new PairingManager({
|
|
3352
|
+
token,
|
|
3353
|
+
serverName: (0, import_node_os4.hostname)(),
|
|
3354
|
+
version: "0.2.0",
|
|
3355
|
+
onStateChange: (state) => mdnsService?.updatePairingState(state)
|
|
3356
|
+
});
|
|
3357
|
+
approvalProxy.setPairingManager(pairingManager);
|
|
3358
|
+
if (opts.enablePairing !== false) {
|
|
3359
|
+
pairingManager.open();
|
|
3360
|
+
}
|
|
3361
|
+
const authManager = new AuthManager();
|
|
3362
|
+
authManager.on("login_url", (url) => {
|
|
3363
|
+
wsBridge.broadcast({ type: "auth_login_url", url });
|
|
3364
|
+
});
|
|
3365
|
+
authManager.on("login_result", (result) => {
|
|
3366
|
+
wsBridge.broadcast({ type: "auth_login_result", success: result.success, error: result.error });
|
|
3367
|
+
if (result.success) {
|
|
3368
|
+
authManager.checkAuth().then((status) => {
|
|
3369
|
+
wsBridge.broadcast({ type: "auth_status", loggedIn: status.loggedIn, email: status.email, authMethod: status.authMethod });
|
|
3370
|
+
});
|
|
3371
|
+
}
|
|
3372
|
+
});
|
|
3108
3373
|
const unreadSessionIds = /* @__PURE__ */ new Set();
|
|
3109
3374
|
notificationService.setGlobalPendingCountProvider(
|
|
3110
|
-
() => approvalProxy.getPendingCount() + unreadSessionIds.size
|
|
3375
|
+
() => approvalProxy.getPendingCount() + sessionManager.getAllPendingQuestions().length + unreadSessionIds.size
|
|
3111
3376
|
);
|
|
3112
3377
|
const broadcastUnreadSessions = () => {
|
|
3113
3378
|
wsBridge.broadcast({ type: "unread_sessions", sessionIds: Array.from(unreadSessionIds) });
|
|
@@ -3322,7 +3587,7 @@ async function start(opts = {}) {
|
|
|
3322
3587
|
break;
|
|
3323
3588
|
}
|
|
3324
3589
|
case "register_push_token": {
|
|
3325
|
-
notificationService.addPushToken(event.token);
|
|
3590
|
+
notificationService.addPushToken(event.token, ws);
|
|
3326
3591
|
break;
|
|
3327
3592
|
}
|
|
3328
3593
|
case "unregister_push_token": {
|
|
@@ -3361,6 +3626,22 @@ async function start(opts = {}) {
|
|
|
3361
3626
|
approvalProxy.addToClaudeSettings(event.projectPath, event.toolName);
|
|
3362
3627
|
break;
|
|
3363
3628
|
}
|
|
3629
|
+
case "check_auth": {
|
|
3630
|
+
const status = await authManager.checkAuth();
|
|
3631
|
+
wsBridge.send(ws, { type: "auth_status", loggedIn: status.loggedIn, email: status.email, authMethod: status.authMethod });
|
|
3632
|
+
break;
|
|
3633
|
+
}
|
|
3634
|
+
case "start_auth_login": {
|
|
3635
|
+
await authManager.startLogin();
|
|
3636
|
+
break;
|
|
3637
|
+
}
|
|
3638
|
+
case "submit_auth_code": {
|
|
3639
|
+
const submitted = authManager.submitCode(event.code);
|
|
3640
|
+
if (!submitted) {
|
|
3641
|
+
wsBridge.send(ws, { type: "auth_login_result", success: false, error: t("server.noActiveLoginProcess") });
|
|
3642
|
+
}
|
|
3643
|
+
break;
|
|
3644
|
+
}
|
|
3364
3645
|
default: {
|
|
3365
3646
|
wsBridge.send(ws, {
|
|
3366
3647
|
type: "error",
|
|
@@ -3438,10 +3719,13 @@ async function start(opts = {}) {
|
|
|
3438
3719
|
connections: wsBridge.getConnectionCount(),
|
|
3439
3720
|
activeSessions: sessionManager.getActiveSessions().length
|
|
3440
3721
|
}));
|
|
3441
|
-
let mdnsService = null;
|
|
3442
3722
|
const startMdns = () => {
|
|
3443
3723
|
if (mdnsService) return;
|
|
3444
|
-
mdnsService = new MdnsService({
|
|
3724
|
+
mdnsService = new MdnsService({
|
|
3725
|
+
wsPort: WS_PORT,
|
|
3726
|
+
httpPort: HTTP_PORT,
|
|
3727
|
+
pairing: pairingManager.state
|
|
3728
|
+
});
|
|
3445
3729
|
mdnsService.start();
|
|
3446
3730
|
};
|
|
3447
3731
|
const stopMdns = () => {
|
|
@@ -3476,7 +3760,9 @@ async function start(opts = {}) {
|
|
|
3476
3760
|
errors.push(err);
|
|
3477
3761
|
}
|
|
3478
3762
|
};
|
|
3763
|
+
await attempt(() => authManager.destroy(), "AuthManager");
|
|
3479
3764
|
await attempt(() => stopMdns(), "mDNS");
|
|
3765
|
+
await attempt(() => pairingManager.destroy(), "PairingManager");
|
|
3480
3766
|
await attempt(() => wsBridge.close(), "WebSocket");
|
|
3481
3767
|
await attempt(() => approvalProxy.close(), "ApprovalProxy");
|
|
3482
3768
|
await attempt(() => sessionManager.destroy(), "SessionManager");
|
|
@@ -3504,7 +3790,9 @@ async function start(opts = {}) {
|
|
|
3504
3790
|
} else {
|
|
3505
3791
|
stopMdns();
|
|
3506
3792
|
}
|
|
3507
|
-
}
|
|
3793
|
+
},
|
|
3794
|
+
openPairing: (duration) => pairingManager.open(duration),
|
|
3795
|
+
closePairing: () => pairingManager.close()
|
|
3508
3796
|
};
|
|
3509
3797
|
}
|
|
3510
3798
|
|
|
@@ -3552,6 +3840,8 @@ async function main() {
|
|
|
3552
3840
|
console.log();
|
|
3553
3841
|
console.log(t("startup.waitingConnection"));
|
|
3554
3842
|
console.log();
|
|
3843
|
+
console.log(t("startup.pairingOpen"));
|
|
3844
|
+
console.log();
|
|
3555
3845
|
const shutdown = async (signal) => {
|
|
3556
3846
|
console.log(`
|
|
3557
3847
|
[Main] ${t("startup.receivedSignal", { signal })}`);
|
|
@@ -3564,8 +3854,24 @@ async function main() {
|
|
|
3564
3854
|
process.exit(1);
|
|
3565
3855
|
}
|
|
3566
3856
|
};
|
|
3567
|
-
process.
|
|
3568
|
-
|
|
3857
|
+
if (process.stdin.isTTY) {
|
|
3858
|
+
process.stdin.setRawMode(true);
|
|
3859
|
+
process.stdin.resume();
|
|
3860
|
+
process.stdin.setEncoding("utf8");
|
|
3861
|
+
process.stdin.on("data", (key) => {
|
|
3862
|
+
if (key === "p" || key === "P") {
|
|
3863
|
+
server.openPairing();
|
|
3864
|
+
console.log(`
|
|
3865
|
+
${t("startup.pairingReopened")}`);
|
|
3866
|
+
}
|
|
3867
|
+
if (key === "") {
|
|
3868
|
+
shutdown("SIGINT");
|
|
3869
|
+
}
|
|
3870
|
+
});
|
|
3871
|
+
} else {
|
|
3872
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
3873
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
3874
|
+
}
|
|
3569
3875
|
}
|
|
3570
3876
|
function getLocalIp() {
|
|
3571
3877
|
const interfaces = (0, import_node_os5.networkInterfaces)();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoNotificationChannel.d.ts","sourceRoot":"","sources":["../../src/notification/ExpoNotificationChannel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAI3F;;;;;;;GAOG;AACH,qBAAa,uBAAwB,YAAW,mBAAmB;IACjE,OAAO,CAAC,MAAM,CAAyB;IAEvC,WAAW,IAAI,OAAO;IAItB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoNotificationChannel.d.ts","sourceRoot":"","sources":["../../src/notification/ExpoNotificationChannel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAI3F;;;;;;;GAOG;AACH,qBAAa,uBAAwB,YAAW,mBAAmB;IACjE,OAAO,CAAC,MAAM,CAAyB;IAEvC,WAAW,IAAI,OAAO;IAItB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;CA6BxD"}
|
|
@@ -45,15 +45,7 @@ class ExpoNotificationChannel {
|
|
|
45
45
|
console.warn('[ExpoNotificationChannel] Expo Push API 返回错误:', res.status, JSON.stringify(body));
|
|
46
46
|
}
|
|
47
47
|
else {
|
|
48
|
-
|
|
49
|
-
const data = body.data;
|
|
50
|
-
if (Array.isArray(data)) {
|
|
51
|
-
for (const ticket of data) {
|
|
52
|
-
if (ticket.status === 'error') {
|
|
53
|
-
console.error(`[ExpoNotificationChannel] 推送失败: ${ticket.message} (${ticket.details?.error ?? 'unknown'})`);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
48
|
+
console.log('[ExpoNotificationChannel] Expo Push API 响应:', JSON.stringify(body));
|
|
57
49
|
}
|
|
58
50
|
}
|
|
59
51
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoNotificationChannel.js","sourceRoot":"","sources":["../../src/notification/ExpoNotificationChannel.ts"],"names":[],"mappings":";;;AAEA,MAAM,aAAa,GAAG,sCAAsC,CAAA;AAE5D;;;;;;;GAOG;AACH,MAAa,uBAAuB;IAC1B,MAAM,GAAgB,IAAI,GAAG,EAAE,CAAA;IAEvC,WAAW;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAA;IAC7B,CAAC;IAED,QAAQ,CAAC,KAAa;QACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACtB,OAAO,CAAC,GAAG,CAAC,mDAAmD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACpF,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACzB,OAAO,CAAC,GAAG,CAAC,mDAAmD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACpF,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAA4B;QACrC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;YAAE,OAAM;QAElC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACpD,EAAE;YACF,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;YACjC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;SACzB,CAAC,CAAC,CAAA;QAEH,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,wCAAwC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;YAC9E,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,EAAE;gBAC3E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;aAC/B,CAAC,CAAA;YAEF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;YAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,+CAA+C,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;YACjG,CAAC;iBAAM,CAAC;gBACN,
|
|
1
|
+
{"version":3,"file":"ExpoNotificationChannel.js","sourceRoot":"","sources":["../../src/notification/ExpoNotificationChannel.ts"],"names":[],"mappings":";;;AAEA,MAAM,aAAa,GAAG,sCAAsC,CAAA;AAE5D;;;;;;;GAOG;AACH,MAAa,uBAAuB;IAC1B,MAAM,GAAgB,IAAI,GAAG,EAAE,CAAA;IAEvC,WAAW;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAA;IAC7B,CAAC;IAED,QAAQ,CAAC,KAAa;QACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACtB,OAAO,CAAC,GAAG,CAAC,mDAAmD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACpF,CAAC;IAED,WAAW,CAAC,KAAa;QACvB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QACzB,OAAO,CAAC,GAAG,CAAC,mDAAmD,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACpF,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAA4B;QACrC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;YAAE,OAAM;QAElC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;YACpD,EAAE;YACF,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;YACjC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;SACzB,CAAC,CAAC,CAAA;QAEH,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,wCAAwC,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;YAC9E,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE;gBACrC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,EAAE;gBAC3E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;aAC/B,CAAC,CAAA;YAEF,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;YAC7B,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,CAAC,IAAI,CAAC,+CAA+C,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;YACjG,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,6CAA6C,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;YAClF,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAA;QACxD,CAAC;IACH,CAAC;CACF;AA9CD,0DA8CC"}
|
|
@@ -36,7 +36,7 @@ export declare class NotificationService {
|
|
|
36
36
|
/** 更新会话的 YOLO 模式状态 */
|
|
37
37
|
setYoloMode(sessionId: string, enabled: boolean): void;
|
|
38
38
|
/** 直接触发审批通知(由 ApprovalProxy 回调调用) */
|
|
39
|
-
notifyApproval(request: ApprovalRequest
|
|
39
|
+
notifyApproval(request: ApprovalRequest): void;
|
|
40
40
|
/** 简单的工具危险等级判断 */
|
|
41
41
|
private getDangerLevel;
|
|
42
42
|
/** 清理资源 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NotificationService.d.ts","sourceRoot":"","sources":["../../src/notification/NotificationService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,6BAA6B,CAAA;AAC3F,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAEnE;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAQ5B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,WAAW;IARrB,OAAO,CAAC,UAAU,CAAwE;IAC1F,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,0CAA0C;IAC1C,OAAO,CAAC,aAAa,CAA6B;gBAGxC,cAAc,EAAE,cAAc,EAC9B,WAAW,GAAE,uBAAuB,GAAG,IAAW;IAQ5D,8BAA8B;IAC9B,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,UAAO,GAAG,IAAI;IAI1E,qBAAqB;IACrB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAKrD,0CAA0C;IAC1C,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIjC,qCAAqC;IACrC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC,8CAA8C;IAC9C,sBAAsB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAI1D,0DAA0D;IAC1D,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI5D,gCAAgC;IAChC,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIhD,sBAAsB;IACtB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAItD,qCAAqC;IACrC,cAAc,CAAC,OAAO,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"NotificationService.d.ts","sourceRoot":"","sources":["../../src/notification/NotificationService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,6BAA6B,CAAA;AAC3F,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAEnE;;;;;;GAMG;AACH,qBAAa,mBAAmB;IAQ5B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,WAAW;IARrB,OAAO,CAAC,UAAU,CAAwE;IAC1F,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,mBAAmB,CAAmC;IAC9D,0CAA0C;IAC1C,OAAO,CAAC,aAAa,CAA6B;gBAGxC,cAAc,EAAE,cAAc,EAC9B,WAAW,GAAE,uBAAuB,GAAG,IAAW;IAQ5D,8BAA8B;IAC9B,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO,UAAO,GAAG,IAAI;IAI1E,qBAAqB;IACrB,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAKrD,0CAA0C;IAC1C,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIjC,qCAAqC;IACrC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC,8CAA8C;IAC9C,sBAAsB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAI1D,0DAA0D;IAC1D,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI5D,gCAAgC;IAChC,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIhD,sBAAsB;IACtB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAItD,qCAAqC;IACrC,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IA0C9C,kBAAkB;IAClB,OAAO,CAAC,cAAc;IAMtB,WAAW;IACX,OAAO,IAAI,IAAI;IAUf,OAAO,CAAC,WAAW;IA2CnB,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,cAAc;IAKtB,sBAAsB;IACtB,OAAO,CAAC,WAAW;CAGpB"}
|
|
@@ -60,21 +60,14 @@ class NotificationService {
|
|
|
60
60
|
this.yoloModeState.set(sessionId, enabled);
|
|
61
61
|
}
|
|
62
62
|
/** 直接触发审批通知(由 ApprovalProxy 回调调用) */
|
|
63
|
-
notifyApproval(request
|
|
63
|
+
notifyApproval(request) {
|
|
64
64
|
// YOLO 模式:客户端会自动批准,不发推送
|
|
65
65
|
if (this.yoloModeState.get(request.sessionId))
|
|
66
66
|
return;
|
|
67
67
|
const projectName = this.getProjectName(request.sessionId);
|
|
68
|
-
// 多个待审批时汇总文案
|
|
69
|
-
const title = pendingCount > 1
|
|
70
|
-
? `${pendingCount} 项待审批 — ${projectName}`
|
|
71
|
-
: `需要授权 — ${projectName}`;
|
|
72
|
-
const body = pendingCount > 1
|
|
73
|
-
? `最新: ${request.toolName}: ${request.description}`
|
|
74
|
-
: `${request.toolName}: ${request.description}`;
|
|
75
68
|
this.notify({
|
|
76
|
-
title
|
|
77
|
-
body
|
|
69
|
+
title: `需要授权 — ${projectName}`,
|
|
70
|
+
body: `${request.toolName}: ${request.description}`,
|
|
78
71
|
sound: 'Funk',
|
|
79
72
|
data: {
|
|
80
73
|
type: 'approval_request',
|
|
@@ -94,13 +87,12 @@ class NotificationService {
|
|
|
94
87
|
toolName: request.toolName,
|
|
95
88
|
description: request.description.slice(0, 80),
|
|
96
89
|
dangerLevel,
|
|
97
|
-
pendingCount,
|
|
98
90
|
},
|
|
99
91
|
isYoloMode,
|
|
100
92
|
updatedAt: Date.now(),
|
|
101
93
|
}, {
|
|
102
|
-
title
|
|
103
|
-
body
|
|
94
|
+
title: `需要授权 — ${projectName}`,
|
|
95
|
+
body: `${request.toolName}: ${request.description}`,
|
|
104
96
|
});
|
|
105
97
|
}
|
|
106
98
|
}
|