tines 0.0.214 → 0.0.215
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 +521 -217
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3407,8 +3407,8 @@ var STATE_CATEGORIES = [
|
|
|
3407
3407
|
"awaiting_human",
|
|
3408
3408
|
"done"
|
|
3409
3409
|
];
|
|
3410
|
-
function runRefLabel(
|
|
3411
|
-
return
|
|
3410
|
+
function runRefLabel(run3) {
|
|
3411
|
+
return run3.issue_ref ? `run on ${run3.issue_ref.project_name}/${run3.issue_ref.number}` : `run ${run3.run_id}`;
|
|
3412
3412
|
}
|
|
3413
3413
|
function actorLabel(actor) {
|
|
3414
3414
|
if (actor.run) {
|
|
@@ -3531,13 +3531,13 @@ function ageLabel(at, now = Date.now()) {
|
|
|
3531
3531
|
function prUrlOf(v) {
|
|
3532
3532
|
return v.pr_repo_url && v.pr_number !== null ? `${v.pr_repo_url}/pull/${v.pr_number}` : null;
|
|
3533
3533
|
}
|
|
3534
|
-
function runDurationLabel(
|
|
3535
|
-
if (!
|
|
3536
|
-
const seconds = Math.max(0, Math.round(((
|
|
3534
|
+
function runDurationLabel(run3, now = Date.now()) {
|
|
3535
|
+
if (!run3.started_at) return "\u2014";
|
|
3536
|
+
const seconds = Math.max(0, Math.round(((run3.ended_at ?? now) - run3.started_at) / 1e3));
|
|
3537
3537
|
return seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m`;
|
|
3538
3538
|
}
|
|
3539
|
-
function runCostLabel(
|
|
3540
|
-
const usage2 =
|
|
3539
|
+
function runCostLabel(run3) {
|
|
3540
|
+
const usage2 = run3.usage;
|
|
3541
3541
|
if (!usage2) return null;
|
|
3542
3542
|
if (usage2.cost_usd !== void 0) {
|
|
3543
3543
|
const dollars = usage2.cost_usd === 0 ? "$0" : usage2.cost_usd < 0.01 ? "<$0.01" : `$${usage2.cost_usd.toFixed(2)}`;
|
|
@@ -3560,13 +3560,13 @@ function utilizationLabel(quota, activeRuns, stateName = (id2) => id2) {
|
|
|
3560
3560
|
return `${activeRuns.length}/${quota.limit} global slot${quota.limit === 1 ? "" : "s"} in use`;
|
|
3561
3561
|
}
|
|
3562
3562
|
const counts = /* @__PURE__ */ new Map();
|
|
3563
|
-
for (const
|
|
3564
|
-
const entry = counts.get(
|
|
3565
|
-
name:
|
|
3563
|
+
for (const run3 of activeRuns) {
|
|
3564
|
+
const entry = counts.get(run3.state_id_at_start) ?? {
|
|
3565
|
+
name: run3.state_at_start_name ?? stateName(run3.state_id_at_start),
|
|
3566
3566
|
n: 0
|
|
3567
3567
|
};
|
|
3568
3568
|
entry.n += 1;
|
|
3569
|
-
counts.set(
|
|
3569
|
+
counts.set(run3.state_id_at_start, entry);
|
|
3570
3570
|
}
|
|
3571
3571
|
for (const stateId of Object.keys(quota.overrides)) {
|
|
3572
3572
|
if (!counts.has(stateId)) counts.set(stateId, { name: stateName(stateId), n: 0 });
|
|
@@ -4799,7 +4799,7 @@ var schedule = shape({
|
|
|
4799
4799
|
});
|
|
4800
4800
|
function validateLibraryV3Shape(value) {
|
|
4801
4801
|
const envelope = { format: oneOf(["tines.library"]), version: oneOf([3]), exported_at: integer };
|
|
4802
|
-
const
|
|
4802
|
+
const digest2 = (v, p) => {
|
|
4803
4803
|
text2(71)(v, p);
|
|
4804
4804
|
if (v !== "" && !/^sha256:[0-9a-f]{64}$/.test(v))
|
|
4805
4805
|
invalid(p, "invalid_digest", "Expected sha256 and 64 lowercase hex digits");
|
|
@@ -4839,7 +4839,7 @@ function validateLibraryV3Shape(value) {
|
|
|
4839
4839
|
})
|
|
4840
4840
|
)
|
|
4841
4841
|
},
|
|
4842
|
-
{ digest }
|
|
4842
|
+
{ digest: digest2 }
|
|
4843
4843
|
),
|
|
4844
4844
|
library: shape(
|
|
4845
4845
|
{
|
|
@@ -4865,7 +4865,7 @@ function validateLibraryV3Shape(value) {
|
|
|
4865
4865
|
),
|
|
4866
4866
|
labels: array(shape({ id, name: labelName, color: oneOf(LABEL_COLORS) }))
|
|
4867
4867
|
},
|
|
4868
|
-
{ digest }
|
|
4868
|
+
{ digest: digest2 }
|
|
4869
4869
|
)
|
|
4870
4870
|
})(value, "");
|
|
4871
4871
|
}
|
|
@@ -5504,6 +5504,14 @@ function usageCostLabel(cost, finalized = 1) {
|
|
|
5504
5504
|
});
|
|
5505
5505
|
}
|
|
5506
5506
|
|
|
5507
|
+
// ../shared/src/effort.ts
|
|
5508
|
+
var EFFORT_CAPABILITIES_MAX_BYTES = 64 * 1024;
|
|
5509
|
+
function supportedEfforts(capabilities, model) {
|
|
5510
|
+
if (!capabilities || capabilities.version !== 1 || !("models" in capabilities) || !model)
|
|
5511
|
+
return null;
|
|
5512
|
+
return capabilities.models.find((entry) => entry.model === model)?.efforts ?? null;
|
|
5513
|
+
}
|
|
5514
|
+
|
|
5507
5515
|
// src/format.ts
|
|
5508
5516
|
function timestamp(ms) {
|
|
5509
5517
|
return new Date(ms).toISOString().replace("T", " ").slice(0, 19);
|
|
@@ -5618,10 +5626,10 @@ function runnerStatusLabel(runner) {
|
|
|
5618
5626
|
function ruleTargetsLabel(rule) {
|
|
5619
5627
|
if (rule.targets.length === 0) return "(no targets)";
|
|
5620
5628
|
if (rule.targets.length === 1 && rule.targets[0]?.runner_id === "*") {
|
|
5621
|
-
return
|
|
5629
|
+
return `1. *:${rule.targets[0].tier}${rule.targets[0].effort ? ` effort=${rule.targets[0].effort}` : ""} (inherited runners)`;
|
|
5622
5630
|
}
|
|
5623
5631
|
return rule.targets.map(
|
|
5624
|
-
(t) => `${t.runner_name}${t.tier ? `:${t.tier}` : ""}${t.runner_status === "paused" ? " (paused)" : ""}`
|
|
5632
|
+
(t, index) => `${index + 1}. ${t.runner_name}${t.tier ? `:${t.tier}` : ""}${t.effort ? ` effort=${t.effort}` : ""}${t.runner_status === "paused" ? " (paused)" : ""}`
|
|
5625
5633
|
).join(" \u2192 ");
|
|
5626
5634
|
}
|
|
5627
5635
|
function quotaLabel(quota, stateName) {
|
|
@@ -5667,7 +5675,7 @@ function roundLines(round, now = Date.now()) {
|
|
|
5667
5675
|
if (latest.artifacts.length > 0) {
|
|
5668
5676
|
lines2.push(` ${latest.artifacts.map(artifactChangeLabel).join(" \xB7 ")}`);
|
|
5669
5677
|
}
|
|
5670
|
-
for (const
|
|
5678
|
+
for (const run3 of earlier) lines2.push(` ${earlierAttemptLine(run3, now)}`);
|
|
5671
5679
|
if (latest.summary_comment) {
|
|
5672
5680
|
lines2.push(` summary (${latest.summary_comment.id}):`);
|
|
5673
5681
|
for (const line of latest.summary_comment.body.split("\n")) lines2.push(` ${line}`);
|
|
@@ -5681,20 +5689,20 @@ function roundLines(round, now = Date.now()) {
|
|
|
5681
5689
|
}
|
|
5682
5690
|
return lines2;
|
|
5683
5691
|
}
|
|
5684
|
-
function runHeadline(
|
|
5685
|
-
const cost = runCostLabel(
|
|
5692
|
+
function runHeadline(run3, now) {
|
|
5693
|
+
const cost = runCostLabel(run3);
|
|
5686
5694
|
return [
|
|
5687
|
-
`${
|
|
5688
|
-
runDurationLabel(
|
|
5689
|
-
|
|
5695
|
+
`${run3.run_id} on ${run3.runner_name}`,
|
|
5696
|
+
runDurationLabel(run3, now),
|
|
5697
|
+
run3.outcome ?? run3.status,
|
|
5690
5698
|
...cost ? [cost] : [],
|
|
5691
|
-
|
|
5699
|
+
run3.transition ? `"${run3.transition.action ?? "moved directly"}" \u2192 ${run3.transition.to_state.name}` : "no transition"
|
|
5692
5700
|
].join(" \xB7 ");
|
|
5693
5701
|
}
|
|
5694
|
-
function earlierAttemptLine(
|
|
5695
|
-
const back =
|
|
5702
|
+
function earlierAttemptLine(run3, now) {
|
|
5703
|
+
const back = run3.returned_via;
|
|
5696
5704
|
const how = back ? back.action ? `sent back by ${back.from_state.name} ("${back.action}")` : "moved directly back" : "never came back";
|
|
5697
|
-
return `${
|
|
5705
|
+
return `${run3.run_id} \xB7 ${runDurationLabel(run3, now)} \xB7 ${run3.outcome ?? run3.status} \xB7 ${how}`;
|
|
5698
5706
|
}
|
|
5699
5707
|
function artifactChangeLabel(a) {
|
|
5700
5708
|
const versions = a.from_version === null ? `v${a.to_version}` : `v${a.from_version} \u2192 v${a.to_version}`;
|
|
@@ -5713,16 +5721,16 @@ function roundSummaryLabel(summary) {
|
|
|
5713
5721
|
];
|
|
5714
5722
|
return parts.length > 0 ? parts.join(" \xB7 ") : "\u2014";
|
|
5715
5723
|
}
|
|
5716
|
-
function runRow(
|
|
5724
|
+
function runRow(run3) {
|
|
5717
5725
|
return [
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
`${
|
|
5722
|
-
`${
|
|
5723
|
-
runDurationLabel(
|
|
5724
|
-
runCostLabel(
|
|
5725
|
-
timestamp(
|
|
5726
|
+
run3.id,
|
|
5727
|
+
run3.issue_ref ? issueRef(run3.issue_ref) : run3.issue_id,
|
|
5728
|
+
run3.runner_name,
|
|
5729
|
+
`${run3.tier}${run3.model ? ` (${run3.model})` : ""}${run3.resolved_effort ? ` \xB7 effort ${run3.resolved_effort} \xB7 ${run3.effort_application_status}` : ""}`,
|
|
5730
|
+
`${run3.status}${run3.resumed_from_run_id ? ` \xB7 resumed run ${run3.resumed_from_run_id}` : ""}`,
|
|
5731
|
+
runDurationLabel(run3),
|
|
5732
|
+
runCostLabel(run3) ?? "\u2014",
|
|
5733
|
+
timestamp(run3.created_at)
|
|
5726
5734
|
];
|
|
5727
5735
|
}
|
|
5728
5736
|
function byteSize(bytes2) {
|
|
@@ -8485,6 +8493,23 @@ function isBlank(starter) {
|
|
|
8485
8493
|
}
|
|
8486
8494
|
|
|
8487
8495
|
// src/commands/routing.ts
|
|
8496
|
+
function applyTargetEfforts(targets, specs) {
|
|
8497
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8498
|
+
for (const spec of specs) {
|
|
8499
|
+
const match = /^(\d+)=(.+)$/.exec(spec);
|
|
8500
|
+
if (!match) die(`invalid --effort ${JSON.stringify(spec)}; expected <target-number=value>`);
|
|
8501
|
+
const index = Number(match[1]);
|
|
8502
|
+
const value = match[2];
|
|
8503
|
+
if (!Number.isSafeInteger(index) || index < 1 || index > targets.length)
|
|
8504
|
+
die(`--effort target ${index} is out of range (1-${targets.length})`);
|
|
8505
|
+
if (seen.has(index)) die(`--effort target ${index} is specified more than once`);
|
|
8506
|
+
if (!/^[a-z][a-z0-9_-]{0,31}$/.test(value))
|
|
8507
|
+
die(`invalid effort ${JSON.stringify(value)}; use a lowercase token of 1-32 characters`);
|
|
8508
|
+
seen.add(index);
|
|
8509
|
+
targets[index - 1] = { ...targets[index - 1], effort: value };
|
|
8510
|
+
}
|
|
8511
|
+
return targets;
|
|
8512
|
+
}
|
|
8488
8513
|
async function resolveRoutingScope(api, opts) {
|
|
8489
8514
|
const projectId = opts.project !== void 0 ? (await resolveProject(api, opts.project)).id : null;
|
|
8490
8515
|
const stateId = opts.state !== void 0 ? (await resolveStateFlag(api, opts.state)).state.id : null;
|
|
@@ -8513,7 +8538,12 @@ function register7(program3) {
|
|
|
8513
8538
|
withCommon(
|
|
8514
8539
|
routing.command("set <target...>").description(
|
|
8515
8540
|
"Create or replace a rule with <runner>[:tier] targets, or scoped '*:smartest' tier inheritance"
|
|
8516
|
-
).option("-p, --project <name>", "scope: project name or id").option("-s, --state <workflow/state>", "scope: workflow-qualified state").option("-l, --label <name>", "scope: issue label name or id")
|
|
8541
|
+
).option("-p, --project <name>", "scope: project name or id").option("-s, --state <workflow/state>", "scope: workflow-qualified state").option("-l, --label <name>", "scope: issue label name or id").option(
|
|
8542
|
+
"--effort <target-number=value>",
|
|
8543
|
+
"set routed effort for a 1-based target (repeatable)",
|
|
8544
|
+
(value, values) => [...values, value],
|
|
8545
|
+
[]
|
|
8546
|
+
)
|
|
8517
8547
|
).action(async (targetSpecs, opts) => {
|
|
8518
8548
|
const parsed = targetSpecs.map(parseTargetSpec);
|
|
8519
8549
|
const wildcard = parsed.filter((target) => target.name === INHERIT_RUNNER_ID);
|
|
@@ -8525,15 +8555,20 @@ function register7(program3) {
|
|
|
8525
8555
|
die("a tier-only rule requires --project, --state, or --label");
|
|
8526
8556
|
}
|
|
8527
8557
|
}
|
|
8558
|
+
applyTargetEfforts(parsed, opts.effort ?? []);
|
|
8528
8559
|
const api = client(opts);
|
|
8529
8560
|
const scope = await resolveRoutingScope(api, opts);
|
|
8530
8561
|
const targets = [];
|
|
8531
|
-
for (const { name: name2, tier } of parsed) {
|
|
8562
|
+
for (const { name: name2, tier, effort } of parsed) {
|
|
8532
8563
|
if (name2 === INHERIT_RUNNER_ID) {
|
|
8533
|
-
targets.push({ runner_id: INHERIT_RUNNER_ID, tier });
|
|
8564
|
+
targets.push({ runner_id: INHERIT_RUNNER_ID, tier, ...effort ? { effort } : {} });
|
|
8534
8565
|
} else {
|
|
8535
8566
|
const runner = await resolveRunner(api, name2);
|
|
8536
|
-
targets.push(
|
|
8567
|
+
targets.push({
|
|
8568
|
+
runner_id: runner.id,
|
|
8569
|
+
...tier ? { tier } : {},
|
|
8570
|
+
...effort ? { effort } : {}
|
|
8571
|
+
});
|
|
8537
8572
|
}
|
|
8538
8573
|
}
|
|
8539
8574
|
const { items } = await api.listRoutingRules();
|
|
@@ -8568,7 +8603,7 @@ function register7(program3) {
|
|
|
8568
8603
|
}
|
|
8569
8604
|
|
|
8570
8605
|
// src/daemon/daemon.ts
|
|
8571
|
-
import { spawn as
|
|
8606
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
8572
8607
|
import {
|
|
8573
8608
|
createWriteStream,
|
|
8574
8609
|
existsSync as existsSync5,
|
|
@@ -9133,8 +9168,8 @@ async function readCodexRolloutRecords(stream, timeoutMs) {
|
|
|
9133
9168
|
pending += decoder.write(chunk);
|
|
9134
9169
|
let newline;
|
|
9135
9170
|
while ((newline = pending.indexOf("\n")) >= 0) {
|
|
9136
|
-
const
|
|
9137
|
-
if (
|
|
9171
|
+
const failure2 = consume(pending.slice(0, newline));
|
|
9172
|
+
if (failure2) return failure2;
|
|
9138
9173
|
pending = pending.slice(newline + 1);
|
|
9139
9174
|
}
|
|
9140
9175
|
if (Buffer.byteLength(pending) > CODEX_ROLLOUT_MAX_LINE_BYTES)
|
|
@@ -9142,8 +9177,8 @@ async function readCodexRolloutRecords(stream, timeoutMs) {
|
|
|
9142
9177
|
}
|
|
9143
9178
|
pending += decoder.end();
|
|
9144
9179
|
if (pending.length) {
|
|
9145
|
-
const
|
|
9146
|
-
if (
|
|
9180
|
+
const failure2 = consume(pending);
|
|
9181
|
+
if (failure2) return failure2;
|
|
9147
9182
|
}
|
|
9148
9183
|
return { records };
|
|
9149
9184
|
} catch {
|
|
@@ -9392,8 +9427,213 @@ var RateLimitDetector = class {
|
|
|
9392
9427
|
}
|
|
9393
9428
|
};
|
|
9394
9429
|
|
|
9430
|
+
// src/daemon/effort-capabilities.ts
|
|
9431
|
+
import { createHash } from "node:crypto";
|
|
9432
|
+
import { execFile, spawn } from "node:child_process";
|
|
9433
|
+
var MAX_STDOUT = 1024 * 1024;
|
|
9434
|
+
var DEADLINE_MS = 5e3;
|
|
9435
|
+
var EFFORT_CAPABILITIES_TTL_MS = 10 * 6e4;
|
|
9436
|
+
var MIN_CLAUDE_EFFORT_VERSION = [2, 1, 258];
|
|
9437
|
+
function claudeEffortVersionSupported(version) {
|
|
9438
|
+
const parsed = version.match(/(\d+)\.(\d+)\.(\d+)/)?.slice(1).map(Number);
|
|
9439
|
+
if (!parsed) return false;
|
|
9440
|
+
for (let i = 0; i < MIN_CLAUDE_EFFORT_VERSION.length; i++) {
|
|
9441
|
+
if (parsed[i] > MIN_CLAUDE_EFFORT_VERSION[i]) return true;
|
|
9442
|
+
if (parsed[i] < MIN_CLAUDE_EFFORT_VERSION[i]) return false;
|
|
9443
|
+
}
|
|
9444
|
+
return true;
|
|
9445
|
+
}
|
|
9446
|
+
function assignmentEffortRejection(assignment, capabilities, harness) {
|
|
9447
|
+
if (!assignment.effort) return null;
|
|
9448
|
+
if (!capabilities || capabilities.version !== 1 || !("models" in capabilities))
|
|
9449
|
+
return "effort assignment requires a compatible V1 daemon capability report";
|
|
9450
|
+
if (capabilities.harness !== harness)
|
|
9451
|
+
return `effort assignment requires ${capabilities.harness}, but this daemon runs ${harness}`;
|
|
9452
|
+
if (capabilities.catalog_digest !== assignment.effort.capability_digest)
|
|
9453
|
+
return "effort capability catalog changed after assignment delivery";
|
|
9454
|
+
const allowed = supportedEfforts(capabilities, assignment.run.model);
|
|
9455
|
+
if (!allowed?.includes(assignment.effort.value))
|
|
9456
|
+
return `${assignment.run.model ?? "the assigned model"} does not support effort ${assignment.effort.value}`;
|
|
9457
|
+
return null;
|
|
9458
|
+
}
|
|
9459
|
+
function digest(models) {
|
|
9460
|
+
return createHash("sha256").update(JSON.stringify(models)).digest("hex");
|
|
9461
|
+
}
|
|
9462
|
+
function failure(harness, daemonVersion, reason) {
|
|
9463
|
+
return {
|
|
9464
|
+
version: 1,
|
|
9465
|
+
daemon_version: daemonVersion.slice(0, 100),
|
|
9466
|
+
harness,
|
|
9467
|
+
harness_version: "unknown",
|
|
9468
|
+
catalog_digest: digest([]),
|
|
9469
|
+
models: [],
|
|
9470
|
+
discovery_error: reason.slice(0, 200)
|
|
9471
|
+
};
|
|
9472
|
+
}
|
|
9473
|
+
function run(file, args) {
|
|
9474
|
+
return new Promise((resolve2, reject) => {
|
|
9475
|
+
execFile(
|
|
9476
|
+
file,
|
|
9477
|
+
args,
|
|
9478
|
+
{ timeout: DEADLINE_MS, maxBuffer: MAX_STDOUT },
|
|
9479
|
+
(error, stdout) => error ? reject(error) : resolve2(stdout)
|
|
9480
|
+
);
|
|
9481
|
+
});
|
|
9482
|
+
}
|
|
9483
|
+
var CLAUDE_MODELS = {
|
|
9484
|
+
"claude-fable-5-1": ["low", "medium", "high", "xhigh", "max"],
|
|
9485
|
+
"claude-fable-5": ["low", "medium", "high", "xhigh", "max"],
|
|
9486
|
+
"claude-opus-5": ["low", "medium", "high", "xhigh", "max"],
|
|
9487
|
+
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
|
|
9488
|
+
"claude-opus-4-8": ["low", "medium", "high", "xhigh", "max"],
|
|
9489
|
+
"claude-opus-4-7": ["low", "medium", "high", "xhigh", "max"],
|
|
9490
|
+
"claude-opus-4-6": ["low", "medium", "high", "max"],
|
|
9491
|
+
"claude-sonnet-4-6": ["low", "medium", "high", "max"]
|
|
9492
|
+
};
|
|
9493
|
+
async function discoverClaude(daemonVersion) {
|
|
9494
|
+
try {
|
|
9495
|
+
const [version, help] = await Promise.all([
|
|
9496
|
+
run("claude", ["--version"]),
|
|
9497
|
+
run("claude", ["--help"])
|
|
9498
|
+
]);
|
|
9499
|
+
if (!help.includes("--effort"))
|
|
9500
|
+
return failure("claude_code", daemonVersion, "installed Claude CLI has no --effort option");
|
|
9501
|
+
if (!claudeEffortVersionSupported(version))
|
|
9502
|
+
return failure(
|
|
9503
|
+
"claude_code",
|
|
9504
|
+
daemonVersion,
|
|
9505
|
+
`installed Claude CLI ${version.trim()} predates verified --effort support 2.1.258`
|
|
9506
|
+
);
|
|
9507
|
+
const models = Object.entries(CLAUDE_MODELS).map(([model, efforts]) => ({ model, efforts }));
|
|
9508
|
+
return {
|
|
9509
|
+
version: 1,
|
|
9510
|
+
daemon_version: daemonVersion,
|
|
9511
|
+
harness: "claude_code",
|
|
9512
|
+
harness_version: version.trim().slice(0, 100),
|
|
9513
|
+
catalog_revision: "claude-effort-v1",
|
|
9514
|
+
catalog_digest: digest(models),
|
|
9515
|
+
models
|
|
9516
|
+
};
|
|
9517
|
+
} catch (error) {
|
|
9518
|
+
return failure(
|
|
9519
|
+
"claude_code",
|
|
9520
|
+
daemonVersion,
|
|
9521
|
+
error instanceof Error ? error.message : String(error)
|
|
9522
|
+
);
|
|
9523
|
+
}
|
|
9524
|
+
}
|
|
9525
|
+
async function discoverCodex(daemonVersion) {
|
|
9526
|
+
let harnessVersion;
|
|
9527
|
+
try {
|
|
9528
|
+
harnessVersion = (await run("codex", ["--version"])).trim().slice(0, 100);
|
|
9529
|
+
} catch (error) {
|
|
9530
|
+
return failure("codex", daemonVersion, error instanceof Error ? error.message : String(error));
|
|
9531
|
+
}
|
|
9532
|
+
return new Promise((resolve2) => {
|
|
9533
|
+
const child = spawn("codex", ["app-server"], { stdio: ["pipe", "pipe", "ignore"] });
|
|
9534
|
+
let buffer = "";
|
|
9535
|
+
let bytes2 = 0;
|
|
9536
|
+
let settled = false;
|
|
9537
|
+
let requestId = 2;
|
|
9538
|
+
const models = [];
|
|
9539
|
+
const finish = (report) => {
|
|
9540
|
+
if (settled) return;
|
|
9541
|
+
settled = true;
|
|
9542
|
+
clearTimeout(timer);
|
|
9543
|
+
child.kill();
|
|
9544
|
+
resolve2(report);
|
|
9545
|
+
};
|
|
9546
|
+
const fail = (reason) => finish(failure("codex", daemonVersion, reason));
|
|
9547
|
+
const sendList = (cursor) => {
|
|
9548
|
+
requestId += 1;
|
|
9549
|
+
child.stdin.write(
|
|
9550
|
+
`${JSON.stringify({ id: requestId, method: "model/list", params: { includeHidden: true, ...cursor ? { cursor } : {} } })}
|
|
9551
|
+
`
|
|
9552
|
+
);
|
|
9553
|
+
};
|
|
9554
|
+
const timer = setTimeout(() => fail("Codex model discovery timed out"), DEADLINE_MS);
|
|
9555
|
+
child.on("error", (error) => fail(error.message));
|
|
9556
|
+
child.stdout.on("data", (chunk) => {
|
|
9557
|
+
bytes2 += chunk.length;
|
|
9558
|
+
if (bytes2 > MAX_STDOUT) return fail("Codex model discovery exceeded 1 MiB");
|
|
9559
|
+
buffer += chunk.toString("utf8");
|
|
9560
|
+
for (; ; ) {
|
|
9561
|
+
const newline = buffer.indexOf("\n");
|
|
9562
|
+
if (newline < 0) break;
|
|
9563
|
+
const line = buffer.slice(0, newline);
|
|
9564
|
+
buffer = buffer.slice(newline + 1);
|
|
9565
|
+
let message3;
|
|
9566
|
+
try {
|
|
9567
|
+
message3 = JSON.parse(line);
|
|
9568
|
+
} catch {
|
|
9569
|
+
continue;
|
|
9570
|
+
}
|
|
9571
|
+
if (message3.id === 1 && message3.result) {
|
|
9572
|
+
child.stdin.write(`${JSON.stringify({ method: "initialized", params: {} })}
|
|
9573
|
+
`);
|
|
9574
|
+
sendList();
|
|
9575
|
+
} else if (typeof message3.id === "number" && message3.id >= 3 && message3.result) {
|
|
9576
|
+
for (const entry of message3.result.data ?? []) {
|
|
9577
|
+
const efforts = (entry.supportedReasoningEfforts ?? []).map((item) => item.reasoningEffort).filter((item) => typeof item === "string");
|
|
9578
|
+
if (typeof entry.model === "string" && efforts.length)
|
|
9579
|
+
models.push({ model: entry.model, efforts: [...new Set(efforts)] });
|
|
9580
|
+
}
|
|
9581
|
+
if (message3.result.nextCursor) sendList(message3.result.nextCursor);
|
|
9582
|
+
else
|
|
9583
|
+
finish({
|
|
9584
|
+
version: 1,
|
|
9585
|
+
daemon_version: daemonVersion,
|
|
9586
|
+
harness: "codex",
|
|
9587
|
+
harness_version: harnessVersion,
|
|
9588
|
+
catalog_digest: digest(models),
|
|
9589
|
+
models
|
|
9590
|
+
});
|
|
9591
|
+
}
|
|
9592
|
+
}
|
|
9593
|
+
});
|
|
9594
|
+
child.stdin.write(
|
|
9595
|
+
`${JSON.stringify({ id: 1, method: "initialize", params: { clientInfo: { name: "tines", version: daemonVersion } } })}
|
|
9596
|
+
`
|
|
9597
|
+
);
|
|
9598
|
+
});
|
|
9599
|
+
}
|
|
9600
|
+
async function discoverEffortCapabilities(harness, daemonVersion) {
|
|
9601
|
+
if (harness === "custom") return void 0;
|
|
9602
|
+
return harness === "codex" ? discoverCodex(daemonVersion) : discoverClaude(daemonVersion);
|
|
9603
|
+
}
|
|
9604
|
+
var EffortCapabilityRefresher = class {
|
|
9605
|
+
constructor(harness, daemonVersion, discover = discoverEffortCapabilities, now = Date.now) {
|
|
9606
|
+
this.harness = harness;
|
|
9607
|
+
this.daemonVersion = daemonVersion;
|
|
9608
|
+
this.discover = discover;
|
|
9609
|
+
this.now = now;
|
|
9610
|
+
}
|
|
9611
|
+
harness;
|
|
9612
|
+
daemonVersion;
|
|
9613
|
+
discover;
|
|
9614
|
+
now;
|
|
9615
|
+
value;
|
|
9616
|
+
refreshedAt = 0;
|
|
9617
|
+
pending = null;
|
|
9618
|
+
async get(force = false) {
|
|
9619
|
+
if (!force && this.refreshedAt && this.now() - this.refreshedAt < EFFORT_CAPABILITIES_TTL_MS)
|
|
9620
|
+
return this.value;
|
|
9621
|
+
if (this.pending) return this.pending;
|
|
9622
|
+
this.pending = this.discover(this.harness, this.daemonVersion).then((value) => {
|
|
9623
|
+
this.value = value;
|
|
9624
|
+
this.refreshedAt = this.now();
|
|
9625
|
+
return value;
|
|
9626
|
+
});
|
|
9627
|
+
try {
|
|
9628
|
+
return await this.pending;
|
|
9629
|
+
} finally {
|
|
9630
|
+
this.pending = null;
|
|
9631
|
+
}
|
|
9632
|
+
}
|
|
9633
|
+
};
|
|
9634
|
+
|
|
9395
9635
|
// src/daemon/cli-refresh.ts
|
|
9396
|
-
import { spawn } from "node:child_process";
|
|
9636
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
9397
9637
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync7 } from "node:fs";
|
|
9398
9638
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
9399
9639
|
|
|
@@ -9417,7 +9657,7 @@ function buildHarnessInvocation(spec, input2) {
|
|
|
9417
9657
|
file: "sh",
|
|
9418
9658
|
args: [
|
|
9419
9659
|
"-c",
|
|
9420
|
-
`claude -p${input2.resumeSessionId ? ` --resume ${shellQuote(input2.resumeSessionId)}` : ""} --output-format stream-json --verbose${input2.model ? ` --model ${shellQuote(input2.model)}` : ""} < ${shellQuote(input2.promptFile)}`
|
|
9660
|
+
`claude -p${input2.resumeSessionId ? ` --resume ${shellQuote(input2.resumeSessionId)}` : ""} --output-format stream-json --verbose${input2.model ? ` --model ${shellQuote(input2.model)}` : ""}${input2.effort ? ` --effort ${shellQuote(input2.effort)}` : ""} < ${shellQuote(input2.promptFile)}`
|
|
9421
9661
|
]
|
|
9422
9662
|
};
|
|
9423
9663
|
case "codex":
|
|
@@ -9428,6 +9668,7 @@ function buildHarnessInvocation(spec, input2) {
|
|
|
9428
9668
|
"--json",
|
|
9429
9669
|
"--skip-git-repo-check",
|
|
9430
9670
|
...input2.model ? ["--model", input2.model] : [],
|
|
9671
|
+
...input2.effort ? ["-c", `model_reasoning_effort=${JSON.stringify(input2.effort)}`] : [],
|
|
9431
9672
|
input2.prompt
|
|
9432
9673
|
]
|
|
9433
9674
|
};
|
|
@@ -9453,6 +9694,7 @@ function formatLaunchBanner(invocation, input2, meta) {
|
|
|
9453
9694
|
const fields = [
|
|
9454
9695
|
`harness=${meta.harness}`,
|
|
9455
9696
|
`model=${input2.model ?? "(fixed)"}`,
|
|
9697
|
+
`effort=${input2.effort ?? "(provider-default)"}`,
|
|
9456
9698
|
`timeout=${meta.timeoutMinutes}m`,
|
|
9457
9699
|
`cli=${meta.cliVersion}`,
|
|
9458
9700
|
`workspace=${input2.workspace}`,
|
|
@@ -9477,9 +9719,9 @@ function formatExitLine(exit) {
|
|
|
9477
9719
|
return `# tines runner: exit ${parts.join(" ")} after ${formatDuration(exit.durationMs)}
|
|
9478
9720
|
`;
|
|
9479
9721
|
}
|
|
9480
|
-
function exitLineForRun(
|
|
9481
|
-
if (
|
|
9482
|
-
return formatExitLine({ ...exit, timedOut:
|
|
9722
|
+
function exitLineForRun(run3, exit) {
|
|
9723
|
+
if (run3.settled) return null;
|
|
9724
|
+
return formatExitLine({ ...exit, timedOut: run3.timedOut });
|
|
9483
9725
|
}
|
|
9484
9726
|
var RunTable = class {
|
|
9485
9727
|
constructor(effects, opts = {}) {
|
|
@@ -9502,8 +9744,8 @@ var RunTable = class {
|
|
|
9502
9744
|
has(runId) {
|
|
9503
9745
|
return this.runs.has(runId);
|
|
9504
9746
|
}
|
|
9505
|
-
track(
|
|
9506
|
-
this.runs.set(
|
|
9747
|
+
track(run3) {
|
|
9748
|
+
this.runs.set(run3.runId, run3);
|
|
9507
9749
|
this.effects.persist();
|
|
9508
9750
|
}
|
|
9509
9751
|
/** Call after setting a run's pid so the state file reflects it. */
|
|
@@ -9519,10 +9761,10 @@ var RunTable = class {
|
|
|
9519
9761
|
* already-settled run, a daemon shutdown. Guessing `failed` also errs the
|
|
9520
9762
|
* safe way — it keeps a directory rather than destroying evidence.
|
|
9521
9763
|
*/
|
|
9522
|
-
cleanup(
|
|
9523
|
-
this.runs.delete(
|
|
9764
|
+
cleanup(run3, outcome = "failed") {
|
|
9765
|
+
this.runs.delete(run3.runId);
|
|
9524
9766
|
this.effects.persist();
|
|
9525
|
-
this.effects.release(
|
|
9767
|
+
this.effects.release(run3, { keep: this.keep(outcome, run3), outcome });
|
|
9526
9768
|
}
|
|
9527
9769
|
/**
|
|
9528
9770
|
* Ends a run: flush logs, finish-report, clean up. On a run someone
|
|
@@ -9538,26 +9780,26 @@ var RunTable = class {
|
|
|
9538
9780
|
* `{ judgment: 'rate_limited' }` with its reset time, while transient 5xx
|
|
9539
9781
|
* and transport outages use `interrupted` and the normal short backoff.
|
|
9540
9782
|
*/
|
|
9541
|
-
async finishAndCleanup(
|
|
9542
|
-
if (
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
if (this.keep(status,
|
|
9547
|
-
await
|
|
9548
|
-
const keptBeforeFinish = this.keep(status,
|
|
9783
|
+
async finishAndCleanup(run3, status, error, judgment) {
|
|
9784
|
+
if (run3.settled) return this.cleanup(run3);
|
|
9785
|
+
run3.settled = true;
|
|
9786
|
+
run3.endNote ??= error;
|
|
9787
|
+
run3.drain?.();
|
|
9788
|
+
if (this.keep(status, run3)) this.effects.noteKept?.(run3);
|
|
9789
|
+
await run3.flush?.();
|
|
9790
|
+
const keptBeforeFinish = this.keep(status, run3);
|
|
9549
9791
|
try {
|
|
9550
|
-
await this.effects.finish(
|
|
9551
|
-
this.effects.log(`run ${
|
|
9552
|
-
if (!keptBeforeFinish && this.keep(status,
|
|
9553
|
-
this.effects.log(`run ${
|
|
9792
|
+
await this.effects.finish(run3, status, error, judgment);
|
|
9793
|
+
this.effects.log(`run ${run3.runId} finished: ${status}${error ? ` (${error})` : ""}`);
|
|
9794
|
+
if (!keptBeforeFinish && this.keep(status, run3)) {
|
|
9795
|
+
this.effects.log(`run ${run3.runId} workspace kept for resume at ${run3.workspace}`);
|
|
9554
9796
|
}
|
|
9555
9797
|
} catch (err) {
|
|
9556
9798
|
this.effects.log(
|
|
9557
|
-
`finish report for run ${
|
|
9799
|
+
`finish report for run ${run3.runId} not accepted: ${err instanceof Error ? err.message : String(err)}`
|
|
9558
9800
|
);
|
|
9559
9801
|
}
|
|
9560
|
-
this.cleanup(
|
|
9802
|
+
this.cleanup(run3, status);
|
|
9561
9803
|
}
|
|
9562
9804
|
/**
|
|
9563
9805
|
* Marks a supervisor-settled run (`cancels`): kill, do NOT finish-report.
|
|
@@ -9566,11 +9808,11 @@ var RunTable = class {
|
|
|
9566
9808
|
* is cleaned up by the launch path's next settled check.
|
|
9567
9809
|
*/
|
|
9568
9810
|
markCanceled(runId) {
|
|
9569
|
-
const
|
|
9570
|
-
if (!
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
return
|
|
9811
|
+
const run3 = this.runs.get(runId);
|
|
9812
|
+
if (!run3 || run3.settled) return null;
|
|
9813
|
+
run3.canceled = true;
|
|
9814
|
+
run3.settled = true;
|
|
9815
|
+
return run3;
|
|
9574
9816
|
}
|
|
9575
9817
|
};
|
|
9576
9818
|
var LogBatcher = class {
|
|
@@ -9746,7 +9988,7 @@ function runNpm(file, args, cwd, timeoutMs) {
|
|
|
9746
9988
|
let output = "";
|
|
9747
9989
|
let done = false;
|
|
9748
9990
|
let timedOut = false;
|
|
9749
|
-
const child =
|
|
9991
|
+
const child = spawn2(file, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
9750
9992
|
const timer = setTimeout(() => {
|
|
9751
9993
|
if (done) return;
|
|
9752
9994
|
timedOut = true;
|
|
@@ -9974,12 +10216,12 @@ function nextStepsMessage(name2, baseUrl) {
|
|
|
9974
10216
|
// src/daemon/daemon.ts
|
|
9975
10217
|
var CLI_REFRESH_TTL_MS = 10 * 6e4;
|
|
9976
10218
|
var DAEMON_VERSION = cliVersion();
|
|
9977
|
-
async function uploadRawLog(
|
|
9978
|
-
const path2 =
|
|
9979
|
-
if (!path2 || !
|
|
9980
|
-
|
|
10219
|
+
async function uploadRawLog(run3) {
|
|
10220
|
+
const path2 = run3.rawSpoolPath;
|
|
10221
|
+
if (!path2 || !run3.rawUpload) return;
|
|
10222
|
+
run3.rawSpoolPath = void 0;
|
|
9981
10223
|
try {
|
|
9982
|
-
await new Promise((resolve2) =>
|
|
10224
|
+
await new Promise((resolve2) => run3.rawSpool?.end(resolve2) ?? resolve2());
|
|
9983
10225
|
const size = statSync4(path2).size;
|
|
9984
10226
|
if (size > 0) {
|
|
9985
10227
|
let body = readFileSync9(path2);
|
|
@@ -9993,7 +10235,7 @@ async function uploadRawLog(run2) {
|
|
|
9993
10235
|
body.subarray(body.byteLength - RUN_LOG_RAW_MAX_BYTES + marker.byteLength)
|
|
9994
10236
|
]);
|
|
9995
10237
|
}
|
|
9996
|
-
await
|
|
10238
|
+
await run3.rawUpload(body);
|
|
9997
10239
|
}
|
|
9998
10240
|
} catch {
|
|
9999
10241
|
} finally {
|
|
@@ -10104,8 +10346,8 @@ async function runDaemon(opts) {
|
|
|
10104
10346
|
log(`agent CLI: ${cliLabel(await ensureCli())}`);
|
|
10105
10347
|
const table2 = new RunTable(
|
|
10106
10348
|
{
|
|
10107
|
-
finish: async (
|
|
10108
|
-
const summary =
|
|
10349
|
+
finish: async (run3, status, error, judgment) => {
|
|
10350
|
+
const summary = run3.renderer?.summary();
|
|
10109
10351
|
if (summary?.pricingEvidence && opts.harness === "codex") {
|
|
10110
10352
|
const raw = summary.pricingEvidence.raw_usage;
|
|
10111
10353
|
const completeRaw = raw && [
|
|
@@ -10114,12 +10356,12 @@ async function runDaemon(opts) {
|
|
|
10114
10356
|
"cache_write_input_tokens",
|
|
10115
10357
|
"output_tokens"
|
|
10116
10358
|
].every((field) => raw[field] !== void 0);
|
|
10117
|
-
if (status === "completed" &&
|
|
10359
|
+
if (status === "completed" && run3.pricingSessionMode === "cold" && summary.pricingEvidence.measurement_status === "complete" && completeRaw && summary.providerSessionId && run3.codexHome && run3.spawnedAt) {
|
|
10118
10360
|
summary.pricingEvidence.request_context = await collectCodexRequestContext({
|
|
10119
|
-
codexHome:
|
|
10361
|
+
codexHome: run3.codexHome,
|
|
10120
10362
|
threadId: summary.providerSessionId,
|
|
10121
|
-
model:
|
|
10122
|
-
startedAt:
|
|
10363
|
+
model: run3.pricingModel ?? null,
|
|
10364
|
+
startedAt: run3.spawnedAt,
|
|
10123
10365
|
endedAt: Date.now(),
|
|
10124
10366
|
terminalUsage: raw
|
|
10125
10367
|
});
|
|
@@ -10141,19 +10383,20 @@ async function runDaemon(opts) {
|
|
|
10141
10383
|
daemon_version: DAEMON_VERSION,
|
|
10142
10384
|
status
|
|
10143
10385
|
};
|
|
10144
|
-
|
|
10386
|
+
run3.batcher.append(`[usage] ${JSON.stringify(accounting)}
|
|
10145
10387
|
`);
|
|
10146
|
-
await
|
|
10147
|
-
const ended = await client2.finishRun(
|
|
10388
|
+
await run3.batcher.flush();
|
|
10389
|
+
const ended = await client2.finishRun(run3.runId, {
|
|
10148
10390
|
status,
|
|
10391
|
+
...run3.effortEvidence ? { effort_application: run3.effortEvidence } : {},
|
|
10149
10392
|
...error ? { error } : {},
|
|
10150
10393
|
...judgment,
|
|
10151
10394
|
usage: accounting.usage,
|
|
10152
10395
|
...summary?.pricingEvidence ? {
|
|
10153
10396
|
pricing_evidence: {
|
|
10154
10397
|
...summary.pricingEvidence,
|
|
10155
|
-
model:
|
|
10156
|
-
session_mode:
|
|
10398
|
+
model: run3.pricingModel ?? null,
|
|
10399
|
+
session_mode: run3.pricingSessionMode ?? "cold",
|
|
10157
10400
|
daemon_version: DAEMON_VERSION
|
|
10158
10401
|
}
|
|
10159
10402
|
} : {},
|
|
@@ -10161,33 +10404,33 @@ async function runDaemon(opts) {
|
|
|
10161
10404
|
...summary?.numTurns !== void 0 ? { turn_count: summary.numTurns } : {},
|
|
10162
10405
|
// The whole conversation's turns, which for a resumed run is
|
|
10163
10406
|
// more than this run's own: the size guard reads this one.
|
|
10164
|
-
...summary?.numTurns !== void 0 ? { conversation_turn_count:
|
|
10165
|
-
workspace_path:
|
|
10407
|
+
...summary?.numTurns !== void 0 ? { conversation_turn_count: run3.priorTurns + summary.numTurns } : {},
|
|
10408
|
+
workspace_path: run3.workspace
|
|
10166
10409
|
});
|
|
10167
|
-
if (ended?.resume_expires_at)
|
|
10410
|
+
if (ended?.resume_expires_at) run3.keepForResume = true;
|
|
10168
10411
|
},
|
|
10169
|
-
release: (
|
|
10170
|
-
if (
|
|
10171
|
-
|
|
10172
|
-
settleWorkspace(
|
|
10173
|
-
run_id:
|
|
10174
|
-
...
|
|
10412
|
+
release: (run3, { keep, outcome }) => {
|
|
10413
|
+
if (run3.timeout) clearTimeout(run3.timeout);
|
|
10414
|
+
run3.renderer?.finish();
|
|
10415
|
+
settleWorkspace(run3.workspace, keep, {
|
|
10416
|
+
run_id: run3.runId,
|
|
10417
|
+
...run3.issueLabel ? { issue_ref: run3.issueLabel } : {},
|
|
10175
10418
|
status: outcome,
|
|
10176
|
-
...
|
|
10419
|
+
...run3.endNote ? { error: run3.endNote } : {}
|
|
10177
10420
|
});
|
|
10178
|
-
void uploadRawLog(
|
|
10421
|
+
void uploadRawLog(run3);
|
|
10179
10422
|
sweepKeptWorkspaces();
|
|
10180
10423
|
},
|
|
10181
|
-
noteKept: (
|
|
10424
|
+
noteKept: (run3) => run3.batcher.append(`workspace kept at ${run3.workspace}
|
|
10182
10425
|
`),
|
|
10183
10426
|
persist: () => {
|
|
10184
|
-
const entries = table2.values().filter((
|
|
10185
|
-
run_id:
|
|
10186
|
-
pid:
|
|
10187
|
-
workspace:
|
|
10188
|
-
key_fingerprint:
|
|
10189
|
-
started_at:
|
|
10190
|
-
...
|
|
10427
|
+
const entries = table2.values().filter((run3) => run3.child?.pid !== void 0).map((run3) => ({
|
|
10428
|
+
run_id: run3.runId,
|
|
10429
|
+
pid: run3.child.pid,
|
|
10430
|
+
workspace: run3.workspace,
|
|
10431
|
+
key_fingerprint: run3.keyFingerprint,
|
|
10432
|
+
started_at: run3.spawnedAt,
|
|
10433
|
+
...run3.issueLabel ? { issue_ref: run3.issueLabel } : {}
|
|
10191
10434
|
}));
|
|
10192
10435
|
saveDaemonState(statePath, entries);
|
|
10193
10436
|
},
|
|
@@ -10196,7 +10439,7 @@ async function runDaemon(opts) {
|
|
|
10196
10439
|
{
|
|
10197
10440
|
// A workspace the server retained for a resume is kept whatever the
|
|
10198
10441
|
// --keep-workspaces mode says; pruning still bounds it by age/count.
|
|
10199
|
-
keep: (outcome,
|
|
10442
|
+
keep: (outcome, run3) => run3.keepForResume || keepWorkspace(opts.keepWorkspaces, outcome)
|
|
10200
10443
|
}
|
|
10201
10444
|
);
|
|
10202
10445
|
for (const orphan of loadDaemonState(statePath)) {
|
|
@@ -10230,16 +10473,18 @@ async function runDaemon(opts) {
|
|
|
10230
10473
|
}
|
|
10231
10474
|
saveDaemonState(statePath, []);
|
|
10232
10475
|
const killWithoutFinish = (runId) => {
|
|
10233
|
-
const
|
|
10234
|
-
if (!
|
|
10235
|
-
|
|
10476
|
+
const run3 = table2.markCanceled(runId);
|
|
10477
|
+
if (!run3) return;
|
|
10478
|
+
run3.endNote ??= "canceled by supervisor";
|
|
10236
10479
|
log(`supervisor canceled run ${runId}; killing without finish-reporting`);
|
|
10237
|
-
if (
|
|
10238
|
-
const pid =
|
|
10480
|
+
if (run3.child?.pid) {
|
|
10481
|
+
const pid = run3.child.pid;
|
|
10239
10482
|
killTree(pid, "SIGTERM");
|
|
10240
10483
|
setTimeout(() => killTree(pid, "SIGKILL"), 5e3).unref?.();
|
|
10241
10484
|
}
|
|
10242
10485
|
};
|
|
10486
|
+
const effortRefresher = new EffortCapabilityRefresher(opts.harness, DAEMON_VERSION);
|
|
10487
|
+
let effortCapabilities = await effortRefresher.get();
|
|
10243
10488
|
const launch = async (assignment) => {
|
|
10244
10489
|
const runId = assignment.run.id;
|
|
10245
10490
|
if (table2.has(runId)) return;
|
|
@@ -10251,7 +10496,7 @@ async function runDaemon(opts) {
|
|
|
10251
10496
|
}
|
|
10252
10497
|
const workspace = resume ? resume.workspace_path : join6(workspacesDir(opts.configDir), runId);
|
|
10253
10498
|
const issueLabel = assignment.run.issue_ref ? `${assignment.run.issue_ref.project_name}/${assignment.run.issue_ref.number}` : void 0;
|
|
10254
|
-
const
|
|
10499
|
+
const run3 = {
|
|
10255
10500
|
runId,
|
|
10256
10501
|
workspace,
|
|
10257
10502
|
...issueLabel ? { issueLabel } : {},
|
|
@@ -10267,8 +10512,23 @@ async function runDaemon(opts) {
|
|
|
10267
10512
|
{ onError: (err) => log(`log append for run ${runId} failed: ${message2(err)}`) }
|
|
10268
10513
|
)
|
|
10269
10514
|
};
|
|
10270
|
-
|
|
10271
|
-
table2.track(
|
|
10515
|
+
run3.flush = () => run3.batcher.flush();
|
|
10516
|
+
table2.track(run3);
|
|
10517
|
+
if (assignment.effort) effortCapabilities = await effortRefresher.get(true);
|
|
10518
|
+
const effortRejection = assignmentEffortRejection(assignment, effortCapabilities, opts.harness);
|
|
10519
|
+
if (effortRejection && assignment.effort) {
|
|
10520
|
+
run3.effortEvidence = {
|
|
10521
|
+
status: "rejected",
|
|
10522
|
+
attempted_effort: assignment.effort.value,
|
|
10523
|
+
transport: "argv",
|
|
10524
|
+
reason: effortRejection
|
|
10525
|
+
};
|
|
10526
|
+
await client2.appendRunLog(runId, {
|
|
10527
|
+
chunk: "",
|
|
10528
|
+
effort_application: run3.effortEvidence
|
|
10529
|
+
}).catch(() => void 0);
|
|
10530
|
+
return table2.finishAndCleanup(run3, "failed", effortRejection);
|
|
10531
|
+
}
|
|
10272
10532
|
log(
|
|
10273
10533
|
resume ? `run ${runId} assigned (issue ${issueLabel ?? assignment.run.issue_id}); resuming run ${resume.previous_run_id} in ${workspace}` : `run ${runId} assigned (issue ${issueLabel ?? assignment.run.issue_id}); materializing workspace`
|
|
10274
10534
|
);
|
|
@@ -10296,28 +10556,28 @@ async function runDaemon(opts) {
|
|
|
10296
10556
|
`
|
|
10297
10557
|
);
|
|
10298
10558
|
for (const repo of resume ? [] : assignment.bundle.repos) {
|
|
10299
|
-
if (
|
|
10559
|
+
if (run3.settled) return table2.cleanup(run3);
|
|
10300
10560
|
const args = [
|
|
10301
10561
|
"clone",
|
|
10302
10562
|
...repo.branch ? ["--branch", repo.branch] : [],
|
|
10303
10563
|
repo.url,
|
|
10304
10564
|
repo.dir
|
|
10305
10565
|
];
|
|
10306
|
-
|
|
10566
|
+
run3.batcher.append(`$ git ${args.join(" ")}
|
|
10307
10567
|
`);
|
|
10308
|
-
const result = await runGit(args, workspace,
|
|
10568
|
+
const result = await runGit(args, workspace, run3.batcher);
|
|
10309
10569
|
if (result !== 0) {
|
|
10310
10570
|
return table2.finishAndCleanup(
|
|
10311
|
-
|
|
10571
|
+
run3,
|
|
10312
10572
|
"failed",
|
|
10313
10573
|
`git clone failed for ${repo.url} (exit ${result})`
|
|
10314
10574
|
);
|
|
10315
10575
|
}
|
|
10316
10576
|
}
|
|
10317
|
-
if (
|
|
10577
|
+
if (run3.settled) return table2.cleanup(run3);
|
|
10318
10578
|
const cli = await ensureCli();
|
|
10319
|
-
if (
|
|
10320
|
-
|
|
10579
|
+
if (run3.settled) return table2.cleanup(run3);
|
|
10580
|
+
run3.batcher.append(
|
|
10321
10581
|
cli.source === "fresh" ? `tines CLI: ${cli.version ?? "unknown"} (daemon-managed)
|
|
10322
10582
|
` : cli.source === "stale" ? `warning: agent CLI refresh failed; using last-good tines ${cli.version ?? "unknown"} from ${opts.configDir}/cli
|
|
10323
10583
|
` : `warning: no daemon-managed tines CLI; using whatever \`tines\` is on this machine's PATH
|
|
@@ -10328,6 +10588,7 @@ async function runDaemon(opts) {
|
|
|
10328
10588
|
promptFile: join6(workspace, "prompt.md"),
|
|
10329
10589
|
prompt: assignment.prompt,
|
|
10330
10590
|
model: assignment.run.model,
|
|
10591
|
+
effort: assignment.effort?.value ?? null,
|
|
10331
10592
|
...resume ? { resumeSessionId: resume.provider_session_id } : {}
|
|
10332
10593
|
};
|
|
10333
10594
|
const invocation = buildHarnessInvocation(
|
|
@@ -10335,10 +10596,10 @@ async function runDaemon(opts) {
|
|
|
10335
10596
|
harnessInput
|
|
10336
10597
|
);
|
|
10337
10598
|
if (opts.harness === "codex") {
|
|
10338
|
-
|
|
10339
|
-
|
|
10599
|
+
run3.pricingModel = harnessInput.model;
|
|
10600
|
+
run3.pricingSessionMode = resume ? "resumed" : "cold";
|
|
10340
10601
|
}
|
|
10341
|
-
|
|
10602
|
+
run3.batcher.append(
|
|
10342
10603
|
formatLaunchBanner(invocation, harnessInput, {
|
|
10343
10604
|
harness: opts.harness,
|
|
10344
10605
|
timeoutMinutes: assignment.timeout_minutes,
|
|
@@ -10351,93 +10612,118 @@ async function runDaemon(opts) {
|
|
|
10351
10612
|
apiKey: assignment.run_key,
|
|
10352
10613
|
apiUrl: baseUrl
|
|
10353
10614
|
});
|
|
10354
|
-
if (opts.harness === "codex")
|
|
10355
|
-
const child =
|
|
10615
|
+
if (opts.harness === "codex") run3.codexHome = resolveCodexHome(spawnEnv, workspace);
|
|
10616
|
+
const child = spawn3(invocation.file, invocation.args, {
|
|
10356
10617
|
cwd: workspace,
|
|
10357
10618
|
env: spawnEnv,
|
|
10358
10619
|
stdio: ["ignore", "pipe", "pipe"],
|
|
10359
10620
|
detached: true
|
|
10360
10621
|
});
|
|
10361
|
-
|
|
10362
|
-
|
|
10622
|
+
if (assignment.effort) {
|
|
10623
|
+
child.once("spawn", () => {
|
|
10624
|
+
run3.effortEvidence = {
|
|
10625
|
+
status: "accepted_unconfirmed",
|
|
10626
|
+
attempted_effort: assignment.effort.value,
|
|
10627
|
+
transport: "argv"
|
|
10628
|
+
};
|
|
10629
|
+
void client2.appendRunLog(runId, {
|
|
10630
|
+
chunk: "",
|
|
10631
|
+
effort_application: run3.effortEvidence
|
|
10632
|
+
}).catch((err) => log(`run ${runId}: effort evidence rejected: ${message2(err)}`));
|
|
10633
|
+
});
|
|
10634
|
+
}
|
|
10635
|
+
run3.child = child;
|
|
10636
|
+
run3.spawnedAt = Date.now();
|
|
10363
10637
|
table2.persist();
|
|
10364
10638
|
log(`run ${runId}: launched ${invocation.file} (pid ${child.pid})`);
|
|
10365
10639
|
if (opts.harness === "claude_code") {
|
|
10366
10640
|
const limiter = new RateLimitDetector();
|
|
10367
|
-
|
|
10641
|
+
run3.limiter = limiter;
|
|
10368
10642
|
const renderer = new ClaudeStreamRenderer(
|
|
10369
|
-
(line) =>
|
|
10643
|
+
(line) => run3.batcher.append(line),
|
|
10370
10644
|
(event) => limiter.noteStreamEvent(event)
|
|
10371
10645
|
);
|
|
10372
|
-
|
|
10646
|
+
run3.renderer = renderer;
|
|
10373
10647
|
const spoolPath = join6(opts.configDir, "rawlogs", `${runId}.ndjson`);
|
|
10374
10648
|
mkdirSync4(dirname4(spoolPath), { recursive: true });
|
|
10375
|
-
|
|
10376
|
-
|
|
10377
|
-
|
|
10649
|
+
run3.rawSpoolPath = spoolPath;
|
|
10650
|
+
run3.rawSpool = createWriteStream(spoolPath);
|
|
10651
|
+
run3.rawUpload = (body) => client2.putRunLogRaw(runId, body);
|
|
10378
10652
|
const decoder = new StringDecoder2("utf8");
|
|
10379
|
-
|
|
10653
|
+
run3.drain = () => {
|
|
10380
10654
|
const trailing = decoder.end();
|
|
10381
10655
|
if (trailing) renderer.write(trailing);
|
|
10382
10656
|
renderer.finish();
|
|
10383
10657
|
};
|
|
10384
10658
|
child.stdout?.on("data", (data) => {
|
|
10385
|
-
|
|
10659
|
+
run3.rawSpool?.write(data);
|
|
10386
10660
|
renderer.write(decoder.write(data));
|
|
10387
10661
|
});
|
|
10388
10662
|
} else if (opts.harness === "codex") {
|
|
10389
|
-
const renderer = new CodexStreamRenderer((line) =>
|
|
10663
|
+
const renderer = new CodexStreamRenderer((line) => run3.batcher.append(line));
|
|
10390
10664
|
const decoder = new StringDecoder2("utf8");
|
|
10391
|
-
|
|
10392
|
-
|
|
10665
|
+
run3.renderer = renderer;
|
|
10666
|
+
run3.drain = () => {
|
|
10393
10667
|
const trailing = decoder.end();
|
|
10394
10668
|
if (trailing) renderer.write(trailing);
|
|
10395
10669
|
renderer.finish();
|
|
10396
10670
|
};
|
|
10397
10671
|
child.stdout?.on("data", (data) => renderer.write(decoder.write(data)));
|
|
10398
10672
|
} else {
|
|
10399
|
-
child.stdout?.on("data", (data) =>
|
|
10673
|
+
child.stdout?.on("data", (data) => run3.batcher.append(data.toString("utf8")));
|
|
10400
10674
|
}
|
|
10401
10675
|
child.stderr?.on("data", (data) => {
|
|
10402
10676
|
const text4 = data.toString("utf8");
|
|
10403
|
-
|
|
10404
|
-
|
|
10677
|
+
run3.batcher.append(text4);
|
|
10678
|
+
run3.limiter?.noteStderr(text4);
|
|
10405
10679
|
});
|
|
10406
|
-
|
|
10407
|
-
if (
|
|
10680
|
+
run3.timeout = setTimeout(() => {
|
|
10681
|
+
if (run3.settled) return;
|
|
10408
10682
|
log(`run ${runId} hit its ${assignment.timeout_minutes}m timeout; killing`);
|
|
10409
|
-
|
|
10683
|
+
run3.timedOut = true;
|
|
10410
10684
|
if (child.pid) killTree(child.pid, "SIGTERM");
|
|
10411
10685
|
if (child.pid) setTimeout(() => killTree(child.pid, "SIGKILL"), 5e3).unref?.();
|
|
10412
10686
|
}, assignment.timeout_minutes * 6e4);
|
|
10413
10687
|
child.on("error", (err) => {
|
|
10414
|
-
|
|
10688
|
+
const reason = `failed to launch harness: ${message2(err)}`;
|
|
10689
|
+
if (assignment.effort)
|
|
10690
|
+
run3.effortEvidence = {
|
|
10691
|
+
status: "rejected",
|
|
10692
|
+
attempted_effort: assignment.effort.value,
|
|
10693
|
+
transport: "argv",
|
|
10694
|
+
reason
|
|
10695
|
+
};
|
|
10696
|
+
const evidence = assignment.effort ? client2.appendRunLog(runId, {
|
|
10697
|
+
chunk: "",
|
|
10698
|
+
effort_application: run3.effortEvidence
|
|
10699
|
+
}).catch(() => void 0) : Promise.resolve();
|
|
10700
|
+
void evidence.then(() => table2.finishAndCleanup(run3, "failed", reason));
|
|
10415
10701
|
});
|
|
10416
10702
|
child.on("close", (code, signal) => {
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
const closing = exitLineForRun(
|
|
10703
|
+
run3.drain?.();
|
|
10704
|
+
run3.limiter?.finish();
|
|
10705
|
+
const closing = exitLineForRun(run3, {
|
|
10420
10706
|
code,
|
|
10421
10707
|
signal,
|
|
10422
|
-
durationMs: Date.now() - (
|
|
10708
|
+
durationMs: Date.now() - (run3.spawnedAt ?? Date.now())
|
|
10423
10709
|
});
|
|
10424
|
-
if (closing)
|
|
10425
|
-
if (
|
|
10710
|
+
if (closing) run3.batcher.append(closing);
|
|
10711
|
+
if (run3.timedOut) {
|
|
10426
10712
|
void table2.finishAndCleanup(
|
|
10427
|
-
|
|
10713
|
+
run3,
|
|
10428
10714
|
"failed",
|
|
10429
10715
|
`run exceeded the ${assignment.timeout_minutes}m timeout; harness killed`
|
|
10430
10716
|
);
|
|
10431
10717
|
} else if (code === 0) {
|
|
10432
|
-
void table2.finishAndCleanup(
|
|
10718
|
+
void table2.finishAndCleanup(run3, "completed");
|
|
10433
10719
|
} else {
|
|
10434
|
-
const limited = signal ? null :
|
|
10435
|
-
const providerError = signal ? null :
|
|
10720
|
+
const limited = signal ? null : run3.limiter?.signal() ?? null;
|
|
10721
|
+
const providerError = signal ? null : run3.limiter?.providerError() ?? null;
|
|
10436
10722
|
if (limited) {
|
|
10437
10723
|
log(
|
|
10438
10724
|
`run ${runId}: harness rate limited (${limited.detail}); reporting without a strike`
|
|
10439
10725
|
);
|
|
10440
|
-
void table2.finishAndCleanup(
|
|
10726
|
+
void table2.finishAndCleanup(run3, "failed", `rate limited: ${limited.detail}`, {
|
|
10441
10727
|
judgment: "rate_limited",
|
|
10442
10728
|
...limited.resumeAt !== null ? { resume_at: limited.resumeAt } : {}
|
|
10443
10729
|
});
|
|
@@ -10445,12 +10731,12 @@ async function runDaemon(opts) {
|
|
|
10445
10731
|
log(
|
|
10446
10732
|
`run ${runId}: transient provider error (${providerError.detail}); reporting without a strike`
|
|
10447
10733
|
);
|
|
10448
|
-
void table2.finishAndCleanup(
|
|
10734
|
+
void table2.finishAndCleanup(run3, "failed", `provider error: ${providerError.detail}`, {
|
|
10449
10735
|
judgment: "interrupted"
|
|
10450
10736
|
});
|
|
10451
10737
|
} else {
|
|
10452
10738
|
void table2.finishAndCleanup(
|
|
10453
|
-
|
|
10739
|
+
run3,
|
|
10454
10740
|
"failed",
|
|
10455
10741
|
signal ? `harness killed by ${signal}` : `harness exited with code ${code}`
|
|
10456
10742
|
);
|
|
@@ -10458,7 +10744,7 @@ async function runDaemon(opts) {
|
|
|
10458
10744
|
}
|
|
10459
10745
|
});
|
|
10460
10746
|
} catch (err) {
|
|
10461
|
-
void table2.finishAndCleanup(
|
|
10747
|
+
void table2.finishAndCleanup(run3, "failed", `workspace setup failed: ${message2(err)}`);
|
|
10462
10748
|
}
|
|
10463
10749
|
};
|
|
10464
10750
|
const shutdown = async () => {
|
|
@@ -10466,9 +10752,9 @@ async function runDaemon(opts) {
|
|
|
10466
10752
|
shuttingDown = true;
|
|
10467
10753
|
log("shutting down; failing in-flight runs");
|
|
10468
10754
|
await Promise.all(
|
|
10469
|
-
table2.values().map(async (
|
|
10470
|
-
if (
|
|
10471
|
-
await table2.finishAndCleanup(
|
|
10755
|
+
table2.values().map(async (run3) => {
|
|
10756
|
+
if (run3.child?.pid) killTree(run3.child.pid, "SIGTERM");
|
|
10757
|
+
await table2.finishAndCleanup(run3, "failed", "daemon shut down", {
|
|
10472
10758
|
judgment: "interrupted"
|
|
10473
10759
|
});
|
|
10474
10760
|
})
|
|
@@ -10483,10 +10769,12 @@ async function runDaemon(opts) {
|
|
|
10483
10769
|
let failures = 0;
|
|
10484
10770
|
while (!shuttingDown) {
|
|
10485
10771
|
try {
|
|
10772
|
+
effortCapabilities = await effortRefresher.get();
|
|
10486
10773
|
const res = await client2.pollRunner(creds.runner_id, {
|
|
10487
10774
|
instance_id: instanceId,
|
|
10488
10775
|
owned_runs: table2.ids(),
|
|
10489
10776
|
max_concurrent: opts.maxConcurrent,
|
|
10777
|
+
...effortCapabilities ? { effort_capabilities: effortCapabilities } : {},
|
|
10490
10778
|
// Stated on every poll while pending; absent otherwise, which
|
|
10491
10779
|
// the server reads as "not draining" — so a daemon that died
|
|
10492
10780
|
// mid-drain cannot pin its runner shut past its relaunch.
|
|
@@ -10519,11 +10807,11 @@ async function runDaemon(opts) {
|
|
|
10519
10807
|
return;
|
|
10520
10808
|
}
|
|
10521
10809
|
if (err instanceof ApiError && err.status === 401) {
|
|
10522
|
-
for (const
|
|
10523
|
-
if (
|
|
10524
|
-
settleWorkspace(
|
|
10525
|
-
run_id:
|
|
10526
|
-
...
|
|
10810
|
+
for (const run3 of table2.values()) {
|
|
10811
|
+
if (run3.child?.pid) killTree(run3.child.pid, "SIGKILL");
|
|
10812
|
+
settleWorkspace(run3.workspace, keepWorkspace(opts.keepWorkspaces, "failed"), {
|
|
10813
|
+
run_id: run3.runId,
|
|
10814
|
+
...run3.issueLabel ? { issue_ref: run3.issueLabel } : {},
|
|
10527
10815
|
status: "failed",
|
|
10528
10816
|
error: "daemon token rejected"
|
|
10529
10817
|
});
|
|
@@ -10557,7 +10845,7 @@ function realpathOrNull(path2) {
|
|
|
10557
10845
|
}
|
|
10558
10846
|
function runGit(args, cwd, batcher) {
|
|
10559
10847
|
return new Promise((resolve2) => {
|
|
10560
|
-
const child =
|
|
10848
|
+
const child = spawn3("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
10561
10849
|
child.stdout?.on("data", (data) => batcher.append(data.toString("utf8")));
|
|
10562
10850
|
child.stderr?.on("data", (data) => batcher.append(data.toString("utf8")));
|
|
10563
10851
|
child.on("error", () => resolve2(127));
|
|
@@ -10633,7 +10921,7 @@ function harnessFlag(harness) {
|
|
|
10633
10921
|
}
|
|
10634
10922
|
|
|
10635
10923
|
// src/commands/runner-service.ts
|
|
10636
|
-
import { execFile } from "node:child_process";
|
|
10924
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
10637
10925
|
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync10, rmSync as rmSync4, statSync as statSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
10638
10926
|
import { homedir as homedir3, hostname as hostname3, userInfo } from "node:os";
|
|
10639
10927
|
import { dirname as dirname6 } from "node:path";
|
|
@@ -10832,7 +11120,7 @@ function managedBinaryPresent(prefix) {
|
|
|
10832
11120
|
}
|
|
10833
11121
|
|
|
10834
11122
|
// src/commands/runner-service.ts
|
|
10835
|
-
var
|
|
11123
|
+
var run2 = promisify(execFile2);
|
|
10836
11124
|
var STARTUP_TIMEOUT_MS = 3e4;
|
|
10837
11125
|
var log2 = (message3) => console.log(message3);
|
|
10838
11126
|
function resolveServiceManager(flag) {
|
|
@@ -10852,7 +11140,7 @@ function resolveServiceManager(flag) {
|
|
|
10852
11140
|
async function runServiceCommands(steps) {
|
|
10853
11141
|
for (const step of steps) {
|
|
10854
11142
|
try {
|
|
10855
|
-
await
|
|
11143
|
+
await run2(step.argv[0], step.argv.slice(1), { timeout: 3e4 });
|
|
10856
11144
|
} catch (err) {
|
|
10857
11145
|
if (step.optional) continue;
|
|
10858
11146
|
const detail = err && typeof err === "object" && "stderr" in err && String(err.stderr).trim() ? `: ${String(err.stderr).trim()}` : err instanceof Error ? `: ${err.message}` : "";
|
|
@@ -10862,7 +11150,7 @@ async function runServiceCommands(steps) {
|
|
|
10862
11150
|
}
|
|
10863
11151
|
async function listProcesses() {
|
|
10864
11152
|
try {
|
|
10865
|
-
const { stdout } = await
|
|
11153
|
+
const { stdout } = await run2("ps", ["-axo", "pid=,args="], { maxBuffer: 16 * 1024 * 1024 });
|
|
10866
11154
|
return stdout;
|
|
10867
11155
|
} catch {
|
|
10868
11156
|
return null;
|
|
@@ -11506,14 +11794,14 @@ function register8(program3) {
|
|
|
11506
11794
|
if (evidence.population === "pending") {
|
|
11507
11795
|
table([
|
|
11508
11796
|
["ID", "ISSUE", "RUNNER", "TIER", "STATUS", "COST", "CREATED"],
|
|
11509
|
-
...items.map((
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11797
|
+
...items.map((run3) => [
|
|
11798
|
+
run3.id,
|
|
11799
|
+
run3.issue_ref ? `${run3.issue_ref.project_name}/${run3.issue_ref.number}` : run3.issue_id,
|
|
11800
|
+
run3.runner_name,
|
|
11801
|
+
run3.tier,
|
|
11514
11802
|
"Pending at cutoff",
|
|
11515
11803
|
"\u2014",
|
|
11516
|
-
timestamp(
|
|
11804
|
+
timestamp(run3.created_at)
|
|
11517
11805
|
])
|
|
11518
11806
|
]);
|
|
11519
11807
|
return;
|
|
@@ -11523,12 +11811,12 @@ function register8(program3) {
|
|
|
11523
11811
|
...items.map(runRow)
|
|
11524
11812
|
]);
|
|
11525
11813
|
if (evidence.population === "finalized") {
|
|
11526
|
-
for (const
|
|
11527
|
-
if (
|
|
11814
|
+
for (const run3 of items)
|
|
11815
|
+
if (run3.usage_dimensions && run3.usage_accounting)
|
|
11528
11816
|
for (const line of usageEvidenceLines(
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11817
|
+
run3.id,
|
|
11818
|
+
run3.usage_dimensions,
|
|
11819
|
+
run3.usage_accounting
|
|
11532
11820
|
))
|
|
11533
11821
|
console.log(line);
|
|
11534
11822
|
}
|
|
@@ -11539,29 +11827,41 @@ function register8(program3) {
|
|
|
11539
11827
|
).action(
|
|
11540
11828
|
async (id2, opts) => {
|
|
11541
11829
|
const api = client(opts);
|
|
11542
|
-
const
|
|
11543
|
-
if (opts.json) return printJson(
|
|
11830
|
+
const run3 = await api.getRun(id2);
|
|
11831
|
+
if (opts.json) return printJson(run3);
|
|
11544
11832
|
console.log(
|
|
11545
|
-
`${
|
|
11833
|
+
`${run3.id} ${run3.status} on ${run3.runner_name}${run3.resumed_from_run_id ? ` \xB7 resumed run ${run3.resumed_from_run_id}` : ""}`
|
|
11834
|
+
);
|
|
11835
|
+
if (run3.issue_ref) console.log(`issue: ${issueRef(run3.issue_ref)} \u2014 ${run3.issue_ref.title}`);
|
|
11836
|
+
console.log(`tier: ${run3.tier} model: ${run3.model ?? "(n/a)"}`);
|
|
11837
|
+
const effortSource = run3.effort_source;
|
|
11838
|
+
const sourceLabel2 = effortSource?.kind === "routing_target" ? `routing target ${effortSource.target_index + 1} (${effortSource.scope_label})` : effortSource?.kind === "runner_tier" ? `runner tier ${effortSource.tier}` : effortSource?.kind === "none" ? "provider default" : "legacy record";
|
|
11839
|
+
const evidence = run3.effort_application_evidence;
|
|
11840
|
+
const observed = evidence?.milestones?.findLast(
|
|
11841
|
+
(item) => item.observed_model !== void 0 || item.observed_effort !== void 0
|
|
11546
11842
|
);
|
|
11547
|
-
if (run2.issue_ref) console.log(`issue: ${issueRef(run2.issue_ref)} \u2014 ${run2.issue_ref.title}`);
|
|
11548
|
-
console.log(`tier: ${run2.tier} model: ${run2.model ?? "(n/a)"}`);
|
|
11549
11843
|
console.log(
|
|
11550
|
-
`
|
|
11844
|
+
`effort: requested ${run3.requested_effort ?? "(none)"} resolved ${run3.resolved_effort ?? "(provider default)"} source ${sourceLabel2}`
|
|
11551
11845
|
);
|
|
11552
11846
|
console.log(
|
|
11553
|
-
`
|
|
11847
|
+
`effort application: ${(run3.effort_application_status ?? "unknown").replaceAll("_", " ")}${observed ? ` observed ${observed.observed_effort ?? "(unknown effort)"} on ${observed.observed_model ?? "(unknown model)"}` : " observed unknown"}${observed?.reason ? ` (${observed.reason})` : ""}`
|
|
11554
11848
|
);
|
|
11555
|
-
|
|
11556
|
-
|
|
11557
|
-
|
|
11849
|
+
console.log(
|
|
11850
|
+
`states: ${run3.state_at_start_name ?? run3.state_id_at_start} \u2192 ${run3.state_at_end_name ?? run3.state_id_at_end ?? "\u2026"}`
|
|
11851
|
+
);
|
|
11852
|
+
console.log(
|
|
11853
|
+
`created: ${timestamp(run3.created_at)} started: ${run3.started_at ? timestamp(run3.started_at) : "\u2014"} ended: ${run3.ended_at ? timestamp(run3.ended_at) : "\u2014"} duration: ${runDurationLabel(run3)}`
|
|
11854
|
+
);
|
|
11855
|
+
if (run3.usage) {
|
|
11856
|
+
const u = run3.usage;
|
|
11857
|
+
const costLabel = runCostLabel(run3);
|
|
11558
11858
|
const metric = (value) => value === void 0 ? "unknown" : value.toLocaleString();
|
|
11559
11859
|
console.log(
|
|
11560
11860
|
`usage: input ${metric(u.input_tokens)} cache-read ${metric(u.cache_read_tokens)} cache-write ${metric(u.cache_write_tokens)} output ${metric(u.output_tokens)}`
|
|
11561
11861
|
);
|
|
11562
11862
|
if (u.cost_usd !== void 0)
|
|
11563
11863
|
console.log(
|
|
11564
|
-
`cost: ${runCostLabel(
|
|
11864
|
+
`cost: ${runCostLabel(run3)}${u.cost_source === void 0 ? " \xB7 source unavailable" : ""}`
|
|
11565
11865
|
);
|
|
11566
11866
|
const pricing = u.pricing;
|
|
11567
11867
|
if (pricing?.status === "provider_authoritative")
|
|
@@ -11596,9 +11896,9 @@ function register8(program3) {
|
|
|
11596
11896
|
);
|
|
11597
11897
|
}
|
|
11598
11898
|
}
|
|
11599
|
-
if (
|
|
11600
|
-
if (
|
|
11601
|
-
if (
|
|
11899
|
+
if (run3.provider_session_id) console.log(`provider session: ${run3.provider_session_id}`);
|
|
11900
|
+
if (run3.provider_url) console.log(`provider console: ${run3.provider_url}`);
|
|
11901
|
+
if (run3.error) console.log(`error: ${run3.error}`);
|
|
11602
11902
|
if (opts.logs) {
|
|
11603
11903
|
console.log("");
|
|
11604
11904
|
if (opts.full || opts.raw) {
|
|
@@ -11615,12 +11915,12 @@ function register8(program3) {
|
|
|
11615
11915
|
process.stdout.write(decoder.decode());
|
|
11616
11916
|
return;
|
|
11617
11917
|
}
|
|
11618
|
-
if (
|
|
11918
|
+
if (run3.log_bytes_dropped > 0) {
|
|
11619
11919
|
console.log(
|
|
11620
|
-
`[${Math.round(
|
|
11920
|
+
`[${Math.round(run3.log_bytes_dropped / 1024)} KB truncated from the head \u2014 ` + (run3.log_expired ? "past its retention window; only this tail remains]" : `run \`tines runs show ${run3.id} --logs --full\` for the complete ${Math.round(run3.log_full_bytes / 1024)} KB log]`)
|
|
11621
11921
|
);
|
|
11622
11922
|
}
|
|
11623
|
-
console.log(
|
|
11923
|
+
console.log(run3.log || "(no log output captured)");
|
|
11624
11924
|
}
|
|
11625
11925
|
}
|
|
11626
11926
|
);
|
|
@@ -11628,10 +11928,10 @@ function register8(program3) {
|
|
|
11628
11928
|
runsCmd.command("cancel <id>").description("Cancel a run (judged like any other end: usually a strike)")
|
|
11629
11929
|
).action(async (id2, opts) => {
|
|
11630
11930
|
const api = client(opts);
|
|
11631
|
-
const
|
|
11632
|
-
if (opts.json) return printJson(
|
|
11931
|
+
const run3 = await api.cancelRun(id2);
|
|
11932
|
+
if (opts.json) return printJson(run3);
|
|
11633
11933
|
console.log(
|
|
11634
|
-
`canceled ${
|
|
11934
|
+
`canceled ${run3.id}${run3.issue_ref ? ` on ${issueRef(run3.issue_ref)}` : ""} (was on ${run3.runner_name})`
|
|
11635
11935
|
);
|
|
11636
11936
|
});
|
|
11637
11937
|
}
|
|
@@ -11858,6 +12158,8 @@ function queueHeadline(block) {
|
|
|
11858
12158
|
return `${runner} backing off`;
|
|
11859
12159
|
case "rate_limited":
|
|
11860
12160
|
return `${runner} rate limited`;
|
|
12161
|
+
case "effort_incompatible":
|
|
12162
|
+
return `${runner} cannot apply the requested effort`;
|
|
11861
12163
|
case "no_rule":
|
|
11862
12164
|
return "no matching routing rule";
|
|
11863
12165
|
case "no_targets":
|
|
@@ -11896,6 +12198,8 @@ function queueFix(block) {
|
|
|
11896
12198
|
return "retries automatically; check the daemon log if it keeps failing";
|
|
11897
12199
|
case "rate_limited":
|
|
11898
12200
|
return "resumes automatically when the usage window resets; nothing to do";
|
|
12201
|
+
case "effort_incompatible":
|
|
12202
|
+
return `upgrade or reconnect ${runner}, or choose a model and effort it reports as supported`;
|
|
11899
12203
|
default:
|
|
11900
12204
|
return null;
|
|
11901
12205
|
}
|
|
@@ -12115,7 +12419,7 @@ import { readFileSync as readFileSync12 } from "node:fs";
|
|
|
12115
12419
|
|
|
12116
12420
|
// src/workflow-packages.ts
|
|
12117
12421
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
12118
|
-
import { createHash } from "node:crypto";
|
|
12422
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
12119
12423
|
import { readFileSync as readFileSync11 } from "node:fs";
|
|
12120
12424
|
var PACKAGE_STDIN = "-";
|
|
12121
12425
|
var MAX_LOCAL_JSON_BYTES = 32 * 1024 * 1024;
|
|
@@ -12282,7 +12586,7 @@ function expectedWorkflowPackageOperations(plan) {
|
|
|
12282
12586
|
function assertPlanBinding(plan) {
|
|
12283
12587
|
const payload = tokenPayload(plan.plan_token);
|
|
12284
12588
|
const { plan_digest: signedDigest, ...unsigned } = payload;
|
|
12285
|
-
const
|
|
12589
|
+
const digest2 = `sha256:${createHash2("sha256").update(canonicalizeLibraryValue({ plan: unsigned, resolved: plan.resolved })).digest("hex")}`;
|
|
12286
12590
|
const mirrors = {
|
|
12287
12591
|
id: plan.plan_id,
|
|
12288
12592
|
plan_digest: plan.plan_digest,
|
|
@@ -12299,7 +12603,7 @@ function assertPlanBinding(plan) {
|
|
|
12299
12603
|
if (canonicalizeLibraryValue(payload[signedField]) !== canonicalizeLibraryValue(value))
|
|
12300
12604
|
throw new Error(`saved workflow package plan has modified ${field}`);
|
|
12301
12605
|
}
|
|
12302
|
-
if (signedDigest !==
|
|
12606
|
+
if (signedDigest !== digest2 || plan.plan_digest !== digest2)
|
|
12303
12607
|
throw new Error("saved workflow package plan digest does not bind its review");
|
|
12304
12608
|
if (canonicalizeLibraryValue(plan.operations) !== canonicalizeLibraryValue(expectedWorkflowPackageOperations(plan)))
|
|
12305
12609
|
throw new Error("saved workflow package plan has modified operations");
|
|
@@ -12922,12 +13226,12 @@ function printEvidence(page) {
|
|
|
12922
13226
|
table([
|
|
12923
13227
|
["RUN", "ISSUE", "SPEND", "AT"],
|
|
12924
13228
|
...page.items.map((item) => {
|
|
12925
|
-
const
|
|
13229
|
+
const run3 = item;
|
|
12926
13230
|
return [
|
|
12927
|
-
|
|
12928
|
-
|
|
12929
|
-
page.population === "pending" ? "Pending" : money(
|
|
12930
|
-
new Date(
|
|
13231
|
+
run3.id,
|
|
13232
|
+
run3.issue_id,
|
|
13233
|
+
page.population === "pending" ? "Pending" : money(run3.usage_accounting?.cost ?? null),
|
|
13234
|
+
new Date(run3.ended_at ?? run3.created_at).toISOString()
|
|
12931
13235
|
];
|
|
12932
13236
|
})
|
|
12933
13237
|
]);
|