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/service-cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as parseSystemdMainPid, a as planFor, b as bootStampFile, c as specFromArgs, d as servicePathOf, g as parseLaunchdTrackedPid, i as pathsFor, m as WINDOWS_TASK_NAME, n as nativeServiceCommandCandidates, o as servicePlatform, p as SYSTEMD_UNIT, r as nativeServiceCommandOf, s as serviceStateFileFromArgs, t as SERVICE_LABEL, u as normalizeServicePathExt, v as parseWindowsTaskRunning, w as serviceLogDir, x as countRecentRestarts, y as RESTART_STORM_WINDOW_MS } from "./plan-D9Ybaj-3.js";
|
|
2
2
|
import { accessSync, constants, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { dirname } from "node:path";
|
|
3
|
+
import { dirname, isAbsolute } from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { createServer } from "node:net";
|
|
6
6
|
async function observeServiceState(spec, run, uid) {
|
|
@@ -103,8 +103,15 @@ Options:
|
|
|
103
103
|
--host <127.0.0.1|0.0.0.0> Bind host (default: 127.0.0.1)
|
|
104
104
|
--port <1..65535> Web port (default: 3080)
|
|
105
105
|
--node <path> Absolute Node executable (default: current Node)
|
|
106
|
-
--dsh <path> Absolute dsh executable (default: resolve from
|
|
106
|
+
--dsh <path> Absolute dsh executable (default: resolve from profile)
|
|
107
107
|
--log-dir <path> Absolute log directory (default: $DSH_HOME/logs)
|
|
108
|
+
--path-source <mode> Service PATH source: current (default), minimal, explicit
|
|
109
|
+
--service-path <value> Explicit PATH (implies --path-source explicit)
|
|
110
|
+
--service-pathext <v> Windows PATHEXT override (for example .COM;.EXE;.CMD)
|
|
111
|
+
|
|
112
|
+
current snapshots this command's PATH; it never executes your shell startup files.
|
|
113
|
+
The final PATH, source, capture time and warnings are stored in the receipt and
|
|
114
|
+
reused by preflight and every later service action.
|
|
108
115
|
|
|
109
116
|
Workflow: plan --dry-run → install → stop the terminal-started DSH yourself → activate.
|
|
110
117
|
|
|
@@ -114,7 +121,7 @@ makes activate fail instead of reporting success.
|
|
|
114
121
|
`;
|
|
115
122
|
}
|
|
116
123
|
function assertSafeText(value, description) {
|
|
117
|
-
if (/[\u0000\
|
|
124
|
+
if (/[\u0000-\u0008\u000A-\u001F\u007F]/.test(value)) throw new Error(`${description} must not contain XML-illegal control characters or line breaks`);
|
|
118
125
|
}
|
|
119
126
|
function assertReadableRegular(path, description) {
|
|
120
127
|
assertSafeText(path, description);
|
|
@@ -135,20 +142,73 @@ function assertExecutable(path, description) {
|
|
|
135
142
|
throw new Error(`${description} is not executable: ${path}`);
|
|
136
143
|
}
|
|
137
144
|
}
|
|
138
|
-
function
|
|
145
|
+
function envValue(env, key) {
|
|
146
|
+
return Object.entries(env).find(([name]) => name.toLowerCase() === key.toLowerCase())?.[1];
|
|
147
|
+
}
|
|
148
|
+
function validateSpec(spec, level = "launch", expectedPlatform, expectedHome, expectedSystemRoot) {
|
|
149
|
+
if (spec.schemaVersion !== 1) throw new Error("managed service receipt has an unsupported schema version");
|
|
150
|
+
if (spec.platform !== "darwin" && spec.platform !== "linux" && spec.platform !== "win32") throw new Error("managed service receipt has an invalid platform");
|
|
151
|
+
if (expectedPlatform !== void 0 && spec.platform !== expectedPlatform) throw new Error("managed service receipt belongs to a different platform");
|
|
152
|
+
if (spec.label !== SERVICE_LABEL || spec.supervisorMarker !== "dsh-update-status") throw new Error("managed service receipt has an unexpected service identity");
|
|
153
|
+
if (expectedHome !== void 0 && spec.home !== expectedHome) throw new Error("managed service receipt belongs to a different home directory");
|
|
139
154
|
for (const [description, value] of [
|
|
140
155
|
["profile", spec.profile],
|
|
141
156
|
["workspace", spec.workspace],
|
|
142
157
|
["home", spec.home],
|
|
143
158
|
["log directory", spec.logDir],
|
|
144
|
-
["host", spec.host]
|
|
145
|
-
|
|
159
|
+
["host", spec.host],
|
|
160
|
+
["Node executable", spec.nodePath],
|
|
161
|
+
["dsh executable", spec.dshPath]
|
|
162
|
+
]) {
|
|
163
|
+
if (typeof value !== "string") throw new Error(`managed service receipt has an invalid ${description}`);
|
|
164
|
+
assertSafeText(value, description);
|
|
165
|
+
}
|
|
166
|
+
for (const [description, value] of [
|
|
167
|
+
["workspace", spec.workspace],
|
|
168
|
+
["home", spec.home],
|
|
169
|
+
["log directory", spec.logDir],
|
|
170
|
+
["Node executable", spec.nodePath],
|
|
171
|
+
["dsh executable", spec.dshPath]
|
|
172
|
+
]) if (!isAbsolute(value)) throw new Error(`managed service receipt has a non-absolute ${description}`);
|
|
173
|
+
if (spec.dshHome !== void 0) {
|
|
174
|
+
if (typeof spec.dshHome !== "string") throw new Error("managed service receipt has an invalid DSH_HOME");
|
|
175
|
+
assertSafeText(spec.dshHome, "DSH_HOME");
|
|
176
|
+
if (!isAbsolute(spec.dshHome)) throw new Error("managed service receipt has a non-absolute DSH_HOME");
|
|
177
|
+
}
|
|
178
|
+
if (!Number.isInteger(spec.port) || spec.port < 1 || spec.port > 65535) throw new Error("managed service receipt has an invalid port");
|
|
179
|
+
if (spec.servicePath !== void 0 && typeof spec.servicePath !== "string") throw new Error("managed service receipt has an invalid service PATH");
|
|
180
|
+
if (spec.servicePathSource !== void 0 && spec.servicePathSource !== "current" && spec.servicePathSource !== "minimal" && spec.servicePathSource !== "explicit") throw new Error("managed service receipt has an invalid service PATH source");
|
|
181
|
+
if (spec.servicePathCapturedAt !== void 0 && (typeof spec.servicePathCapturedAt !== "string" || Number.isNaN(Date.parse(spec.servicePathCapturedAt)))) throw new Error("managed service receipt has an invalid service PATH capture time");
|
|
182
|
+
if (spec.servicePathExt !== void 0 && typeof spec.servicePathExt !== "string") throw new Error("managed service receipt has an invalid PATHEXT");
|
|
183
|
+
if (spec.servicePathWarnings !== void 0 && (!Array.isArray(spec.servicePathWarnings) || spec.servicePathWarnings.length > 256 || spec.servicePathWarnings.some((value) => typeof value !== "string"))) throw new Error("managed service receipt has invalid service PATH warnings");
|
|
184
|
+
if (spec.servicePath === void 0 && (spec.servicePathSource !== void 0 || spec.servicePathCapturedAt !== void 0 || spec.servicePathExt !== void 0 || spec.servicePathWarnings !== void 0)) throw new Error("managed service receipt has PATH metadata without a service PATH");
|
|
185
|
+
if (spec.servicePath !== void 0 && (spec.servicePathSource === void 0 || spec.servicePathCapturedAt === void 0)) throw new Error("managed service receipt has an incomplete service PATH record");
|
|
186
|
+
if (spec.platform === "win32" && spec.servicePath !== void 0 && spec.servicePathExt === void 0) throw new Error("managed Windows service receipt has no PATHEXT");
|
|
187
|
+
if (spec.platform !== "win32" && spec.servicePathExt !== void 0) throw new Error("managed non-Windows service receipt has PATHEXT");
|
|
188
|
+
if (spec.nativeServiceCommand !== void 0 && typeof spec.nativeServiceCommand !== "string") throw new Error("managed service receipt has an invalid native service command");
|
|
189
|
+
const servicePath = servicePathOf(spec);
|
|
190
|
+
assertSafeText(servicePath, "service PATH");
|
|
191
|
+
if (servicePath.length > 8192) throw new Error("managed service receipt has an overlong service PATH");
|
|
192
|
+
if (spec.servicePathExt !== void 0) {
|
|
193
|
+
assertSafeText(spec.servicePathExt, "PATHEXT");
|
|
194
|
+
if (spec.servicePathExt.length > 8192) throw new Error("managed service receipt has an overlong PATHEXT");
|
|
195
|
+
normalizeServicePathExt(spec.servicePathExt);
|
|
196
|
+
}
|
|
197
|
+
for (const warning of spec.servicePathWarnings ?? []) assertSafeText(warning, "service PATH warning");
|
|
198
|
+
const nativeCommand = nativeServiceCommandOf(spec);
|
|
199
|
+
assertSafeText(nativeCommand, "native service command");
|
|
200
|
+
if (!isAbsolute(nativeCommand)) throw new Error("managed service receipt has a non-absolute native service command");
|
|
201
|
+
const allowedNativeCommands = nativeServiceCommandCandidates(spec.platform, expectedSystemRoot);
|
|
202
|
+
const nativeKey = spec.platform === "win32" ? nativeCommand.toLowerCase() : nativeCommand;
|
|
203
|
+
if (!allowedNativeCommands.some((candidate) => (spec.platform === "win32" ? candidate.toLowerCase() : candidate) === nativeKey)) throw new Error("managed service receipt has an unexpected native service command");
|
|
146
204
|
if (spec.host !== "127.0.0.1" && spec.host !== "0.0.0.0") throw new Error("`--host` must be 127.0.0.1 or 0.0.0.0");
|
|
147
205
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(spec.profile)) throw new Error("`--profile` must contain only letters, numbers, dot, underscore, or hyphen");
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
206
|
+
if (level === "launch") {
|
|
207
|
+
assertExecutable(spec.nodePath, "Node executable");
|
|
208
|
+
assertReadableRegular(spec.dshPath, "dsh executable");
|
|
209
|
+
assertExecutable(nativeCommand, "Native service command");
|
|
210
|
+
if (!existsSync(spec.workspace) || !statSync(spec.workspace).isDirectory()) throw new Error(`workspace is not a directory: ${spec.workspace}`);
|
|
211
|
+
}
|
|
152
212
|
}
|
|
153
213
|
function atomicWrite(path, content) {
|
|
154
214
|
mkdirSync(dirname(path), {
|
|
@@ -182,19 +242,31 @@ function ensureReplaceable(path, expected, managed) {
|
|
|
182
242
|
}
|
|
183
243
|
function receiptOwnsPath(previous, path) {
|
|
184
244
|
if (previous === void 0) return false;
|
|
185
|
-
|
|
245
|
+
const owned = pathsFor(previous.spec);
|
|
246
|
+
return owned.definitionFile === path || owned.stateFile === path || owned.wrapperFile === path;
|
|
186
247
|
}
|
|
187
248
|
function receiptTextOf(receipt) {
|
|
188
249
|
return JSON.stringify(receipt, null, 2) + "\n";
|
|
189
250
|
}
|
|
190
|
-
function
|
|
191
|
-
return
|
|
251
|
+
function samePaths(left, right) {
|
|
252
|
+
return left.stateFile === right.stateFile && left.definitionFile === right.definitionFile && left.wrapperFile === right.wrapperFile && left.stdoutFile === right.stdoutFile && left.stderrFile === right.stderrFile;
|
|
253
|
+
}
|
|
254
|
+
function readReceiptIfPresent(path, env) {
|
|
255
|
+
return existsSync(path) ? readReceipt(path, env) : void 0;
|
|
192
256
|
}
|
|
193
|
-
function readReceipt(path) {
|
|
257
|
+
function readReceipt(path, env) {
|
|
194
258
|
try {
|
|
195
259
|
const value = JSON.parse(readFileSync(path, "utf8"));
|
|
196
260
|
if (value.version !== RECEIPT_VERSION || value.managedBy !== "dsh-update-status" || value.spec === void 0 || value.paths === void 0) throw new Error("not a dsh-update-status service receipt");
|
|
197
|
-
|
|
261
|
+
validateSpec(value.spec, "structural", servicePlatform(env.platform), env.home, envValue(env.env, "SYSTEMROOT"));
|
|
262
|
+
const canonical = pathsFor(value.spec);
|
|
263
|
+
if (canonical.stateFile !== path || !samePaths(value.paths, canonical)) throw new Error("managed service receipt paths do not match its service spec");
|
|
264
|
+
return {
|
|
265
|
+
version: RECEIPT_VERSION,
|
|
266
|
+
managedBy: "dsh-update-status",
|
|
267
|
+
spec: value.spec,
|
|
268
|
+
paths: canonical
|
|
269
|
+
};
|
|
198
270
|
} catch (error) {
|
|
199
271
|
throw new Error(`cannot read managed service receipt ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
200
272
|
}
|
|
@@ -207,6 +279,7 @@ async function portIsFree(host, port) {
|
|
|
207
279
|
});
|
|
208
280
|
}
|
|
209
281
|
function serialisePlan(plan) {
|
|
282
|
+
const inheritedWindowsPath = plan.spec.platform === "win32" && plan.spec.servicePath === void 0;
|
|
210
283
|
return JSON.stringify({
|
|
211
284
|
platform: plan.spec.platform,
|
|
212
285
|
label: plan.spec.label,
|
|
@@ -216,6 +289,14 @@ function serialisePlan(plan) {
|
|
|
216
289
|
workspace: plan.spec.workspace,
|
|
217
290
|
host: plan.spec.host,
|
|
218
291
|
port: plan.spec.port,
|
|
292
|
+
nativeServiceCommand: nativeServiceCommandOf(plan.spec),
|
|
293
|
+
servicePath: {
|
|
294
|
+
source: inheritedWindowsPath ? "inherited logon environment (legacy receipt)" : plan.spec.servicePathSource ?? "minimal (legacy receipt)",
|
|
295
|
+
value: inheritedWindowsPath ? null : servicePathOf(plan.spec),
|
|
296
|
+
...plan.spec.servicePathCapturedAt === void 0 ? {} : { capturedAt: plan.spec.servicePathCapturedAt },
|
|
297
|
+
...plan.spec.servicePathExt === void 0 ? {} : { pathExt: plan.spec.servicePathExt },
|
|
298
|
+
warnings: plan.spec.servicePathWarnings ?? []
|
|
299
|
+
},
|
|
219
300
|
definitionFile: plan.paths.definitionFile,
|
|
220
301
|
wrapperFile: plan.paths.wrapperFile,
|
|
221
302
|
stateFile: plan.paths.stateFile,
|
|
@@ -233,38 +314,9 @@ function serialisePlan(plan) {
|
|
|
233
314
|
}
|
|
234
315
|
}, null, 2) + "\n";
|
|
235
316
|
}
|
|
236
|
-
function commandsForActivate(plan,
|
|
237
|
-
if (plan.spec.platform === "darwin") return [
|
|
238
|
-
|
|
239
|
-
"bootstrap",
|
|
240
|
-
`gui/${uid}`,
|
|
241
|
-
plan.paths.definitionFile
|
|
242
|
-
]];
|
|
243
|
-
if (plan.spec.platform === "linux") return [[
|
|
244
|
-
"systemctl",
|
|
245
|
-
"--user",
|
|
246
|
-
"daemon-reload"
|
|
247
|
-
], [
|
|
248
|
-
"systemctl",
|
|
249
|
-
"--user",
|
|
250
|
-
"enable",
|
|
251
|
-
"--now",
|
|
252
|
-
"dsh-update-status-web.service"
|
|
253
|
-
]];
|
|
254
|
-
return [[
|
|
255
|
-
"schtasks.exe",
|
|
256
|
-
"/Create",
|
|
257
|
-
"/TN",
|
|
258
|
-
"DSH Update Status Web",
|
|
259
|
-
"/XML",
|
|
260
|
-
plan.paths.definitionFile,
|
|
261
|
-
"/F"
|
|
262
|
-
], [
|
|
263
|
-
"schtasks.exe",
|
|
264
|
-
"/Run",
|
|
265
|
-
"/TN",
|
|
266
|
-
"DSH Update Status Web"
|
|
267
|
-
]];
|
|
317
|
+
function commandsForActivate(plan, _uid) {
|
|
318
|
+
if (plan.spec.platform === "darwin") return [plan.installCommand];
|
|
319
|
+
return [plan.installCommand, plan.startCommand];
|
|
268
320
|
}
|
|
269
321
|
function invoke(command, run) {
|
|
270
322
|
const [file, ...args] = command;
|
|
@@ -286,7 +338,8 @@ function preflight(spec) {
|
|
|
286
338
|
env: {
|
|
287
339
|
HOME: spec.home,
|
|
288
340
|
...spec.dshHome === void 0 ? {} : { DSH_HOME: spec.dshHome },
|
|
289
|
-
PATH:
|
|
341
|
+
PATH: servicePathOf(spec),
|
|
342
|
+
...spec.platform === "win32" && spec.servicePathExt !== void 0 ? { PATHEXT: spec.servicePathExt } : {}
|
|
290
343
|
}
|
|
291
344
|
});
|
|
292
345
|
if (result.status !== 0) {
|
|
@@ -294,6 +347,32 @@ function preflight(spec) {
|
|
|
294
347
|
throw new Error(`DSH boot-free preflight failed; no service definition was written: ${diagnostic}`);
|
|
295
348
|
}
|
|
296
349
|
}
|
|
350
|
+
const VALUE_OPTIONS = /* @__PURE__ */ new Set([
|
|
351
|
+
"--profile",
|
|
352
|
+
"--workspace",
|
|
353
|
+
"--dsh-home",
|
|
354
|
+
"--host",
|
|
355
|
+
"--port",
|
|
356
|
+
"--node",
|
|
357
|
+
"--dsh",
|
|
358
|
+
"--log-dir",
|
|
359
|
+
"--path-source",
|
|
360
|
+
"--service-path",
|
|
361
|
+
"--service-pathext"
|
|
362
|
+
]);
|
|
363
|
+
function assertKnownOptions(args) {
|
|
364
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
365
|
+
const value = args[index];
|
|
366
|
+
if (value === "--dry-run") continue;
|
|
367
|
+
if (!VALUE_OPTIONS.has(value)) throw new Error(`unknown option: ${value}`);
|
|
368
|
+
const next = args[index + 1];
|
|
369
|
+
if (next === void 0 || next.startsWith("--")) throw new Error(`missing value after ${value}`);
|
|
370
|
+
index += 1;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function warnAboutPath(spec) {
|
|
374
|
+
for (const warning of spec.servicePathWarnings ?? []) process.stderr.write(`Warning: ${warning}\n`);
|
|
375
|
+
}
|
|
297
376
|
async function main(argv = process.argv.slice(2), env = environment(), run = runner, hooks = {}) {
|
|
298
377
|
const [action, ...rawArgs] = argv;
|
|
299
378
|
if (action === void 0 || action === "--help" || action === "-h") {
|
|
@@ -311,19 +390,27 @@ async function main(argv = process.argv.slice(2), env = environment(), run = run
|
|
|
311
390
|
process.stderr.write(`Unknown command: ${action}\n${usage()}`);
|
|
312
391
|
return 2;
|
|
313
392
|
}
|
|
393
|
+
try {
|
|
394
|
+
assertKnownOptions(rawArgs);
|
|
395
|
+
} catch (error) {
|
|
396
|
+
process.stderr.write(`dsh-update-status-service: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
397
|
+
return 2;
|
|
398
|
+
}
|
|
314
399
|
const dryRun = rawArgs.includes("--dry-run") || action === "plan";
|
|
315
400
|
const args = rawArgs.filter((value) => value !== "--dry-run");
|
|
316
401
|
try {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
402
|
+
if (dryRun || action === "install") {
|
|
403
|
+
const spec = specFromArgs(args, env);
|
|
404
|
+
validateSpec(spec, "launch", servicePlatform(env.platform), env.home, envValue(env.env, "SYSTEMROOT"));
|
|
405
|
+
const plan = planFor(spec, env.uid ?? 0);
|
|
406
|
+
if (dryRun) {
|
|
407
|
+
process.stdout.write(serialisePlan(plan));
|
|
408
|
+
return 0;
|
|
409
|
+
}
|
|
410
|
+
process.stdout.write(`Service PATH (${spec.servicePathSource ?? "minimal"}): ${servicePathOf(spec)}\n`);
|
|
411
|
+
warnAboutPath(spec);
|
|
325
412
|
(hooks.preflight ?? preflight)(spec);
|
|
326
|
-
const previous = readReceiptIfPresent(plan.paths.stateFile);
|
|
413
|
+
const previous = readReceiptIfPresent(plan.paths.stateFile, env);
|
|
327
414
|
ensureReplaceable(plan.paths.definitionFile, plan.definition, receiptOwnsPath(previous, plan.paths.definitionFile));
|
|
328
415
|
if (plan.wrapper !== void 0 && plan.paths.wrapperFile !== void 0) ensureReplaceable(plan.paths.wrapperFile, plan.wrapper, receiptOwnsPath(previous, plan.paths.wrapperFile));
|
|
329
416
|
const receiptText = receiptTextOf({
|
|
@@ -343,7 +430,9 @@ async function main(argv = process.argv.slice(2), env = environment(), run = run
|
|
|
343
430
|
process.stdout.write(`Staged user service definition: ${plan.paths.definitionFile}\nNo service has started. Stop your terminal-started DSH, then run activate.\n`);
|
|
344
431
|
return 0;
|
|
345
432
|
}
|
|
346
|
-
const receipt = readReceipt(
|
|
433
|
+
const receipt = readReceipt(serviceStateFileFromArgs(args, env), env);
|
|
434
|
+
const plan = planFor(receipt.spec, env.uid ?? 0);
|
|
435
|
+
if (action === "activate") validateSpec(receipt.spec, "launch", servicePlatform(env.platform), env.home, envValue(env.env, "SYSTEMROOT"));
|
|
347
436
|
if (action === "activate") {
|
|
348
437
|
if (!await portIsFree(receipt.spec.host, receipt.spec.port)) throw new Error(`port ${receipt.spec.host}:${String(receipt.spec.port)} is in use; stop the existing DSH yourself before activate. Nothing was killed.`);
|
|
349
438
|
for (const command of commandsForActivate(plan, env.uid ?? 0)) invoke(command, run);
|
|
@@ -369,9 +458,9 @@ async function main(argv = process.argv.slice(2), env = environment(), run = run
|
|
|
369
458
|
}
|
|
370
459
|
const result = run(plan.uninstallCommand[0], plan.uninstallCommand.slice(1));
|
|
371
460
|
if (result.status !== 0) process.stderr.write(`Warning: ${result.stderr || result.stdout || "service was not loaded"}\n`);
|
|
372
|
-
rmSync(
|
|
373
|
-
if (
|
|
374
|
-
rmSync(
|
|
461
|
+
rmSync(plan.paths.definitionFile, { force: true });
|
|
462
|
+
if (plan.paths.wrapperFile !== void 0) rmSync(plan.paths.wrapperFile, { force: true });
|
|
463
|
+
rmSync(plan.paths.stateFile, { force: true });
|
|
375
464
|
process.stdout.write("Removed the managed user-service definition. Logs were preserved.\n");
|
|
376
465
|
return 0;
|
|
377
466
|
} catch (error) {
|
|
@@ -383,4 +472,4 @@ if (import.meta.url === new URL(process.argv[1] ?? "", "file:").href) main().the
|
|
|
383
472
|
process.exitCode = code;
|
|
384
473
|
});
|
|
385
474
|
//#endregion
|
|
386
|
-
export { main };
|
|
475
|
+
export { main, serialisePlan };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-update-status",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "DeepSeek Harness Web plugin for version status, copy-only upgrade guidance, and safe restart when an explicit user-level supervisor is installed.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -71,7 +71,8 @@
|
|
|
71
71
|
"0.1.7-rc.2": "compatible",
|
|
72
72
|
"0.2.0-rc.1": "compatible",
|
|
73
73
|
"0.2.0-rc.2": "compatible",
|
|
74
|
-
"0.2.1-alpha.1": "compatible"
|
|
74
|
+
"0.2.1-alpha.1": "compatible",
|
|
75
|
+
"0.2.1-alpha.3": "compatible"
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
},
|