@garuda-agent/garuda 0.18.0 → 0.18.2

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 (58) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/README.md +3 -2
  3. package/dist/{acpCommand-IUZPLPLI.js → acpCommand-PUJHFWYU.js} +10 -8
  4. package/dist/advise-C777SZ5M.js +433 -0
  5. package/dist/brief-RWKESOPT.js +91 -0
  6. package/dist/buildCheck-HB46NWLX.js +19 -0
  7. package/dist/buildInfo-Z4P7QAQL.js +8 -0
  8. package/dist/chunk-2OYTNNUJ.js +216 -0
  9. package/dist/chunk-4BELTWP4.js +156 -0
  10. package/dist/chunk-4QRTTRVK.js +88 -0
  11. package/dist/chunk-6JQTPW3P.js +88 -0
  12. package/dist/chunk-A5DLAXB4.js +1780 -0
  13. package/dist/{chunk-FARS4R67.js → chunk-AX3A5KPH.js} +18 -1
  14. package/dist/chunk-CFDRP6XW.js +9 -0
  15. package/dist/chunk-E6YRCDSF.js +9 -0
  16. package/dist/{chunk-OQ26W5L4.js → chunk-HP6EGFHV.js} +132 -75
  17. package/dist/chunk-L55VUSX3.js +54 -0
  18. package/dist/{chunk-B4SJY7KT.js → chunk-LMKGSYJC.js} +77 -8
  19. package/dist/{chunk-Q4P3W657.js → chunk-LWNMEGDF.js} +10 -1124
  20. package/dist/{chunk-23FXBNBB.js → chunk-MNE7HHX2.js} +2 -1
  21. package/dist/{chunk-UKIE4AAM.js → chunk-NLS7GMF7.js} +11 -105
  22. package/dist/{chunk-6XHON3Q6.js → chunk-QXTHEFKP.js} +3 -3
  23. package/dist/{chunk-4BVCYCQT.js → chunk-R7RCW4BQ.js} +9 -7
  24. package/dist/{chunk-NHWHG3SW.js → chunk-STVFWSIL.js} +350 -57
  25. package/dist/{chunk-5B5HDTUR.js → chunk-TWQ7V2L6.js} +2 -2
  26. package/dist/chunk-ULAJPMY7.js +107 -0
  27. package/dist/chunk-VISKX36R.js +306 -0
  28. package/dist/{chunk-55CFEEIN.js → chunk-WK5NE6RY.js} +2 -2
  29. package/dist/chunk-Y62J7PTD.js +90 -0
  30. package/dist/chunk-YAQ6QLKB.js +40 -0
  31. package/dist/{chunk-FOPBOB7W.js → chunk-YEH2OONM.js} +6 -4
  32. package/dist/{chunk-7TH3NHCQ.js → chunk-ZKT4P2PC.js} +2 -2
  33. package/dist/cli/index.js +242 -52
  34. package/dist/{create-W6BV75QX.js → create-OACSGJ37.js} +5 -5
  35. package/dist/{evalCommand-SKJQ6CW2.js → evalCommand-MRO6ENCA.js} +77 -39
  36. package/dist/{evalTune-CZRCPSZ3.js → evalTune-VL5RHYOG.js} +24 -18
  37. package/dist/{export-SJ3DUP6W.js → export-ZPF3AMO6.js} +27 -4
  38. package/dist/exportHtml-ISISG5HG.js +21 -0
  39. package/dist/{inkChat-WYYAFZXD.js → inkChat-UDFX6GH6.js} +256 -41
  40. package/dist/{install-TKWN5AYH.js → install-4ST5BNRG.js} +3 -3
  41. package/dist/{jobCommand-2ODQLHB3.js → jobCommand-ILOTYOX3.js} +8 -7
  42. package/dist/{launchd-3A3ONEW5.js → launchd-QG6R5RAK.js} +4 -4
  43. package/dist/{lspCommand-ZZ6R4PA2.js → lspCommand-X4FTTONR.js} +3 -3
  44. package/dist/{manager-TCYTA5XU.js → manager-YH7722C2.js} +3 -3
  45. package/dist/{nightCommand-WJU6VZA6.js → nightCommand-XPWT6CQZ.js} +8 -7
  46. package/dist/receiptView-YFDHV253.js +19 -0
  47. package/dist/{remove-42WQNVPX.js → remove-STX5UO7X.js} +3 -3
  48. package/dist/{run-PTMRQCIU.js → run-W4TK52WT.js} +5 -5
  49. package/dist/runner-EBF6EOYM.js +97 -0
  50. package/dist/{server-VEYIJHEU.js → server-ASM73QVY.js} +3 -3
  51. package/dist/tour-CEVMAC5S.js +18 -0
  52. package/dist/tune-KSNKBPNJ.js +51 -0
  53. package/dist/uiState-YFJQ43D7.js +16 -0
  54. package/package.json +1 -1
  55. package/dist/chunk-4JSUUDFQ.js +0 -118
  56. package/dist/chunk-C57GHLKP.js +0 -9
  57. package/dist/chunk-DOCDCQVM.js +0 -484
  58. package/dist/tune-YVI2KWQF.js +0 -31
