@hydra-acp/cli 0.1.37 → 0.1.39

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/dist/cli.js CHANGED
@@ -308,7 +308,12 @@ var init_config = __esm({
308
308
  // "enqueue" — flips the two: Enter enqueues the prompt (sends
309
309
  // immediately when idle, queues behind an in-flight turn);
310
310
  // Shift+Enter amends the in-flight turn.
311
- defaultEnterAction: z.enum(["enqueue", "amend"]).default("amend")
311
+ defaultEnterAction: z.enum(["enqueue", "amend"]).default("amend"),
312
+ // When true (default), agent_thought events render as dim italic
313
+ // streaming lines beneath the live thinking block. Set false to
314
+ // suppress them — the TUI hotkey ^T toggles this at runtime without
315
+ // persisting back to config.
316
+ showThoughts: z.boolean().default(true)
312
317
  });
313
318
  ExtensionName = z.string().min(1).regex(/^[A-Za-z0-9._-]+$/, "extension name must be filename-safe");
314
319
  ExtensionBody = z.object({
@@ -353,7 +358,8 @@ var init_config = __esm({
353
358
  logMaxBytes: 5 * 1024 * 1024,
354
359
  cwdColumnMaxWidth: 24,
355
360
  progressIndicator: true,
356
- defaultEnterAction: "amend"
361
+ defaultEnterAction: "amend",
362
+ showThoughts: true
357
363
  })
358
364
  });
359
365
  }
