@nowcrew/daemon 0.5.38 → 0.5.40
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/README.md +9 -14
- package/dist/daemon-update-eligibility.js +57 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,23 +95,18 @@ crew-daemon doctor --profile work
|
|
|
95
95
|
crew-daemon status --profile work
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
For a non-default daemon home, the
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
For a non-default daemon home, the daemon now recognizes the pre-registry service ID when its descriptor
|
|
99
|
+
exactly matches the running profile's node path, package entry, profile name, and `--daemon-home`. No
|
|
100
|
+
uninstall/reinstall migration is required. The first self-update uses that exact legacy service ID for the
|
|
101
|
+
restart; future service lifecycle commands can continue to migrate it explicitly if desired:
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
|
-
CREW_DAEMON_HOME="$HOME/.crew/daemon-dev" crew-daemon
|
|
105
|
-
CREW_DAEMON_HOME="$HOME/.crew/daemon-dev" crew-daemon
|
|
106
|
-
CREW_DAEMON_HOME="$HOME/.crew/daemon-dev" crew-daemon install --profile work
|
|
107
|
-
CREW_DAEMON_HOME="$HOME/.crew/daemon-dev" crew-daemon start --profile work
|
|
108
|
-
CREW_DAEMON_HOME="$HOME/.crew/daemon-dev" crew-daemon doctor --profile work
|
|
109
|
-
CREW_DAEMON_HOME="$HOME/.crew/daemon-dev" crew-daemon status --profile work
|
|
104
|
+
CREW_DAEMON_HOME="$HOME/.crew/daemon-dev" crew-daemon doctor --profile dev
|
|
105
|
+
CREW_DAEMON_HOME="$HOME/.crew/daemon-dev" crew-daemon status --profile dev
|
|
110
106
|
```
|
|
111
107
|
|
|
112
|
-
If
|
|
113
|
-
|
|
114
|
-
prevent either path from removing a drifted descriptor.
|
|
108
|
+
If the descriptor has drifted, the profile is stopped, or another host descriptor is not registered, the
|
|
109
|
+
daemon fails closed and remains manually upgradeable.
|
|
115
110
|
|
|
116
111
|
The daemon advertises `daemon_update_v1` only when all of these conditions hold:
|
|
117
112
|
|
|
@@ -120,7 +115,7 @@ The daemon advertises `daemon_update_v1` only when all of these conditions hold:
|
|
|
120
115
|
| Platform | macOS LaunchAgent or Linux systemd user service |
|
|
121
116
|
| Entrypoint | global `@nowcrew/daemon/dist/main.js`, not npx or source/tsx |
|
|
122
117
|
| Startup | `crew-daemon serve --profile <name>` through the installed service |
|
|
123
|
-
| Registry | every NowCrew descriptor on the OS user account is registered and conflict-free |
|
|
118
|
+
| Registry | every other NowCrew descriptor on the OS user account is registered and conflict-free; the exact target legacy descriptor may be adopted once |
|
|
124
119
|
| Identity | service ID, descriptor, daemon home, Agent root, entrypoint, package root, and npm prefix match |
|
|
125
120
|
| Service | the selected profile is running and holds the installation lease |
|
|
126
121
|
| Install root | a standard writable Unix global npm prefix can be derived from the running entrypoint |
|
|
@@ -53,9 +53,8 @@ export async function detectDaemonUpdateEligibility(profileName, overrides = {})
|
|
|
53
53
|
entryPath: deps.entryPath,
|
|
54
54
|
profileHome: deps.profileHome,
|
|
55
55
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return { eligible: false, reason: "service_not_running" };
|
|
56
|
+
let selectedSpec = spec;
|
|
57
|
+
let status = await deps.serviceStatus(spec);
|
|
59
58
|
let services;
|
|
60
59
|
try {
|
|
61
60
|
services = await deps.readManagedServices();
|
|
@@ -65,34 +64,66 @@ export async function detectDaemonUpdateEligibility(profileName, overrides = {})
|
|
|
65
64
|
}
|
|
66
65
|
const registered = services.find((record) => record.serviceId === spec.id
|
|
67
66
|
|| (record.daemonHome === deps.profileHome && record.profile === profileName));
|
|
68
|
-
if (registered
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
if (registered !== undefined) {
|
|
68
|
+
try {
|
|
69
|
+
assertRegistryCoversDescriptors(services, await deps.listManagedDescriptorPaths());
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return { eligible: false, reason: "managed_service_registry_incomplete" };
|
|
73
|
+
}
|
|
74
|
+
const descriptor = await deps.readServiceDescriptor(spec).catch(() => null);
|
|
75
|
+
if (descriptor === null || spec.descriptorPath === null || spec.descriptor === null
|
|
76
|
+
|| !managedServiceIdentityMatches(registered, {
|
|
77
|
+
version: 1,
|
|
78
|
+
platform: deps.platform,
|
|
79
|
+
serviceId: spec.id,
|
|
80
|
+
profile: profileName,
|
|
81
|
+
daemonHome: deps.profileHome,
|
|
82
|
+
agentsRoot: resolveAgentsRoot(profile.agentsRoot, deps.userHome, deps.platform),
|
|
83
|
+
nodePath: deps.nodePath,
|
|
84
|
+
entryPath: deps.entryPath,
|
|
85
|
+
packageRoot: installation.packageRoot,
|
|
86
|
+
npmPrefix: installation.npmPrefix,
|
|
87
|
+
descriptorPath: spec.descriptorPath,
|
|
88
|
+
descriptorSha256: serviceDescriptorSha256(descriptor),
|
|
89
|
+
})
|
|
90
|
+
|| descriptor !== spec.descriptor) {
|
|
91
|
+
return { eligible: false, reason: "managed_service_identity_mismatch" };
|
|
92
|
+
}
|
|
76
93
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
94
|
+
else {
|
|
95
|
+
// Releases before the managed-service registry used the unsuffixed service id.
|
|
96
|
+
// Adopt only an exact descriptor for this profile; never infer ownership from a
|
|
97
|
+
// running process or accept a descriptor with a different entry/home.
|
|
98
|
+
const legacySpec = buildServiceSpec({
|
|
81
99
|
platform: deps.platform,
|
|
82
|
-
serviceId: spec.id,
|
|
83
100
|
profile: profileName,
|
|
84
|
-
|
|
85
|
-
|
|
101
|
+
userHome: deps.userHome,
|
|
102
|
+
uid: deps.uid,
|
|
86
103
|
nodePath: deps.nodePath,
|
|
87
104
|
entryPath: deps.entryPath,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
profileHome: deps.profileHome,
|
|
106
|
+
legacyServiceId: true,
|
|
107
|
+
});
|
|
108
|
+
const legacyDescriptor = await deps.readServiceDescriptor(legacySpec).catch(() => null);
|
|
109
|
+
if (legacyDescriptor !== legacySpec.descriptor) {
|
|
110
|
+
return { eligible: false, reason: "managed_service_not_registered" };
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const descriptorPaths = await deps.listManagedDescriptorPaths();
|
|
114
|
+
const targetPath = legacySpec.descriptorPath;
|
|
115
|
+
assertRegistryCoversDescriptors(services, descriptorPaths.filter((descriptorPath) => descriptorPath !== targetPath));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return { eligible: false, reason: "managed_service_registry_incomplete" };
|
|
119
|
+
}
|
|
120
|
+
status = await deps.serviceStatus(legacySpec);
|
|
121
|
+
if (!status.running)
|
|
122
|
+
return { eligible: false, reason: "service_not_running" };
|
|
123
|
+
selectedSpec = legacySpec;
|
|
95
124
|
}
|
|
125
|
+
if (!status.running)
|
|
126
|
+
return { eligible: false, reason: "service_not_running" };
|
|
96
127
|
if (!deps.installationLeaseHeld(installation.npmPrefix)) {
|
|
97
128
|
return { eligible: false, reason: "installation_lease_missing" };
|
|
98
129
|
}
|
|
@@ -106,6 +137,6 @@ export async function detectDaemonUpdateEligibility(profileName, overrides = {})
|
|
|
106
137
|
eligible: true,
|
|
107
138
|
profileName,
|
|
108
139
|
...installation,
|
|
109
|
-
serviceSpec:
|
|
140
|
+
serviceSpec: selectedSpec,
|
|
110
141
|
};
|
|
111
142
|
}
|