@@ -1,4 +1,9 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ KEYS_HELP,
4
+ contextBar,
5
+ contextLevel
6
+ } from "./chunk-L55VUSX3.js";
2
7
  import {
3
8
  FOCUS_REPORTING_OFF,
4
9
  FOCUS_REPORTING_ON,
@@ -6,11 +11,14 @@ import {
6
11
  fuzzyFiles,
7
12
  runChat,
8
13
  statusOf
9
- } from "./chunk-OQ26W5L4.js";
14
+ } from "./chunk-HP6EGFHV.js";
10
15
  import {
11
16
  colorPreview,
12
- header
13
- } from "./chunk-4JSUUDFQ.js";
17
+ header,
18
+ hunkCount,
19
+ terminalPaint,
20
+ unifiedDiff
21
+ } from "./chunk-VISKX36R.js";
14
22
  import {
15
23
  retryText,
16
24
  serverToolOutput,
@@ -18,23 +26,31 @@ import {
18
26
  summariseCall,
19
27
  summariseResult,
20
28
  todoLines
21
- } from "./chunk-FARS4R67.js";
22
- import "./chunk-NHWHG3SW.js";
23
- import "./chunk-65NUEOI7.js";
29
+ } from "./chunk-AX3A5KPH.js";
30
+ import {
31
+ receiptText,
32
+ screenReaderMode
33
+ } from "./chunk-2OYTNNUJ.js";
34
+ import "./chunk-Y62J7PTD.js";
35
+ import "./chunk-STVFWSIL.js";
24
36
  import "./chunk-G2AX7MGS.js";
37
+ import "./chunk-ULAJPMY7.js";
38
+ import "./chunk-65NUEOI7.js";
39
+ import "./chunk-4QRTTRVK.js";
25
40
  import "./chunk-A2QAIRQL.js";
26
- import "./chunk-UKIE4AAM.js";
41
+ import "./chunk-NLS7GMF7.js";
27
42
  import "./chunk-7KBOIPUT.js";
28
43
  import "./chunk-B25VL4RU.js";
29
- import "./chunk-23FXBNBB.js";
44
+ import "./chunk-MNE7HHX2.js";
45
+ import "./chunk-42DSA4EA.js";
30
46
  import "./chunk-EU7PA45O.js";
31
- import "./chunk-C57GHLKP.js";
47
+ import "./chunk-CFDRP6XW.js";
32
48
  import "./chunk-5DEWP3YX.js";
33
49
  import "./chunk-PZS3V6P3.js";
34
50
  import "./chunk-QANRZW7W.js";
35
51
  import "./chunk-ATW7BNIG.js";
36
52
  import "./chunk-AOGFYUKG.js";
37
- import "./chunk-B4SJY7KT.js";
53
+ import "./chunk-LMKGSYJC.js";
38
54
  import "./chunk-BHZ6G65V.js";
39
55
  import "./chunk-P6XWWIEK.js";
40
56
  import "./chunk-VTMD5IHD.js";
@@ -357,6 +373,45 @@ function paletteWindow(selected, count) {
357
373
  return Math.min(Math.max(0, selected - PALETTE_ROWS + 1), count - PALETTE_ROWS);
358
374
  }
359
375
 
376
+ // src/cli/chat/toolGroups.ts
377
+ var GROUPS = {
378
+ read_file: (n) => `Read ${n} files`,
379
+ glob: (n) => `Listed files ${n} times`,
380
+ grep: (n) => `Searched ${n} times`,
381
+ find_symbol: (n) => `Looked up ${n} symbols`,
382
+ find_references: (n) => `Found references ${n} times`,
383
+ find_callers: (n) => `Found callers ${n} times`,
384
+ repo_map: (n) => `Mapped the repository ${n} times`
385
+ };
386
+ function groups(name) {
387
+ return Object.hasOwn(GROUPS, name);
388
+ }
389
+ function groupTargets(calls, width) {
390
+ const all = calls.map((c) => summariseCall(c)).filter((t) => t !== "");
391
+ const shown = [];
392
+ for (const [i, target] of all.entries()) {
393
+ const rest = all.length - i - 1;
394
+ const next = [...shown, target].join(", ");
395
+ const tail = rest > 0 ? `, +${rest}` : "";
396
+ if (shown.length > 0 && next.length + tail.length > width) {
397
+ return `${shown.join(", ")}, +${all.length - i}`;
398
+ }
399
+ shown.push(target);
400
+ }
401
+ return shown.join(", ");
402
+ }
403
+ function groupLine(name, calls, paint, columns) {
404
+ const head = GROUPS[name]?.(calls.length) ?? `${name} \xD7${calls.length}`;
405
+ const room = Math.max(20, columns - head.length - 6);
406
+ return `${paint("cyan", "\u25CF")} ${paint("bold", head)} ${paint("dim", groupTargets(calls, room))}`;
407
+ }
408
+ function planText(lines, paint) {
409
+ const painted = lines.map(
410
+ (line) => line.startsWith("\u2714") ? paint("green", line) : line.startsWith("\u25B6") ? paint("yellow", line) : paint("dim", line)
411
+ );
412
+ return [paint("bold", "Plan"), ...painted.map((l) => ` ${l}`)].join("\n");
413
+ }
414
+
360
415
  // src/cli/chat/store.ts
