cruo-agent 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -110,7 +110,7 @@ given up on work nobody abandoned.
110
110
  | `--worktree` | a checkout per card |
111
111
  | `--allow <tools>` | what the harness may use |
112
112
  | `--push` | publish the branch after a run that commits |
113
- | `--harness-timeout <seconds>` | kill a run that wedges (default 1800) |
113
+ | `--harness-timeout <seconds>` | kill a run that wedges (default 3000 — 50 minutes; keep it under an hour, which is how long a run's board session lasts) |
114
114
  | `--max-attempts <n>` | give up on a card after n unproductive runs (default 3) |
115
115
 
116
116
  The full list, and what each is for: <https://cruo.space/docs#agents>
package/dist/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.13
1
+ 0.1.15
package/dist/cli.js CHANGED
@@ -46535,8 +46535,14 @@ function refusalIn(stdout) {
46535
46535
  }
46536
46536
  return null;
46537
46537
  }
46538
+ function costlessInstant(run) {
46539
+ if (!run.usage || run.durationMs >= 1e4) return false;
46540
+ const tokens = (run.usage.inputTokens ?? 0) + (run.usage.outputTokens ?? 0);
46541
+ const cost = run.usage.costUsd ?? 0;
46542
+ return tokens === 0 && cost === 0;
46543
+ }
46538
46544
  function neverRan(run) {
46539
- return run.refusal !== null || run.stdoutBytes === 0;
46545
+ return run.refusal !== null || run.stdoutBytes === 0 || costlessInstant(run);
46540
46546
  }
46541
46547
  function usageIn(text) {
46542
46548
  const trimmed = text.trimEnd();
@@ -46641,13 +46647,25 @@ var init_harness_signal = __esm({
46641
46647
  // literal string in the 2.x binary. That one word cost 8,239 runs (CRA-89):
46642
46648
  // the refusal went unrecognised, so `neverRan` was false, so the backoff
46643
46649
  // never engaged and every card was charged for an outage.
46650
+ //
46651
+ // The NOUN is a family, not a list to extend one incident at a time. This
46652
+ // pattern has now been widened three times — `usage` (CRA-75), `reached
46653
+ // your` (CRA-89), and `session` (CRA-125, after "You've hit your session
46654
+ // limit · resets 2:30pm" set two cards aside inside sixty seconds). Each
46655
+ // miss costs the same way: the refusal is unrecognised, `neverRan` is false,
46656
+ // and an account outage is charged to whatever cards the agent was holding.
46657
+ // The word `limit` is still required, so a model writing about limits in a
46658
+ // card is not matched.
46644
46659
  [
46645
- /(hit|reached) your (monthly |weekly |daily )?(spend|usage) limit/i,
46660
+ /(hit|reached) your (monthly |weekly |daily |hourly )?(spend|usage|session|message|rate) limit/i,
46646
46661
  "the account's usage limit is reached"
46647
46662
  ],
46648
46663
  // The passive voice of the same thing, which is what the harness prints when
46649
46664
  // it is reporting rather than addressing you.
46650
- [/(usage|spend|usage credit) limit reached/i, "the account's usage limit is reached"],
46665
+ [
46666
+ /(usage|spend|usage credit|session|message|rate) limit reached/i,
46667
+ "the account's usage limit is reached"
46668
+ ],
46651
46669
  // `is` optional: the binary carries BOTH "credit balance is too low" and
46652
46670
  // "credit balance too low", and the pattern only knew the longer one.
46653
46671
  [
@@ -46711,10 +46729,21 @@ var init_pacing = __esm({
46711
46729
  function blocksAgentPickup(state) {
46712
46730
  return state.requires_human === true;
46713
46731
  }
46732
+ function byPriority(a, b) {
46733
+ return (PRIORITY_RANK[a.issue.priority] ?? 9) - (PRIORITY_RANK[b.issue.priority] ?? 9);
46734
+ }
46735
+ var PRIORITY_RANK;
46714
46736
  var init_queries = __esm({
46715
46737
  "src/queries.ts"() {
46716
46738
  "use strict";
46717
46739
  init_dist();
46740
+ PRIORITY_RANK = {
46741
+ urgent: 0,
46742
+ high: 1,
46743
+ medium: 2,
46744
+ low: 3,
46745
+ none: 4
46746
+ };
46718
46747
  }
46719
46748
  });
46720
46749
 
@@ -46929,7 +46958,7 @@ async function pollAssigned(ctx) {
46929
46958
  notificationIds: []
46930
46959
  }
46931
46960
  ];
46932
- });
46961
+ }).sort(byPriority);
46933
46962
  }
46934
46963
  async function poll(ctx, identity) {
46935
46964
  const { data: states, error: stateErr } = await ctx.client.from("workflow_states").select("*").eq("workspace_id", ctx.workspaceId).eq("owner_function", identity.jobFunction);
@@ -46966,9 +46995,7 @@ async function poll(ctx, identity) {
46966
46995
  notificationIds: []
46967
46996
  }
46968
46997
  ];
