@nowcrew/daemon 0.5.46 → 0.5.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/daemon-update-controller.js +20 -12
- package/dist/daemon-update-eligibility.js +10 -0
- package/dist/daemon-updater.js +21 -0
- package/dist/serve.js +9 -12
- package/package.json +1 -1
|
@@ -4,6 +4,12 @@ const DaemonUpdateMessageSchema = z.object({
|
|
|
4
4
|
updateId: z.string().uuid(),
|
|
5
5
|
targetVersion: z.string().regex(/^\d+\.\d+\.\d+$/),
|
|
6
6
|
}).strict();
|
|
7
|
+
const DaemonRestartMessageSchema = z.object({
|
|
8
|
+
type: z.literal("daemon:restart"),
|
|
9
|
+
updateId: z.string().uuid(),
|
|
10
|
+
targetVersion: z.string().regex(/^\d+\.\d+\.\d+$/),
|
|
11
|
+
}).strict();
|
|
12
|
+
const DaemonControlMessageSchema = z.union([DaemonUpdateMessageSchema, DaemonRestartMessageSchema]);
|
|
7
13
|
export function createDaemonUpdateController(deps) {
|
|
8
14
|
const handled = new Set();
|
|
9
15
|
let running = null;
|
|
@@ -17,16 +23,18 @@ export function createDaemonUpdateController(deps) {
|
|
|
17
23
|
failed(message.updateId, "ineligible");
|
|
18
24
|
return;
|
|
19
25
|
}
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const preparation = message.type === "daemon:restart"
|
|
27
|
+
? await deps.prepareRestart()
|
|
28
|
+
: await deps.install({
|
|
29
|
+
targetVersion: message.targetVersion,
|
|
30
|
+
packageRoot: eligibility.packageRoot,
|
|
31
|
+
npmPrefix: eligibility.npmPrefix,
|
|
32
|
+
onInstalling: () => {
|
|
33
|
+
deps.sendStatus({ type: "daemon:update-status", updateId: message.updateId, status: "installing" });
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
if (!preparation.ok) {
|
|
37
|
+
failed(message.updateId, preparation.errorCode);
|
|
30
38
|
return;
|
|
31
39
|
}
|
|
32
40
|
let released = false;
|
|
@@ -34,7 +42,7 @@ export function createDaemonUpdateController(deps) {
|
|
|
34
42
|
if (released)
|
|
35
43
|
return;
|
|
36
44
|
released = true;
|
|
37
|
-
await
|
|
45
|
+
await preparation.release();
|
|
38
46
|
};
|
|
39
47
|
deps.sendStatus({ type: "daemon:update-status", updateId: message.updateId, status: "restarting" });
|
|
40
48
|
try {
|
|
@@ -66,7 +74,7 @@ export function createDaemonUpdateController(deps) {
|
|
|
66
74
|
}
|
|
67
75
|
},
|
|
68
76
|
handle: async (input) => {
|
|
69
|
-
const parsed =
|
|
77
|
+
const parsed = DaemonControlMessageSchema.safeParse(input);
|
|
70
78
|
if (!parsed.success)
|
|
71
79
|
return false;
|
|
72
80
|
const message = parsed.data;
|
|
@@ -10,6 +10,16 @@ import { daemonInstallationLeaseHeld } from "./daemon-installation-lease.js";
|
|
|
10
10
|
import { inspectLegacyServiceInstallation } from "./legacy-service-installation.js";
|
|
11
11
|
import { inspectWindowsServiceUpdateScope } from "./windows-scheduled-task.js";
|
|
12
12
|
import { assertRegistryCoversDescriptors, listManagedServiceDescriptorPaths, managedServiceIdentityMatches, readManagedServiceRegistry, serviceDescriptorSha256, } from "./managed-service-registry.js";
|
|
13
|
+
export async function managedDaemonCapabilities(eligibility) {
|
|
14
|
+
try {
|
|
15
|
+
return (await eligibility()).eligible
|
|
16
|
+
? ["daemon_update_v1", "daemon_restart_v1"]
|
|
17
|
+
: [];
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
13
23
|
function defaults() {
|
|
14
24
|
return {
|
|
15
25
|
platform: process.platform,
|
package/dist/daemon-updater.js
CHANGED
|
@@ -3,6 +3,27 @@ import { resolve } from "node:path";
|
|
|
3
3
|
import { systemCommandRunner } from "./computer-service.js";
|
|
4
4
|
import { daemonGlobalInstallation } from "./daemon-installation.js";
|
|
5
5
|
const RELEASED_VERSION_RE = /^\d+\.\d+\.\d+$/;
|
|
6
|
+
export async function prepareDaemonRestart(input) {
|
|
7
|
+
const local = input.localSlots.tryAcquireExclusive();
|
|
8
|
+
if (local === null)
|
|
9
|
+
return { ok: false, errorCode: "runtime_busy" };
|
|
10
|
+
const host = await input.hostCoordinator.tryAcquireExclusiveExecution();
|
|
11
|
+
if (host === null) {
|
|
12
|
+
local.release();
|
|
13
|
+
return { ok: false, errorCode: "runtime_busy" };
|
|
14
|
+
}
|
|
15
|
+
let released = false;
|
|
16
|
+
return {
|
|
17
|
+
ok: true,
|
|
18
|
+
release: async () => {
|
|
19
|
+
if (released)
|
|
20
|
+
return;
|
|
21
|
+
released = true;
|
|
22
|
+
await host.release();
|
|
23
|
+
local.release();
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
6
27
|
async function readPackageVersion(packageRoot) {
|
|
7
28
|
const body = JSON.parse(await readFile(resolve(packageRoot, "package.json"), "utf8"));
|
|
8
29
|
return typeof body.version === "string" ? body.version : "";
|
package/dist/serve.js
CHANGED
|
@@ -32,9 +32,9 @@ import { createCompletionRetransmitter } from "./completion-retransmitter.js";
|
|
|
32
32
|
import { createAgentMemoryBridge } from "./agent-memory/bridge.js";
|
|
33
33
|
import { createRuntimeStartupGate } from "./runtime-startup-gate.js";
|
|
34
34
|
import { createHostExecutionCoordinator, hostCoordinatedSlotManager, hostCoordinatedStartupGate, } from "./host-execution-coordinator.js";
|
|
35
|
-
import { detectDaemonUpdateEligibility, } from "./daemon-update-eligibility.js";
|
|
35
|
+
import { detectDaemonUpdateEligibility, managedDaemonCapabilities, } from "./daemon-update-eligibility.js";
|
|
36
36
|
import { createDaemonUpdateController } from "./daemon-update-controller.js";
|
|
37
|
-
import { installExactDaemonUpdate } from "./daemon-updater.js";
|
|
37
|
+
import { installExactDaemonUpdate, prepareDaemonRestart } from "./daemon-updater.js";
|
|
38
38
|
import { scheduleServiceRestart } from "./computer-service.js";
|
|
39
39
|
import { createProjectRegistry } from "./project-skills/registry.js";
|
|
40
40
|
import { createProjectSkillsController, } from "./project-skills/controller.js";
|
|
@@ -100,6 +100,10 @@ export function serve(config, opts = {}) {
|
|
|
100
100
|
localSlots,
|
|
101
101
|
hostCoordinator,
|
|
102
102
|
})),
|
|
103
|
+
prepareRestart: opts.update?.prepareRestart ?? (() => prepareDaemonRestart({
|
|
104
|
+
localSlots,
|
|
105
|
+
hostCoordinator,
|
|
106
|
+
})),
|
|
103
107
|
scheduleRestart: opts.update?.scheduleRestart ?? scheduleServiceRestart,
|
|
104
108
|
sendStatus: (frame) => {
|
|
105
109
|
try {
|
|
@@ -310,14 +314,7 @@ export function serve(config, opts = {}) {
|
|
|
310
314
|
...(detectInstalled ? { detectInstalled } : {}),
|
|
311
315
|
// First hello must not wait for third-party handshakes; optional transports arrive in the refresh.
|
|
312
316
|
detectExecutable: async (installed) => conservativeExecutionRuntimes(installed),
|
|
313
|
-
additionalCapabilities:
|
|
314
|
-
try {
|
|
315
|
-
return (await updateEligibility()).eligible ? ["daemon_update_v1"] : [];
|
|
316
|
-
}
|
|
317
|
-
catch {
|
|
318
|
-
return [];
|
|
319
|
-
}
|
|
320
|
-
},
|
|
317
|
+
additionalCapabilities: () => managedDaemonCapabilities(updateEligibility),
|
|
321
318
|
});
|
|
322
319
|
runtimeFacts = helloPromise
|
|
323
320
|
.then(async (hello) => {
|
|
@@ -390,9 +387,9 @@ export function serve(config, opts = {}) {
|
|
|
390
387
|
if (typeof decoded !== "object" || decoded === null)
|
|
391
388
|
return;
|
|
392
389
|
const rawType = "type" in decoded && typeof decoded.type === "string" ? decoded.type : "";
|
|
393
|
-
if (rawType === "daemon:update") {
|
|
390
|
+
if (rawType === "daemon:update" || rawType === "daemon:restart") {
|
|
394
391
|
void updateController.handle(decoded).catch((error) => {
|
|
395
|
-
dslog("daemon.
|
|
392
|
+
dslog("daemon.control_failed", "daemon 控制操作处理失败", {
|
|
396
393
|
level: "ERROR", error_message: error.message,
|
|
397
394
|
});
|
|
398
395
|
});
|