361
416
  var APPROVAL_KEY_DELAY_MS = 400;
362
417
  var APPROVAL_CHOICES = [
@@ -387,10 +442,18 @@ var ChatStore = class {
387
442
  /** Ctrl-G and /editor (0.6): the chat sets it; it edits the text in the user's editor. */
388
443
  externalEdit;
389
444
  paint;
445
+ columns;
446
+ /** The turn's answer has started (its first text item got the mark). */
447
+ answered = true;
448
+ /** UX U4: the open group: one tool, its calls, and the text of a lone call. */
449
+ openGroup;
450
+ /** UX U4: the last plan of the turn, for the scrollback at the end. */
451
+ planLines;
390
452
  now;
391
453
  constructor(status, options = {}) {
392
454
  this.paint = options.paint ?? ansi;
393
455
  this.now = options.now ?? Date.now;
456
+ this.columns = options.columns ?? (() => process.stdout.columns || 80);
394
457
  this.approvalKeyDelayMs = options.approvalKeyDelayMs ?? APPROVAL_KEY_DELAY_MS;
395
458
  this.state = {
396
459
  items: [],
@@ -401,7 +464,8 @@ var ChatStore = class {
401
464
  editor: emptyEditor(options.history),
402
465
  busy: false,
403
466
  status,
404
- exiting: false
467
+ exiting: false,
468
+ keyHints: options.keyHints ?? true
405
469
  };
406
470
  }
407
471
  // The external store for React (useSyncExternalStore).
@@ -415,7 +479,14 @@ var ChatStore = class {
415
479
  for (const listener of this.listeners) listener();
416
480
  }
417
481
  add(item) {
418
- this.update({ items: [...this.state.items, { ...item, id: this.nextId++ }] });
482
+ const lead = item.kind === "text" && !this.answered;
483
+ if (item.kind === "text") this.answered = true;
484
+ this.update({
485
+ items: [
486
+ ...this.state.items,
487
+ { ...item, ...lead ? { lead } : {}, id: this.nextId++ }
488
+ ]
489
+ });
419
490
  }
420
491
  // Input.
421
492
  /** The next line to run: from the queue, or the next Enter. undefined means exit. */
@@ -571,11 +642,14 @@ var ChatStore = class {
571
642
  /** Start a turn. `show: false` when the line is already on screen (a custom command). */
572
643
  begin(prompt, show = true) {
573
644
  if (show) this.add({ kind: "user", text: prompt });
645
+ this.answered = false;
574
646
  this.stopping = false;
575
647
  this.update({ busy: true });
576
648
  }
577
649
  end(status) {
578
650
  this.flushText();
651
+ this.closeGroup();
652
+ this.closePlan();
579
653
  this.stopping = false;
580
654
  this.update({ busy: false, running: [], status: { ...this.state.status, ...status } });
581
655
  }
@@ -612,6 +686,7 @@ ${text}` });
612
686
  return;
613
687
  case "text_delta": {
614
688
  this.flushThinking();
689
+ this.closeGroup();
615
690
  const { blocks, rest } = takeBlocks(this.state.streaming + event.text);
616
691
  for (const block of blocks)
617
692
  this.add({ kind: "text", text: renderMarkdown(block, this.paint) });
@@ -644,14 +719,30 @@ ${text}` });
644
719
  const summary = summariseResult(event.call, event.outcome);
645
720
  const line = `${this.paint("cyan", "\u25CF")} ${this.paint("bold", event.call.name)} ${summariseCall(event.call)}`;
646
721
  const result = ` ${this.paint("dim", "\u23BF")} ${event.outcome.isError ? this.paint("red", summary) : this.paint("dim", summary)}`;
647
- const todos = todoLines(event.call, event.outcome).map((l) => ` ${l}`);
648
722
  const shown = this.details || event.outcome.isError ? [result] : [];
649
- this.add({ kind: "tool", text: [line, ...shown, ...todos].join("\n") });
723
+ const text = [line, ...shown].join("\n");
650
724
  this.lastOutput = {
651
725
  title: `${event.call.name} ${summariseCall(event.call)}`,
652
726
  text: event.outcome.content
653
727
  };
654
- this.update({ running: this.state.running.filter((r) => r.id !== event.call.id) });
728
+ const running = this.state.running.filter((r) => r.id !== event.call.id);
729
+ const todos = todoLines(event.call, event.outcome);
730
+ if (event.call.name === "todo_write" && todos.length > 0) {
731
+ this.planLines = todos;
732
+ this.update({ running, plan: planText(todos, this.paint) });
733
+ return;
734
+ }
735
+ if (groups(event.call.name) && !event.outcome.isError) {
736
+ if (this.openGroup?.name !== event.call.name) this.closeGroup();
737
+ const open = this.openGroup ?? { name: event.call.name, calls: [], single: text };
738
+ open.calls.push(event.call);
739
+ this.openGroup = open;
740
+ this.update({ running, group: this.groupText(open) });
741
+ return;
742
+ }
743
+ this.closeGroup();
744
+ this.add({ kind: "tool", text });
745
+ this.update({ running });
655
746
  return;
656
747
  }
657
748
  case "compaction": {
@@ -667,6 +758,7 @@ ${text}` });
667
758
  return;
668
759
  case "server_tool": {
669
760
  this.flushText();
761
+ this.closeGroup();
670
762
  const { call, result } = serverToolText(event);
671
763
  const failed = event.result?.error !== void 0;
672
764
  const head = `${this.paint("cyan", "\u25CF")} ${this.paint("bold", call)}`;
@@ -685,6 +777,24 @@ ${text}` });
685
777
  info(text) {
686
778
  this.note("info", text);
687
779
  }
