tines 0.0.186 → 0.0.188
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 +229 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4139,7 +4139,10 @@ function createApiClient(options) {
|
|
|
4139
4139
|
appendRunLog: (runId, body) => request("POST", `/api/v1/runs/${runId}/logs`, body),
|
|
4140
4140
|
finishRun: (runId, body) => request("POST", `/api/v1/runs/${runId}/finish`, body),
|
|
4141
4141
|
// Agent runs
|
|
4142
|
-
listRuns: (filters = {}) => get(
|
|
4142
|
+
listRuns: (filters = {}) => get(
|
|
4143
|
+
`/api/v1/runs${query(filters)}`
|
|
4144
|
+
),
|
|
4145
|
+
getUsage: (filters = {}) => get(`/api/v1/usage${query(filters)}`),
|
|
4143
4146
|
getRun: (id2) => get(`/api/v1/runs/${id2}`),
|
|
4144
4147
|
/**
|
|
4145
4148
|
* The run's complete log (not the 256 KB tail `getRun` returns) as a
|
|
@@ -4410,6 +4413,51 @@ async function listAll(fetchPage, opts = {}) {
|
|
|
4410
4413
|
// ../shared/src/routing.ts
|
|
4411
4414
|
var INHERIT_RUNNER_ID = "*";
|
|
4412
4415
|
|
|
4416
|
+
// ../shared/src/issue-transfer.ts
|
|
4417
|
+
var compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
4418
|
+
function conflictsByKey(context) {
|
|
4419
|
+
const repositories = new Map(context.repos.map((repo) => [repo.item_id, repo]));
|
|
4420
|
+
return new Map(
|
|
4421
|
+
context.conflicts.map((conflict) => {
|
|
4422
|
+
const ids = [...new Set(conflict.item_ids)].sort(compare);
|
|
4423
|
+
const key = JSON.stringify([conflict.dir, ids]);
|
|
4424
|
+
return [
|
|
4425
|
+
key,
|
|
4426
|
+
{
|
|
4427
|
+
dir: conflict.dir,
|
|
4428
|
+
participants: ids.map((item_id) => {
|
|
4429
|
+
const repo = repositories.get(item_id);
|
|
4430
|
+
return {
|
|
4431
|
+
item_id,
|
|
4432
|
+
name: repo?.name ?? null,
|
|
4433
|
+
scope_label: repo?.scope.label ?? null
|
|
4434
|
+
};
|
|
4435
|
+
})
|
|
4436
|
+
}
|
|
4437
|
+
];
|
|
4438
|
+
})
|
|
4439
|
+
);
|
|
4440
|
+
}
|
|
4441
|
+
function deriveTransferConflictDeltas(before, after) {
|
|
4442
|
+
const beforeByKey = conflictsByKey(before);
|
|
4443
|
+
const afterByKey = conflictsByKey(after);
|
|
4444
|
+
const keys = /* @__PURE__ */ new Set([...beforeByKey.keys(), ...afterByKey.keys()]);
|
|
4445
|
+
const rank = { retained: 0, resolved: 1, introduced: 2 };
|
|
4446
|
+
return [...keys].map((key) => {
|
|
4447
|
+
const oldConflict = beforeByKey.get(key);
|
|
4448
|
+
const newConflict = afterByKey.get(key);
|
|
4449
|
+
return {
|
|
4450
|
+
key,
|
|
4451
|
+
change: oldConflict && newConflict ? "retained" : oldConflict ? "resolved" : "introduced",
|
|
4452
|
+
dir: (oldConflict ?? newConflict).dir,
|
|
4453
|
+
before: oldConflict?.participants ?? [],
|
|
4454
|
+
after: newConflict?.participants ?? []
|
|
4455
|
+
};
|
|
4456
|
+
}).sort(
|
|
4457
|
+
(a, b) => rank[a.change] - rank[b.change] || compare(a.dir, b.dir) || compare(a.key, b.key)
|
|
4458
|
+
);
|
|
4459
|
+
}
|
|
4460
|
+
|
|
4413
4461
|
// ../shared/src/library/types.ts
|
|
4414
4462
|
var LibraryValidationError = class extends Error {
|
|
4415
4463
|
constructor(diagnostics) {
|
|
@@ -4540,6 +4588,20 @@ var schedule = shape({
|
|
|
4540
4588
|
// ../shared/src/library/choices.ts
|
|
4541
4589
|
var PACKAGE_CHOICES_MAX_BYTES = 512 * 1024;
|
|
4542
4590
|
|
|
4591
|
+
// ../shared/src/usage.ts
|
|
4592
|
+
function usageCostLabel(cost, finalized = 1) {
|
|
4593
|
+
if (finalized === 0) return "No runs";
|
|
4594
|
+
if (cost === null) return "Unknown";
|
|
4595
|
+
if (cost === 0) return "$0";
|
|
4596
|
+
if (cost < 0.01) return "<$0.01";
|
|
4597
|
+
return cost.toLocaleString("en-US", {
|
|
4598
|
+
style: "currency",
|
|
4599
|
+
currency: "USD",
|
|
4600
|
+
minimumFractionDigits: 2,
|
|
4601
|
+
maximumFractionDigits: 2
|
|
4602
|
+
});
|
|
4603
|
+
}
|
|
4604
|
+
|
|
4543
4605
|
// src/format.ts
|
|
4544
4606
|
function timestamp(ms) {
|
|
4545
4607
|
return new Date(ms).toISOString().replace("T", " ").slice(0, 19);
|
|
@@ -5380,6 +5442,7 @@ function routingLines(preview) {
|
|
|
5380
5442
|
lines.push(
|
|
5381
5443
|
` ${check.ok ? "pass" : "FAIL"} ${check.name}: ${check.detail}${check.action?.label ? ` (${check.action.label})` : ""}`
|
|
5382
5444
|
);
|
|
5445
|
+
if (check.action?.cli) lines.push(` fix: ${check.action.cli}`);
|
|
5383
5446
|
}
|
|
5384
5447
|
if (explainer.matched_rule)
|
|
5385
5448
|
lines.push(` matched rule ${explainer.matched_rule.scope_label}`);
|
|
@@ -5437,18 +5500,15 @@ function effectiveRepositoryLines(preview) {
|
|
|
5437
5500
|
}
|
|
5438
5501
|
function conflictLines(preview) {
|
|
5439
5502
|
const lines = ["", "Repository checkout conflicts:"];
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
}).join(", ");
|
|
5450
|
-
lines.push(`${label}: ${conflict.dir} \u2014 ${participants}`);
|
|
5451
|
-
}
|
|
5503
|
+
const deltas = deriveTransferConflictDeltas(preview.context.before, preview.context.after);
|
|
5504
|
+
if (!deltas.length) return [...lines, " none"];
|
|
5505
|
+
const participants = (items) => items.map(
|
|
5506
|
+
(item) => item.name && item.scope_label ? `${item.name} (${item.scope_label})` : item.item_id
|
|
5507
|
+
).join(", ");
|
|
5508
|
+
for (const delta of deltas) {
|
|
5509
|
+
lines.push(` ${delta.change[0].toUpperCase()}${delta.change.slice(1)} \u2014 ${delta.dir}`);
|
|
5510
|
+
if (delta.before.length) lines.push(` Before: ${participants(delta.before)}`);
|
|
5511
|
+
if (delta.after.length) lines.push(` After: ${participants(delta.after)}`);
|
|
5452
5512
|
}
|
|
5453
5513
|
return lines;
|
|
5454
5514
|
}
|
|
@@ -9641,22 +9701,71 @@ function register8(program3) {
|
|
|
9641
9701
|
});
|
|
9642
9702
|
const runsCmd = program3.command("runs").description("Agent runs: attempts at issues by runners");
|
|
9643
9703
|
withList(
|
|
9644
|
-
runsCmd.command("list").description("List runs, newest first").option("-i, --issue <ref>", "filter to one issue (<project>/<number>)").option("-r, --runner <name>", "filter by runner name").option("--active", "only runs holding a claim (assigned/launching/running)")
|
|
9704
|
+
runsCmd.command("list").description("List runs, newest first").option("-i, --issue <ref>", "filter to one issue (<project>/<number>)").option("-r, --runner <name>", "filter by runner name").option("--active", "only runs holding a claim (assigned/launching/running)").addOption(
|
|
9705
|
+
new Option("--population <mode>", "period evidence population").choices([
|
|
9706
|
+
"finalized",
|
|
9707
|
+
"pending"
|
|
9708
|
+
])
|
|
9709
|
+
).option("--from <timestamp>", "inclusive period start").option("--to <timestamp>", "exclusive period cutoff").option("--project <name-or-id>", "project, including archived").option("--workflow <name-or-id>", "workflow").option("--state <id>", "starting state id").option("--tier <tier>", "model tier").addOption(
|
|
9710
|
+
new Option("--outcome <outcome>", "recorded outcome").choices([
|
|
9711
|
+
"advanced",
|
|
9712
|
+
"stalled",
|
|
9713
|
+
"interrupted",
|
|
9714
|
+
"unknown"
|
|
9715
|
+
])
|
|
9716
|
+
).addOption(
|
|
9717
|
+
new Option("--accounting-status <status>", "usage accounting status").choices([
|
|
9718
|
+
"priced",
|
|
9719
|
+
"unpriced",
|
|
9720
|
+
"unreported"
|
|
9721
|
+
])
|
|
9722
|
+
)
|
|
9645
9723
|
).action(async (opts) => {
|
|
9646
9724
|
const api = client(opts);
|
|
9725
|
+
const evidence = opts;
|
|
9726
|
+
if (evidence.from === void 0 !== (evidence.to === void 0))
|
|
9727
|
+
die("--from and --to are required together");
|
|
9728
|
+
if ((evidence.from || evidence.to) && !evidence.population)
|
|
9729
|
+
die("period filters require --population");
|
|
9647
9730
|
const issueId = opts.issue ? (await resolveIssue(api, opts.issue)).id : void 0;
|
|
9648
9731
|
const runnerId = opts.runner ? (await resolveRunner(api, opts.runner)).id : void 0;
|
|
9732
|
+
const projectId = evidence.project ? (await resolveProject(api, evidence.project)).id : void 0;
|
|
9733
|
+
const workflowId = evidence.workflow ? (await resolveWorkflow(api, evidence.workflow)).id : void 0;
|
|
9649
9734
|
const res = await fetchList(
|
|
9650
9735
|
opts,
|
|
9651
9736
|
(page) => api.listRuns({
|
|
9652
9737
|
issue: issueId,
|
|
9653
9738
|
runner: runnerId,
|
|
9654
9739
|
active: opts.active ? true : void 0,
|
|
9740
|
+
population: evidence.population,
|
|
9741
|
+
from: evidence.from,
|
|
9742
|
+
to: evidence.to,
|
|
9743
|
+
project: projectId,
|
|
9744
|
+
workflow: workflowId,
|
|
9745
|
+
state: evidence.state,
|
|
9746
|
+
tier: evidence.tier,
|
|
9747
|
+
outcome: evidence.outcome,
|
|
9748
|
+
accounting_status: evidence.accountingStatus,
|
|
9655
9749
|
...page
|
|
9656
9750
|
})
|
|
9657
9751
|
);
|
|
9658
9752
|
printList(res, opts, (items) => {
|
|
9659
9753
|
if (items.length === 0) return console.log(opts.active ? "no active runs" : "no runs");
|
|
9754
|
+
if (evidence.population === "pending") {
|
|
9755
|
+
table([
|
|
9756
|
+
["ID", "ISSUE", "RUNNER", "TIER", "STATUS", "COST", "CREATED"],
|
|
9757
|
+
...items.map((run) => [
|
|
9758
|
+
run.id,
|
|
9759
|
+
run.issue_ref ? `${run.issue_ref.project_name}/${run.issue_ref.number}` : run.issue_id,
|
|
9760
|
+
run.runner_name,
|
|
9761
|
+
run.tier,
|
|
9762
|
+
"Pending at cutoff",
|
|
9763
|
+
"\u2014",
|
|
9764
|
+
timestamp(run.created_at)
|
|
9765
|
+
])
|
|
9766
|
+
]);
|
|
9767
|
+
return;
|
|
9768
|
+
}
|
|
9660
9769
|
table([
|
|
9661
9770
|
["ID", "ISSUE", "RUNNER", "TIER", "STATUS", "DURATION", "COST", "CREATED"],
|
|
9662
9771
|
...items.map(runRow)
|
|
@@ -10442,6 +10551,111 @@ see \`tines workflows create --help\` for the expected shape`
|
|
|
10442
10551
|
});
|
|
10443
10552
|
}
|
|
10444
10553
|
|
|
10554
|
+
// src/commands/usage.ts
|
|
10555
|
+
var money = (value) => usageCostLabel(value);
|
|
10556
|
+
function printReport(report) {
|
|
10557
|
+
console.log(`Usage \xB7 ${report.filters.project ?? "All projects"} \xB7 ${report.by}`);
|
|
10558
|
+
console.log(
|
|
10559
|
+
`${new Date(report.from).toISOString()} \u2014 ${new Date(report.to).toISOString()} \xB7 ${report.timezone} (${report.timezone_source.replace("_", " ")})`
|
|
10560
|
+
);
|
|
10561
|
+
console.log(
|
|
10562
|
+
`generated ${new Date(report.generated_at).toISOString()} \xB7 ${report.accounting_basis}`
|
|
10563
|
+
);
|
|
10564
|
+
const scope = report.scope_total;
|
|
10565
|
+
console.log(
|
|
10566
|
+
`Scope total: ${money(scope.cost_usd)} \xB7 ${scope.coverage} \xB7 ${scope.finalized_run_count} finalized \xB7 ${scope.priced_run_count} priced \xB7 ${scope.unpriced_run_count + scope.unreported_run_count} without price`
|
|
10567
|
+
);
|
|
10568
|
+
if (JSON.stringify(report.filters) !== JSON.stringify({ ...report.filters.project ? { project: report.filters.project } : {} })) {
|
|
10569
|
+
const matching = report.matching_total;
|
|
10570
|
+
console.log(
|
|
10571
|
+
`Matching subtotal: ${money(matching.cost_usd)} \xB7 ${matching.coverage} \xB7 ${matching.finalized_run_count} finalized`
|
|
10572
|
+
);
|
|
10573
|
+
}
|
|
10574
|
+
const total = report.matching_total;
|
|
10575
|
+
console.log(
|
|
10576
|
+
`Pending at cutoff: ${report.pending.matching_count}${report.pending.unapplied_filters.length ? ` (before ${report.pending.unapplied_filters.join("/")} filters)` : ""}`
|
|
10577
|
+
);
|
|
10578
|
+
if (report.groups.length === 0) return console.log("no finalized runs");
|
|
10579
|
+
table([
|
|
10580
|
+
["GROUP", "SPEND", "COVERAGE", "FINAL", "PRICED", "MISSING", "MEDIAN", "P95", "MAX", "MEAN"],
|
|
10581
|
+
...report.groups.map(({ dimension, aggregate: a }) => [
|
|
10582
|
+
dimension.name,
|
|
10583
|
+
money(a.cost_usd),
|
|
10584
|
+
a.coverage,
|
|
10585
|
+
String(a.finalized_run_count),
|
|
10586
|
+
String(a.priced_run_count),
|
|
10587
|
+
String(a.unpriced_run_count + a.unreported_run_count),
|
|
10588
|
+
money(a.distribution.median_cost_usd),
|
|
10589
|
+
money(a.distribution.p95_cost_usd),
|
|
10590
|
+
money(a.distribution.max_cost_usd),
|
|
10591
|
+
money(a.distribution.mean_cost_usd)
|
|
10592
|
+
])
|
|
10593
|
+
]);
|
|
10594
|
+
console.log("Per-run cost \xB7 priced subset; p95 uses nearest rank.");
|
|
10595
|
+
if (report.groups.some((g) => g.aggregate.distribution.low_sample))
|
|
10596
|
+
console.log("Small samples (under 20): p95 equals maximum.");
|
|
10597
|
+
console.log(
|
|
10598
|
+
`Matching tokens: ${Object.entries(total.tokens).map(
|
|
10599
|
+
([name2, t]) => `${name2} ${t.value ?? "unknown"} (${t.reported_runs}/${total.finalized_run_count} runs)`
|
|
10600
|
+
).join(" \xB7 ")}`
|
|
10601
|
+
);
|
|
10602
|
+
console.log(
|
|
10603
|
+
`Matching sources: provider ${total.portions.provider.cost_usd_exact} \xB7 calculated ${total.portions.calculated.cost_usd_exact} \xB7 unknown ${total.portions.unknown_source.cost_usd_exact}`
|
|
10604
|
+
);
|
|
10605
|
+
for (const portion of total.rate_portions) {
|
|
10606
|
+
const basis = portion.basis;
|
|
10607
|
+
console.log(
|
|
10608
|
+
basis ? `Rate: ${basis.rate_id} v${basis.rate_version} \xB7 ${basis.model} \xB7 ${basis.source_url}` : `Rate: historical calculated amount \xB7 basis unavailable`
|
|
10609
|
+
);
|
|
10610
|
+
}
|
|
10611
|
+
}
|
|
10612
|
+
function register12(program3) {
|
|
10613
|
+
withCommon(
|
|
10614
|
+
program3.command("usage").description("Compare finalized run spend for a period").addOption(
|
|
10615
|
+
new Option("--window <window>", "today, 7d, or 30d").choices(["today", "7d", "30d"])
|
|
10616
|
+
).option("--from <bound>", "custom inclusive start (date or offset timestamp)").option("--to <bound>", "custom exclusive end (date or offset timestamp)").option("--project <name-or-id>", "project scope (including archived), or unknown").option("--workflow <name-or-id>", "workflow filter, or unknown").option("--state <id>", "starting state id (requires --workflow)").option("--runner <name-or-id>", "runner filter, or unknown").option("--tier <tier>", "tier filter").addOption(
|
|
10617
|
+
new Option("--outcome <outcome>", "recorded outcome").choices([
|
|
10618
|
+
"advanced",
|
|
10619
|
+
"stalled",
|
|
10620
|
+
"interrupted",
|
|
10621
|
+
"unknown"
|
|
10622
|
+
])
|
|
10623
|
+
).addOption(
|
|
10624
|
+
new Option("--accounting-status <status>", "price coverage").choices([
|
|
10625
|
+
"priced",
|
|
10626
|
+
"unpriced",
|
|
10627
|
+
"unreported"
|
|
10628
|
+
])
|
|
10629
|
+
).addOption(
|
|
10630
|
+
new Option("--by <dimension>", "group dimension").choices(["project", "workflow", "state", "outcome", "runner", "tier"]).default("workflow")
|
|
10631
|
+
)
|
|
10632
|
+
).action(async (opts) => {
|
|
10633
|
+
if (opts.from === void 0 !== (opts.to === void 0))
|
|
10634
|
+
throw new Error("--from and --to are required together");
|
|
10635
|
+
if (opts.window && opts.from) throw new Error("--window cannot be combined with --from/--to");
|
|
10636
|
+
if (opts.state && !opts.workflow) throw new Error("--state requires --workflow");
|
|
10637
|
+
const api = client(opts);
|
|
10638
|
+
const project = opts.project && opts.project !== "unknown" ? (await resolveProject(api, opts.project)).id : opts.project;
|
|
10639
|
+
const workflow = opts.workflow && opts.workflow !== "unknown" ? (await resolveWorkflow(api, opts.workflow)).id : opts.workflow;
|
|
10640
|
+
const runner = opts.runner && opts.runner !== "unknown" ? (await resolveRunner(api, opts.runner)).id : opts.runner;
|
|
10641
|
+
const report = await api.getUsage({
|
|
10642
|
+
window: opts.window,
|
|
10643
|
+
from: opts.from,
|
|
10644
|
+
to: opts.to,
|
|
10645
|
+
project,
|
|
10646
|
+
workflow,
|
|
10647
|
+
state: opts.state,
|
|
10648
|
+
runner,
|
|
10649
|
+
tier: opts.tier,
|
|
10650
|
+
outcome: opts.outcome,
|
|
10651
|
+
accounting_status: opts.accountingStatus,
|
|
10652
|
+
by: opts.by
|
|
10653
|
+
});
|
|
10654
|
+
if (opts.json) return printJson(report);
|
|
10655
|
+
printReport(report);
|
|
10656
|
+
});
|
|
10657
|
+
}
|
|
10658
|
+
|
|
10445
10659
|
// src/program.ts
|
|
10446
10660
|
var program2 = new Command();
|
|
10447
10661
|
program2.name("tines").description("CLI for Tines").version(cliVersion()).enablePositionalOptions();
|
|
@@ -10457,6 +10671,7 @@ register9(program2);
|
|
|
10457
10671
|
register8(program2);
|
|
10458
10672
|
register7(program2);
|
|
10459
10673
|
register10(program2);
|
|
10674
|
+
register12(program2);
|
|
10460
10675
|
registerEvents(program2);
|
|
10461
10676
|
|
|
10462
10677
|
// src/index.ts
|