@garuda-agent/garuda 0.17.0 → 0.18.1

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 (64) hide show
  1. package/CHANGELOG.md +243 -0
  2. package/README.md +3 -2
  3. package/SECURITY.md +1 -1
  4. package/dist/{acpCommand-7EY3NHPG.js → acpCommand-JAYNMIMP.js} +19 -16
  5. package/dist/advise-HDKJGNBL.js +195 -0
  6. package/dist/brief-RWKESOPT.js +91 -0
  7. package/dist/buildCheck-HB46NWLX.js +19 -0
  8. package/dist/buildInfo-K73FFI5S.js +8 -0
  9. package/dist/chunk-2OYTNNUJ.js +216 -0
  10. package/dist/{chunk-Z66BWTMD.js → chunk-34WBDQBL.js} +135 -78
  11. package/dist/chunk-4QRTTRVK.js +88 -0
  12. package/dist/{chunk-2DYMJMRQ.js → chunk-5UDYQ5MK.js} +405 -70
  13. package/dist/{chunk-J4346IDH.js → chunk-7KBOIPUT.js} +2 -1
  14. package/dist/chunk-CWVXOSAA.js +894 -0
  15. package/dist/{chunk-FARS4R67.js → chunk-DQSCCE77.js} +18 -1
  16. package/dist/chunk-DUYLVGPY.js +821 -0
  17. package/dist/chunk-GKU62MHQ.js +5258 -0
  18. package/dist/chunk-H7LIBGZT.js +9 -0
  19. package/dist/chunk-IKPGHM54.js +334 -0
  20. package/dist/chunk-IYGJWX65.js +9 -0
  21. package/dist/{chunk-U65DQZDB.js → chunk-JMH5W5DG.js} +2 -45
  22. package/dist/chunk-L55VUSX3.js +54 -0
  23. package/dist/{chunk-B4SJY7KT.js → chunk-LMKGSYJC.js} +77 -8
  24. package/dist/{chunk-23FXBNBB.js → chunk-MNE7HHX2.js} +2 -1
  25. package/dist/chunk-NH72AELP.js +48 -0
  26. package/dist/{chunk-735BKABA.js → chunk-NLS7GMF7.js} +12 -106
  27. package/dist/{chunk-ZAE25JM2.js → chunk-QANRZW7W.js} +8 -1
  28. package/dist/{chunk-JRVWH27M.js → chunk-QLBCM2YQ.js} +7 -3
  29. package/dist/{chunk-6XHON3Q6.js → chunk-QXTHEFKP.js} +3 -3
  30. package/dist/{chunk-TJIWD7R7.js → chunk-R7RCW4BQ.js} +10 -8
  31. package/dist/chunk-TLA2PDGM.js +156 -0
  32. package/dist/{chunk-5B5HDTUR.js → chunk-TWQ7V2L6.js} +2 -2
  33. package/dist/chunk-ULAJPMY7.js +107 -0
  34. package/dist/chunk-VISKX36R.js +306 -0
  35. package/dist/{chunk-55CFEEIN.js → chunk-WK5NE6RY.js} +2 -2
  36. package/dist/chunk-Y62J7PTD.js +90 -0
  37. package/dist/chunk-YAQ6QLKB.js +40 -0
  38. package/dist/{chunk-7TH3NHCQ.js → chunk-ZKT4P2PC.js} +2 -2
  39. package/dist/cli/index.js +289 -65
  40. package/dist/config-WV2H64TF.js +23 -0
  41. package/dist/{create-W6BV75QX.js → create-OACSGJ37.js} +5 -5
  42. package/dist/evalCommand-BLJJ4G76.js +696 -0
  43. package/dist/evalTune-W53KAD4V.js +302 -0
  44. package/dist/{export-SJ3DUP6W.js → export-E677HIQS.js} +27 -4
  45. package/dist/exportHtml-BMV73YRO.js +21 -0
  46. package/dist/{inkChat-FNUBK43U.js → inkChat-EVLYDC3K.js} +263 -47
  47. package/dist/{install-TKWN5AYH.js → install-4ST5BNRG.js} +3 -3
  48. package/dist/{jobCommand-FE6XN3YD.js → jobCommand-ILOTYOX3.js} +9 -8
  49. package/dist/{launchd-3A3ONEW5.js → launchd-QG6R5RAK.js} +4 -4
  50. package/dist/{lspCommand-ZZ6R4PA2.js → lspCommand-X4FTTONR.js} +3 -3
  51. package/dist/{manager-73MPYFTP.js → manager-L25IUXHW.js} +11 -11
  52. package/dist/{nightCommand-OODJNWDT.js → nightCommand-XPWT6CQZ.js} +9 -8
  53. package/dist/receiptView-YFDHV253.js +19 -0
  54. package/dist/{remove-42WQNVPX.js → remove-STX5UO7X.js} +3 -3
  55. package/dist/{run-ML6GSPN4.js → run-W4TK52WT.js} +6 -6
  56. package/dist/{server-VEYIJHEU.js → server-ASM73QVY.js} +3 -3
  57. package/dist/{setupCommand-GBQIVYJC.js → setupCommand-OSOMFHDQ.js} +10 -9
  58. package/dist/tour-CEVMAC5S.js +18 -0
  59. package/dist/tune-VX2WQTHS.js +52 -0
  60. package/dist/uiState-YFJQ43D7.js +16 -0
  61. package/package.json +1 -1
  62. package/dist/chunk-4JSUUDFQ.js +0 -118
  63. package/dist/chunk-BSK5T2ZG.js +0 -9
  64. package/dist/evalCommand-YVQAWUZE.js +0 -2833