46969
- }).sort(
46970
- (a, b) => (PRIORITY_RANK[a.issue.priority] ?? 9) - (PRIORITY_RANK[b.issue.priority] ?? 9)
46971
- );
46998
+ }).sort(byPriority);
46972
46999
  }
46973
47000
  async function pollMentions(ctx, identity) {
46974
47001
  const { data: notes, error: error51 } = await ctx.client.schema("public").from("notifications").select("id, issue_id").eq("user_id", ctx.userId).eq("kind", "mention").is("read_at", null).not("issue_id", "is", null).order("created_at", { ascending: true });
@@ -47011,9 +47038,7 @@ async function pollMentions(ctx, identity) {
47011
47038
  notificationIds: byIssue.get(issue2.id) ?? []
47012
47039
  }
47013
47040
  ];
47014
- }).sort(
47015
- (a, b) => (PRIORITY_RANK[a.issue.priority] ?? 9) - (PRIORITY_RANK[b.issue.priority] ?? 9)
47016
- );
47041
+ }).sort(byPriority);
47017
47042
  }
47018
47043
  async function claim(ctx, hit) {
47019
47044
  const ttlMs = options.harnessTimeoutMs + 3e4;
@@ -47885,7 +47910,7 @@ to catch: a second supervisor nothing could see or stop.
47885
47910
  if (stopping) return;
47886
47911
  }
47887
47912
  }
47888
- var argv, flag, opt, num2, ms, readOptions, options, log, worktreeConfig, lastRefusal, PRIORITY_RANK, CONFIG_DIR_PREFIX, CRUO_OWNED_ENV, HEAD_STORED, lastHolding, warnedAboutSpendTable, stopping, paused, stopRequestedAt, currentRun, pendingWait;
47913
+ var argv, flag, opt, num2, ms, readOptions, options, log, worktreeConfig, lastRefusal, CONFIG_DIR_PREFIX, CRUO_OWNED_ENV, HEAD_STORED, lastHolding, warnedAboutSpendTable, stopping, paused, stopRequestedAt, currentRun, pendingWait;
47889
47914
  var init_supervisor = __esm({
47890
47915
  "src/supervisor.ts"() {
47891
47916
  "use strict";
@@ -47952,7 +47977,11 @@ var init_supervisor = __esm({
47952
47977
  * test file — was killed at it twice, having written real work both times
47953
47978
  * and committed neither. Err long: the cheap failure is the slow one.
47954
47979
  */
47955
- harnessTimeoutMs: ms("harness-timeout", 1800),
47980
+ // 50 minutes since CRA-122: roughly double the longest real run (26.3 min),
47981
+ // and deliberately short of an hour — the run's own board session lasts
47982
+ // exactly 60 minutes (see `writeMcpConfig`), so a longer limit lets a run
47983
+ // lose the board in the minutes it hands the card on.
47984
+ harnessTimeoutMs: ms("harness-timeout", 3e3),
47956
47985
  /**
47957
47986
  * Give up on an issue after this many unproductive runs. Persisted in
47958
47987
  * `pm.issue_attempts` since CRA-7 — it was in-memory, which meant a restart
@@ -48052,13 +48081,6 @@ cruo-supervisor: ${error51.message}
48052
48081
  log = (...parts) => console.log(`[${(/* @__PURE__ */ new Date()).toLocaleTimeString("en-GB", { hour12: false })}]`, ...parts);
48053
48082
  worktreeConfig = null;
48054
48083
  lastRefusal = null;
48055
- PRIORITY_RANK = {
48056
- urgent: 0,
48057
- high: 1,
48058
- medium: 2,
48059
- low: 3,
48060
- none: 4
48061
- };
48062
48084
  CONFIG_DIR_PREFIX = "cruo-sup-";
48063
48085
  CRUO_OWNED_ENV = [
48064
48086
  "SUPABASE_URL",
@@ -48497,8 +48519,9 @@ ${name} started (pid ${child.pid}).
48497
48519
  check cruo ps
48498
48520
  stop cruo stop ${name}
48499
48521
 
48500
- It survives this terminal closing. It does not survive the machine
48501
- sleeping or shutting down \u2014 for that, see the launchd notes in
48522
+ It survives this terminal closing, and the machine sleeping \u2014 it pauses
48523
+ and carries on when you wake it. It does not survive a restart or a
48524
+ shutdown; for that, see "Surviving a reboot" at
48502
48525
  https://cruo.space/docs#agents.
48503
48526
  `
48504
48527
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cruo-agent",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Run a Cruo agent: it watches your board, picks up the cards you assign it, and works them.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://cruo.space/docs#agents",