cruo-agent 0.1.7 → 0.1.9

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 (3) hide show
  1. package/dist/VERSION +1 -1
  2. package/dist/cli.js +231 -21
  3. package/package.json +1 -1
package/dist/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.7
1
+ 0.1.9
package/dist/cli.js CHANGED
@@ -45913,6 +45913,36 @@ function isKnownCommandWord(first) {
45913
45913
  function nearestCommands(first) {
45914
45914
  return CRUO_COMMANDS.filter((k) => k[0] === first[0]).slice(0, 3);
45915
45915
  }
45916
+ function editDistance(a, b) {
45917
+ const row = Array.from({ length: b.length + 1 }, (_, j) => j);
45918
+ for (let i = 1; i <= a.length; i++) {
45919
+ let diagonal = row[0];
45920
+ row[0] = i;
45921
+ for (let j = 1; j <= b.length; j++) {
45922
+ const above = row[j];
45923
+ row[j] = Math.min(row[j] + 1, row[j - 1] + 1, diagonal + (a[i - 1] === b[j - 1] ? 0 : 1));
45924
+ diagonal = above;
45925
+ }
45926
+ }
45927
+ return row[b.length];
45928
+ }
45929
+ function unknownFlags(argv2, valued = [...SUPERVISOR_VALUED, ...CLI_VALUED], switches = SUPERVISOR_SWITCHES) {
45930
+ const known = [...valued, ...switches];
45931
+ const found = [];
45932
+ for (let i = 0; i < argv2.length; i++) {
45933
+ const arg = argv2[i];
45934
+ if (!arg.startsWith("-")) continue;
45935
+ const name = arg.replace(/^-+/, "");
45936
+ if (valued.includes(name)) {
45937
+ i++;
45938
+ continue;
45939
+ }
45940
+ if (switches.includes(name)) continue;
45941
+ const ranked = known.map((k) => ({ k, d: editDistance(name.split("=")[0], k) })).sort((x, y) => x.d - y.d)[0];
45942
+ found.push({ flag: arg, nearest: ranked && ranked.d <= 2 ? `--${ranked.k}` : null });
45943
+ }
45944
+ return found;
45945
+ }
45916
45946
  function numericIn(argv2, name, spec = {}) {
45917
45947
  const i = argv2.indexOf(`--${name}`);
45918
45948
  if (i < 0) return spec.fallback;
@@ -45947,7 +45977,7 @@ function requiredNumericIn(argv2, name, fallback, spec = {}) {
45947
45977
  function secondsIn(argv2, name, fallbackSeconds) {
45948
45978
  return requiredNumericIn(argv2, name, fallbackSeconds, { unit: "seconds" }) * 1e3;
45949
45979
  }
45950
- var CRUO_COMMANDS, OptionError, flagIn, optIn;
45980
+ var CRUO_COMMANDS, SUPERVISOR_SWITCHES, SUPERVISOR_VALUED, CLI_VALUED, OptionError, flagIn, optIn;
45951
45981
  var init_options = __esm({
45952
45982
  "src/options.ts"() {
45953
45983
  "use strict";
@@ -45963,8 +45993,32 @@ var init_options = __esm({
45963
45993
  "stop",
45964
45994
  "pause",
45965
45995
  "resume",
45966
- "logs"
45996
+ "logs",
45997
+ "run",
45998
+ "version",
45999
+ "?"
45967
46000
  ];
46001
+ SUPERVISOR_SWITCHES = ["once", "dry-run", "worktree", "keep-failed", "push", "usage"];
46002
+ SUPERVISOR_VALUED = [
46003
+ "allow",
46004
+ "base",
46005
+ "cwd",
46006
+ "function",
46007
+ "harness",
46008
+ "harness-timeout",
46009
+ "interval",
46010
+ "limit",
46011
+ "max-attempts",
46012
+ "max-interval",
46013
+ "model",
46014
+ "prepare",
46015
+ "prepare-timeout",
46016
+ "project",
46017
+ "push-remote",
46018
+ "repo",
46019
+ "worktree-root"
46020
+ ];
46021
+ CLI_VALUED = ["as", "token"];
45968
46022
  OptionError = class extends Error {
45969
46023
  constructor(message) {
45970
46024
  super(message);
@@ -46228,7 +46282,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
46228
46282
  cacheRead: 0,
46229
46283
  cacheWrite: 0,
46230
46284
  cost: 0,
46231
- measured: 0
46285
+ measured: 0,
46286
+ opening: 0,
46287
+ openingMeasured: 0,
46288
+ sysChars: 0,
46289
+ userChars: 0,
46290
+ charsMeasured: 0
46232
46291
  });
46233
46292
  const fold = (a, r) => {
46234
46293
  a.runs += 1;
@@ -46242,6 +46301,16 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
46242
46301
  a.cacheWrite += n(r.cache_write_tokens);
46243
46302
  a.cost += n(r.cost_usd);
46244
46303
  if (r.input_tokens !== null || r.cost_usd !== null) a.measured += 1;
46304
+ const openingKnown = r.opening_context_input_tokens !== null || r.opening_context_cache_read_tokens !== null || r.opening_context_cache_write_tokens !== null;
46305
+ if (openingKnown) {
46306
+ a.opening += n(r.opening_context_input_tokens) + n(r.opening_context_cache_read_tokens) + n(r.opening_context_cache_write_tokens);
46307
+ a.openingMeasured += 1;
46308
+ }
46309
+ if (r.system_prompt_chars !== null || r.user_prompt_chars !== null) {
46310
+ a.sysChars += n(r.system_prompt_chars);
46311
+ a.userChars += n(r.user_prompt_chars);
46312
+ a.charsMeasured += 1;
46313
+ }
46245
46314
  };
46246
46315
  const byAgent = /* @__PURE__ */ new Map();
46247
46316
  const total = blank();
@@ -46253,11 +46322,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
46253
46322
  const w = Math.max(12, ...[...byAgent.keys()].map((id) => nameOf(id).length));
46254
46323
  console.log(
46255
46324
  `
46256
- ${pad("agent", w)} ${rpad("runs", 5)} ${rpad("useful", 7)} ${rpad("dead", 5)} ${rpad("time", 7)} ${rpad("in", 8)} ${rpad("out", 8)} ${rpad("cost", 9)}`
46325
+ ${pad("agent", w)} ${rpad("runs", 5)} ${rpad("useful", 7)} ${rpad("dead", 5)} ${rpad("time", 7)} ${rpad("in", 8)} ${rpad("out", 8)} ${rpad("opening", 8)} ${rpad("cost", 9)}`
46257
46326
  );
46258
46327
  for (const [id, a] of [...byAgent].sort((x, y) => y[1].runs - x[1].runs)) {
46328
+ const openingAvg = a.openingMeasured > 0 ? compact(Math.round(a.opening / a.openingMeasured)) : "\u2014";
46259
46329
  console.log(
46260
- ` ${pad(nameOf(id), w)} ${rpad(String(a.runs), 5)} ${rpad(String(a.productive), 7)} ${rpad(String(a.neverRan), 5)} ${rpad(duration3(a.ms), 7)} ${rpad(compact(a.input + a.cacheRead), 8)} ${rpad(compact(a.output), 8)} ${rpad(a.cost > 0 ? `$${a.cost.toFixed(2)}` : "\u2014", 9)}`
46330
+ ` ${pad(nameOf(id), w)} ${rpad(String(a.runs), 5)} ${rpad(String(a.productive), 7)} ${rpad(String(a.neverRan), 5)} ${rpad(duration3(a.ms), 7)} ${rpad(compact(a.input + a.cacheRead), 8)} ${rpad(compact(a.output), 8)} ${rpad(openingAvg, 8)} ${rpad(a.cost > 0 ? `$${a.cost.toFixed(2)}` : "\u2014", 9)}`
46261
46331
  );
46262
46332
  }
46263
46333
  if (!opts.issue) {
@@ -46290,8 +46360,12 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
46290
46360
  console.log(`
46291
46361
  run by run`);
46292
46362
  for (const r of rows) {
46363
+ const openingKnown = r.opening_context_input_tokens !== null || r.opening_context_cache_read_tokens !== null || r.opening_context_cache_write_tokens !== null;
46364
+ const opening = openingKnown ? compact(
46365
+ n(r.opening_context_input_tokens) + n(r.opening_context_cache_read_tokens) + n(r.opening_context_cache_write_tokens)
46366
+ ) : "\u2014";
46293
46367
  console.log(
46294
- ` ${r.started_at.slice(0, 16).replace("T", " ")} ${pad(r.outcome, 13)} ${rpad(duration3(r.duration_ms), 6)} ${rpad(compact(n(r.output_tokens)), 7)} out ${nameOf(r.agent_id)}`
46368
+ ` ${r.started_at.slice(0, 16).replace("T", " ")} ${pad(r.outcome, 13)} ${rpad(duration3(r.duration_ms), 6)} ${rpad(compact(n(r.output_tokens)), 7)} out ${rpad(opening, 7)} opening ${nameOf(r.agent_id)}`
46295
46369
  );
46296
46370
  }
46297
46371
  }
@@ -46318,6 +46392,35 @@ predate cost recording (\`CRA-89\`, 2026-08-29).
46318
46392
  } else {
46319
46393
  console.log("");
46320
46394
  }
46395
+ if (total.openingMeasured === 0) {
46396
+ console.log(
46397
+ ` No opening-context figure: needs --usage AND a harness that reports
46398
+ per-turn usage on its own events, which is stricter than reporting a
46399
+ final total \u2014 some harnesses do the second and not the first.
46400
+ `
46401
+ );
46402
+ } else {
46403
+ const avg = Math.round(total.opening / total.openingMeasured);
46404
+ console.log(
46405
+ ` opening context \u2014 what was loaded before any work happened, not a slice of "in":
46406
+ avg ${compact(avg)} tokens over ${total.openingMeasured} of ${total.runs} run(s) that reported a first turn.`
46407
+ );
46408
+ if (total.charsMeasured > 0) {
46409
+ const sysAvg = Math.round(total.sysChars / total.charsMeasured);
46410
+ const userAvg = Math.round(total.userChars / total.charsMeasured);
46411
+ console.log(
46412
+ ` Known by source: the system prompt averaged ${sysAvg} chars, the user prompt
46413
+ ${userAvg} \u2014 CHARACTERS, not tokens, because no tokenizer runs here, so this is
46414
+ not subtracted from the ${compact(avg)}-token figure above. The rest of the
46415
+ opening context \u2014 CLAUDE.md, the docs it points at, the card and its comments,
46416
+ and the MCP tool schemas \u2014 is read by the harness itself, off a filesystem and
46417
+ a tool list the supervisor cannot see, and is NOT broken down any further.
46418
+ `
46419
+ );
46420
+ } else {
46421
+ console.log("");
46422
+ }
46423
+ }
46321
46424
  }
46322
46425
  var n, pad, rpad, duration3;
46323
46426
  var init_usage = __esm({
@@ -46371,6 +46474,29 @@ function usageIn(text) {
46371
46474
  const measured = Object.values(out).some((v) => v !== void 0);
46372
46475
  return measured ? out : null;
46373
46476
  }
46477
+ function turnUsageIn(line) {
46478
+ let event;
46479
+ try {
46480
+ event = JSON.parse(line);
46481
+ } catch {
46482
+ return null;
46483
+ }
46484
+ if (typeof event !== "object" || event === null) return null;
46485
+ const e = event;
46486
+ if (e.type !== "assistant") return null;
46487
+ const message = e.message;
46488
+ const usage = message?.usage;
46489
+ if (!usage || typeof usage !== "object") return null;
46490
+ const out = {
46491
+ model: typeof message?.model === "string" ? message.model : void 0,
46492
+ inputTokens: num(usage.input_tokens) ?? num(usage.inputTokens),
46493
+ outputTokens: num(usage.output_tokens) ?? num(usage.outputTokens),
46494
+ cacheReadTokens: num(usage.cache_read_input_tokens) ?? num(usage.cacheReadInputTokens),
46495
+ cacheWriteTokens: num(usage.cache_creation_input_tokens) ?? num(usage.cacheCreationInputTokens)
46496
+ };
46497
+ const measured = Object.values(out).some((v) => v !== void 0);
46498
+ return measured ? out : null;
46499
+ }
46374
46500
  function renderEvent(line) {
46375
46501
  let event;
46376
46502
  try {
@@ -46488,6 +46614,17 @@ var init_pacing = __esm({
46488
46614
  }
46489
46615
  });
46490
46616
 
46617
+ // src/queries.ts
46618
+ function blocksAgentPickup(state) {
46619
+ return state.requires_human === true;
46620
+ }
46621
+ var init_queries = __esm({
46622
+ "src/queries.ts"() {
46623
+ "use strict";
46624
+ init_dist();
46625
+ }
46626
+ });
46627
+
46491
46628
  // src/worktree.ts
46492
46629
  import { execFile as execFile2 } from "node:child_process";
46493
46630
  import { mkdir as mkdir2, readdir as readdir2, rm as rm2, stat } from "node:fs/promises";
@@ -46680,6 +46817,12 @@ async function pollAssigned(ctx) {
46680
46817
  const project = byProject.get(issue2.project_id);
46681
46818
  if (!state || !project) return [];
46682
46819
  if (options.project && project.key !== options.project) return [];
46820
+ if (blocksAgentPickup(state)) {
46821
+ log(
46822
+ ` ${project.key}-${issue2.number} is in ${state.name}, which requires a human \u2014 not starting`
46823
+ );
46824
+ return [];
46825
+ }
46683
46826
  if (state.category === "completed" || state.category === "canceled") return [];
46684
46827
  const said = lastSaid.get(issue2.id);
46685
46828
  if (said && issue2.updated_at && said > issue2.updated_at) return [];
@@ -46714,6 +46857,12 @@ async function poll(ctx, identity) {
46714
46857
  const state = byState.get(issue2.status_id);
46715
46858
  if (!project || !state) return [];
46716
46859
  if (options.project && project.key !== options.project) return [];
46860
+ if (blocksAgentPickup(state)) {
46861
+ log(
46862
+ ` ${project.key}-${issue2.number} is in ${state.name}, which requires a human \u2014 not starting`
46863
+ );
46864
+ return [];
46865
+ }
46717
46866
  return [
46718
46867
  {
46719
46868
  ref: `${project.key}-${issue2.number}`,
@@ -47005,9 +47154,11 @@ async function invokeHarness(ctx, identity, hit, worktree) {
47005
47154
  options.allow.split(",").map((t) => t.trim()).filter((t) => t !== "" && !t.startsWith("mcp__")).map((t) => t.replace(/\(.*$/, ""))
47006
47155
  )
47007
47156
  ].join(",");
47157
+ const userPromptText = userPrompt(hit);
47158
+ const systemPromptText = systemPrompt(ctx, identity, worktree);
47008
47159
  const args = [
47009
47160
  "-p",
47010
- userPrompt(hit),
47161
+ userPromptText,
47011
47162
  "--mcp-config",
47012
47163
  mcpConfig,
47013
47164
  // Both, always. See the note above: without `--restricted` the harness
@@ -47023,7 +47174,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
47023
47174
  "--allowedTools",
47024
47175
  options.allow,
47025
47176
  "--system-prompt",
47026
- systemPrompt(ctx, identity, worktree),
47177
+ systemPromptText,
47027
47178
  ...options.model ? ["--model", options.model] : [],
47028
47179
  // `--verbose` is not optional alongside stream-json: without it the harness
47029
47180
  // emits only the final result and the live view is a blank terminal for the
@@ -47045,6 +47196,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
47045
47196
  let tail = "";
47046
47197
  let head2 = "";
47047
47198
  let pending = "";
47199
+ let openingContext = null;
47048
47200
  const addHead = (text) => {
47049
47201
  if (head2.length < 2048) head2 += text.slice(0, 2048 - head2.length);
47050
47202
  };
@@ -47063,6 +47215,7 @@ async function invokeHarness(ctx, identity, hit, worktree) {
47063
47215
  for (const line of lines) {
47064
47216
  if (line.trim() === "") continue;
47065
47217
  tail = line;
47218
+ if (openingContext === null) openingContext = turnUsageIn(line);
47066
47219
  const rendered = renderEvent(line);
47067
47220
  if (rendered.text) addHead(rendered.text + "\n");
47068
47221
  if (rendered.show) process.stdout.write(rendered.show + "\n");
@@ -47086,13 +47239,17 @@ async function invokeHarness(ctx, identity, hit, worktree) {
47086
47239
  durationMs: Date.now() - startedAtMs,
47087
47240
  usage: null,
47088
47241
  killed,
47089
- stdoutHead: headFor(head2)
47242
+ stdoutHead: headFor(head2),
47243
+ openingContext: null,
47244
+ systemPromptChars: systemPromptText.length,
47245
+ userPromptChars: userPromptText.length
47090
47246
  });
47091
47247
  });
47092
47248
  child.on("close", (code) => {
47093
47249
  clearTimeout(timer);
47094
47250
  if (streaming && pending.trim() !== "") {
47095
47251
  tail = pending;
47252
+ if (openingContext === null) openingContext = turnUsageIn(pending);
47096
47253
  const rendered = renderEvent(pending);
47097
47254
  if (rendered.text) addHead(rendered.text + "\n");
47098
47255
  if (rendered.show) process.stdout.write(rendered.show + "\n");
@@ -47105,7 +47262,10 @@ async function invokeHarness(ctx, identity, hit, worktree) {
47105
47262
  durationMs: Date.now() - startedAtMs,
47106
47263
  usage: usageIn(tail),
47107
47264
  killed,
47108
- stdoutHead: headFor(head2)
47265
+ stdoutHead: headFor(head2),
47266
+ openingContext,
47267
+ systemPromptChars: systemPromptText.length,
47268
+ userPromptChars: userPromptText.length
47109
47269
  });
47110
47270
  });
47111
47271
  });
@@ -47207,6 +47367,16 @@ function announce(status) {
47207
47367
  }
47208
47368
  })();
47209
47369
  }
47370
+ function beatWhileBusy(ctx, deadTicks) {
47371
+ const timer = setInterval(() => {
47372
+ void beat(ctx, { holding: lastHolding, deadTicks, intervalMs: options.intervalMs }).catch(
47373
+ () => {
47374
+ }
47375
+ );
47376
+ }, options.intervalMs);
47377
+ timer.unref?.();
47378
+ return () => clearInterval(timer);
47379
+ }
47210
47380
  async function recordRun(ctx, hit, run, outcome) {
47211
47381
  const { error: error51 } = await ctx.client.from("harness_runs").insert({
47212
47382
  agent_id: ctx.userId,
@@ -47223,7 +47393,12 @@ async function recordRun(ctx, hit, run, outcome) {
47223
47393
  output_tokens: run.usage?.outputTokens ?? null,
47224
47394
  cache_read_tokens: run.usage?.cacheReadTokens ?? null,
47225
47395
  cache_write_tokens: run.usage?.cacheWriteTokens ?? null,
47226
- cost_usd: run.usage?.costUsd ?? null
47396
+ cost_usd: run.usage?.costUsd ?? null,
47397
+ opening_context_input_tokens: run.openingContext?.inputTokens ?? null,
47398
+ opening_context_cache_read_tokens: run.openingContext?.cacheReadTokens ?? null,
47399
+ opening_context_cache_write_tokens: run.openingContext?.cacheWriteTokens ?? null,
47400
+ system_prompt_chars: run.systemPromptChars,
47401
+ user_prompt_chars: run.userPromptChars
47227
47402
  });
47228
47403
  if (error51 && !warnedAboutSpendTable) {
47229
47404
  warnedAboutSpendTable = true;
@@ -47314,6 +47489,7 @@ async function tick(ctx, identity, deadTicks, allowance) {
47314
47489
  let run;
47315
47490
  let committed = 0;
47316
47491
  let salvaged = null;
47492
+ const stopBusyBeat = beatWhileBusy(ctx, deadTicks);
47317
47493
  try {
47318
47494
  run = await invokeHarness(ctx, identity, hit, worktree);
47319
47495
  if (worktree) committed = await worktree.commits();
@@ -47336,6 +47512,7 @@ async function tick(ctx, identity, deadTicks, allowance) {
47336
47512
  );
47337
47513
  }
47338
47514
  } finally {
47515
+ stopBusyBeat();
47339
47516
  await release(ctx, hit);
47340
47517
  }
47341
47518
  const code = run.code;
@@ -47571,6 +47748,7 @@ var init_supervisor = __esm({
47571
47748
  init_harness_signal();
47572
47749
  init_process();
47573
47750
  init_pacing();
47751
+ init_queries();
47574
47752
  init_worktree();
47575
47753
  argv = process.argv.slice(2);
47576
47754
  flag = (name) => flagIn(argv, name);
@@ -47705,6 +47883,12 @@ var init_supervisor = __esm({
47705
47883
  });
47706
47884
  options = (() => {
47707
47885
  try {
47886
+ const [unknown2] = unknownFlags(argv, SUPERVISOR_VALUED);
47887
+ if (unknown2) {
47888
+ throw new OptionError(
47889
+ `${unknown2.flag} is not a flag the supervisor reads` + (unknown2.nearest ? ` \u2014 did you mean ${unknown2.nearest}?` : ".") + ` Nothing was started.`
47890
+ );
47891
+ }
47708
47892
  return readOptions();
47709
47893
  } catch (error51) {
47710
47894
  if (error51 instanceof OptionError) {
@@ -47790,8 +47974,10 @@ var USAGE = `cruo \u2014 run a Cruo agent
47790
47974
  cruo agents list what is remembered (never the tokens)
47791
47975
  cruo usage [--days 7] what the agents have been spending
47792
47976
  cruo logout [name] forget one, or --all
47793
- cruo [options] run the agent's supervisor, in this terminal
47794
- cruo --as <name> \u2026 run a particular one
47977
+ cruo run [options] run the agent's supervisor, in this terminal
47978
+ cruo --as <name> \u2026 run a particular one (flags alone also run it)
47979
+ cruo version which build this is
47980
+ cruo help this list (also: cruo, cruo -h, cruo ?)
47795
47981
 
47796
47982
  Running one in the background
47797
47983
  cruo start [options] same, detached \u2014 survives closing the terminal
@@ -47903,7 +48089,7 @@ ${CONFIG_PATH} is readable only by you.
47903
48089
 
47904
48090
  ` + (config3.default === name ? `Run \`cruo --dry-run\` to see what it would pick up.
47905
48091
  ` : `Run \`cruo --as ${name} --dry-run\` to see what it would pick up.
47906
- A bare \`cruo\` still runs \`${config3.default}\`.
48092
+ \`cruo run\` still runs \`${config3.default}\`.
47907
48093
  `)
47908
48094
  );
47909
48095
  }
@@ -47954,7 +48140,7 @@ Nothing stored for \`${which}\`. Stored: ${names.join(", ") || "(none)"}
47954
48140
  await writeConfig(config3);
47955
48141
  console.log(
47956
48142
  `
47957
- Forgot the token for \`${which}\`.` + (config3.default ? ` A bare \`cruo\` now runs \`${config3.default}\`.
48143
+ Forgot the token for \`${which}\`.` + (config3.default ? ` \`cruo run\` now runs \`${config3.default}\`.
47958
48144
  ` : ` Nothing is stored now.
47959
48145
  `)
47960
48146
  );
@@ -47976,7 +48162,7 @@ No tokens stored. \`cruo login <token>\` to add one.
47976
48162
  console.log(` ${mark} ${name}${who}`);
47977
48163
  }
47978
48164
  console.log(`
47979
- * is what a bare \`cruo\` runs. Use \`--as <name>\` for another.
48165
+ * is what \`cruo run\` runs. Use \`--as <name>\` for another.
47980
48166
  `);
47981
48167
  }
47982
48168
  async function targetName(explicit, asName) {
@@ -48051,13 +48237,14 @@ Either \`cruo start ${stored[0]}\`, or add this one:
48051
48237
  );
48052
48238
  process.exit(2);
48053
48239
  }
48240
+ refuseUnknownFlags(argv2.slice(positional ? 2 : 1).filter((a) => a !== "--all"));
48054
48241
  await mkdir4(logDir(), { recursive: true });
48055
48242
  const logPath = join4(logDir(), `${name}.log`);
48056
48243
  const handle = await open(logPath, "a");
48057
48244
  const rest = argv2.slice(positional ? 2 : 1).filter((a) => a !== "--all");
48058
48245
  const chosen = storedKey ?? positional ?? asName;
48059
48246
  const withoutAs = rest.filter((a, i, all) => a !== "--as" && all[i - 1] !== "--as");
48060
- const forwarded = chosen ? ["--as", chosen, ...withoutAs] : withoutAs;
48247
+ const forwarded = ["run", ...chosen ? ["--as", chosen] : [], ...withoutAs];
48061
48248
  const child = spawn2(process.execPath, [process.argv[1], ...forwarded], {
48062
48249
  detached: true,
48063
48250
  stdio: ["ignore", handle.fd, handle.fd],
@@ -48161,6 +48348,26 @@ A detached run writes one; a foreground run prints to its terminal.
48161
48348
  });
48162
48349
  await new Promise((resolve2) => child.on("close", resolve2));
48163
48350
  }
48351
+ async function printVersion() {
48352
+ try {
48353
+ const pkg = JSON.parse(await readFile3(new URL("../package.json", import.meta.url), "utf8"));
48354
+ console.log(`${pkg.name} ${pkg.version}`);
48355
+ } catch {
48356
+ console.log("unknown \u2014 no package.json beside this build");
48357
+ }
48358
+ }
48359
+ function refuseUnknownFlags(argv2) {
48360
+ const unknown2 = unknownFlags(argv2);
48361
+ if (unknown2.length === 0) return;
48362
+ console.error(
48363
+ `
48364
+ ${unknown2.map((u) => `\`${u.flag}\` is not a cruo flag.` + (u.nearest ? ` Did you mean ${u.nearest}?` : "")).join("\n")}
48365
+
48366
+ Nothing was started. Everything it takes: cruo help
48367
+ `
48368
+ );
48369
+ process.exit(2);
48370
+ }
48164
48371
  async function main2() {
48165
48372
  const argv2 = process.argv.slice(2);
48166
48373
  const [first] = argv2;
@@ -48197,10 +48404,11 @@ Usage: cruo login <token> [--as <name>]
48197
48404
  }
48198
48405
  if (first === "usage") {
48199
48406
  }
48200
- if (first === "help" || argv2.includes("--help") || argv2.includes("-h")) {
48407
+ if (first === void 0 || first === "help" || first === "?" || argv2.includes("--help") || argv2.includes("-h")) {
48201
48408
  console.log(USAGE);
48202
48409
  return;
48203
48410
  }
48411
+ if (first === "version" || first === "--version" || first === "-v") return printVersion();
48204
48412
  if (!isKnownCommandWord(first)) {
48205
48413
  const near = nearestCommands(first);
48206
48414
  console.error(
@@ -48209,13 +48417,15 @@ Usage: cruo login <token> [--as <name>]
48209
48417
 
48210
48418
  ` + (near.length > 0 ? `Did you mean: ${near.map((k) => `cruo ${k}`).join(" ")}
48211
48419
 
48212
- ` : "") + `To run the agent, give no command: cruo [options]
48213
- Everything it takes: cruo --help
48420
+ ` : "") + `To run the agent: cruo run [options]
48421
+ Everything it takes: cruo help
48214
48422
  `
48215
48423
  );
48216
48424
  process.exit(2);
48217
48425
  }
48218
48426
  if (first === "start") return startDetached(argv2, flagValue("--as"));
48427
+ const runArgv = first === "run" ? argv2.slice(1) : argv2;
48428
+ if (first !== "usage") refuseUnknownFlags(runArgv);
48219
48429
  const flagIndex = argv2.indexOf("--token");
48220
48430
  const fromFlag = flagIndex >= 0 ? argv2[flagIndex + 1] : void 0;
48221
48431
  if (fromFlag) {
@@ -48255,7 +48465,7 @@ Get one from Cruo \u2192 Settings \u2192 Members \u2192 Add an agent.
48255
48465
  process.env.CRUO_IDENTITY = asName ?? config3.default ?? "";
48256
48466
  }
48257
48467
  process.env.CRUO_TOKEN = token;
48258
- const passthrough = stripTokenFlag(argv2).filter((a, i, all) => a !== "--as" && all[i - 1] !== "--as");
48468
+ const passthrough = stripTokenFlag(runArgv).filter((a, i, all) => a !== "--as" && all[i - 1] !== "--as");
48259
48469
  process.argv = [process.argv[0], process.argv[1], ...passthrough];
48260
48470
  if (first === "usage") {
48261
48471
  const { reportUsage: reportUsage2 } = await Promise.resolve().then(() => (init_usage(), usage_exports));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cruo-agent",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
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",