hub-runner 0.2.1 → 0.2.3
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/bin/hub-runner.mjs +8 -2
- package/check.mjs +1336 -0
- package/main.mjs +43 -8
- package/package.json +3 -2
package/main.mjs
CHANGED
|
@@ -2174,17 +2174,17 @@ function createSupervisor({
|
|
|
2174
2174
|
warn(`[registry] ! ${entry.name} crashed: ${entry.error}`);
|
|
2175
2175
|
return changed(entry);
|
|
2176
2176
|
}
|
|
2177
|
-
const
|
|
2177
|
+
const delay3 = Math.min(BACKOFF_BASE_MS * 2 ** (entry.crashes.length - 1), BACKOFF_MAX_MS);
|
|
2178
2178
|
entry.status = "down";
|
|
2179
|
-
entry.nextRestartAt = new Date(now +
|
|
2180
|
-
warn(`[registry] ${entry.name} exited unexpectedly (${how}); restarting in ${
|
|
2179
|
+
entry.nextRestartAt = new Date(now + delay3).toISOString();
|
|
2180
|
+
warn(`[registry] ${entry.name} exited unexpectedly (${how}); restarting in ${delay3 / 1e3}s`);
|
|
2181
2181
|
entry.timer = setTimeout(async () => {
|
|
2182
2182
|
await untilTreeGone(pgid, tree, KILL_GRACE_MS);
|
|
2183
2183
|
if (entry.status !== "down" || entry.stopping) return;
|
|
2184
2184
|
entry.restarts++;
|
|
2185
2185
|
changed(entry);
|
|
2186
2186
|
void spawnAgent(entry, { recovered: true });
|
|
2187
|
-
},
|
|
2187
|
+
}, delay3);
|
|
2188
2188
|
entry.timer.unref();
|
|
2189
2189
|
changed(entry);
|
|
2190
2190
|
}
|
|
@@ -2575,7 +2575,7 @@ async function sendToBot(fetchFn, eve, d, context, loadImage) {
|
|
|
2575
2575
|
}
|
|
2576
2576
|
|
|
2577
2577
|
// ../../hosted-hub/runner/hub-runner.ts
|
|
2578
|
-
import { setTimeout as
|
|
2578
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
2579
2579
|
|
|
2580
2580
|
// ../../hosted-hub/runner/status.ts
|
|
2581
2581
|
import { renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
@@ -3130,6 +3130,8 @@ async function stageLocal(workspace, dir2, pnpm) {
|
|
|
3130
3130
|
for (const entry of readdirSync3(staged)) if (!SKIP.has(entry)) rmSync2(join3(staged, entry), { recursive: true, force: true });
|
|
3131
3131
|
}
|
|
3132
3132
|
cpSync(join3(workspace, "agents"), join3(dir2, "agents"), { recursive: true, force: true, filter: (p) => !SKIP.has(p.split("/").at(-1)) });
|
|
3133
|
+
rmSync2(join3(dir2, "lib"), { recursive: true, force: true });
|
|
3134
|
+
if (existsSync3(join3(workspace, "lib"))) cpSync(join3(workspace, "lib"), join3(dir2, "lib"), { recursive: true, filter: (p) => !SKIP.has(p.split("/").at(-1)) });
|
|
3133
3135
|
const config = join3(dir2, "hub.workspace.json");
|
|
3134
3136
|
if (existsSync3(config) || (() => {
|
|
3135
3137
|
try {
|
|
@@ -4545,6 +4547,38 @@ function modelCredential(o) {
|
|
|
4545
4547
|
} };
|
|
4546
4548
|
}
|
|
4547
4549
|
|
|
4550
|
+
// ../../hosted-hub/runner/held.ts
|
|
4551
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
4552
|
+
function heldReports(send, failed) {
|
|
4553
|
+
const told = /* @__PURE__ */ new Map();
|
|
4554
|
+
const now = (bot) => told.has(bot) ? told.get(bot) : null;
|
|
4555
|
+
let sending = Promise.resolve();
|
|
4556
|
+
const tell = (bot, reason) => sending = sending.catch(() => {
|
|
4557
|
+
}).then(async () => {
|
|
4558
|
+
if (now(bot) === reason) return;
|
|
4559
|
+
told.set(bot, void 0);
|
|
4560
|
+
await send({ bot, reason });
|
|
4561
|
+
if (reason) told.set(bot, reason);
|
|
4562
|
+
else told.delete(bot);
|
|
4563
|
+
});
|
|
4564
|
+
return (waiting, why) => {
|
|
4565
|
+
for (const bot of /* @__PURE__ */ new Set([...waiting, ...told.keys()])) {
|
|
4566
|
+
const reason = why(bot);
|
|
4567
|
+
if (now(bot) !== reason) tell(bot, reason).catch(failed);
|
|
4568
|
+
}
|
|
4569
|
+
};
|
|
4570
|
+
}
|
|
4571
|
+
async function stopWithin(stop, ms, signal) {
|
|
4572
|
+
const stopped = new AbortController();
|
|
4573
|
+
await Promise.race([
|
|
4574
|
+
stop.finally(() => stopped.abort()),
|
|
4575
|
+
delay(ms, void 0, { signal: AbortSignal.any([signal, stopped.signal]) }).then(() => {
|
|
4576
|
+
throw new Error(`it did not stop in ${ms / 1e3}s`);
|
|
4577
|
+
}, () => {
|
|
4578
|
+
})
|
|
4579
|
+
]);
|
|
4580
|
+
}
|
|
4581
|
+
|
|
4548
4582
|
// ../../hosted-hub/runner/hub-runner.ts
|
|
4549
4583
|
var realBots = { stage: stageLocal, supervise: createSupervisor };
|
|
4550
4584
|
var HeldElsewhere = class extends Error {
|
|
@@ -4822,7 +4856,7 @@ async function run3(config, bots = realBots) {
|
|
|
4822
4856
|
if (restarted.get(name)?.requestedAt !== requestedAt) {
|
|
4823
4857
|
if (agent) {
|
|
4824
4858
|
try {
|
|
4825
|
-
await supervisor.stop(agent);
|
|
4859
|
+
await stopWithin(supervisor.stop(agent), config.stopTimeoutMs ?? 6e4, shutdown.signal);
|
|
4826
4860
|
shutdown.signal.throwIfAborted();
|
|
4827
4861
|
supervisor.start(agent);
|
|
4828
4862
|
if (!await supervisor.waitUp(agent, 12e4)) throw new Error("it did not come back up");
|
|
@@ -4867,7 +4901,7 @@ async function run3(config, bots = realBots) {
|
|
|
4867
4901
|
}
|
|
4868
4902
|
}
|
|
4869
4903
|
let syncing = null, again = false, drained = null;
|
|
4870
|
-
const unsettled = /* @__PURE__ */ new Set();
|
|
4904
|
+
const unsettled = /* @__PURE__ */ new Set(), held = heldReports((body) => hubJson("/api/local-runner/setup", { method: "POST", body: JSON.stringify(body), signal: AbortSignal.timeout(ACK_MS) }), (e) => failed("held report", e));
|
|
4871
4905
|
async function sync() {
|
|
4872
4906
|
const work = await hubJson("/api/local-runner/work");
|
|
4873
4907
|
if (drained && !work.sessions.length && !work.children.length && !work.deliveries.some(([d]) => unsettled.has(d.id))) {
|
|
@@ -4895,6 +4929,7 @@ async function run3(config, bots = realBots) {
|
|
|
4895
4929
|
for (const [id, abort] of following) if (![...sessions, ...work.children].some((s) => s.sessionId === id)) abort.abort();
|
|
4896
4930
|
restart(work);
|
|
4897
4931
|
compact2(work);
|
|
4932
|
+
held(work.deliveries.map(([d]) => d.bot), (bot) => drained ? "draining" : restarting.has(bot) ? "restarting" : !running.has(bot) ? "stopped" : null);
|
|
4898
4933
|
await Promise.all([
|
|
4899
4934
|
...sessions.filter((s) => s.cancel.length).map((s) => cancel(s, work.human).catch((e) => failed("cancel", e))),
|
|
4900
4935
|
...work.deliveries.filter(([d]) => (!drained || unsettled.has(d.id)) && running.has(d.bot) && !restarting.has(d.bot) && !dead.has(d.bot) && !retired.has(d.sessionId)).map((q) => deliver(q, work).catch((e) => failed("delivery", e)))
|
|
@@ -4951,7 +4986,7 @@ async function run3(config, bots = realBots) {
|
|
|
4951
4986
|
} finally {
|
|
4952
4987
|
clearTimeout(watchdog);
|
|
4953
4988
|
}
|
|
4954
|
-
await
|
|
4989
|
+
await delay2(RETRY_MS, void 0, { signal: shutdown.signal }).catch(() => {
|
|
4955
4990
|
});
|
|
4956
4991
|
}
|
|
4957
4992
|
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hub-runner",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Runs a hub workspace's Mac bots on this Mac under launchd, with no app needed.",
|
|
6
6
|
"type": "module",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"bin",
|
|
12
12
|
"lib",
|
|
13
|
-
"main.mjs"
|
|
13
|
+
"main.mjs",
|
|
14
|
+
"check.mjs"
|
|
14
15
|
],
|
|
15
16
|
"engines": {
|
|
16
17
|
"node": ">=24"
|