package/dist/cli/index.js CHANGED
@@ -1,35 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  BUILD_PROMPT,
4
+ CONTINUE_PROMPT,
4
5
  CommandArgs,
5
6
  FOCUS_REPORTING_OFF,
6
7
  FocusTracker,
8
+ SUMMARY_PROMPT,
7
9
  commandNames,
8
10
  complete,
9
11
  describeError,
10
- formatTokens,
11
12
  planHandoff,
12
13
  reportsFocus,
13
14
  rootFiles,
14
15
  rootLister,
15
16
  runCommand,
16
17
  runTurnInTerminal,
17
- stopMessage
18
- } from "../chunk-Z66BWTMD.js";
19
- import {
20
- PlainRenderer
21
- } from "../chunk-FARS4R67.js";
18
+ stopHandoff
19
+ } from "../chunk-34WBDQBL.js";
22
20
  import {
23
21
  AutoApprover
24
22
  } from "../chunk-NXJ4XLB5.js";
25
- import {
26
- Notifier,
27
- pickChannel
28
- } from "../chunk-N4I6YS3E.js";
29
- import {
30
- SwitchApprover,
31
- TerminalApprover
32
- } from "../chunk-4JSUUDFQ.js";
33
23
  import {
34
24
  DEFAULT_MAX_TOKENS,
35
25
  Runtime,
@@ -39,9 +29,38 @@ import {
39
29
  rebuildState,
40
30
  runAgent,
41
31
  signature
42
- } from "../chunk-2DYMJMRQ.js";
32
+ } from "../chunk-5UDYQ5MK.js";
43
33
  import "../chunk-G2AX7MGS.js";
34
+ import {
35
+ Notifier,
36
+ pickChannel
37
+ } from "../chunk-N4I6YS3E.js";
38
+ import "../chunk-ULAJPMY7.js";
39
+ import {
40
+ loadCatalog
41
+ } from "../chunk-JMH5W5DG.js";
42
+ import {
43
+ NO_MODEL,
44
+ chooseModel,
45
+ keepProviderKeys,
46
+ loadModelsConfig,
47
+ providerKeySource,
48
+ resolveModel
49
+ } from "../chunk-QLBCM2YQ.js";
50
+ import "../chunk-NH72AELP.js";
51
+ import {
52
+ SwitchApprover,
53
+ TerminalApprover
54
+ } from "../chunk-VISKX36R.js";
55
+ import {
56
+ PlainRenderer
57
+ } from "../chunk-DQSCCE77.js";
58
+ import "../chunk-4QRTTRVK.js";
44
59
  import "../chunk-A2QAIRQL.js";
60
+ import {
61
+ formatTokens,
62
+ stopMessage
63
+ } from "../chunk-2OYTNNUJ.js";
45
64
  import {
46
65
  FileSessionStore,
47
66
  closeOpenToolCalls,
@@ -52,37 +71,30 @@ import {
52
71
  popPoint,
53
72
  pushPoint,
54
73
  redoPoint
55
- } from "../chunk-735BKABA.js";
56
- import {
57
- NO_MODEL,
58
- chooseModel,
59
- keepProviderKeys,
60
- loadModelsConfig,
61
- providerKeySource,
62
- resolveModel
63
- } from "../chunk-JRVWH27M.js";
74
+ } from "../chunk-NLS7GMF7.js";
75
+ import "../chunk-7KBOIPUT.js";
64
76
  import {
65
- loadCatalog
66
- } from "../chunk-U65DQZDB.js";
67
- import "../chunk-J4346IDH.js";
77
+ tourChoice
78
+ } from "../chunk-Y62J7PTD.js";
68
79
  import {
69
80
  loadSearchConfig
70
81
  } from "../chunk-B25VL4RU.js";
71
82
  import {
72
83
  BUILTIN_COMMANDS
73
- } from "../chunk-23FXBNBB.js";
84
+ } from "../chunk-MNE7HHX2.js";
85
+ import "../chunk-42DSA4EA.js";
74
86
  import "../chunk-EU7PA45O.js";
75
87
  import {
76
88
  VERSION
77
- } from "../chunk-BSK5T2ZG.js";
89
+ } from "../chunk-IYGJWX65.js";
78
90
  import "../chunk-5DEWP3YX.js";
79
- import "../chunk-ZAE25JM2.js";
80
- import "../chunk-ATW7BNIG.js";
81
91
  import "../chunk-PZS3V6P3.js";
92
+ import "../chunk-QANRZW7W.js";
93
+ import "../chunk-ATW7BNIG.js";
82
94
  import "../chunk-AOGFYUKG.js";
83
95
  import {
84
96
  JOB_DENIAL
85
- } from "../chunk-B4SJY7KT.js";
97
+ } from "../chunk-LMKGSYJC.js";
86
98
  import "../chunk-BHZ6G65V.js";
87
99
  import "../chunk-P6XWWIEK.js";
88
100
  import "../chunk-VTMD5IHD.js";
@@ -95,6 +107,7 @@ import { existsSync, readFileSync, realpathSync } from "fs";
95
107
  import { homedir as homedir2 } from "os";
96
108
  import { join } from "path";
97
109
  import { Writable } from "stream";
110
+ import { styleText } from "util";
98
111
  import { Command, Option } from "commander";
99
112
 
100
113
  // src/loop/replay.ts
