tines 0.0.209 → 0.0.210
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/README.md +2 -0
- package/dist/index.js +151 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,6 +45,8 @@ tines issues comment <project>/<number> - <<'EOF' # body from stdin; @file al
|
|
|
45
45
|
…
|
|
46
46
|
EOF
|
|
47
47
|
tines events list --issue <project>/<number>
|
|
48
|
+
tines events list --since 2026-09-01T00:00:00Z --until 2026-09-08T00:00:00Z --state Engineering/Review
|
|
49
|
+
tines supervisor stats --window 7d --project Tines
|
|
48
50
|
```
|
|
49
51
|
|
|
50
52
|
Issues are addressed as `<project>/<number>`; schedules as `<project>/<name>`; workflow
|
package/dist/index.js
CHANGED
|
@@ -3482,6 +3482,7 @@ function parsePrSpec(spec) {
|
|
|
3482
3482
|
return repoUrl2 ? { repo_url: repoUrl2, number: Number.parseInt(url[2], 10) } : null;
|
|
3483
3483
|
}
|
|
3484
3484
|
var MODEL_TIERS = ["smartest", "balanced", "cheapest"];
|
|
3485
|
+
var RUN_END_OUTCOMES = ["advanced", "stalled", "interrupted"];
|
|
3485
3486
|
var RUNNER_ONLINE_WINDOW_MS = 2 * 60 * 1e3;
|
|
3486
3487
|
var DEFAULT_RESUME_WINDOW_HOURS = 48;
|
|
3487
3488
|
var DEFAULT_RESUME_MAX_TURNS = 25;
|
|
@@ -3575,6 +3576,11 @@ function utilizationLabel(quota, activeRuns, stateName = (id2) => id2) {
|
|
|
3575
3576
|
([stateId, { name: name2, n }]) => `${name2} ${n}/${quota.overrides[stateId] ?? quota.default_limit}`
|
|
3576
3577
|
).join(" \xB7 ");
|
|
3577
3578
|
}
|
|
3579
|
+
var RUN_OUTCOME_BUCKETS = [
|
|
3580
|
+
...RUN_END_OUTCOMES,
|
|
3581
|
+
"failed",
|
|
3582
|
+
"unrecorded"
|
|
3583
|
+
];
|
|
3578
3584
|
var LIBRARY_MAX_BYTES = 5 * 1024 * 1024;
|
|
3579
3585
|
|
|
3580
3586
|
// ../shared/src/events.ts
|
|
@@ -4183,7 +4189,9 @@ function createApiClient(options) {
|
|
|
4183
4189
|
getPreferences: () => get("/api/v1/preferences"),
|
|
4184
4190
|
updatePreferences: (body) => request("PATCH", "/api/v1/preferences", body),
|
|
4185
4191
|
getSupervisorSettings: () => get("/api/v1/supervisor/settings"),
|
|
4186
|
-
getSupervisorQueue: () => get(
|
|
4192
|
+
getSupervisorQueue: (q = {}) => get(`/api/v1/supervisor/queue${query(q)}`),
|
|
4193
|
+
getSupervisorStats: (q = {}) => get(`/api/v1/supervisor/stats${query(q)}`),
|
|
4194
|
+
getSupervisorSentBack: (q) => get(`/api/v1/supervisor/stats/sent-back${query(q)}`),
|
|
4187
4195
|
updateSupervisorSettings: (body) => request("PUT", "/api/v1/supervisor/settings", body),
|
|
4188
4196
|
// API keys (create/revoke require a browser session, not a key)
|
|
4189
4197
|
listApiKeys: (filters = {}) => get(`/api/v1/api-keys${query(filters)}`),
|
|
@@ -4426,6 +4434,38 @@ async function listAll(fetchPage, opts = {}) {
|
|
|
4426
4434
|
// ../shared/src/routing.ts
|
|
4427
4435
|
var INHERIT_RUNNER_ID = "*";
|
|
4428
4436
|
|
|
4437
|
+
// ../shared/src/stats-format.ts
|
|
4438
|
+
var MIN = 6e4;
|
|
4439
|
+
var HOUR = 60 * MIN;
|
|
4440
|
+
var DAY = 24 * HOUR;
|
|
4441
|
+
function durationLabel(ms) {
|
|
4442
|
+
if (ms === null || ms === void 0) return "\u2014";
|
|
4443
|
+
if (ms < MIN) return `${Math.round(ms / 1e3)} s`;
|
|
4444
|
+
if (ms < HOUR) return `${Math.round(ms / MIN)} min`;
|
|
4445
|
+
if (ms < DAY) return `${(ms / HOUR).toFixed(1)} h`;
|
|
4446
|
+
return `${(ms / DAY).toFixed(1)} d`;
|
|
4447
|
+
}
|
|
4448
|
+
function shareLabel(share) {
|
|
4449
|
+
if (share === null || share === void 0) return "\u2014";
|
|
4450
|
+
return `${Math.round(share * 100)}%`;
|
|
4451
|
+
}
|
|
4452
|
+
function deltaLabel(delta, kind) {
|
|
4453
|
+
if (delta === null || delta === void 0) return "";
|
|
4454
|
+
if (delta === 0) return "=";
|
|
4455
|
+
const arrow = delta > 0 ? "\u25B2" : "\u25BC";
|
|
4456
|
+
const size = Math.abs(delta);
|
|
4457
|
+
switch (kind) {
|
|
4458
|
+
case "ms":
|
|
4459
|
+
return `${arrow} ${durationLabel(size)}`;
|
|
4460
|
+
case "share":
|
|
4461
|
+
return `${arrow} ${Math.round(size * 100)} pp`;
|
|
4462
|
+
case "ratio":
|
|
4463
|
+
return `${arrow} ${size.toFixed(1)}`;
|
|
4464
|
+
default:
|
|
4465
|
+
return `${arrow} ${size}`;
|
|
4466
|
+
}
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4429
4469
|
// ../shared/src/issue-transfer.ts
|
|
4430
4470
|
var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
4431
4471
|
function conflictsByKey(context2) {
|
|
@@ -8171,27 +8211,33 @@ function registerTime(program3) {
|
|
|
8171
8211
|
function registerEvents(program3) {
|
|
8172
8212
|
const events = program3.command("events").description("Read the activity log");
|
|
8173
8213
|
withList(
|
|
8174
|
-
events.command("list").description("List activity events, newest first").option("-i, --issue <ref>", "filter to one issue (<project>/<number>)").option("-p, --project <name>", "filter by project name or id").option("-t, --type <type>", "filter by event type (e.g. issue.transitioned)")
|
|
8175
|
-
).action(
|
|
8176
|
-
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
opts,
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8193
|
-
|
|
8194
|
-
|
|
8214
|
+
events.command("list").description("List activity events, newest first").option("-i, --issue <ref>", "filter to one issue (<project>/<number>)").option("-p, --project <name>", "filter by project name or id").option("-t, --type <type>", "filter by event type (e.g. issue.transitioned)").option("--since <time>", "inclusive lower bound (ISO 8601 or epoch ms)").option("--until <time>", "exclusive upper bound (ISO 8601 or epoch ms)").option("--state <workflow/state>", "events referencing a workflow state")
|
|
8215
|
+
).action(
|
|
8216
|
+
async (opts) => {
|
|
8217
|
+
const api = client(opts);
|
|
8218
|
+
const issueId = opts.issue ? (await resolveIssue(api, opts.issue)).id : void 0;
|
|
8219
|
+
const stateId = opts.state ? (await resolveStateFlag(api, opts.state)).state.id : void 0;
|
|
8220
|
+
const res = await fetchList(
|
|
8221
|
+
opts,
|
|
8222
|
+
(page) => api.listEvents({
|
|
8223
|
+
issue: issueId,
|
|
8224
|
+
project: opts.project,
|
|
8225
|
+
type: opts.type,
|
|
8226
|
+
since: opts.since,
|
|
8227
|
+
until: opts.until,
|
|
8228
|
+
state: stateId,
|
|
8229
|
+
...page
|
|
8230
|
+
})
|
|
8231
|
+
);
|
|
8232
|
+
printList(res, opts, (items) => {
|
|
8233
|
+
if (items.length === 0) return console.log("no events");
|
|
8234
|
+
table([
|
|
8235
|
+
["WHEN", "ACTOR", "EVENT"],
|
|
8236
|
+
...items.map((ev) => [timestamp(ev.created_at), displayActor(ev), eventSummary(ev)])
|
|
8237
|
+
]);
|
|
8238
|
+
});
|
|
8239
|
+
}
|
|
8240
|
+
);
|
|
8195
8241
|
}
|
|
8196
8242
|
|
|
8197
8243
|
// src/commands/projects.ts
|
|
@@ -11834,10 +11880,26 @@ function queueFix(block) {
|
|
|
11834
11880
|
return null;
|
|
11835
11881
|
}
|
|
11836
11882
|
}
|
|
11883
|
+
function outcomeLabel(stats) {
|
|
11884
|
+
const o = stats.current.runs.outcomes;
|
|
11885
|
+
const parts = [`adv ${o.advanced}`, `stalled ${o.stalled}`, `failed ${o.failed}`];
|
|
11886
|
+
if (o.interrupted > 0) parts.push(`intr ${o.interrupted}`);
|
|
11887
|
+
if (o.unrecorded > 0) parts.push(`unrecorded ${o.unrecorded}`);
|
|
11888
|
+
if (stats.current.runs.active > 0) parts.push(`active ${stats.current.runs.active}`);
|
|
11889
|
+
return parts.join(" \xB7 ");
|
|
11890
|
+
}
|
|
11891
|
+
function statsLevers() {
|
|
11892
|
+
return [
|
|
11893
|
+
"levers:",
|
|
11894
|
+
" queue wait tines supervisor quota roster --state <wf>/<state>=<n>",
|
|
11895
|
+
" runs tines runs list --state <wf>/<state>",
|
|
11896
|
+
" sent back tines context show <wf>/<state> instructions"
|
|
11897
|
+
];
|
|
11898
|
+
}
|
|
11837
11899
|
function register10(program3) {
|
|
11838
11900
|
const supervisor = program3.command("supervisor").description("The automation kill switch, quota policy, and attempt limit");
|
|
11839
11901
|
withCommon(
|
|
11840
|
-
supervisor.command("status").description("One-screen overview: kill switch, quota, utilization, runners")
|
|
11902
|
+
supervisor.command("status").description("One-screen overview: kill switch, quota, utilization, runners").option("--project <name-or-id>", "filter waiting work to one project")
|
|
11841
11903
|
).action(async (opts) => {
|
|
11842
11904
|
const api = client(opts);
|
|
11843
11905
|
const [settings, runnersRes, workflows, activeRunItems, queue] = await Promise.all([
|
|
@@ -11845,7 +11907,7 @@ function register10(program3) {
|
|
|
11845
11907
|
api.listRunners(),
|
|
11846
11908
|
api.listWorkflows(),
|
|
11847
11909
|
listAll((page) => api.listRuns({ active: true, ...page })),
|
|
11848
|
-
api.getSupervisorQueue()
|
|
11910
|
+
api.getSupervisorQueue({ project: opts.project })
|
|
11849
11911
|
]);
|
|
11850
11912
|
if (opts.json) {
|
|
11851
11913
|
return printJson({
|
|
@@ -11902,6 +11964,71 @@ function register10(program3) {
|
|
|
11902
11964
|
);
|
|
11903
11965
|
}
|
|
11904
11966
|
});
|
|
11967
|
+
withCommon(
|
|
11968
|
+
supervisor.command("stats").description("Per-stage flow this week: queue wait, work time, runs per visit, sent back").option("--window <window>", "Rolling window, e.g. 24h or 7d", "7d").option("--project <ref>", "Narrow to one project (id or name)").option("--sent-back <workflow/state>", "Show the issues behind one sent-back figure")
|
|
11969
|
+
).action(async (opts) => {
|
|
11970
|
+
const api = client(opts);
|
|
11971
|
+
const project = opts.project ? await resolveProject(api, opts.project) : null;
|
|
11972
|
+
if (opts.sentBack) {
|
|
11973
|
+
const { state } = await resolveStateFlag(api, opts.sentBack);
|
|
11974
|
+
const detail = await api.getSupervisorSentBack({
|
|
11975
|
+
state: state.id,
|
|
11976
|
+
window: opts.window,
|
|
11977
|
+
project: project?.id ?? void 0
|
|
11978
|
+
});
|
|
11979
|
+
if (opts.json) return printJson(detail);
|
|
11980
|
+
console.log(`sent back from ${detail.state.workflow_name}/${detail.state.name}`);
|
|
11981
|
+
if (detail.prompt)
|
|
11982
|
+
console.log(`prompt: ${detail.prompt.name} (current v${detail.prompt.current_version})`);
|
|
11983
|
+
if (detail.items.length === 0) return console.log("no issues sent back");
|
|
11984
|
+
for (const item of detail.items) {
|
|
11985
|
+
console.log(
|
|
11986
|
+
`${item.issue.project_name}/${item.issue.number} \u2192 ${item.to_state_name} \xB7 prompt ${item.prompt_version ? `v${item.prompt_version}` : "unknown"} \xB7 ${item.actor.user_name}`
|
|
11987
|
+
);
|
|
11988
|
+
console.log(` ${item.comment?.excerpt.split("\n")[0] ?? "no comment"}`);
|
|
11989
|
+
}
|
|
11990
|
+
return;
|
|
11991
|
+
}
|
|
11992
|
+
const report = await api.getSupervisorStats({
|
|
11993
|
+
window: opts.window,
|
|
11994
|
+
project: project?.id ?? void 0
|
|
11995
|
+
});
|
|
11996
|
+
if (opts.json) return printJson(report);
|
|
11997
|
+
if (report.states.length === 0) {
|
|
11998
|
+
console.log("No agent stage saw work in the last window.");
|
|
11999
|
+
return;
|
|
12000
|
+
}
|
|
12001
|
+
const windowLabel = opts.window ?? "7d";
|
|
12002
|
+
console.log(
|
|
12003
|
+
`this week (${windowLabel}${report.project ? `, project ${report.project.name}` : ""})${report.previous ? ` \u2014 vs the ${windowLabel} before` : ""}`
|
|
12004
|
+
);
|
|
12005
|
+
table([
|
|
12006
|
+
[" stage", "visits", "queue p50", "p90", "work p50", "runs/visit", "ended", "sent back"],
|
|
12007
|
+
...report.states.map((s) => [
|
|
12008
|
+
` ${s.workflow_name}/${s.state_name}`,
|
|
12009
|
+
`${s.current.visits}\xB7${s.current.exits} ${deltaLabel(s.delta.visits, "count")}`.trim(),
|
|
12010
|
+
`${durationLabel(s.current.queue_wait?.p50 ?? null)} ${deltaLabel(s.delta.queue_wait_p50, "ms")}`.trim(),
|
|
12011
|
+
durationLabel(s.current.queue_wait?.p90 ?? null),
|
|
12012
|
+
`${durationLabel(s.current.work?.p50 ?? null)} ${deltaLabel(s.delta.work_p50, "ms")}`.trim(),
|
|
12013
|
+
s.current.runs.per_visit === null ? "\u2014" : `${s.current.runs.per_visit.toFixed(1)} ${deltaLabel(s.delta.runs_per_visit, "ratio")}`.trim(),
|
|
12014
|
+
outcomeLabel(s),
|
|
12015
|
+
`${s.current.sent_back.count} of ${s.current.exits} (${shareLabel(s.current.sent_back.share)}) \xB7 agents ${s.current.sent_back.agent} ${deltaLabel(s.delta.sent_back_share, "share")}`.trim()
|
|
12016
|
+
])
|
|
12017
|
+
]);
|
|
12018
|
+
if (report.markers.length > 0) {
|
|
12019
|
+
console.log("changes:");
|
|
12020
|
+
for (const marker of report.markers) {
|
|
12021
|
+
console.log(` ${marker.label}`);
|
|
12022
|
+
for (const effect of marker.effects) {
|
|
12023
|
+
const state = report.states.find((row) => row.state_id === effect.state_id);
|
|
12024
|
+
console.log(
|
|
12025
|
+
` ${state?.state_name ?? effect.state_id}: since ${effect.after?.exits ?? 0} exits, ${shareLabel(effect.after?.sent_back_share)} sent back, queue ${durationLabel(effect.after?.queue_wait_p50)} \xB7 before ${effect.before?.exits ?? 0} exits, ${shareLabel(effect.before?.sent_back_share)} sent back, queue ${durationLabel(effect.before?.queue_wait_p50)}`
|
|
12026
|
+
);
|
|
12027
|
+
}
|
|
12028
|
+
}
|
|
12029
|
+
}
|
|
12030
|
+
for (const line of statsLevers()) console.log(line);
|
|
12031
|
+
});
|
|
11905
12032
|
withCommon(
|
|
11906
12033
|
supervisor.command("enable").description("Resume automation (the kill switch on)")
|
|
11907
12034
|
).action(async (opts) => {
|