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.
Files changed (2) hide show
  1. package/dist/index.js +521 -217
  2. 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(run2) {
3411
- return run2.issue_ref ? `run on ${run2.issue_ref.project_name}/${run2.issue_ref.number}` : `run ${run2.run_id}`;
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(run2, now = Date.now()) {
3535
- if (!run2.started_at) return "\u2014";
3536
- const seconds = Math.max(0, Math.round(((run2.ended_at ?? now) - run2.started_at) / 1e3));
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(run2) {
3540
- const usage2 = run2.usage;
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 run2 of activeRuns) {
3564
- const entry = counts.get(run2.state_id_at_start) ?? {
3565
- name: run2.state_at_start_name ?? stateName(run2.state_id_at_start),
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(run2.state_id_at_start, entry);
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 digest = (v, p) => {
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 `*:${rule.targets[0].tier} (inherited runners)`;
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 run2 of earlier) lines2.push(` ${earlierAttemptLine(run2, now)}`);
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(run2, now) {
5685
- const cost = runCostLabel(run2);
5692
+ function runHeadline(run3, now) {
5693
+ const cost = runCostLabel(run3);
5686
5694
  return [
5687
- `${run2.run_id} on ${run2.runner_name}`,
5688
- runDurationLabel(run2, now),
5689
- run2.outcome ?? run2.status,
5695
+ `${run3.run_id} on ${run3.runner_name}`,
5696
+ runDurationLabel(run3, now),
5697
+ run3.outcome ?? run3.status,
5690
5698
  ...cost ? [cost] : [],
5691
- run2.transition ? `"${run2.transition.action ?? "moved directly"}" \u2192 ${run2.transition.to_state.name}` : "no transition"
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(run2, now) {
5695
- const back = run2.returned_via;
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 `${run2.run_id} \xB7 ${runDurationLabel(run2, now)} \xB7 ${run2.outcome ?? run2.status} \xB7 ${how}`;
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(run2) {
5724
+ function runRow(run3) {
5717
5725
  return [
5718
- run2.id,
5719
- run2.issue_ref ? issueRef(run2.issue_ref) : run2.issue_id,
5720
- run2.runner_name,
5721
- `${run2.tier}${run2.model ? ` (${run2.model})` : ""}`,
5722
- `${run2.status}${run2.resumed_from_run_id ? ` \xB7 resumed run ${run2.resumed_from_run_id}` : ""}`,
5723
- runDurationLabel(run2),
5724
- runCostLabel(run2) ?? "\u2014",
5725
- timestamp(run2.created_at)
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(tier ? { runner_id: runner.id, tier } : { runner_id: runner.id });
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 spawn2 } from "node:child_process";
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 failure = consume(pending.slice(0, newline));
9137
- if (failure) return failure;
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 failure = consume(pending);
9146
- if (failure) return failure;
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(run2, exit) {
9481
- if (run2.settled) return null;
9482
- return formatExitLine({ ...exit, timedOut: run2.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(run2) {
9506
- this.runs.set(run2.runId, run2);
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(run2, outcome = "failed") {
9523
- this.runs.delete(run2.runId);
9764
+ cleanup(run3, outcome = "failed") {
9765
+ this.runs.delete(run3.runId);
9524
9766
  this.effects.persist();
9525
- this.effects.release(run2, { keep: this.keep(outcome, run2), outcome });
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(run2, status, error, judgment) {
9542
- if (run2.settled) return this.cleanup(run2);
9543
- run2.settled = true;
9544
- run2.endNote ??= error;
9545
- run2.drain?.();
9546
- if (this.keep(status, run2)) this.effects.noteKept?.(run2);
9547
- await run2.flush?.();
9548
- const keptBeforeFinish = this.keep(status, run2);
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(run2, status, error, judgment);
9551
- this.effects.log(`run ${run2.runId} finished: ${status}${error ? ` (${error})` : ""}`);
9552
- if (!keptBeforeFinish && this.keep(status, run2)) {
9553
- this.effects.log(`run ${run2.runId} workspace kept for resume at ${run2.workspace}`);
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 ${run2.runId} not accepted: ${err instanceof Error ? err.message : String(err)}`
9799
+ `finish report for run ${run3.runId} not accepted: ${err instanceof Error ? err.message : String(err)}`
9558
9800
  );
9559
9801
  }
9560
- this.cleanup(run2, status);
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 run2 = this.runs.get(runId);
9570
- if (!run2 || run2.settled) return null;
9571
- run2.canceled = true;
9572
- run2.settled = true;
9573
- return run2;
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 = spawn(file, args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
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(run2) {
9978
- const path2 = run2.rawSpoolPath;
9979
- if (!path2 || !run2.rawUpload) return;
9980
- run2.rawSpoolPath = void 0;
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) => run2.rawSpool?.end(resolve2) ?? 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 run2.rawUpload(body);
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 (run2, status, error, judgment) => {
10108
- const summary = run2.renderer?.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" && run2.pricingSessionMode === "cold" && summary.pricingEvidence.measurement_status === "complete" && completeRaw && summary.providerSessionId && run2.codexHome && run2.spawnedAt) {
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: run2.codexHome,
10361
+ codexHome: run3.codexHome,
10120
10362
  threadId: summary.providerSessionId,
10121
- model: run2.pricingModel ?? null,
10122
- startedAt: run2.spawnedAt,
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
- run2.batcher.append(`[usage] ${JSON.stringify(accounting)}
10386
+ run3.batcher.append(`[usage] ${JSON.stringify(accounting)}
10145
10387
  `);
10146
- await run2.batcher.flush();
10147
- const ended = await client2.finishRun(run2.runId, {
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: run2.pricingModel ?? null,
10156
- session_mode: run2.pricingSessionMode ?? "cold",
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: run2.priorTurns + summary.numTurns } : {},
10165
- workspace_path: run2.workspace
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) run2.keepForResume = true;
10410
+ if (ended?.resume_expires_at) run3.keepForResume = true;
10168
10411
  },
10169
- release: (run2, { keep, outcome }) => {
10170
- if (run2.timeout) clearTimeout(run2.timeout);
10171
- run2.renderer?.finish();
10172
- settleWorkspace(run2.workspace, keep, {
10173
- run_id: run2.runId,
10174
- ...run2.issueLabel ? { issue_ref: run2.issueLabel } : {},
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
- ...run2.endNote ? { error: run2.endNote } : {}
10419
+ ...run3.endNote ? { error: run3.endNote } : {}
10177
10420
  });
10178
- void uploadRawLog(run2);
10421
+ void uploadRawLog(run3);
10179
10422
  sweepKeptWorkspaces();
10180
10423
  },
10181
- noteKept: (run2) => run2.batcher.append(`workspace kept at ${run2.workspace}
10424
+ noteKept: (run3) => run3.batcher.append(`workspace kept at ${run3.workspace}
10182
10425
  `),
10183
10426
  persist: () => {
10184
- const entries = table2.values().filter((run2) => run2.child?.pid !== void 0).map((run2) => ({
10185
- run_id: run2.runId,
10186
- pid: run2.child.pid,
10187
- workspace: run2.workspace,
10188
- key_fingerprint: run2.keyFingerprint,
10189
- started_at: run2.spawnedAt,
10190
- ...run2.issueLabel ? { issue_ref: run2.issueLabel } : {}
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, run2) => run2.keepForResume || keepWorkspace(opts.keepWorkspaces, 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 run2 = table2.markCanceled(runId);
10234
- if (!run2) return;
10235
- run2.endNote ??= "canceled by supervisor";
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 (run2.child?.pid) {
10238
- const pid = run2.child.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 run2 = {
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
- run2.flush = () => run2.batcher.flush();
10271
- table2.track(run2);
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 (run2.settled) return table2.cleanup(run2);
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
- run2.batcher.append(`$ git ${args.join(" ")}
10566
+ run3.batcher.append(`$ git ${args.join(" ")}
10307
10567
  `);
10308
- const result = await runGit(args, workspace, run2.batcher);
10568
+ const result = await runGit(args, workspace, run3.batcher);
10309
10569
  if (result !== 0) {
10310
10570
  return table2.finishAndCleanup(
10311
- run2,
10571
+ run3,
10312
10572
  "failed",
10313
10573
  `git clone failed for ${repo.url} (exit ${result})`
10314
10574
  );
10315
10575
  }
10316
10576
  }
10317
- if (run2.settled) return table2.cleanup(run2);
10577
+ if (run3.settled) return table2.cleanup(run3);
10318
10578
  const cli = await ensureCli();
10319
- if (run2.settled) return table2.cleanup(run2);
10320
- run2.batcher.append(
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
- run2.pricingModel = harnessInput.model;
10339
- run2.pricingSessionMode = resume ? "resumed" : "cold";
10599
+ run3.pricingModel = harnessInput.model;
10600
+ run3.pricingSessionMode = resume ? "resumed" : "cold";
10340
10601
  }
10341
- run2.batcher.append(
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") run2.codexHome = resolveCodexHome(spawnEnv, workspace);
10355
- const child = spawn2(invocation.file, invocation.args, {
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
- run2.child = child;
10362
- run2.spawnedAt = Date.now();
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
- run2.limiter = limiter;
10641
+ run3.limiter = limiter;
10368
10642
  const renderer = new ClaudeStreamRenderer(
10369
- (line) => run2.batcher.append(line),
10643
+ (line) => run3.batcher.append(line),
10370
10644
  (event) => limiter.noteStreamEvent(event)
10371
10645
  );
10372
- run2.renderer = renderer;
10646
+ run3.renderer = renderer;
10373
10647
  const spoolPath = join6(opts.configDir, "rawlogs", `${runId}.ndjson`);
10374
10648
  mkdirSync4(dirname4(spoolPath), { recursive: true });
10375
- run2.rawSpoolPath = spoolPath;
10376
- run2.rawSpool = createWriteStream(spoolPath);
10377
- run2.rawUpload = (body) => client2.putRunLogRaw(runId, body);
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
- run2.drain = () => {
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
- run2.rawSpool?.write(data);
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) => run2.batcher.append(line));
10663
+ const renderer = new CodexStreamRenderer((line) => run3.batcher.append(line));
10390
10664
  const decoder = new StringDecoder2("utf8");
10391
- run2.renderer = renderer;
10392
- run2.drain = () => {
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) => run2.batcher.append(data.toString("utf8")));
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
- run2.batcher.append(text4);
10404
- run2.limiter?.noteStderr(text4);
10677
+ run3.batcher.append(text4);
10678
+ run3.limiter?.noteStderr(text4);
10405
10679
  });
10406
- run2.timeout = setTimeout(() => {
10407
- if (run2.settled) return;
10680
+ run3.timeout = setTimeout(() => {
10681
+ if (run3.settled) return;
10408
10682
  log(`run ${runId} hit its ${assignment.timeout_minutes}m timeout; killing`);
10409
- run2.timedOut = true;
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
- void table2.finishAndCleanup(run2, "failed", `failed to launch harness: ${message2(err)}`);
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
- run2.drain?.();
10418
- run2.limiter?.finish();
10419
- const closing = exitLineForRun(run2, {
10703
+ run3.drain?.();
10704
+ run3.limiter?.finish();
10705
+ const closing = exitLineForRun(run3, {
10420
10706
  code,
10421
10707
  signal,
10422
- durationMs: Date.now() - (run2.spawnedAt ?? Date.now())
10708
+ durationMs: Date.now() - (run3.spawnedAt ?? Date.now())
10423
10709
  });
10424
- if (closing) run2.batcher.append(closing);
10425
- if (run2.timedOut) {
10710
+ if (closing) run3.batcher.append(closing);
10711
+ if (run3.timedOut) {
10426
10712
  void table2.finishAndCleanup(
10427
- run2,
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(run2, "completed");
10718
+ void table2.finishAndCleanup(run3, "completed");
10433
10719
  } else {
10434
- const limited = signal ? null : run2.limiter?.signal() ?? null;
10435
- const providerError = signal ? null : run2.limiter?.providerError() ?? 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(run2, "failed", `rate limited: ${limited.detail}`, {
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(run2, "failed", `provider error: ${providerError.detail}`, {
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
- run2,
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(run2, "failed", `workspace setup failed: ${message2(err)}`);
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 (run2) => {
10470
- if (run2.child?.pid) killTree(run2.child.pid, "SIGTERM");
10471
- await table2.finishAndCleanup(run2, "failed", "daemon shut down", {
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 run2 of table2.values()) {
10523
- if (run2.child?.pid) killTree(run2.child.pid, "SIGKILL");
10524
- settleWorkspace(run2.workspace, keepWorkspace(opts.keepWorkspaces, "failed"), {
10525
- run_id: run2.runId,
10526
- ...run2.issueLabel ? { issue_ref: run2.issueLabel } : {},
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 = spawn2("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"] });
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 run = promisify(execFile);
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 run(step.argv[0], step.argv.slice(1), { timeout: 3e4 });
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 run("ps", ["-axo", "pid=,args="], { maxBuffer: 16 * 1024 * 1024 });
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((run2) => [
11510
- run2.id,
11511
- run2.issue_ref ? `${run2.issue_ref.project_name}/${run2.issue_ref.number}` : run2.issue_id,
11512
- run2.runner_name,
11513
- run2.tier,
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(run2.created_at)
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 run2 of items)
11527
- if (run2.usage_dimensions && run2.usage_accounting)
11814
+ for (const run3 of items)
11815
+ if (run3.usage_dimensions && run3.usage_accounting)
11528
11816
  for (const line of usageEvidenceLines(
11529
- run2.id,
11530
- run2.usage_dimensions,
11531
- run2.usage_accounting
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 run2 = await api.getRun(id2);
11543
- if (opts.json) return printJson(run2);
11830
+ const run3 = await api.getRun(id2);
11831
+ if (opts.json) return printJson(run3);
11544
11832
  console.log(
11545
- `${run2.id} ${run2.status} on ${run2.runner_name}${run2.resumed_from_run_id ? ` \xB7 resumed run ${run2.resumed_from_run_id}` : ""}`
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
- `states: ${run2.state_at_start_name ?? run2.state_id_at_start} \u2192 ${run2.state_at_end_name ?? run2.state_id_at_end ?? "\u2026"}`
11844
+ `effort: requested ${run3.requested_effort ?? "(none)"} resolved ${run3.resolved_effort ?? "(provider default)"} source ${sourceLabel2}`
11551
11845
  );
11552
11846
  console.log(
11553
- `created: ${timestamp(run2.created_at)} started: ${run2.started_at ? timestamp(run2.started_at) : "\u2014"} ended: ${run2.ended_at ? timestamp(run2.ended_at) : "\u2014"} duration: ${runDurationLabel(run2)}`
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
- if (run2.usage) {
11556
- const u = run2.usage;
11557
- const costLabel = runCostLabel(run2);
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(run2)}${u.cost_source === void 0 ? " \xB7 source unavailable" : ""}`
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 (run2.provider_session_id) console.log(`provider session: ${run2.provider_session_id}`);
11600
- if (run2.provider_url) console.log(`provider console: ${run2.provider_url}`);
11601
- if (run2.error) console.log(`error: ${run2.error}`);
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 (run2.log_bytes_dropped > 0) {
11918
+ if (run3.log_bytes_dropped > 0) {
11619
11919
  console.log(
11620
- `[${Math.round(run2.log_bytes_dropped / 1024)} KB truncated from the head \u2014 ` + (run2.log_expired ? "past its retention window; only this tail remains]" : `run \`tines runs show ${run2.id} --logs --full\` for the complete ${Math.round(run2.log_full_bytes / 1024)} KB log]`)
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(run2.log || "(no log output captured)");
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 run2 = await api.cancelRun(id2);
11632
- if (opts.json) return printJson(run2);
11931
+ const run3 = await api.cancelRun(id2);
11932
+ if (opts.json) return printJson(run3);
11633
11933
  console.log(
11634
- `canceled ${run2.id}${run2.issue_ref ? ` on ${issueRef(run2.issue_ref)}` : ""} (was on ${run2.runner_name})`
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 digest = `sha256:${createHash("sha256").update(canonicalizeLibraryValue({ plan: unsigned, resolved: plan.resolved })).digest("hex")}`;
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 !== digest || plan.plan_digest !== digest)
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 run2 = item;
13229
+ const run3 = item;
12926
13230
  return [
12927
- run2.id,
12928
- run2.issue_id,
12929
- page.population === "pending" ? "Pending" : money(run2.usage_accounting?.cost ?? null),
12930
- new Date(run2.ended_at ?? run2.created_at).toISOString()
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
  ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tines",
3
- "version": "0.0.214",
3
+ "version": "0.0.215",
4
4
  "description": "CLI for Tines, an orchestration layer for AI agents",
5
5
  "repository": {
6
6
  "type": "git",