780
+ /** UX U10: `?` on an empty input line prints every key. */
781
+ showKeys() {
782
+ this.add({ kind: "output", text: this.paint("dim", KEYS_HELP) });
783
+ }
784
+ /** UX U1: the turn's receipt, as a box in the scrollback. */
785
+ receipt(receipt) {
786
+ this.flushText();
787
+ this.closeGroup();
788
+ this.add({
789
+ kind: "output",
790
+ text: `
791
+ ${receiptText(receipt, {
792
+ columns: this.columns(),
793
+ paint: (style, text) => this.paint(style, text),
794
+ screenReader: screenReaderMode()
795
+ })}`
796
+ });
797
+ }
688
798
  warn(text) {
689
799
  this.note("warn", text);
690
800
  }
@@ -693,6 +803,7 @@ ${text}` });
693
803
  }
694
804
  note(level, text) {
695
805
  this.flushText();
806
+ this.closeGroup();
696
807
  const trimmed = text.replace(/^\n+/, "");
697
808
  const style = level === "info" ? "dim" : level === "warn" ? "yellow" : "red";
698
809
  this.add({ kind: "note", level, text: this.paint(style, trimmed) });
@@ -707,6 +818,30 @@ ${text}` });
707
818
  this.add({ kind: "output", text: thinkingPreview(text, (s) => this.paint("dim", s)) });
708
819
  this.lastOutput = { title: "thinking", text };
709
820
  }
