dsh-update-status 0.4.0 → 0.4.2
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/CHANGELOG.md +14 -0
- package/README.md +10 -8
- package/README.zh.md +10 -8
- package/docs/platform-acceptance.md +4 -4
- package/docs/service-supervision.md +14 -7
- package/lib/client.js.map +1 -1
- package/lib/index.js +3 -2
- package/lib/{plan-BornHBEZ.js → plan-D9Ybaj-3.js} +184 -25
- package/lib/service-cli.d.ts +36 -0
- package/lib/service-cli.js +152 -63
- package/package.json +3 -2
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as recordBootStamp, S as dshHomeOf, _ as parseSystemdMainPid, a as planFor, b as bootStampFile, f as LAUNCHD_LABEL, g as parseLaunchdTrackedPid, p as SYSTEMD_UNIT, w as serviceLogDir, x as countRecentRestarts, y as RESTART_STORM_WINDOW_MS } from "./plan-D9Ybaj-3.js";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
4
4
|
import { basename, dirname, join, normalize, sep } from "node:path";
|
|
@@ -21,7 +21,8 @@ const VERIFIED_DSH_VERSIONS = [
|
|
|
21
21
|
"0.1.7-rc.2",
|
|
22
22
|
"0.2.0-rc.1",
|
|
23
23
|
"0.2.0-rc.2",
|
|
24
|
-
"0.2.1-alpha.1"
|
|
24
|
+
"0.2.1-alpha.1",
|
|
25
|
+
"0.2.1-alpha.3"
|
|
25
26
|
];
|
|
26
27
|
function isCacheTtlMinutes(value) {
|
|
27
28
|
return typeof value === "number" && Number.isInteger(value) && value >= 30 && value <= 1440;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import { dirname, isAbsolute, join, posix, resolve, win32 } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
//#region src/shared/restart-evidence.ts
|
|
6
6
|
/**
|
|
@@ -165,15 +165,135 @@ function parseWindowsTaskRunning(output) {
|
|
|
165
165
|
return /(?:^|\W)running(?:\W|$)/i.test(output);
|
|
166
166
|
}
|
|
167
167
|
//#endregion
|
|
168
|
+
//#region src/service/service-path.ts
|
|
169
|
+
/** Resolve one audited PATH that preflight and the native service both consume. */
|
|
170
|
+
/** A service definition must stay inspectable; never silently truncate it. */
|
|
171
|
+
const MAX_SERVICE_PATH_LENGTH = 8192;
|
|
172
|
+
const MINIMAL_POSIX = {
|
|
173
|
+
darwin: [
|
|
174
|
+
"/usr/local/bin",
|
|
175
|
+
"/usr/bin",
|
|
176
|
+
"/bin",
|
|
177
|
+
"/usr/sbin",
|
|
178
|
+
"/sbin"
|
|
179
|
+
],
|
|
180
|
+
linux: [
|
|
181
|
+
"/usr/local/bin",
|
|
182
|
+
"/usr/bin",
|
|
183
|
+
"/bin"
|
|
184
|
+
]
|
|
185
|
+
};
|
|
186
|
+
const DEFAULT_WINDOWS_PATHEXT = ".COM;.EXE;.BAT;.CMD";
|
|
187
|
+
function normalizeServicePathExt(value) {
|
|
188
|
+
const raw = value?.trim() || DEFAULT_WINDOWS_PATHEXT;
|
|
189
|
+
validateText(raw);
|
|
190
|
+
const seen = /* @__PURE__ */ new Set();
|
|
191
|
+
const extensions = [];
|
|
192
|
+
for (const original of raw.split(";")) {
|
|
193
|
+
const extension = original.trim();
|
|
194
|
+
if (extension === "") continue;
|
|
195
|
+
if (!/^\.[A-Za-z0-9]+$/.test(extension)) throw new Error(`invalid PATHEXT entry: ${extension}`);
|
|
196
|
+
const key = extension.toUpperCase();
|
|
197
|
+
if (seen.has(key)) continue;
|
|
198
|
+
seen.add(key);
|
|
199
|
+
extensions.push(extension);
|
|
200
|
+
}
|
|
201
|
+
if (extensions.length === 0) throw new Error("PATHEXT has no usable extension");
|
|
202
|
+
return extensions.join(";");
|
|
203
|
+
}
|
|
204
|
+
function delimiter(platform) {
|
|
205
|
+
return platform === "win32" ? ";" : ":";
|
|
206
|
+
}
|
|
207
|
+
function nodeDirectory(platform, nodePath) {
|
|
208
|
+
return platform === "win32" ? win32.dirname(nodePath) : posix.dirname(nodePath);
|
|
209
|
+
}
|
|
210
|
+
function isAbsolute$1(platform, value) {
|
|
211
|
+
return platform === "win32" ? win32.isAbsolute(value) : posix.isAbsolute(value);
|
|
212
|
+
}
|
|
213
|
+
function minimalEntries(platform, nodePath, override) {
|
|
214
|
+
const node = nodeDirectory(platform, nodePath);
|
|
215
|
+
if (override !== void 0 && override.trim() !== "") return [node, ...override.split(delimiter(platform))];
|
|
216
|
+
if (platform === "win32") return [node];
|
|
217
|
+
return [node, ...MINIMAL_POSIX[platform]];
|
|
218
|
+
}
|
|
219
|
+
function sourceValue(options) {
|
|
220
|
+
if (options.source === "minimal") return minimalEntries(options.platform, options.nodePath, options.minimalPath).join(delimiter(options.platform));
|
|
221
|
+
if (options.source === "explicit") {
|
|
222
|
+
if (options.explicitPath === void 0 || options.explicitPath.trim() === "") throw new Error("`--service-path` is required when `--path-source explicit` is used");
|
|
223
|
+
return options.explicitPath;
|
|
224
|
+
}
|
|
225
|
+
if (options.currentPath === void 0 || options.currentPath.trim() === "") throw new Error("current PATH is empty; use `--path-source minimal` or `--service-path`");
|
|
226
|
+
return options.currentPath;
|
|
227
|
+
}
|
|
228
|
+
function validateText(value) {
|
|
229
|
+
if (/[\u0000-\u0008\u000A-\u001F\u007F]/.test(value)) throw new Error("service PATH must not contain control characters or line breaks");
|
|
230
|
+
if (value.length > 8192) throw new Error(`service PATH is too long (maximum ${String(MAX_SERVICE_PATH_LENGTH)} characters); use --service-path with a shorter value`);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Resolve at install/plan time — no user rc file is executed. Missing absolute
|
|
234
|
+
* directories are preserved (they may be mounted or created later) and reported.
|
|
235
|
+
*/
|
|
236
|
+
function resolveServicePath(options) {
|
|
237
|
+
const split = delimiter(options.platform);
|
|
238
|
+
const raw = sourceValue(options);
|
|
239
|
+
validateText(raw);
|
|
240
|
+
if (options.platform !== "win32" && /(?:^|;)[A-Za-z]:[\\/]/.test(raw)) throw new Error("Windows-style PATH cannot be used for Linux/WSL; provide a colon-separated PATH");
|
|
241
|
+
const exists = options.exists ?? existsSync;
|
|
242
|
+
const warnings = [];
|
|
243
|
+
const values = [nodeDirectory(options.platform, options.nodePath), ...raw.split(split)];
|
|
244
|
+
const seen = /* @__PURE__ */ new Set();
|
|
245
|
+
const entries = [];
|
|
246
|
+
let warnedEmpty = false;
|
|
247
|
+
for (const rawEntry of values) {
|
|
248
|
+
if (rawEntry === "") {
|
|
249
|
+
if (!warnedEmpty) warnings.push("ignored empty PATH entry (current-directory lookup)");
|
|
250
|
+
warnedEmpty = true;
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const entry = options.platform === "win32" && rawEntry.length >= 2 && rawEntry.startsWith("\"") && rawEntry.endsWith("\"") ? rawEntry.slice(1, -1) : rawEntry;
|
|
254
|
+
if (!isAbsolute$1(options.platform, entry)) {
|
|
255
|
+
warnings.push(`ignored relative PATH entry: ${entry}`);
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const key = options.platform === "win32" ? entry.toLowerCase() : entry;
|
|
259
|
+
if (seen.has(key)) continue;
|
|
260
|
+
seen.add(key);
|
|
261
|
+
entries.push(entry);
|
|
262
|
+
if (!exists(entry)) warnings.push(`PATH directory does not exist yet: ${entry}`);
|
|
263
|
+
}
|
|
264
|
+
const value = entries.join(split);
|
|
265
|
+
if (value === "") throw new Error("service PATH has no absolute directory");
|
|
266
|
+
validateText(value);
|
|
267
|
+
const pathExt = options.platform === "win32" ? normalizeServicePathExt(options.currentPathExt) : void 0;
|
|
268
|
+
return {
|
|
269
|
+
source: options.source,
|
|
270
|
+
value,
|
|
271
|
+
...pathExt === void 0 ? {} : { pathExt },
|
|
272
|
+
warnings
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/** Old receipts had no PATH fields; keep their exact historical minimal shape. */
|
|
276
|
+
function servicePathOf(spec) {
|
|
277
|
+
return spec.servicePath ?? minimalEntries(spec.platform, spec.nodePath).join(delimiter(spec.platform));
|
|
278
|
+
}
|
|
279
|
+
//#endregion
|
|
168
280
|
//#region src/service/plan.ts
|
|
169
281
|
/** Build transparent per-OS user-service definitions; do not install them here. */
|
|
170
282
|
const SERVICE_LABEL = LAUNCHD_LABEL;
|
|
171
283
|
const SUPERVISOR_MARKER = "dsh-update-status";
|
|
284
|
+
function nativeServiceCommandCandidates(platform, systemRoot) {
|
|
285
|
+
if (platform === "darwin") return ["/bin/launchctl"];
|
|
286
|
+
if (platform === "linux") return ["/usr/bin/systemctl", "/bin/systemctl"];
|
|
287
|
+
return [`${systemRoot ?? "C:\\Windows"}\\System32\\schtasks.exe`];
|
|
288
|
+
}
|
|
289
|
+
function nativeServiceCommandOf(spec) {
|
|
290
|
+
return spec.nativeServiceCommand ?? nativeServiceCommandCandidates(spec.platform)[0];
|
|
291
|
+
}
|
|
172
292
|
function xml(value) {
|
|
173
293
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
174
294
|
}
|
|
175
295
|
function systemd(value) {
|
|
176
|
-
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
296
|
+
return value.replace(/%/g, "%%").replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
177
297
|
}
|
|
178
298
|
function powerShell(value) {
|
|
179
299
|
return value.replace(/'/g, "''");
|
|
@@ -216,6 +336,24 @@ function servicePlatform(value) {
|
|
|
216
336
|
if (value === "darwin" || value === "linux" || value === "win32") return value;
|
|
217
337
|
throw new Error(`unsupported platform: ${value}; supported: macOS, Linux, Windows`);
|
|
218
338
|
}
|
|
339
|
+
function envValue(env, key, platform) {
|
|
340
|
+
if (platform !== "win32") return env[key];
|
|
341
|
+
return Object.entries(env).find(([name]) => name.toLowerCase() === key.toLowerCase())?.[1];
|
|
342
|
+
}
|
|
343
|
+
function pathSourceOf(args) {
|
|
344
|
+
const explicit = valueAfter(args, "--service-path");
|
|
345
|
+
const raw = valueAfter(args, "--path-source");
|
|
346
|
+
if (raw === void 0) return explicit === void 0 ? "current" : "explicit";
|
|
347
|
+
if (raw !== "current" && raw !== "minimal" && raw !== "explicit") throw new Error("`--path-source` must be current, minimal, or explicit");
|
|
348
|
+
if (explicit !== void 0 && raw !== "explicit") throw new Error("`--service-path` requires `--path-source explicit` (or omit --path-source)");
|
|
349
|
+
return raw;
|
|
350
|
+
}
|
|
351
|
+
function serviceStateFileFromArgs(args, env) {
|
|
352
|
+
const home = env.home || homedir();
|
|
353
|
+
const dshHome = valueAfter(args, "--dsh-home") ?? (env.env.DSH_HOME?.trim() || void 0);
|
|
354
|
+
if (dshHome !== void 0 && !isAbsolute(dshHome)) throw new Error("`--dsh-home` must be an absolute path");
|
|
355
|
+
return join(dshHome ?? join(home, ".dsh"), "dsh-update-status-service.json");
|
|
356
|
+
}
|
|
219
357
|
function specFromArgs(args, env) {
|
|
220
358
|
const platform = servicePlatform(env.platform);
|
|
221
359
|
const profile = valueAfter(args, "--profile") ?? env.env.DSH_PROFILE ?? "web";
|
|
@@ -233,6 +371,20 @@ function specFromArgs(args, env) {
|
|
|
233
371
|
if (!isAbsolute(dshPath)) throw new Error("`--dsh` must be an absolute executable path");
|
|
234
372
|
if (!isAbsolute(workspace)) throw new Error("`--workspace` must be an absolute path");
|
|
235
373
|
if (!isAbsolute(logDir)) throw new Error("`--log-dir` must be an absolute path");
|
|
374
|
+
const systemRoot = envValue(env.env, "SYSTEMROOT", platform);
|
|
375
|
+
const pathExtOverride = valueAfter(args, "--service-pathext");
|
|
376
|
+
if (pathExtOverride !== void 0 && platform !== "win32") throw new Error("`--service-pathext` is supported only on Windows");
|
|
377
|
+
const candidates = nativeServiceCommandCandidates(platform, systemRoot);
|
|
378
|
+
const nativeServiceCommand = platform === "linux" ? candidates.find((candidate) => existsSync(candidate)) ?? candidates[0] : candidates[0];
|
|
379
|
+
const servicePath = resolveServicePath({
|
|
380
|
+
platform,
|
|
381
|
+
nodePath,
|
|
382
|
+
source: pathSourceOf(args),
|
|
383
|
+
currentPath: env.path ?? envValue(env.env, "PATH", platform),
|
|
384
|
+
currentPathExt: pathExtOverride ?? envValue(env.env, "PATHEXT", platform),
|
|
385
|
+
explicitPath: valueAfter(args, "--service-path"),
|
|
386
|
+
minimalPath: platform === "win32" && systemRoot !== void 0 ? `${systemRoot}\\System32;${systemRoot}` : void 0
|
|
387
|
+
});
|
|
236
388
|
return {
|
|
237
389
|
schemaVersion: 1,
|
|
238
390
|
platform,
|
|
@@ -246,6 +398,12 @@ function specFromArgs(args, env) {
|
|
|
246
398
|
home,
|
|
247
399
|
...dshHome === void 0 ? {} : { dshHome },
|
|
248
400
|
logDir,
|
|
401
|
+
servicePath: servicePath.value,
|
|
402
|
+
servicePathSource: servicePath.source,
|
|
403
|
+
servicePathCapturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
404
|
+
...servicePath.pathExt === void 0 ? {} : { servicePathExt: servicePath.pathExt },
|
|
405
|
+
...servicePath.warnings.length === 0 ? {} : { servicePathWarnings: servicePath.warnings },
|
|
406
|
+
nativeServiceCommand,
|
|
249
407
|
supervisorMarker: SUPERVISOR_MARKER
|
|
250
408
|
};
|
|
251
409
|
}
|
|
@@ -292,7 +450,7 @@ function webArguments(spec) {
|
|
|
292
450
|
}
|
|
293
451
|
function launchdWrapper(spec, paths, uid) {
|
|
294
452
|
const args = [spec.nodePath, ...webArguments(spec)].map(shQuote).join(" ");
|
|
295
|
-
const kickstart =
|
|
453
|
+
const kickstart = `${shQuote(nativeServiceCommandOf(spec))} kickstart -k gui/${String(uid)}/${spec.label}`;
|
|
296
454
|
return `#!/bin/sh
|
|
297
455
|
# Managed by dsh-update-status. This wrapper, not launchd, owns the restart loop.
|
|
298
456
|
#
|
|
@@ -349,7 +507,7 @@ function launchdDefinition(spec, paths) {
|
|
|
349
507
|
const args = ["/bin/sh", wrapper].map((value) => ` <string>${xml(value)}</string>`).join("\n");
|
|
350
508
|
const envXml = [
|
|
351
509
|
["HOME", spec.home],
|
|
352
|
-
["PATH",
|
|
510
|
+
["PATH", servicePathOf(spec)],
|
|
353
511
|
["DSH_WEB_SUPERVISOR", spec.supervisorMarker],
|
|
354
512
|
...spec.dshHome === void 0 ? [] : [["DSH_HOME", spec.dshHome]]
|
|
355
513
|
].map(([key, value]) => ` <key>${xml(key)}</key>\n <string>${xml(value)}</string>`).join("\n");
|
|
@@ -383,7 +541,7 @@ function systemdDefinition(spec) {
|
|
|
383
541
|
const command = [spec.nodePath, ...webArguments(spec)].map((value) => `"${systemd(value)}"`).join(" ");
|
|
384
542
|
const env = [
|
|
385
543
|
`Environment="HOME=${systemd(spec.home)}"`,
|
|
386
|
-
`Environment="PATH=${systemd(
|
|
544
|
+
`Environment="PATH=${systemd(servicePathOf(spec))}"`,
|
|
387
545
|
`Environment="DSH_WEB_SUPERVISOR=${spec.supervisorMarker}"`,
|
|
388
546
|
...spec.dshHome === void 0 ? [] : [`Environment="DSH_HOME=${systemd(spec.dshHome)}"`]
|
|
389
547
|
].join("\n");
|
|
@@ -418,7 +576,7 @@ function windowsWrapper(spec, paths) {
|
|
|
418
576
|
const dshHome = spec.dshHome === void 0 ? "" : `$env:DSH_HOME = '${powerShell(spec.dshHome)}'\n`;
|
|
419
577
|
return `$ErrorActionPreference = 'Stop'
|
|
420
578
|
$env:HOME = '${home}'
|
|
421
|
-
$env:DSH_WEB_SUPERVISOR = '${spec.supervisorMarker}'
|
|
579
|
+
${spec.servicePath === void 0 ? "" : `$env:PATH = '${powerShell(spec.servicePath)}'\n$env:PATHEXT = '${powerShell(spec.servicePathExt ?? ".COM;.EXE;.BAT;.CMD")}'\n`}$env:DSH_WEB_SUPERVISOR = '${spec.supervisorMarker}'
|
|
422
580
|
${dshHome}Set-Location -LiteralPath '${workspace}'
|
|
423
581
|
$rapidWindowSeconds = ${String(30)}
|
|
424
582
|
$rapidLimit = ${String(5)}
|
|
@@ -463,6 +621,7 @@ function windowsDefinition(spec, paths) {
|
|
|
463
621
|
/** Generate a service plan without writing, starting, or stopping anything. */
|
|
464
622
|
function planFor(spec, uid = 0) {
|
|
465
623
|
const paths = pathsFor(spec);
|
|
624
|
+
const control = nativeServiceCommandOf(spec);
|
|
466
625
|
if (spec.platform === "darwin") {
|
|
467
626
|
const domain = `gui/${uid}`;
|
|
468
627
|
return {
|
|
@@ -471,30 +630,30 @@ function planFor(spec, uid = 0) {
|
|
|
471
630
|
definition: launchdDefinition(spec, paths),
|
|
472
631
|
wrapper: launchdWrapper(spec, paths, uid),
|
|
473
632
|
installCommand: [
|
|
474
|
-
|
|
633
|
+
control,
|
|
475
634
|
"bootstrap",
|
|
476
635
|
domain,
|
|
477
636
|
paths.definitionFile
|
|
478
637
|
],
|
|
479
638
|
startCommand: [
|
|
480
|
-
|
|
639
|
+
control,
|
|
481
640
|
"kickstart",
|
|
482
641
|
"-k",
|
|
483
642
|
`${domain}/${spec.label}`
|
|
484
643
|
],
|
|
485
|
-
recoverCommand:
|
|
644
|
+
recoverCommand: `${shQuote(control)} kickstart -k ${domain}/${spec.label}`,
|
|
486
645
|
statusCommand: [
|
|
487
|
-
|
|
646
|
+
control,
|
|
488
647
|
"print",
|
|
489
648
|
`${domain}/${spec.label}`
|
|
490
649
|
],
|
|
491
650
|
stopCommand: [
|
|
492
|
-
|
|
651
|
+
control,
|
|
493
652
|
"bootout",
|
|
494
653
|
`${domain}/${spec.label}`
|
|
495
654
|
],
|
|
496
655
|
uninstallCommand: [
|
|
497
|
-
|
|
656
|
+
control,
|
|
498
657
|
"bootout",
|
|
499
658
|
`${domain}/${spec.label}`
|
|
500
659
|
]
|
|
@@ -505,33 +664,33 @@ function planFor(spec, uid = 0) {
|
|
|
505
664
|
paths,
|
|
506
665
|
definition: systemdDefinition(spec),
|
|
507
666
|
installCommand: [
|
|
508
|
-
|
|
667
|
+
control,
|
|
509
668
|
"--user",
|
|
510
669
|
"daemon-reload"
|
|
511
670
|
],
|
|
512
671
|
startCommand: [
|
|
513
|
-
|
|
672
|
+
control,
|
|
514
673
|
"--user",
|
|
515
674
|
"enable",
|
|
516
675
|
"--now",
|
|
517
676
|
"dsh-update-status-web.service"
|
|
518
677
|
],
|
|
519
|
-
recoverCommand:
|
|
678
|
+
recoverCommand: `${shQuote(control)} --user reset-failed ${SYSTEMD_UNIT} && ${shQuote(control)} --user enable --now ${SYSTEMD_UNIT}`,
|
|
520
679
|
statusCommand: [
|
|
521
|
-
|
|
680
|
+
control,
|
|
522
681
|
"--user",
|
|
523
682
|
"status",
|
|
524
683
|
"dsh-update-status-web.service"
|
|
525
684
|
],
|
|
526
685
|
stopCommand: [
|
|
527
|
-
|
|
686
|
+
control,
|
|
528
687
|
"--user",
|
|
529
688
|
"disable",
|
|
530
689
|
"--now",
|
|
531
690
|
"dsh-update-status-web.service"
|
|
532
691
|
],
|
|
533
692
|
uninstallCommand: [
|
|
534
|
-
|
|
693
|
+
control,
|
|
535
694
|
"--user",
|
|
536
695
|
"disable",
|
|
537
696
|
"--now",
|
|
@@ -544,7 +703,7 @@ function planFor(spec, uid = 0) {
|
|
|
544
703
|
definition: windowsDefinition(spec, paths),
|
|
545
704
|
wrapper: windowsWrapper(spec, paths),
|
|
546
705
|
installCommand: [
|
|
547
|
-
|
|
706
|
+
control,
|
|
548
707
|
"/Create",
|
|
549
708
|
"/TN",
|
|
550
709
|
"DSH Update Status Web",
|
|
@@ -553,14 +712,14 @@ function planFor(spec, uid = 0) {
|
|
|
553
712
|
"/F"
|
|
554
713
|
],
|
|
555
714
|
startCommand: [
|
|
556
|
-
|
|
715
|
+
control,
|
|
557
716
|
"/Run",
|
|
558
717
|
"/TN",
|
|
559
718
|
"DSH Update Status Web"
|
|
560
719
|
],
|
|
561
|
-
recoverCommand: "
|
|
720
|
+
recoverCommand: `"${control}" /Run /TN "DSH Update Status Web"`,
|
|
562
721
|
statusCommand: [
|
|
563
|
-
|
|
722
|
+
control,
|
|
564
723
|
"/Query",
|
|
565
724
|
"/TN",
|
|
566
725
|
"DSH Update Status Web",
|
|
@@ -569,13 +728,13 @@ function planFor(spec, uid = 0) {
|
|
|
569
728
|
"LIST"
|
|
570
729
|
],
|
|
571
730
|
stopCommand: [
|
|
572
|
-
|
|
731
|
+
control,
|
|
573
732
|
"/End",
|
|
574
733
|
"/TN",
|
|
575
734
|
"DSH Update Status Web"
|
|
576
735
|
],
|
|
577
736
|
uninstallCommand: [
|
|
578
|
-
|
|
737
|
+
control,
|
|
579
738
|
"/Delete",
|
|
580
739
|
"/TN",
|
|
581
740
|
"DSH Update Status Web",
|
|
@@ -584,4 +743,4 @@ function planFor(spec, uid = 0) {
|
|
|
584
743
|
};
|
|
585
744
|
}
|
|
586
745
|
//#endregion
|
|
587
|
-
export {
|
|
746
|
+
export { recordBootStamp as C, dshHomeOf as S, parseSystemdMainPid as _, planFor as a, bootStampFile as b, specFromArgs as c, servicePathOf as d, LAUNCHD_LABEL as f, parseLaunchdTrackedPid as g, WINDOWS_WRAPPER_BASENAME as h, pathsFor as i, MAX_SERVICE_PATH_LENGTH as l, WINDOWS_TASK_NAME as m, nativeServiceCommandCandidates as n, servicePlatform as o, SYSTEMD_UNIT as p, nativeServiceCommandOf as r, serviceStateFileFromArgs as s, SERVICE_LABEL as t, normalizeServicePathExt as u, parseWindowsTaskRunning as v, serviceLogDir as w, countRecentRestarts as x, RESTART_STORM_WINDOW_MS as y };
|
package/lib/service-cli.d.ts
CHANGED
|
@@ -16,9 +16,44 @@ interface ServiceSpec {
|
|
|
16
16
|
readonly home: string;
|
|
17
17
|
readonly dshHome?: string;
|
|
18
18
|
readonly logDir: string;
|
|
19
|
+
/** Final audited PATH persisted by install and reused by every later action. */
|
|
20
|
+
readonly servicePath?: string;
|
|
21
|
+
readonly servicePathSource?: 'current' | 'minimal' | 'explicit';
|
|
22
|
+
readonly servicePathCapturedAt?: string;
|
|
23
|
+
/** Windows command extension lookup, persisted alongside PATH. */
|
|
24
|
+
readonly servicePathExt?: string;
|
|
25
|
+
/** Human-readable warnings retained in the receipt and dry-run output. */
|
|
26
|
+
readonly servicePathWarnings?: readonly string[];
|
|
27
|
+
/** Absolute launchctl/systemctl/schtasks path; later actions never search PATH. */
|
|
28
|
+
readonly nativeServiceCommand?: string;
|
|
19
29
|
/** Written by the user-service definition, never inferred from a TTY. */
|
|
20
30
|
readonly supervisorMarker: 'dsh-update-status';
|
|
21
31
|
}
|
|
32
|
+
interface ServicePaths {
|
|
33
|
+
readonly stateFile: string;
|
|
34
|
+
readonly definitionFile: string;
|
|
35
|
+
/** macOS and Windows: the wrapper that owns the restart loop. */
|
|
36
|
+
readonly wrapperFile?: string;
|
|
37
|
+
readonly stdoutFile: string;
|
|
38
|
+
readonly stderrFile: string;
|
|
39
|
+
}
|
|
40
|
+
interface ServicePlan {
|
|
41
|
+
readonly spec: ServiceSpec;
|
|
42
|
+
readonly paths: ServicePaths;
|
|
43
|
+
readonly definition: string;
|
|
44
|
+
readonly wrapper?: string;
|
|
45
|
+
readonly installCommand: readonly string[];
|
|
46
|
+
readonly startCommand: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* One copy-only line that lets the service take over again after it stopped
|
|
49
|
+
* (a tripped start limit, a given-up wrapper). Displayed only — never run by
|
|
50
|
+
* the plugin.
|
|
51
|
+
*/
|
|
52
|
+
readonly recoverCommand: string;
|
|
53
|
+
readonly statusCommand: readonly string[];
|
|
54
|
+
readonly stopCommand: readonly string[];
|
|
55
|
+
readonly uninstallCommand: readonly string[];
|
|
56
|
+
}
|
|
22
57
|
interface CliEnvironment {
|
|
23
58
|
readonly platform: NodeJS.Platform;
|
|
24
59
|
readonly home: string;
|
|
@@ -49,6 +84,7 @@ type ServiceVerification = {
|
|
|
49
84
|
};
|
|
50
85
|
//#endregion
|
|
51
86
|
//#region src/service/cli.d.ts
|
|
87
|
+
export declare function serialisePlan(plan: ServicePlan): string;
|
|
52
88
|
export interface CliHooks {
|
|
53
89
|
readonly preflight?: (spec: ServiceSpec) => void;
|
|
54
90
|
/** Injected in tests; defaults to the real post-activation verification. */
|