@indigoai-us/hq-cli 5.345.47 → 5.345.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/CHANGELOG.md +5 -0
- package/assets/scaffold/core/scripts/hq-session.sh +113 -7
- package/assets/scaffold/core/scripts/lib/session-scope-capability.sh +101 -0
- package/dist/command-catalog.generated.d.ts +4 -0
- package/dist/command-catalog.generated.js +5 -0
- package/dist/commands/core-hq-session-native.d.ts +2 -0
- package/dist/commands/core-hq-session-native.js +242 -52
- package/dist/commands/core-resolve-company-native.d.ts +1 -0
- package/dist/commands/core-resolve-company-native.js +41 -11
- package/dist/commands/secrets.d.ts +5 -0
- package/dist/commands/secrets.js +181 -2
- package/dist/commands/workers.d.ts +4 -1
- package/dist/commands/workers.js +57 -15
- package/dist/lib/cli-flag-keys.d.ts +1 -0
- package/dist/lib/cli-flag-keys.js +1 -0
- package/dist/lib/core-utils/session-id.d.ts +6 -0
- package/dist/lib/core-utils/session-id.js +35 -0
- package/dist/lib/daemon/catalog.js +1 -1
- package/dist/lib/daemon/lanes-reconcile-guard.d.ts +6 -5
- package/dist/lib/daemon/lanes-reconcile-guard.js +26 -7
- package/dist/lib/daemon/run.d.ts +6 -0
- package/dist/lib/daemon/run.js +36 -9
- package/dist/lib/daemon/supervisor.d.ts +7 -1
- package/dist/lib/daemon/supervisor.js +50 -4
- package/dist/utils/resident-package-preload.js +4 -0
- package/package.json +1 -1
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
* - restart/trigger/stop requests from the CLI are polled and applied; a
|
|
14
14
|
* request for a unit that is not planned yet re-reads the plan first;
|
|
15
15
|
* - stop() sends SIGTERM to every child, escalates to SIGKILL after
|
|
16
|
-
* STOP_ESCALATION_MS
|
|
16
|
+
* STOP_ESCALATION_MS except for a sync runner already stopping, which it lets
|
|
17
|
+
* finish persisting pending pushes before resolving;
|
|
17
18
|
* - release() instead leaves every child running and reports the long-running
|
|
18
19
|
* ones, so the next daemon can adopt them (`adopt`). Adopted units whose
|
|
19
20
|
* command is unchanged keep running; changed ones are replaced one at a
|
|
@@ -27,6 +28,7 @@ const BACKOFF_BASE_MS = 1_000;
|
|
|
27
28
|
const BACKOFF_MAX_MS = 60_000;
|
|
28
29
|
const HEALTHY_RUN_MS = 60_000;
|
|
29
30
|
export const STOP_ESCALATION_MS = 10_000;
|
|
31
|
+
export const SYNC_RUNNER_PERSIST_GRACE_MS = 60_000;
|
|
30
32
|
const CLI_UPDATE_SYNC_IDLE_MAX_MS = 10 * 60_000;
|
|
31
33
|
export const CLI_UPDATE_SYNC_IDLE_KILL_GRACE_MS = 60_000;
|
|
32
34
|
const MESH_OWNER_RECHECK_MS = 15_000;
|
|
@@ -91,6 +93,7 @@ export function createSupervisor(deps) {
|
|
|
91
93
|
let handoffTimer;
|
|
92
94
|
/** Every child process not yet known to have exited, including ones the slots have let go of. */
|
|
93
95
|
const live = new Set();
|
|
96
|
+
const liveOwners = new Map();
|
|
94
97
|
let drained = null;
|
|
95
98
|
let onDrained = null;
|
|
96
99
|
let deferredCliRestart = false;
|
|
@@ -247,6 +250,16 @@ export function createSupervisor(deps) {
|
|
|
247
250
|
deps.log("error", `could not send ${signal} to ${slot.plan.id}: ${errorMessage(err)}`);
|
|
248
251
|
}
|
|
249
252
|
};
|
|
253
|
+
const syncRunnerIsStopping = (slot) => slot?.plan.service === "sync" && slot.lastProtocolStatus === "stopping";
|
|
254
|
+
const scheduleSyncRunnerPersistEscalation = (slot, child) => {
|
|
255
|
+
slot.killTimer = setT(() => {
|
|
256
|
+
slot.killTimer = undefined;
|
|
257
|
+
if (slot.child !== child)
|
|
258
|
+
return;
|
|
259
|
+
deps.log("warn", `${slot.plan.id} did not finish persisting pending pushes within ${SYNC_RUNNER_PERSIST_GRACE_MS / 1_000} s; sending SIGKILL${lastProtocolHint(slot)}`);
|
|
260
|
+
signalChild(slot, child, "SIGKILL");
|
|
261
|
+
}, SYNC_RUNNER_PERSIST_GRACE_MS);
|
|
262
|
+
};
|
|
250
263
|
/**
|
|
251
264
|
* Stop the slot's child (if any), then run `then` once it has exited. With
|
|
252
265
|
* `drain`, a unit that has a drain signal gets it first and SIGTERM only
|
|
@@ -276,6 +289,11 @@ export function createSupervisor(deps) {
|
|
|
276
289
|
slot.killTimer = undefined;
|
|
277
290
|
if (slot.child !== child)
|
|
278
291
|
return;
|
|
292
|
+
if (syncRunnerIsStopping(slot)) {
|
|
293
|
+
deps.log("info", `${slot.plan.id} is stopping; allowing ${SYNC_RUNNER_PERSIST_GRACE_MS / 1_000} s for pending pushes to persist`);
|
|
294
|
+
scheduleSyncRunnerPersistEscalation(slot, child);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
279
297
|
deps.log("warn", `${slot.plan.id} did not exit within ${killGraceMs / 1_000} s of SIGTERM; sending SIGKILL${lastProtocolHint(slot)}`);
|
|
280
298
|
signalChild(slot, child, "SIGKILL");
|
|
281
299
|
}, killGraceMs);
|
|
@@ -313,6 +331,7 @@ export function createSupervisor(deps) {
|
|
|
313
331
|
};
|
|
314
332
|
const watch = (slot, child) => {
|
|
315
333
|
live.add(child);
|
|
334
|
+
liveOwners.set(child, slot);
|
|
316
335
|
let ended = false;
|
|
317
336
|
const timeoutMs = slot.plan.heartbeatTimeoutMs;
|
|
318
337
|
const decoder = timeoutMs ? new StringDecoder("utf8") : null;
|
|
@@ -350,6 +369,8 @@ export function createSupervisor(deps) {
|
|
|
350
369
|
slot.syncPassActive = false;
|
|
351
370
|
else if (event.type === "status" && typeof event.state === "string") {
|
|
352
371
|
slot.lastProtocolStatus = event.state;
|
|
372
|
+
if (event.state === "stopping")
|
|
373
|
+
deps.onSyncRunnerStopping?.();
|
|
353
374
|
if (event.state === "stopped" || event.state === "waiting-for-lock")
|
|
354
375
|
slot.syncPassActive = false;
|
|
355
376
|
else if (slot.syncPassActive === undefined && (event.state === "starting" || event.state === "running")) {
|
|
@@ -405,6 +426,7 @@ export function createSupervisor(deps) {
|
|
|
405
426
|
return;
|
|
406
427
|
ended = true;
|
|
407
428
|
live.delete(child);
|
|
429
|
+
liveOwners.delete(child);
|
|
408
430
|
if (live.size === 0)
|
|
409
431
|
onDrained?.();
|
|
410
432
|
if (slot.child !== child)
|
|
@@ -991,10 +1013,8 @@ export function createSupervisor(deps) {
|
|
|
991
1013
|
clearT(handoffTimer);
|
|
992
1014
|
clearDeferredCliRestart();
|
|
993
1015
|
clearPendingSyncCommandRestart();
|
|
994
|
-
const childOwners = new Map();
|
|
1016
|
+
const childOwners = new Map(liveOwners);
|
|
995
1017
|
for (const slot of slots.values()) {
|
|
996
|
-
if (slot.child)
|
|
997
|
-
childOwners.set(slot.child, slot);
|
|
998
1018
|
clearTimer(slot);
|
|
999
1019
|
clearHeartbeatTimer(slot);
|
|
1000
1020
|
slot.child = undefined;
|
|
@@ -1020,9 +1040,16 @@ export function createSupervisor(deps) {
|
|
|
1020
1040
|
resolve();
|
|
1021
1041
|
return;
|
|
1022
1042
|
}
|
|
1043
|
+
const persistingSyncRunners = new Set();
|
|
1044
|
+
let persistEscalation;
|
|
1023
1045
|
const escalation = setT(() => {
|
|
1024
1046
|
for (const child of live) {
|
|
1025
1047
|
const owner = childOwners.get(child);
|
|
1048
|
+
if (owner && syncRunnerIsStopping(owner)) {
|
|
1049
|
+
deps.log("info", `${owner.plan.id} is stopping; allowing ${SYNC_RUNNER_PERSIST_GRACE_MS / 1_000} s for pending pushes to persist`);
|
|
1050
|
+
persistingSyncRunners.add(child);
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1026
1053
|
deps.log("warn", `${owner?.plan.id ?? `pid ${child.pid ?? "?"}`} did not exit within ${STOP_ESCALATION_MS / 1_000} s of SIGTERM; sending SIGKILL${owner ? lastProtocolHint(owner) : ""}`);
|
|
1027
1054
|
try {
|
|
1028
1055
|
child.kill("SIGKILL");
|
|
@@ -1031,10 +1058,28 @@ export function createSupervisor(deps) {
|
|
|
1031
1058
|
deps.log("error", `could not SIGKILL pid ${child.pid ?? "?"}: ${errorMessage(err)}`);
|
|
1032
1059
|
}
|
|
1033
1060
|
}
|
|
1061
|
+
if (persistingSyncRunners.size > 0) {
|
|
1062
|
+
persistEscalation = setT(() => {
|
|
1063
|
+
for (const child of persistingSyncRunners) {
|
|
1064
|
+
if (!live.has(child))
|
|
1065
|
+
continue;
|
|
1066
|
+
const owner = childOwners.get(child);
|
|
1067
|
+
deps.log("warn", `${owner?.plan.id ?? `pid ${child.pid ?? "?"}`} did not finish persisting pending pushes within ${SYNC_RUNNER_PERSIST_GRACE_MS / 1_000} s; sending SIGKILL${owner ? lastProtocolHint(owner) : ""}`);
|
|
1068
|
+
try {
|
|
1069
|
+
child.kill("SIGKILL");
|
|
1070
|
+
}
|
|
1071
|
+
catch (err) {
|
|
1072
|
+
deps.log("error", `could not SIGKILL pid ${child.pid ?? "?"}: ${errorMessage(err)}`);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}, SYNC_RUNNER_PERSIST_GRACE_MS);
|
|
1076
|
+
}
|
|
1034
1077
|
}, STOP_ESCALATION_MS);
|
|
1035
1078
|
onDrained = () => {
|
|
1036
1079
|
onDrained = null;
|
|
1037
1080
|
clearT(escalation);
|
|
1081
|
+
if (persistEscalation !== undefined)
|
|
1082
|
+
clearT(persistEscalation);
|
|
1038
1083
|
resolve();
|
|
1039
1084
|
};
|
|
1040
1085
|
});
|
|
@@ -1042,6 +1087,7 @@ export function createSupervisor(deps) {
|
|
|
1042
1087
|
},
|
|
1043
1088
|
reconcile,
|
|
1044
1089
|
state: snapshot,
|
|
1090
|
+
hasStoppingSyncRunner: () => [...liveOwners.values()].some(syncRunnerIsStopping),
|
|
1045
1091
|
release() {
|
|
1046
1092
|
const released = [];
|
|
1047
1093
|
for (const slot of slots.values()) {
|
|
@@ -83,6 +83,8 @@ export const RESIDENT_PACKAGE_MODULES = {
|
|
|
83
83
|
"../utils/cli-telemetry.js",
|
|
84
84
|
"../utils/cognito-session.js",
|
|
85
85
|
"../lib/first-sync-next-step.js",
|
|
86
|
+
"../lib/process-flag-company-context.js",
|
|
87
|
+
"../lib/flag-snapshot-file.js",
|
|
86
88
|
"@indigoai-us/hq-cloud",
|
|
87
89
|
],
|
|
88
90
|
};
|
|
@@ -352,6 +354,8 @@ const LOADERS = {
|
|
|
352
354
|
() => import("../utils/cli-telemetry.js"),
|
|
353
355
|
() => import("../utils/cognito-session.js"),
|
|
354
356
|
() => import("../lib/first-sync-next-step.js"),
|
|
357
|
+
() => import("../lib/process-flag-company-context.js"),
|
|
358
|
+
() => import("../lib/flag-snapshot-file.js"),
|
|
355
359
|
() => import("@indigoai-us/hq-cloud"),
|
|
356
360
|
],
|
|
357
361
|
};
|