crewly 1.20.174 → 1.20.175
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/config/skills/orchestrator/restart-crewly/SKILL.md +11 -23
- package/config/skills/orchestrator/restart-crewly/execute.sh +7 -5
- package/dist/backend/backend/src/constants.d.ts +55 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +55 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/system-control.controller.d.ts +67 -0
- package/dist/backend/backend/src/controllers/system/system-control.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/system/system-control.controller.js +183 -0
- package/dist/backend/backend/src/controllers/system/system-control.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/system/system.controller.d.ts +0 -13
- package/dist/backend/backend/src/controllers/system/system.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/system/system.controller.js +0 -87
- package/dist/backend/backend/src/controllers/system/system.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts +7 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +84 -1
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/system.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/system.routes.js +4 -2
- package/dist/backend/backend/src/routes/modules/system.routes.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +7 -0
- package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.service.d.ts +58 -0
- package/dist/backend/backend/src/services/system/auto-update.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.service.js +128 -52
- package/dist/backend/backend/src/services/system/auto-update.service.js.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.utils.d.ts +7 -0
- package/dist/backend/backend/src/services/system/auto-update.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/services/system/auto-update.utils.js +14 -0
- package/dist/backend/backend/src/services/system/auto-update.utils.js.map +1 -1
- package/dist/backend/backend/src/services/system/restart-replacement.d.ts +78 -0
- package/dist/backend/backend/src/services/system/restart-replacement.d.ts.map +1 -0
- package/dist/backend/backend/src/services/system/restart-replacement.js +109 -0
- package/dist/backend/backend/src/services/system/restart-replacement.js.map +1 -0
- package/dist/backend/backend/src/services/system/supervisor-detect.d.ts +78 -0
- package/dist/backend/backend/src/services/system/supervisor-detect.d.ts.map +1 -0
- package/dist/backend/backend/src/services/system/supervisor-detect.js +171 -0
- package/dist/backend/backend/src/services/system/supervisor-detect.js.map +1 -0
- package/dist/backend/backend/src/services/system/system-control.service.d.ts +337 -0
- package/dist/backend/backend/src/services/system/system-control.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/system/system-control.service.js +574 -0
- package/dist/backend/backend/src/services/system/system-control.service.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +55 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +55 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/system/auto-update.utils.d.ts +7 -0
- package/dist/cli/backend/src/services/system/auto-update.utils.d.ts.map +1 -1
- package/dist/cli/backend/src/services/system/auto-update.utils.js +14 -0
- package/dist/cli/backend/src/services/system/auto-update.utils.js.map +1 -1
- package/frontend/dist/assets/{index-36e85ac8.js → index-0726afab.js} +281 -281
- package/frontend/dist/assets/{index-15501404.css → index-0c5449b5.css} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,574 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System Control Service — the owner's Upgrade and Restart buttons.
|
|
3
|
+
*
|
|
4
|
+
* Jenkins-style "safe restart" for Crewly
|
|
5
|
+
* (specs/2026-10-01-upgrade-restart-controls.md):
|
|
6
|
+
*
|
|
7
|
+
* - **Status.** Running version, latest on npm, install kind, who relaunches
|
|
8
|
+
* the backend, agents mid-turn, and the current / last action.
|
|
9
|
+
* - **Upgrade** (`when: idle | now`). npm global installs only. It reuses the
|
|
10
|
+
* AutoUpdateService install path (same prefix, same npm, same verify), then
|
|
11
|
+
* restarts. A source checkout is refused: it is updated with git.
|
|
12
|
+
* - **Restart** (`when: idle | now`). The graceful drained shutdown, exiting
|
|
13
|
+
* with RESTART_REQUESTED. When nothing is known to relaunch the backend, a
|
|
14
|
+
* detached launcher is started first so the machine never stays down.
|
|
15
|
+
* - **When idle** waits until no agent is mid-turn, capped (30 min), then
|
|
16
|
+
* goes ahead. Asking again with `now` cuts the wait short.
|
|
17
|
+
* - **One at a time.** A second request while one is running is refused,
|
|
18
|
+
* as is any request while a shutdown is already under way.
|
|
19
|
+
* - **Survives the restart.** Progress and outcome are kept in
|
|
20
|
+
* `<crewlyHome>/system-action.json`; the next boot settles the record
|
|
21
|
+
* ("Restarted at …", "Upgraded to x.y.z", or what went wrong), so the
|
|
22
|
+
* dashboard can show it after it reconnects.
|
|
23
|
+
*
|
|
24
|
+
* All I/O goes through {@link SystemControlDeps}.
|
|
25
|
+
*
|
|
26
|
+
* @module services/system/system-control.service
|
|
27
|
+
*/
|
|
28
|
+
import * as fs from 'fs';
|
|
29
|
+
import * as path from 'path';
|
|
30
|
+
import { randomUUID } from 'crypto';
|
|
31
|
+
import { PROCESS_EXIT_CODES, SYSTEM_CONTROL_CONSTANTS } from '../../constants.js';
|
|
32
|
+
import { isNewerVersion } from './auto-update.utils.js';
|
|
33
|
+
/** Statuses that mean "still running". */
|
|
34
|
+
const ACTIVE_STATUSES = new Set(['waiting-idle', 'installing', 'restarting']);
|
|
35
|
+
/**
|
|
36
|
+
* Map the AutoUpdate install kind onto the public one.
|
|
37
|
+
*
|
|
38
|
+
* @param install - Install info
|
|
39
|
+
* @returns Public kind
|
|
40
|
+
*/
|
|
41
|
+
export function toPublicInstallKind(install) {
|
|
42
|
+
if (install.kind === 'npm-global')
|
|
43
|
+
return 'npm-global';
|
|
44
|
+
if (install.kind === 'dev-checkout')
|
|
45
|
+
return 'dev-checkout';
|
|
46
|
+
return 'other';
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Read the persisted action record.
|
|
50
|
+
*
|
|
51
|
+
* @param file - State file
|
|
52
|
+
* @returns The record, or null when missing / malformed
|
|
53
|
+
*/
|
|
54
|
+
export function readActionRecord(file) {
|
|
55
|
+
try {
|
|
56
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
57
|
+
return parsed && typeof parsed.id === 'string' && typeof parsed.status === 'string' ? parsed : null;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Write the action record atomically.
|
|
65
|
+
*
|
|
66
|
+
* @param file - State file
|
|
67
|
+
* @param record - Record
|
|
68
|
+
*/
|
|
69
|
+
export function writeActionRecord(file, record) {
|
|
70
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
71
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
72
|
+
fs.writeFileSync(tmp, JSON.stringify(record, null, 2), 'utf-8');
|
|
73
|
+
fs.renameSync(tmp, file);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Upgrade / restart controller for the running backend.
|
|
77
|
+
*/
|
|
78
|
+
export class SystemControlService {
|
|
79
|
+
deps;
|
|
80
|
+
static instance = null;
|
|
81
|
+
action = null;
|
|
82
|
+
stateFile;
|
|
83
|
+
/** Resolves the current idle wait early ("now" pressed while waiting) */
|
|
84
|
+
cutIdleWaitShort = null;
|
|
85
|
+
/**
|
|
86
|
+
* @param deps - Injected I/O
|
|
87
|
+
*/
|
|
88
|
+
constructor(deps) {
|
|
89
|
+
this.deps = deps;
|
|
90
|
+
this.stateFile = path.join(deps.crewlyHome, SYSTEM_CONTROL_CONSTANTS.STATE_FILE);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Register the process-wide instance.
|
|
94
|
+
*
|
|
95
|
+
* @param service - Instance, or null to clear
|
|
96
|
+
*/
|
|
97
|
+
static setInstance(service) {
|
|
98
|
+
SystemControlService.instance = service;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The process-wide instance, when the server registered one.
|
|
102
|
+
*
|
|
103
|
+
* @returns The instance or null
|
|
104
|
+
*/
|
|
105
|
+
static getInstance() {
|
|
106
|
+
return SystemControlService.instance;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Boot: settle the record a previous process left behind, so the
|
|
110
|
+
* dashboard can say "Restarted at …" / "Upgraded to x.y.z" after it
|
|
111
|
+
* reconnects.
|
|
112
|
+
*/
|
|
113
|
+
handleBoot() {
|
|
114
|
+
const record = readActionRecord(this.stateFile);
|
|
115
|
+
if (!record || !ACTIVE_STATUSES.has(record.status) || record.pid === this.deps.pid)
|
|
116
|
+
return;
|
|
117
|
+
const now = new Date(this.deps.now()).toISOString();
|
|
118
|
+
const running = this.deps.currentVersion;
|
|
119
|
+
let settled;
|
|
120
|
+
if (record.status === 'restarting') {
|
|
121
|
+
if (record.kind === 'upgrade' && record.toVersion && running !== record.toVersion) {
|
|
122
|
+
settled = {
|
|
123
|
+
...record,
|
|
124
|
+
status: 'failed',
|
|
125
|
+
message: `Crewly came back on ${running ?? 'an unknown version'} instead of ${record.toVersion}.`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
settled = {
|
|
130
|
+
...record,
|
|
131
|
+
status: 'completed',
|
|
132
|
+
message: record.kind === 'upgrade' ? `Upgraded to ${running} and restarted at ${now}.` : `Restarted at ${now}.`,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
settled = {
|
|
138
|
+
...record,
|
|
139
|
+
status: 'interrupted',
|
|
140
|
+
message: record.kind === 'upgrade'
|
|
141
|
+
? 'Crewly stopped before the upgrade finished. Nothing was installed or the install was not confirmed; try again.'
|
|
142
|
+
: 'Crewly stopped before the restart started.',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
settled = { ...settled, completedAt: now, updatedAt: now, resultVersion: running };
|
|
146
|
+
this.action = settled;
|
|
147
|
+
this.persist();
|
|
148
|
+
this.deps.logger.info('Previous upgrade/restart settled at boot', {
|
|
149
|
+
id: settled.id,
|
|
150
|
+
kind: settled.kind,
|
|
151
|
+
status: settled.status,
|
|
152
|
+
requestedBy: settled.requestedBy,
|
|
153
|
+
message: settled.message,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Whether an upgrade or restart from this process is still running.
|
|
158
|
+
*
|
|
159
|
+
* @returns True while one is
|
|
160
|
+
*/
|
|
161
|
+
isActionInProgress() {
|
|
162
|
+
return !!this.action && ACTIVE_STATUSES.has(this.action.status) && this.action.pid === this.deps.pid;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* The current or last action (this boot, or the one settled at boot).
|
|
166
|
+
*
|
|
167
|
+
* @returns The record or null
|
|
168
|
+
*/
|
|
169
|
+
getAction() {
|
|
170
|
+
if (this.action)
|
|
171
|
+
return this.action;
|
|
172
|
+
return readActionRecord(this.stateFile);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* How the backend comes back after an exit.
|
|
176
|
+
*
|
|
177
|
+
* @param supervisor - Supervisor info
|
|
178
|
+
* @returns supervisor or replacement
|
|
179
|
+
*/
|
|
180
|
+
relaunchMethod(supervisor) {
|
|
181
|
+
return supervisor.willRelaunch === 'yes' ? 'supervisor' : 'replacement';
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Status for the dashboard.
|
|
185
|
+
*
|
|
186
|
+
* @param options - `refresh` re-asks the registry when the cached answer is over a minute old
|
|
187
|
+
* @returns Status
|
|
188
|
+
*/
|
|
189
|
+
async getStatus(options = {}) {
|
|
190
|
+
const { install, currentVersion } = this.deps;
|
|
191
|
+
let latest = null;
|
|
192
|
+
try {
|
|
193
|
+
latest = await this.deps.fetchLatestVersion(options.refresh ? SYSTEM_CONTROL_CONSTANTS.REGISTRY_MAX_AGE_MS : SYSTEM_CONTROL_CONSTANTS.STATUS_REGISTRY_MAX_AGE_MS);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
latest = null;
|
|
197
|
+
}
|
|
198
|
+
const updateAvailable = !!latest && !!currentVersion && isNewerVersion(latest, currentVersion);
|
|
199
|
+
const installKind = toPublicInstallKind(install);
|
|
200
|
+
const busy = this.inProgressReason();
|
|
201
|
+
const supervisor = this.deps.getSupervisor();
|
|
202
|
+
let upgradeBlockedReason = null;
|
|
203
|
+
if (installKind === 'dev-checkout')
|
|
204
|
+
upgradeBlockedReason = SYSTEM_CONTROL_CONSTANTS.MESSAGES.DEV_CHECKOUT;
|
|
205
|
+
else if (installKind === 'other')
|
|
206
|
+
upgradeBlockedReason = SYSTEM_CONTROL_CONSTANTS.MESSAGES.NOT_NPM_GLOBAL;
|
|
207
|
+
else if (busy)
|
|
208
|
+
upgradeBlockedReason = busy;
|
|
209
|
+
else if (!latest)
|
|
210
|
+
upgradeBlockedReason = SYSTEM_CONTROL_CONSTANTS.MESSAGES.REGISTRY_UNREACHABLE;
|
|
211
|
+
else if (!updateAvailable)
|
|
212
|
+
upgradeBlockedReason = `Crewly is up to date (${currentVersion}).`;
|
|
213
|
+
else if (!this.deps.getInstaller())
|
|
214
|
+
upgradeBlockedReason = SYSTEM_CONTROL_CONSTANTS.MESSAGES.UNAVAILABLE;
|
|
215
|
+
return {
|
|
216
|
+
currentVersion,
|
|
217
|
+
latestVersion: latest,
|
|
218
|
+
updateAvailable,
|
|
219
|
+
installKind,
|
|
220
|
+
packageRoot: install.packageRoot,
|
|
221
|
+
canUpgrade: upgradeBlockedReason === null,
|
|
222
|
+
upgradeBlockedReason,
|
|
223
|
+
canRestart: busy === null,
|
|
224
|
+
restartBlockedReason: busy,
|
|
225
|
+
supervisor,
|
|
226
|
+
relaunch: this.relaunchMethod(supervisor),
|
|
227
|
+
busyAgents: this.safeBusyAgents(),
|
|
228
|
+
inProgress: busy !== null,
|
|
229
|
+
action: this.getAction(),
|
|
230
|
+
bootId: this.deps.bootId,
|
|
231
|
+
startedAt: this.deps.startedAt,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Why nothing new can start right now (null when it can).
|
|
236
|
+
*
|
|
237
|
+
* @returns Owner-readable reason or null
|
|
238
|
+
*/
|
|
239
|
+
inProgressReason() {
|
|
240
|
+
if (this.isActionInProgress() && this.action) {
|
|
241
|
+
return this.action.kind === 'upgrade'
|
|
242
|
+
? `An upgrade to ${this.action.toVersion} is already in progress.`
|
|
243
|
+
: 'A restart is already in progress.';
|
|
244
|
+
}
|
|
245
|
+
if (this.deps.isShutdownInProgress())
|
|
246
|
+
return SYSTEM_CONTROL_CONSTANTS.MESSAGES.RESTART_IN_PROGRESS;
|
|
247
|
+
if (this.deps.getInstaller()?.isBusy())
|
|
248
|
+
return 'An automatic update is running right now. Try again in a few minutes.';
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Busy agents, never throwing.
|
|
253
|
+
*
|
|
254
|
+
* @returns Agents mid-turn
|
|
255
|
+
*/
|
|
256
|
+
safeBusyAgents() {
|
|
257
|
+
try {
|
|
258
|
+
return this.deps.getBusyAgents();
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
return [];
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Escalate a running "when idle" wait of the same kind to "now".
|
|
266
|
+
*
|
|
267
|
+
* @param kind - Requested kind
|
|
268
|
+
* @param request - Request
|
|
269
|
+
* @returns Accepted answer, or null when this is not an escalation
|
|
270
|
+
*/
|
|
271
|
+
tryEscalate(kind, request) {
|
|
272
|
+
const action = this.action;
|
|
273
|
+
if (request.when !== 'now' ||
|
|
274
|
+
!action ||
|
|
275
|
+
!this.isActionInProgress() ||
|
|
276
|
+
action.kind !== kind ||
|
|
277
|
+
action.status !== 'waiting-idle' ||
|
|
278
|
+
!this.cutIdleWaitShort) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
this.deps.logger.info(`${kind === 'upgrade' ? 'Upgrade' : 'Restart'}: "now" requested while waiting for idle`, {
|
|
282
|
+
id: action.id,
|
|
283
|
+
requestedBy: request.actor,
|
|
284
|
+
});
|
|
285
|
+
this.update({ when: 'now', message: `${request.actor} asked to go ahead now.` });
|
|
286
|
+
this.cutIdleWaitShort();
|
|
287
|
+
return { ok: true, action: this.action, escalated: true };
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Refusal for "something is already running", or null.
|
|
291
|
+
*
|
|
292
|
+
* @returns Refusal or null
|
|
293
|
+
*/
|
|
294
|
+
busyRefusal() {
|
|
295
|
+
if (this.isActionInProgress()) {
|
|
296
|
+
return { ok: false, httpStatus: 409, code: SYSTEM_CONTROL_CONSTANTS.CODES.IN_PROGRESS, error: this.inProgressReason() };
|
|
297
|
+
}
|
|
298
|
+
const reason = this.inProgressReason();
|
|
299
|
+
if (reason) {
|
|
300
|
+
return { ok: false, httpStatus: 409, code: SYSTEM_CONTROL_CONSTANTS.CODES.RESTART_IN_PROGRESS, error: reason };
|
|
301
|
+
}
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Owner pressed "Upgrade".
|
|
306
|
+
*
|
|
307
|
+
* @param request - When, and who
|
|
308
|
+
* @returns Accepted (work continues in the background) or a refusal
|
|
309
|
+
*/
|
|
310
|
+
async requestUpgrade(request) {
|
|
311
|
+
const { install, currentVersion } = this.deps;
|
|
312
|
+
if (install.kind === 'dev-checkout') {
|
|
313
|
+
this.deps.logger.info('Upgrade refused: source checkout', { requestedBy: request.actor, packageRoot: install.packageRoot });
|
|
314
|
+
return { ok: false, httpStatus: 409, code: SYSTEM_CONTROL_CONSTANTS.CODES.DEV_CHECKOUT, error: SYSTEM_CONTROL_CONSTANTS.MESSAGES.DEV_CHECKOUT };
|
|
315
|
+
}
|
|
316
|
+
if (install.kind !== 'npm-global') {
|
|
317
|
+
this.deps.logger.info('Upgrade refused: not an npm global install', { requestedBy: request.actor, detail: install.detail });
|
|
318
|
+
return { ok: false, httpStatus: 409, code: SYSTEM_CONTROL_CONSTANTS.CODES.NOT_NPM_GLOBAL, error: SYSTEM_CONTROL_CONSTANTS.MESSAGES.NOT_NPM_GLOBAL };
|
|
319
|
+
}
|
|
320
|
+
const escalated = this.tryEscalate('upgrade', request);
|
|
321
|
+
if (escalated)
|
|
322
|
+
return escalated;
|
|
323
|
+
const busy = this.busyRefusal();
|
|
324
|
+
if (busy)
|
|
325
|
+
return busy;
|
|
326
|
+
const installer = this.deps.getInstaller();
|
|
327
|
+
if (!installer) {
|
|
328
|
+
return { ok: false, httpStatus: 503, code: SYSTEM_CONTROL_CONSTANTS.CODES.UNAVAILABLE, error: SYSTEM_CONTROL_CONSTANTS.MESSAGES.UNAVAILABLE };
|
|
329
|
+
}
|
|
330
|
+
let latest = null;
|
|
331
|
+
try {
|
|
332
|
+
latest = await this.deps.fetchLatestVersion(SYSTEM_CONTROL_CONSTANTS.REGISTRY_MAX_AGE_MS);
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
latest = null;
|
|
336
|
+
}
|
|
337
|
+
if (!latest) {
|
|
338
|
+
return { ok: false, httpStatus: 502, code: SYSTEM_CONTROL_CONSTANTS.CODES.REGISTRY_UNREACHABLE, error: SYSTEM_CONTROL_CONSTANTS.MESSAGES.REGISTRY_UNREACHABLE };
|
|
339
|
+
}
|
|
340
|
+
if (!currentVersion || !isNewerVersion(latest, currentVersion)) {
|
|
341
|
+
return { ok: false, httpStatus: 409, code: SYSTEM_CONTROL_CONSTANTS.CODES.UP_TO_DATE, error: `Crewly is already up to date (${currentVersion ?? latest}).` };
|
|
342
|
+
}
|
|
343
|
+
// The registry await gave another request a chance to start.
|
|
344
|
+
const raced = this.busyRefusal();
|
|
345
|
+
if (raced)
|
|
346
|
+
return raced;
|
|
347
|
+
const action = this.begin('upgrade', request, latest);
|
|
348
|
+
installer.appendLogLine(`${new Date(this.deps.now()).toISOString()} Manual upgrade to ${latest} requested by ${request.actor} (${request.when})`);
|
|
349
|
+
void this.runUpgrade(installer, latest).catch((error) => this.fail(`Upgrade crashed: ${errorText(error)}`));
|
|
350
|
+
return { ok: true, action };
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Owner pressed "Restart".
|
|
354
|
+
*
|
|
355
|
+
* @param request - When, and who
|
|
356
|
+
* @returns Accepted (work continues in the background) or a refusal
|
|
357
|
+
*/
|
|
358
|
+
async requestRestart(request) {
|
|
359
|
+
const escalated = this.tryEscalate('restart', request);
|
|
360
|
+
if (escalated)
|
|
361
|
+
return escalated;
|
|
362
|
+
const busy = this.busyRefusal();
|
|
363
|
+
if (busy)
|
|
364
|
+
return busy;
|
|
365
|
+
const action = this.begin('restart', request, null);
|
|
366
|
+
void this.runRestart().catch((error) => this.fail(`Restart crashed: ${errorText(error)}`));
|
|
367
|
+
return { ok: true, action };
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Create and persist a new action.
|
|
371
|
+
*
|
|
372
|
+
* @param kind - upgrade or restart
|
|
373
|
+
* @param request - Request
|
|
374
|
+
* @param toVersion - Upgrade target
|
|
375
|
+
* @returns The record
|
|
376
|
+
*/
|
|
377
|
+
begin(kind, request, toVersion) {
|
|
378
|
+
const now = new Date(this.deps.now()).toISOString();
|
|
379
|
+
const supervisor = this.deps.getSupervisor();
|
|
380
|
+
const label = kind === 'upgrade' ? `Upgrade to ${toVersion}` : 'Restart';
|
|
381
|
+
this.action = {
|
|
382
|
+
id: randomUUID(),
|
|
383
|
+
kind,
|
|
384
|
+
when: request.when,
|
|
385
|
+
status: request.when === 'idle' ? 'waiting-idle' : kind === 'upgrade' ? 'installing' : 'restarting',
|
|
386
|
+
requestedBy: request.actor,
|
|
387
|
+
requestedAt: now,
|
|
388
|
+
updatedAt: now,
|
|
389
|
+
fromVersion: this.deps.currentVersion,
|
|
390
|
+
toVersion,
|
|
391
|
+
pid: this.deps.pid,
|
|
392
|
+
relaunch: this.relaunchMethod(supervisor),
|
|
393
|
+
message: request.when === 'idle' ? `${label} will start when no agent is mid-turn.` : `${label} is starting.`,
|
|
394
|
+
};
|
|
395
|
+
this.persist();
|
|
396
|
+
this.deps.logger.info(`${label} requested`, {
|
|
397
|
+
id: this.action.id,
|
|
398
|
+
when: request.when,
|
|
399
|
+
requestedBy: request.actor,
|
|
400
|
+
fromVersion: this.deps.currentVersion,
|
|
401
|
+
supervisor: supervisor.kind,
|
|
402
|
+
willRelaunch: supervisor.willRelaunch,
|
|
403
|
+
});
|
|
404
|
+
return this.action;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Upgrade body: (wait for idle) → install → verify → marker → restart.
|
|
408
|
+
*
|
|
409
|
+
* @param installer - AutoUpdate install path
|
|
410
|
+
* @param version - Target
|
|
411
|
+
*/
|
|
412
|
+
async runUpgrade(installer, version) {
|
|
413
|
+
if (this.action?.when === 'idle')
|
|
414
|
+
await this.waitForIdle();
|
|
415
|
+
if (this.deps.isShutdownInProgress()) {
|
|
416
|
+
this.fail('Crewly started shutting down for another reason before the upgrade began.');
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
this.update({ status: 'installing', message: `Installing ${version}…` });
|
|
420
|
+
const attempt = await installer.installVersion(version);
|
|
421
|
+
if (!attempt.ok) {
|
|
422
|
+
this.deps.logger.warn('Manual upgrade install failed; not restarting', { version, outcome: attempt.outcome, reason: attempt.reason, ...attempt.details });
|
|
423
|
+
this.fail(`Could not install ${version}: ${attempt.reason}. Crewly keeps running ${this.deps.currentVersion}.`);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
installer.writeUpgradeMarker(this.deps.currentVersion ?? 'unknown', version);
|
|
427
|
+
const restarted = this.restartNow(`owner upgrade ${this.deps.currentVersion} -> ${version}`, `Installed ${version}. Restarting…`);
|
|
428
|
+
if (!restarted)
|
|
429
|
+
installer.clearUpgradeMarker();
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Restart body: (wait for idle) → restart.
|
|
433
|
+
*/
|
|
434
|
+
async runRestart() {
|
|
435
|
+
if (this.action?.when === 'idle')
|
|
436
|
+
await this.waitForIdle();
|
|
437
|
+
if (this.deps.isShutdownInProgress()) {
|
|
438
|
+
this.fail('Crewly started shutting down for another reason before the restart began.');
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
await this.deps.sleep(SYSTEM_CONTROL_CONSTANTS.RESPONSE_FLUSH_MS);
|
|
442
|
+
this.restartNow('owner restart', 'Restarting… agents finish their current turn first.');
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Make sure something brings the backend back, then run the graceful
|
|
446
|
+
* restart.
|
|
447
|
+
*
|
|
448
|
+
* @param reason - Shutdown reason (logs)
|
|
449
|
+
* @param message - Owner-readable progress
|
|
450
|
+
* @returns False when the restart could not be started
|
|
451
|
+
*/
|
|
452
|
+
restartNow(reason, message) {
|
|
453
|
+
const supervisor = this.deps.getSupervisor();
|
|
454
|
+
const relaunch = this.relaunchMethod(supervisor);
|
|
455
|
+
if (relaunch === 'replacement') {
|
|
456
|
+
try {
|
|
457
|
+
this.deps.spawnReplacement(supervisor.willRelaunch === 'unknown');
|
|
458
|
+
this.deps.logger.info('Started the replacement launcher; it brings Crewly back after this process exits', {
|
|
459
|
+
supervisor: supervisor.kind,
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
this.fail(`Could not arrange for Crewly to come back (${errorText(error)}), so it was not restarted.`);
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
this.update({ status: 'restarting', relaunch, message });
|
|
468
|
+
this.deps.logger.info('Restarting Crewly', { reason, relaunch, requestedBy: this.action?.requestedBy });
|
|
469
|
+
let started = false;
|
|
470
|
+
try {
|
|
471
|
+
started = this.deps.requestGracefulRestart(reason);
|
|
472
|
+
}
|
|
473
|
+
catch (error) {
|
|
474
|
+
this.deps.logger.warn('Graceful restart unavailable; exiting directly', { error: errorText(error) });
|
|
475
|
+
}
|
|
476
|
+
if (!started) {
|
|
477
|
+
this.deps.logger.warn('No graceful shutdown handler; exiting with the restart code');
|
|
478
|
+
this.deps.exit(PROCESS_EXIT_CODES.RESTART_REQUESTED);
|
|
479
|
+
}
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Wait until no agent is mid-turn, at most IDLE_WAIT_CAP_MS; a later "now"
|
|
484
|
+
* request ends the wait at once.
|
|
485
|
+
*/
|
|
486
|
+
async waitForIdle() {
|
|
487
|
+
const deadline = this.deps.now() + SYSTEM_CONTROL_CONSTANTS.IDLE_WAIT_CAP_MS;
|
|
488
|
+
let cut = false;
|
|
489
|
+
const cutPromise = new Promise((resolve) => {
|
|
490
|
+
this.cutIdleWaitShort = () => {
|
|
491
|
+
cut = true;
|
|
492
|
+
resolve();
|
|
493
|
+
};
|
|
494
|
+
});
|
|
495
|
+
let lastBusy = '';
|
|
496
|
+
try {
|
|
497
|
+
for (;;) {
|
|
498
|
+
if (cut) {
|
|
499
|
+
this.update({ idleWaitEndedBy: 'now' });
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
const busy = this.safeBusyAgents().map((a) => a.session);
|
|
503
|
+
if (busy.length === 0) {
|
|
504
|
+
this.update({ idleWaitEndedBy: 'idle', waitingFor: [] });
|
|
505
|
+
this.deps.logger.info('No agent is mid-turn; going ahead', { id: this.action?.id });
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (this.deps.now() >= deadline) {
|
|
509
|
+
this.update({ idleWaitEndedBy: 'cap', waitingFor: busy });
|
|
510
|
+
this.deps.logger.info('Waited the maximum for agents to go idle; going ahead (the restart drain still lets turns finish)', {
|
|
511
|
+
id: this.action?.id,
|
|
512
|
+
busy,
|
|
513
|
+
});
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const key = busy.join(',');
|
|
517
|
+
if (key !== lastBusy) {
|
|
518
|
+
lastBusy = key;
|
|
519
|
+
this.update({ waitingFor: busy, message: `Waiting for ${busy.length} agent${busy.length === 1 ? '' : 's'} to finish: ${busy.join(', ')}.` });
|
|
520
|
+
}
|
|
521
|
+
await Promise.race([this.deps.sleep(SYSTEM_CONTROL_CONSTANTS.IDLE_POLL_MS), cutPromise]);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
finally {
|
|
525
|
+
this.cutIdleWaitShort = null;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Mark the current action failed.
|
|
530
|
+
*
|
|
531
|
+
* @param message - Owner-readable reason
|
|
532
|
+
*/
|
|
533
|
+
fail(message) {
|
|
534
|
+
if (!this.action)
|
|
535
|
+
return;
|
|
536
|
+
const now = new Date(this.deps.now()).toISOString();
|
|
537
|
+
this.update({ status: 'failed', message, completedAt: now, resultVersion: this.deps.currentVersion });
|
|
538
|
+
this.deps.logger.warn('Upgrade/restart failed', { id: this.action.id, kind: this.action.kind, message, requestedBy: this.action.requestedBy });
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Merge a patch into the current action and persist it.
|
|
542
|
+
*
|
|
543
|
+
* @param patch - Fields to change
|
|
544
|
+
*/
|
|
545
|
+
update(patch) {
|
|
546
|
+
if (!this.action)
|
|
547
|
+
return;
|
|
548
|
+
this.action = { ...this.action, ...patch, updatedAt: new Date(this.deps.now()).toISOString() };
|
|
549
|
+
this.persist();
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Write the current action (best-effort).
|
|
553
|
+
*/
|
|
554
|
+
persist() {
|
|
555
|
+
if (!this.action)
|
|
556
|
+
return;
|
|
557
|
+
try {
|
|
558
|
+
writeActionRecord(this.stateFile, this.action);
|
|
559
|
+
}
|
|
560
|
+
catch (error) {
|
|
561
|
+
this.deps.logger.warn('Could not save upgrade/restart progress', { error: errorText(error) });
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Error text.
|
|
567
|
+
*
|
|
568
|
+
* @param error - Anything thrown
|
|
569
|
+
* @returns Message
|
|
570
|
+
*/
|
|
571
|
+
function errorText(error) {
|
|
572
|
+
return error instanceof Error ? error.message : String(error);
|
|
573
|
+
}
|
|
574
|
+
//# sourceMappingURL=system-control.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-control.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/system/system-control.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -4815,4 +4815,59 @@ export declare const SECRET_SCRUB_CONSTANTS: {
|
|
|
4815
4815
|
/** settings.json under CREWLY_HOME, whose apiKeys are masked by exact value */
|
|
4816
4816
|
readonly SETTINGS_FILE: "settings.json";
|
|
4817
4817
|
};
|
|
4818
|
+
/**
|
|
4819
|
+
* Owner-facing Upgrade / Restart controls in the dashboard
|
|
4820
|
+
* (specs/2026-10-01-upgrade-restart-controls.md).
|
|
4821
|
+
*/
|
|
4822
|
+
export declare const SYSTEM_CONTROL_CONSTANTS: {
|
|
4823
|
+
/** Progress / outcome of the last upgrade or restart, under CREWLY_HOME */
|
|
4824
|
+
readonly STATE_FILE: "system-action.json";
|
|
4825
|
+
/** Log file under `<crewlyHome>/logs/` written by the detached replacement launcher */
|
|
4826
|
+
readonly REPLACEMENT_LOG_FILE: "restart-replacement.log";
|
|
4827
|
+
/** "When idle": longest wait for agents to finish their turns before going ahead anyway (ms) — 30 min */
|
|
4828
|
+
readonly IDLE_WAIT_CAP_MS: number;
|
|
4829
|
+
/** "When idle": how often the busy check runs while waiting (ms) */
|
|
4830
|
+
readonly IDLE_POLL_MS: number;
|
|
4831
|
+
/** Pause before shutting down so the HTTP answer reaches the dashboard (ms) */
|
|
4832
|
+
readonly RESPONSE_FLUSH_MS: 500;
|
|
4833
|
+
/** A registry answer older than this is re-fetched when the owner asks to upgrade (ms) */
|
|
4834
|
+
readonly REGISTRY_MAX_AGE_MS: number;
|
|
4835
|
+
/** Registry answer age accepted for the status read (ms) — matches auto-update */
|
|
4836
|
+
readonly STATUS_REGISTRY_MAX_AGE_MS: number;
|
|
4837
|
+
/** Replacement launcher: how often it checks whether the old process is gone (ms) */
|
|
4838
|
+
readonly REPLACEMENT_PID_POLL_MS: 500;
|
|
4839
|
+
/** Replacement launcher: give up waiting for the old process after this long (ms) — drain is ≤ 2 min */
|
|
4840
|
+
readonly REPLACEMENT_MAX_WAIT_MS: number;
|
|
4841
|
+
/** Replacement launcher: grace before checking the port when nothing is expected to relaunch us (ms) */
|
|
4842
|
+
readonly REPLACEMENT_PORT_GRACE_MS: number;
|
|
4843
|
+
/** Replacement launcher: grace when an unknown supervisor might relaunch us first (ms) */
|
|
4844
|
+
readonly REPLACEMENT_PORT_GRACE_UNKNOWN_MS: number;
|
|
4845
|
+
/** Login item script that keeps `crewly start` running on the owner's Mac */
|
|
4846
|
+
readonly LOGIN_WRAPPER_SCRIPT: "crewly-start.command";
|
|
4847
|
+
/** systemd unit `crewly service install` writes */
|
|
4848
|
+
readonly SYSTEMD_UNIT: "crewly.service";
|
|
4849
|
+
/** Accepted values of the `when` body field */
|
|
4850
|
+
readonly WHEN_VALUES: readonly ["idle", "now"];
|
|
4851
|
+
/** Refusal codes returned with 4xx/5xx answers */
|
|
4852
|
+
readonly CODES: {
|
|
4853
|
+
readonly OWNER_ONLY: "owner-only";
|
|
4854
|
+
readonly DEV_CHECKOUT: "dev-checkout";
|
|
4855
|
+
readonly NOT_NPM_GLOBAL: "not-npm-global";
|
|
4856
|
+
readonly UP_TO_DATE: "up-to-date";
|
|
4857
|
+
readonly IN_PROGRESS: "in-progress";
|
|
4858
|
+
readonly RESTART_IN_PROGRESS: "restart-in-progress";
|
|
4859
|
+
readonly REGISTRY_UNREACHABLE: "registry-unreachable";
|
|
4860
|
+
readonly UNAVAILABLE: "unavailable";
|
|
4861
|
+
readonly BAD_REQUEST: "bad-request";
|
|
4862
|
+
};
|
|
4863
|
+
/** Owner-facing messages (the dashboard shows these as-is; English only) */
|
|
4864
|
+
readonly MESSAGES: {
|
|
4865
|
+
readonly OWNER_ONLY: "Only the owner can upgrade or restart Crewly. Agents cannot trigger this.";
|
|
4866
|
+
readonly DEV_CHECKOUT: "This machine runs Crewly from a source checkout — update it with git (git pull, npm run build), then restart.";
|
|
4867
|
+
readonly NOT_NPM_GLOBAL: "This copy of Crewly is not a global npm install, so it cannot upgrade itself. Update it the way it was installed.";
|
|
4868
|
+
readonly UNAVAILABLE: "Upgrade and restart controls are not ready yet — Crewly is still starting. Try again in a minute.";
|
|
4869
|
+
readonly REGISTRY_UNREACHABLE: "Could not reach the npm registry to find the latest version. Try again later.";
|
|
4870
|
+
readonly RESTART_IN_PROGRESS: "Crewly is already shutting down or restarting.";
|
|
4871
|
+
};
|
|
4872
|
+
};
|
|
4818
4873
|
//# sourceMappingURL=constants.d.ts.map
|