@@ -2462,15 +2468,15 @@ var init_session = __esm({
2462
2468
  return count;
2463
2469
  }
2464
2470
  broadcastQueueAdded(entry, options) {
2465
- const depth = this.visibleQueueDepth();
2466
- const position = options?.position ?? Math.max(0, depth - 1);
2471
+ const depth2 = this.visibleQueueDepth();
2472
+ const position = options?.position ?? Math.max(0, depth2 - 1);
2467
2473
  const params = {
2468
2474
  sessionId: this.sessionId,
2469
2475
  messageId: entry.messageId,
2470
2476
  originator: entry.originator,
2471
2477
  prompt: entry.prompt,
2472
2478
  position,
2473
- queueDepth: depth,
2479
+ queueDepth: depth2,
2474
2480
  enqueuedAt: entry.enqueuedAt
2475
2481
  };
2476
2482
  if (options?.amending !== void 0) {
@@ -4935,6 +4941,35 @@ function disabled() {
4935
4941
  }
4936
4942
  return false;
4937
4943
  }
4944
+ function parseVersion(v) {
4945
+ const core = v.split("-", 1)[0] ?? v;
4946
+ const parts = core.split(".");
4947
+ const major = Number(parts[0]);
4948
+ const minor = Number(parts[1]);
4949
+ const patch = Number(parts[2]);
4950
+ if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) {
4951
+ return null;
4952
+ }
4953
+ return [major, minor, patch];
4954
+ }
4955
+ function isNewer(latest, current) {
4956
+ const a = parseVersion(latest);
4957
+ const b = parseVersion(current);
4958
+ if (!a || !b) {
4959
+ return latest !== current;
4960
+ }
4961
+ for (let i = 0; i < 3; i++) {
4962
+ const av = a[i];
4963
+ const bv = b[i];
4964
+ if (av > bv) {
4965
+ return true;
4966
+ }
4967
+ if (av < bv) {
4968
+ return false;
4969
+ }
4970
+ }
4971
+ return false;
4972
+ }
4938
4973
  async function getPendingUpdate() {
4939
4974
  if (cached !== void 0) {
4940
4975
  return cached;
@@ -4950,7 +4985,7 @@ async function getPendingUpdate() {
4950
4985
  pkg: { name: PKG_NAME, version: HYDRA_VERSION }
4951
4986
  });
4952
4987
  const u = notifier.update;
4953
- if (u && typeof u.latest === "string" && typeof u.current === "string" && u.latest !== u.current) {
4988
+ if (u && typeof u.latest === "string" && typeof u.current === "string" && isNewer(u.latest, u.current)) {
4954
4989
  try {
4955
4990
  notifier.config?.set?.("update", u);
4956
4991
  } catch {
@@ -4961,6 +4996,12 @@ async function getPendingUpdate() {
4961
4996
  type: typeof u.type === "string" ? u.type : "unknown"
4962
4997
  };
4963
4998
  } else {
4999
+ if (u && typeof u.latest === "string" && typeof u.current === "string") {
5000
+ try {
5001
+ notifier.config?.set?.("update", void 0);
5002
+ } catch {
5003
+ }
5004
+ }
4964
5005
  cached = null;
4965
5006
  }
4966
5007
  } catch {
@@ -5224,6 +5265,9 @@ var init_input = __esm({
5224
5265
  case "ctrl-p":
5225
5266
  return [{ type: "switch-session" }];
5226
5267
  case "ctrl-t":
5268
+ return [{ type: "toggle-thoughts" }];
5269
+ case "alt-n":
5270
+ case "alt-tab":
5227
5271
  return [{ type: "next-live-session" }];
5228
5272
  case "ctrl-r":
5229
5273
  return this.startHistorySearch();
@@ -5928,6 +5972,38 @@ var init_attachments = __esm({
5928
5972
  }
5929
5973
  });
5930
5974
 
5975
+ // src/tui/sync.ts
5976
+ function beginSync() {
5977
+ if (depth === 0) {
5978
+ process.stdout.write("\x1B[?2026h");
5979
+ }
5980
+ depth++;
5981
+ }
5982
+ function endSync() {
5983
+ if (depth === 0) {
5984
+ return;
5985
+ }
5986
+ depth--;
5987
+ if (depth === 0) {
5988
+ process.stdout.write("\x1B[?2026l");
5989
+ }
5990
+ }
5991
+ function withSync(fn) {
5992
+ beginSync();
5993
+ try {
5994
+ fn();
5995
+ } finally {
5996
+ endSync();
5997
+ }
5998
+ }
5999
+ var depth;
6000
+ var init_sync = __esm({
6001
+ "src/tui/sync.ts"() {
6002
+ "use strict";
6003
+ depth = 0;
6004
+ }
6005
+ });
6006
+
5931
6007
  // src/tui/screen.ts
5932
6008
  import stringWidth from "string-width";
5933
6009
  import wrapAnsi from "wrap-ansi";
@@ -6410,6 +6486,12 @@ function mapKeyName(name) {
6410
6486
  case "ALT_F":
6411
6487
  case "META_F":
6412
6488
  return "alt-f";
6489
+ case "ALT_N":
6490
+ case "META_N":
6491
+ return "alt-n";
6492
+ case "ALT_TAB":
6493
+ case "META_TAB":
6494
+ return "alt-tab";
6413
6495
  case "CTRL_T":
6414
6496
  return "ctrl-t";
6415
6497
  case "SHIFT_TAB":
@@ -6551,6 +6633,9 @@ function mapCsiUToKeyName(code, mod) {
6551
6633
  if (mod === 2) {
6552
6634
  return "shift-tab";
6553
6635
  }
6636
+ if (mod === 3) {
6637
+ return "alt-tab";
6638
+ }
6554
6639
  if (mod === 1) {
6555
6640
  return "tab";
6556
6641
  }
@@ -6581,6 +6666,9 @@ function mapCsiUToKeyName(code, mod) {
6581
6666
  if (code === 102 || code === 70) {
6582
6667
  return "alt-f";
6583
6668
  }
6669
+ if (code === 110 || code === 78) {
6670
+ return "alt-n";
6671
+ }
6584
6672
  return null;
6585
6673
  }
6586
6674
  return null;
@@ -6593,6 +6681,7 @@ var init_screen = __esm({
6593
6681
  init_paths();
6594
6682
  init_session();
6595
6683
  init_attachments();
6684
+ init_sync();
6596
6685
  SESSIONBAR_ROWS = 1;
6597
6686
  BANNER_ROWS = 1;
6598
6687
  SEPARATOR_ROWS = 1;
@@ -6619,6 +6708,11 @@ var init_screen = __esm({
6619
6708
  // the starts of any later keyed blocks if the size changes.
6620
6709
  keyedBlocks = /* @__PURE__ */ new Map();
6621
6710
  streamingActive = false;
6711
+ // When true, lines with bodyStyle="thought" are skipped at draw time
6712
+ // (they remain in `this.lines` so toggling back on reveals them again).
6713
+ // Set via setHideThoughts; the app drives this from the ^T hotkey and
6714
+ // the tui.showThoughts config.
6715
+ hideThoughts = false;
6622
6716
  lastPromptRows = 0;
6623
6717
  queuedTexts = [];
6624
6718
  lastQueueEditingIndex = -1;
@@ -6746,12 +6840,23 @@ var init_screen = __esm({
6746
6840
  this.mouseHandler = (name) => this.handleMouse(name);
6747
6841
  this.rawStdinHandler = (chunk) => this.handleRawStdin(chunk);
6748
6842
  }
6749
- start() {
6843
+ // Starts (or resumes) the screen's painting + input pipeline. When
6844
+ // called fresh from the process entrypoint (no opts), enters the
6845
+ // alternate screen buffer and saves the host shell's cursor for
6846
+ // later restore. When resuming from a picker that ran with
6847
+ // `keepFullscreen: true` (`skipFullscreen: true`), we don't toggle
6848
+ // fullscreen — re-emitting CSI ? 1049 h while already in alt would
6849
+ // (a) clear the alt buffer, briefly showing black before our repaint
6850
+ // lands, and (b) overwrite the cursor save with the picker's last
6851
+ // cursor position, which then becomes wrong on final exit.
6852
+ start(opts = {}) {
6750
6853
  if (this.started) {
6751
6854
  return;
6752
6855
  }
6753
6856
  this.started = true;
6754
- this.term.fullscreen(true);
6857
+ if (!opts.skipFullscreen) {
6858
+ this.term.fullscreen(true);
6859
+ }
6755
6860
  this.lastFrameRows.clear();
6756
6861
  this.lastFrameW = 0;
6757
6862
  this.lastFrameH = 0;
@@ -6774,7 +6879,16 @@ var init_screen = __esm({
6774
6879
  this.writeProgressIndicator(this.banner.status === "busy" ? 3 : 0);
6775
6880
  this.repaint();
6776
6881
  }
6777
- stop() {
6882
+ // Stops the screen's painting + input pipeline. When called from the
6883
+ // process-exit path (no opts), also leaves the alternate screen buffer
6884
+ // and re-enables auto-wrap so the host shell behaves normally. When
6885
+ // entering the session picker (`keepFullscreen: true`), we skip the
6886
+ // alt-screen toggle so the user doesn't see a frame of the host
6887
+ // shell's main-buffer content flash between the live session
6888
+ // tearing down and the picker painting from row 1 — the picker's
6889
+ // moveTo(1,1) + eraseDisplayBelow simply repaints over the same alt
6890
+ // screen buffer the live session was using.
6891
+ stop(opts = {}) {
6778
6892
  if (!this.started) {
6779
6893
  return;
6780
6894
  }
@@ -6795,11 +6909,15 @@ var init_screen = __esm({
6795
6909
  this.term.off("resize", this.resizeHandler);
6796
6910
  this.term.grabInput(false);
6797
6911
  this.term.hideCursor(false);
6798
- process.stdout.write("\x1B[?7h");
6912
+ if (!opts.keepFullscreen) {
6913
+ process.stdout.write("\x1B[?7h");
6914
+ }
6799
6915
  this.writeProgressIndicator(0);
6800
6916
  this.started = false;
6801
- this.term.fullscreen(false);
6802
- this.term("\n");
6917
+ if (!opts.keepFullscreen) {
6918
+ this.term.fullscreen(false);
6919
+ this.term("\n");
6920
+ }
6803
6921
  }
6804
6922
  // Enables bracketed paste mode + modifyOtherKeys on the terminal and
6805
6923
  // rewires stdin so we see the \x1b[200~/\x1b[201~ paste markers and
@@ -7233,8 +7351,27 @@ uncaught: ${err.stack ?? err.message}
7233
7351
  setBanner(banner) {
7234
7352
  this.banner = { ...this.banner, ...banner };
7235
7353
  this.writeProgressIndicator(this.banner.status === "busy" ? 3 : 0);
7236
- this.drawBanner();
7237
- this.placeCursor();
7354
+ this.syncedPartialRepaint(() => this.drawBanner());
7355
+ }
7356
+ // Wrap a partial repaint (banner-only, indicator-only, etc.) in a
7357
+ // synchronized-output bracket so the row swap is atomic on terminals
7358
+ // that support DEC 2026, and hide the cursor across the paint so it
7359
+ // doesn't visibly jump to the row being repainted before placeCursor
7360
+ // snaps it back. placeCursor re-asserts visibility for normal /
7361
+ // scrollback-search / readonly; modal modes only moveTo, so we
7362
+ // re-show explicitly when one of them is active.
7363
+ syncedPartialRepaint(paint) {
7364
+ if (!this.started) {
7365
+ return;
7366
+ }
7367
+ withSync(() => {
7368
+ this.term.hideCursor();
7369
+ paint();
7370
+ this.placeCursor();
7371
+ if (this.permissionPrompt || this.confirmPrompt || this.helpPrompt) {
7372
+ this.term.hideCursor(false);
7373
+ }
7374
+ });
7238
7375
  }
7239
7376
  currentModeId() {
7240
7377
  return this.banner.currentMode;
@@ -7273,11 +7410,9 @@ uncaught: ${err.stack ?? err.message}
7273
7410
  this.bannerNotificationTimer = setTimeout(() => {
7274
7411
  this.bannerNotification = null;
7275
7412
  this.bannerNotificationTimer = null;
7276
- this.drawBanner();
7277
- this.placeCursor();
7413
+ this.syncedPartialRepaint(() => this.drawBanner());
7278
7414
  }, durationMs);
7279
- this.drawBanner();
7280
- this.placeCursor();
7415
+ this.syncedPartialRepaint(() => this.drawBanner());
7281
7416
  }
7282
7417
  // Runtime toggle for terminal mouse capture. With capture on, the
7283
7418
  // wheel drives scrollback but text selection requires shift+drag
@@ -7338,8 +7473,7 @@ uncaught: ${err.stack ?? err.message}
7338
7473
  return;
7339
7474
  }
7340
7475
  this.bannerSearchIndicator = text;
7341
- this.drawBanner();
7342
- this.placeCursor();
7476
+ this.syncedPartialRepaint(() => this.drawBanner());
7343
7477
  }
7344
7478
  // Computes what (if anything) the right-side banner slot should show
7345
7479
  // this paint. Priority: scrollback search term > prompt-history
@@ -7370,6 +7504,17 @@ uncaught: ${err.stack ?? err.message}
7370
7504
  this.scrollOffset = 0;
7371
7505
  this.repaint();
7372
7506
  }
7507
+ // Toggle visibility of agent-thought lines without removing them from
7508
+ // storage. Idempotent — repeated calls with the same value are no-ops.
7509
+ // Reveals are immediate (a repaint runs) so the user sees thoughts
7510
+ // appear / disappear the moment they press ^T.
7511
+ setHideThoughts(hide) {
7512
+ if (this.hideThoughts === hide) {
7513
+ return;
7514
+ }
7515
+ this.hideThoughts = hide;
7516
+ this.repaint();
7517
+ }
7373
7518
  // Forget an upsert key without touching scrollback. The next upsertLines
7374
7519
  // for this key will append at the bottom instead of splicing in place —
7375
7520
  // used to scope a logical block (e.g. an agent's plan) to one turn so
@@ -7509,19 +7654,23 @@ uncaught: ${err.stack ?? err.message}
7509
7654
  // otherwise an in-place prompt redraw is enough. (Queued-zone changes
7510
7655
  // already trigger a full repaint via setQueuedPrompts.) Queue-edit
7511
7656
  // navigation may also change which queued row is marked, so check
7512
- // for that and redraw just that zone in-place.
7657
+ // for that and redraw just that zone in-place. Wrap the per-keystroke
7658
+ // paint in withSync + hide the cursor so the user doesn't see it walk
7659
+ // across the prompt row each frame before snapping back to the typing
7660
+ // position; placeCursor + hideCursor(false) restore it at the end.
7513
7661
  refreshPrompt() {
7514
7662
  if (this.promptRows() !== this.lastPromptRows) {
7515
7663
  this.repaint();
7516
7664
  return;
7517
7665
  }
7518
- const editingIndex = this.dispatcher.state().queueIndex;
7519
- if (editingIndex !== this.lastQueueEditingIndex) {
7520
- this.lastQueueEditingIndex = editingIndex;
7521
- this.drawQueuedZone();
7522
- }
7523
- this.drawPrompt();
7524
- this.placeCursor();
7666
+ this.syncedPartialRepaint(() => {
7667
+ const editingIndex = this.dispatcher.state().queueIndex;
7668
+ if (editingIndex !== this.lastQueueEditingIndex) {
7669
+ this.lastQueueEditingIndex = editingIndex;
7670
+ this.drawQueuedZone();
7671
+ }
7672
+ this.drawPrompt();
7673
+ });
7525
7674
  }
7526
7675
  handleKey(name, data) {
7527
7676
  if (data.isCharacter) {
@@ -7854,10 +8003,20 @@ uncaught: ${err.stack ?? err.message}
7854
8003
  }, this.contentRepaintThrottleMs - elapsed);
7855
8004
  }
7856
8005
  // Funnel for every row that any drawX method renders. Skips emitting
7857
- // moveTo+eraseLineAfter+paint when the row's signature matches the
7858
- // previous frame's. The signature must capture everything that affects
7859
- // visible output for that row (width, FormattedLine fields, banner
7860
- // state, etc.) so identical sigs guarantee identical bytes.
8006
+ // moveTo + paint when the row's signature matches the previous frame's.
8007
+ // The signature must capture everything that affects visible output for
8008
+ // that row (width, FormattedLine fields, banner state, etc.) so
8009
+ // identical sigs guarantee identical bytes.
8010
+ //
8011
+ // Order matters: we move, draw the new content over the old, reset SGR,
8012
+ // then erase from the cursor to end of line. Erasing BEFORE paint
8013
+ // blanks the whole row first — visible as a per-row flash on banner
8014
+ // ticks and single-char prompt edits, since some terminals still
8015
+ // render incrementally inside DEC 2026 brackets. Overwriting first
8016
+ // and erasing only the trailing leftovers means the row is never
8017
+ // blank mid-frame. The styleReset stops the trailing erase from
8018
+ // inheriting the paint's last SGR (a bgBlue selection slice, etc.)
8019
+ // and painting the rest of the line in that colour.
7861
8020
  paintRow(row, signature, paint) {
7862
8021
  if (!this.started) {
7863
8022
  return;
@@ -7869,8 +8028,10 @@ uncaught: ${err.stack ?? err.message}
7869
8028
  return;
7870
8029
  }
7871
8030
  this.lastFrameRows.set(row, signature);
7872
- this.term.moveTo(1, row).eraseLineAfter();
8031
+ this.term.moveTo(1, row);
7873
8032
  paint();
8033
+ this.term.styleReset();
8034
+ this.term.eraseLineAfter();
7874
8035
  }
7875
8036
  repaint() {
7876
8037
  if (!this.started) {
@@ -7895,19 +8056,25 @@ uncaught: ${err.stack ?? err.message}
7895
8056
  this.lastFrameW = w;
7896
8057
  this.lastFrameH = h;
7897
8058
  }
7898
- this.drawScrollback();
7899
- this.drawCompletionZone();
7900
- this.drawQueuedZone();
7901
- this.drawAttachmentChipZone();
7902
- const promptRows = this.promptRows();
7903
- const separatorAbovePromptRow = h - promptRows - BANNER_ROWS - SEPARATOR_ROWS - SESSIONBAR_ROWS;
7904
- this.drawSeparator(separatorAbovePromptRow);
7905
- this.drawPrompt();
7906
- this.drawBanner();
7907
- this.drawSeparator(h - SESSIONBAR_ROWS);
7908
- this.drawSessionbar();
7909
- this.placeCursor();
7910
- this.lastPromptRows = promptRows;
8059
+ withSync(() => {
8060
+ this.term.hideCursor();
8061
+ this.drawScrollback();
8062
+ this.drawCompletionZone();
8063
+ this.drawQueuedZone();
8064
+ this.drawAttachmentChipZone();
8065
+ const promptRows = this.promptRows();
8066
+ const separatorAbovePromptRow = h - promptRows - BANNER_ROWS - SEPARATOR_ROWS - SESSIONBAR_ROWS;
8067
+ this.drawSeparator(separatorAbovePromptRow);
8068
+ this.drawPrompt();
8069
+ this.drawBanner();
8070
+ this.drawSeparator(h - SESSIONBAR_ROWS);
8071
+ this.drawSessionbar();
8072
+ this.placeCursor();
8073
+ if (this.permissionPrompt || this.confirmPrompt || this.helpPrompt) {
8074
+ this.term.hideCursor(false);
8075
+ }
8076
+ this.lastPromptRows = promptRows;
8077
+ });
7911
8078
  }
7912
8079
  drawSessionbar() {
7913
8080
  const w = this.term.width;
@@ -8342,9 +8509,10 @@ uncaught: ${err.stack ?? err.message}
8342
8509
  `\u21E7\u21E5 mode: ${this.banner.currentMode}`
8343
8510
  ) : this.banner.hint;
8344
8511
  this.term(" \xB7 ").dim(hint);
8512
+ this.term.eraseLineAfter();
8345
8513
  if (right) {
8346
8514
  const visibleWidth = stringWidth(right.text);
8347
- const col = Math.max(1, w - visibleWidth + 1);
8515
+ const col = Math.max(1, w - visibleWidth);
8348
8516
  this.term.moveTo(col, row).eraseLineAfter();
8349
8517
  if (right.kind === "search") {
8350
8518
  this.term.brightCyan.noFormat(right.text);
@@ -8437,11 +8605,19 @@ uncaught: ${err.stack ?? err.message}
8437
8605
  // instead of 10k. With `needed = Infinity` this walks everything and
8438
8606
  // doubles as a total-row counter for maxScrollOffset.
8439
8607
  wrapTail(width, needed) {
8608
+ const isThought = (line) => this.hideThoughts && line.bodyStyle === "thought";
8440
8609
  if (width <= 4) {
8441
- const take = Math.min(needed, this.lines.length);
8610
+ const visible = [];
8611
+ for (const line of this.lines) {
8612
+ if (isThought(line)) {
8613
+ continue;
8614
+ }
8615
+ visible.push(line);
8616
+ }
8617
+ const take = Math.min(needed, visible.length);
8442
8618
  return {
8443
- rows: this.lines.slice(this.lines.length - take),
8444
- exhausted: needed >= this.lines.length
8619
+ rows: visible.slice(visible.length - take),
8620
+ exhausted: needed >= visible.length
8445
8621
  };
8446
8622
  }
8447
8623
  if (this.wrapCacheWidth !== width) {
@@ -8454,8 +8630,16 @@ uncaught: ${err.stack ?? err.message}
8454
8630
  const batches = [];
8455
8631
  let total = 0;
8456
8632
  let stoppedAt = 0;
8633
+ let sawOldest = false;
8457
8634
  for (let i = this.lines.length - 1; i >= 0; i--) {
8458
- const wrapped = this.wrapOne(this.lines[i], width);
8635
+ const line = this.lines[i];
8636
+ if (isThought(line)) {
8637
+ if (i === 0) {
8638
+ sawOldest = true;
8639
+ }
8640
+ continue;
8641
+ }
8642
+ const wrapped = this.wrapOne(line, width);
8459
8643
  batches.push(wrapped);
8460
8644
  total += wrapped.length;
8461
8645
  stoppedAt = i;
@@ -8467,7 +8651,7 @@ uncaught: ${err.stack ?? err.message}
8467
8651
  for (let i = batches.length - 1; i >= 0; i--) {
8468
8652
  rows.push(...batches[i]);
8469
8653
  }
8470
- return { rows, exhausted: stoppedAt === 0 };
8654
+ return { rows, exhausted: stoppedAt === 0 || sawOldest };
8471
8655
  }
8472
8656
  wrapOne(line, width) {
8473
8657
  const id = this.lineIds.get(line);
@@ -8655,8 +8839,12 @@ async function pickSession(term, opts) {
8655
8839
  const reserved = 6 + composerRows;
8656
8840
  const maxViewportRows = Math.max(3, termHeight - reserved);
8657
8841
  viewportSize = Math.min(visible.length, maxViewportRows);
8658
- headerLine = formatRow(HEADER, widths, rowMaxWidth, cwdMaxWidth);
8659
- sessionLines = rows.map((r) => formatRow(r, widths, rowMaxWidth, cwdMaxWidth));
8842
+ headerLine = formatRow(HEADER, widths, rowMaxWidth, cwdMaxWidth).padEnd(
8843
+ rowMaxWidth
8844
+ );
8845
+ sessionLines = rows.map(
8846
+ (r) => formatRow(r, widths, rowMaxWidth, cwdMaxWidth).padEnd(rowMaxWidth)
8847
+ );
8660
8848
  };
8661
8849
  const rebuildRows = () => {
8662
8850
  rows = visible.map((s) => toRow(s, Date.now()));
@@ -8777,37 +8965,31 @@ async function pickSession(term, opts) {
8777
8965
  };
8778
8966
  const shortId2 = (sessionId) => stripHydraSessionPrefix(sessionId);
8779
8967
  const paintIndicator = () => {
8780
- term.moveTo(1, indicatorRow()).eraseLineAfter();
8781
- if (mode === "confirm-kill" && pendingAction) {
8782
- term.brightYellow.noFormat(` kill ${shortId2(pendingAction.sessionId)}? [y/N]`);
8783
- return;
8784
- }
8785
- if (mode === "confirm-delete" && pendingAction) {
8786
- term.brightRed.noFormat(` delete ${shortId2(pendingAction.sessionId)}? [y/N]`);
8787
- return;
8788
- }
8789
- if (mode === "busy" && pendingAction) {
8790
- term.dim.noFormat(` working on ${shortId2(pendingAction.sessionId)}\u2026`);
8791
- return;
8792
- }
8793
- if (mode === "rename" && pendingAction) {
8794
- term.brightYellow.noFormat(` title: ${renameBuffer}`);
8795
- term.bgBrightYellow(" ");
8796
- term.dim.noFormat(" Enter saves \xB7 Esc cancels");
8797
- return;
8798
- }
8799
- if (transientStatus !== null) {
8800
- term.dim.noFormat(` ${transientStatus}`);
8801
- return;
8802
- }
8803
- if (searchActive) {
8804
- term.brightYellow.noFormat(` /${searchTerm}`);
8805
- term.bgBrightYellow(" ");
8806
- const hint = visible.length === 0 ? " no matches" : ` ${visible.length} match${visible.length === 1 ? "" : "es"}`;
8807
- term.dim.noFormat(`${hint} \xB7 ^c clears`);
8808
- return;
8809
- }
8810
- term.dim.noFormat(formatIndicator());
8968
+ withSync(() => {
8969
+ term.moveTo(1, indicatorRow());
8970
+ if (mode === "confirm-kill" && pendingAction) {
8971
+ term.brightYellow.noFormat(` kill ${shortId2(pendingAction.sessionId)}? [y/N]`);
8972
+ } else if (mode === "confirm-delete" && pendingAction) {
8973
+ term.brightRed.noFormat(` delete ${shortId2(pendingAction.sessionId)}? [y/N]`);
8974
+ } else if (mode === "busy" && pendingAction) {
8975
+ term.dim.noFormat(` working on ${shortId2(pendingAction.sessionId)}\u2026`);
8976
+ } else if (mode === "rename" && pendingAction) {
8977
+ term.brightYellow.noFormat(` title: ${renameBuffer}`);
8978
+ term.bgBrightYellow(" ");
8979
+ term.dim.noFormat(" Enter saves \xB7 Esc cancels");
8980
+ } else if (transientStatus !== null) {
8981
+ term.dim.noFormat(` ${transientStatus}`);
8982
+ } else if (searchActive) {
8983
+ term.brightYellow.noFormat(` /${searchTerm}`);
8984
+ term.bgBrightYellow(" ");
8985
+ const hint = visible.length === 0 ? " no matches" : ` ${visible.length} match${visible.length === 1 ? "" : "es"}`;
8986
+ term.dim.noFormat(`${hint} \xB7 ^c clears`);
8987
+ } else {
8988
+ term.dim.noFormat(formatIndicator());
8989
+ }
8990
+ term.styleReset();
8991
+ term.eraseLineAfter();
8992
+ });
8811
8993
  };
8812
8994
  const composerBodyRow = (visualOffset) => startRow + 1 + visualOffset;
8813
8995
  const composerBottomRow = () => startRow + composerRows + 1;
@@ -8827,93 +9009,172 @@ async function pickSession(term, opts) {
8827
9009
  renderHelp();
8828
9010
  return;
8829
9011
  }
8830
- computeLayout();
8831
- adjustScroll();
8832
- startRow = 1;
8833
- term.moveTo(1, 1).eraseDisplayBelow();
8834
- paintComposerTopBorder();
8835
- term("\n");
8836
- for (let v = 0; v < composerRows; v++) {
8837
- paintComposerBodyRow(composerWindowStart + v);
9012
+ withSync(() => {
9013
+ term.hideCursor();
9014
+ computeLayout();
9015
+ adjustScroll();
9016
+ startRow = 1;
9017
+ term.moveTo(1, 1).eraseDisplayBelow();
9018
+ paintComposerTopBorder();
8838
9019
  term("\n");
8839
- }
8840
- paintComposerBottomBorder();
8841
- term("\n\n");
8842
- term.dim.noFormat(` ${headerLine}`)("\n");
8843
- for (let v = 0; v < viewportSize; v++) {
8844
- paintSessionRow(scrollOffset + v);
9020
+ for (let v = 0; v < composerRows; v++) {
9021
+ paintComposerBodyRow(composerWindowStart + v);
9022
+ term("\n");
9023
+ }
9024
+ paintComposerBottomBorder();
9025
+ term("\n\n");
9026
+ term.dim.noFormat(` ${headerLine}`)("\n");
9027
+ for (let v = 0; v < viewportSize; v++) {
9028
+ paintSessionRow(scrollOffset + v);
9029
+ term("\n");
9030
+ }
9031
+ paintIndicator();
8845
9032
  term("\n");
8846
- }
8847
- paintIndicator();
8848
- term("\n");
8849
- if (selectedIdx === 0) {
8850
- placeComposerCursor();
8851
- term.hideCursor(false);
8852
- } else {
8853
- term.hideCursor();
8854
- }
9033
+ if (selectedIdx === 0) {
9034
+ placeComposerCursor();
9035
+ term.hideCursor(false);
9036
+ }
9037
+ });
8855
9038
  };
8856
9039
  const renderHelp = () => {
8857
- term.moveTo(1, 1).eraseDisplayBelow();
8858
- term.brightWhite.bold.noFormat(" Picker hotkeys")("\n\n");
8859
- for (const entry of HELP_ENTRIES) {
8860
- if (entry === null) {
8861
- term("\n");
8862
- continue;
9040
+ withSync(() => {
9041
+ term.hideCursor();
9042
+ term.moveTo(1, 1).eraseDisplayBelow();
9043
+ term.brightWhite.bold.noFormat(" Picker hotkeys")("\n\n");
9044
+ for (const entry of HELP_ENTRIES) {
9045
+ if (entry === null) {
9046
+ term("\n");
9047
+ continue;
9048
+ }
9049
+ const [keys, desc] = entry;
9050
+ term.brightCyan.noFormat(` ${keys.padEnd(HELP_KEYS_WIDTH)}`);
9051
+ term.noFormat(desc)("\n");
8863
9052
  }
8864
- const [keys, desc] = entry;
8865
- term.brightCyan.noFormat(` ${keys.padEnd(HELP_KEYS_WIDTH)}`);
8866
- term.noFormat(desc)("\n");
8867
- }
8868
- term("\n");
8869
- term.dim.noFormat(" press any key to dismiss")("\n");
9053
+ term("\n");
9054
+ term.dim.noFormat(" press any key to dismiss")("\n");
9055
+ });
8870
9056
  };
8871
9057
  const repaintComposerChrome = () => {
8872
- term.moveTo(1, startRow).eraseLineAfter();
8873
- paintComposerTopBorder();
8874
- term.moveTo(1, composerBottomRow()).eraseLineAfter();
8875
- paintComposerBottomBorder();
8876
- for (let v = 0; v < composerRows; v++) {
8877
- term.moveTo(1, composerBodyRow(v)).eraseLineAfter();
8878
- paintComposerBodyRow(composerWindowStart + v);
8879
- }
9058
+ withSync(() => {
9059
+ const showCursor = selectedIdx === 0;
9060
+ if (showCursor) {
9061
+ term.hideCursor();
9062
+ }
9063
+ term.moveTo(1, startRow);
9064
+ paintComposerTopBorder();
9065
+ term.moveTo(1, composerBottomRow());
9066
+ paintComposerBottomBorder();
9067
+ for (let v = 0; v < composerRows; v++) {
9068
+ term.moveTo(1, composerBodyRow(v));
9069
+ paintComposerBodyRow(composerWindowStart + v);
9070
+ }
9071
+ if (showCursor) {
9072
+ placeComposerCursor();
9073
+ term.hideCursor(false);
9074
+ }
9075
+ });
8880
9076
  };
8881
9077
  const repaintComposerBody = () => {
8882
- const state = composer.state();
8883
- composerVisualRows = computePromptVisualRows(state.buffer, composerRoom);
8884
- const layout = computePromptLayout(
8885
- composerVisualRows,
8886
- state,
8887
- PICKER_COMPOSER_MAX_ROWS
8888
- );
8889
- composerWindowStart = layout.windowStart;
8890
- composerCursorRow = layout.cursorVisualRow;
8891
- composerCursorCol = layout.cursorVisualCol;
8892
- for (let v = 0; v < composerRows; v++) {
8893
- term.moveTo(1, composerBodyRow(v)).eraseLineAfter();
8894
- paintComposerBodyRow(composerWindowStart + v);
8895
- }
8896
- if (selectedIdx === 0) {
8897
- placeComposerCursor();
8898
- }
9078
+ withSync(() => {
9079
+ const state = composer.state();
9080
+ composerVisualRows = computePromptVisualRows(state.buffer, composerRoom);
9081
+ const layout = computePromptLayout(
9082
+ composerVisualRows,
9083
+ state,
9084
+ PICKER_COMPOSER_MAX_ROWS
9085
+ );
9086
+ composerWindowStart = layout.windowStart;
9087
+ composerCursorRow = layout.cursorVisualRow;
9088
+ composerCursorCol = layout.cursorVisualCol;
9089
+ const showCursor = selectedIdx === 0;
9090
+ if (showCursor) {
9091
+ term.hideCursor();
9092
+ }
9093
+ for (let v = 0; v < composerRows; v++) {
9094
+ term.moveTo(1, composerBodyRow(v));
9095
+ paintComposerBodyRow(composerWindowStart + v);
9096
+ }
9097
+ if (showCursor) {
9098
+ placeComposerCursor();
9099
+ term.hideCursor(false);
9100
+ }
9101
+ });
8899
9102
  };
8900
9103
  const repaintSessionRow = (sessionIdx) => {
8901
9104
  if (sessionIdx < scrollOffset || sessionIdx >= scrollOffset + viewportSize) {
8902
9105
  return;
8903
9106
  }
8904
- term.moveTo(1, sessionRow(sessionIdx)).eraseLineAfter();
8905
- paintSessionRow(sessionIdx);
9107
+ withSync(() => {
9108
+ term.moveTo(1, sessionRow(sessionIdx));
9109
+ paintSessionRow(sessionIdx);
9110
+ });
8906
9111
  };
8907
9112
  const repaintViewport = () => {
8908
- for (let v = 0; v < viewportSize; v++) {
8909
- const row = headerRow() + 1 + v;
8910
- term.moveTo(1, row).eraseLineAfter();
8911
- const sessionIdx = scrollOffset + v;
8912
- if (sessionIdx < visible.length) {
8913
- paintSessionRow(sessionIdx);
9113
+ withSync(() => {
9114
+ for (let v = 0; v < viewportSize; v++) {
9115
+ const row = headerRow() + 1 + v;
9116
+ const sessionIdx = scrollOffset + v;
9117
+ if (sessionIdx < visible.length) {
9118
+ term.moveTo(1, row);
9119
+ paintSessionRow(sessionIdx);
9120
+ } else {
9121
+ term.moveTo(1, row).eraseLineAfter();
9122
+ }
9123
+ }
9124
+ paintIndicator();
9125
+ });
9126
+ };
9127
+ let pasteActive = false;
9128
+ let pasteBuffer = "";
9129
+ let tkStdinHandler = null;
9130
+ const PASTE_START = "\x1B[200~";
9131
+ const PASTE_END = "\x1B[201~";
9132
+ const rawStdinHandler = (chunk) => {
9133
+ let text = chunk.toString("binary");
9134
+ if (pasteActive) {
9135
+ const endIdx = text.indexOf(PASTE_END);
9136
+ if (endIdx === -1) {
9137
+ pasteBuffer += text;
9138
+ return;
9139
+ }
9140
+ pasteBuffer += text.slice(0, endIdx);
9141
+ pasteActive = false;
9142
+ const pasted = Buffer.from(pasteBuffer, "binary").toString("utf-8").replace(/\r\n?/g, "\n");
9143
+ pasteBuffer = "";
9144
+ const remaining = text.slice(endIdx + PASTE_END.length);
9145
+ if (selectedIdx === 0 && !searchActive) {
9146
+ composer.feed({ type: "paste", text: pasted });
9147
+ const after = composer.state();
9148
+ const newVr = computePromptVisualRows(after.buffer, composerRoom);
9149
+ const newLayout = computePromptLayout(
9150
+ newVr,
9151
+ after,
9152
+ PICKER_COMPOSER_MAX_ROWS
9153
+ );
9154
+ if (newLayout.rendered !== composerRows) {
9155
+ renderFromScratch();
9156
+ } else {
9157
+ repaintComposerBody();
9158
+ }
9159
+ }
9160
+ if (remaining.length > 0 && tkStdinHandler) {
9161
+ tkStdinHandler(Buffer.from(remaining, "binary"));
8914
9162
  }
9163
+ return;
9164
+ }
9165
+ const startIdx = text.indexOf(PASTE_START);
9166
+ if (startIdx === -1) {
9167
+ tkStdinHandler?.(chunk);
9168
+ return;
9169
+ }
9170
+ if (startIdx > 0) {
9171
+ tkStdinHandler?.(Buffer.from(text.slice(0, startIdx), "binary"));
9172
+ }
9173
+ text = text.slice(startIdx + PASTE_START.length);
9174
+ pasteActive = true;
9175
+ if (text.length > 0) {
9176
+ rawStdinHandler(Buffer.from(text, "binary"));
8915
9177
  }
8916
- paintIndicator();
8917
9178
  };
8918
9179
  renderFromScratch();
8919
9180
  return await new Promise((resolve6) => {
@@ -8931,6 +9192,15 @@ async function pickSession(term, opts) {
8931
9192
  resolved = true;
8932
9193
  term.off("key", onKey);
8933
9194
  term.off("resize", onResize);
9195
+ process.stdout.write("\x1B[?2004l");
9196
+ const tClean = term;
9197
+ if (tClean.stdin && tkStdinHandler) {
9198
+ tClean.stdin.removeListener("data", rawStdinHandler);
9199
+ tClean.stdin.on("data", tkStdinHandler);
9200
+ tkStdinHandler = null;
9201
+ }
9202
+ pasteActive = false;
9203
+ pasteBuffer = "";
8934
9204
  term.grabInput(false);
8935
9205
  term.hideCursor(false);
8936
9206
  term.moveTo(1, indicatorRow() + 1);
@@ -9035,18 +9305,20 @@ async function pickSession(term, opts) {
9035
9305
  const oldScroll = scrollOffset;
9036
9306
  selectedIdx = next;
9037
9307
  adjustScroll();
9038
- if (scrollOffset !== oldScroll) {
9039
- repaintViewport();
9308
+ withSync(() => {
9309
+ if (scrollOffset !== oldScroll) {
9310
+ repaintViewport();
9311
+ onFocusChange(old, selectedIdx);
9312
+ return;
9313
+ }
9314
+ if (old !== 0) {
9315
+ repaintSessionRow(old - 1);
9316
+ }
9317
+ if (selectedIdx !== 0) {
9318
+ repaintSessionRow(selectedIdx - 1);
9319
+ }
9040
9320
  onFocusChange(old, selectedIdx);
9041
- return;
9042
- }
9043
- if (old !== 0) {
9044
- repaintSessionRow(old - 1);
9045
- }
9046
- if (selectedIdx !== 0) {
9047
- repaintSessionRow(selectedIdx - 1);
9048
- }
9049
- onFocusChange(old, selectedIdx);
9321
+ });
9050
9322
  };
9051
9323
  const clearTransient = () => {
9052
9324
  if (transientStatus === null) {
@@ -9370,10 +9642,12 @@ async function pickSession(term, opts) {
9370
9642
  switch (name) {
9371
9643
  case "UP":
9372
9644
  case "SHIFT_TAB":
9645
+ case "CTRL_P":
9373
9646
  move(-1);
9374
9647
  return;
9375
9648
  case "DOWN":
9376
9649
  case "TAB":
9650
+ case "CTRL_N":
9377
9651
  move(1);
9378
9652
  return;
9379
9653
  case "PAGE_UP":
@@ -9419,6 +9693,13 @@ async function pickSession(term, opts) {
9419
9693
  }
9420
9694
  };
9421
9695
  term.grabInput({});
9696
+ const tSetup = term;
9697
+ if (tSetup.stdin && typeof tSetup.onStdin === "function") {
9698
+ tkStdinHandler = tSetup.onStdin;
9699
+ tSetup.stdin.removeListener("data", tSetup.onStdin);
9700
+ tSetup.stdin.on("data", rawStdinHandler);
9701
+ process.stdout.write("\x1B[?2004h");
9702
+ }
9422
9703
  term.on("key", onKey);
9423
9704
  term.on("resize", onResize);
9424
9705
  });
@@ -9491,6 +9772,7 @@ var init_picker = __esm({
9491
9772
  init_discovery();
9492
9773
  init_input();
9493
9774
  init_screen();
9775
+ init_sync();
9494
9776
  ROW_PREFIX_WIDTH = 2;
9495
9777
  PICKER_COMPOSER_MAX_ROWS = 4;
9496
9778
  BOX_HORIZONTAL_PAD = 4;
@@ -9499,7 +9781,7 @@ var init_picker = __esm({
9499
9781
  ["Composer", "type prompt for new session; Enter creates + submits"],
9500
9782
  ["\u2193 from composer", "drop focus into session list"],
9501
9783
  null,
9502
- ["\u2191 / \u2193 or n / p", "navigate sessions"],
9784
+ ["\u2191 / \u2193, n / p, ^p / ^n", "navigate sessions"],
9503
9785
  ["PgUp / PgDn", "page up / page down"],
9504
9786
  ["Home / End", "first / last"],
9505
9787
  ["Enter", "open selected session"],
@@ -10853,9 +11135,12 @@ async function runTuiApp(opts) {
10853
11135
  }
10854
11136
  const term = termkit.terminal;
10855
11137
  const exitHint = {};
11138
+ const viewPrefs = {
11139
+ showThoughts: config.tui.showThoughts
11140
+ };
10856
11141
  let nextOpts = opts;
10857
11142
  while (nextOpts !== null) {
10858
- nextOpts = await runSession(term, config, target, nextOpts, exitHint);
11143
+ nextOpts = await runSession(term, config, target, nextOpts, exitHint, viewPrefs);
10859
11144
  }
10860
11145
  const pendingUpdate = await getPendingUpdate();
10861
11146
  if (pendingUpdate) {
@@ -10872,7 +11157,7 @@ async function runTuiApp(opts) {
10872
11157
  );
10873
11158
  }
10874
11159
  }
10875
- async function runSession(term, config, target, opts, exitHint) {
11160
+ async function runSession(term, config, target, opts, exitHint, viewPrefs) {
10876
11161
  const ctx = await resolveSession(term, config, target, opts);
10877
11162
  if (!ctx) {
10878
11163
  term.grabInput(false);
@@ -11584,6 +11869,7 @@ async function runSession(term, config, target, opts, exitHint) {
11584
11869
  const usage = { ...initialUsage ?? {} };
11585
11870
  installStatus.finalize();
11586
11871
  screen.start();
11872
+ screen.setHideThoughts(!viewPrefs.showThoughts);
11587
11873
  screen.setSessionbar({
11588
11874
  agent: sessionbarAgent,
11589
11875
  cwd: resolvedCwd,
@@ -11754,7 +12040,7 @@ async function runSession(term, config, target, opts, exitHint) {
11754
12040
  dispatcher.setHistory(history);
11755
12041
  }
11756
12042
  screen.pauseRepaint();
11757
- screen.stop();
12043
+ screen.stop({ keepFullscreen: true });
11758
12044
  saveHistory(historyFile, history).catch(() => void 0);
11759
12045
  let resolvedChoice = null;
11760
12046
  let attachOverrides = null;
@@ -11768,7 +12054,7 @@ async function runSession(term, config, target, opts, exitHint) {
11768
12054
  currentSessionId: resolvedSessionId
11769
12055
  });
11770
12056
  if (choice2.kind === "abort") {
11771
- screen.start();
12057
+ screen.start({ skipFullscreen: true });
11772
12058
  screen.resumeRepaint();
11773
12059
  return;
11774
12060
  }
@@ -11785,7 +12071,7 @@ async function runSession(term, config, target, opts, exitHint) {
11785
12071
  const opsShim = { ...opts, readonly: false };
11786
12072
  const decided = await runImportedFirstLaunchFlow(term, chosen, choice2, opsShim);
11787
12073
  if (decided.kind === "cancel") {
11788
- screen.start();
12074
+ screen.start({ skipFullscreen: true });
11789
12075
  screen.resumeRepaint();
11790
12076
  return;
11791
12077
  }
@@ -11969,6 +12255,13 @@ async function runSession(term, config, target, opts, exitHint) {
11969
12255
  toolsExpanded = !toolsExpanded;
11970
12256
  renderToolsBlock();
11971
12257
  return;
12258
+ case "toggle-thoughts":
12259
+ viewPrefs.showThoughts = !viewPrefs.showThoughts;
12260
+ screen.setHideThoughts(!viewPrefs.showThoughts);
12261
+ screen.notify(
12262
+ viewPrefs.showThoughts ? "thoughts shown" : "thoughts hidden"
12263
+ );
12264
+ return;
11972
12265
  case "toggle-mouse": {
11973
12266
  const next = !screen.isMouseEnabled();
11974
12267
  screen.setMouseEnabled(next);
@@ -13163,7 +13456,8 @@ var init_app = __esm({
13163
13456
  ["^Y", "yank last kill"],
13164
13457
  null,
13165
13458
  ["^P", "switch session (picker)"],
13166
- ["^T", "next live session"],
13459
+ ["Alt+N / Alt+Tab", "next live session"],
13460
+ ["^T", "show / hide thoughts"],
13167
13461
  ["^V", "paste image from clipboard"],
13168
13462
  ["^O", "expand / collapse tools block"],
13169
13463
  null,
package/dist/index.d.ts CHANGED
@@ -106,6 +106,7 @@ declare const HydraConfig: z.ZodObject<{
106
106
  cwdColumnMaxWidth: z.ZodDefault<z.ZodNumber>;
107
107
  progressIndicator: z.ZodDefault<z.ZodBoolean>;
108
108
  defaultEnterAction: z.ZodDefault<z.ZodEnum<["enqueue", "amend"]>>;
109
+ showThoughts: z.ZodDefault<z.ZodBoolean>;
109
110
  }, "strip", z.ZodTypeAny, {
110
111
  repaintThrottleMs: number;
111
112
  maxScrollbackLines: number;
@@ -114,6 +115,7 @@ declare const HydraConfig: z.ZodObject<{
114
115
  cwdColumnMaxWidth: number;
115
116
  progressIndicator: boolean;
116
117
  defaultEnterAction: "enqueue" | "amend";
118
+ showThoughts: boolean;
117
119
  }, {
118
120
  repaintThrottleMs?: number | undefined;
119
121
  maxScrollbackLines?: number | undefined;
@@ -122,6 +124,7 @@ declare const HydraConfig: z.ZodObject<{
122
124
  cwdColumnMaxWidth?: number | undefined;
123
125
  progressIndicator?: boolean | undefined;
124
126
  defaultEnterAction?: "enqueue" | "amend" | undefined;
127
+ showThoughts?: boolean | undefined;
125
128
  }>>;
126
129
  }, "strip", z.ZodTypeAny, {
127
130
  tui: {
@@ -132,6 +135,7 @@ declare const HydraConfig: z.ZodObject<{
132
135
  cwdColumnMaxWidth: number;
133
136
  progressIndicator: boolean;
134
137
  defaultEnterAction: "enqueue" | "amend";
138
+ showThoughts: boolean;
135
139
  };
136
140
  daemon: {
137
141
  host: string;
@@ -170,6 +174,7 @@ declare const HydraConfig: z.ZodObject<{
170
174
  cwdColumnMaxWidth?: number | undefined;
171
175
  progressIndicator?: boolean | undefined;
172
176
  defaultEnterAction?: "enqueue" | "amend" | undefined;
177
+ showThoughts?: boolean | undefined;
173
178
  } | undefined;
174
179
  daemon?: {
175
180
  host?: string | undefined;
package/dist/index.js CHANGED
@@ -216,7 +216,12 @@ var TuiConfig = z.object({
216
216
  // "enqueue" — flips the two: Enter enqueues the prompt (sends
217
217
  // immediately when idle, queues behind an in-flight turn);
218
218
  // Shift+Enter amends the in-flight turn.
219
- defaultEnterAction: z.enum(["enqueue", "amend"]).default("amend")
219
+ defaultEnterAction: z.enum(["enqueue", "amend"]).default("amend"),
220
+ // When true (default), agent_thought events render as dim italic
221
+ // streaming lines beneath the live thinking block. Set false to
222
+ // suppress them — the TUI hotkey ^T toggles this at runtime without
223
+ // persisting back to config.
224
+ showThoughts: z.boolean().default(true)
220
225
  });
221
226
  var ExtensionName = z.string().min(1).regex(/^[A-Za-z0-9._-]+$/, "extension name must be filename-safe");
222
227
  var ExtensionBody = z.object({
@@ -261,7 +266,8 @@ var HydraConfig = z.object({
261
266
  logMaxBytes: 5 * 1024 * 1024,
262
267
  cwdColumnMaxWidth: 24,
263
268
  progressIndicator: true,
264
- defaultEnterAction: "amend"
269
+ defaultEnterAction: "amend",
270
+ showThoughts: true
265
271
  })
266
272
  });
267
273
  function extensionList(config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hydra-acp/cli",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Multi-client ACP session daemon: spawn agents, attach over WSS, multiplex sessions across editors.",
5
5
  "license": "MIT",
6
6
  "type": "module",