sessix-server 0.2.6 → 0.2.8
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 +303 -73
- package/dist/server.d.ts +2 -0
- package/dist/server.js +285 -73
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -46,7 +46,10 @@ var zh = {
|
|
|
46
46
|
autoDiscoveryHint: " \u5982\u5728\u516C\u5171\u7F51\u7EDC\uFF0C\u5EFA\u8BAE\u5173\u95ED: SESSIX_AUTO_CONNECT=false npx sessix-server",
|
|
47
47
|
autoDiscoveryOff: " \u2139\uFE0F \u81EA\u52A8\u53D1\u73B0\u5DF2\u5173\u95ED\uFF0C\u624B\u673A\u9700\u624B\u52A8\u8F93\u5165\u5730\u5740\u8FDE\u63A5",
|
|
48
48
|
pairingOpen: " \u{1F513} \u914D\u5BF9\u6A21\u5F0F\u5DF2\u5F00\u542F\uFF085 \u5206\u949F\u5185\u6709\u6548\uFF09\u2014 \u6309 p \u91CD\u65B0\u5F00\u542F",
|
|
49
|
+
pressT: " \u{1F511} \u6309 t \u91CD\u7F6E Token\uFF08\u6CC4\u9732\u540E\u5237\u65B0\uFF09",
|
|
49
50
|
pairingReopened: "\u{1F513} \u914D\u5BF9\u6A21\u5F0F\u5DF2\u91CD\u65B0\u5F00\u542F\uFF085 \u5206\u949F\uFF09",
|
|
51
|
+
tokenRegenerated: "\u{1F511} Token \u5DF2\u91CD\u7F6E\uFF0C\u6240\u6709\u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00\uFF0C\u8BF7\u91CD\u65B0\u626B\u7801\u914D\u5BF9",
|
|
52
|
+
tokenRegenerateFailed: "Token \u91CD\u7F6E\u5931\u8D25:",
|
|
50
53
|
updateAvailable: "\u53D1\u73B0\u65B0\u7248\u672C v{{latest}}\uFF08\u5F53\u524D v{{current}}\uFF09\uFF0C\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0\uFF1A",
|
|
51
54
|
receivedSignal: "\u6536\u5230 {{signal}}\uFF0C\u6B63\u5728\u4F18\u96C5\u5173\u95ED...",
|
|
52
55
|
goodbye: "\u6240\u6709\u670D\u52A1\u5DF2\u5173\u95ED\uFF0C\u518D\u89C1\uFF01",
|
|
@@ -75,7 +78,8 @@ var zh = {
|
|
|
75
78
|
activityPushEnabled: "ActivityKit Push \u5DF2\u542F\u7528",
|
|
76
79
|
activityPushFailed: "ActivityKit Push \u521D\u59CB\u5316\u5931\u8D25:",
|
|
77
80
|
activityPushContinue: "\u7EE7\u7EED\u542F\u52A8\uFF08Live Activity \u540E\u53F0\u63A8\u9001\u4E0D\u53EF\u7528\uFF09",
|
|
78
|
-
noActiveLoginProcess: "\u6CA1\u6709\u6D3B\u8DC3\u7684\u767B\u5F55\u8FDB\u7A0B"
|
|
81
|
+
noActiveLoginProcess: "\u6CA1\u6709\u6D3B\u8DC3\u7684\u767B\u5F55\u8FDB\u7A0B",
|
|
82
|
+
tokenRegenerated: "Token \u5DF2\u91CD\u7F6E: {{token}}"
|
|
79
83
|
},
|
|
80
84
|
ws: {
|
|
81
85
|
started: "WebSocket \u670D\u52A1\u5DF2\u542F\u52A8\uFF0C\u7AEF\u53E3 {{port}}",
|
|
@@ -152,7 +156,10 @@ var en = {
|
|
|
152
156
|
autoDiscoveryHint: " On public networks, disable with: SESSIX_AUTO_CONNECT=false npx sessix-server",
|
|
153
157
|
autoDiscoveryOff: " Auto-discovery disabled, phone must enter address manually",
|
|
154
158
|
pairingOpen: " \u{1F513} Pairing mode open (5 min) \u2014 press p to reopen",
|
|
159
|
+
pressT: " \u{1F511} Press t to regenerate token (refresh after leak)",
|
|
155
160
|
pairingReopened: "\u{1F513} Pairing mode reopened (5 min)",
|
|
161
|
+
tokenRegenerated: "\u{1F511} Token regenerated, all clients disconnected. Scan QR to re-pair",
|
|
162
|
+
tokenRegenerateFailed: "Token regeneration failed:",
|
|
156
163
|
updateAvailable: "New version v{{latest}} available (current v{{current}}). Update with:",
|
|
157
164
|
receivedSignal: "Received {{signal}}, graceful shutdown...",
|
|
158
165
|
goodbye: "All services closed, goodbye!",
|
|
@@ -181,7 +188,8 @@ var en = {
|
|
|
181
188
|
activityPushEnabled: "ActivityKit Push enabled",
|
|
182
189
|
activityPushFailed: "ActivityKit Push init failed:",
|
|
183
190
|
activityPushContinue: "Continuing startup (Live Activity background push unavailable)",
|
|
184
|
-
noActiveLoginProcess: "No active login process"
|
|
191
|
+
noActiveLoginProcess: "No active login process",
|
|
192
|
+
tokenRegenerated: "Token regenerated: {{token}}"
|
|
185
193
|
},
|
|
186
194
|
ws: {
|
|
187
195
|
started: "WebSocket server started on port {{port}}",
|
|
@@ -287,11 +295,11 @@ function t(key, params) {
|
|
|
287
295
|
}
|
|
288
296
|
|
|
289
297
|
// src/server.ts
|
|
290
|
-
var
|
|
298
|
+
var import_uuid5 = require("uuid");
|
|
291
299
|
var import_promises4 = require("fs/promises");
|
|
292
300
|
var import_node_os6 = require("os");
|
|
293
301
|
var import_node_path5 = require("path");
|
|
294
|
-
var
|
|
302
|
+
var import_node_child_process6 = require("child_process");
|
|
295
303
|
var import_node_util = require("util");
|
|
296
304
|
|
|
297
305
|
// src/providers/ProcessProvider.ts
|
|
@@ -1538,6 +1546,13 @@ var WsBridge = class _WsBridge {
|
|
|
1538
1546
|
getConnectionCount() {
|
|
1539
1547
|
return this.wss.clients.size;
|
|
1540
1548
|
}
|
|
1549
|
+
/** 更新 token 并断开所有现有连接(token 刷新后需重新配对) */
|
|
1550
|
+
updateToken(newToken) {
|
|
1551
|
+
this.token = newToken;
|
|
1552
|
+
for (const ws of this.wss.clients) {
|
|
1553
|
+
ws.close(4001, "Token regenerated");
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1541
1556
|
/** 优雅关闭 WebSocket 服务 */
|
|
1542
1557
|
close() {
|
|
1543
1558
|
return new Promise((resolve, reject) => {
|
|
@@ -1977,6 +1992,10 @@ var ApprovalProxy = class _ApprovalProxy {
|
|
|
1977
1992
|
});
|
|
1978
1993
|
}
|
|
1979
1994
|
}
|
|
1995
|
+
/** 更新 token(token 刷新时调用) */
|
|
1996
|
+
updateToken(newToken) {
|
|
1997
|
+
this.token = newToken;
|
|
1998
|
+
}
|
|
1980
1999
|
/** 返回连接 token(仅本机访问) */
|
|
1981
2000
|
handleToken(req, res) {
|
|
1982
2001
|
const remoteAddress = req.socket.remoteAddress;
|
|
@@ -2040,79 +2059,120 @@ var ApprovalProxy = class _ApprovalProxy {
|
|
|
2040
2059
|
};
|
|
2041
2060
|
|
|
2042
2061
|
// src/mdns/MdnsService.ts
|
|
2043
|
-
var
|
|
2062
|
+
var import_node_child_process3 = require("child_process");
|
|
2044
2063
|
var import_node_os4 = require("os");
|
|
2045
|
-
function
|
|
2046
|
-
|
|
2047
|
-
for (const [name, addrs] of Object.entries((0, import_node_os4.networkInterfaces)())) {
|
|
2048
|
-
if (name.startsWith("utun") || name === "lo") continue;
|
|
2049
|
-
if (isWindows && (name.startsWith("vEthernet") || name.includes("Loopback"))) continue;
|
|
2050
|
-
for (const addr of addrs ?? []) {
|
|
2051
|
-
if (addr.family === "IPv4" && !addr.internal) {
|
|
2052
|
-
results.push(addr.address);
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
}
|
|
2056
|
-
return results;
|
|
2064
|
+
function buildTxtArgs(txt) {
|
|
2065
|
+
return Object.entries(txt).map(([k, v]) => `${k}=${v}`);
|
|
2057
2066
|
}
|
|
2058
2067
|
var MdnsService = class {
|
|
2059
|
-
|
|
2060
|
-
|
|
2068
|
+
proc = null;
|
|
2069
|
+
bonjourInstance = null;
|
|
2070
|
+
bonjourService = null;
|
|
2061
2071
|
wsPort;
|
|
2062
2072
|
httpPort;
|
|
2063
2073
|
version;
|
|
2064
2074
|
pairing;
|
|
2075
|
+
useDnsSd;
|
|
2065
2076
|
constructor(options) {
|
|
2066
2077
|
this.wsPort = options.wsPort;
|
|
2067
2078
|
this.httpPort = options.httpPort;
|
|
2068
2079
|
this.version = options.version ?? "0.1.0";
|
|
2069
2080
|
this.pairing = options.pairing ?? "closed";
|
|
2081
|
+
this.useDnsSd = (0, import_node_os4.platform)() === "darwin";
|
|
2082
|
+
}
|
|
2083
|
+
getTxt() {
|
|
2084
|
+
return {
|
|
2085
|
+
version: this.version,
|
|
2086
|
+
httpPort: String(this.httpPort),
|
|
2087
|
+
wsPort: String(this.wsPort),
|
|
2088
|
+
pairing: this.pairing
|
|
2089
|
+
};
|
|
2070
2090
|
}
|
|
2071
2091
|
/**
|
|
2072
2092
|
* 启动 mDNS 广播
|
|
2073
2093
|
*/
|
|
2074
2094
|
start() {
|
|
2075
|
-
if (this.
|
|
2095
|
+
if (this.useDnsSd) {
|
|
2096
|
+
this.startDnsSd();
|
|
2097
|
+
} else {
|
|
2098
|
+
this.startBonjour();
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
startDnsSd() {
|
|
2102
|
+
if (this.proc) {
|
|
2076
2103
|
console.warn(`[MdnsService] ${t("mdns.alreadyRunning")}`);
|
|
2077
2104
|
return;
|
|
2078
2105
|
}
|
|
2079
|
-
const
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
wsPort: String(this.wsPort),
|
|
2098
|
-
pairing: this.pairing
|
|
2106
|
+
const args = [
|
|
2107
|
+
"-R",
|
|
2108
|
+
"Sessix",
|
|
2109
|
+
"_sessix._tcp",
|
|
2110
|
+
"local",
|
|
2111
|
+
String(this.wsPort),
|
|
2112
|
+
...buildTxtArgs(this.getTxt())
|
|
2113
|
+
];
|
|
2114
|
+
this.proc = (0, import_node_child_process3.spawn)("dns-sd", args, { stdio: "ignore" });
|
|
2115
|
+
this.proc.on("error", (err) => {
|
|
2116
|
+
console.warn(`[MdnsService] dns-sd failed, falling back to bonjour-service: ${err.message}`);
|
|
2117
|
+
this.proc = null;
|
|
2118
|
+
this.useDnsSd = false;
|
|
2119
|
+
this.startBonjour();
|
|
2120
|
+
});
|
|
2121
|
+
this.proc.on("exit", (code) => {
|
|
2122
|
+
if (code !== null && code !== 0) {
|
|
2123
|
+
console.warn(`[MdnsService] dns-sd exited with code ${code}`);
|
|
2099
2124
|
}
|
|
2125
|
+
this.proc = null;
|
|
2100
2126
|
});
|
|
2101
|
-
console.log(`[MdnsService] ${t("mdns.started", { port: this.wsPort })}`);
|
|
2127
|
+
console.log(`[MdnsService] ${t("mdns.started", { port: this.wsPort })} (dns-sd)`);
|
|
2128
|
+
}
|
|
2129
|
+
async startBonjour() {
|
|
2130
|
+
if (this.bonjourInstance) {
|
|
2131
|
+
console.warn(`[MdnsService] ${t("mdns.alreadyRunning")}`);
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
try {
|
|
2135
|
+
const { default: Bonjour } = await import("bonjour-service");
|
|
2136
|
+
const { networkInterfaces: networkInterfaces2 } = await import("os");
|
|
2137
|
+
const lanAddrs = getLanAddresses(networkInterfaces2);
|
|
2138
|
+
const opts = lanAddrs.length > 0 ? { interface: lanAddrs[0] } : {};
|
|
2139
|
+
const onError = (err) => {
|
|
2140
|
+
if (err.code === "EADDRINUSE") return;
|
|
2141
|
+
console.warn(`[MdnsService] mDNS error (non-fatal): ${err.message}`);
|
|
2142
|
+
};
|
|
2143
|
+
this.bonjourInstance = new Bonjour(opts, onError);
|
|
2144
|
+
this.bonjourInstance.server?.mdns?.on("error", onError);
|
|
2145
|
+
if (lanAddrs.length > 0) {
|
|
2146
|
+
console.log(`[MdnsService] ${t("mdns.boundInterface", { ip: lanAddrs[0] })}`);
|
|
2147
|
+
}
|
|
2148
|
+
this.bonjourService = this.bonjourInstance.publish({
|
|
2149
|
+
name: "Sessix",
|
|
2150
|
+
type: "sessix",
|
|
2151
|
+
port: this.wsPort,
|
|
2152
|
+
txt: this.getTxt()
|
|
2153
|
+
});
|
|
2154
|
+
console.log(`[MdnsService] ${t("mdns.started", { port: this.wsPort })} (bonjour-service)`);
|
|
2155
|
+
} catch (err) {
|
|
2156
|
+
console.warn(`[MdnsService] bonjour-service failed: ${err.message}`);
|
|
2157
|
+
}
|
|
2102
2158
|
}
|
|
2103
2159
|
/**
|
|
2104
2160
|
* 停止 mDNS 广播
|
|
2105
2161
|
*/
|
|
2106
2162
|
stop() {
|
|
2107
|
-
if (this.
|
|
2108
|
-
this.
|
|
2163
|
+
if (this.proc) {
|
|
2164
|
+
this.proc.kill();
|
|
2165
|
+
this.proc = null;
|
|
2166
|
+
}
|
|
2167
|
+
if (this.bonjourService) {
|
|
2168
|
+
this.bonjourService.stop?.(() => {
|
|
2109
2169
|
console.log(`[MdnsService] ${t("mdns.stopped")}`);
|
|
2110
2170
|
});
|
|
2111
|
-
this.
|
|
2171
|
+
this.bonjourService = null;
|
|
2112
2172
|
}
|
|
2113
|
-
if (this.
|
|
2114
|
-
this.
|
|
2115
|
-
this.
|
|
2173
|
+
if (this.bonjourInstance) {
|
|
2174
|
+
this.bonjourInstance.destroy();
|
|
2175
|
+
this.bonjourInstance = null;
|
|
2116
2176
|
}
|
|
2117
2177
|
console.log(`[MdnsService] ${t("mdns.closed")}`);
|
|
2118
2178
|
}
|
|
@@ -2121,30 +2181,45 @@ var MdnsService = class {
|
|
|
2121
2181
|
*/
|
|
2122
2182
|
updatePairingState(state) {
|
|
2123
2183
|
this.pairing = state;
|
|
2124
|
-
if (
|
|
2184
|
+
if (this.useDnsSd) {
|
|
2185
|
+
if (this.proc) {
|
|
2186
|
+
this.proc.kill();
|
|
2187
|
+
this.proc = null;
|
|
2188
|
+
}
|
|
2189
|
+
this.startDnsSd();
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
2192
|
+
if (!this.bonjourInstance) return;
|
|
2125
2193
|
const republish = () => {
|
|
2126
|
-
if (!this.
|
|
2127
|
-
this.
|
|
2194
|
+
if (!this.bonjourInstance) return;
|
|
2195
|
+
this.bonjourService = this.bonjourInstance.publish({
|
|
2128
2196
|
name: "Sessix",
|
|
2129
2197
|
type: "sessix",
|
|
2130
2198
|
port: this.wsPort,
|
|
2131
|
-
txt:
|
|
2132
|
-
version: this.version,
|
|
2133
|
-
httpPort: String(this.httpPort),
|
|
2134
|
-
wsPort: String(this.wsPort),
|
|
2135
|
-
pairing: state
|
|
2136
|
-
}
|
|
2199
|
+
txt: this.getTxt()
|
|
2137
2200
|
});
|
|
2138
2201
|
};
|
|
2139
|
-
if (this.
|
|
2140
|
-
const old = this.
|
|
2141
|
-
this.
|
|
2202
|
+
if (this.bonjourService) {
|
|
2203
|
+
const old = this.bonjourService;
|
|
2204
|
+
this.bonjourService = null;
|
|
2142
2205
|
old.stop?.(() => republish());
|
|
2143
2206
|
} else {
|
|
2144
2207
|
republish();
|
|
2145
2208
|
}
|
|
2146
2209
|
}
|
|
2147
2210
|
};
|
|
2211
|
+
function getLanAddresses(networkInterfacesFn) {
|
|
2212
|
+
const results = [];
|
|
2213
|
+
for (const [name, addrs] of Object.entries(networkInterfacesFn())) {
|
|
2214
|
+
if (name.startsWith("utun") || name === "lo") continue;
|
|
2215
|
+
for (const addr of addrs ?? []) {
|
|
2216
|
+
if (addr.family === "IPv4" && !addr.internal) {
|
|
2217
|
+
results.push(addr.address);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
return results;
|
|
2222
|
+
}
|
|
2148
2223
|
|
|
2149
2224
|
// src/hooks/HookInstaller.ts
|
|
2150
2225
|
var import_promises2 = require("fs/promises");
|
|
@@ -2618,7 +2693,7 @@ var NotificationService = class {
|
|
|
2618
2693
|
};
|
|
2619
2694
|
|
|
2620
2695
|
// src/notification/DesktopNotificationChannel.ts
|
|
2621
|
-
var
|
|
2696
|
+
var import_node_child_process4 = require("child_process");
|
|
2622
2697
|
var DesktopNotificationChannel = class {
|
|
2623
2698
|
isAvailable() {
|
|
2624
2699
|
return process.platform === "darwin";
|
|
@@ -2630,7 +2705,7 @@ var DesktopNotificationChannel = class {
|
|
|
2630
2705
|
const sound = payload.sound ?? "Ping";
|
|
2631
2706
|
const script = `display notification "${body}" with title "${title}" sound name "${sound}"`;
|
|
2632
2707
|
return new Promise((resolve) => {
|
|
2633
|
-
(0,
|
|
2708
|
+
(0, import_node_child_process4.execFile)("osascript", ["-e", script], (err) => {
|
|
2634
2709
|
if (err) {
|
|
2635
2710
|
console.warn("[DesktopNotificationChannel] Send notification failed:", err.message);
|
|
2636
2711
|
}
|
|
@@ -3245,6 +3320,9 @@ var PairingManager = class {
|
|
|
3245
3320
|
this.close();
|
|
3246
3321
|
return result;
|
|
3247
3322
|
}
|
|
3323
|
+
updateToken(newToken) {
|
|
3324
|
+
this.token = newToken;
|
|
3325
|
+
}
|
|
3248
3326
|
getRemainingSeconds() {
|
|
3249
3327
|
if (this._state !== "open") return 0;
|
|
3250
3328
|
return Math.max(0, Math.ceil((this.deadline - Date.now()) / 1e3));
|
|
@@ -3377,9 +3455,98 @@ var AuthManager = class extends import_events2.EventEmitter {
|
|
|
3377
3455
|
|
|
3378
3456
|
// src/server.ts
|
|
3379
3457
|
var import_promises5 = require("fs/promises");
|
|
3458
|
+
|
|
3459
|
+
// src/terminal/TerminalExecutor.ts
|
|
3460
|
+
var import_node_child_process5 = require("child_process");
|
|
3461
|
+
var import_uuid4 = require("uuid");
|
|
3462
|
+
var EXEC_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
3463
|
+
var TerminalExecutor = class {
|
|
3464
|
+
processes = /* @__PURE__ */ new Map();
|
|
3465
|
+
eventCallbacks = [];
|
|
3466
|
+
onEvent(callback) {
|
|
3467
|
+
this.eventCallbacks.push(callback);
|
|
3468
|
+
return () => {
|
|
3469
|
+
const idx = this.eventCallbacks.indexOf(callback);
|
|
3470
|
+
if (idx !== -1) this.eventCallbacks.splice(idx, 1);
|
|
3471
|
+
};
|
|
3472
|
+
}
|
|
3473
|
+
emit(event) {
|
|
3474
|
+
for (const cb of this.eventCallbacks) {
|
|
3475
|
+
try {
|
|
3476
|
+
cb(event);
|
|
3477
|
+
} catch (err) {
|
|
3478
|
+
console.error("[TerminalExecutor] Event callback error:", err);
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
exec(sessionId, command, cwd) {
|
|
3483
|
+
const execId = (0, import_uuid4.v4)();
|
|
3484
|
+
const shell = isWindows ? "powershell" : "bash";
|
|
3485
|
+
const args = isWindows ? ["-Command", command] : ["-c", command];
|
|
3486
|
+
const proc = (0, import_node_child_process5.spawn)(shell, args, {
|
|
3487
|
+
cwd,
|
|
3488
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3489
|
+
env: { ...process.env }
|
|
3490
|
+
});
|
|
3491
|
+
this.processes.set(execId, proc);
|
|
3492
|
+
proc.stdout?.on("data", (chunk) => {
|
|
3493
|
+
this.emit({
|
|
3494
|
+
type: "terminal_output",
|
|
3495
|
+
sessionId,
|
|
3496
|
+
execId,
|
|
3497
|
+
stream: "stdout",
|
|
3498
|
+
data: chunk.toString()
|
|
3499
|
+
});
|
|
3500
|
+
});
|
|
3501
|
+
proc.stderr?.on("data", (chunk) => {
|
|
3502
|
+
this.emit({
|
|
3503
|
+
type: "terminal_output",
|
|
3504
|
+
sessionId,
|
|
3505
|
+
execId,
|
|
3506
|
+
stream: "stderr",
|
|
3507
|
+
data: chunk.toString()
|
|
3508
|
+
});
|
|
3509
|
+
});
|
|
3510
|
+
proc.on("exit", (code, signal) => {
|
|
3511
|
+
clearTimeout(timer);
|
|
3512
|
+
this.processes.delete(execId);
|
|
3513
|
+
this.emit({
|
|
3514
|
+
type: "terminal_exit",
|
|
3515
|
+
sessionId,
|
|
3516
|
+
execId,
|
|
3517
|
+
code,
|
|
3518
|
+
signal
|
|
3519
|
+
});
|
|
3520
|
+
});
|
|
3521
|
+
const timer = setTimeout(() => {
|
|
3522
|
+
if (this.processes.has(execId)) {
|
|
3523
|
+
killProcessCrossPlatform(proc);
|
|
3524
|
+
}
|
|
3525
|
+
}, EXEC_TIMEOUT_MS);
|
|
3526
|
+
console.log(`[TerminalExecutor] exec ${execId}: ${command.substring(0, 100)} (cwd: ${cwd})`);
|
|
3527
|
+
return execId;
|
|
3528
|
+
}
|
|
3529
|
+
kill(execId) {
|
|
3530
|
+
const proc = this.processes.get(execId);
|
|
3531
|
+
if (proc) {
|
|
3532
|
+
killProcessCrossPlatform(proc);
|
|
3533
|
+
console.log(`[TerminalExecutor] kill ${execId}`);
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
destroy() {
|
|
3537
|
+
for (const [execId, proc] of this.processes) {
|
|
3538
|
+
killProcessCrossPlatform(proc);
|
|
3539
|
+
console.log(`[TerminalExecutor] cleanup ${execId}`);
|
|
3540
|
+
}
|
|
3541
|
+
this.processes.clear();
|
|
3542
|
+
this.eventCallbacks.length = 0;
|
|
3543
|
+
}
|
|
3544
|
+
};
|
|
3545
|
+
|
|
3546
|
+
// src/server.ts
|
|
3380
3547
|
var WS_PORT = 3745;
|
|
3381
3548
|
var HTTP_PORT = 3746;
|
|
3382
|
-
var execAsync = (0, import_node_util.promisify)(
|
|
3549
|
+
var execAsync = (0, import_node_util.promisify)(import_node_child_process6.exec);
|
|
3383
3550
|
async function killPortProcess(port) {
|
|
3384
3551
|
try {
|
|
3385
3552
|
if (isWindows) {
|
|
@@ -3434,7 +3601,7 @@ async function start(opts = {}) {
|
|
|
3434
3601
|
try {
|
|
3435
3602
|
token = (await (0, import_promises4.readFile)(tokenFile, "utf8")).trim();
|
|
3436
3603
|
} catch {
|
|
3437
|
-
token = (0,
|
|
3604
|
+
token = (0, import_uuid5.v4)();
|
|
3438
3605
|
await (0, import_promises4.mkdir)(configDir, { recursive: true });
|
|
3439
3606
|
await (0, import_promises4.writeFile)(tokenFile, token, "utf8");
|
|
3440
3607
|
}
|
|
@@ -3442,6 +3609,20 @@ async function start(opts = {}) {
|
|
|
3442
3609
|
}
|
|
3443
3610
|
const provider = new ProcessProvider();
|
|
3444
3611
|
const sessionManager = new SessionManager(provider);
|
|
3612
|
+
const terminalExecutor = new TerminalExecutor();
|
|
3613
|
+
const wsBridge = await createWithRetry(
|
|
3614
|
+
"WsBridge",
|
|
3615
|
+
WS_PORT,
|
|
3616
|
+
() => WsBridge.create({ port: WS_PORT, token })
|
|
3617
|
+
);
|
|
3618
|
+
const unreadSessionIds = /* @__PURE__ */ new Set();
|
|
3619
|
+
sessionManager.onEvent((event) => {
|
|
3620
|
+
if (event.type === "status_change" && (event.status === "idle" || event.status === "error")) {
|
|
3621
|
+
if (!wsBridge.isViewingSession(event.sessionId)) {
|
|
3622
|
+
unreadSessionIds.add(event.sessionId);
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
});
|
|
3445
3626
|
const expoChannel = new ExpoNotificationChannel();
|
|
3446
3627
|
const notificationService = new NotificationService(sessionManager, expoChannel);
|
|
3447
3628
|
notificationService.addChannel("expo", expoChannel, opts.enableExpoPush !== false);
|
|
@@ -3456,11 +3637,6 @@ async function start(opts = {}) {
|
|
|
3456
3637
|
console.log(`[Server] ${t("server.activityPushContinue")}`);
|
|
3457
3638
|
}
|
|
3458
3639
|
}
|
|
3459
|
-
const wsBridge = await createWithRetry(
|
|
3460
|
-
"WsBridge",
|
|
3461
|
-
WS_PORT,
|
|
3462
|
-
() => WsBridge.create({ port: WS_PORT, token })
|
|
3463
|
-
);
|
|
3464
3640
|
const sessionFileWatcher = new SessionFileWatcher((event) => {
|
|
3465
3641
|
wsBridge.broadcast(event);
|
|
3466
3642
|
});
|
|
@@ -3489,7 +3665,6 @@ async function start(opts = {}) {
|
|
|
3489
3665
|
});
|
|
3490
3666
|
}
|
|
3491
3667
|
});
|
|
3492
|
-
const unreadSessionIds = /* @__PURE__ */ new Set();
|
|
3493
3668
|
notificationService.setGlobalPendingCountProvider(
|
|
3494
3669
|
() => approvalProxy.getPendingCount() + sessionManager.getAllPendingQuestions().length + unreadSessionIds.size
|
|
3495
3670
|
);
|
|
@@ -3520,6 +3695,8 @@ async function start(opts = {}) {
|
|
|
3520
3695
|
switch (event.type) {
|
|
3521
3696
|
case "create_session": {
|
|
3522
3697
|
await (0, import_promises4.mkdir)(event.projectPath, { recursive: true });
|
|
3698
|
+
const resumeId = event.resumeSessionId ?? event.newSessionId;
|
|
3699
|
+
if (resumeId) sessionFileWatcher.unwatch(resumeId);
|
|
3523
3700
|
await sessionManager.createSession(
|
|
3524
3701
|
event.projectPath,
|
|
3525
3702
|
event.message,
|
|
@@ -3537,6 +3714,7 @@ async function start(opts = {}) {
|
|
|
3537
3714
|
break;
|
|
3538
3715
|
}
|
|
3539
3716
|
case "send_message": {
|
|
3717
|
+
sessionFileWatcher.unwatch(event.sessionId);
|
|
3540
3718
|
await sessionManager.sendMessage(event.sessionId, event.message, event.permissionMode, event.images);
|
|
3541
3719
|
wsBridge.broadcast({
|
|
3542
3720
|
type: "session_list",
|
|
@@ -3625,6 +3803,10 @@ async function start(opts = {}) {
|
|
|
3625
3803
|
code: "PROJECT_LIST_ERROR"
|
|
3626
3804
|
});
|
|
3627
3805
|
}
|
|
3806
|
+
wsBridge.send(ws, {
|
|
3807
|
+
type: "session_list",
|
|
3808
|
+
sessions: sessionManager.getActiveSessions()
|
|
3809
|
+
});
|
|
3628
3810
|
break;
|
|
3629
3811
|
}
|
|
3630
3812
|
case "list_sessions": {
|
|
@@ -3719,6 +3901,20 @@ async function start(opts = {}) {
|
|
|
3719
3901
|
notificationService.setSoundPreferences(event.preferences);
|
|
3720
3902
|
break;
|
|
3721
3903
|
}
|
|
3904
|
+
case "terminal_exec": {
|
|
3905
|
+
const activeSession = sessionManager.getActiveSessions().find((s) => s.id === event.sessionId);
|
|
3906
|
+
const cwd = activeSession?.projectPath ?? sessionManager.getSessionProjectPath(event.sessionId);
|
|
3907
|
+
if (!cwd) {
|
|
3908
|
+
wsBridge.send(ws, { type: "error", code: "TERMINAL_EXEC_ERROR", message: "Session not found or no project path", sessionId: event.sessionId });
|
|
3909
|
+
break;
|
|
3910
|
+
}
|
|
3911
|
+
terminalExecutor.exec(event.sessionId, event.command, cwd);
|
|
3912
|
+
break;
|
|
3913
|
+
}
|
|
3914
|
+
case "terminal_kill": {
|
|
3915
|
+
terminalExecutor.kill(event.execId);
|
|
3916
|
+
break;
|
|
3917
|
+
}
|
|
3722
3918
|
case "register_activity_push_token": {
|
|
3723
3919
|
notificationService.addActivityPushToken(event.sessionId, event.token);
|
|
3724
3920
|
break;
|
|
@@ -3790,12 +3986,14 @@ async function start(opts = {}) {
|
|
|
3790
3986
|
sessionManager.onEvent((event) => {
|
|
3791
3987
|
wsBridge.broadcast(event);
|
|
3792
3988
|
if (event.type === "status_change" && (event.status === "idle" || event.status === "error")) {
|
|
3793
|
-
if (
|
|
3794
|
-
unreadSessionIds.add(event.sessionId);
|
|
3989
|
+
if (unreadSessionIds.has(event.sessionId)) {
|
|
3795
3990
|
broadcastUnreadSessions();
|
|
3796
3991
|
}
|
|
3797
3992
|
}
|
|
3798
3993
|
});
|
|
3994
|
+
terminalExecutor.onEvent((event) => {
|
|
3995
|
+
wsBridge.broadcast(event);
|
|
3996
|
+
});
|
|
3799
3997
|
wsBridge.onDisconnect(() => {
|
|
3800
3998
|
if (wsBridge.getConnectionCount() === 0 && approvalProxy.getPendingCount() > 0) {
|
|
3801
3999
|
approvalProxy.approveAll(t("server.phoneDisconnected"));
|
|
@@ -3895,6 +4093,7 @@ async function start(opts = {}) {
|
|
|
3895
4093
|
await attempt(() => wsBridge.close(), "WebSocket");
|
|
3896
4094
|
await attempt(() => approvalProxy.close(), "ApprovalProxy");
|
|
3897
4095
|
await attempt(() => sessionManager.destroy(), "SessionManager");
|
|
4096
|
+
await attempt(() => terminalExecutor.destroy(), "TerminalExecutor");
|
|
3898
4097
|
await attempt(() => notificationService.destroy(), "NotificationService");
|
|
3899
4098
|
await attempt(() => sessionFileWatcher.destroy(), "SessionFileWatcher");
|
|
3900
4099
|
if (errors.length > 0) {
|
|
@@ -3903,7 +4102,7 @@ async function start(opts = {}) {
|
|
|
3903
4102
|
}
|
|
3904
4103
|
console.log(`[Server] ${t("server.shutdownComplete")}`);
|
|
3905
4104
|
};
|
|
3906
|
-
|
|
4105
|
+
const instance = {
|
|
3907
4106
|
token,
|
|
3908
4107
|
wsPort: WS_PORT,
|
|
3909
4108
|
httpPort: HTTP_PORT,
|
|
@@ -3921,8 +4120,21 @@ async function start(opts = {}) {
|
|
|
3921
4120
|
}
|
|
3922
4121
|
},
|
|
3923
4122
|
openPairing: (duration) => pairingManager.open(duration),
|
|
3924
|
-
closePairing: () => pairingManager.close()
|
|
4123
|
+
closePairing: () => pairingManager.close(),
|
|
4124
|
+
regenerateToken: async () => {
|
|
4125
|
+
const newToken = (0, import_uuid5.v4)();
|
|
4126
|
+
await (0, import_promises4.mkdir)(configDir, { recursive: true });
|
|
4127
|
+
await (0, import_promises4.writeFile)(tokenFile, newToken, "utf8");
|
|
4128
|
+
instance.token = newToken;
|
|
4129
|
+
wsBridge.updateToken(newToken);
|
|
4130
|
+
approvalProxy.updateToken(newToken);
|
|
4131
|
+
pairingManager.updateToken(newToken);
|
|
4132
|
+
pairingManager.open();
|
|
4133
|
+
console.log(`[Server] ${t("server.tokenRegenerated", { token: newToken })}`);
|
|
4134
|
+
return newToken;
|
|
4135
|
+
}
|
|
3925
4136
|
};
|
|
4137
|
+
return instance;
|
|
3926
4138
|
}
|
|
3927
4139
|
|
|
3928
4140
|
// src/index.ts
|
|
@@ -3994,6 +4206,7 @@ async function main() {
|
|
|
3994
4206
|
console.log(t("startup.waitingConnection"));
|
|
3995
4207
|
console.log();
|
|
3996
4208
|
console.log(t("startup.pairingOpen"));
|
|
4209
|
+
console.log(t("startup.pressT"));
|
|
3997
4210
|
console.log();
|
|
3998
4211
|
fetchLatestVersion().then((latest) => {
|
|
3999
4212
|
if (!latest || latest === PKG_VERSION) return;
|
|
@@ -4024,6 +4237,23 @@ async function main() {
|
|
|
4024
4237
|
console.log(`
|
|
4025
4238
|
${t("startup.pairingReopened")}`);
|
|
4026
4239
|
}
|
|
4240
|
+
if (key === "t" || key === "T") {
|
|
4241
|
+
server.regenerateToken().then((newToken) => {
|
|
4242
|
+
console.log();
|
|
4243
|
+
console.log(` ${t("startup.tokenRegenerated")}`);
|
|
4244
|
+
console.log(t("startup.token", { token: newToken }));
|
|
4245
|
+
console.log();
|
|
4246
|
+
const newQrUrl = buildQrUrl(getLocalIp(), server.wsPort, newToken);
|
|
4247
|
+
console.log(t("startup.scanToPair"));
|
|
4248
|
+
import_qrcode_terminal.default.generate(newQrUrl, { small: true }, (qr) => {
|
|
4249
|
+
qr.split("\n").forEach((line) => console.log(` ${line}`));
|
|
4250
|
+
});
|
|
4251
|
+
console.log();
|
|
4252
|
+
}).catch((err) => {
|
|
4253
|
+
console.error(`
|
|
4254
|
+
${t("startup.tokenRegenerateFailed")}`, err);
|
|
4255
|
+
});
|
|
4256
|
+
}
|
|
4027
4257
|
if (key === "") {
|
|
4028
4258
|
shutdown("SIGINT");
|
|
4029
4259
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ interface ServerInstance {
|
|
|
19
19
|
openPairing: (duration?: number) => void;
|
|
20
20
|
/** 运行时关闭配对窗口 */
|
|
21
21
|
closePairing: () => void;
|
|
22
|
+
/** 重新生成 token(泄露后刷新),断开所有客户端并开启配对窗口 */
|
|
23
|
+
regenerateToken: () => Promise<string>;
|
|
22
24
|
}
|
|
23
25
|
interface ServerOptions {
|
|
24
26
|
/** 覆盖 token(默认读取 ~/.sessix/token 或自动生成) */
|
package/dist/server.js
CHANGED
|
@@ -52,7 +52,10 @@ var zh = {
|
|
|
52
52
|
autoDiscoveryHint: " \u5982\u5728\u516C\u5171\u7F51\u7EDC\uFF0C\u5EFA\u8BAE\u5173\u95ED: SESSIX_AUTO_CONNECT=false npx sessix-server",
|
|
53
53
|
autoDiscoveryOff: " \u2139\uFE0F \u81EA\u52A8\u53D1\u73B0\u5DF2\u5173\u95ED\uFF0C\u624B\u673A\u9700\u624B\u52A8\u8F93\u5165\u5730\u5740\u8FDE\u63A5",
|
|
54
54
|
pairingOpen: " \u{1F513} \u914D\u5BF9\u6A21\u5F0F\u5DF2\u5F00\u542F\uFF085 \u5206\u949F\u5185\u6709\u6548\uFF09\u2014 \u6309 p \u91CD\u65B0\u5F00\u542F",
|
|
55
|
+
pressT: " \u{1F511} \u6309 t \u91CD\u7F6E Token\uFF08\u6CC4\u9732\u540E\u5237\u65B0\uFF09",
|
|
55
56
|
pairingReopened: "\u{1F513} \u914D\u5BF9\u6A21\u5F0F\u5DF2\u91CD\u65B0\u5F00\u542F\uFF085 \u5206\u949F\uFF09",
|
|
57
|
+
tokenRegenerated: "\u{1F511} Token \u5DF2\u91CD\u7F6E\uFF0C\u6240\u6709\u5BA2\u6237\u7AEF\u5DF2\u65AD\u5F00\uFF0C\u8BF7\u91CD\u65B0\u626B\u7801\u914D\u5BF9",
|
|
58
|
+
tokenRegenerateFailed: "Token \u91CD\u7F6E\u5931\u8D25:",
|
|
56
59
|
updateAvailable: "\u53D1\u73B0\u65B0\u7248\u672C v{{latest}}\uFF08\u5F53\u524D v{{current}}\uFF09\uFF0C\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0\uFF1A",
|
|
57
60
|
receivedSignal: "\u6536\u5230 {{signal}}\uFF0C\u6B63\u5728\u4F18\u96C5\u5173\u95ED...",
|
|
58
61
|
goodbye: "\u6240\u6709\u670D\u52A1\u5DF2\u5173\u95ED\uFF0C\u518D\u89C1\uFF01",
|
|
@@ -81,7 +84,8 @@ var zh = {
|
|
|
81
84
|
activityPushEnabled: "ActivityKit Push \u5DF2\u542F\u7528",
|
|
82
85
|
activityPushFailed: "ActivityKit Push \u521D\u59CB\u5316\u5931\u8D25:",
|
|
83
86
|
activityPushContinue: "\u7EE7\u7EED\u542F\u52A8\uFF08Live Activity \u540E\u53F0\u63A8\u9001\u4E0D\u53EF\u7528\uFF09",
|
|
84
|
-
noActiveLoginProcess: "\u6CA1\u6709\u6D3B\u8DC3\u7684\u767B\u5F55\u8FDB\u7A0B"
|
|
87
|
+
noActiveLoginProcess: "\u6CA1\u6709\u6D3B\u8DC3\u7684\u767B\u5F55\u8FDB\u7A0B",
|
|
88
|
+
tokenRegenerated: "Token \u5DF2\u91CD\u7F6E: {{token}}"
|
|
85
89
|
},
|
|
86
90
|
ws: {
|
|
87
91
|
started: "WebSocket \u670D\u52A1\u5DF2\u542F\u52A8\uFF0C\u7AEF\u53E3 {{port}}",
|
|
@@ -158,7 +162,10 @@ var en = {
|
|
|
158
162
|
autoDiscoveryHint: " On public networks, disable with: SESSIX_AUTO_CONNECT=false npx sessix-server",
|
|
159
163
|
autoDiscoveryOff: " Auto-discovery disabled, phone must enter address manually",
|
|
160
164
|
pairingOpen: " \u{1F513} Pairing mode open (5 min) \u2014 press p to reopen",
|
|
165
|
+
pressT: " \u{1F511} Press t to regenerate token (refresh after leak)",
|
|
161
166
|
pairingReopened: "\u{1F513} Pairing mode reopened (5 min)",
|
|
167
|
+
tokenRegenerated: "\u{1F511} Token regenerated, all clients disconnected. Scan QR to re-pair",
|
|
168
|
+
tokenRegenerateFailed: "Token regeneration failed:",
|
|
162
169
|
updateAvailable: "New version v{{latest}} available (current v{{current}}). Update with:",
|
|
163
170
|
receivedSignal: "Received {{signal}}, graceful shutdown...",
|
|
164
171
|
goodbye: "All services closed, goodbye!",
|
|
@@ -187,7 +194,8 @@ var en = {
|
|
|
187
194
|
activityPushEnabled: "ActivityKit Push enabled",
|
|
188
195
|
activityPushFailed: "ActivityKit Push init failed:",
|
|
189
196
|
activityPushContinue: "Continuing startup (Live Activity background push unavailable)",
|
|
190
|
-
noActiveLoginProcess: "No active login process"
|
|
197
|
+
noActiveLoginProcess: "No active login process",
|
|
198
|
+
tokenRegenerated: "Token regenerated: {{token}}"
|
|
191
199
|
},
|
|
192
200
|
ws: {
|
|
193
201
|
started: "WebSocket server started on port {{port}}",
|
|
@@ -293,11 +301,11 @@ function t(key, params) {
|
|
|
293
301
|
}
|
|
294
302
|
|
|
295
303
|
// src/server.ts
|
|
296
|
-
var
|
|
304
|
+
var import_uuid5 = require("uuid");
|
|
297
305
|
var import_promises4 = require("fs/promises");
|
|
298
306
|
var import_node_os6 = require("os");
|
|
299
307
|
var import_node_path5 = require("path");
|
|
300
|
-
var
|
|
308
|
+
var import_node_child_process6 = require("child_process");
|
|
301
309
|
var import_node_util = require("util");
|
|
302
310
|
|
|
303
311
|
// src/providers/ProcessProvider.ts
|
|
@@ -1544,6 +1552,13 @@ var WsBridge = class _WsBridge {
|
|
|
1544
1552
|
getConnectionCount() {
|
|
1545
1553
|
return this.wss.clients.size;
|
|
1546
1554
|
}
|
|
1555
|
+
/** 更新 token 并断开所有现有连接(token 刷新后需重新配对) */
|
|
1556
|
+
updateToken(newToken) {
|
|
1557
|
+
this.token = newToken;
|
|
1558
|
+
for (const ws of this.wss.clients) {
|
|
1559
|
+
ws.close(4001, "Token regenerated");
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1547
1562
|
/** 优雅关闭 WebSocket 服务 */
|
|
1548
1563
|
close() {
|
|
1549
1564
|
return new Promise((resolve, reject) => {
|
|
@@ -1983,6 +1998,10 @@ var ApprovalProxy = class _ApprovalProxy {
|
|
|
1983
1998
|
});
|
|
1984
1999
|
}
|
|
1985
2000
|
}
|
|
2001
|
+
/** 更新 token(token 刷新时调用) */
|
|
2002
|
+
updateToken(newToken) {
|
|
2003
|
+
this.token = newToken;
|
|
2004
|
+
}
|
|
1986
2005
|
/** 返回连接 token(仅本机访问) */
|
|
1987
2006
|
handleToken(req, res) {
|
|
1988
2007
|
const remoteAddress = req.socket.remoteAddress;
|
|
@@ -2046,79 +2065,120 @@ var ApprovalProxy = class _ApprovalProxy {
|
|
|
2046
2065
|
};
|
|
2047
2066
|
|
|
2048
2067
|
// src/mdns/MdnsService.ts
|
|
2049
|
-
var
|
|
2068
|
+
var import_node_child_process3 = require("child_process");
|
|
2050
2069
|
var import_node_os4 = require("os");
|
|
2051
|
-
function
|
|
2052
|
-
|
|
2053
|
-
for (const [name, addrs] of Object.entries((0, import_node_os4.networkInterfaces)())) {
|
|
2054
|
-
if (name.startsWith("utun") || name === "lo") continue;
|
|
2055
|
-
if (isWindows && (name.startsWith("vEthernet") || name.includes("Loopback"))) continue;
|
|
2056
|
-
for (const addr of addrs ?? []) {
|
|
2057
|
-
if (addr.family === "IPv4" && !addr.internal) {
|
|
2058
|
-
results.push(addr.address);
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
return results;
|
|
2070
|
+
function buildTxtArgs(txt) {
|
|
2071
|
+
return Object.entries(txt).map(([k, v]) => `${k}=${v}`);
|
|
2063
2072
|
}
|
|
2064
2073
|
var MdnsService = class {
|
|
2065
|
-
|
|
2066
|
-
|
|
2074
|
+
proc = null;
|
|
2075
|
+
bonjourInstance = null;
|
|
2076
|
+
bonjourService = null;
|
|
2067
2077
|
wsPort;
|
|
2068
2078
|
httpPort;
|
|
2069
2079
|
version;
|
|
2070
2080
|
pairing;
|
|
2081
|
+
useDnsSd;
|
|
2071
2082
|
constructor(options) {
|
|
2072
2083
|
this.wsPort = options.wsPort;
|
|
2073
2084
|
this.httpPort = options.httpPort;
|
|
2074
2085
|
this.version = options.version ?? "0.1.0";
|
|
2075
2086
|
this.pairing = options.pairing ?? "closed";
|
|
2087
|
+
this.useDnsSd = (0, import_node_os4.platform)() === "darwin";
|
|
2088
|
+
}
|
|
2089
|
+
getTxt() {
|
|
2090
|
+
return {
|
|
2091
|
+
version: this.version,
|
|
2092
|
+
httpPort: String(this.httpPort),
|
|
2093
|
+
wsPort: String(this.wsPort),
|
|
2094
|
+
pairing: this.pairing
|
|
2095
|
+
};
|
|
2076
2096
|
}
|
|
2077
2097
|
/**
|
|
2078
2098
|
* 启动 mDNS 广播
|
|
2079
2099
|
*/
|
|
2080
2100
|
start() {
|
|
2081
|
-
if (this.
|
|
2101
|
+
if (this.useDnsSd) {
|
|
2102
|
+
this.startDnsSd();
|
|
2103
|
+
} else {
|
|
2104
|
+
this.startBonjour();
|
|
2105
|
+
}
|
|
2106
|
+
}
|
|
2107
|
+
startDnsSd() {
|
|
2108
|
+
if (this.proc) {
|
|
2082
2109
|
console.warn(`[MdnsService] ${t("mdns.alreadyRunning")}`);
|
|
2083
2110
|
return;
|
|
2084
2111
|
}
|
|
2085
|
-
const
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
wsPort: String(this.wsPort),
|
|
2104
|
-
pairing: this.pairing
|
|
2112
|
+
const args = [
|
|
2113
|
+
"-R",
|
|
2114
|
+
"Sessix",
|
|
2115
|
+
"_sessix._tcp",
|
|
2116
|
+
"local",
|
|
2117
|
+
String(this.wsPort),
|
|
2118
|
+
...buildTxtArgs(this.getTxt())
|
|
2119
|
+
];
|
|
2120
|
+
this.proc = (0, import_node_child_process3.spawn)("dns-sd", args, { stdio: "ignore" });
|
|
2121
|
+
this.proc.on("error", (err) => {
|
|
2122
|
+
console.warn(`[MdnsService] dns-sd failed, falling back to bonjour-service: ${err.message}`);
|
|
2123
|
+
this.proc = null;
|
|
2124
|
+
this.useDnsSd = false;
|
|
2125
|
+
this.startBonjour();
|
|
2126
|
+
});
|
|
2127
|
+
this.proc.on("exit", (code) => {
|
|
2128
|
+
if (code !== null && code !== 0) {
|
|
2129
|
+
console.warn(`[MdnsService] dns-sd exited with code ${code}`);
|
|
2105
2130
|
}
|
|
2131
|
+
this.proc = null;
|
|
2106
2132
|
});
|
|
2107
|
-
console.log(`[MdnsService] ${t("mdns.started", { port: this.wsPort })}`);
|
|
2133
|
+
console.log(`[MdnsService] ${t("mdns.started", { port: this.wsPort })} (dns-sd)`);
|
|
2134
|
+
}
|
|
2135
|
+
async startBonjour() {
|
|
2136
|
+
if (this.bonjourInstance) {
|
|
2137
|
+
console.warn(`[MdnsService] ${t("mdns.alreadyRunning")}`);
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
try {
|
|
2141
|
+
const { default: Bonjour } = await import("bonjour-service");
|
|
2142
|
+
const { networkInterfaces } = await import("os");
|
|
2143
|
+
const lanAddrs = getLanAddresses(networkInterfaces);
|
|
2144
|
+
const opts = lanAddrs.length > 0 ? { interface: lanAddrs[0] } : {};
|
|
2145
|
+
const onError = (err) => {
|
|
2146
|
+
if (err.code === "EADDRINUSE") return;
|
|
2147
|
+
console.warn(`[MdnsService] mDNS error (non-fatal): ${err.message}`);
|
|
2148
|
+
};
|
|
2149
|
+
this.bonjourInstance = new Bonjour(opts, onError);
|
|
2150
|
+
this.bonjourInstance.server?.mdns?.on("error", onError);
|
|
2151
|
+
if (lanAddrs.length > 0) {
|
|
2152
|
+
console.log(`[MdnsService] ${t("mdns.boundInterface", { ip: lanAddrs[0] })}`);
|
|
2153
|
+
}
|
|
2154
|
+
this.bonjourService = this.bonjourInstance.publish({
|
|
2155
|
+
name: "Sessix",
|
|
2156
|
+
type: "sessix",
|
|
2157
|
+
port: this.wsPort,
|
|
2158
|
+
txt: this.getTxt()
|
|
2159
|
+
});
|
|
2160
|
+
console.log(`[MdnsService] ${t("mdns.started", { port: this.wsPort })} (bonjour-service)`);
|
|
2161
|
+
} catch (err) {
|
|
2162
|
+
console.warn(`[MdnsService] bonjour-service failed: ${err.message}`);
|
|
2163
|
+
}
|
|
2108
2164
|
}
|
|
2109
2165
|
/**
|
|
2110
2166
|
* 停止 mDNS 广播
|
|
2111
2167
|
*/
|
|
2112
2168
|
stop() {
|
|
2113
|
-
if (this.
|
|
2114
|
-
this.
|
|
2169
|
+
if (this.proc) {
|
|
2170
|
+
this.proc.kill();
|
|
2171
|
+
this.proc = null;
|
|
2172
|
+
}
|
|
2173
|
+
if (this.bonjourService) {
|
|
2174
|
+
this.bonjourService.stop?.(() => {
|
|
2115
2175
|
console.log(`[MdnsService] ${t("mdns.stopped")}`);
|
|
2116
2176
|
});
|
|
2117
|
-
this.
|
|
2177
|
+
this.bonjourService = null;
|
|
2118
2178
|
}
|
|
2119
|
-
if (this.
|
|
2120
|
-
this.
|
|
2121
|
-
this.
|
|
2179
|
+
if (this.bonjourInstance) {
|
|
2180
|
+
this.bonjourInstance.destroy();
|
|
2181
|
+
this.bonjourInstance = null;
|
|
2122
2182
|
}
|
|
2123
2183
|
console.log(`[MdnsService] ${t("mdns.closed")}`);
|
|
2124
2184
|
}
|
|
@@ -2127,30 +2187,45 @@ var MdnsService = class {
|
|
|
2127
2187
|
*/
|
|
2128
2188
|
updatePairingState(state) {
|
|
2129
2189
|
this.pairing = state;
|
|
2130
|
-
if (
|
|
2190
|
+
if (this.useDnsSd) {
|
|
2191
|
+
if (this.proc) {
|
|
2192
|
+
this.proc.kill();
|
|
2193
|
+
this.proc = null;
|
|
2194
|
+
}
|
|
2195
|
+
this.startDnsSd();
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
if (!this.bonjourInstance) return;
|
|
2131
2199
|
const republish = () => {
|
|
2132
|
-
if (!this.
|
|
2133
|
-
this.
|
|
2200
|
+
if (!this.bonjourInstance) return;
|
|
2201
|
+
this.bonjourService = this.bonjourInstance.publish({
|
|
2134
2202
|
name: "Sessix",
|
|
2135
2203
|
type: "sessix",
|
|
2136
2204
|
port: this.wsPort,
|
|
2137
|
-
txt:
|
|
2138
|
-
version: this.version,
|
|
2139
|
-
httpPort: String(this.httpPort),
|
|
2140
|
-
wsPort: String(this.wsPort),
|
|
2141
|
-
pairing: state
|
|
2142
|
-
}
|
|
2205
|
+
txt: this.getTxt()
|
|
2143
2206
|
});
|
|
2144
2207
|
};
|
|
2145
|
-
if (this.
|
|
2146
|
-
const old = this.
|
|
2147
|
-
this.
|
|
2208
|
+
if (this.bonjourService) {
|
|
2209
|
+
const old = this.bonjourService;
|
|
2210
|
+
this.bonjourService = null;
|
|
2148
2211
|
old.stop?.(() => republish());
|
|
2149
2212
|
} else {
|
|
2150
2213
|
republish();
|
|
2151
2214
|
}
|
|
2152
2215
|
}
|
|
2153
2216
|
};
|
|
2217
|
+
function getLanAddresses(networkInterfacesFn) {
|
|
2218
|
+
const results = [];
|
|
2219
|
+
for (const [name, addrs] of Object.entries(networkInterfacesFn())) {
|
|
2220
|
+
if (name.startsWith("utun") || name === "lo") continue;
|
|
2221
|
+
for (const addr of addrs ?? []) {
|
|
2222
|
+
if (addr.family === "IPv4" && !addr.internal) {
|
|
2223
|
+
results.push(addr.address);
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
return results;
|
|
2228
|
+
}
|
|
2154
2229
|
|
|
2155
2230
|
// src/hooks/HookInstaller.ts
|
|
2156
2231
|
var import_promises2 = require("fs/promises");
|
|
@@ -2624,7 +2699,7 @@ var NotificationService = class {
|
|
|
2624
2699
|
};
|
|
2625
2700
|
|
|
2626
2701
|
// src/notification/DesktopNotificationChannel.ts
|
|
2627
|
-
var
|
|
2702
|
+
var import_node_child_process4 = require("child_process");
|
|
2628
2703
|
var DesktopNotificationChannel = class {
|
|
2629
2704
|
isAvailable() {
|
|
2630
2705
|
return process.platform === "darwin";
|
|
@@ -2636,7 +2711,7 @@ var DesktopNotificationChannel = class {
|
|
|
2636
2711
|
const sound = payload.sound ?? "Ping";
|
|
2637
2712
|
const script = `display notification "${body}" with title "${title}" sound name "${sound}"`;
|
|
2638
2713
|
return new Promise((resolve) => {
|
|
2639
|
-
(0,
|
|
2714
|
+
(0, import_node_child_process4.execFile)("osascript", ["-e", script], (err) => {
|
|
2640
2715
|
if (err) {
|
|
2641
2716
|
console.warn("[DesktopNotificationChannel] Send notification failed:", err.message);
|
|
2642
2717
|
}
|
|
@@ -3251,6 +3326,9 @@ var PairingManager = class {
|
|
|
3251
3326
|
this.close();
|
|
3252
3327
|
return result;
|
|
3253
3328
|
}
|
|
3329
|
+
updateToken(newToken) {
|
|
3330
|
+
this.token = newToken;
|
|
3331
|
+
}
|
|
3254
3332
|
getRemainingSeconds() {
|
|
3255
3333
|
if (this._state !== "open") return 0;
|
|
3256
3334
|
return Math.max(0, Math.ceil((this.deadline - Date.now()) / 1e3));
|
|
@@ -3383,9 +3461,98 @@ var AuthManager = class extends import_events2.EventEmitter {
|
|
|
3383
3461
|
|
|
3384
3462
|
// src/server.ts
|
|
3385
3463
|
var import_promises5 = require("fs/promises");
|
|
3464
|
+
|
|
3465
|
+
// src/terminal/TerminalExecutor.ts
|
|
3466
|
+
var import_node_child_process5 = require("child_process");
|
|
3467
|
+
var import_uuid4 = require("uuid");
|
|
3468
|
+
var EXEC_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
3469
|
+
var TerminalExecutor = class {
|
|
3470
|
+
processes = /* @__PURE__ */ new Map();
|
|
3471
|
+
eventCallbacks = [];
|
|
3472
|
+
onEvent(callback) {
|
|
3473
|
+
this.eventCallbacks.push(callback);
|
|
3474
|
+
return () => {
|
|
3475
|
+
const idx = this.eventCallbacks.indexOf(callback);
|
|
3476
|
+
if (idx !== -1) this.eventCallbacks.splice(idx, 1);
|
|
3477
|
+
};
|
|
3478
|
+
}
|
|
3479
|
+
emit(event) {
|
|
3480
|
+
for (const cb of this.eventCallbacks) {
|
|
3481
|
+
try {
|
|
3482
|
+
cb(event);
|
|
3483
|
+
} catch (err) {
|
|
3484
|
+
console.error("[TerminalExecutor] Event callback error:", err);
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
exec(sessionId, command, cwd) {
|
|
3489
|
+
const execId = (0, import_uuid4.v4)();
|
|
3490
|
+
const shell = isWindows ? "powershell" : "bash";
|
|
3491
|
+
const args = isWindows ? ["-Command", command] : ["-c", command];
|
|
3492
|
+
const proc = (0, import_node_child_process5.spawn)(shell, args, {
|
|
3493
|
+
cwd,
|
|
3494
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
3495
|
+
env: { ...process.env }
|
|
3496
|
+
});
|
|
3497
|
+
this.processes.set(execId, proc);
|
|
3498
|
+
proc.stdout?.on("data", (chunk) => {
|
|
3499
|
+
this.emit({
|
|
3500
|
+
type: "terminal_output",
|
|
3501
|
+
sessionId,
|
|
3502
|
+
execId,
|
|
3503
|
+
stream: "stdout",
|
|
3504
|
+
data: chunk.toString()
|
|
3505
|
+
});
|
|
3506
|
+
});
|
|
3507
|
+
proc.stderr?.on("data", (chunk) => {
|
|
3508
|
+
this.emit({
|
|
3509
|
+
type: "terminal_output",
|
|
3510
|
+
sessionId,
|
|
3511
|
+
execId,
|
|
3512
|
+
stream: "stderr",
|
|
3513
|
+
data: chunk.toString()
|
|
3514
|
+
});
|
|
3515
|
+
});
|
|
3516
|
+
proc.on("exit", (code, signal) => {
|
|
3517
|
+
clearTimeout(timer);
|
|
3518
|
+
this.processes.delete(execId);
|
|
3519
|
+
this.emit({
|
|
3520
|
+
type: "terminal_exit",
|
|
3521
|
+
sessionId,
|
|
3522
|
+
execId,
|
|
3523
|
+
code,
|
|
3524
|
+
signal
|
|
3525
|
+
});
|
|
3526
|
+
});
|
|
3527
|
+
const timer = setTimeout(() => {
|
|
3528
|
+
if (this.processes.has(execId)) {
|
|
3529
|
+
killProcessCrossPlatform(proc);
|
|
3530
|
+
}
|
|
3531
|
+
}, EXEC_TIMEOUT_MS);
|
|
3532
|
+
console.log(`[TerminalExecutor] exec ${execId}: ${command.substring(0, 100)} (cwd: ${cwd})`);
|
|
3533
|
+
return execId;
|
|
3534
|
+
}
|
|
3535
|
+
kill(execId) {
|
|
3536
|
+
const proc = this.processes.get(execId);
|
|
3537
|
+
if (proc) {
|
|
3538
|
+
killProcessCrossPlatform(proc);
|
|
3539
|
+
console.log(`[TerminalExecutor] kill ${execId}`);
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
destroy() {
|
|
3543
|
+
for (const [execId, proc] of this.processes) {
|
|
3544
|
+
killProcessCrossPlatform(proc);
|
|
3545
|
+
console.log(`[TerminalExecutor] cleanup ${execId}`);
|
|
3546
|
+
}
|
|
3547
|
+
this.processes.clear();
|
|
3548
|
+
this.eventCallbacks.length = 0;
|
|
3549
|
+
}
|
|
3550
|
+
};
|
|
3551
|
+
|
|
3552
|
+
// src/server.ts
|
|
3386
3553
|
var WS_PORT = 3745;
|
|
3387
3554
|
var HTTP_PORT = 3746;
|
|
3388
|
-
var execAsync = (0, import_node_util.promisify)(
|
|
3555
|
+
var execAsync = (0, import_node_util.promisify)(import_node_child_process6.exec);
|
|
3389
3556
|
async function killPortProcess(port) {
|
|
3390
3557
|
try {
|
|
3391
3558
|
if (isWindows) {
|
|
@@ -3440,7 +3607,7 @@ async function start(opts = {}) {
|
|
|
3440
3607
|
try {
|
|
3441
3608
|
token = (await (0, import_promises4.readFile)(tokenFile, "utf8")).trim();
|
|
3442
3609
|
} catch {
|
|
3443
|
-
token = (0,
|
|
3610
|
+
token = (0, import_uuid5.v4)();
|
|
3444
3611
|
await (0, import_promises4.mkdir)(configDir, { recursive: true });
|
|
3445
3612
|
await (0, import_promises4.writeFile)(tokenFile, token, "utf8");
|
|
3446
3613
|
}
|
|
@@ -3448,6 +3615,20 @@ async function start(opts = {}) {
|
|
|
3448
3615
|
}
|
|
3449
3616
|
const provider = new ProcessProvider();
|
|
3450
3617
|
const sessionManager = new SessionManager(provider);
|
|
3618
|
+
const terminalExecutor = new TerminalExecutor();
|
|
3619
|
+
const wsBridge = await createWithRetry(
|
|
3620
|
+
"WsBridge",
|
|
3621
|
+
WS_PORT,
|
|
3622
|
+
() => WsBridge.create({ port: WS_PORT, token })
|
|
3623
|
+
);
|
|
3624
|
+
const unreadSessionIds = /* @__PURE__ */ new Set();
|
|
3625
|
+
sessionManager.onEvent((event) => {
|
|
3626
|
+
if (event.type === "status_change" && (event.status === "idle" || event.status === "error")) {
|
|
3627
|
+
if (!wsBridge.isViewingSession(event.sessionId)) {
|
|
3628
|
+
unreadSessionIds.add(event.sessionId);
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
});
|
|
3451
3632
|
const expoChannel = new ExpoNotificationChannel();
|
|
3452
3633
|
const notificationService = new NotificationService(sessionManager, expoChannel);
|
|
3453
3634
|
notificationService.addChannel("expo", expoChannel, opts.enableExpoPush !== false);
|
|
@@ -3462,11 +3643,6 @@ async function start(opts = {}) {
|
|
|
3462
3643
|
console.log(`[Server] ${t("server.activityPushContinue")}`);
|
|
3463
3644
|
}
|
|
3464
3645
|
}
|
|
3465
|
-
const wsBridge = await createWithRetry(
|
|
3466
|
-
"WsBridge",
|
|
3467
|
-
WS_PORT,
|
|
3468
|
-
() => WsBridge.create({ port: WS_PORT, token })
|
|
3469
|
-
);
|
|
3470
3646
|
const sessionFileWatcher = new SessionFileWatcher((event) => {
|
|
3471
3647
|
wsBridge.broadcast(event);
|
|
3472
3648
|
});
|
|
@@ -3495,7 +3671,6 @@ async function start(opts = {}) {
|
|
|
3495
3671
|
});
|
|
3496
3672
|
}
|
|
3497
3673
|
});
|
|
3498
|
-
const unreadSessionIds = /* @__PURE__ */ new Set();
|
|
3499
3674
|
notificationService.setGlobalPendingCountProvider(
|
|
3500
3675
|
() => approvalProxy.getPendingCount() + sessionManager.getAllPendingQuestions().length + unreadSessionIds.size
|
|
3501
3676
|
);
|
|
@@ -3526,6 +3701,8 @@ async function start(opts = {}) {
|
|
|
3526
3701
|
switch (event.type) {
|
|
3527
3702
|
case "create_session": {
|
|
3528
3703
|
await (0, import_promises4.mkdir)(event.projectPath, { recursive: true });
|
|
3704
|
+
const resumeId = event.resumeSessionId ?? event.newSessionId;
|
|
3705
|
+
if (resumeId) sessionFileWatcher.unwatch(resumeId);
|
|
3529
3706
|
await sessionManager.createSession(
|
|
3530
3707
|
event.projectPath,
|
|
3531
3708
|
event.message,
|
|
@@ -3543,6 +3720,7 @@ async function start(opts = {}) {
|
|
|
3543
3720
|
break;
|
|
3544
3721
|
}
|
|
3545
3722
|
case "send_message": {
|
|
3723
|
+
sessionFileWatcher.unwatch(event.sessionId);
|
|
3546
3724
|
await sessionManager.sendMessage(event.sessionId, event.message, event.permissionMode, event.images);
|
|
3547
3725
|
wsBridge.broadcast({
|
|
3548
3726
|
type: "session_list",
|
|
@@ -3631,6 +3809,10 @@ async function start(opts = {}) {
|
|
|
3631
3809
|
code: "PROJECT_LIST_ERROR"
|
|
3632
3810
|
});
|
|
3633
3811
|
}
|
|
3812
|
+
wsBridge.send(ws, {
|
|
3813
|
+
type: "session_list",
|
|
3814
|
+
sessions: sessionManager.getActiveSessions()
|
|
3815
|
+
});
|
|
3634
3816
|
break;
|
|
3635
3817
|
}
|
|
3636
3818
|
case "list_sessions": {
|
|
@@ -3725,6 +3907,20 @@ async function start(opts = {}) {
|
|
|
3725
3907
|
notificationService.setSoundPreferences(event.preferences);
|
|
3726
3908
|
break;
|
|
3727
3909
|
}
|
|
3910
|
+
case "terminal_exec": {
|
|
3911
|
+
const activeSession = sessionManager.getActiveSessions().find((s) => s.id === event.sessionId);
|
|
3912
|
+
const cwd = activeSession?.projectPath ?? sessionManager.getSessionProjectPath(event.sessionId);
|
|
3913
|
+
if (!cwd) {
|
|
3914
|
+
wsBridge.send(ws, { type: "error", code: "TERMINAL_EXEC_ERROR", message: "Session not found or no project path", sessionId: event.sessionId });
|
|
3915
|
+
break;
|
|
3916
|
+
}
|
|
3917
|
+
terminalExecutor.exec(event.sessionId, event.command, cwd);
|
|
3918
|
+
break;
|
|
3919
|
+
}
|
|
3920
|
+
case "terminal_kill": {
|
|
3921
|
+
terminalExecutor.kill(event.execId);
|
|
3922
|
+
break;
|
|
3923
|
+
}
|
|
3728
3924
|
case "register_activity_push_token": {
|
|
3729
3925
|
notificationService.addActivityPushToken(event.sessionId, event.token);
|
|
3730
3926
|
break;
|
|
@@ -3796,12 +3992,14 @@ async function start(opts = {}) {
|
|
|
3796
3992
|
sessionManager.onEvent((event) => {
|
|
3797
3993
|
wsBridge.broadcast(event);
|
|
3798
3994
|
if (event.type === "status_change" && (event.status === "idle" || event.status === "error")) {
|
|
3799
|
-
if (
|
|
3800
|
-
unreadSessionIds.add(event.sessionId);
|
|
3995
|
+
if (unreadSessionIds.has(event.sessionId)) {
|
|
3801
3996
|
broadcastUnreadSessions();
|
|
3802
3997
|
}
|
|
3803
3998
|
}
|
|
3804
3999
|
});
|
|
4000
|
+
terminalExecutor.onEvent((event) => {
|
|
4001
|
+
wsBridge.broadcast(event);
|
|
4002
|
+
});
|
|
3805
4003
|
wsBridge.onDisconnect(() => {
|
|
3806
4004
|
if (wsBridge.getConnectionCount() === 0 && approvalProxy.getPendingCount() > 0) {
|
|
3807
4005
|
approvalProxy.approveAll(t("server.phoneDisconnected"));
|
|
@@ -3901,6 +4099,7 @@ async function start(opts = {}) {
|
|
|
3901
4099
|
await attempt(() => wsBridge.close(), "WebSocket");
|
|
3902
4100
|
await attempt(() => approvalProxy.close(), "ApprovalProxy");
|
|
3903
4101
|
await attempt(() => sessionManager.destroy(), "SessionManager");
|
|
4102
|
+
await attempt(() => terminalExecutor.destroy(), "TerminalExecutor");
|
|
3904
4103
|
await attempt(() => notificationService.destroy(), "NotificationService");
|
|
3905
4104
|
await attempt(() => sessionFileWatcher.destroy(), "SessionFileWatcher");
|
|
3906
4105
|
if (errors.length > 0) {
|
|
@@ -3909,7 +4108,7 @@ async function start(opts = {}) {
|
|
|
3909
4108
|
}
|
|
3910
4109
|
console.log(`[Server] ${t("server.shutdownComplete")}`);
|
|
3911
4110
|
};
|
|
3912
|
-
|
|
4111
|
+
const instance = {
|
|
3913
4112
|
token,
|
|
3914
4113
|
wsPort: WS_PORT,
|
|
3915
4114
|
httpPort: HTTP_PORT,
|
|
@@ -3927,8 +4126,21 @@ async function start(opts = {}) {
|
|
|
3927
4126
|
}
|
|
3928
4127
|
},
|
|
3929
4128
|
openPairing: (duration) => pairingManager.open(duration),
|
|
3930
|
-
closePairing: () => pairingManager.close()
|
|
4129
|
+
closePairing: () => pairingManager.close(),
|
|
4130
|
+
regenerateToken: async () => {
|
|
4131
|
+
const newToken = (0, import_uuid5.v4)();
|
|
4132
|
+
await (0, import_promises4.mkdir)(configDir, { recursive: true });
|
|
4133
|
+
await (0, import_promises4.writeFile)(tokenFile, newToken, "utf8");
|
|
4134
|
+
instance.token = newToken;
|
|
4135
|
+
wsBridge.updateToken(newToken);
|
|
4136
|
+
approvalProxy.updateToken(newToken);
|
|
4137
|
+
pairingManager.updateToken(newToken);
|
|
4138
|
+
pairingManager.open();
|
|
4139
|
+
console.log(`[Server] ${t("server.tokenRegenerated", { token: newToken })}`);
|
|
4140
|
+
return newToken;
|
|
4141
|
+
}
|
|
3931
4142
|
};
|
|
4143
|
+
return instance;
|
|
3932
4144
|
}
|
|
3933
4145
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3934
4146
|
0 && (module.exports = {
|