821
+ /** UX U4: the open group's text: a lone call as it always was, else one line for all. */
822
+ groupText(open) {
823
+ return open.calls.length === 1 ? open.single : groupLine(open.name, open.calls, this.paint, this.columns());
824
+ }
825
+ /** UX U4: the open group goes into the scrollback as one item. */
826
+ closeGroup() {
827
+ const open = this.openGroup;
828
+ if (open === void 0) return;
829
+ this.openGroup = void 0;
830
+ this.add({ kind: "tool", text: this.groupText(open) });
831
+ const { group: _closed, ...rest } = this.state;
832
+ this.state = rest;
833
+ for (const listener of this.listeners) listener();
834
+ }
835
+ /** UX U4: at the end of a turn, the last plan goes into the scrollback once. */
836
+ closePlan() {
837
+ const lines = this.planLines;
838
+ if (lines === void 0) return;
839
+ this.planLines = void 0;
840
+ this.add({ kind: "tool", text: planText(lines, this.paint) });
841
+ const { plan: _closed, ...rest } = this.state;
842
+ this.state = rest;
843
+ for (const listener of this.listeners) listener();
844
+ }
710
845
  flushText() {
711
846
  this.flushThinking();
712
847
  const rest = this.state.streaming;
@@ -741,8 +876,13 @@ ${text}` });
741
876
  approvalKeyDelayMs;
742
877
  askNow(request, signal) {
743
878
  this.flushText();
744
- this.add({ kind: "output", text: `${header(request)}
745
- ${colorPreview(request)}` });
879
+ const hunks = request.selectHunks === void 0 ? 0 : hunkCount(request.preview);
880
+ const hint = hunks >= 2 ? this.paint("dim", ` \xB7 ${hunks} hunks \xB7 h reviews them one by one`) : "";
881
+ this.add({
882
+ kind: "output",
883
+ text: `${header(request)}${hint}
884
+ ${colorPreview(request, this.columns())}`
885
+ });
746
886
  return new Promise((resolve, reject) => {
747
887
  const onAbort = () => {
748
888
  this.answer = void 0;
@@ -881,6 +1021,7 @@ function App({ store }) {
881
1021
  /* @__PURE__ */ jsx(Static, { items: state.items, children: (item) => /* @__PURE__ */ jsx(ItemView, { item }, item.id) }),
882
1022
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
883
1023
  state.streaming !== "" && /* @__PURE__ */ jsx(Text, { children: state.streaming }),
1024
+ state.group !== void 0 && /* @__PURE__ */ jsx(Text, { children: state.group }),
884
1025
  state.running.map((tool) => /* @__PURE__ */ jsxs(Text, { children: [
885
1026
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: frame }),
886
1027
  " ",
@@ -900,6 +1041,7 @@ function App({ store }) {
900
1041
  hasHunks: state.approval.request.selectHunks !== void 0
901
1042
  }
902
1043
  ),
1044
+ state.plan !== void 0 && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { children: state.plan }) }),
903
1045
  state.queue.map((line, i) => (
904
1046
  // biome-ignore lint/suspicious/noArrayIndexKey: queued lines can repeat.
905
1047
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
@@ -914,15 +1056,45 @@ function App({ store }) {
914
1056
  ] })
915
1057
  ] });
916
1058
  }
1059
+ var USER_BAR = "\u258C";
1060
+ var USER_BORDER = {
1061
+ topLeft: "",
1062
+ top: "",
1063
+ topRight: "",
1064
+ left: USER_BAR,
1065
+ right: "",
1066
+ bottomLeft: "",
1067
+ bottom: "",
1068
+ bottomRight: ""
1069
+ };
1070
+ var GARUDA_MARK = "\u2726 ";
917
1071
  function ItemView({ item }) {
918
1072
  switch (item.kind) {
919
1073
  case "user":
920
- return /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { bold: true, children: [
921
- "\u203A ",
1074
+ if (screenReaderMode()) {
1075
+ return /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { bold: true, children: [
1076
+ "You: ",
1077
+ item.text
1078
+ ] }) });
1079
+ }
1080
+ return /* @__PURE__ */ jsx(
1081
+ Box,
1082
+ {
1083
+ marginTop: 1,
1084
+ borderStyle: USER_BORDER,
1085
+ borderColor: "cyan",
1086
+ borderTop: false,
1087
+ borderRight: false,
1088
+ borderBottom: false,
1089
+ paddingLeft: 1,
1090
+ children: /* @__PURE__ */ jsx(Text, { bold: true, children: item.text })
1091
+ }
1092
+ );
1093
+ case "text":
1094
+ return /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
1095
+ item.lead === true && /* @__PURE__ */ jsx(Text, { color: "yellow", children: screenReaderMode() ? "Garuda: " : GARUDA_MARK }),
922
1096
  item.text
923
1097
  ] }) });
924
- case "text":
925
- return /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { children: item.text }) });
926
1098
  default:
927
1099
  return /* @__PURE__ */ jsx(Text, { children: item.text });
928
1100
  }
@@ -951,13 +1123,7 @@ function HunkStagingView({ staging }) {
951
1123
  ] })
952
1124
  ] }),
953
1125
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: current.header }),
954
- /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingLeft: 1, children: current.lines.map((line, i) => {
955
- const color = line.startsWith("+") ? "green" : line.startsWith("-") ? "red" : void 0;
956
- return (
957
- // biome-ignore lint/suspicious/noArrayIndexKey: diff lines can be identical
958
- /* @__PURE__ */ jsx(Text, { ...color ? { color } : {}, children: line }, i)
959
- );
960
- }) }),
1126
+ /* @__PURE__ */ jsx(Box, { flexDirection: "column", paddingLeft: 1, children: /* @__PURE__ */ jsx(Text, { children: unifiedDiff(current.lines.join("\n"), terminalPaint) }) }),
961
1127
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "[y] stage hunk \xB7 [n] skip \xB7 [a] stage all \xB7 [d] discard all \xB7 [\u2190/\u2192] prev/next \xB7 [Esc] back" })
962
1128
  ] });
963
1129
  }
@@ -1013,36 +1179,76 @@ function PaletteView({ palette }) {
1013
1179
  ] })
1014
1180
  ] });
1015
1181
  }
1182
+ var INPUT_HINT = "Type a task \xB7 / for commands \xB7 @ for files";
1183
+ var INPUT_HINT_BUSY = "Type to queue the next task \xB7 Esc stops this one";
1184
+ var INPUT_BOX_MIN_COLUMNS = 40;
1016
1185
  function InputLine({ state }) {
1017
1186
  const { text, cursor } = state.editor;
1018
1187
  const at = text[cursor];
1019
- return /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs(Text, { children: [
1188
+ const line = text === "" ? /* @__PURE__ */ jsxs(Text, { children: [
1189
+ /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u203A " }),
1190
+ /* @__PURE__ */ jsx(Text, { inverse: true, children: " " }),
1191
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: state.busy ? INPUT_HINT_BUSY : INPUT_HINT })
1192
+ ] }) : /* @__PURE__ */ jsxs(Text, { children: [
1020
1193
  /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u203A " }),
1021
1194
  text.slice(0, cursor),
1022
1195
  /* @__PURE__ */ jsx(Text, { inverse: true, children: at === void 0 || at === "\n" ? " " : at }),
1023
1196
  at === "\n" ? "\n" : "",
1024
1197
  text.slice(cursor + 1)
1025
- ] }) });
1198
+ ] });
1199
+ if (screenReaderMode() || (process.stdout.columns || 80) < INPUT_BOX_MIN_COLUMNS) {
1200
+ return /* @__PURE__ */ jsx(Box, { marginTop: 1, children: line });
1201
+ }
1202
+ return /* @__PURE__ */ jsx(
1203
+ Box,
1204
+ {
1205
+ marginTop: 1,
1206
+ borderStyle: "round",
1207
+ borderColor: "cyan",
1208
+ borderDimColor: state.busy,
1209
+ paddingX: 1,
1210
+ children: line
1211
+ }
1212
+ );
1026
1213
  }
1027
1214
  function Footer({ state }) {
1028
1215
  const { model, sandbox, contextPercent, costUsd, mode } = state.status;
1029
- const parts = [model, sandbox];
1030
- if (contextPercent !== void 0) parts.push(`context ${contextPercent}%`);
1031
- if (costUsd !== void 0) parts.push(`$${costUsd.toFixed(costUsd < 0.01 ? 4 : 2)}`);
1032
- const keys = state.busy ? "Esc stop \xB7 Ctrl-O output" : "\\ then Enter: new line \xB7 Ctrl-G editor \xB7 Ctrl-P commands";
1216
+ const keys = footerKeys(state.busy, state.keyHints);
1217
+ const level = contextPercent === void 0 ? "ok" : contextLevel(contextPercent);
1033
1218
  return /* @__PURE__ */ jsxs(Text, { children: [
1219
+ " ",
1034
1220
  mode === "plan" ? /* @__PURE__ */ jsxs(Text, { color: "yellow", bold: true, children: [
1035
1221
  "PLAN",
1036
1222
  " "
1037
1223
  ] }) : null,
1224
+ /* @__PURE__ */ jsx(
1225
+ Text,
1226
+ {
1227
+ dimColor: true,
1228
+ children: `${model} \xB7 ${sandbox === "no sandbox" ? sandbox : `\u26E8 ${sandbox.replace(/^sandbox /, "")}`}`
1229
+ }
1230
+ ),
1231
+ contextPercent !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
1232
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
1233
+ /* @__PURE__ */ jsx(
1234
+ Text,
1235
+ {
1236
+ ...level === "ok" ? { dimColor: true } : { color: level === "full" ? "red" : "yellow" },
1237
+ children: `${contextBar(contextPercent)} ${contextPercent}%`
1238
+ }
1239
+ )
1240
+ ] }),
1038
1241
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
1039
- parts.join(" \xB7 "),
1040
- " ",
1242
+ costUsd === void 0 ? "" : ` \xB7 $${costUsd.toFixed(costUsd < 0.01 ? 4 : 2)}`,
1041
1243
  " ",
1042
1244
  keys
1043
1245
  ] })
1044
1246
  ] });
1045
1247
  }
1248
+ function footerKeys(busy, hints) {
1249
+ if (busy) return "Esc stop \xB7 Ctrl-O output";
1250
+ return hints ? "\\ then Enter: new line \xB7 Ctrl-G editor \xB7 Ctrl-P commands \xB7 ? keys" : "? keys";
1251
+ }
1046
1252
  var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1047
1253
  function useSpinner(active) {
1048
1254
  const [i, setI] = useState(0);
@@ -1135,7 +1341,9 @@ function onKey(store, state, input, key) {
1135
1341
  if (key.shift) store.toggleMode();
1136
1342
  else store.completeLine();
1137
1343
  } else if (/[\r\n]/.test(input)) typeAhead(store, input);
1138
- else if (input !== "" && !key.meta) store.editLine({ type: "insert", text: input });
1344
+ else if (input === "?" && store.getState().editor.text === "" && !store.getState().busy) {
1345
+ store.showKeys();
1346
+ } else if (input !== "" && !key.meta) store.editLine({ type: "insert", text: input });
1139
1347
  }
1140
1348
  function typeAhead(store, chunk) {
1141
1349
  const parts = chunk.split(/\r\n|\r|\n/);
@@ -1152,8 +1360,14 @@ function typeAhead(store, chunk) {
1152
1360
  }
1153
1361
 
1154
1362
  // src/cli/chat/inkChat.ts
1155
- async function runInkChat(runtime, approver, setEventTarget, banner, sessionPath, exitNow, firstInput, notifier, focus) {
1156
- const store = new ChatStore(statusOf(runtime));
1363
+ function clearScreenKeepingScrollback(rows) {
1364
+ return `${"\n".repeat(Math.max(1, rows))}\x1B[H`;
1365
+ }
1366
+ async function runInkChat(runtime, approver, setEventTarget, banner, sessionPath, exitNow, firstInput, notifier, focus, keyHints = true, clearOnStart = true, tour) {
1367
+ if (clearOnStart && process.stdout.isTTY === true) {
1368
+ process.stdout.write(clearScreenKeepingScrollback(process.stdout.rows || 24));
1369
+ }
1370
+ const store = new ChatStore(statusOf(runtime), { keyHints });
1157
1371
  store.print(banner);
1158
1372
  if (firstInput !== void 0) store.enqueue(firstInput);
1159
1373
  approver.current = store;
@@ -1185,13 +1399,14 @@ async function runInkChat(runtime, approver, setEventTarget, banner, sessionPath
1185
1399
  return exitNow();
1186
1400
  };
1187
1401
  try {
1188
- await runChat(runtime, store, sessionPath, exitClean, notifier);
1402
+ await runChat(runtime, store, sessionPath, exitClean, notifier, tour);
1189
1403
  } finally {
1190
1404
  reportFocus(false);
1191
1405
  ink.unmount();
1192
1406
  }
1193
1407
  }
1194
1408
  export {
1409
+ clearScreenKeepingScrollback,
1195
1410
  runInkChat
1196
1411
  };
1197
- //# sourceMappingURL=inkChat-WYYAFZXD.js.map
1412
+ //# sourceMappingURL=inkChat-UDFX6GH6.js.map
@@ -3,9 +3,9 @@ import {
3
3
  INSTALL_TIMEOUT_MS,
4
4
  installCommand,
5
5
  installServer
6
- } from "./chunk-7TH3NHCQ.js";
6
+ } from "./chunk-ZKT4P2PC.js";
7
7
  import "./chunk-EU7PA45O.js";
8
- import "./chunk-B4SJY7KT.js";
8
+ import "./chunk-LMKGSYJC.js";
9
9
  import "./chunk-BHZ6G65V.js";
10
10
  import "./chunk-P6XWWIEK.js";
11
11
  import "./chunk-UIRJOQQS.js";
@@ -16,4 +16,4 @@ export {
16
16
  installCommand,
17
17
  installServer
18
18
  };
19
- //# sourceMappingURL=install-TKWN5AYH.js.map
19
+ //# sourceMappingURL=install-4ST5BNRG.js.map
@@ -5,18 +5,19 @@ import {
5
5
  msUntil,
6
6
  prepareJob,
7
7
  testsBefore
8
- } from "./chunk-4BVCYCQT.js";
8
+ } from "./chunk-R7RCW4BQ.js";
9
9
  import "./chunk-N4I6YS3E.js";
10
- import "./chunk-UKIE4AAM.js";
10
+ import "./chunk-ULAJPMY7.js";
11
+ import "./chunk-NLS7GMF7.js";
11
12
  import "./chunk-7KBOIPUT.js";
12
13
  import "./chunk-5DEWP3YX.js";
13
14
  import "./chunk-PZS3V6P3.js";
14
- import "./chunk-55CFEEIN.js";
15
- import "./chunk-5B5HDTUR.js";
15
+ import "./chunk-WK5NE6RY.js";
16
+ import "./chunk-TWQ7V2L6.js";
16
17
  import "./chunk-3MRQJKUO.js";
17
18
  import "./chunk-AOGFYUKG.js";
18
- import "./chunk-6XHON3Q6.js";
19
- import "./chunk-B4SJY7KT.js";
19
+ import "./chunk-QXTHEFKP.js";
20
+ import "./chunk-LMKGSYJC.js";
20
21
  import "./chunk-BHZ6G65V.js";
21
22
  import "./chunk-P6XWWIEK.js";
22
23
  import "./chunk-VTMD5IHD.js";
@@ -30,4 +31,4 @@ export {
30
31
  prepareJob,
31
32
  testsBefore
32
33
  };
33
- //# sourceMappingURL=jobCommand-2ODQLHB3.js.map
34
+ //# sourceMappingURL=jobCommand-ILOTYOX3.js.map
@@ -14,9 +14,9 @@ import {
14
14
  removeSpec,
15
15
  specPath,
16
16
  specPlist
17
- } from "./chunk-5B5HDTUR.js";
18
- import "./chunk-6XHON3Q6.js";
19
- import "./chunk-B4SJY7KT.js";
17
+ } from "./chunk-TWQ7V2L6.js";
18
+ import "./chunk-QXTHEFKP.js";
19
+ import "./chunk-LMKGSYJC.js";
20
20
  import "./chunk-BHZ6G65V.js";
21
21
  import "./chunk-P6XWWIEK.js";
22
22
  import "./chunk-VTMD5IHD.js";
@@ -39,4 +39,4 @@ export {
39
39
  specPath,
40
40
  specPlist
41
41
  };
42
- //# sourceMappingURL=launchd-3A3ONEW5.js.map
42
+ //# sourceMappingURL=launchd-QG6R5RAK.js.map
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-36GQIVGT.js";
6
6
  import {
7
7
  installServer
8
- } from "./chunk-7TH3NHCQ.js";
8
+ } from "./chunk-ZKT4P2PC.js";
9
9
  import {
10
10
  LSP_CONFIG_FILE,
11
11
  loadLspConfig
@@ -18,7 +18,7 @@ import {
18
18
  HostExecutor,
19
19
  createExecutor,
20
20
  loadSettings
21
- } from "./chunk-B4SJY7KT.js";
21
+ } from "./chunk-LMKGSYJC.js";
22
22
  import "./chunk-BHZ6G65V.js";
23
23
  import "./chunk-P6XWWIEK.js";
24
24
  import "./chunk-UIRJOQQS.js";
@@ -98,4 +98,4 @@ export {
98
98
  lspInstallCommand,
99
99
  lspStatusCommand
100
100
  };
101
- //# sourceMappingURL=lspCommand-ZZ6R4PA2.js.map
101
+ //# sourceMappingURL=lspCommand-X4FTTONR.js.map
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-4P26OKTP.js";
12
12
  import {
13
13
  VERSION
14
- } from "./chunk-C57GHLKP.js";
14
+ } from "./chunk-CFDRP6XW.js";
15
15
  import {
16
16
  USER_SCOPE
17
17
  } from "./chunk-5DEWP3YX.js";
@@ -34,7 +34,7 @@ import {
34
34
  import {
35
35
  DEFAULT_ENV_ALLOWLIST,
36
36
  sandboxPaths
37
- } from "./chunk-B4SJY7KT.js";
37
+ } from "./chunk-LMKGSYJC.js";
38
38
  import "./chunk-BHZ6G65V.js";
39
39
  import "./chunk-P6XWWIEK.js";
40
40
  import "./chunk-UIRJOQQS.js";
@@ -846,4 +846,4 @@ export {
846
846
  changeLines,
847
847
  warnings
848
848
  };
849
- //# sourceMappingURL=manager-TCYTA5XU.js.map
849
+ //# sourceMappingURL=manager-YH7722C2.js.map
@@ -1,21 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  msUntil
4
- } from "./chunk-4BVCYCQT.js";
4
+ } from "./chunk-R7RCW4BQ.js";
5
5
  import {
6
6
  notificationBytes,
7
7
  pickChannel
8
8
  } from "./chunk-N4I6YS3E.js";
9
- import "./chunk-UKIE4AAM.js";
9
+ import "./chunk-ULAJPMY7.js";
10
+ import "./chunk-NLS7GMF7.js";
10
11
  import "./chunk-7KBOIPUT.js";
11
12
  import "./chunk-5DEWP3YX.js";
12
13
  import "./chunk-PZS3V6P3.js";
13
- import "./chunk-55CFEEIN.js";
14
+ import "./chunk-WK5NE6RY.js";
14
15
  import {
15
16
  defaultAgentEnv,
16
17
  nightSpec,
17
18
  removeSpec
18
- } from "./chunk-5B5HDTUR.js";
19
+ } from "./chunk-TWQ7V2L6.js";
19
20
  import {
20
21
  formatCost,
21
22
  jobCost,
@@ -27,10 +28,10 @@ import {
27
28
  import {
28
29
  hostCommand,
29
30
  shellWord
30
- } from "./chunk-6XHON3Q6.js";
31
+ } from "./chunk-QXTHEFKP.js";
31
32
  import {
32
33
  createExecutor
33
- } from "./chunk-B4SJY7KT.js";
34
+ } from "./chunk-LMKGSYJC.js";
34
35
  import "./chunk-BHZ6G65V.js";
35
36
  import "./chunk-P6XWWIEK.js";
36
37
  import {
@@ -252,4 +253,4 @@ Digest: ${file}`);
252
253
  export {
253
254
  nightCommand
254
255
  };
255
- //# sourceMappingURL=nightCommand-WJU6VZA6.js.map
256
+ //# sourceMappingURL=nightCommand-XPWT6CQZ.js.map