@rynx-ai/daemon 0.1.11-beta.2 → 0.1.11-beta.4
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/bundled-plugins/plugins/lark/dist/runtime.js +6 -7
- package/bundled-plugins/plugins/lark/dist/settings.js +6 -4
- package/bundled-plugins/plugins/lark/package.json +1 -1
- package/dist/browser-artifact-management.d.ts +4 -1
- package/dist/browser-artifact-management.js +18 -10
- package/dist/browser-artifacts.d.ts +1 -0
- package/dist/browser-artifacts.js +1 -0
- package/dist/chrome-for-testing-runtime.d.ts +27 -0
- package/dist/chrome-for-testing-runtime.js +193 -0
- package/dist/chrome-for-testing-store.d.ts +2 -0
- package/dist/chrome-for-testing-store.js +9 -0
- package/dist/daemon-server.d.ts +4 -1
- package/dist/daemon-server.js +137 -32
- package/dist/db.js +2 -0
- package/dist/entry-path.d.ts +3 -0
- package/dist/entry-path.js +12 -0
- package/dist/index-daemon.js +3 -87
- package/dist/lifecycle.d.ts +12 -0
- package/dist/lifecycle.js +16 -0
- package/dist/maintenance-lease.d.ts +39 -0
- package/dist/maintenance-lease.js +250 -0
- package/dist/plugin-host-rpc.d.ts +19 -1
- package/dist/plugin-host-rpc.js +163 -23
- package/dist/plugin-installer.js +59 -0
- package/dist/plugin-supervisor.d.ts +5 -0
- package/dist/plugin-supervisor.js +218 -29
- package/dist/pm2.d.ts +11 -2
- package/dist/pm2.js +116 -19
- package/dist/process.d.ts +12 -0
- package/dist/process.js +91 -0
- package/dist/session-launch-operations.d.ts +10 -1
- package/dist/session-launch-operations.js +15 -6
- package/dist/setup-service.d.ts +20 -0
- package/dist/setup-service.js +38 -0
- package/package.json +33 -20
- package/dist/browser-cli-args.d.ts +0 -20
- package/dist/browser-cli-args.js +0 -100
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -550
- package/dist/control-client.d.ts +0 -122
- package/dist/control-client.js +0 -855
- package/dist/control-endpoint.d.ts +0 -14
- package/dist/control-endpoint.js +0 -124
- package/dist/desktop-browser-host-client.d.ts +0 -35
- package/dist/desktop-browser-host-client.js +0 -415
- package/dist/setup.d.ts +0 -20
- package/dist/setup.js +0 -386
- package/dist/update.d.ts +0 -25
- package/dist/update.js +0 -133
package/dist/plugin-installer.js
CHANGED
|
@@ -180,6 +180,8 @@ export async function uninstallPlugin(identity, onProgress = () => { }, options
|
|
|
180
180
|
throw new Error(`bundled plugin "${record.canonicalId}" cannot be uninstalled; disable it instead`);
|
|
181
181
|
}
|
|
182
182
|
assertNoActiveLeases(record);
|
|
183
|
+
if (options.purgeData)
|
|
184
|
+
assertNoOwnedSessions(record);
|
|
183
185
|
return removePlugin(record.canonicalId);
|
|
184
186
|
}).immediate();
|
|
185
187
|
if (!removed)
|
|
@@ -193,9 +195,37 @@ export async function uninstallPlugin(identity, onProgress = () => { }, options
|
|
|
193
195
|
onProgress(`uninstalled plugin "${record.canonicalId}"`);
|
|
194
196
|
return true;
|
|
195
197
|
}
|
|
198
|
+
function assertNoOwnedSessions(record) {
|
|
199
|
+
const row = db()
|
|
200
|
+
.prepare(`WITH RECURSIVE owned(id) AS (
|
|
201
|
+
SELECT session_id
|
|
202
|
+
FROM plugin_session_launch_operations
|
|
203
|
+
WHERE plugin_id = ?
|
|
204
|
+
UNION
|
|
205
|
+
SELECT id FROM sessions WHERE source = ?
|
|
206
|
+
UNION
|
|
207
|
+
SELECT sessions.id
|
|
208
|
+
FROM sessions
|
|
209
|
+
JOIN owned ON sessions.forked_from_session_id = owned.id
|
|
210
|
+
UNION
|
|
211
|
+
SELECT session_fork_operations.target_session_id
|
|
212
|
+
FROM session_fork_operations
|
|
213
|
+
JOIN owned ON session_fork_operations.source_session_id = owned.id
|
|
214
|
+
)
|
|
215
|
+
SELECT COUNT(*) AS count
|
|
216
|
+
FROM sessions
|
|
217
|
+
JOIN owned ON sessions.id = owned.id`)
|
|
218
|
+
.get(record.canonicalId, `plugin:${record.canonicalId}`);
|
|
219
|
+
if (row.count > 0) {
|
|
220
|
+
throw new Error(`cannot purge plugin "${record.canonicalId}": ${row.count} plugin-owned Session(s) still exist`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
196
223
|
export function pruneInactivePluginInstallations() {
|
|
197
224
|
const { cacheRoot } = ensureStorageRoots();
|
|
198
225
|
const active = new Set(listActivePaths().map(canonicalFilesystemPath));
|
|
226
|
+
for (const leased of listActiveRuntimeLeasePaths(cacheRoot)) {
|
|
227
|
+
active.add(leased);
|
|
228
|
+
}
|
|
199
229
|
const removed = [];
|
|
200
230
|
for (const marketplace of safeDirectories(cacheRoot)) {
|
|
201
231
|
for (const plugin of safeDirectories(join(cacheRoot, marketplace))) {
|
|
@@ -327,6 +357,35 @@ function listActivePaths() {
|
|
|
327
357
|
}
|
|
328
358
|
return paths;
|
|
329
359
|
}
|
|
360
|
+
function listActiveRuntimeLeasePaths(cacheRoot) {
|
|
361
|
+
const dataRoot = join(rynxHome(), "plugins", "data");
|
|
362
|
+
const active = [];
|
|
363
|
+
for (const marketplace of safeDirectories(dataRoot)) {
|
|
364
|
+
for (const plugin of safeDirectories(join(dataRoot, marketplace))) {
|
|
365
|
+
const generationRoot = join(cacheRoot, marketplace, plugin);
|
|
366
|
+
const managedGenerations = new Set(safeDirectories(generationRoot).map((generation) => canonicalFilesystemPath(join(generationRoot, generation))));
|
|
367
|
+
if (managedGenerations.size === 0)
|
|
368
|
+
continue;
|
|
369
|
+
const dataDir = join(dataRoot, marketplace, plugin);
|
|
370
|
+
for (const lease of readPluginRuntimeLeases(dataDir)) {
|
|
371
|
+
// A lease is plugin-owned input. It may pin only the same plugin
|
|
372
|
+
// namespace from which it was read and only one exact host-owned,
|
|
373
|
+
// immutable generation directory.
|
|
374
|
+
if (lease.pluginId !== plugin)
|
|
375
|
+
continue;
|
|
376
|
+
const pid = pluginCliInvocationLeasePid(lease.leaseId);
|
|
377
|
+
if (pid !== undefined && !isProcessAlive(pid)) {
|
|
378
|
+
removePluginRuntimeLease(dataDir, lease.leaseId);
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
const installPath = canonicalFilesystemPath(lease.installPath);
|
|
382
|
+
if (managedGenerations.has(installPath))
|
|
383
|
+
active.push(installPath);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return active;
|
|
388
|
+
}
|
|
330
389
|
function safeProgress(callback) {
|
|
331
390
|
return (line) => {
|
|
332
391
|
try {
|
|
@@ -20,6 +20,8 @@ export interface PluginSupervisorOptions {
|
|
|
20
20
|
restartMaxMs?: number;
|
|
21
21
|
healthPollMs?: number;
|
|
22
22
|
daemonInstanceId?: string;
|
|
23
|
+
productVersion?: string;
|
|
24
|
+
cliVersion?: string;
|
|
23
25
|
verifyPackage?: (record: RunnablePluginRecord) => Promise<void>;
|
|
24
26
|
}
|
|
25
27
|
export interface PluginRuntimeStatusSnapshot {
|
|
@@ -42,12 +44,15 @@ export declare class PluginSupervisor {
|
|
|
42
44
|
private readonly spawnRunner;
|
|
43
45
|
private readonly log;
|
|
44
46
|
private readonly daemonInstanceId;
|
|
47
|
+
private readonly productVersion;
|
|
48
|
+
private readonly cliVersion;
|
|
45
49
|
private readonly restartBaseMs;
|
|
46
50
|
private readonly restartMaxMs;
|
|
47
51
|
private readonly healthPollMs;
|
|
48
52
|
private readonly verifyPackage;
|
|
49
53
|
private services?;
|
|
50
54
|
private disposed;
|
|
55
|
+
private disposePromise?;
|
|
51
56
|
constructor(records: readonly RunnablePluginRecord[], options?: PluginSupervisorOptions);
|
|
52
57
|
bindHostServices(services: PluginHostServices): void;
|
|
53
58
|
startPluginRuntimes(): Promise<void>;
|
|
@@ -23,17 +23,22 @@ export class PluginSupervisor {
|
|
|
23
23
|
spawnRunner;
|
|
24
24
|
log;
|
|
25
25
|
daemonInstanceId;
|
|
26
|
+
productVersion;
|
|
27
|
+
cliVersion;
|
|
26
28
|
restartBaseMs;
|
|
27
29
|
restartMaxMs;
|
|
28
30
|
healthPollMs;
|
|
29
31
|
verifyPackage;
|
|
30
32
|
services;
|
|
31
33
|
disposed = false;
|
|
34
|
+
disposePromise;
|
|
32
35
|
constructor(records, options = {}) {
|
|
33
36
|
this.services = options.services;
|
|
34
37
|
this.spawnRunner = options.spawnRunner ?? spawnPluginRunner;
|
|
35
38
|
this.log = options.log ?? (() => { });
|
|
36
39
|
this.daemonInstanceId = options.daemonInstanceId ?? randomUUID();
|
|
40
|
+
this.productVersion = options.productVersion ?? "development";
|
|
41
|
+
this.cliVersion = options.cliVersion ?? "development";
|
|
37
42
|
this.restartBaseMs = options.restartBaseMs ?? DEFAULT_RESTART_BASE_MS;
|
|
38
43
|
this.restartMaxMs = Math.min(options.restartMaxMs ?? MAX_RESTART_DELAY_MS, MAX_RESTART_DELAY_MS);
|
|
39
44
|
this.healthPollMs = options.healthPollMs ?? DEFAULT_HEALTH_POLL_MS;
|
|
@@ -211,13 +216,27 @@ export class PluginSupervisor {
|
|
|
211
216
|
};
|
|
212
217
|
}
|
|
213
218
|
async dispose() {
|
|
214
|
-
if (this.
|
|
215
|
-
return;
|
|
219
|
+
if (this.disposePromise)
|
|
220
|
+
return this.disposePromise;
|
|
216
221
|
this.disposed = true;
|
|
217
|
-
|
|
218
|
-
await this.
|
|
219
|
-
|
|
220
|
-
|
|
222
|
+
const attempt = (async () => {
|
|
223
|
+
const stopped = await Promise.allSettled([...this.states.values()].map((state) => this.runSerialized(state.record.canonicalId, async () => {
|
|
224
|
+
await this.stopState(state);
|
|
225
|
+
await this.stopSettingsState(state);
|
|
226
|
+
})));
|
|
227
|
+
const failures = stopped
|
|
228
|
+
.filter((result) => result.status === "rejected")
|
|
229
|
+
.map((result) => result.reason);
|
|
230
|
+
if (failures.length > 0) {
|
|
231
|
+
throw new AggregateError(failures, "plugin supervisor could not stop every runtime");
|
|
232
|
+
}
|
|
233
|
+
})();
|
|
234
|
+
this.disposePromise = attempt;
|
|
235
|
+
void attempt.catch(() => {
|
|
236
|
+
if (this.disposePromise === attempt)
|
|
237
|
+
this.disposePromise = undefined;
|
|
238
|
+
});
|
|
239
|
+
return attempt;
|
|
221
240
|
}
|
|
222
241
|
upsertState(record) {
|
|
223
242
|
const current = this.states.get(record.canonicalId);
|
|
@@ -237,7 +256,10 @@ export class PluginSupervisor {
|
|
|
237
256
|
return state;
|
|
238
257
|
}
|
|
239
258
|
async startState(state) {
|
|
240
|
-
if (this.disposed
|
|
259
|
+
if (this.disposed
|
|
260
|
+
|| state.runner
|
|
261
|
+
|| blockingCleanupError(state)
|
|
262
|
+
|| !state.record.enabled)
|
|
241
263
|
return;
|
|
242
264
|
const runtime = state.record.manifest.runtime;
|
|
243
265
|
if (!runtime) {
|
|
@@ -270,6 +292,8 @@ export class PluginSupervisor {
|
|
|
270
292
|
pluginId: state.record.pluginId,
|
|
271
293
|
principalId: state.record.canonicalId,
|
|
272
294
|
daemonInstanceId: this.daemonInstanceId,
|
|
295
|
+
productVersion: this.productVersion,
|
|
296
|
+
cliVersion: this.cliVersion,
|
|
273
297
|
capabilities: state.record.manifest.capabilities,
|
|
274
298
|
services: this.services,
|
|
275
299
|
...(state.record.pluginId === "workspace"
|
|
@@ -333,8 +357,21 @@ export class PluginSupervisor {
|
|
|
333
357
|
});
|
|
334
358
|
}
|
|
335
359
|
catch (error) {
|
|
336
|
-
|
|
360
|
+
try {
|
|
361
|
+
await hostRpc?.dispose();
|
|
362
|
+
}
|
|
363
|
+
catch (cleanupError) {
|
|
364
|
+
const failure = new AggregateError([error, cleanupError], "plugin runtime startup failed and active-run cleanup was unproven");
|
|
365
|
+
state.runtimeCleanupError = failure;
|
|
366
|
+
this.failState(state, failure);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
337
369
|
state.hostRpc = undefined;
|
|
370
|
+
if (isUnprovenProcessCleanup(error)) {
|
|
371
|
+
state.runtimeCleanupError = error;
|
|
372
|
+
this.failState(state, error);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
338
375
|
removePluginRuntimeLease(dataDir, RUNTIME_LEASE_ID);
|
|
339
376
|
this.failState(state, error);
|
|
340
377
|
this.scheduleRestart(state);
|
|
@@ -343,6 +380,9 @@ export class PluginSupervisor {
|
|
|
343
380
|
async startSettingsState(state) {
|
|
344
381
|
if (this.disposed)
|
|
345
382
|
throw new Error("plugin supervisor is disposed");
|
|
383
|
+
const cleanupError = blockingCleanupError(state);
|
|
384
|
+
if (cleanupError)
|
|
385
|
+
throw cleanupError;
|
|
346
386
|
if (state.settingsRunner)
|
|
347
387
|
return state.settingsRunner;
|
|
348
388
|
const background = state.record.manifest.settings?.background;
|
|
@@ -369,6 +409,8 @@ export class PluginSupervisor {
|
|
|
369
409
|
pluginId: state.record.pluginId,
|
|
370
410
|
principalId: state.record.canonicalId,
|
|
371
411
|
daemonInstanceId: this.daemonInstanceId,
|
|
412
|
+
productVersion: this.productVersion,
|
|
413
|
+
cliVersion: this.cliVersion,
|
|
372
414
|
capabilities: state.record.manifest.capabilities,
|
|
373
415
|
services: this.services,
|
|
374
416
|
...(state.record.pluginId === "workspace"
|
|
@@ -429,8 +471,32 @@ export class PluginSupervisor {
|
|
|
429
471
|
return runner;
|
|
430
472
|
}
|
|
431
473
|
catch (error) {
|
|
432
|
-
|
|
433
|
-
|
|
474
|
+
const cleanupErrors = [];
|
|
475
|
+
if (runner) {
|
|
476
|
+
try {
|
|
477
|
+
await runner.close();
|
|
478
|
+
}
|
|
479
|
+
catch (cleanupError) {
|
|
480
|
+
state.settingsRunner = runner;
|
|
481
|
+
cleanupErrors.push(cleanupError);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
try {
|
|
485
|
+
await hostRpc?.dispose();
|
|
486
|
+
}
|
|
487
|
+
catch (cleanupError) {
|
|
488
|
+
state.settingsHostRpc = hostRpc;
|
|
489
|
+
cleanupErrors.push(cleanupError);
|
|
490
|
+
}
|
|
491
|
+
if (cleanupErrors.length > 0) {
|
|
492
|
+
const failure = new AggregateError([error, ...cleanupErrors], "plugin settings startup failed and cleanup was unproven");
|
|
493
|
+
state.settingsCleanupError = failure;
|
|
494
|
+
throw failure;
|
|
495
|
+
}
|
|
496
|
+
if (isUnprovenProcessCleanup(error)) {
|
|
497
|
+
state.settingsCleanupError = error;
|
|
498
|
+
throw error;
|
|
499
|
+
}
|
|
434
500
|
removePluginRuntimeLease(dataDir, SETTINGS_LEASE_ID);
|
|
435
501
|
throw error;
|
|
436
502
|
}
|
|
@@ -438,20 +504,71 @@ export class PluginSupervisor {
|
|
|
438
504
|
async stopSettingsState(state) {
|
|
439
505
|
const runner = state.settingsRunner;
|
|
440
506
|
const hostRpc = state.settingsHostRpc;
|
|
441
|
-
state.
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
507
|
+
if (state.settingsCleanupError && !runner && !hostRpc) {
|
|
508
|
+
throw state.settingsCleanupError;
|
|
509
|
+
}
|
|
510
|
+
const errors = [];
|
|
511
|
+
if (runner) {
|
|
512
|
+
try {
|
|
513
|
+
await runner.close();
|
|
514
|
+
if (state.settingsRunner === runner)
|
|
515
|
+
state.settingsRunner = undefined;
|
|
516
|
+
}
|
|
517
|
+
catch (error) {
|
|
518
|
+
errors.push(error);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (hostRpc) {
|
|
522
|
+
try {
|
|
523
|
+
await hostRpc.dispose();
|
|
524
|
+
if (state.settingsHostRpc === hostRpc)
|
|
525
|
+
state.settingsHostRpc = undefined;
|
|
526
|
+
}
|
|
527
|
+
catch (error) {
|
|
528
|
+
errors.push(error);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (errors.length > 0) {
|
|
532
|
+
const failure = cleanupFailure(errors, "plugin settings cleanup was unproven");
|
|
533
|
+
state.settingsCleanupError = failure;
|
|
534
|
+
throw failure;
|
|
535
|
+
}
|
|
536
|
+
state.settingsCleanupError = undefined;
|
|
445
537
|
removePluginRuntimeLease(pluginDataDir(state.record.marketplaceId, state.record.pluginId), SETTINGS_LEASE_ID);
|
|
446
538
|
}
|
|
447
539
|
async handleSettingsExit(state, runner, hostRpc, exit) {
|
|
448
540
|
if (state.settingsRunner !== runner)
|
|
449
541
|
return;
|
|
542
|
+
try {
|
|
543
|
+
await runner.terminateTree();
|
|
544
|
+
}
|
|
545
|
+
catch (error) {
|
|
546
|
+
state.settingsCleanupError = error;
|
|
547
|
+
this.log({
|
|
548
|
+
level: "error",
|
|
549
|
+
event: "plugin-settings-exited",
|
|
550
|
+
pluginId: state.record.canonicalId,
|
|
551
|
+
message: error instanceof Error ? error.message : String(error),
|
|
552
|
+
});
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
450
555
|
state.settingsRunner = undefined;
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
556
|
+
try {
|
|
557
|
+
await hostRpc.dispose();
|
|
558
|
+
if (state.settingsHostRpc === hostRpc)
|
|
559
|
+
state.settingsHostRpc = undefined;
|
|
560
|
+
}
|
|
561
|
+
catch (error) {
|
|
562
|
+
state.settingsCleanupError = error;
|
|
563
|
+
this.log({
|
|
564
|
+
level: "error",
|
|
565
|
+
event: "plugin-settings-exited",
|
|
566
|
+
pluginId: state.record.canonicalId,
|
|
567
|
+
message: error instanceof Error ? error.message : String(error),
|
|
568
|
+
});
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
state.settingsCleanupError = undefined;
|
|
455
572
|
removePluginRuntimeLease(pluginDataDir(state.record.marketplaceId, state.record.pluginId), SETTINGS_LEASE_ID);
|
|
456
573
|
if (!this.disposed) {
|
|
457
574
|
this.log({
|
|
@@ -473,10 +590,38 @@ export class PluginSupervisor {
|
|
|
473
590
|
clearTimeout(state.healthTimer);
|
|
474
591
|
state.healthTimer = undefined;
|
|
475
592
|
const runner = state.runner;
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
593
|
+
const hostRpc = state.hostRpc;
|
|
594
|
+
if (state.runtimeCleanupError && !runner && !hostRpc) {
|
|
595
|
+
throw state.runtimeCleanupError;
|
|
596
|
+
}
|
|
597
|
+
const errors = [];
|
|
598
|
+
if (runner) {
|
|
599
|
+
try {
|
|
600
|
+
await runner.close();
|
|
601
|
+
if (state.runner === runner)
|
|
602
|
+
state.runner = undefined;
|
|
603
|
+
}
|
|
604
|
+
catch (error) {
|
|
605
|
+
errors.push(error);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
if (hostRpc) {
|
|
609
|
+
try {
|
|
610
|
+
await hostRpc.dispose();
|
|
611
|
+
if (state.hostRpc === hostRpc)
|
|
612
|
+
state.hostRpc = undefined;
|
|
613
|
+
}
|
|
614
|
+
catch (error) {
|
|
615
|
+
errors.push(error);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (errors.length > 0) {
|
|
619
|
+
const failure = cleanupFailure(errors, "plugin runtime cleanup was unproven");
|
|
620
|
+
state.runtimeCleanupError = failure;
|
|
621
|
+
this.failState(state, failure);
|
|
622
|
+
throw failure;
|
|
623
|
+
}
|
|
624
|
+
state.runtimeCleanupError = undefined;
|
|
480
625
|
removePluginRuntimeLease(pluginDataDir(state.record.marketplaceId, state.record.pluginId), RUNTIME_LEASE_ID);
|
|
481
626
|
state.health = undefined;
|
|
482
627
|
state.error = undefined;
|
|
@@ -489,10 +634,26 @@ export class PluginSupervisor {
|
|
|
489
634
|
if (state.healthTimer)
|
|
490
635
|
clearTimeout(state.healthTimer);
|
|
491
636
|
state.healthTimer = undefined;
|
|
637
|
+
try {
|
|
638
|
+
await runner.terminateTree();
|
|
639
|
+
}
|
|
640
|
+
catch (error) {
|
|
641
|
+
state.runtimeCleanupError = error;
|
|
642
|
+
this.failState(state, error);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
492
645
|
state.runner = undefined;
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
646
|
+
try {
|
|
647
|
+
await state.hostRpc?.dispose();
|
|
648
|
+
state.hostRpc = undefined;
|
|
649
|
+
}
|
|
650
|
+
catch (error) {
|
|
651
|
+
state.runtimeCleanupError = error;
|
|
652
|
+
if (!state.stopping && !this.disposed)
|
|
653
|
+
this.failState(state, error);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
state.runtimeCleanupError = undefined;
|
|
496
657
|
removePluginRuntimeLease(pluginDataDir(state.record.marketplaceId, state.record.pluginId), RUNTIME_LEASE_ID);
|
|
497
658
|
if (state.stopping || this.disposed)
|
|
498
659
|
return;
|
|
@@ -571,13 +732,29 @@ export class PluginSupervisor {
|
|
|
571
732
|
async failRunningState(state, runner, error) {
|
|
572
733
|
if (state.runner !== runner)
|
|
573
734
|
return;
|
|
574
|
-
state.runner = undefined;
|
|
575
735
|
if (state.healthTimer)
|
|
576
736
|
clearTimeout(state.healthTimer);
|
|
577
737
|
state.healthTimer = undefined;
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
738
|
+
try {
|
|
739
|
+
await runner.close();
|
|
740
|
+
}
|
|
741
|
+
catch (cleanupError) {
|
|
742
|
+
state.runtimeCleanupError = cleanupError;
|
|
743
|
+
this.failState(state, cleanupError);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
state.runner = undefined;
|
|
747
|
+
try {
|
|
748
|
+
await state.hostRpc?.dispose();
|
|
749
|
+
state.hostRpc = undefined;
|
|
750
|
+
}
|
|
751
|
+
catch (cleanupError) {
|
|
752
|
+
state.runtimeCleanupError = cleanupError;
|
|
753
|
+
if (!state.stopping && !this.disposed)
|
|
754
|
+
this.failState(state, cleanupError);
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
state.runtimeCleanupError = undefined;
|
|
581
758
|
removePluginRuntimeLease(pluginDataDir(state.record.marketplaceId, state.record.pluginId), RUNTIME_LEASE_ID);
|
|
582
759
|
if (state.stopping || this.disposed)
|
|
583
760
|
return;
|
|
@@ -595,6 +772,18 @@ export class PluginSupervisor {
|
|
|
595
772
|
return current;
|
|
596
773
|
}
|
|
597
774
|
}
|
|
775
|
+
function cleanupFailure(errors, message) {
|
|
776
|
+
return errors.length === 1 ? errors[0] : new AggregateError(errors, message);
|
|
777
|
+
}
|
|
778
|
+
function blockingCleanupError(state) {
|
|
779
|
+
return state.runtimeCleanupError ?? state.settingsCleanupError;
|
|
780
|
+
}
|
|
781
|
+
function isUnprovenProcessCleanup(error) {
|
|
782
|
+
return Boolean(error
|
|
783
|
+
&& typeof error === "object"
|
|
784
|
+
&& "code" in error
|
|
785
|
+
&& error.code === "PROCESS_TREE_STUCK");
|
|
786
|
+
}
|
|
598
787
|
function healthState(health) {
|
|
599
788
|
return health.state;
|
|
600
789
|
}
|
package/dist/pm2.d.ts
CHANGED
|
@@ -8,12 +8,21 @@ export declare function formatControlUrl(host: string, port: number): string;
|
|
|
8
8
|
* entry from scratch (delete + start) so config flags are always fresh; the
|
|
9
9
|
* `force === false` path short-circuits when it's already online.
|
|
10
10
|
*/
|
|
11
|
-
export declare function startDaemon({ force, quiet }: {
|
|
11
|
+
export declare function startDaemon({ force, quiet, launchEnvironment, }: {
|
|
12
12
|
force: boolean;
|
|
13
13
|
quiet?: boolean;
|
|
14
|
+
launchEnvironment?: NodeJS.ProcessEnv;
|
|
14
15
|
}): number;
|
|
15
16
|
export declare function isPm2DaemonOnline(): boolean;
|
|
16
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Stop the daemon and terminate its dedicated pm2 supervisor.
|
|
19
|
+
*
|
|
20
|
+
* PM2_HOME lives below RYNX_HOME, so this supervisor cannot own unrelated
|
|
21
|
+
* applications. Leaving it alive across an npm replacement is unsafe: the
|
|
22
|
+
* daemon process container path is resolved inside the old pm2 package. Once
|
|
23
|
+
* npm swaps @rynx-ai/daemon, that cached path may no longer exist and every
|
|
24
|
+
* subsequent `rynx start` enters a restart loop before our code can run.
|
|
25
|
+
*/
|
|
17
26
|
export declare function stopDaemon(): number;
|
|
18
27
|
/** Print a one-line status; exit 0 only when online. */
|
|
19
28
|
export declare function statusDaemon(): number;
|