tines 0.0.142 → 0.0.143
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/dist/index.js +118 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4029,6 +4029,7 @@ function createApiClient(options) {
|
|
|
4029
4029
|
deleteRoutingRule: (id) => request("DELETE", `/api/v1/routing-rules/${id}`),
|
|
4030
4030
|
// Supervisor settings
|
|
4031
4031
|
getSupervisorSettings: () => get("/api/v1/supervisor/settings"),
|
|
4032
|
+
getSupervisorQueue: () => get("/api/v1/supervisor/queue"),
|
|
4032
4033
|
updateSupervisorSettings: (body) => request("PUT", "/api/v1/supervisor/settings", body),
|
|
4033
4034
|
// API keys (create/revoke require a browser session, not a key)
|
|
4034
4035
|
listApiKeys: (filters = {}) => get(`/api/v1/api-keys${query(filters)}`),
|
|
@@ -4266,6 +4267,11 @@ function ageLabel(isoTimestamp, now = Date.now()) {
|
|
|
4266
4267
|
if (seconds < 86400) return `${Math.floor(seconds / 3600)}h`;
|
|
4267
4268
|
return `${Math.floor(seconds / 86400)}d`;
|
|
4268
4269
|
}
|
|
4270
|
+
function hoursLabel(ms, now = Date.now()) {
|
|
4271
|
+
const hours = Math.max(0, now - ms) / 36e5;
|
|
4272
|
+
if (hours < 48) return `${hours < 10 ? hours.toFixed(1) : Math.round(hours)}h`;
|
|
4273
|
+
return `${Math.round(hours / 24)}d`;
|
|
4274
|
+
}
|
|
4269
4275
|
function keptWorkspaceRow(kept, sizeBytes, now = Date.now()) {
|
|
4270
4276
|
return [
|
|
4271
4277
|
kept.run_id,
|
|
@@ -8258,20 +8264,108 @@ recent instances:`);
|
|
|
8258
8264
|
}
|
|
8259
8265
|
|
|
8260
8266
|
// src/commands/supervisor.ts
|
|
8267
|
+
function queueBlocks(groups) {
|
|
8268
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
8269
|
+
for (const g of groups) {
|
|
8270
|
+
const key = `${g.verdict}|${g.runner_id ?? ""}`;
|
|
8271
|
+
const seen = byKey.get(key);
|
|
8272
|
+
if (seen) {
|
|
8273
|
+
seen.count += g.count;
|
|
8274
|
+
seen.groups.push(g);
|
|
8275
|
+
seen.binding ??= g.binding;
|
|
8276
|
+
} else {
|
|
8277
|
+
byKey.set(key, {
|
|
8278
|
+
verdict: g.verdict,
|
|
8279
|
+
runnerName: g.runner_name,
|
|
8280
|
+
binding: g.binding,
|
|
8281
|
+
count: g.count,
|
|
8282
|
+
groups: [g]
|
|
8283
|
+
});
|
|
8284
|
+
}
|
|
8285
|
+
}
|
|
8286
|
+
return [...byKey.values()].sort((a, b) => b.count - a.count);
|
|
8287
|
+
}
|
|
8288
|
+
function queueHeadline(block) {
|
|
8289
|
+
const runner = block.runnerName ?? "the routed runner";
|
|
8290
|
+
switch (block.verdict) {
|
|
8291
|
+
case "ok":
|
|
8292
|
+
return "dispatching next pass";
|
|
8293
|
+
case "at_capacity":
|
|
8294
|
+
return block.binding?.kind === "max_concurrent" ? `at capacity on ${runner} (${block.binding.current}/${block.binding.limit})` : `at capacity on ${runner}`;
|
|
8295
|
+
case "quota_exhausted":
|
|
8296
|
+
if (block.binding?.kind === "global_cap")
|
|
8297
|
+
return `global cap reached (${block.binding.current}/${block.binding.limit})`;
|
|
8298
|
+
if (block.binding?.kind === "state_roster")
|
|
8299
|
+
return `roster limit reached (${block.binding.current}/${block.binding.limit})`;
|
|
8300
|
+
return "quota exhausted";
|
|
8301
|
+
case "offline":
|
|
8302
|
+
return `${runner} offline`;
|
|
8303
|
+
case "paused":
|
|
8304
|
+
return `${runner} paused`;
|
|
8305
|
+
case "draining":
|
|
8306
|
+
return `${runner} draining`;
|
|
8307
|
+
case "backing_off":
|
|
8308
|
+
return `${runner} backing off`;
|
|
8309
|
+
case "no_rule":
|
|
8310
|
+
return "no matching routing rule";
|
|
8311
|
+
case "no_targets":
|
|
8312
|
+
return "the matching rule has no targets";
|
|
8313
|
+
case "ambiguous_rule":
|
|
8314
|
+
return "two routing rules tie";
|
|
8315
|
+
case "pin_missing":
|
|
8316
|
+
return "pinned to a runner that is gone";
|
|
8317
|
+
case "automation_off":
|
|
8318
|
+
return "automation is off";
|
|
8319
|
+
case "parked":
|
|
8320
|
+
return "parked";
|
|
8321
|
+
}
|
|
8322
|
+
}
|
|
8323
|
+
function queueFix(block) {
|
|
8324
|
+
const runner = block.runnerName ?? "the routed runner";
|
|
8325
|
+
switch (block.verdict) {
|
|
8326
|
+
case "at_capacity":
|
|
8327
|
+
return `raise the cap on ${runner} \u2014 restart its daemon with tines runner daemon --max-concurrent N, or edit the runner on the Agents page`;
|
|
8328
|
+
case "quota_exhausted":
|
|
8329
|
+
return block.binding?.kind === "state_roster" ? "raise the roster limit \u2014 tines supervisor quota roster --default <n> --state <workflow>/<state>=<n> (this replaces the whole roster, so restate every override you keep)" : "raise the cap \u2014 tines supervisor quota global <n> \u2014 or switch to a per-state roster with tines supervisor quota roster";
|
|
8330
|
+
case "offline":
|
|
8331
|
+
return `start the daemon on that machine \u2014 tines runner daemon`;
|
|
8332
|
+
case "paused":
|
|
8333
|
+
return `tines runners resume ${runner}`;
|
|
8334
|
+
case "no_rule":
|
|
8335
|
+
return "add a routing rule for that state \u2014 tines routing set <runner> --state <workflow>/<state>";
|
|
8336
|
+
case "no_targets":
|
|
8337
|
+
case "ambiguous_rule":
|
|
8338
|
+
return "tines routing list, then edit the rule";
|
|
8339
|
+
case "pin_missing":
|
|
8340
|
+
return "clear the pin on those issues";
|
|
8341
|
+
case "automation_off":
|
|
8342
|
+
return "tines supervisor enable";
|
|
8343
|
+
case "backing_off":
|
|
8344
|
+
return "retries automatically; check the daemon log if it keeps failing";
|
|
8345
|
+
default:
|
|
8346
|
+
return null;
|
|
8347
|
+
}
|
|
8348
|
+
}
|
|
8261
8349
|
function register10(program3) {
|
|
8262
8350
|
const supervisor = program3.command("supervisor").description("The automation kill switch, quota policy, and attempt limit");
|
|
8263
8351
|
withCommon(
|
|
8264
8352
|
supervisor.command("status").description("One-screen overview: kill switch, quota, utilization, runners")
|
|
8265
8353
|
).action(async (opts) => {
|
|
8266
8354
|
const api = client(opts);
|
|
8267
|
-
const [settings, runnersRes, workflows, activeRunItems] = await Promise.all([
|
|
8355
|
+
const [settings, runnersRes, workflows, activeRunItems, queue] = await Promise.all([
|
|
8268
8356
|
api.getSupervisorSettings(),
|
|
8269
8357
|
api.listRunners(),
|
|
8270
8358
|
api.listWorkflows(),
|
|
8271
|
-
listAll((page) => api.listRuns({ active: true, ...page }))
|
|
8359
|
+
listAll((page) => api.listRuns({ active: true, ...page })),
|
|
8360
|
+
api.getSupervisorQueue()
|
|
8272
8361
|
]);
|
|
8273
8362
|
if (opts.json) {
|
|
8274
|
-
return printJson({
|
|
8363
|
+
return printJson({
|
|
8364
|
+
settings,
|
|
8365
|
+
runners: runnersRes.items,
|
|
8366
|
+
active_runs: activeRunItems,
|
|
8367
|
+
queue
|
|
8368
|
+
});
|
|
8275
8369
|
}
|
|
8276
8370
|
const stateNames = /* @__PURE__ */ new Map();
|
|
8277
8371
|
for (const wf of workflows.items) {
|
|
@@ -8285,6 +8379,27 @@ function register10(program3) {
|
|
|
8285
8379
|
`utilization: ${utilizationLabel(settings.quota, activeRunItems, (id) => stateNames.get(id) ?? id)}`
|
|
8286
8380
|
);
|
|
8287
8381
|
console.log(`attempt limit: ${settings.attempt_limit} strikes, then the issue parks`);
|
|
8382
|
+
if (queue.waiting === 0) {
|
|
8383
|
+
console.log("waiting: nothing");
|
|
8384
|
+
} else {
|
|
8385
|
+
console.log(`waiting: ${queue.waiting} ${queue.waiting === 1 ? "issue" : "issues"}`);
|
|
8386
|
+
for (const block of queueBlocks(queue.groups)) {
|
|
8387
|
+
const states = block.groups.map(
|
|
8388
|
+
(g) => `${stateNames.get(g.state_id) ?? g.state_name} ${g.count} (oldest ${hoursLabel(g.oldest_entered_at)})`
|
|
8389
|
+
).join(" \xB7 ");
|
|
8390
|
+
console.log(` ${queueHeadline(block)}: ${states}`);
|
|
8391
|
+
const fix = queueFix(block);
|
|
8392
|
+
if (fix) console.log(` fix: ${fix}`);
|
|
8393
|
+
}
|
|
8394
|
+
}
|
|
8395
|
+
console.log(
|
|
8396
|
+
queue.parked.count === 0 ? "parked: none" : `parked: ${queue.parked.count}, oldest ${hoursLabel(queue.parked.oldest_entered_at ?? Date.now())}`
|
|
8397
|
+
);
|
|
8398
|
+
if (queue.awaiting_human.count > 0) {
|
|
8399
|
+
console.log(
|
|
8400
|
+
`awaiting you: ${queue.awaiting_human.count} issues, oldest ${hoursLabel(queue.awaiting_human.oldest_entered_at ?? Date.now())}`
|
|
8401
|
+
);
|
|
8402
|
+
}
|
|
8288
8403
|
if (runnersRes.items.length === 0) {
|
|
8289
8404
|
console.log("runners: none");
|
|
8290
8405
|
} else {
|