@dsh-sup/dsh-core-win-x64 0.1.6-BETA.2 → 0.1.6-BETA.3
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/core.cjs +1323 -1304
- package/package.json +1 -1
package/core.cjs
CHANGED
|
@@ -107,1503 +107,1503 @@ var require_exec = __commonJS({
|
|
|
107
107
|
}
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
-
// src/platform/
|
|
111
|
-
var
|
|
112
|
-
"src/platform/
|
|
110
|
+
// src/platform/os/pidlookup/norm.js
|
|
111
|
+
var require_norm = __commonJS({
|
|
112
|
+
"src/platform/os/pidlookup/norm.js"(exports2, module2) {
|
|
113
113
|
"use strict";
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
114
|
+
function parseProcNetTcpInodes(txt, port) {
|
|
115
|
+
const inodes = /* @__PURE__ */ new Set();
|
|
116
|
+
for (const lineRaw of String(txt || "").split("\n")) {
|
|
117
|
+
const cols = lineRaw.trim().split(/\s+/);
|
|
118
|
+
if (cols.length < 10) continue;
|
|
119
|
+
const local = cols[1];
|
|
120
|
+
const st = cols[3];
|
|
121
|
+
const inode = cols[9];
|
|
122
|
+
if (!local || !inode) continue;
|
|
123
|
+
const p = local.split(":")[1];
|
|
124
|
+
if (st === "0A" && p && parseInt(p, 16) === port) inodes.add("socket:[" + inode + "]");
|
|
124
125
|
}
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
return inodes;
|
|
127
|
+
}
|
|
128
|
+
function parseLsofPid(out) {
|
|
129
|
+
for (const line of String(out || "").split("\n")) {
|
|
130
|
+
const m = line.trim().split(/\s+/);
|
|
131
|
+
if (m.length >= 2 && /^\d+$/.test(m[1])) return Number(m[1]);
|
|
127
132
|
}
|
|
128
|
-
|
|
129
|
-
return xdg && String(xdg).trim() ? path2.join(String(xdg).trim(), "dsh-supervisor") : path2.join(os2.homedir(), ".local", "state", "dsh-supervisor");
|
|
133
|
+
return null;
|
|
130
134
|
}
|
|
131
|
-
function
|
|
132
|
-
|
|
135
|
+
function parseNetstatPid(out, port) {
|
|
136
|
+
const want = String(port);
|
|
137
|
+
for (const line of String(out || "").split("\n")) {
|
|
138
|
+
const parts = line.trim().split(/\s+/);
|
|
139
|
+
if (parts.length >= 5 && (parts[0] === "TCP" || parts[0] === "TCPv6") && parts[3] === "LISTENING") {
|
|
140
|
+
const lp = parts[1];
|
|
141
|
+
const p = lp.slice(lp.lastIndexOf(":") + 1);
|
|
142
|
+
if (p === want) {
|
|
143
|
+
const pid = Number(parts[4]);
|
|
144
|
+
if (Number.isInteger(pid) && pid > 0) return pid;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
133
149
|
}
|
|
134
|
-
function
|
|
135
|
-
|
|
150
|
+
function parseSsPid(out) {
|
|
151
|
+
const m = out && /pid=(\d+)/.exec(String(out));
|
|
152
|
+
return m ? Number(m[1]) : null;
|
|
136
153
|
}
|
|
137
|
-
function
|
|
138
|
-
|
|
154
|
+
function parseWmicCommandLine(out) {
|
|
155
|
+
if (!out) return null;
|
|
156
|
+
const m = /CommandLine=([\s\S]*)/.exec(String(out));
|
|
157
|
+
const v = m ? m[1].trim() : "";
|
|
158
|
+
return v || null;
|
|
139
159
|
}
|
|
140
|
-
function
|
|
141
|
-
|
|
160
|
+
function parsePowerShellCommandLine(out) {
|
|
161
|
+
const v = out ? String(out).trim() : "";
|
|
162
|
+
return v || null;
|
|
142
163
|
}
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
for (const [from, to] of [
|
|
146
|
-
[legacySupervisorDir(), supervisorDir()],
|
|
147
|
-
[legacyShellDir(), shellDir()]
|
|
148
|
-
]) {
|
|
149
|
-
try {
|
|
150
|
-
if (!fs2.existsSync(from)) continue;
|
|
151
|
-
fs2.mkdirSync(to, { recursive: true });
|
|
152
|
-
for (const name of fs2.readdirSync(from)) {
|
|
153
|
-
const src = path2.join(from, name);
|
|
154
|
-
const dst = path2.join(to, name);
|
|
155
|
-
if (fs2.existsSync(dst)) continue;
|
|
156
|
-
try {
|
|
157
|
-
fs2.renameSync(src, dst);
|
|
158
|
-
moved.push(src + " -> " + dst);
|
|
159
|
-
} catch {
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
try {
|
|
163
|
-
if (fs2.readdirSync(from).length === 0) fs2.rmdirSync(from);
|
|
164
|
-
} catch {
|
|
165
|
-
}
|
|
166
|
-
} catch {
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return moved;
|
|
164
|
+
function normCmdline(s) {
|
|
165
|
+
return String(s || "").replace(/\\/g, "/");
|
|
170
166
|
}
|
|
171
|
-
module2.exports = {
|
|
167
|
+
module2.exports = {
|
|
168
|
+
parseProcNetTcpInodes,
|
|
169
|
+
parseLsofPid,
|
|
170
|
+
parseNetstatPid,
|
|
171
|
+
parseSsPid,
|
|
172
|
+
parseWmicCommandLine,
|
|
173
|
+
parsePowerShellCommandLine,
|
|
174
|
+
normCmdline
|
|
175
|
+
};
|
|
172
176
|
}
|
|
173
177
|
});
|
|
174
178
|
|
|
175
|
-
// src/platform/
|
|
176
|
-
var
|
|
177
|
-
"src/platform/
|
|
179
|
+
// src/platform/os/exec-path.js
|
|
180
|
+
var require_exec_path = __commonJS({
|
|
181
|
+
"src/platform/os/exec-path.js"(exports2, module2) {
|
|
178
182
|
"use strict";
|
|
179
|
-
var
|
|
183
|
+
var fs2 = require("node:fs");
|
|
180
184
|
var path2 = require("node:path");
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if (!ext || typeof ext !== "object") return NO_EXTENSION;
|
|
191
|
-
return {
|
|
192
|
-
defaults: Array.isArray(ext.defaults) ? ext.defaults : [],
|
|
193
|
-
aliases: Array.isArray(ext.aliases) ? ext.aliases : []
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
var BASE_DEFAULTS = {
|
|
197
|
-
probeIntervalMs: 5e3,
|
|
198
|
-
// 健康探测三层:L0 进程存活 + L1 端口监听 + L2 HTTP GET healthUrl。probeTimeoutMs = 单次探测超时;
|
|
199
|
-
// failThreshold = 连续失败判故障(防抖动);httpProbeEnabled=false 退化为端口在线即健康。
|
|
200
|
-
probeTimeoutMs: 3e3,
|
|
201
|
-
failThreshold: 2,
|
|
202
|
-
httpProbeEnabled: true,
|
|
203
|
-
startTimeoutMs: 3e4,
|
|
204
|
-
stopGraceMs: 1e4,
|
|
205
|
-
portReleaseWaitMs: 1e4,
|
|
206
|
-
crashWindowMs: 6e5,
|
|
207
|
-
crashBurst: 5,
|
|
208
|
-
backoff: [3e4, 6e4, 12e4, 3e5, 6e5],
|
|
209
|
-
apiHost: "127.0.0.1",
|
|
210
|
-
// API 端口:高位不常用段起始(常用端口段易冲突);守卫启动被占则自动顺延并持久化。
|
|
211
|
-
apiPort: 36360,
|
|
212
|
-
// 注意:daemon 控制通道端口属业务域知识,经注入声明提供(同上),原键名与值逐字保留。
|
|
213
|
-
// 动态端口池(范围是配置项,非编译期常量):null = 内置默认池,默认避开 OS 动态端口范围
|
|
214
|
-
// (Linux ip_local_port_range=32768-60999),落在 IANA User 段低位。额外池由域装配期申报(DS-G4)。
|
|
215
|
-
portPools: null,
|
|
216
|
-
stateFile: path2.join(SUP, "state.json"),
|
|
217
|
-
// 日志目录布局:事件在 events/guard.events.log,分级日志在 log/;显式配置的路径尊重用户给定值,不强改。
|
|
218
|
-
logFile: path2.join(SUP, "events", "guard.events.log"),
|
|
219
|
-
eventsMaxBytes: 5 * 1024 * 1024,
|
|
220
|
-
supervisorLogFile: path2.join(SUP, "log", "guard.log"),
|
|
221
|
-
dshLogFile: path2.join(SUP, "log", "dsh.log"),
|
|
222
|
-
upgradeLogFile: path2.join(SUP, "log", "upgrade.log"),
|
|
223
|
-
logLevel: "info",
|
|
224
|
-
logMaxBytes: 5 * 1024 * 1024,
|
|
225
|
-
notifyEnabled: true,
|
|
226
|
-
// 内核更新单写入者 = 桌面壳:corePackageName 仅为内核自身 npm 子包名,守卫只读它查版本状态,
|
|
227
|
-
// 安装/升级由壳执行。不得再引入 manifest 更新通道(残留键已删,config.json 中未知键加载时忽略)。
|
|
228
|
-
corePackageName: null,
|
|
229
|
-
pluginsProfileName: "web",
|
|
230
|
-
packageName: "@deepseek-ai/dsh",
|
|
231
|
-
// 灰度名单(RELEASE-CHANNEL-CONTRACT):本机 canary:true 即灰度机,仅对内核包生效,对第三方包
|
|
232
|
-
// (packageName)无效;未置真即非灰度。
|
|
233
|
-
canary: false,
|
|
234
|
-
// 最小兜底镜像源(不变量 C2):完整目录归壳管理,经 <产品状态根>/supervisor/registry.json 投放,
|
|
235
|
-
// 内核由 platform/distribution 读取(契约见 platform/contract/registry.js);
|
|
236
|
-
// 此处官方源 + npmmirror 两条兜底,保证契约不可用时仍可安装。
|
|
237
|
-
registries: [
|
|
238
|
-
"https://registry.npmjs.org",
|
|
239
|
-
"https://registry.npmmirror.com"
|
|
240
|
-
],
|
|
241
|
-
updateCheckEnabled: true,
|
|
242
|
-
updateCheckIntervalMs: 36e5,
|
|
243
|
-
initialCheckDelayMs: 2e4,
|
|
244
|
-
upgradeTimeoutMs: 6e5,
|
|
245
|
-
installCommandTemplate: ["npm", "install", "-g", "{pkg}@{version}"],
|
|
246
|
-
// apiAccessKey(可选)出回环访问密钥:配置后,0.0.0.0(局域网)与 FRP 公网通道的 API 请求必须携带
|
|
247
|
-
// Authorization: Bearer <key> 或 ?access_key=<key>,否则 401;回环豁免。
|
|
248
|
-
// 不配置 = LAN 受 RFC1918 白名单约束,FRP 暴露仍强制 remoteToken。
|
|
249
|
-
apiAccessKey: null,
|
|
250
|
-
// 关闭窗口行为(系统级):'hide' = 隐藏至托盘、服务常驻(默认);'exit' = 退出管家并停全部服务链。
|
|
251
|
-
closeAction: "hide"
|
|
252
|
-
};
|
|
253
|
-
function buildDefaults2(ext) {
|
|
254
|
-
const pending = normalizeExtension(ext).defaults.slice();
|
|
255
|
-
const out = {};
|
|
256
|
-
for (const key of Object.keys(BASE_DEFAULTS)) {
|
|
257
|
-
for (let i = pending.length - 1; i >= 0; i--) {
|
|
258
|
-
const g = pending[i];
|
|
259
|
-
if (g && g.at === key) {
|
|
260
|
-
if (g.values && typeof g.values === "object") Object.assign(out, g.values);
|
|
261
|
-
pending.splice(i, 1);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
out[key] = BASE_DEFAULTS[key];
|
|
265
|
-
}
|
|
266
|
-
for (const g of pending) {
|
|
267
|
-
if (g && g.values && typeof g.values === "object") Object.assign(out, g.values);
|
|
185
|
+
var os2 = require("node:os");
|
|
186
|
+
function candidateNames(base, platform) {
|
|
187
|
+
const win = (platform || process.platform) === "win32";
|
|
188
|
+
if (!win) return [base];
|
|
189
|
+
const exts = String(process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
|
|
190
|
+
const names = [base + ".exe", base + ".cmd", base + ".bat"];
|
|
191
|
+
for (const e of exts) {
|
|
192
|
+
const n = base + e.toLowerCase();
|
|
193
|
+
if (!names.some((x) => x.toLowerCase() === n)) names.push(n);
|
|
268
194
|
}
|
|
269
|
-
|
|
195
|
+
names.push(base);
|
|
196
|
+
return [...new Set(names)];
|
|
270
197
|
}
|
|
271
|
-
|
|
272
|
-
function normalize(raw, ext) {
|
|
273
|
-
const extension = normalizeExtension(ext);
|
|
274
|
-
const provided = raw || {};
|
|
275
|
-
const cfg = Object.assign(buildDefaults2(extension), provided);
|
|
276
|
-
cfg.stateFile = expandHome(cfg.stateFile);
|
|
277
|
-
cfg.logFile = expandHome(cfg.logFile);
|
|
278
|
-
cfg.supervisorLogFile = expandHome(cfg.supervisorLogFile);
|
|
279
|
-
cfg.dshLogFile = expandHome(cfg.dshLogFile);
|
|
280
|
-
cfg.upgradeLogFile = expandHome(cfg.upgradeLogFile);
|
|
281
|
-
let u;
|
|
198
|
+
function isExecutableFile(p, platform) {
|
|
282
199
|
try {
|
|
283
|
-
|
|
200
|
+
if (!fs2.statSync(p).isFile()) return false;
|
|
201
|
+
if ((platform || process.platform) === "win32") return true;
|
|
202
|
+
fs2.accessSync(p, fs2.constants.X_OK);
|
|
203
|
+
return true;
|
|
284
204
|
} catch {
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
cfg.targetHost = u.hostname;
|
|
288
|
-
cfg.targetPort = Number(u.port || (u.protocol === "https:" ? 443 : 80));
|
|
289
|
-
for (const [from, to] of extension.aliases) {
|
|
290
|
-
if (provided[to] === void 0 && provided[from] !== void 0) cfg[to] = provided[from] === true;
|
|
291
|
-
}
|
|
292
|
-
const cmdPort = extractPortFromCommand(cfg.command);
|
|
293
|
-
if (cmdPort !== null) cfg.targetPort = cmdPort;
|
|
294
|
-
cfg.probeTimeoutMs = Number.isFinite(Number(cfg.probeTimeoutMs)) && Number(cfg.probeTimeoutMs) > 0 ? Number(cfg.probeTimeoutMs) : 3e3;
|
|
295
|
-
cfg.failThreshold = Number.isInteger(Number(cfg.failThreshold)) && Number(cfg.failThreshold) >= 1 ? Number(cfg.failThreshold) : 2;
|
|
296
|
-
cfg.httpProbeEnabled = cfg.httpProbeEnabled !== false;
|
|
297
|
-
if (!Array.isArray(cfg.command) || cfg.command.length === 0) {
|
|
298
|
-
throw new Error("config.command \u7F3A\u5931\uFF1A\u9700\u8981\u4E00\u4E2A\u547D\u4EE4\u6570\u7EC4");
|
|
205
|
+
return false;
|
|
299
206
|
}
|
|
300
|
-
return cfg;
|
|
301
207
|
}
|
|
302
|
-
function
|
|
303
|
-
if (!
|
|
304
|
-
for (
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
const m = /^--port=(\d+)$/.exec(a);
|
|
311
|
-
if (m) {
|
|
312
|
-
const n = Number(m[1]);
|
|
313
|
-
if (Number.isInteger(n) && n > 0 && n <= 65535) return n;
|
|
208
|
+
function firstExecutable(dir, base, platform) {
|
|
209
|
+
if (!dir) return null;
|
|
210
|
+
for (const name of candidateNames(base, platform)) {
|
|
211
|
+
const p = path2.join(dir, name);
|
|
212
|
+
try {
|
|
213
|
+
if (isExecutableFile(p, platform)) return p;
|
|
214
|
+
} catch {
|
|
314
215
|
}
|
|
315
216
|
}
|
|
316
217
|
return null;
|
|
317
218
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
{
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
routerCtlPort: 43107,
|
|
334
|
-
lanCtlPort: 43108
|
|
335
|
-
}
|
|
336
|
-
},
|
|
337
|
-
{
|
|
338
|
-
at: "corePackageName",
|
|
339
|
-
// 智能路由启动开关。
|
|
340
|
-
values: {
|
|
341
|
-
routerAutostart: false
|
|
219
|
+
function standardDirs(platform, home, env) {
|
|
220
|
+
const pl = platform || process.platform;
|
|
221
|
+
const h = home || os2.homedir();
|
|
222
|
+
const e = env || process.env;
|
|
223
|
+
const dirs = [];
|
|
224
|
+
if (pl === "win32") {
|
|
225
|
+
if (e.APPDATA) dirs.push(path2.join(e.APPDATA, "npm"));
|
|
226
|
+
if (e.LOCALAPPDATA) dirs.push(path2.join(e.LOCALAPPDATA, "Programs", "dsh-supervisor"));
|
|
227
|
+
dirs.push(path2.join(h, ".local", "bin"));
|
|
228
|
+
} else {
|
|
229
|
+
dirs.push(path2.join(h, ".local", "bin"));
|
|
230
|
+
dirs.push(path2.join(h, ".npm-global", "bin"));
|
|
231
|
+
if (pl === "darwin") {
|
|
232
|
+
dirs.push("/opt/homebrew/bin");
|
|
233
|
+
dirs.push("/usr/local/bin");
|
|
342
234
|
}
|
|
343
235
|
}
|
|
344
|
-
|
|
345
|
-
var aliases = [
|
|
346
|
-
["switcherAutoStart", "routerAutostart"]
|
|
347
|
-
];
|
|
348
|
-
function extension() {
|
|
349
|
-
return {
|
|
350
|
-
defaults: defaults.map((g) => ({ at: g.at, values: Object.assign({}, g.values) })),
|
|
351
|
-
aliases: aliases.map((a) => a.slice())
|
|
352
|
-
};
|
|
236
|
+
return dirs;
|
|
353
237
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
"use strict";
|
|
362
|
-
var fs2 = require("node:fs");
|
|
363
|
-
var path2 = require("node:path");
|
|
364
|
-
function guardVersion() {
|
|
365
|
-
if (true) return String("0.1.6-BETA.2");
|
|
366
|
-
try {
|
|
367
|
-
return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
|
|
368
|
-
} catch {
|
|
369
|
-
return "unknown";
|
|
238
|
+
function inPath(base, platform, env) {
|
|
239
|
+
const e = env || process.env;
|
|
240
|
+
const raw = e.PATH || e.Path || "";
|
|
241
|
+
for (const d of raw.split(path2.delimiter)) {
|
|
242
|
+
if (!d) continue;
|
|
243
|
+
const hit = firstExecutable(d, base, platform);
|
|
244
|
+
if (hit) return hit;
|
|
370
245
|
}
|
|
246
|
+
return null;
|
|
371
247
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
const
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
248
|
+
function resolveExecutable(base, opts) {
|
|
249
|
+
const o = opts || {};
|
|
250
|
+
const pl = o.platform;
|
|
251
|
+
const env = o.env;
|
|
252
|
+
const E = env || process.env;
|
|
253
|
+
if (o.envVar && E[o.envVar]) {
|
|
254
|
+
const v = E[o.envVar];
|
|
255
|
+
if (isExecutableFile(v, pl)) return v;
|
|
256
|
+
}
|
|
257
|
+
const inPathHit = inPath(base, pl, env);
|
|
258
|
+
if (inPathHit) return inPathHit;
|
|
259
|
+
for (const d of [...o.extraDirs || [], ...standardDirs(pl, void 0, env)]) {
|
|
260
|
+
const hit = firstExecutable(d, base, pl);
|
|
261
|
+
if (hit) return hit;
|
|
262
|
+
}
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
function npxBin(opts) {
|
|
266
|
+
const o = opts || {};
|
|
267
|
+
const pl = o.platform || process.platform;
|
|
268
|
+
const env = o.env || process.env;
|
|
269
|
+
if (pl !== "win32") return "npx";
|
|
270
|
+
const resolved = resolveExecutable("npx", { platform: pl, env, extraDirs: [
|
|
271
|
+
env.APPDATA ? path2.join(env.APPDATA, "npm") : null
|
|
272
|
+
].filter(Boolean) });
|
|
273
|
+
if (resolved) return resolved;
|
|
274
|
+
return "npx.cmd";
|
|
275
|
+
}
|
|
276
|
+
function npmBin(opts) {
|
|
277
|
+
const o = opts || {};
|
|
278
|
+
const pl = o.platform || process.platform;
|
|
279
|
+
const env = o.env || process.env;
|
|
280
|
+
if (pl !== "win32") return "npm";
|
|
281
|
+
const resolved = resolveExecutable("npm", { platform: pl, env, extraDirs: [
|
|
282
|
+
env.APPDATA ? path2.join(env.APPDATA, "npm") : null
|
|
283
|
+
].filter(Boolean) });
|
|
284
|
+
if (resolved) return resolved;
|
|
285
|
+
return "npm.cmd";
|
|
286
|
+
}
|
|
287
|
+
var DSH_PKG = ["@deepseek-ai", "dsh"];
|
|
288
|
+
function dshJsIn(prefix) {
|
|
289
|
+
return path2.join(prefix, "node_modules", ...DSH_PKG, "lib", "bin.js");
|
|
290
|
+
}
|
|
291
|
+
function resolveDsh(opts) {
|
|
292
|
+
const o = opts || {};
|
|
293
|
+
const pl = o.platform || process.platform;
|
|
294
|
+
const env = o.env || process.env;
|
|
295
|
+
const isFile = (p) => {
|
|
388
296
|
try {
|
|
389
|
-
return
|
|
297
|
+
return fs2.statSync(p).isFile();
|
|
390
298
|
} catch {
|
|
391
|
-
return
|
|
299
|
+
return false;
|
|
392
300
|
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
desired: "running",
|
|
401
|
-
guardian: true,
|
|
402
|
-
ownership: { ports: [], rootPath: null, unit: null, daemonScript: null, processMode: "spawn", meta: null },
|
|
403
|
-
phase: "stopped",
|
|
404
|
-
lastObserved: null,
|
|
405
|
-
backoffLevel: 0,
|
|
406
|
-
backoffUntil: null,
|
|
407
|
-
crashWindowStart: null,
|
|
408
|
-
crashWindowRestarts: 0,
|
|
409
|
-
restartCount: 0,
|
|
410
|
-
startedAt: null,
|
|
411
|
-
lastTransitionAt: null,
|
|
412
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
413
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
414
|
-
process: null
|
|
415
|
-
};
|
|
301
|
+
};
|
|
302
|
+
const asJs = (bin, launcher) => ({ runtime: process.execPath, bin, isJs: true, launcher: launcher || null });
|
|
303
|
+
if (env.DSH_BIN) {
|
|
304
|
+
try {
|
|
305
|
+
const r = fs2.realpathSync(env.DSH_BIN);
|
|
306
|
+
if (isFile(r)) return asJs(r, env.DSH_BIN);
|
|
307
|
+
} catch {
|
|
416
308
|
}
|
|
417
|
-
return fallback;
|
|
418
309
|
}
|
|
419
|
-
|
|
420
|
-
|
|
310
|
+
const hit = resolveExecutable("dsh", { platform: pl, env });
|
|
311
|
+
if (hit) {
|
|
421
312
|
try {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
} catch
|
|
425
|
-
const l = logger();
|
|
426
|
-
if (l && l.warn) l.warn("persistCrashField: " + (e && e.message || e));
|
|
313
|
+
const real = fs2.realpathSync(hit);
|
|
314
|
+
if (isFile(real) && /\.(js|cjs|mjs)$/i.test(real)) return asJs(real, hit);
|
|
315
|
+
} catch {
|
|
427
316
|
}
|
|
317
|
+
const js = dshJsIn(path2.dirname(hit));
|
|
318
|
+
if (isFile(js)) return asJs(js, hit);
|
|
319
|
+
if (isFile(hit) && !/\.(cmd|bat|exe)$/i.test(hit)) return asJs(hit, hit);
|
|
320
|
+
return { runtime: null, bin: hit, isJs: false, launcher: hit };
|
|
428
321
|
}
|
|
429
|
-
|
|
430
|
-
|
|
322
|
+
if (o.npmRoot) {
|
|
323
|
+
const js = dshJsIn(o.npmRoot);
|
|
324
|
+
if (isFile(js)) return asJs(js, null);
|
|
431
325
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
function knownDshEntries(opts) {
|
|
329
|
+
const o = opts || {};
|
|
330
|
+
const out = [];
|
|
331
|
+
try {
|
|
332
|
+
const r = resolveDsh(o);
|
|
333
|
+
if (r) {
|
|
334
|
+
if (typeof r.bin === "string" && r.bin) out.push(r.bin);
|
|
335
|
+
if (typeof r.launcher === "string" && r.launcher) out.push(r.launcher);
|
|
440
336
|
}
|
|
441
|
-
|
|
337
|
+
} catch {
|
|
442
338
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
p = e.process = {
|
|
448
|
-
child: null,
|
|
449
|
-
adoptedPid: null,
|
|
450
|
-
adopted: false,
|
|
451
|
-
observedOnly: false,
|
|
452
|
-
startDeadline: null,
|
|
453
|
-
restartAt: null,
|
|
454
|
-
spawnBlockedUntil: null,
|
|
455
|
-
missingNotified: false,
|
|
456
|
-
failStreak: 0,
|
|
457
|
-
lastProbeAt: null,
|
|
458
|
-
lastProbeOk: null,
|
|
459
|
-
lastProbeHttpOk: null,
|
|
460
|
-
lastFailure: null,
|
|
461
|
-
lastRestartAt: null
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
if (write) {
|
|
465
|
-
if (p[name] !== v) p[name] = v;
|
|
466
|
-
return p;
|
|
339
|
+
if (o.npmRoot) {
|
|
340
|
+
try {
|
|
341
|
+
out.push(dshJsIn(o.npmRoot));
|
|
342
|
+
} catch {
|
|
467
343
|
}
|
|
468
|
-
return p[name];
|
|
469
344
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
345
|
+
if (typeof o.dshBin === "string" && /^(?:[A-Za-z]:[\\/]|[\\/])/.test(o.dshBin)) out.push(o.dshBin);
|
|
346
|
+
return [...new Set(out.filter((x) => typeof x === "string" && x))];
|
|
347
|
+
}
|
|
348
|
+
function commandEntryViolation(cmdArr, opts) {
|
|
349
|
+
const o = opts || {};
|
|
350
|
+
const rp = o.realpath || ((p) => fs2.realpathSync(p));
|
|
351
|
+
if (!Array.isArray(cmdArr) || !cmdArr.length) return null;
|
|
352
|
+
const head = String(cmdArr[0] || "");
|
|
353
|
+
const NODE_HEAD = /* @__PURE__ */ new Set(["node", "node.exe"]);
|
|
354
|
+
const baseOf = (p) => String(p).split(/[\\/]/).pop().toLowerCase();
|
|
355
|
+
let entry = head;
|
|
356
|
+
const nodeHead = NODE_HEAD.has(baseOf(head));
|
|
357
|
+
if (nodeHead) {
|
|
358
|
+
if (cmdArr.length < 2) return "\u542F\u52A8\u547D\u4EE4\u4EE5 node \u6253\u5934\u4F46\u7F3A\u5C11 DSH \u5165\u53E3\u53C2\u6570";
|
|
359
|
+
entry = String(cmdArr[1] || "");
|
|
360
|
+
}
|
|
361
|
+
if (!entry) return "\u542F\u52A8\u547D\u4EE4\u7F3A\u5C11 DSH \u5165\u53E3";
|
|
362
|
+
const isAbsolute = (p) => /^(?:[A-Za-z]:[\\/]|[\\/])/.test(String(p));
|
|
363
|
+
const hasSep = (p) => /[\\/]/.test(String(p));
|
|
364
|
+
if (!hasSep(entry)) {
|
|
365
|
+
if (nodeHead && o.requireAbsoluteEntry) {
|
|
366
|
+
return "command[0] \u4E3A node \u65F6 command[1] \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u7684 DSH \u5165\u53E3\uFF08\u76F8\u5BF9/\u88F8\u540D\u4F1A\u6309\u5DE5\u4F5C\u76EE\u5F55\u6216 PATH \u89E3\u6790\uFF09";
|
|
367
|
+
}
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
if (!isAbsolute(entry)) {
|
|
371
|
+
return "DSH \u5165\u53E3\u4E0D\u63A5\u53D7\u76F8\u5BF9\u8DEF\u5F84\uFF08\u4F1A\u6309\u8C03\u7528\u65B9\u5DE5\u4F5C\u76EE\u5F55\u89E3\u6790\uFF1B\u6C99\u7BB1\u5B9E\u4F8B\u7684\u8BE5\u76EE\u5F55\u6C99\u7BB1\u5185\u53EF\u5199\uFF09";
|
|
372
|
+
}
|
|
373
|
+
let real = null;
|
|
374
|
+
try {
|
|
375
|
+
real = rp(entry);
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
if (typeof o.allowEntry === "function") {
|
|
379
|
+
try {
|
|
380
|
+
if (o.allowEntry(entry, real)) return null;
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
if (real === null) return "DSH \u5165\u53E3\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u89E3\u6790\uFF08fail-closed\uFF09\uFF1A" + entry;
|
|
385
|
+
for (const f of Array.isArray(o.files) ? o.files : []) {
|
|
386
|
+
try {
|
|
387
|
+
if (rp(f) === real) return null;
|
|
388
|
+
} catch {
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
for (const r of Array.isArray(o.roots) ? o.roots : []) {
|
|
392
|
+
let rr;
|
|
393
|
+
try {
|
|
394
|
+
rr = rp(r);
|
|
395
|
+
} catch {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
const base = String(rr).replace(/[\\/]+$/, "");
|
|
399
|
+
if (real === base || real.indexOf(base + path2.sep) === 0) return null;
|
|
400
|
+
}
|
|
401
|
+
return "DSH \u5165\u53E3\u4E0D\u5728\u5141\u8BB8\u4F4D\u7F6E\uFF08\u987B\u4E3A\u8BE5\u5B9E\u4F8B\u5B89\u88C5\u6839\u4E4B\u4E0B\u7684\u5165\u53E3\uFF0C\u6216\u5185\u6838\u89E3\u6790\u51FA\u7684\u5DF2\u77E5 DSH \u5165\u53E3\uFF09\uFF1A" + entry;
|
|
402
|
+
}
|
|
403
|
+
module2.exports = {
|
|
404
|
+
resolveExecutable,
|
|
405
|
+
candidateNames,
|
|
406
|
+
standardDirs,
|
|
407
|
+
npmBin,
|
|
408
|
+
npxBin,
|
|
409
|
+
resolveDsh,
|
|
410
|
+
dshJsIn,
|
|
411
|
+
knownDshEntries,
|
|
412
|
+
commandEntryViolation,
|
|
413
|
+
isExecutableFile
|
|
414
|
+
};
|
|
473
415
|
}
|
|
474
416
|
});
|
|
475
417
|
|
|
476
|
-
// src/platform/
|
|
477
|
-
var
|
|
478
|
-
"src/platform/
|
|
418
|
+
// src/platform/os/pidlookup/probe.js
|
|
419
|
+
var require_probe = __commonJS({
|
|
420
|
+
"src/platform/os/pidlookup/probe.js"(exports2, module2) {
|
|
479
421
|
"use strict";
|
|
480
422
|
var fs2 = require("node:fs");
|
|
481
|
-
var
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
423
|
+
var ex2 = require_exec();
|
|
424
|
+
var { isExecutableFile } = require_exec_path();
|
|
425
|
+
var {
|
|
426
|
+
parseProcNetTcpInodes,
|
|
427
|
+
parseLsofPid,
|
|
428
|
+
parseNetstatPid,
|
|
429
|
+
parseSsPid,
|
|
430
|
+
parseWmicCommandLine,
|
|
431
|
+
parsePowerShellCommandLine
|
|
432
|
+
} = require_norm();
|
|
433
|
+
var isLinux = process.platform === "linux";
|
|
434
|
+
var isMac = process.platform === "darwin";
|
|
435
|
+
var isWindows = process.platform === "win32";
|
|
436
|
+
function linuxListeningInodes(port) {
|
|
437
|
+
const inodes = /* @__PURE__ */ new Set();
|
|
438
|
+
for (const f of ["/proc/net/tcp", "/proc/net/tcp6"]) {
|
|
439
|
+
let txt = "";
|
|
489
440
|
try {
|
|
490
|
-
|
|
441
|
+
txt = fs2.readFileSync(f, "utf8");
|
|
491
442
|
} catch {
|
|
492
|
-
|
|
443
|
+
continue;
|
|
493
444
|
}
|
|
494
|
-
for (const
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
445
|
+
for (const x of parseProcNetTcpInodes(txt, port)) inodes.add(x);
|
|
446
|
+
}
|
|
447
|
+
return inodes;
|
|
448
|
+
}
|
|
449
|
+
function linuxFind(port) {
|
|
450
|
+
try {
|
|
451
|
+
const inodes = linuxListeningInodes(port);
|
|
452
|
+
if (!inodes.size) return null;
|
|
453
|
+
const entries = fs2.readdirSync("/proc").filter((e) => /^\d+$/.test(e));
|
|
454
|
+
for (const pid of entries) {
|
|
455
|
+
let fds;
|
|
456
|
+
try {
|
|
457
|
+
fds = fs2.readdirSync("/proc/" + pid + "/fd");
|
|
458
|
+
} catch {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
for (const fd of fds) {
|
|
462
|
+
let link;
|
|
500
463
|
try {
|
|
501
|
-
|
|
502
|
-
total += st.size;
|
|
464
|
+
link = fs2.readlinkSync("/proc/" + pid + "/fd/" + fd);
|
|
503
465
|
} catch {
|
|
466
|
+
continue;
|
|
504
467
|
}
|
|
468
|
+
if (inodes.has(link)) return Number(pid);
|
|
505
469
|
}
|
|
506
|
-
seen++;
|
|
507
470
|
}
|
|
508
|
-
}
|
|
471
|
+
} catch {
|
|
472
|
+
}
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
function macFind(port) {
|
|
509
476
|
try {
|
|
510
|
-
|
|
477
|
+
const out = ex2.runOut("lsof", ["-nP", "-iTCP:" + port, "-sTCP:LISTEN"], { timeoutMs: 3e3 });
|
|
478
|
+
if (!out) return null;
|
|
479
|
+
return parseLsofPid(out);
|
|
511
480
|
} catch {
|
|
512
481
|
}
|
|
513
|
-
return
|
|
482
|
+
return null;
|
|
514
483
|
}
|
|
515
|
-
function
|
|
516
|
-
const mode = opts && typeof opts.mode === "number" ? opts.mode : 384;
|
|
517
|
-
const fp = path2.resolve(file);
|
|
518
|
-
const dir = path2.dirname(fp);
|
|
519
|
-
const tmp = fp + ".tmp." + process.pid + "." + Date.now();
|
|
484
|
+
function winFind(port) {
|
|
520
485
|
try {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
486
|
+
const out = ex2.runOut("netstat", ["-ano"], { timeoutMs: 3e3 });
|
|
487
|
+
if (!out) return null;
|
|
488
|
+
return parseNetstatPid(out, port);
|
|
489
|
+
} catch {
|
|
490
|
+
}
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
function linuxFindSs(port) {
|
|
494
|
+
const candidates = ["ss", "/usr/sbin/ss", "/usr/bin/ss", "/bin/ss"];
|
|
495
|
+
for (const ssBin of candidates) {
|
|
496
|
+
if (ssBin.includes("/") && !isExecutableFile(ssBin)) continue;
|
|
528
497
|
try {
|
|
529
|
-
|
|
498
|
+
const out = ex2.runOut(ssBin, ["-tlnHp", "sport = :" + port], { timeoutMs: 3e3 });
|
|
499
|
+
const pid = parseSsPid(out);
|
|
500
|
+
if (pid !== null) return pid;
|
|
530
501
|
} catch {
|
|
531
502
|
}
|
|
532
|
-
|
|
503
|
+
}
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
function isAlive(pid) {
|
|
507
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
508
|
+
try {
|
|
509
|
+
process.kill(pid, 0);
|
|
510
|
+
return true;
|
|
533
511
|
} catch (e) {
|
|
512
|
+
return !!e && e.code === "EPERM";
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
function isZombie(pid) {
|
|
516
|
+
if (!Number.isInteger(pid) || pid <= 0 || isWindows) return false;
|
|
517
|
+
if (isLinux) {
|
|
534
518
|
try {
|
|
535
|
-
|
|
519
|
+
const st = fs2.readFileSync("/proc/" + pid + "/stat", "utf8");
|
|
520
|
+
const idx = st.lastIndexOf(") ");
|
|
521
|
+
return idx >= 0 && st[idx + 2] === "Z";
|
|
536
522
|
} catch {
|
|
523
|
+
return false;
|
|
537
524
|
}
|
|
538
|
-
|
|
525
|
+
}
|
|
526
|
+
try {
|
|
527
|
+
const o = ex2.runOut("ps", ["-o", "state=", "-p", String(pid)], { timeoutMs: 3e3 });
|
|
528
|
+
return !!o && /^Z/.test(o.trim());
|
|
529
|
+
} catch {
|
|
530
|
+
return false;
|
|
539
531
|
}
|
|
540
532
|
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
// src/app/state/main-store.js
|
|
546
|
-
var require_main_store = __commonJS({
|
|
547
|
-
"src/app/state/main-store.js"(exports2, module2) {
|
|
548
|
-
"use strict";
|
|
549
|
-
var fs2 = require("node:fs");
|
|
550
|
-
var path2 = require("node:path");
|
|
551
|
-
var { writeAtomic } = require_fs();
|
|
552
|
-
function createMainStore(deps) {
|
|
553
|
-
const g = deps || {};
|
|
554
|
-
const config = () => typeof g.getConfig === "function" ? g.getConfig() || {} : {};
|
|
555
|
-
const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
|
|
556
|
-
let live = null;
|
|
557
|
-
let corrupt = false;
|
|
558
|
-
function dshMainFile() {
|
|
533
|
+
function readCmdline2(pid) {
|
|
534
|
+
if (isLinux) {
|
|
559
535
|
try {
|
|
560
|
-
|
|
536
|
+
const buf = fs2.readFileSync("/proc/" + pid + "/cmdline");
|
|
537
|
+
return buf.toString("utf8").replace(/\0/g, " ").trim();
|
|
561
538
|
} catch {
|
|
562
539
|
return null;
|
|
563
540
|
}
|
|
564
541
|
}
|
|
565
|
-
|
|
542
|
+
if (isMac) {
|
|
566
543
|
try {
|
|
567
|
-
const
|
|
568
|
-
return
|
|
544
|
+
const o = ex2.runOut("ps", ["-o", "command=", "-p", String(pid)], { timeoutMs: 3e3 });
|
|
545
|
+
return o ? o.trim() || null : null;
|
|
569
546
|
} catch {
|
|
570
|
-
return
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
function readDshMainFile() {
|
|
574
|
-
try {
|
|
575
|
-
const f = dshMainFile();
|
|
576
|
-
if (f && fs2.existsSync(f)) {
|
|
577
|
-
const j = JSON.parse(fs2.readFileSync(f, "utf8"));
|
|
578
|
-
corrupt = false;
|
|
579
|
-
return {
|
|
580
|
-
guardian: j.guardian === true,
|
|
581
|
-
remoteMode: legacyRemoteMode(j),
|
|
582
|
-
remoteToken: String(j.remoteToken || "")
|
|
583
|
-
};
|
|
584
|
-
}
|
|
585
|
-
} catch (e) {
|
|
586
|
-
corrupt = true;
|
|
587
|
-
const l = logger();
|
|
588
|
-
if (l && l.warn) l.warn("dsh-main.json \u8BFB/\u89E3\u6790\u5931\u8D25\uFF0C\u5199\u56DE\u5C06\u88AB\u62D2\u7EDD\u76F4\u81F3\u663E\u5F0F\u91CD\u8BBE remoteToken: " + (e && e.message || e));
|
|
547
|
+
return null;
|
|
589
548
|
}
|
|
590
|
-
return { guardian: false, remoteMode: "off", remoteToken: "" };
|
|
591
549
|
}
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
if (
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
return live;
|
|
550
|
+
if (isWindows) {
|
|
551
|
+
const out = ex2.runOut("wmic", ["process", "where", "ProcessId=" + pid, "get", "CommandLine", "/value"], { timeoutMs: 5e3 });
|
|
552
|
+
const viaWmic = parseWmicCommandLine(out);
|
|
553
|
+
if (viaWmic) return viaWmic;
|
|
554
|
+
{
|
|
555
|
+
const ps = "(Get-CimInstance Win32_Process -Filter 'ProcessId=" + pid + "').CommandLine";
|
|
556
|
+
const o = ex2.runOut("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { timeoutMs: 5e3 });
|
|
557
|
+
return parsePowerShellCommandLine(o);
|
|
558
|
+
}
|
|
602
559
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
function pgrepList(pattern) {
|
|
563
|
+
const out = [];
|
|
564
|
+
const readCmd = (pid) => readCmdline2(pid) || "";
|
|
565
|
+
try {
|
|
566
|
+
if (isMac) {
|
|
567
|
+
const pids = (ex2.runOut("pgrep", ["-f", String(pattern)], { timeoutMs: 3e3 }) || "").split(/\r?\n/);
|
|
568
|
+
for (const line of pids) {
|
|
569
|
+
const pid = parseInt(line.trim(), 10);
|
|
570
|
+
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
571
|
+
const cmd2 = readCmd(pid);
|
|
572
|
+
if (!cmd2) continue;
|
|
573
|
+
out.push({ pid, cmdline: cmd2 });
|
|
574
|
+
}
|
|
575
|
+
return out;
|
|
610
576
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
577
|
+
if (isWindows) {
|
|
578
|
+
const ps = "Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress";
|
|
579
|
+
const j = ex2.runOut("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { timeoutMs: 8e3 }) || "";
|
|
580
|
+
let arr = [];
|
|
581
|
+
try {
|
|
582
|
+
arr = JSON.parse(j);
|
|
583
|
+
if (!Array.isArray(arr)) arr = [arr];
|
|
584
|
+
} catch {
|
|
585
|
+
}
|
|
586
|
+
for (const it of arr) {
|
|
587
|
+
if (!it || !it.ProcessId) continue;
|
|
588
|
+
const pid = Number(it.ProcessId);
|
|
589
|
+
if (!Number.isInteger(pid) || pid <= 0) continue;
|
|
590
|
+
const cmd2 = String(it.CommandLine || "");
|
|
591
|
+
if (!cmd2.includes(pattern)) continue;
|
|
592
|
+
out.push({ pid, cmdline: cmd2 });
|
|
593
|
+
}
|
|
594
|
+
return out;
|
|
595
|
+
}
|
|
596
|
+
const res = ex2.runOut("pgrep", ["-af", String(pattern)], { timeoutMs: 3e3 }) || "";
|
|
597
|
+
for (const line of res.split(/\r?\n/)) {
|
|
598
|
+
const m = /^(\d+)\s+([\s\S]*)$/.exec(line.trim());
|
|
599
|
+
if (m) out.push({ pid: Number(m[1]), cmdline: m[2] });
|
|
629
600
|
}
|
|
601
|
+
} catch {
|
|
630
602
|
}
|
|
631
|
-
return
|
|
603
|
+
return out;
|
|
632
604
|
}
|
|
633
|
-
module2.exports = {
|
|
605
|
+
module2.exports = {
|
|
606
|
+
linuxListeningInodes,
|
|
607
|
+
linuxFind,
|
|
608
|
+
macFind,
|
|
609
|
+
winFind,
|
|
610
|
+
linuxFindSs,
|
|
611
|
+
readCmdline: readCmdline2,
|
|
612
|
+
pgrepList,
|
|
613
|
+
isAlive,
|
|
614
|
+
isZombie
|
|
615
|
+
};
|
|
634
616
|
}
|
|
635
617
|
});
|
|
636
618
|
|
|
637
|
-
// src/
|
|
638
|
-
var
|
|
639
|
-
"src/
|
|
619
|
+
// src/platform/os/pidlookup/index.js
|
|
620
|
+
var require_pidlookup = __commonJS({
|
|
621
|
+
"src/platform/os/pidlookup/index.js"(exports2, module2) {
|
|
640
622
|
"use strict";
|
|
641
|
-
var
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
623
|
+
var {
|
|
624
|
+
parseProcNetTcpInodes,
|
|
625
|
+
parseLsofPid,
|
|
626
|
+
parseNetstatPid,
|
|
627
|
+
parseSsPid,
|
|
628
|
+
parseWmicCommandLine,
|
|
629
|
+
parsePowerShellCommandLine,
|
|
630
|
+
normCmdline
|
|
631
|
+
} = require_norm();
|
|
632
|
+
var {
|
|
633
|
+
linuxFind,
|
|
634
|
+
linuxFindSs,
|
|
635
|
+
macFind,
|
|
636
|
+
winFind,
|
|
637
|
+
readCmdline: readCmdline2,
|
|
638
|
+
pgrepList,
|
|
639
|
+
isAlive,
|
|
640
|
+
isZombie
|
|
641
|
+
} = require_probe();
|
|
642
|
+
var isLinux = process.platform === "linux";
|
|
643
|
+
var isMac = process.platform === "darwin";
|
|
644
|
+
function findListeningPid(port) {
|
|
645
|
+
if (!Number.isInteger(port) || port <= 0) return null;
|
|
646
|
+
if (isLinux) {
|
|
647
|
+
const a = linuxFind(port);
|
|
648
|
+
if (a !== null && a !== void 0) return a;
|
|
649
|
+
return linuxFindSs(port);
|
|
650
|
+
}
|
|
651
|
+
if (isMac) return macFind(port);
|
|
652
|
+
return winFind(port);
|
|
653
|
+
}
|
|
654
|
+
function isDshCmdline(pid) {
|
|
655
|
+
const cmd2 = readCmdline2(pid);
|
|
656
|
+
if (!cmd2) return false;
|
|
657
|
+
return /(^|\s)(node|.*dsh.*)(\s|$)/i.test(cmd2) && /dsh/i.test(cmd2);
|
|
658
|
+
}
|
|
659
|
+
module2.exports = {
|
|
660
|
+
findListeningPid,
|
|
661
|
+
isAlive,
|
|
662
|
+
isZombie,
|
|
663
|
+
readCmdline: readCmdline2,
|
|
664
|
+
normCmdline,
|
|
665
|
+
isDshCmdline,
|
|
666
|
+
pgrepList,
|
|
667
|
+
parseProcNetTcpInodes,
|
|
668
|
+
parseLsofPid,
|
|
669
|
+
parseNetstatPid,
|
|
670
|
+
parseSsPid,
|
|
671
|
+
parseWmicCommandLine,
|
|
672
|
+
parsePowerShellCommandLine
|
|
673
|
+
};
|
|
667
674
|
}
|
|
668
675
|
});
|
|
669
676
|
|
|
670
|
-
// src/
|
|
671
|
-
var
|
|
672
|
-
"src/
|
|
677
|
+
// src/platform/service/state-root.js
|
|
678
|
+
var require_state_root = __commonJS({
|
|
679
|
+
"src/platform/service/state-root.js"(exports2, module2) {
|
|
673
680
|
"use strict";
|
|
674
|
-
|
|
675
|
-
|
|
681
|
+
var fs2 = require("node:fs");
|
|
682
|
+
var os2 = require("node:os");
|
|
683
|
+
var path2 = require("node:path");
|
|
684
|
+
var SCHEMA = 1;
|
|
685
|
+
function root() {
|
|
686
|
+
const override = process.env.DSH_SUPERVISOR_HOME;
|
|
687
|
+
if (override && String(override).trim()) return path2.resolve(String(override).trim());
|
|
688
|
+
if (process.platform === "win32") {
|
|
689
|
+
const local = process.env.LOCALAPPDATA || path2.join(os2.homedir(), "AppData", "Local");
|
|
690
|
+
return path2.join(local, "dsh-supervisor");
|
|
691
|
+
}
|
|
692
|
+
if (process.platform === "darwin") {
|
|
693
|
+
return path2.join(os2.homedir(), "Library", "Application Support", "dsh-supervisor");
|
|
694
|
+
}
|
|
695
|
+
const xdg = process.env.XDG_STATE_HOME;
|
|
696
|
+
return xdg && String(xdg).trim() ? path2.join(String(xdg).trim(), "dsh-supervisor") : path2.join(os2.homedir(), ".local", "state", "dsh-supervisor");
|
|
676
697
|
}
|
|
677
|
-
function
|
|
678
|
-
return
|
|
698
|
+
function supervisorDir() {
|
|
699
|
+
return path2.join(root(), "supervisor");
|
|
679
700
|
}
|
|
680
|
-
|
|
701
|
+
function shellDir() {
|
|
702
|
+
return path2.join(root(), "shell");
|
|
703
|
+
}
|
|
704
|
+
function legacySupervisorDir() {
|
|
705
|
+
return path2.join(os2.homedir(), ".dsh", "supervisor");
|
|
706
|
+
}
|
|
707
|
+
function legacyShellDir() {
|
|
708
|
+
return path2.join(os2.homedir(), ".dsh", "shell");
|
|
709
|
+
}
|
|
710
|
+
function migrateLegacy() {
|
|
711
|
+
const moved = [];
|
|
712
|
+
for (const [from, to] of [
|
|
713
|
+
[legacySupervisorDir(), supervisorDir()],
|
|
714
|
+
[legacyShellDir(), shellDir()]
|
|
715
|
+
]) {
|
|
716
|
+
try {
|
|
717
|
+
if (!fs2.existsSync(from)) continue;
|
|
718
|
+
fs2.mkdirSync(to, { recursive: true });
|
|
719
|
+
for (const name of fs2.readdirSync(from)) {
|
|
720
|
+
const src = path2.join(from, name);
|
|
721
|
+
const dst = path2.join(to, name);
|
|
722
|
+
if (fs2.existsSync(dst)) continue;
|
|
723
|
+
try {
|
|
724
|
+
fs2.renameSync(src, dst);
|
|
725
|
+
moved.push(src + " -> " + dst);
|
|
726
|
+
} catch {
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
try {
|
|
730
|
+
if (fs2.readdirSync(from).length === 0) fs2.rmdirSync(from);
|
|
731
|
+
} catch {
|
|
732
|
+
}
|
|
733
|
+
} catch {
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
return moved;
|
|
737
|
+
}
|
|
738
|
+
module2.exports = { SCHEMA, root, supervisorDir, shellDir, migrateLegacy };
|
|
681
739
|
}
|
|
682
740
|
});
|
|
683
741
|
|
|
684
|
-
// src/
|
|
685
|
-
var
|
|
686
|
-
"src/
|
|
742
|
+
// src/platform/service/config.js
|
|
743
|
+
var require_config = __commonJS({
|
|
744
|
+
"src/platform/service/config.js"(exports2, module2) {
|
|
687
745
|
"use strict";
|
|
688
|
-
var
|
|
689
|
-
var
|
|
690
|
-
function
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
746
|
+
var os2 = require("node:os");
|
|
747
|
+
var path2 = require("node:path");
|
|
748
|
+
function expandHome(p) {
|
|
749
|
+
if (typeof p !== "string") return p;
|
|
750
|
+
if (p === "~") return os2.homedir();
|
|
751
|
+
if (p.startsWith("~/")) return path2.join(os2.homedir(), p.slice(2));
|
|
752
|
+
return p;
|
|
753
|
+
}
|
|
754
|
+
var SUP = require_state_root().supervisorDir();
|
|
755
|
+
var NO_EXTENSION = Object.freeze({ defaults: [], aliases: [] });
|
|
756
|
+
function normalizeExtension(ext) {
|
|
757
|
+
if (!ext || typeof ext !== "object") return NO_EXTENSION;
|
|
758
|
+
return {
|
|
759
|
+
defaults: Array.isArray(ext.defaults) ? ext.defaults : [],
|
|
760
|
+
aliases: Array.isArray(ext.aliases) ? ext.aliases : []
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
var BASE_DEFAULTS = {
|
|
764
|
+
probeIntervalMs: 5e3,
|
|
765
|
+
// 健康探测三层:L0 进程存活 + L1 端口监听 + L2 HTTP GET healthUrl。probeTimeoutMs = 单次探测超时;
|
|
766
|
+
// failThreshold = 连续失败判故障(防抖动);httpProbeEnabled=false 退化为端口在线即健康。
|
|
767
|
+
probeTimeoutMs: 3e3,
|
|
768
|
+
failThreshold: 2,
|
|
769
|
+
httpProbeEnabled: true,
|
|
770
|
+
startTimeoutMs: 3e4,
|
|
771
|
+
stopGraceMs: 1e4,
|
|
772
|
+
portReleaseWaitMs: 1e4,
|
|
773
|
+
crashWindowMs: 6e5,
|
|
774
|
+
crashBurst: 5,
|
|
775
|
+
backoff: [3e4, 6e4, 12e4, 3e5, 6e5],
|
|
776
|
+
apiHost: "127.0.0.1",
|
|
777
|
+
// API 端口:高位不常用段起始(常用端口段易冲突);守卫启动被占则自动顺延并持久化。
|
|
778
|
+
apiPort: 36360,
|
|
779
|
+
// 注意:daemon 控制通道端口属业务域知识,经注入声明提供(同上),原键名与值逐字保留。
|
|
780
|
+
// 动态端口池(范围是配置项,非编译期常量):null = 内置默认池,默认避开 OS 动态端口范围
|
|
781
|
+
// (Linux ip_local_port_range=32768-60999),落在 IANA User 段低位。额外池由域装配期申报(DS-G4)。
|
|
782
|
+
portPools: null,
|
|
783
|
+
stateFile: path2.join(SUP, "state.json"),
|
|
784
|
+
// 日志目录布局:事件在 events/guard.events.log,分级日志在 log/;显式配置的路径尊重用户给定值,不强改。
|
|
785
|
+
logFile: path2.join(SUP, "events", "guard.events.log"),
|
|
786
|
+
eventsMaxBytes: 5 * 1024 * 1024,
|
|
787
|
+
supervisorLogFile: path2.join(SUP, "log", "guard.log"),
|
|
788
|
+
dshLogFile: path2.join(SUP, "log", "dsh.log"),
|
|
789
|
+
upgradeLogFile: path2.join(SUP, "log", "upgrade.log"),
|
|
790
|
+
logLevel: "info",
|
|
791
|
+
logMaxBytes: 5 * 1024 * 1024,
|
|
792
|
+
notifyEnabled: true,
|
|
793
|
+
// 内核更新单写入者 = 桌面壳:corePackageName 仅为内核自身 npm 子包名,守卫只读它查版本状态,
|
|
794
|
+
// 安装/升级由壳执行。不得再引入 manifest 更新通道(残留键已删,config.json 中未知键加载时忽略)。
|
|
795
|
+
corePackageName: null,
|
|
796
|
+
pluginsProfileName: "web",
|
|
797
|
+
packageName: "@deepseek-ai/dsh",
|
|
798
|
+
// 灰度名单(RELEASE-CHANNEL-CONTRACT):本机 canary:true 即灰度机,仅对内核包生效,对第三方包
|
|
799
|
+
// (packageName)无效;未置真即非灰度。
|
|
800
|
+
canary: false,
|
|
801
|
+
// 最小兜底镜像源(不变量 C2):完整目录归壳管理,经 <产品状态根>/supervisor/registry.json 投放,
|
|
802
|
+
// 内核由 platform/distribution 读取(契约见 platform/contract/registry.js);
|
|
803
|
+
// 此处官方源 + npmmirror 两条兜底,保证契约不可用时仍可安装。
|
|
804
|
+
registries: [
|
|
805
|
+
"https://registry.npmjs.org",
|
|
806
|
+
"https://registry.npmmirror.com"
|
|
807
|
+
],
|
|
808
|
+
updateCheckEnabled: true,
|
|
809
|
+
updateCheckIntervalMs: 36e5,
|
|
810
|
+
initialCheckDelayMs: 2e4,
|
|
811
|
+
upgradeTimeoutMs: 6e5,
|
|
812
|
+
installCommandTemplate: ["npm", "install", "-g", "{pkg}@{version}"],
|
|
813
|
+
// apiAccessKey(可选)出回环访问密钥:配置后,0.0.0.0(局域网)与 FRP 公网通道的 API 请求必须携带
|
|
814
|
+
// Authorization: Bearer <key> 或 ?access_key=<key>,否则 401;回环豁免。
|
|
815
|
+
// 不配置 = LAN 受 RFC1918 白名单约束,FRP 暴露仍强制 remoteToken。
|
|
816
|
+
apiAccessKey: null,
|
|
817
|
+
// 关闭窗口行为(系统级):'hide' = 隐藏至托盘、服务常驻(默认);'exit' = 退出管家并停全部服务链。
|
|
818
|
+
closeAction: "hide"
|
|
819
|
+
};
|
|
820
|
+
function buildDefaults2(ext) {
|
|
821
|
+
const pending = normalizeExtension(ext).defaults.slice();
|
|
822
|
+
const out = {};
|
|
823
|
+
for (const key of Object.keys(BASE_DEFAULTS)) {
|
|
824
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
825
|
+
const g = pending[i];
|
|
826
|
+
if (g && g.at === key) {
|
|
827
|
+
if (g.values && typeof g.values === "object") Object.assign(out, g.values);
|
|
828
|
+
pending.splice(i, 1);
|
|
718
829
|
}
|
|
719
|
-
} catch (e2) {
|
|
720
|
-
const l = logger();
|
|
721
|
-
if (l && l.warn) l.warn("_mSetPhase: " + (e2 && e2.message || e2));
|
|
722
830
|
}
|
|
831
|
+
out[key] = BASE_DEFAULTS[key];
|
|
723
832
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
return mainStore.readDshMain().guardian === true;
|
|
727
|
-
} catch {
|
|
728
|
-
return false;
|
|
729
|
-
}
|
|
833
|
+
for (const g of pending) {
|
|
834
|
+
if (g && g.values && typeof g.values === "object") Object.assign(out, g.values);
|
|
730
835
|
}
|
|
731
|
-
|
|
732
|
-
|
|
836
|
+
return out;
|
|
837
|
+
}
|
|
838
|
+
var DEFAULTS = buildDefaults2(null);
|
|
839
|
+
function normalize(raw, ext) {
|
|
840
|
+
const extension = normalizeExtension(ext);
|
|
841
|
+
const provided = raw || {};
|
|
842
|
+
const cfg = Object.assign(buildDefaults2(extension), provided);
|
|
843
|
+
cfg.stateFile = expandHome(cfg.stateFile);
|
|
844
|
+
cfg.logFile = expandHome(cfg.logFile);
|
|
845
|
+
cfg.supervisorLogFile = expandHome(cfg.supervisorLogFile);
|
|
846
|
+
cfg.dshLogFile = expandHome(cfg.dshLogFile);
|
|
847
|
+
cfg.upgradeLogFile = expandHome(cfg.upgradeLogFile);
|
|
848
|
+
let u;
|
|
849
|
+
try {
|
|
850
|
+
u = new URL(cfg.healthUrl);
|
|
851
|
+
} catch {
|
|
852
|
+
throw new Error("config.healthUrl \u65E0\u6548: " + JSON.stringify(cfg.healthUrl));
|
|
733
853
|
}
|
|
734
|
-
|
|
735
|
-
|
|
854
|
+
cfg.targetHost = u.hostname;
|
|
855
|
+
cfg.targetPort = Number(u.port || (u.protocol === "https:" ? 443 : 80));
|
|
856
|
+
for (const [from, to] of extension.aliases) {
|
|
857
|
+
if (provided[to] === void 0 && provided[from] !== void 0) cfg[to] = provided[from] === true;
|
|
736
858
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
} else if (e.desired !== want) {
|
|
745
|
-
e.desired = want;
|
|
746
|
-
}
|
|
747
|
-
} catch (e2) {
|
|
748
|
-
const l = logger();
|
|
749
|
-
if (l && l.warn) l.warn("_mSetDesired: " + (e2 && e2.message || e2));
|
|
750
|
-
}
|
|
859
|
+
const cmdPort = extractPortFromCommand(cfg.command);
|
|
860
|
+
if (cmdPort !== null) cfg.targetPort = cmdPort;
|
|
861
|
+
cfg.probeTimeoutMs = Number.isFinite(Number(cfg.probeTimeoutMs)) && Number(cfg.probeTimeoutMs) > 0 ? Number(cfg.probeTimeoutMs) : 3e3;
|
|
862
|
+
cfg.failThreshold = Number.isInteger(Number(cfg.failThreshold)) && Number(cfg.failThreshold) >= 1 ? Number(cfg.failThreshold) : 2;
|
|
863
|
+
cfg.httpProbeEnabled = cfg.httpProbeEnabled !== false;
|
|
864
|
+
if (!Array.isArray(cfg.command) || cfg.command.length === 0) {
|
|
865
|
+
throw new Error("config.command \u7F3A\u5931\uFF1A\u9700\u8981\u4E00\u4E2A\u547D\u4EE4\u6570\u7EC4");
|
|
751
866
|
}
|
|
752
|
-
|
|
753
|
-
|
|
867
|
+
return cfg;
|
|
868
|
+
}
|
|
869
|
+
function extractPortFromCommand(command) {
|
|
870
|
+
if (!Array.isArray(command)) return null;
|
|
871
|
+
for (let i = 0; i < command.length; i++) {
|
|
872
|
+
const a = String(command[i]);
|
|
873
|
+
if ((a === "--port" || a === "-p") && i + 1 < command.length) {
|
|
874
|
+
const n = Number(command[i + 1]);
|
|
875
|
+
if (Number.isInteger(n) && n > 0 && n <= 65535) return n;
|
|
876
|
+
}
|
|
877
|
+
const m = /^--port=(\d+)$/.exec(a);
|
|
878
|
+
if (m) {
|
|
879
|
+
const n = Number(m[1]);
|
|
880
|
+
if (Number.isInteger(n) && n > 0 && n <= 65535) return n;
|
|
881
|
+
}
|
|
754
882
|
}
|
|
755
|
-
|
|
756
|
-
|
|
883
|
+
return null;
|
|
884
|
+
}
|
|
885
|
+
module2.exports = { DEFAULTS, BASE_DEFAULTS, buildDefaults: buildDefaults2, normalize, extractPortFromCommand };
|
|
886
|
+
}
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
// src/app/settings/domain-config.js
|
|
890
|
+
var require_domain_config = __commonJS({
|
|
891
|
+
"src/app/settings/domain-config.js"(exports2, module2) {
|
|
892
|
+
"use strict";
|
|
893
|
+
var defaults = [
|
|
894
|
+
{
|
|
895
|
+
at: "portPools",
|
|
896
|
+
// daemon 控制通道端口:集中定义,杜绝散落硬编码。
|
|
897
|
+
// 这两个值同时是 app/ctl/client.js 与两个 daemon 的兜底端口,不得单独改动
|
|
898
|
+
// (改动即需同步 8 处 43107/43108 兜底常量)。
|
|
899
|
+
values: {
|
|
900
|
+
routerCtlPort: 43107,
|
|
901
|
+
lanCtlPort: 43108
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
at: "corePackageName",
|
|
906
|
+
// 智能路由启动开关。
|
|
907
|
+
values: {
|
|
908
|
+
routerAutostart: false
|
|
909
|
+
}
|
|
757
910
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
const setEntry = (n, v) => {
|
|
764
|
-
record.fieldOf(n, v, true);
|
|
765
|
-
};
|
|
766
|
-
const accessors = {
|
|
767
|
-
phase: { get: () => phase(), set: (v) => {
|
|
768
|
-
setPhase(v);
|
|
769
|
-
} },
|
|
770
|
-
desired: { get: () => desired(), set: (v) => {
|
|
771
|
-
setDesired(v);
|
|
772
|
-
} },
|
|
773
|
-
child: { get: () => getProc("child"), set: (c) => {
|
|
774
|
-
setProc("child", c);
|
|
775
|
-
} },
|
|
776
|
-
adoptedPid: { get: () => getProc("adoptedPid"), set: (v) => {
|
|
777
|
-
setProc("adoptedPid", v);
|
|
778
|
-
} },
|
|
779
|
-
adopted: { get: () => getProc("adopted") === true, set: (v) => {
|
|
780
|
-
setProc("adopted", v === true);
|
|
781
|
-
} },
|
|
782
|
-
observedOnly: { get: () => getProc("observedOnly") === true, set: (v) => {
|
|
783
|
-
setProc("observedOnly", v === true);
|
|
784
|
-
} },
|
|
785
|
-
restartCount: { get: () => {
|
|
786
|
-
const v = getEntry("restartCount");
|
|
787
|
-
return typeof v === "number" ? v : 0;
|
|
788
|
-
}, set: (v) => {
|
|
789
|
-
setEntry("restartCount", v);
|
|
790
|
-
} },
|
|
791
|
-
spawnBlockedUntil: { get: () => {
|
|
792
|
-
const v = getProc("spawnBlockedUntil");
|
|
793
|
-
return v === void 0 ? null : v;
|
|
794
|
-
}, set: (v) => {
|
|
795
|
-
setProc("spawnBlockedUntil", v);
|
|
796
|
-
} },
|
|
797
|
-
missingNotified: { get: () => getProc("missingNotified") === true, set: (v) => {
|
|
798
|
-
setProc("missingNotified", v === true);
|
|
799
|
-
} }
|
|
800
|
-
};
|
|
911
|
+
];
|
|
912
|
+
var aliases = [
|
|
913
|
+
["switcherAutoStart", "routerAutostart"]
|
|
914
|
+
];
|
|
915
|
+
function extension() {
|
|
801
916
|
return {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
guardian,
|
|
805
|
-
mainGuardian,
|
|
806
|
-
desired,
|
|
807
|
-
setDesired,
|
|
808
|
-
field,
|
|
809
|
-
procField,
|
|
810
|
-
accessors,
|
|
811
|
-
legacyToEntryPhase: toEntry,
|
|
812
|
-
entryToLegacyPhase: toLegacy,
|
|
813
|
-
child: () => getProc("child"),
|
|
814
|
-
adoptPid: () => getProc("adoptedPid"),
|
|
815
|
-
observedOnly: () => getProc("observedOnly") === true,
|
|
816
|
-
setObservedOnly: (v) => {
|
|
817
|
-
setProc("observedOnly", v === true);
|
|
818
|
-
},
|
|
819
|
-
ENTRY_FIELDS,
|
|
820
|
-
PROC_FIELDS
|
|
917
|
+
defaults: defaults.map((g) => ({ at: g.at, values: Object.assign({}, g.values) })),
|
|
918
|
+
aliases: aliases.map((a) => a.slice())
|
|
821
919
|
};
|
|
822
920
|
}
|
|
823
|
-
module2.exports = {
|
|
921
|
+
module2.exports = { extension, defaults, aliases };
|
|
824
922
|
}
|
|
825
923
|
});
|
|
826
924
|
|
|
827
|
-
// src/
|
|
828
|
-
var
|
|
829
|
-
"src/
|
|
925
|
+
// src/platform/service/version.js
|
|
926
|
+
var require_version = __commonJS({
|
|
927
|
+
"src/platform/service/version.js"(exports2, module2) {
|
|
830
928
|
"use strict";
|
|
831
929
|
var fs2 = require("node:fs");
|
|
832
930
|
var path2 = require("node:path");
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const upgradeHold = g.upgradeHold;
|
|
840
|
-
const config = () => typeof g.getConfig === "function" ? g.getConfig() || {} : {};
|
|
841
|
-
const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
|
|
842
|
-
const events = () => typeof g.getEvents === "function" ? g.getEvents() : null;
|
|
843
|
-
const instances = () => typeof g.getInstances === "function" ? g.getInstances() : null;
|
|
844
|
-
const views = () => typeof g.getViews === "function" ? g.getViews() : null;
|
|
845
|
-
const reg = () => typeof g.getManagedObjects === "function" ? g.getManagedObjects() : null;
|
|
846
|
-
let lastStateBody = null;
|
|
847
|
-
function writeState(force) {
|
|
848
|
-
try {
|
|
849
|
-
const snap = views().status();
|
|
850
|
-
const updatedAt = snap.updatedAt;
|
|
851
|
-
snap.updatedAt = null;
|
|
852
|
-
const body = JSON.stringify(snap, null, 2);
|
|
853
|
-
if (!force && body === lastStateBody) return;
|
|
854
|
-
lastStateBody = body;
|
|
855
|
-
snap.updatedAt = updatedAt;
|
|
856
|
-
const dir = path2.dirname(config().stateFile);
|
|
857
|
-
fs2.mkdirSync(dir, { recursive: true });
|
|
858
|
-
writeAtomic(config().stateFile, JSON.stringify(snap, null, 2), { mode: 384 });
|
|
859
|
-
} catch (e) {
|
|
860
|
-
const l = logger();
|
|
861
|
-
if (l && l.error) l.error("state write failed: " + e.message);
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
function loadState() {
|
|
865
|
-
let raw = null;
|
|
866
|
-
try {
|
|
867
|
-
raw = JSON.parse(fs2.readFileSync(config().stateFile, "utf8"));
|
|
868
|
-
} catch (e) {
|
|
869
|
-
if (!e || e.code !== "ENOENT") {
|
|
870
|
-
const l = logger();
|
|
871
|
-
if (l && l.warn) l.warn("state load failed\uFF08\u6309\u7A7A\u72B6\u6001\u7EE7\u7EED\uFF09: " + (e && e.message || e));
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
if (raw && typeof raw === "object") try {
|
|
875
|
-
if (raw.desired === "stopped" || raw.desired === "running") {
|
|
876
|
-
const m = reg();
|
|
877
|
-
const registryHasSource = !!(m && m._loadedFromDisk);
|
|
878
|
-
if (!registryHasSource) fields.setDesired(raw.desired);
|
|
879
|
-
}
|
|
880
|
-
if (typeof raw.restartCount === "number") record.fieldOf("restartCount", raw.restartCount, true);
|
|
881
|
-
if (typeof raw.backoffLevel === "number") record.fieldOf("backoffLevel", raw.backoffLevel, true);
|
|
882
|
-
if (typeof raw.crashWindowStart === "number" || raw.crashWindowStart === null) record.fieldOf("crashWindowStart", raw.crashWindowStart, true);
|
|
883
|
-
if (typeof raw.crashWindowRestarts === "number") record.fieldOf("crashWindowRestarts", raw.crashWindowRestarts, true);
|
|
884
|
-
if (typeof raw.lastFailure === "string" || raw.lastFailure === null) record.procFieldOf("lastFailure", raw.lastFailure, true);
|
|
885
|
-
if (typeof raw.lastRestartAt === "string" || raw.lastRestartAt === null) record.procFieldOf("lastRestartAt", raw.lastRestartAt, true);
|
|
886
|
-
if (raw.upgradeHold === true) upgradeHold.enter();
|
|
887
|
-
if (raw.shellHalted === true && typeof g.setShellHalted === "function") g.setShellHalted(true);
|
|
888
|
-
} catch (e) {
|
|
889
|
-
const l = logger();
|
|
890
|
-
if (l && l.warn) l.warn("state restore partial\uFF08\u5B57\u6BB5\u7EA7\u8DF3\u8FC7\uFF0Cboot \u4ECD\u7EE7\u7EED\uFF09: " + (e && e.message || e));
|
|
891
|
-
}
|
|
892
|
-
try {
|
|
893
|
-
fields.setPhase("STOPPED");
|
|
894
|
-
} catch {
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
function migrateMainRecord() {
|
|
898
|
-
try {
|
|
899
|
-
const im = instances();
|
|
900
|
-
if (!im || !Array.isArray(im.instances)) return;
|
|
901
|
-
const idx = im.instances.findIndex((i) => i.id === "main");
|
|
902
|
-
if (idx < 0) return;
|
|
903
|
-
const main = im.instances[idx];
|
|
904
|
-
const f = mainStore.dshMainFile();
|
|
905
|
-
if (f && !fs2.existsSync(f)) {
|
|
906
|
-
mainStore.writeDshMain({
|
|
907
|
-
guardian: main.guardian === true,
|
|
908
|
-
remoteMode: main.remoteEnabled === true ? main.frpEnabled === true ? "wan" : "lan" : "off",
|
|
909
|
-
remoteToken: String(main.remoteToken || "")
|
|
910
|
-
});
|
|
911
|
-
}
|
|
912
|
-
im.instances.splice(idx, 1);
|
|
913
|
-
if (im.save) {
|
|
914
|
-
try {
|
|
915
|
-
im.save();
|
|
916
|
-
} catch {
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
const l = logger();
|
|
920
|
-
if (l && l.info) l.info("[main] \u6982\u5FF5\u6E05\u5206\uFF1Amain \u8BB0\u5F55\u5DF2\u8FC1\u51FA instances.json \u2192 dsh-main.json");
|
|
921
|
-
const ev = events();
|
|
922
|
-
if (ev) ev.append("main_meta_migrated", {});
|
|
923
|
-
} catch (e) {
|
|
924
|
-
const l = logger();
|
|
925
|
-
if (l && l.warn) l.warn("_migrateMainRecord: " + (e && e.message));
|
|
926
|
-
}
|
|
931
|
+
function guardVersion() {
|
|
932
|
+
if (true) return String("0.1.6-BETA.3");
|
|
933
|
+
try {
|
|
934
|
+
return JSON.parse(fs2.readFileSync(path2.join(__dirname, "..", "..", "package.json"), "utf8")).version || "unknown";
|
|
935
|
+
} catch {
|
|
936
|
+
return "unknown";
|
|
927
937
|
}
|
|
928
|
-
return { writeState, loadState, migrateMainRecord };
|
|
929
938
|
}
|
|
930
|
-
module2.exports = {
|
|
939
|
+
module2.exports = { guardVersion };
|
|
931
940
|
}
|
|
932
941
|
});
|
|
933
942
|
|
|
934
|
-
// src/app/state/
|
|
935
|
-
var
|
|
936
|
-
"src/app/state/
|
|
943
|
+
// src/app/state/main-record.js
|
|
944
|
+
var require_main_record = __commonJS({
|
|
945
|
+
"src/app/state/main-record.js"(exports2, module2) {
|
|
937
946
|
"use strict";
|
|
938
|
-
|
|
939
|
-
var { writeAtomic } = require_fs();
|
|
940
|
-
function createDesired(deps) {
|
|
947
|
+
function createMainRecord(deps) {
|
|
941
948
|
const g = deps || {};
|
|
942
|
-
const
|
|
943
|
-
const store = g.store;
|
|
944
|
-
const intents = () => typeof g.getIntents === "function" ? g.getIntents() : null;
|
|
945
|
-
const events = () => typeof g.getEvents === "function" ? g.getEvents() : null;
|
|
946
|
-
const configPath = () => typeof g.getConfigPath === "function" ? g.getConfigPath() : null;
|
|
949
|
+
const reg = () => typeof g.getManagedObjects === "function" ? g.getManagedObjects() : null;
|
|
947
950
|
const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
const tick = () => {
|
|
953
|
-
if (typeof g.tick === "function") g.tick();
|
|
954
|
-
};
|
|
955
|
-
const stopProcess = (why) => {
|
|
956
|
-
if (typeof g.stopProcess === "function") g.stopProcess(why);
|
|
957
|
-
};
|
|
958
|
-
function setDesired(v) {
|
|
959
|
-
if (v !== "running" && v !== "stopped") return { error: "invalid desired" };
|
|
960
|
-
if (v === "running") {
|
|
961
|
-
const it = intents();
|
|
962
|
-
if (it) it.register("start");
|
|
963
|
-
setCrashHalted(false);
|
|
964
|
-
}
|
|
965
|
-
if (v === "running" && fields.phase() === "OBSERVED") {
|
|
966
|
-
fields.setObservedOnly(false);
|
|
967
|
-
fields.setPhase("STOPPED");
|
|
968
|
-
}
|
|
969
|
-
if (v === "stopped" && fields.phase() === "OBSERVED" && fields.observedOnly()) {
|
|
970
|
-
stopProcess("desired_stopped");
|
|
971
|
-
}
|
|
972
|
-
if (fields.desired() !== v) {
|
|
973
|
-
fields.setDesired(v);
|
|
974
|
-
const ev = events();
|
|
975
|
-
if (ev) ev.append("desired_changed", { desired: v });
|
|
976
|
-
store.writeState();
|
|
977
|
-
}
|
|
978
|
-
tick();
|
|
979
|
-
return { ok: true, desired: fields.desired() };
|
|
980
|
-
}
|
|
981
|
-
function requestRestart() {
|
|
982
|
-
if (fields.desired() === "stopped") {
|
|
983
|
-
const ev2 = events();
|
|
984
|
-
if (ev2) ev2.append("manual_restart_requested", { ignored: "desired=stopped" });
|
|
985
|
-
return { ok: false, error: "desired=stopped\uFF0C\u8BF7\u5148 /start" };
|
|
986
|
-
}
|
|
987
|
-
setManualRestart(true);
|
|
988
|
-
setCrashHalted(false);
|
|
989
|
-
const it = intents();
|
|
990
|
-
if (it) it.register("restart");
|
|
991
|
-
const ev = events();
|
|
992
|
-
if (ev) ev.append("manual_restart_requested", {});
|
|
993
|
-
tick();
|
|
994
|
-
return { ok: true };
|
|
995
|
-
}
|
|
996
|
-
function persistConfigPatch(patch) {
|
|
997
|
-
const p = configPath();
|
|
998
|
-
if (!p) return false;
|
|
999
|
-
const abort = (m) => {
|
|
1000
|
-
const l = logger();
|
|
1001
|
-
if (l && l.warn) l.warn("config persist aborted (fail-closed): " + m);
|
|
1002
|
-
const ev = events();
|
|
1003
|
-
if (ev) {
|
|
1004
|
-
try {
|
|
1005
|
-
ev.append("config_persist_aborted", { reason: m });
|
|
1006
|
-
} catch {
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
return false;
|
|
1010
|
-
};
|
|
951
|
+
let fallback = null;
|
|
952
|
+
function entryOf() {
|
|
953
|
+
const m = reg();
|
|
954
|
+
if (!m || typeof m.get !== "function") return null;
|
|
1011
955
|
try {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
raw = fs2.readFileSync(p, "utf8");
|
|
1016
|
-
} catch (e) {
|
|
1017
|
-
if (!e || e.code !== "ENOENT") return abort("read failed: " + (e && e.message || e));
|
|
1018
|
-
}
|
|
1019
|
-
if (raw !== null) {
|
|
1020
|
-
try {
|
|
1021
|
-
cur = JSON.parse(raw);
|
|
1022
|
-
if (!cur || typeof cur !== "object" || Array.isArray(cur)) throw new Error("root is not an object");
|
|
1023
|
-
} catch (e) {
|
|
1024
|
-
return abort("parse failed, original bytes preserved: " + (e && e.message || e));
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
Object.assign(cur, patch);
|
|
1028
|
-
delete cur.switcherAutoStart;
|
|
1029
|
-
writeAtomic(p, JSON.stringify(cur, null, 2), { mode: 384 });
|
|
1030
|
-
return true;
|
|
1031
|
-
} catch (e) {
|
|
1032
|
-
const l = logger();
|
|
1033
|
-
if (l && l.warn) l.warn("config persist failed: " + e.message);
|
|
1034
|
-
return false;
|
|
956
|
+
return m.get("main") || null;
|
|
957
|
+
} catch {
|
|
958
|
+
return null;
|
|
1035
959
|
}
|
|
1036
960
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
961
|
+
function fallbackEntryOf() {
|
|
962
|
+
if (!fallback) {
|
|
963
|
+
fallback = {
|
|
964
|
+
kind: "dsh",
|
|
965
|
+
id: "main",
|
|
966
|
+
name: "\u4E3B\u5B9E\u4F8B",
|
|
967
|
+
desired: "running",
|
|
968
|
+
guardian: true,
|
|
969
|
+
ownership: { ports: [], rootPath: null, unit: null, daemonScript: null, processMode: "spawn", meta: null },
|
|
970
|
+
phase: "stopped",
|
|
971
|
+
lastObserved: null,
|
|
972
|
+
backoffLevel: 0,
|
|
973
|
+
backoffUntil: null,
|
|
974
|
+
crashWindowStart: null,
|
|
975
|
+
crashWindowRestarts: 0,
|
|
976
|
+
restartCount: 0,
|
|
977
|
+
startedAt: null,
|
|
978
|
+
lastTransitionAt: null,
|
|
979
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
980
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
981
|
+
process: null
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
return fallback;
|
|
1058
985
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
986
|
+
function persistCrashField() {
|
|
987
|
+
const m = reg();
|
|
988
|
+
try {
|
|
989
|
+
if (m && typeof m.persistCrashState === "function") m.persistCrashState();
|
|
990
|
+
else if (m && typeof m._save === "function") m._save();
|
|
991
|
+
} catch (e) {
|
|
992
|
+
const l = logger();
|
|
993
|
+
if (l && l.warn) l.warn("persistCrashField: " + (e && e.message || e));
|
|
994
|
+
}
|
|
1065
995
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
if (p === want) {
|
|
1076
|
-
const pid = Number(parts[4]);
|
|
1077
|
-
if (Number.isInteger(pid) && pid > 0) return pid;
|
|
996
|
+
function storeOf() {
|
|
997
|
+
return entryOf() || fallbackEntryOf();
|
|
998
|
+
}
|
|
999
|
+
function fieldOf(name, v, write) {
|
|
1000
|
+
const e = storeOf();
|
|
1001
|
+
if (write) {
|
|
1002
|
+
if (e[name] !== v) {
|
|
1003
|
+
e[name] = v;
|
|
1004
|
+
persistCrashField();
|
|
1078
1005
|
}
|
|
1006
|
+
return e;
|
|
1079
1007
|
}
|
|
1008
|
+
return e[name];
|
|
1080
1009
|
}
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1010
|
+
function procFieldOf(name, v, write) {
|
|
1011
|
+
const e = storeOf();
|
|
1012
|
+
let p = e.process;
|
|
1013
|
+
if (!p) {
|
|
1014
|
+
p = e.process = {
|
|
1015
|
+
child: null,
|
|
1016
|
+
adoptedPid: null,
|
|
1017
|
+
adopted: false,
|
|
1018
|
+
observedOnly: false,
|
|
1019
|
+
startDeadline: null,
|
|
1020
|
+
restartAt: null,
|
|
1021
|
+
spawnBlockedUntil: null,
|
|
1022
|
+
missingNotified: false,
|
|
1023
|
+
failStreak: 0,
|
|
1024
|
+
lastProbeAt: null,
|
|
1025
|
+
lastProbeOk: null,
|
|
1026
|
+
lastProbeHttpOk: null,
|
|
1027
|
+
lastFailure: null,
|
|
1028
|
+
lastRestartAt: null
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
if (write) {
|
|
1032
|
+
if (p[name] !== v) p[name] = v;
|
|
1033
|
+
return p;
|
|
1034
|
+
}
|
|
1035
|
+
return p[name];
|
|
1036
|
+
}
|
|
1037
|
+
return { entryOf, fallbackEntryOf, persistCrashField, storeOf, fieldOf, procFieldOf };
|
|
1099
1038
|
}
|
|
1100
|
-
module2.exports = {
|
|
1101
|
-
parseProcNetTcpInodes,
|
|
1102
|
-
parseLsofPid,
|
|
1103
|
-
parseNetstatPid,
|
|
1104
|
-
parseSsPid,
|
|
1105
|
-
parseWmicCommandLine,
|
|
1106
|
-
parsePowerShellCommandLine,
|
|
1107
|
-
normCmdline
|
|
1108
|
-
};
|
|
1039
|
+
module2.exports = { createMainRecord };
|
|
1109
1040
|
}
|
|
1110
1041
|
});
|
|
1111
1042
|
|
|
1112
|
-
// src/platform/
|
|
1113
|
-
var
|
|
1114
|
-
"src/platform/
|
|
1043
|
+
// src/platform/util/fs.js
|
|
1044
|
+
var require_fs = __commonJS({
|
|
1045
|
+
"src/platform/util/fs.js"(exports2, module2) {
|
|
1115
1046
|
"use strict";
|
|
1116
1047
|
var fs2 = require("node:fs");
|
|
1117
1048
|
var path2 = require("node:path");
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1049
|
+
function dirSizeBytes(root) {
|
|
1050
|
+
let total = 0;
|
|
1051
|
+
let seen = 0;
|
|
1052
|
+
const MAX = 2e5;
|
|
1053
|
+
const walk = (dir) => {
|
|
1054
|
+
if (seen > MAX) return;
|
|
1055
|
+
let entries;
|
|
1056
|
+
try {
|
|
1057
|
+
entries = fs2.readdirSync(dir, { withFileTypes: true });
|
|
1058
|
+
} catch {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
for (const en of entries) {
|
|
1062
|
+
if (seen > MAX) return;
|
|
1063
|
+
const full = path2.join(dir, en.name);
|
|
1064
|
+
if (en.isSymbolicLink()) continue;
|
|
1065
|
+
if (en.isDirectory()) walk(full);
|
|
1066
|
+
else if (en.isFile()) {
|
|
1067
|
+
try {
|
|
1068
|
+
const st = fs2.statSync(full);
|
|
1069
|
+
total += st.size;
|
|
1070
|
+
} catch {
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
seen++;
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1132
1076
|
try {
|
|
1133
|
-
|
|
1134
|
-
if ((platform || process.platform) === "win32") return true;
|
|
1135
|
-
fs2.accessSync(p, fs2.constants.X_OK);
|
|
1136
|
-
return true;
|
|
1077
|
+
walk(root);
|
|
1137
1078
|
} catch {
|
|
1138
|
-
return false;
|
|
1139
1079
|
}
|
|
1080
|
+
return total;
|
|
1140
1081
|
}
|
|
1141
|
-
function
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1082
|
+
function writeAtomic(file, data, opts) {
|
|
1083
|
+
const mode = opts && typeof opts.mode === "number" ? opts.mode : 384;
|
|
1084
|
+
const fp = path2.resolve(file);
|
|
1085
|
+
const dir = path2.dirname(fp);
|
|
1086
|
+
const tmp = fp + ".tmp." + process.pid + "." + Date.now();
|
|
1087
|
+
try {
|
|
1088
|
+
if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
|
|
1089
|
+
fs2.writeFileSync(tmp, data, { mode });
|
|
1145
1090
|
try {
|
|
1146
|
-
|
|
1091
|
+
fs2.chmodSync(tmp, mode);
|
|
1147
1092
|
} catch {
|
|
1148
1093
|
}
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
const pl = platform || process.platform;
|
|
1154
|
-
const h = home || os2.homedir();
|
|
1155
|
-
const e = env || process.env;
|
|
1156
|
-
const dirs = [];
|
|
1157
|
-
if (pl === "win32") {
|
|
1158
|
-
if (e.APPDATA) dirs.push(path2.join(e.APPDATA, "npm"));
|
|
1159
|
-
if (e.LOCALAPPDATA) dirs.push(path2.join(e.LOCALAPPDATA, "Programs", "dsh-supervisor"));
|
|
1160
|
-
dirs.push(path2.join(h, ".local", "bin"));
|
|
1161
|
-
} else {
|
|
1162
|
-
dirs.push(path2.join(h, ".local", "bin"));
|
|
1163
|
-
dirs.push(path2.join(h, ".npm-global", "bin"));
|
|
1164
|
-
if (pl === "darwin") {
|
|
1165
|
-
dirs.push("/opt/homebrew/bin");
|
|
1166
|
-
dirs.push("/usr/local/bin");
|
|
1094
|
+
fs2.renameSync(tmp, fp);
|
|
1095
|
+
try {
|
|
1096
|
+
fs2.chmodSync(fp, mode);
|
|
1097
|
+
} catch {
|
|
1167
1098
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
}
|
|
1171
|
-
function inPath(base, platform, env) {
|
|
1172
|
-
const e = env || process.env;
|
|
1173
|
-
const raw = e.PATH || e.Path || "";
|
|
1174
|
-
for (const d of raw.split(path2.delimiter)) {
|
|
1175
|
-
if (!d) continue;
|
|
1176
|
-
const hit = firstExecutable(d, base, platform);
|
|
1177
|
-
if (hit) return hit;
|
|
1178
|
-
}
|
|
1179
|
-
return null;
|
|
1180
|
-
}
|
|
1181
|
-
function resolveExecutable(base, opts) {
|
|
1182
|
-
const o = opts || {};
|
|
1183
|
-
const pl = o.platform;
|
|
1184
|
-
const env = o.env;
|
|
1185
|
-
const E = env || process.env;
|
|
1186
|
-
if (o.envVar && E[o.envVar]) {
|
|
1187
|
-
const v = E[o.envVar];
|
|
1188
|
-
if (isExecutableFile(v, pl)) return v;
|
|
1189
|
-
}
|
|
1190
|
-
const inPathHit = inPath(base, pl, env);
|
|
1191
|
-
if (inPathHit) return inPathHit;
|
|
1192
|
-
for (const d of [...o.extraDirs || [], ...standardDirs(pl, void 0, env)]) {
|
|
1193
|
-
const hit = firstExecutable(d, base, pl);
|
|
1194
|
-
if (hit) return hit;
|
|
1195
|
-
}
|
|
1196
|
-
return null;
|
|
1197
|
-
}
|
|
1198
|
-
function npxBin(opts) {
|
|
1199
|
-
const o = opts || {};
|
|
1200
|
-
const pl = o.platform || process.platform;
|
|
1201
|
-
const env = o.env || process.env;
|
|
1202
|
-
if (pl !== "win32") return "npx";
|
|
1203
|
-
const resolved = resolveExecutable("npx", { platform: pl, env, extraDirs: [
|
|
1204
|
-
env.APPDATA ? path2.join(env.APPDATA, "npm") : null
|
|
1205
|
-
].filter(Boolean) });
|
|
1206
|
-
if (resolved) return resolved;
|
|
1207
|
-
return "npx.cmd";
|
|
1208
|
-
}
|
|
1209
|
-
function npmBin(opts) {
|
|
1210
|
-
const o = opts || {};
|
|
1211
|
-
const pl = o.platform || process.platform;
|
|
1212
|
-
const env = o.env || process.env;
|
|
1213
|
-
if (pl !== "win32") return "npm";
|
|
1214
|
-
const resolved = resolveExecutable("npm", { platform: pl, env, extraDirs: [
|
|
1215
|
-
env.APPDATA ? path2.join(env.APPDATA, "npm") : null
|
|
1216
|
-
].filter(Boolean) });
|
|
1217
|
-
if (resolved) return resolved;
|
|
1218
|
-
return "npm.cmd";
|
|
1219
|
-
}
|
|
1220
|
-
var DSH_PKG = ["@deepseek-ai", "dsh"];
|
|
1221
|
-
function dshJsIn(prefix) {
|
|
1222
|
-
return path2.join(prefix, "node_modules", ...DSH_PKG, "lib", "bin.js");
|
|
1223
|
-
}
|
|
1224
|
-
function resolveDsh(opts) {
|
|
1225
|
-
const o = opts || {};
|
|
1226
|
-
const pl = o.platform || process.platform;
|
|
1227
|
-
const env = o.env || process.env;
|
|
1228
|
-
const isFile = (p) => {
|
|
1099
|
+
return fp;
|
|
1100
|
+
} catch (e) {
|
|
1229
1101
|
try {
|
|
1230
|
-
|
|
1102
|
+
if (fs2.existsSync(tmp)) fs2.truncateSync(tmp, 0);
|
|
1231
1103
|
} catch {
|
|
1232
|
-
return false;
|
|
1233
1104
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1105
|
+
throw e;
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
module2.exports = { dirSizeBytes, writeAtomic };
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
// src/app/state/main-store.js
|
|
1113
|
+
var require_main_store = __commonJS({
|
|
1114
|
+
"src/app/state/main-store.js"(exports2, module2) {
|
|
1115
|
+
"use strict";
|
|
1116
|
+
var fs2 = require("node:fs");
|
|
1117
|
+
var path2 = require("node:path");
|
|
1118
|
+
var { writeAtomic } = require_fs();
|
|
1119
|
+
function createMainStore(deps) {
|
|
1120
|
+
const g = deps || {};
|
|
1121
|
+
const config = () => typeof g.getConfig === "function" ? g.getConfig() || {} : {};
|
|
1122
|
+
const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
|
|
1123
|
+
let live = null;
|
|
1124
|
+
let corrupt = false;
|
|
1125
|
+
function dshMainFile() {
|
|
1237
1126
|
try {
|
|
1238
|
-
|
|
1239
|
-
if (isFile(r)) return asJs(r, env.DSH_BIN);
|
|
1127
|
+
return path2.join(path2.dirname(config().stateFile), "dsh-main.json");
|
|
1240
1128
|
} catch {
|
|
1129
|
+
return null;
|
|
1241
1130
|
}
|
|
1242
1131
|
}
|
|
1243
|
-
|
|
1244
|
-
if (hit) {
|
|
1132
|
+
function registryFileName() {
|
|
1245
1133
|
try {
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1134
|
+
const b = path2.basename(config().stateFile || "state.json", ".json");
|
|
1135
|
+
return b === "state" ? "managed-objects.json" : b + ".managed-objects.json";
|
|
1248
1136
|
} catch {
|
|
1137
|
+
return "managed-objects.json";
|
|
1249
1138
|
}
|
|
1250
|
-
const js = dshJsIn(path2.dirname(hit));
|
|
1251
|
-
if (isFile(js)) return asJs(js, hit);
|
|
1252
|
-
if (isFile(hit) && !/\.(cmd|bat|exe)$/i.test(hit)) return asJs(hit, hit);
|
|
1253
|
-
return { runtime: null, bin: hit, isJs: false, launcher: hit };
|
|
1254
|
-
}
|
|
1255
|
-
if (o.npmRoot) {
|
|
1256
|
-
const js = dshJsIn(o.npmRoot);
|
|
1257
|
-
if (isFile(js)) return asJs(js, null);
|
|
1258
1139
|
}
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1140
|
+
function readDshMainFile() {
|
|
1141
|
+
try {
|
|
1142
|
+
const f = dshMainFile();
|
|
1143
|
+
if (f && fs2.existsSync(f)) {
|
|
1144
|
+
const j = JSON.parse(fs2.readFileSync(f, "utf8"));
|
|
1145
|
+
corrupt = false;
|
|
1146
|
+
return {
|
|
1147
|
+
guardian: j.guardian === true,
|
|
1148
|
+
remoteMode: legacyRemoteMode(j),
|
|
1149
|
+
remoteToken: String(j.remoteToken || "")
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
} catch (e) {
|
|
1153
|
+
corrupt = true;
|
|
1154
|
+
const l = logger();
|
|
1155
|
+
if (l && l.warn) l.warn("dsh-main.json \u8BFB/\u89E3\u6790\u5931\u8D25\uFF0C\u5199\u56DE\u5C06\u88AB\u62D2\u7EDD\u76F4\u81F3\u663E\u5F0F\u91CD\u8BBE remoteToken: " + (e && e.message || e));
|
|
1269
1156
|
}
|
|
1270
|
-
|
|
1157
|
+
return { guardian: false, remoteMode: "off", remoteToken: "" };
|
|
1271
1158
|
}
|
|
1272
|
-
|
|
1159
|
+
function legacyRemoteMode(j) {
|
|
1160
|
+
if (j.remoteMode === "lan" || j.remoteMode === "wan") return j.remoteMode;
|
|
1161
|
+
if (j.remoteEnabled === true && j.frpEnabled === true) return "wan";
|
|
1162
|
+
if (j.remoteEnabled === true) return "lan";
|
|
1163
|
+
return "off";
|
|
1164
|
+
}
|
|
1165
|
+
function readDshMain() {
|
|
1166
|
+
if (live) return live;
|
|
1167
|
+
live = readDshMainFile();
|
|
1168
|
+
return live;
|
|
1169
|
+
}
|
|
1170
|
+
function writeDshMain(meta) {
|
|
1171
|
+
const m = meta || {};
|
|
1172
|
+
if (!live) live = readDshMainFile();
|
|
1173
|
+
if (corrupt && !(typeof m.remoteToken === "string" && m.remoteToken)) {
|
|
1174
|
+
const l = logger();
|
|
1175
|
+
if (l && l.warn) l.warn("_writeDshMain: \u6587\u4EF6\u635F\u574F\u6001\uFF0C\u62D2\u7EDD\u4EE5\u9ED8\u8BA4\u503C\u8986\u76D6\u5199\u56DE");
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
corrupt = false;
|
|
1179
|
+
Object.assign(live, m);
|
|
1180
|
+
const f = dshMainFile();
|
|
1181
|
+
if (!f) return;
|
|
1273
1182
|
try {
|
|
1274
|
-
|
|
1275
|
-
|
|
1183
|
+
const cur = readDshMain();
|
|
1184
|
+
const merged = Object.assign({}, cur, m);
|
|
1185
|
+
const dir = path2.dirname(f);
|
|
1186
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
1187
|
+
const body = JSON.stringify({
|
|
1188
|
+
guardian: merged.guardian === true,
|
|
1189
|
+
remoteMode: merged.remoteMode === "lan" || merged.remoteMode === "wan" ? merged.remoteMode : "off",
|
|
1190
|
+
remoteToken: String(merged.remoteToken || "")
|
|
1191
|
+
}, null, 2);
|
|
1192
|
+
writeAtomic(f, body, { mode: 384 });
|
|
1193
|
+
} catch (e) {
|
|
1194
|
+
const l = logger();
|
|
1195
|
+
if (l && l.warn) l.warn("_writeDshMain: " + (e && e.message || e));
|
|
1276
1196
|
}
|
|
1277
1197
|
}
|
|
1278
|
-
|
|
1279
|
-
return [...new Set(out.filter((x) => typeof x === "string" && x))];
|
|
1198
|
+
return { dshMainFile, registryFileName, readDshMain, readDshMainFile, writeDshMain };
|
|
1280
1199
|
}
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1200
|
+
module2.exports = { createMainStore };
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1204
|
+
// src/app/state/field-tables.js
|
|
1205
|
+
var require_field_tables = __commonJS({
|
|
1206
|
+
"src/app/state/field-tables.js"(exports2, module2) {
|
|
1207
|
+
"use strict";
|
|
1208
|
+
var ENTRY_FIELDS = [
|
|
1209
|
+
// [读写 helper 后缀, entry 字段]
|
|
1210
|
+
["CrashWindowStart", "crashWindowStart"],
|
|
1211
|
+
["CrashWindowRestarts", "crashWindowRestarts"],
|
|
1212
|
+
["BackoffLevel", "backoffLevel"],
|
|
1213
|
+
["BackoffUntil", "backoffUntil"],
|
|
1214
|
+
["RestartCount", "restartCount"]
|
|
1215
|
+
];
|
|
1216
|
+
var PROC_FIELDS = [
|
|
1217
|
+
// [读写 helper 后缀, process 字段, 是否布尔]
|
|
1218
|
+
["Child", "child", false],
|
|
1219
|
+
["AdoptPid", "adoptedPid", false],
|
|
1220
|
+
["Adopted", "adopted", true],
|
|
1221
|
+
["ObservedOnly", "observedOnly", true],
|
|
1222
|
+
["FailStreak", "failStreak", false],
|
|
1223
|
+
["RestartAt", "restartAt", false],
|
|
1224
|
+
["StartDeadline", "startDeadline", false],
|
|
1225
|
+
["SpawnBlockedUntil", "spawnBlockedUntil", false],
|
|
1226
|
+
["MissingNotified", "missingNotified", true],
|
|
1227
|
+
["LastProbeAt", "lastProbeAt", false],
|
|
1228
|
+
["LastProbeOk", "lastProbeOk", false],
|
|
1229
|
+
["LastProbeHttpOk", "lastProbeHttpOk", false],
|
|
1230
|
+
["LastFailure", "lastFailure", false],
|
|
1231
|
+
["LastRestartAt", "lastRestartAt", false]
|
|
1232
|
+
];
|
|
1233
|
+
module2.exports = { ENTRY_FIELDS, PROC_FIELDS };
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
|
|
1237
|
+
// src/app/state/phase.js
|
|
1238
|
+
var require_phase = __commonJS({
|
|
1239
|
+
"src/app/state/phase.js"(exports2, module2) {
|
|
1240
|
+
"use strict";
|
|
1241
|
+
function legacyToEntryPhase(ph) {
|
|
1242
|
+
return { STOPPED: "stopped", STARTING: "starting", RUNNING: "running", RESTARTING: "restarting", BACKOFF: "backoff", OBSERVED: "stopped" }[ph] || "stopped";
|
|
1243
|
+
}
|
|
1244
|
+
function entryToLegacyPhase(ph) {
|
|
1245
|
+
return { stopped: "STOPPED", starting: "STARTING", running: "RUNNING", restarting: "RESTARTING", backoff: "BACKOFF" }[ph] || "STOPPED";
|
|
1246
|
+
}
|
|
1247
|
+
module2.exports = { legacyToEntryPhase, entryToLegacyPhase };
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
|
|
1251
|
+
// src/app/state/fields.js
|
|
1252
|
+
var require_fields = __commonJS({
|
|
1253
|
+
"src/app/state/fields.js"(exports2, module2) {
|
|
1254
|
+
"use strict";
|
|
1255
|
+
var { ENTRY_FIELDS, PROC_FIELDS } = require_field_tables();
|
|
1256
|
+
var { legacyToEntryPhase, entryToLegacyPhase } = require_phase();
|
|
1257
|
+
function createFields(deps) {
|
|
1258
|
+
const g = deps || {};
|
|
1259
|
+
const record = g.record;
|
|
1260
|
+
const mainStore = g.mainStore;
|
|
1261
|
+
const reg = () => typeof g.getManagedObjects === "function" ? g.getManagedObjects() : null;
|
|
1262
|
+
const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
|
|
1263
|
+
function toEntry(ph) {
|
|
1264
|
+
return legacyToEntryPhase(ph);
|
|
1293
1265
|
}
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
const hasSep = (p) => /[\\/]/.test(String(p));
|
|
1297
|
-
if (!hasSep(entry)) {
|
|
1298
|
-
if (nodeHead && o.requireAbsoluteEntry) {
|
|
1299
|
-
return "command[0] \u4E3A node \u65F6 command[1] \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84\u7684 DSH \u5165\u53E3\uFF08\u76F8\u5BF9/\u88F8\u540D\u4F1A\u6309\u5DE5\u4F5C\u76EE\u5F55\u6216 PATH \u89E3\u6790\uFF09";
|
|
1300
|
-
}
|
|
1301
|
-
return null;
|
|
1266
|
+
function toLegacy(ph) {
|
|
1267
|
+
return entryToLegacyPhase(ph);
|
|
1302
1268
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1269
|
+
function phase() {
|
|
1270
|
+
const e = record.storeOf();
|
|
1271
|
+
const p = e.process || null;
|
|
1272
|
+
const upper = entryToLegacyPhase(e.phase || "stopped");
|
|
1273
|
+
if (upper === "STOPPED" && p && p.observedOnly && p.adopted) return "OBSERVED";
|
|
1274
|
+
return upper;
|
|
1305
1275
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1276
|
+
function setPhase(upper) {
|
|
1277
|
+
const e = record.storeOf();
|
|
1278
|
+
const ph = legacyToEntryPhase(upper);
|
|
1279
|
+
const m = reg();
|
|
1280
|
+
try {
|
|
1281
|
+
if (m && typeof m.setPhase === "function" && record.entryOf() === e) {
|
|
1282
|
+
if (e.phase !== ph) m.setPhase("main", ph);
|
|
1283
|
+
} else if (e.phase !== ph) {
|
|
1284
|
+
e.phase = ph;
|
|
1285
|
+
}
|
|
1286
|
+
} catch (e2) {
|
|
1287
|
+
const l = logger();
|
|
1288
|
+
if (l && l.warn) l.warn("_mSetPhase: " + (e2 && e2.message || e2));
|
|
1289
|
+
}
|
|
1310
1290
|
}
|
|
1311
|
-
|
|
1291
|
+
function guardian() {
|
|
1312
1292
|
try {
|
|
1313
|
-
|
|
1293
|
+
return mainStore.readDshMain().guardian === true;
|
|
1314
1294
|
} catch {
|
|
1295
|
+
return false;
|
|
1315
1296
|
}
|
|
1316
1297
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1298
|
+
function mainGuardian() {
|
|
1299
|
+
return guardian();
|
|
1300
|
+
}
|
|
1301
|
+
function desired() {
|
|
1302
|
+
return record.storeOf().desired === "stopped" ? "stopped" : "running";
|
|
1303
|
+
}
|
|
1304
|
+
function setDesired(v) {
|
|
1305
|
+
const want = v === "stopped" ? "stopped" : "running";
|
|
1306
|
+
const e = record.storeOf();
|
|
1307
|
+
const m = reg();
|
|
1319
1308
|
try {
|
|
1320
|
-
if (
|
|
1321
|
-
|
|
1309
|
+
if (m && typeof m.update === "function" && record.entryOf() === e) {
|
|
1310
|
+
if (e.desired !== want) m.update("main", { desired: want });
|
|
1311
|
+
} else if (e.desired !== want) {
|
|
1312
|
+
e.desired = want;
|
|
1313
|
+
}
|
|
1314
|
+
} catch (e2) {
|
|
1315
|
+
const l = logger();
|
|
1316
|
+
if (l && l.warn) l.warn("_mSetDesired: " + (e2 && e2.message || e2));
|
|
1322
1317
|
}
|
|
1323
1318
|
}
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
try {
|
|
1327
|
-
rr = rp(r);
|
|
1328
|
-
} catch {
|
|
1329
|
-
continue;
|
|
1330
|
-
}
|
|
1331
|
-
const base = String(rr).replace(/[\\/]+$/, "");
|
|
1332
|
-
if (real === base || real.indexOf(base + path2.sep) === 0) return null;
|
|
1319
|
+
function field(name, v) {
|
|
1320
|
+
return arguments.length >= 2 ? record.fieldOf(name, v, true) : record.fieldOf(name, void 0, false);
|
|
1333
1321
|
}
|
|
1334
|
-
|
|
1322
|
+
function procField(name, v) {
|
|
1323
|
+
return arguments.length >= 2 ? record.procFieldOf(name, v, true) : record.procFieldOf(name, void 0, false);
|
|
1324
|
+
}
|
|
1325
|
+
const getProc = (n) => record.procFieldOf(n);
|
|
1326
|
+
const setProc = (n, v) => {
|
|
1327
|
+
record.procFieldOf(n, v, true);
|
|
1328
|
+
};
|
|
1329
|
+
const getEntry = (n) => record.fieldOf(n);
|
|
1330
|
+
const setEntry = (n, v) => {
|
|
1331
|
+
record.fieldOf(n, v, true);
|
|
1332
|
+
};
|
|
1333
|
+
const accessors = {
|
|
1334
|
+
phase: { get: () => phase(), set: (v) => {
|
|
1335
|
+
setPhase(v);
|
|
1336
|
+
} },
|
|
1337
|
+
desired: { get: () => desired(), set: (v) => {
|
|
1338
|
+
setDesired(v);
|
|
1339
|
+
} },
|
|
1340
|
+
child: { get: () => getProc("child"), set: (c) => {
|
|
1341
|
+
setProc("child", c);
|
|
1342
|
+
} },
|
|
1343
|
+
adoptedPid: { get: () => getProc("adoptedPid"), set: (v) => {
|
|
1344
|
+
setProc("adoptedPid", v);
|
|
1345
|
+
} },
|
|
1346
|
+
adopted: { get: () => getProc("adopted") === true, set: (v) => {
|
|
1347
|
+
setProc("adopted", v === true);
|
|
1348
|
+
} },
|
|
1349
|
+
observedOnly: { get: () => getProc("observedOnly") === true, set: (v) => {
|
|
1350
|
+
setProc("observedOnly", v === true);
|
|
1351
|
+
} },
|
|
1352
|
+
restartCount: { get: () => {
|
|
1353
|
+
const v = getEntry("restartCount");
|
|
1354
|
+
return typeof v === "number" ? v : 0;
|
|
1355
|
+
}, set: (v) => {
|
|
1356
|
+
setEntry("restartCount", v);
|
|
1357
|
+
} },
|
|
1358
|
+
spawnBlockedUntil: { get: () => {
|
|
1359
|
+
const v = getProc("spawnBlockedUntil");
|
|
1360
|
+
return v === void 0 ? null : v;
|
|
1361
|
+
}, set: (v) => {
|
|
1362
|
+
setProc("spawnBlockedUntil", v);
|
|
1363
|
+
} },
|
|
1364
|
+
missingNotified: { get: () => getProc("missingNotified") === true, set: (v) => {
|
|
1365
|
+
setProc("missingNotified", v === true);
|
|
1366
|
+
} }
|
|
1367
|
+
};
|
|
1368
|
+
return {
|
|
1369
|
+
phase,
|
|
1370
|
+
setPhase,
|
|
1371
|
+
guardian,
|
|
1372
|
+
mainGuardian,
|
|
1373
|
+
desired,
|
|
1374
|
+
setDesired,
|
|
1375
|
+
field,
|
|
1376
|
+
procField,
|
|
1377
|
+
accessors,
|
|
1378
|
+
legacyToEntryPhase: toEntry,
|
|
1379
|
+
entryToLegacyPhase: toLegacy,
|
|
1380
|
+
child: () => getProc("child"),
|
|
1381
|
+
adoptPid: () => getProc("adoptedPid"),
|
|
1382
|
+
observedOnly: () => getProc("observedOnly") === true,
|
|
1383
|
+
setObservedOnly: (v) => {
|
|
1384
|
+
setProc("observedOnly", v === true);
|
|
1385
|
+
},
|
|
1386
|
+
ENTRY_FIELDS,
|
|
1387
|
+
PROC_FIELDS
|
|
1388
|
+
};
|
|
1335
1389
|
}
|
|
1336
|
-
module2.exports = {
|
|
1337
|
-
resolveExecutable,
|
|
1338
|
-
candidateNames,
|
|
1339
|
-
standardDirs,
|
|
1340
|
-
npmBin,
|
|
1341
|
-
npxBin,
|
|
1342
|
-
resolveDsh,
|
|
1343
|
-
dshJsIn,
|
|
1344
|
-
knownDshEntries,
|
|
1345
|
-
commandEntryViolation,
|
|
1346
|
-
isExecutableFile
|
|
1347
|
-
};
|
|
1390
|
+
module2.exports = { createFields };
|
|
1348
1391
|
}
|
|
1349
1392
|
});
|
|
1350
1393
|
|
|
1351
|
-
// src/
|
|
1352
|
-
var
|
|
1353
|
-
"src/
|
|
1394
|
+
// src/app/state/store.js
|
|
1395
|
+
var require_store = __commonJS({
|
|
1396
|
+
"src/app/state/store.js"(exports2, module2) {
|
|
1354
1397
|
"use strict";
|
|
1355
1398
|
var fs2 = require("node:fs");
|
|
1356
|
-
var
|
|
1357
|
-
var {
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
let txt = "";
|
|
1399
|
+
var path2 = require("node:path");
|
|
1400
|
+
var { writeAtomic } = require_fs();
|
|
1401
|
+
function createStore(deps) {
|
|
1402
|
+
const g = deps || {};
|
|
1403
|
+
const record = g.record;
|
|
1404
|
+
const fields = g.fields;
|
|
1405
|
+
const mainStore = g.mainStore;
|
|
1406
|
+
const upgradeHold = g.upgradeHold;
|
|
1407
|
+
const config = () => typeof g.getConfig === "function" ? g.getConfig() || {} : {};
|
|
1408
|
+
const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
|
|
1409
|
+
const events = () => typeof g.getEvents === "function" ? g.getEvents() : null;
|
|
1410
|
+
const instances = () => typeof g.getInstances === "function" ? g.getInstances() : null;
|
|
1411
|
+
const views = () => typeof g.getViews === "function" ? g.getViews() : null;
|
|
1412
|
+
const reg = () => typeof g.getManagedObjects === "function" ? g.getManagedObjects() : null;
|
|
1413
|
+
let lastStateBody = null;
|
|
1414
|
+
function writeState(force) {
|
|
1373
1415
|
try {
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1416
|
+
const snap = views().status();
|
|
1417
|
+
const updatedAt = snap.updatedAt;
|
|
1418
|
+
snap.updatedAt = null;
|
|
1419
|
+
const body = JSON.stringify(snap, null, 2);
|
|
1420
|
+
if (!force && body === lastStateBody) return;
|
|
1421
|
+
lastStateBody = body;
|
|
1422
|
+
snap.updatedAt = updatedAt;
|
|
1423
|
+
const dir = path2.dirname(config().stateFile);
|
|
1424
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
1425
|
+
writeAtomic(config().stateFile, JSON.stringify(snap, null, 2), { mode: 384 });
|
|
1426
|
+
} catch (e) {
|
|
1427
|
+
const l = logger();
|
|
1428
|
+
if (l && l.error) l.error("state write failed: " + e.message);
|
|
1377
1429
|
}
|
|
1378
|
-
for (const x of parseProcNetTcpInodes(txt, port)) inodes.add(x);
|
|
1379
1430
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
let fds;
|
|
1389
|
-
try {
|
|
1390
|
-
fds = fs2.readdirSync("/proc/" + pid + "/fd");
|
|
1391
|
-
} catch {
|
|
1392
|
-
continue;
|
|
1431
|
+
function loadState() {
|
|
1432
|
+
let raw = null;
|
|
1433
|
+
try {
|
|
1434
|
+
raw = JSON.parse(fs2.readFileSync(config().stateFile, "utf8"));
|
|
1435
|
+
} catch (e) {
|
|
1436
|
+
if (!e || e.code !== "ENOENT") {
|
|
1437
|
+
const l = logger();
|
|
1438
|
+
if (l && l.warn) l.warn("state load failed\uFF08\u6309\u7A7A\u72B6\u6001\u7EE7\u7EED\uFF09: " + (e && e.message || e));
|
|
1393
1439
|
}
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
}
|
|
1401
|
-
if (inodes.has(link)) return Number(pid);
|
|
1440
|
+
}
|
|
1441
|
+
if (raw && typeof raw === "object") try {
|
|
1442
|
+
if (raw.desired === "stopped" || raw.desired === "running") {
|
|
1443
|
+
const m = reg();
|
|
1444
|
+
const registryHasSource = !!(m && m._loadedFromDisk);
|
|
1445
|
+
if (!registryHasSource) fields.setDesired(raw.desired);
|
|
1402
1446
|
}
|
|
1447
|
+
if (typeof raw.restartCount === "number") record.fieldOf("restartCount", raw.restartCount, true);
|
|
1448
|
+
if (typeof raw.backoffLevel === "number") record.fieldOf("backoffLevel", raw.backoffLevel, true);
|
|
1449
|
+
if (typeof raw.crashWindowStart === "number" || raw.crashWindowStart === null) record.fieldOf("crashWindowStart", raw.crashWindowStart, true);
|
|
1450
|
+
if (typeof raw.crashWindowRestarts === "number") record.fieldOf("crashWindowRestarts", raw.crashWindowRestarts, true);
|
|
1451
|
+
if (typeof raw.lastFailure === "string" || raw.lastFailure === null) record.procFieldOf("lastFailure", raw.lastFailure, true);
|
|
1452
|
+
if (typeof raw.lastRestartAt === "string" || raw.lastRestartAt === null) record.procFieldOf("lastRestartAt", raw.lastRestartAt, true);
|
|
1453
|
+
if (raw.upgradeHold === true) upgradeHold.enter();
|
|
1454
|
+
if (raw.shellHalted === true && typeof g.setShellHalted === "function") g.setShellHalted(true);
|
|
1455
|
+
} catch (e) {
|
|
1456
|
+
const l = logger();
|
|
1457
|
+
if (l && l.warn) l.warn("state restore partial\uFF08\u5B57\u6BB5\u7EA7\u8DF3\u8FC7\uFF0Cboot \u4ECD\u7EE7\u7EED\uFF09: " + (e && e.message || e));
|
|
1403
1458
|
}
|
|
1404
|
-
} catch {
|
|
1405
|
-
}
|
|
1406
|
-
return null;
|
|
1407
|
-
}
|
|
1408
|
-
function macFind(port) {
|
|
1409
|
-
try {
|
|
1410
|
-
const out = ex2.runOut("lsof", ["-nP", "-iTCP:" + port, "-sTCP:LISTEN"], { timeoutMs: 3e3 });
|
|
1411
|
-
if (!out) return null;
|
|
1412
|
-
return parseLsofPid(out);
|
|
1413
|
-
} catch {
|
|
1414
|
-
}
|
|
1415
|
-
return null;
|
|
1416
|
-
}
|
|
1417
|
-
function winFind(port) {
|
|
1418
|
-
try {
|
|
1419
|
-
const out = ex2.runOut("netstat", ["-ano"], { timeoutMs: 3e3 });
|
|
1420
|
-
if (!out) return null;
|
|
1421
|
-
return parseNetstatPid(out, port);
|
|
1422
|
-
} catch {
|
|
1423
|
-
}
|
|
1424
|
-
return null;
|
|
1425
|
-
}
|
|
1426
|
-
function linuxFindSs(port) {
|
|
1427
|
-
const candidates = ["ss", "/usr/sbin/ss", "/usr/bin/ss", "/bin/ss"];
|
|
1428
|
-
for (const ssBin of candidates) {
|
|
1429
|
-
if (ssBin.includes("/") && !isExecutableFile(ssBin)) continue;
|
|
1430
1459
|
try {
|
|
1431
|
-
|
|
1432
|
-
const pid = parseSsPid(out);
|
|
1433
|
-
if (pid !== null) return pid;
|
|
1460
|
+
fields.setPhase("STOPPED");
|
|
1434
1461
|
} catch {
|
|
1435
1462
|
}
|
|
1436
1463
|
}
|
|
1437
|
-
|
|
1438
|
-
}
|
|
1439
|
-
function isAlive(pid) {
|
|
1440
|
-
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
1441
|
-
try {
|
|
1442
|
-
process.kill(pid, 0);
|
|
1443
|
-
return true;
|
|
1444
|
-
} catch (e) {
|
|
1445
|
-
return !!e && e.code === "EPERM";
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
|
-
function isZombie(pid) {
|
|
1449
|
-
if (!Number.isInteger(pid) || pid <= 0 || isWindows) return false;
|
|
1450
|
-
if (isLinux) {
|
|
1464
|
+
function migrateMainRecord() {
|
|
1451
1465
|
try {
|
|
1452
|
-
const
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1466
|
+
const im = instances();
|
|
1467
|
+
if (!im || !Array.isArray(im.instances)) return;
|
|
1468
|
+
const idx = im.instances.findIndex((i) => i.id === "main");
|
|
1469
|
+
if (idx < 0) return;
|
|
1470
|
+
const main = im.instances[idx];
|
|
1471
|
+
const f = mainStore.dshMainFile();
|
|
1472
|
+
if (f && !fs2.existsSync(f)) {
|
|
1473
|
+
mainStore.writeDshMain({
|
|
1474
|
+
guardian: main.guardian === true,
|
|
1475
|
+
remoteMode: main.remoteEnabled === true ? main.frpEnabled === true ? "wan" : "lan" : "off",
|
|
1476
|
+
remoteToken: String(main.remoteToken || "")
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
im.instances.splice(idx, 1);
|
|
1480
|
+
if (im.save) {
|
|
1481
|
+
try {
|
|
1482
|
+
im.save();
|
|
1483
|
+
} catch {
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
const l = logger();
|
|
1487
|
+
if (l && l.info) l.info("[main] \u6982\u5FF5\u6E05\u5206\uFF1Amain \u8BB0\u5F55\u5DF2\u8FC1\u51FA instances.json \u2192 dsh-main.json");
|
|
1488
|
+
const ev = events();
|
|
1489
|
+
if (ev) ev.append("main_meta_migrated", {});
|
|
1490
|
+
} catch (e) {
|
|
1491
|
+
const l = logger();
|
|
1492
|
+
if (l && l.warn) l.warn("_migrateMainRecord: " + (e && e.message));
|
|
1457
1493
|
}
|
|
1458
1494
|
}
|
|
1459
|
-
|
|
1460
|
-
const o = ex2.runOut("ps", ["-o", "state=", "-p", String(pid)], { timeoutMs: 3e3 });
|
|
1461
|
-
return !!o && /^Z/.test(o.trim());
|
|
1462
|
-
} catch {
|
|
1463
|
-
return false;
|
|
1464
|
-
}
|
|
1495
|
+
return { writeState, loadState, migrateMainRecord };
|
|
1465
1496
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1497
|
+
module2.exports = { createStore };
|
|
1498
|
+
}
|
|
1499
|
+
});
|
|
1500
|
+
|
|
1501
|
+
// src/app/state/desired.js
|
|
1502
|
+
var require_desired = __commonJS({
|
|
1503
|
+
"src/app/state/desired.js"(exports2, module2) {
|
|
1504
|
+
"use strict";
|
|
1505
|
+
var fs2 = require("node:fs");
|
|
1506
|
+
var { writeAtomic } = require_fs();
|
|
1507
|
+
function createDesired(deps) {
|
|
1508
|
+
const g = deps || {};
|
|
1509
|
+
const fields = g.fields;
|
|
1510
|
+
const store = g.store;
|
|
1511
|
+
const intents = () => typeof g.getIntents === "function" ? g.getIntents() : null;
|
|
1512
|
+
const events = () => typeof g.getEvents === "function" ? g.getEvents() : null;
|
|
1513
|
+
const configPath = () => typeof g.getConfigPath === "function" ? g.getConfigPath() : null;
|
|
1514
|
+
const logger = () => typeof g.getLogger === "function" ? g.getLogger() : null;
|
|
1515
|
+
const setCrashHalted = typeof g.setCrashHalted === "function" ? g.setCrashHalted : () => {
|
|
1516
|
+
};
|
|
1517
|
+
const setManualRestart = typeof g.setManualRestart === "function" ? g.setManualRestart : () => {
|
|
1518
|
+
};
|
|
1519
|
+
const tick = () => {
|
|
1520
|
+
if (typeof g.tick === "function") g.tick();
|
|
1521
|
+
};
|
|
1522
|
+
const stopProcess = (why) => {
|
|
1523
|
+
if (typeof g.stopProcess === "function") g.stopProcess(why);
|
|
1524
|
+
};
|
|
1525
|
+
function setDesired(v) {
|
|
1526
|
+
if (v !== "running" && v !== "stopped") return { error: "invalid desired" };
|
|
1527
|
+
if (v === "running") {
|
|
1528
|
+
const it = intents();
|
|
1529
|
+
if (it) it.register("start");
|
|
1530
|
+
setCrashHalted(false);
|
|
1473
1531
|
}
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1532
|
+
if (v === "running" && fields.phase() === "OBSERVED") {
|
|
1533
|
+
fields.setObservedOnly(false);
|
|
1534
|
+
fields.setPhase("STOPPED");
|
|
1535
|
+
}
|
|
1536
|
+
if (v === "stopped" && fields.phase() === "OBSERVED" && fields.observedOnly()) {
|
|
1537
|
+
stopProcess("desired_stopped");
|
|
1538
|
+
}
|
|
1539
|
+
if (fields.desired() !== v) {
|
|
1540
|
+
fields.setDesired(v);
|
|
1541
|
+
const ev = events();
|
|
1542
|
+
if (ev) ev.append("desired_changed", { desired: v });
|
|
1543
|
+
store.writeState();
|
|
1481
1544
|
}
|
|
1545
|
+
tick();
|
|
1546
|
+
return { ok: true, desired: fields.desired() };
|
|
1482
1547
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
const ps = "(Get-CimInstance Win32_Process -Filter 'ProcessId=" + pid + "').CommandLine";
|
|
1489
|
-
const o = ex2.runOut("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { timeoutMs: 5e3 });
|
|
1490
|
-
return parsePowerShellCommandLine(o);
|
|
1548
|
+
function requestRestart() {
|
|
1549
|
+
if (fields.desired() === "stopped") {
|
|
1550
|
+
const ev2 = events();
|
|
1551
|
+
if (ev2) ev2.append("manual_restart_requested", { ignored: "desired=stopped" });
|
|
1552
|
+
return { ok: false, error: "desired=stopped\uFF0C\u8BF7\u5148 /start" };
|
|
1491
1553
|
}
|
|
1554
|
+
setManualRestart(true);
|
|
1555
|
+
setCrashHalted(false);
|
|
1556
|
+
const it = intents();
|
|
1557
|
+
if (it) it.register("restart");
|
|
1558
|
+
const ev = events();
|
|
1559
|
+
if (ev) ev.append("manual_restart_requested", {});
|
|
1560
|
+
tick();
|
|
1561
|
+
return { ok: true };
|
|
1492
1562
|
}
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
if (!cmd2) continue;
|
|
1506
|
-
out.push({ pid, cmdline: cmd2 });
|
|
1563
|
+
function persistConfigPatch(patch) {
|
|
1564
|
+
const p = configPath();
|
|
1565
|
+
if (!p) return false;
|
|
1566
|
+
const abort = (m) => {
|
|
1567
|
+
const l = logger();
|
|
1568
|
+
if (l && l.warn) l.warn("config persist aborted (fail-closed): " + m);
|
|
1569
|
+
const ev = events();
|
|
1570
|
+
if (ev) {
|
|
1571
|
+
try {
|
|
1572
|
+
ev.append("config_persist_aborted", { reason: m });
|
|
1573
|
+
} catch {
|
|
1574
|
+
}
|
|
1507
1575
|
}
|
|
1508
|
-
return
|
|
1509
|
-
}
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
let arr = [];
|
|
1576
|
+
return false;
|
|
1577
|
+
};
|
|
1578
|
+
try {
|
|
1579
|
+
let cur = {};
|
|
1580
|
+
let raw = null;
|
|
1514
1581
|
try {
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1582
|
+
raw = fs2.readFileSync(p, "utf8");
|
|
1583
|
+
} catch (e) {
|
|
1584
|
+
if (!e || e.code !== "ENOENT") return abort("read failed: " + (e && e.message || e));
|
|
1518
1585
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1586
|
+
if (raw !== null) {
|
|
1587
|
+
try {
|
|
1588
|
+
cur = JSON.parse(raw);
|
|
1589
|
+
if (!cur || typeof cur !== "object" || Array.isArray(cur)) throw new Error("root is not an object");
|
|
1590
|
+
} catch (e) {
|
|
1591
|
+
return abort("parse failed, original bytes preserved: " + (e && e.message || e));
|
|
1592
|
+
}
|
|
1526
1593
|
}
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1594
|
+
Object.assign(cur, patch);
|
|
1595
|
+
delete cur.switcherAutoStart;
|
|
1596
|
+
writeAtomic(p, JSON.stringify(cur, null, 2), { mode: 384 });
|
|
1597
|
+
return true;
|
|
1598
|
+
} catch (e) {
|
|
1599
|
+
const l = logger();
|
|
1600
|
+
if (l && l.warn) l.warn("config persist failed: " + e.message);
|
|
1601
|
+
return false;
|
|
1533
1602
|
}
|
|
1534
|
-
} catch {
|
|
1535
|
-
}
|
|
1536
|
-
return out;
|
|
1537
|
-
}
|
|
1538
|
-
module2.exports = {
|
|
1539
|
-
linuxListeningInodes,
|
|
1540
|
-
linuxFind,
|
|
1541
|
-
macFind,
|
|
1542
|
-
winFind,
|
|
1543
|
-
linuxFindSs,
|
|
1544
|
-
readCmdline,
|
|
1545
|
-
pgrepList,
|
|
1546
|
-
isAlive,
|
|
1547
|
-
isZombie
|
|
1548
|
-
};
|
|
1549
|
-
}
|
|
1550
|
-
});
|
|
1551
|
-
|
|
1552
|
-
// src/platform/os/pidlookup/index.js
|
|
1553
|
-
var require_pidlookup = __commonJS({
|
|
1554
|
-
"src/platform/os/pidlookup/index.js"(exports2, module2) {
|
|
1555
|
-
"use strict";
|
|
1556
|
-
var {
|
|
1557
|
-
parseProcNetTcpInodes,
|
|
1558
|
-
parseLsofPid,
|
|
1559
|
-
parseNetstatPid,
|
|
1560
|
-
parseSsPid,
|
|
1561
|
-
parseWmicCommandLine,
|
|
1562
|
-
parsePowerShellCommandLine,
|
|
1563
|
-
normCmdline
|
|
1564
|
-
} = require_norm();
|
|
1565
|
-
var {
|
|
1566
|
-
linuxFind,
|
|
1567
|
-
linuxFindSs,
|
|
1568
|
-
macFind,
|
|
1569
|
-
winFind,
|
|
1570
|
-
readCmdline,
|
|
1571
|
-
pgrepList,
|
|
1572
|
-
isAlive,
|
|
1573
|
-
isZombie
|
|
1574
|
-
} = require_probe();
|
|
1575
|
-
var isLinux = process.platform === "linux";
|
|
1576
|
-
var isMac = process.platform === "darwin";
|
|
1577
|
-
function findListeningPid(port) {
|
|
1578
|
-
if (!Number.isInteger(port) || port <= 0) return null;
|
|
1579
|
-
if (isLinux) {
|
|
1580
|
-
const a = linuxFind(port);
|
|
1581
|
-
if (a !== null && a !== void 0) return a;
|
|
1582
|
-
return linuxFindSs(port);
|
|
1583
1603
|
}
|
|
1584
|
-
|
|
1585
|
-
return winFind(port);
|
|
1586
|
-
}
|
|
1587
|
-
function isDshCmdline(pid) {
|
|
1588
|
-
const cmd2 = readCmdline(pid);
|
|
1589
|
-
if (!cmd2) return false;
|
|
1590
|
-
return /(^|\s)(node|.*dsh.*)(\s|$)/i.test(cmd2) && /dsh/i.test(cmd2);
|
|
1604
|
+
return { setDesired, requestRestart, persistConfigPatch };
|
|
1591
1605
|
}
|
|
1592
|
-
module2.exports = {
|
|
1593
|
-
findListeningPid,
|
|
1594
|
-
isAlive,
|
|
1595
|
-
isZombie,
|
|
1596
|
-
readCmdline,
|
|
1597
|
-
normCmdline,
|
|
1598
|
-
isDshCmdline,
|
|
1599
|
-
pgrepList,
|
|
1600
|
-
parseProcNetTcpInodes,
|
|
1601
|
-
parseLsofPid,
|
|
1602
|
-
parseNetstatPid,
|
|
1603
|
-
parseSsPid,
|
|
1604
|
-
parseWmicCommandLine,
|
|
1605
|
-
parsePowerShellCommandLine
|
|
1606
|
-
};
|
|
1606
|
+
module2.exports = { createDesired };
|
|
1607
1607
|
}
|
|
1608
1608
|
});
|
|
1609
1609
|
|
|
@@ -27806,6 +27806,7 @@ var path = require("node:path");
|
|
|
27806
27806
|
var os = require("node:os");
|
|
27807
27807
|
var http = require("node:http");
|
|
27808
27808
|
var ex = require_exec();
|
|
27809
|
+
var { readCmdline } = require_pidlookup();
|
|
27809
27810
|
function findPackageRoot(start) {
|
|
27810
27811
|
let d = start;
|
|
27811
27812
|
for (let i = 0; i < 6; i += 1) {
|
|
@@ -27918,12 +27919,31 @@ function apiRequest(method, apiPath) {
|
|
|
27918
27919
|
});
|
|
27919
27920
|
}
|
|
27920
27921
|
var LOCK_FILE = process.env.DSH_SUPERVISOR_LOCK_FILE || path.join(SUPERVISOR_DIR, "guard.lock");
|
|
27922
|
+
var LOCK_OWNER = { pid: process.pid, started: Date.now(), entry: process.argv[1] || "" };
|
|
27923
|
+
function readLock() {
|
|
27924
|
+
let raw;
|
|
27925
|
+
try {
|
|
27926
|
+
raw = fs.readFileSync(LOCK_FILE, "utf8");
|
|
27927
|
+
} catch {
|
|
27928
|
+
return null;
|
|
27929
|
+
}
|
|
27930
|
+
try {
|
|
27931
|
+
const j = JSON.parse(raw);
|
|
27932
|
+
if (j && Number.isInteger(j.pid) && j.pid > 0) return j;
|
|
27933
|
+
} catch {
|
|
27934
|
+
}
|
|
27935
|
+
const pid = parseInt(raw, 10);
|
|
27936
|
+
return Number.isInteger(pid) && pid > 0 ? { pid } : null;
|
|
27937
|
+
}
|
|
27938
|
+
function isOwnGuardEntry(cmdline) {
|
|
27939
|
+
return typeof cmdline === "string" && cmdline.includes("dsh-supervisor");
|
|
27940
|
+
}
|
|
27921
27941
|
function acquireLock() {
|
|
27922
27942
|
fs.mkdirSync(SUPERVISOR_DIR, { recursive: true });
|
|
27923
27943
|
const tryCreate = () => {
|
|
27924
27944
|
try {
|
|
27925
27945
|
const fd = fs.openSync(LOCK_FILE, "wx");
|
|
27926
|
-
fs.writeSync(fd,
|
|
27946
|
+
fs.writeSync(fd, JSON.stringify(LOCK_OWNER));
|
|
27927
27947
|
fs.closeSync(fd);
|
|
27928
27948
|
return true;
|
|
27929
27949
|
} catch (e) {
|
|
@@ -27933,18 +27953,19 @@ function acquireLock() {
|
|
|
27933
27953
|
}
|
|
27934
27954
|
};
|
|
27935
27955
|
if (tryCreate()) return true;
|
|
27936
|
-
|
|
27937
|
-
|
|
27938
|
-
|
|
27939
|
-
} catch {
|
|
27940
|
-
}
|
|
27941
|
-
if (Number.isInteger(holder) && holder > 0) {
|
|
27956
|
+
const held = readLock();
|
|
27957
|
+
if (held) {
|
|
27958
|
+
let alive = false;
|
|
27942
27959
|
try {
|
|
27943
|
-
process.kill(
|
|
27944
|
-
|
|
27960
|
+
process.kill(held.pid, 0);
|
|
27961
|
+
alive = true;
|
|
27945
27962
|
} catch (err) {
|
|
27946
|
-
|
|
27963
|
+
alive = err.code === "EPERM";
|
|
27947
27964
|
}
|
|
27965
|
+
const cmdline = alive ? readCmdline(held.pid) : null;
|
|
27966
|
+
if (alive && !cmdline) return false;
|
|
27967
|
+
if (alive && isOwnGuardEntry(cmdline)) return false;
|
|
27968
|
+
console.log("[supervisor] \u6E05\u7406\u9648\u65E7\u5B88\u536B\u9501\uFF08\u6301\u6709 pid " + held.pid + (alive ? " \u5B58\u6D3B\u4F46\u547D\u4EE4\u884C\u4E0D\u662F\u672C\u4EA7\u54C1\u7684\u5B88\u536B\u5165\u53E3\uFF1A" + cmdline : " \u5DF2\u9000\u51FA") + "\uFF09");
|
|
27948
27969
|
}
|
|
27949
27970
|
try {
|
|
27950
27971
|
fs.unlinkSync(LOCK_FILE);
|
|
@@ -27954,10 +27975,8 @@ function acquireLock() {
|
|
|
27954
27975
|
}
|
|
27955
27976
|
function releaseLock() {
|
|
27956
27977
|
try {
|
|
27957
|
-
|
|
27958
|
-
|
|
27959
|
-
if (holder === process.pid) fs.unlinkSync(LOCK_FILE);
|
|
27960
|
-
}
|
|
27978
|
+
const held = readLock();
|
|
27979
|
+
if (held && held.pid === process.pid) fs.unlinkSync(LOCK_FILE);
|
|
27961
27980
|
} catch {
|
|
27962
27981
|
}
|
|
27963
27982
|
}
|