@@ -297,6 +310,37 @@ function compare(a, b) {
297
310
 
298
311
  // src/cli/banner.ts
299
312
  import { homedir } from "os";
313
+ var WORDMARK_LARGE_COLUMNS = 130;
314
+ function wordmark3d(scale, face, shadow) {
315
+ const rows = WORDMARK.map((row) => row.padEnd(Math.max(...WORDMARK.map((r) => r.length))));
316
+ const lit = (x, y) => x >= 0 && y >= 0 && rows[Math.floor(y / scale)]?.[Math.floor(x / scale)] === "\u2588";
317
+ const dx = scale;
318
+ const dy = 1;
319
+ const width = (rows[0]?.length ?? 0) * scale + dx;
320
+ const height = rows.length * scale + dy;
321
+ const out = [];
322
+ for (let y = 0; y < height; y++) {
323
+ let line = "";
324
+ for (let x = 0; x < width; x++) {
325
+ line += lit(x, y) ? face(x, width) : lit(x - dx, y - dy) ? shadow(x, width) : " ";
326
+ }
327
+ out.push(line.replace(/\s+$/, ""));
328
+ }
329
+ return out;
330
+ }
331
+ function visibleWidth(line) {
332
+ return [...line.replace(/\u001b\[[0-9;]*m/g, "")].length;
333
+ }
334
+ function centerBlock(lines, width, columns) {
335
+ const pad = Math.floor((columns - width) / 2);
336
+ return pad <= 0 ? [...lines] : lines.map((line) => `${" ".repeat(pad)}${line}`);
337
+ }
338
+ function centerLines(lines, columns) {
339
+ return lines.map((line) => {
340
+ const pad = Math.floor((columns - visibleWidth(line)) / 2);
341
+ return line === "" || pad <= 0 ? line : `${" ".repeat(pad)}${line}`;
342
+ });
343
+ }
300
344
  var WORDMARK = [
301
345
  " \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 ",
302
346
  "\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588",
@@ -314,17 +358,38 @@ function colorLevel(stream = process.stdout, env = process.env) {
314
358
  function banner(info, options) {
315
359
  const c = paint(options.color);
316
360
  const lines = [];
317
- if (options.columns >= WORDMARK_MIN_COLUMNS) {
318
- const width = WORDMARK[0]?.length ?? 1;
319
- for (const row of WORDMARK) lines.push(c.gradient(row, width));
320
- lines.push("");
361
+ let markWidth;
362
+ const block = (rows, width) => options.center === true ? centerBlock(rows, width, options.columns) : rows;
363
+ if (options.screenReader === true) {
364
+ } else if (options.center === true && options.columns >= WORDMARK_MIN_COLUMNS) {
365
+ const scale = options.columns >= WORDMARK_LARGE_COLUMNS ? 2 : 1;
366
+ const mark = wordmark3d(scale, c.face, c.shadow);
367
+ const height = mark.length + 12;
368
+ const top = options.rows === void 0 ? 0 : Math.floor((options.rows - height) / 4);
369
+ for (let i = 0; i < Math.min(Math.max(0, top), 6); i++) lines.push("");
370
+ markWidth = Math.max(...mark.map(visibleWidth));
371
+ lines.push(...block(mark, markWidth), "");
372
+ } else if (options.columns >= WORDMARK_MIN_COLUMNS) {
373
+ const width = Math.max(...WORDMARK.map((row) => row.length));
374
+ lines.push(
375
+ ...block(
376
+ WORDMARK.map((row) => c.gradient(row, width)),
377
+ width
378
+ ),
379
+ ""
380
+ );
321
381
  }
322
- lines.push(...card(info, options, c));
382
+ const cardLines = card(info, options, c, markWidth);
383
+ lines.push(...block(cardLines, Math.max(...cardLines.map(visibleWidth))));
323
384
  const tips = info.ink ? "/help \xB7 Esc stops a task \xB7 \\ then Enter: new line \xB7 Ctrl-G editor \xB7 Ctrl-P commands" : "/help \xB7 Ctrl-C stops a task \xB7 \\ at the end: new line";
385
+ if (options.center === true) {
386
+ lines.push(...centerLines([c.dim(tips)], options.columns), "");
387
+ return lines.join("\n");
388
+ }
324
389
  lines.push(c.dim(` ${tips}`), "");
325
390
  return lines.join("\n");
326
391
  }
327
- function card(info, options, c) {
392
+ function card(info, options, c, minWidth) {
328
393
  const home = options.home ?? homedir();
329
394
  const folder = info.root === home || info.root.startsWith(`${home}/`) ? `~${info.root.slice(home.length)}` : info.root;
330
395
  const title = `\u2726 Garuda ${info.version} \xB7 a terminal coding agent`;
@@ -354,7 +419,10 @@ function card(info, options, c) {
354
419
  const labelWidth = Math.max(9, maxLabel + 2);
355
420
  const prefix = 2 + labelWidth;
356
421
  const natural = Math.max(title.length, ...rows.map(([, v]) => prefix + v.length));
357
- const inner = Math.max(20, Math.min(natural + 1, options.columns - 4));
422
+ const inner = Math.max(
423
+ 20,
424
+ Math.min(Math.max(natural + 1, (minWidth ?? 0) - 4), options.columns - 4)
425
+ );
358
426
  const cutStart = (text, max) => text.length <= max ? text : `\u2026${text.slice(text.length - max + 1)}`;
359
427
  const border = (left, right) => c.dim(`${left}${"\u2500".repeat(inner + 2)}${right}`);
360
428
  const line = (plain, styled) => `${c.dim("\u2502")} ${styled}${" ".repeat(Math.max(0, inner - plain.length))} ${c.dim("\u2502")}`;
@@ -378,15 +446,37 @@ function card(info, options, c) {
378
446
  function paint(level) {
379
447
  const esc = (code, text, reset) => `\x1B[${code}m${text}\x1B[${reset}m`;
380
448
  if (level === "none") {
381
- return { gradient: (t) => t, gold: (t) => t, bold: (t) => t, dim: (t) => t };
449
+ return {
450
+ gradient: (t) => t,
451
+ face: () => "\u2588",
452
+ shadow: () => "\u2591",
453
+ gold: (t) => t,
454
+ bold: (t) => t,
455
+ dim: (t) => t
456
+ };
382
457
  }
383
458
  const bold = (t) => esc("1", t, "22");
384
459
  const dim = (t) => esc("2", t, "22");
385
460
  if (level === "basic") {
386
- return { gradient: (t) => esc("33", t, "39"), gold: (t) => esc("33", t, "39"), bold, dim };
461
+ return {
462
+ gradient: (t) => esc("33", t, "39"),
463
+ face: () => esc("33", "\u2588", "39"),
464
+ shadow: () => esc("31", "\u2593", "39"),
465
+ gold: (t) => esc("33", t, "39"),
466
+ bold,
467
+ dim
468
+ };
387
469
  }
388
470
  const rgb = ([r, g, b]) => `38;2;${r};${g};${b}`;
471
+ const mixAt = (x, width) => {
472
+ const t = width <= 1 ? 0 : x / (width - 1);
473
+ return FROM.map((f, k) => Math.round(f + ((TO[k] ?? f) - f) * t));
474
+ };
389
475
  return {
476
+ face: (x, width) => esc(rgb(mixAt(x, width)), "\u2588", "39"),
477
+ // The shadow: the face's colour at half its brightness, so it reads as depth on light and
478
+ // dark backgrounds.
479
+ shadow: (x, width) => esc(rgb(mixAt(x, width).map((v) => Math.round(v * 0.45))), "\u2588", "39"),
390
480
  gradient: (text, width) => [...text].map((ch, i) => {
391
481
  if (ch === " ") return ch;
392
482
  const t = width <= 1 ? 0 : i / (width - 1);
@@ -402,6 +492,36 @@ function paint(level) {
402
492
  // src/cli/jsonOutput.ts
403
493
  import { randomUUID } from "crypto";
404
494
  var OUTPUT_FORMATS = ["text", "json", "stream-json"];
495
+ function receiptJson(r) {
496
+ return {
497
+ turn: r.turn,
498
+ stop_reason: r.stopReason,
499
+ steps: r.steps,
500
+ duration_ms: r.durationMs,
501
+ ...r.costUsd === void 0 ? { cost_is_unknown: true } : { cost_usd: r.costUsd },
502
+ ...r.costIncomplete === true ? { cost_is_incomplete: true } : {},
503
+ files: r.files === void 0 ? null : r.files.map((f) => ({
504
+ path: f.path,
505
+ ...f.added === void 0 ? { binary: true } : { added: f.added, removed: f.removed }
506
+ })),
507
+ ...r.tests === void 0 ? {} : {
508
+ tests: {
509
+ command: r.tests.command,
510
+ passed: r.tests.passed,
511
+ ...r.tests.timedOut === true ? { timed_out: true } : {},
512
+ ...r.tests.total === void 0 ? {} : { total: r.tests.total, failed: r.tests.failed },
513
+ ...r.tests.previousTotal === void 0 ? {} : { previous_total: r.tests.previousTotal }
514
+ }
515
+ },
516
+ commands: {
517
+ sandboxed: r.commands.sandboxed,
518
+ outside: r.commands.outside,
519
+ blocked_hosts: r.commands.blockedHosts
520
+ },
521
+ context_percent: r.contextPercent,
522
+ ...r.keptChanges === void 0 ? {} : { kept_changes: r.keptChanges }
523
+ };
524
+ }
405
525
  var JsonOutput = class {
406
526
  constructor(options) {
407
527
  this.options = options;
@@ -623,13 +743,15 @@ function resultLine(outcome, info) {
623
743
  },
624
744
  permission_denials: info.denials,
625
745
  ...errors === void 0 ? {} : { errors },
626
- ...stop?.terminal === void 0 ? {} : { terminal_reason: stop.terminal }
746
+ ...stop?.terminal === void 0 ? {} : { terminal_reason: stop.terminal },
747
+ ...info.receipt === void 0 ? {} : { receipt: receiptJson(info.receipt) }
627
748
  };
628
749
  }
629
750
 
630
751
  // src/cli/repl.ts
631
752
  import { createInterface } from "readline";
632
- async function runRepl(runtime, approver, renderer, sessionPath, exitNow, io = { input: process.stdin, output: process.stderr }, firstInput, notifier) {
753
+ async function runRepl(runtime, approver, renderer, sessionPath, exitNow, io = { input: process.stdin, output: process.stderr }, firstInput, notifier, tour) {
754
+ let tourTasks = tour;
633
755
  const history = [];
634
756
  const list = rootLister(runtime.root);
635
757
  const args = new CommandArgs(runtime);
@@ -670,7 +792,8 @@ async function runRepl(runtime, approver, renderer, sessionPath, exitNow, io = {
670
792
  raw = `${raw.slice(0, -1)}
671
793
  ${more.text}`;
672
794
  }
673
- const text = raw.trim();
795
+ const text = tourChoice(raw.trim(), tourTasks);
796
+ tourTasks = void 0;
674
797
  if (text === "") continue;
675
798
  history.unshift(raw);
676
799
  if (text.startsWith("!") && text.length > 1) {
@@ -706,8 +829,20 @@ ${more.text}`;
706
829
  renderer,
707
830
  prompt,
708
831
  exitNow,
709
- notifier
832
+ notifier,
833
+ { chat: true }
710
834
  );
835
+ if (outcome.kind === "done" && outcome.result.stopReason === "max_steps") {
836
+ const next = await stopHandoff(
837
+ approver,
838
+ runtime.limits.maxSteps,
839
+ runtime.executor.isolation
840
+ );
841
+ if (next === "stop") break;
842
+ prompt = next === "more" ? CONTINUE_PROMPT : SUMMARY_PROMPT;
843
+ renderer.info(`\u203A ${prompt}`);
844
+ continue;
845
+ }
711
846
  if (!planning || outcome.kind !== "done" || outcome.result.stopReason !== "done") break;
712
847
  if (await planHandoff(runtime, approver) !== "now") break;
713
848
  renderer.info(`\u203A ${BUILD_PROMPT}`);
@@ -784,10 +919,23 @@ async function main() {
784
919
  ).option("--verbose", "with json output: also show the tool activity on stderr").action(async (options) => {
785
920
  process.exitCode = await start(options, program);
786
921
  });
787
- program.command("eval").description("run the eval tasks in scratch folders and report pass/fail, steps and cost").option("-m, --model <id>", "model id (or set GARUDA_MODEL)").option("-s, --suite <name>", "basic (default), hard, java, python, all or repo").option("-t, --task <ids...>", "run only these tasks (from any suite)").option("--max-steps <n>", "step limit per task", (v) => Number.parseInt(v, 10)).option(
922
+ const evalCommand = program.command("eval").description("run the eval tasks in scratch folders and report pass/fail, steps and cost").option("-m, --model <id>", "model id (or set GARUDA_MODEL)").option("-s, --suite <name>", "basic (default), hard, java, python, medium, all or repo").option(
923
+ "-t, --task <ids...>",
924
+ "run only these tasks (from any dev suite, or the held-out set with --split)"
925
+ ).option("--max-steps <n>", "step limit per task", (v) => Number.parseInt(v, 10)).option(
788
926
  "--repeat <n>",
789
927
  "run each task n times and show the mean",
790
928
  (v) => Number.parseInt(v, 10)
929
+ ).option("--agent <name>", "garuda (default) or claude-code: the baseline on the same tasks").option(
930
+ "--split <name>",
931
+ "dev (default), heldout or all: the held-out tasks run only on request"
932
+ ).option("--addendum <file>", "add this text (4000 characters at most) to the system prompt").option("--mcp <server>", "allow this one server from ~/.garuda/mcp.json (an MCP A/B)").option(
933
+ "--mcp-prepare <command>",
934
+ "with --mcp: run this in each scratch folder before the agent (e.g. graphify update .)"
935
+ ).option("--shuffle", "run the tasks and their repeats in a random order from --seed").option(
936
+ "--seed <n>",
937
+ "seed for --shuffle and the report's interval (default 1)",
938
+ (v) => Number(v)
791
939
  ).option("--index <mode>", "code index tools for the model: off (default), lookup or all").option("--executor <name>", "auto (default), os or host").option("--keep", "keep the scratch folders").option("--list", "list the tasks and exit").option("--subagents <mode>", "the explore subagent: off (default) or on, for A/B runs").option("--subagent-model <id>", "model of the explore subagent; default: the main model").option("--todo <mode>", "the todo_write tool: off (default) or on, for A/B runs").option("--lsp <mode>", "language server errors in edit results: off (default) or on").option(
792
940
  "--format <mode>",
793
941
  "the project's formatter after edits: off (default) or on, for A/B runs"
@@ -819,13 +967,47 @@ async function main() {
819
967
  "--test-command <cmd>",
820
968
  "with --from-git: the test command; {files} takes the test files (default: detected)"
821
969
  ).action(async (options) => {
822
- const { runEvalCommand } = await import("../evalCommand-YVQAWUZE.js");
970
+ const { runEvalCommand } = await import("../evalCommand-BLJJ4G76.js");
823
971
  process.exitCode = await runEvalCommand({
824
972
  ...options,
825
973
  model: options.model ?? process.env.GARUDA_MODEL,
826
974
  subagentModel: options.subagentModel ?? process.env.GARUDA_SUBAGENT_MODEL
827
975
  });
828
976
  });
977
+ evalCommand.command("tune").description(
978
+ "improve a prompt addendum: a proposer model edits it, an edit stays when the dev score improves, the held-out set is measured once"
979
+ ).requiredOption(
980
+ "--addendum <file>",
981
+ "the starting addendum (a missing file starts empty); never edited"
982
+ ).option("--proposer <model>", "the model that proposes edits (default claude-opus-5-5)").option("-m, --model <id>", "the agent's model (or set GARUDA_MODEL)").option("-s, --suite <names...>", "dev suites (default: basic hard medium)").option("--rounds <n>", "proposals (default 5)", (v) => Number(v)).option("--repeat <n>", "runs of each dev task per score (default 3)", (v) => Number(v)).option("--heldout-repeat <n>", "runs of each held-out task (default 5)", (v) => Number(v)).option("--margin <n>", "more passing runs that keep an edit (default 2)", (v) => Number(v)).option(
983
+ "--max-cost <usd>",
984
+ "stop before a round that would pass this (default 20)",
985
+ (v) => Number(v)
986
+ ).option("--seed <n>", "seed for the run order and the intervals (default 1)", (v) => Number(v)).option("--yes", "start without the question").option("--parallel <n>", "runs at the same time in each score (default 4)", (v) => Number(v)).action(async (options) => {
987
+ const { runEvalTune } = await import("../evalTune-W53KAD4V.js");
988
+ process.exitCode = await runEvalTune({
989
+ ...options,
990
+ model: options.model ?? process.env.GARUDA_MODEL
991
+ });
992
+ });
993
+ evalCommand.command("compare").description("compare two eval reports of the same tasks (pass rates with a paired interval)").argument("<a>", "report.json, or its run folder (.garuda/evals/<run-id>)").argument("<b>", "the second report").option("--seed <n>", "seed for the bootstrap (default 1)", (v) => Number(v)).action(async (a, b, options) => {
994
+ const { runEvalCompare } = await import("../evalCommand-BLJJ4G76.js");
995
+ process.exitCode = await runEvalCompare(a, b, options);
996
+ });
997
+ program.command("advise").description(
998
+ "which model for this repo: run its own history (garuda eval --from-git) on two models and compare"
999
+ ).option(
1000
+ "--models <a,b>",
1001
+ "two models (default claude-haiku-5-5,claude-sonnet-5-5)",
1002
+ (v) => v.split(",").map((m) => m.trim())
1003
+ ).option("--repeat <n>", "runs of each task (default 2)", (v) => Number(v)).option(
1004
+ "--max-cost <usd>",
1005
+ "stop before a model that would pass this (default 2)",
1006
+ (v) => Number(v)
1007
+ ).option("--seed <n>", "seed for the run order and the intervals (default 1)", (v) => Number(v)).option("--yes", "start without the question").action(async (options) => {
1008
+ const { runAdvise } = await import("../advise-HDKJGNBL.js");
1009
+ process.exitCode = await runAdvise(options);
1010
+ });
829
1011
  program.command("init").description(
830
1012
  "set up this folder (AGENTS.md; commands, MCP servers and rules from Claude Code, OpenCode, Codex, Gemini CLI, Tabnine, Cursor, Copilot), then chat"
831
1013
  ).option("-m, --model <id>", "model id (or set GARUDA_MODEL)").action(async (options) => {
@@ -841,30 +1023,30 @@ async function main() {
841
1023
  program.command("night").description(
842
1024
  "run this project's night queue (jobs from /schedule), up to 3 at a time, then write one digest"
843
1025
  ).option("--at <HH:MM>", "wait until this local time first (keep the terminal open)").option("--parallel <n>", "jobs at the same time (1 to 10, default 3)").addOption(new Option("--from-launchd").hideHelp()).action(async (options) => {
844
- const { nightCommand } = await import("../nightCommand-OODJNWDT.js");
1026
+ const { nightCommand } = await import("../nightCommand-XPWT6CQZ.js");
845
1027
  process.exitCode = await nightCommand(options, new PlainRenderer());
846
1028
  });
847
1029
  program.command("setup").description(
848
1030
  "choose a provider and model and store its key (~/.garuda/credentials, only you can read it); editors run it to sign in"
849
1031
  ).option("--show", "show the model and where each key comes from (keys masked)").option("--forget [key-name]", "remove a stored key, or all of them").action(async (options) => {
850
- const { setupCommand, terminalIO } = await import("../setupCommand-GBQIVYJC.js");
1032
+ const { setupCommand, terminalIO } = await import("../setupCommand-OSOMFHDQ.js");
851
1033
  process.exitCode = await setupCommand(options, { io: await terminalIO() });
852
1034
  });
853
1035
  program.command("acp").description(
854
1036
  "run as an agent for an editor over the Agent Client Protocol (VS Code with an extension, Zed, JetBrains, Neovim, Emacs); the editor starts it"
855
1037
  ).argument("[action]", "setup: run garuda setup (the editor's sign-in, ACP Terminal Auth)").option("-m, --model <id>", "model id (or set GARUDA_MODEL)").action(async (action, options) => {
856
- const { acpCommand } = await import("../acpCommand-7EY3NHPG.js");
1038
+ const { acpCommand } = await import("../acpCommand-JAYNMIMP.js");
857
1039
  process.exitCode = await acpCommand({
858
1040
  ...options,
859
1041
  ...action === void 0 ? {} : { action }
860
1042
  });
861
1043
  });
862
1044
  const lsp = program.command("lsp").description("show the language servers for diagnostics (TS/JS, Python, Java)").action(async () => {
863
- const { lspStatusCommand } = await import("../lspCommand-ZZ6R4PA2.js");
1045
+ const { lspStatusCommand } = await import("../lspCommand-X4FTTONR.js");
864
1046
  process.exitCode = await lspStatusCommand();
865
1047
  });
866
1048
  lsp.command("install").description("install a pinned language server into ~/.garuda/lsp (needs the network)").argument("<language>", "typescript, python or java").action(async (language) => {
867
- const { lspInstallCommand } = await import("../lspCommand-ZZ6R4PA2.js");
1049
+ const { lspInstallCommand } = await import("../lspCommand-X4FTTONR.js");
868
1050
  process.exitCode = await lspInstallCommand(language);
869
1051
  });
870
1052
  await program.parseAsync();
@@ -876,7 +1058,7 @@ async function start(options, program) {
876
1058
  let job;
877
1059
  let jobGuard;
878
1060
  if (options.job !== void 0) {
879
- const { prepareJob } = await import("../jobCommand-FE6XN3YD.js");
1061
+ const { prepareJob } = await import("../jobCommand-ILOTYOX3.js");
880
1062
  const prepared = await prepareJob(
881
1063
  mainRoot,
882
1064
  options.job,
@@ -984,6 +1166,8 @@ async function start(options, program) {
984
1166
  // The project's settings that loosen safety: asked at startup when there is a terminal,
985
1167
  // pinned in ~/.garuda/trust.json (a job passes its own settings).
986
1168
  projectSettings: { home: homedir2(), ask: process.stdin.isTTY === true },
1169
+ // UX U2: a chat watches the network, so a command that needs a host asks for it.
1170
+ ...job === void 0 && prompt === void 0 && process.stdin.isTTY === true ? { network: { watch: true } } : {},
987
1171
  // Web search (0.5) and Claude's own search (0.6): only the user's search.json and environment.
988
1172
  ...searchConfig.config === void 0 && searchConfig.claude === void 0 ? {} : {
989
1173
  search: {
@@ -1036,7 +1220,7 @@ async function start(options, program) {
1036
1220
  job.job.status = "failed";
1037
1221
  await saveJob(job.job);
1038
1222
  if (options.fromLaunchd === true || job.job.launchd !== void 0) {
1039
- const { removeAgent, defaultAgentEnv } = await import("../launchd-3A3ONEW5.js");
1223
+ const { removeAgent, defaultAgentEnv } = await import("../launchd-QG6R5RAK.js");
1040
1224
  await removeAgent(runtime.executor, job.job, defaultAgentEnv());
1041
1225
  }
1042
1226
  return 1;
@@ -1101,7 +1285,8 @@ async function start(options, program) {
1101
1285
  ...runIncomplete ? { runCostIncomplete: true } : {},
1102
1286
  contextWindow: runtime.limits.contextWindow,
1103
1287
  maxOutputTokens: resolved.maxTokens ?? DEFAULT_MAX_TOKENS,
1104
- ...outcome2.kind === "done" ? { stopMessage: stopMessage(outcome2.result.stopReason, runtime.limits) } : {}
1288
+ ...outcome2.kind === "done" ? { stopMessage: stopMessage(outcome2.result.stopReason, runtime.limits) } : {},
1289
+ ...outcome2.kind === "done" && runtime.lastReceipt !== void 0 ? { receipt: runtime.lastReceipt } : {}
1105
1290
  });
1106
1291
  };
1107
1292
  if (prompt.startsWith("/")) {
@@ -1115,7 +1300,7 @@ async function start(options, program) {
1115
1300
  if (resolved2.kind === "prompt") prompt = resolved2.prompt;
1116
1301
  }
1117
1302
  if (job !== void 0) {
1118
- const { testsBefore } = await import("../jobCommand-FE6XN3YD.js");
1303
+ const { testsBefore } = await import("../jobCommand-ILOTYOX3.js");
1119
1304
  await testsBefore(job, runtime, renderer);
1120
1305
  }
1121
1306
  const outcome = await runTurnInTerminal(
@@ -1128,7 +1313,7 @@ async function start(options, program) {
1128
1313
  await runtime.close();
1129
1314
  finish(outcome);
1130
1315
  if (job !== void 0) {
1131
- const { finishJob } = await import("../jobCommand-FE6XN3YD.js");
1316
+ const { finishJob } = await import("../jobCommand-ILOTYOX3.js");
1132
1317
  await finishJob(job, outcome, runtime, renderer, void 0, {
1133
1318
  fromLaunchd: options.fromLaunchd === true
1134
1319
  });
@@ -1150,15 +1335,48 @@ async function start(options, program) {
1150
1335
  tools: runtime.toolsSummary(),
1151
1336
  ink: ink !== void 0
1152
1337
  };
1338
+ const { screenReaderMode } = await import("../receiptView-YFDHV253.js");
1153
1339
  let startBanner = banner(bannerInfo, {
1154
1340
  columns: process.stdout.columns || 80,
1155
- color: colorLevel(process.stdout)
1341
+ color: colorLevel(process.stdout),
1342
+ // 0.18.1: the Ink chat centres the banner; a screen reader gets it as it is.
1343
+ center: ink !== void 0 && !screenReaderMode(),
1344
+ ...process.stdout.rows ? { rows: process.stdout.rows } : {},
1345
+ screenReader: screenReaderMode()
1156
1346
  });
1347
+ {
1348
+ const { BUILD_COMMIT } = await import("../buildInfo-K73FFI5S.js");
1349
+ const { CHAT_STALE, garudaCommit, staleBuildNote } = await import("../buildCheck-HB46NWLX.js");
1350
+ const stale = staleBuildNote(BUILD_COMMIT, await garudaCommit(), CHAT_STALE);
1351
+ if (stale !== void 0) {
1352
+ startBanner += `
1353
+ ${colorLevel(process.stdout) === "none" ? stale : styleText("yellow", stale)}`;
1354
+ }
1355
+ }
1356
+ let tour;
1157
1357
  if (options.firstInput === void 0) {
1358
+ const colored = colorLevel(process.stdout) !== "none";
1359
+ const { morningBrief } = await import("../brief-RWKESOPT.js");
1360
+ const brief = await morningBrief(
1361
+ root,
1362
+ (style, text) => colored ? styleText(style, text) : text
1363
+ ).catch(() => void 0);
1364
+ if (brief !== void 0) startBanner += `
1365
+ ${brief}
1366
+ `;
1158
1367
  const { initTip } = await import("../detect-LARDSLLZ.js");
1159
1368
  const tip = initTip(root);
1160
- if (tip !== void 0) startBanner += `
1161
- ${tip}`;
1369
+ const { firstRunTour } = await import("../tour-CEVMAC5S.js");
1370
+ const first = await firstRunTour(root, homedir2(), runtime.profiles).catch(() => void 0);
1371
+ if (first !== void 0) {
1372
+ tour = first.prompts;
1373
+ startBanner += `
1374
+ ${first.text}${tip === void 0 ? "" : " /init sets up AGENTS.md for this project."}`;
1375
+ } else if (tip !== void 0) {
1376
+ const shown = ink !== void 0 && !screenReaderMode() ? centerLines([tip], process.stdout.columns || 80)[0] : tip;
1377
+ startBanner += `
1378
+ ${shown}`;
1379
+ }
1162
1380
  }
1163
1381
  const sessionPath = (id2) => join(store.dir, `${id2}.jsonl`);
1164
1382
  const notify = runtime.notificationSettings;
@@ -1176,6 +1394,8 @@ ${tip}`;
1176
1394
  const setEventTarget = (target) => {
1177
1395
  events = target;
1178
1396
  };
1397
+ const { countChat, KEY_HINT_CHATS } = await import("../uiState-YFJQ43D7.js");
1398
+ const chats = await countChat(homedir2());
1179
1399
  await ink.runInkChat(
1180
1400
  runtime,
1181
1401
  approver,
@@ -1185,7 +1405,10 @@ ${tip}`;
1185
1405
  exitNow,
1186
1406
  options.firstInput,
1187
1407
  notifier,
1188
- focus
1408
+ focus,
1409
+ chats <= KEY_HINT_CHATS,
1410
+ runtime.uiSettings?.clearOnStart !== false,
1411
+ tour
1189
1412
  );
1190
1413
  } else {
1191
1414
  process.stderr.write(`${startBanner}
@@ -1198,7 +1421,8 @@ ${tip}`;
1198
1421
  exitNow,
1199
1422
  void 0,
1200
1423
  options.firstInput,
1201
- notifier
1424
+ notifier,
1425
+ tour
1202
1426
  );
1203
1427
  }
1204
1428
  await runtime.close();
@@ -1214,7 +1438,7 @@ function wantsInk() {
1214
1438
  }
1215
1439
  async function loadInk(renderer) {
1216
1440
  try {
1217
- return await import("../inkChat-FNUBK43U.js");
1441
+ return await import("../inkChat-EVLYDC3K.js");
1218
1442
  } catch (error) {
1219
1443
  renderer.info(`Plain chat (Ink is not available: ${error.message.split("\n")[0]}).`);
1220
1444
  return void 0;
@@ -1246,8 +1470,8 @@ function recordJobDenial(job, tool, target) {
1246
1470
  }
1247
1471
  async function jobBatchClient(job, resolved, renderer) {
1248
1472
  const { DeadlineClient } = await import("../deadline-TP7ZGLT2.js");
1249
- const { nextTime } = await import("../launchd-3A3ONEW5.js");
1250
- const { DEFAULT_FINISH_BY, DEFAULT_STEP_LIMIT_MINUTES, SWITCH_BEFORE_MS } = await import("../create-W6BV75QX.js");
1473
+ const { nextTime } = await import("../launchd-QG6R5RAK.js");
1474
+ const { DEFAULT_FINISH_BY, DEFAULT_STEP_LIMIT_MINUTES, SWITCH_BEFORE_MS } = await import("../create-OACSGJ37.js");
1251
1475
  const finishBy = job.job.finishBy ?? DEFAULT_FINISH_BY;
1252
1476
  const stepLimit = job.job.stepLimitMinutes ?? DEFAULT_STEP_LIMIT_MINUTES;
1253
1477
  const switchAt = new Date(nextTime(finishBy).getTime() - SWITCH_BEFORE_MS);
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ MCP_FILE,
4
+ SERVER_NAME,
5
+ checkServerUrl,
6
+ commandLine,
7
+ defHash,
8
+ expandEnv,
9
+ isHttp,
10
+ loadMcpConfig
11
+ } from "./chunk-QANRZW7W.js";
12
+ import "./chunk-ATW7BNIG.js";
13
+ export {
14
+ MCP_FILE,
15
+ SERVER_NAME,
16
+ checkServerUrl,
17
+ commandLine,
18
+ defHash,
19
+ expandEnv,
20
+ isHttp,
21
+ loadMcpConfig
22
+ };
23
+ //# sourceMappingURL=config-WV2H64TF.js.map
@@ -3,7 +3,7 @@ import {
3
3
  jobBase,
4
4
  linkCandidates,
5
5
  worktreeDir
6
- } from "./chunk-55CFEEIN.js";
6
+ } from "./chunk-WK5NE6RY.js";
7
7
  import {
8
8
  agentLabel,
9
9
  defaultAgentEnv,
@@ -12,15 +12,15 @@ import {
12
12
  nextTime,
13
13
  nightAgentTime,
14
14
  nightSpec
15
- } from "./chunk-5B5HDTUR.js";
15
+ } from "./chunk-TWQ7V2L6.js";
16
16
  import {
17
17
  jobPrompt
18
18
  } from "./chunk-3MRQJKUO.js";
19
19
  import "./chunk-AOGFYUKG.js";
20
20
  import {
21
21
  JobGitError
22
- } from "./chunk-6XHON3Q6.js";
23
- import "./chunk-B4SJY7KT.js";
22
+ } from "./chunk-QXTHEFKP.js";
23
+ import "./chunk-LMKGSYJC.js";
24
24
  import "./chunk-BHZ6G65V.js";
25
25
  import "./chunk-P6XWWIEK.js";
26
26
  import {
@@ -227,4 +227,4 @@ export {
227
227
  createJob,
228
228
  switchTime
229
229
  };
230
- //# sourceMappingURL=create-W6BV75QX.js.map
230
+ //# sourceMappingURL=create-OACSGJ37.js.map