@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 +466 -172
- package/dist/index.d.ts +5 -0
- package/dist/index.js +8 -2
- package/package.json +1 -1
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
|
|
2466
|
-
const position = options?.position ?? Math.max(0,
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6912
|
+
if (!opts.keepFullscreen) {
|
|
6913
|
+
process.stdout.write("\x1B[?7h");
|
|
6914
|
+
}
|
|
6799
6915
|
this.writeProgressIndicator(0);
|
|
6800
6916
|
this.started = false;
|
|
6801
|
-
|
|
6802
|
-
|
|
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
|
-
|
|
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
|
-
|
|
7519
|
-
|
|
7520
|
-
this.lastQueueEditingIndex
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
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+
|
|
7858
|
-
//
|
|
7859
|
-
//
|
|
7860
|
-
//
|
|
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)
|
|
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
|
-
|
|
7899
|
-
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
|
|
7903
|
-
|
|
7904
|
-
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
|
|
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
|
|
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
|
|
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:
|
|
8444
|
-
exhausted: needed >=
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
|
|
8786
|
-
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
|
|
8796
|
-
|
|
8797
|
-
|
|
8798
|
-
|
|
8799
|
-
|
|
8800
|
-
|
|
8801
|
-
|
|
8802
|
-
|
|
8803
|
-
|
|
8804
|
-
|
|
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
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
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
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
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
|
-
|
|
8848
|
-
|
|
8849
|
-
|
|
8850
|
-
|
|
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
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
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
|
-
|
|
8865
|
-
term.
|
|
8866
|
-
|
|
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
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
term.moveTo(1,
|
|
8878
|
-
|
|
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
|
-
|
|
8883
|
-
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
8890
|
-
|
|
8891
|
-
|
|
8892
|
-
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
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
|
-
|
|
8905
|
-
|
|
9107
|
+
withSync(() => {
|
|
9108
|
+
term.moveTo(1, sessionRow(sessionIdx));
|
|
9109
|
+
paintSessionRow(sessionIdx);
|
|
9110
|
+
});
|
|
8906
9111
|
};
|
|
8907
9112
|
const repaintViewport = () => {
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
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
|
-
|
|
9039
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
["
|
|
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) {
|