@crouton-kit/humanloop 0.3.27 → 0.3.29

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.
@@ -1 +1 @@
1
- export declare const TERMRENDER_VERSION = "4.0.0";
1
+ export declare const TERMRENDER_VERSION = "4.10.3";
@@ -1 +1 @@
1
- export const TERMRENDER_VERSION = '4.0.0';
1
+ export const TERMRENDER_VERSION = '4.10.3';
package/dist/tui/input.js CHANGED
@@ -151,16 +151,16 @@ function handleItemReview(input, key, state, render) {
151
151
  render();
152
152
  return;
153
153
  }
154
- // Body scroll: u/d or Ctrl+D / Ctrl+U (half-page), Ctrl+E / Ctrl+Y (line).
154
+ // Body scroll: u/d, PageUp/PageDown, or Ctrl+D / Ctrl+U (half-page), Ctrl+E / Ctrl+Y (line).
155
155
  // Plain u/d exists because tmux configs commonly bind C-d/C-u for pane scroll
156
156
  // and intercept them before they reach the app. Render clamps state.scrollOffset,
157
157
  // so over-scroll past the bottom is harmless.
158
- if (input === 'd' || (key.ctrl && (input === 'd' || input === 'e'))) {
158
+ if (input === 'd' || key.pageDown || (key.ctrl && (input === 'd' || input === 'e'))) {
159
159
  state.scrollOffset = (state.scrollOffset ?? 0) + (input === 'e' ? 1 : 10);
160
160
  render();
161
161
  return;
162
162
  }
163
- if (input === 'u' || (key.ctrl && (input === 'u' || input === 'y'))) {
163
+ if (input === 'u' || key.pageUp || (key.ctrl && (input === 'u' || input === 'y'))) {
164
164
  state.scrollOffset = Math.max(0, (state.scrollOffset ?? 0) - (input === 'y' ? 1 : 10));
165
165
  render();
166
166
  return;
@@ -295,6 +295,30 @@ function handleInputMode(input, key, state, render) {
295
295
  }
296
296
  return;
297
297
  }
298
+ if (key.pageDown) {
299
+ state.scrollOffset = (state.scrollOffset ?? 0) + 10;
300
+ render();
301
+ return;
302
+ }
303
+ if (key.pageUp) {
304
+ state.scrollOffset = Math.max(0, (state.scrollOffset ?? 0) - 10);
305
+ render();
306
+ return;
307
+ }
308
+ if (key.downArrow) {
309
+ const next = lineBelowIndex(mode.buffer, mode.cursor);
310
+ if (next !== undefined)
311
+ mode.cursor = next;
312
+ render();
313
+ return;
314
+ }
315
+ if (key.upArrow) {
316
+ const next = lineAboveIndex(mode.buffer, mode.cursor);
317
+ if (next !== undefined)
318
+ mode.cursor = next;
319
+ render();
320
+ return;
321
+ }
298
322
  if (key.return) {
299
323
  const interaction = state.interactions[state.currentIndex];
300
324
  const perOption = interaction.multiSelect === true
@@ -471,6 +495,31 @@ function lineEnd(buffer, cursor) {
471
495
  i++;
472
496
  return i;
473
497
  }
498
+ function lineAboveIndex(buffer, cursor) {
499
+ const chars = [...buffer];
500
+ const at = Math.min(cursor, chars.length);
501
+ const start = lineStart(buffer, at);
502
+ if (start === 0)
503
+ return undefined;
504
+ const column = at - start;
505
+ const previousEnd = start - 1;
506
+ const previousStart = lineStart(buffer, previousEnd);
507
+ return Math.min(previousStart + column, previousEnd);
508
+ }
509
+ function lineBelowIndex(buffer, cursor) {
510
+ const chars = [...buffer];
511
+ const at = Math.min(cursor, chars.length);
512
+ const start = lineStart(buffer, at);
513
+ const column = at - start;
514
+ const end = lineEnd(buffer, at);
515
+ if (end >= chars.length)
516
+ return undefined;
517
+ const nextStart = end + 1;
518
+ let nextEnd = nextStart;
519
+ while (nextEnd < chars.length && chars[nextEnd] !== '\n')
520
+ nextEnd++;
521
+ return Math.min(nextStart + column, nextEnd);
522
+ }
474
523
  // ── Final ────────────────────────────────────────────────────────────────────
475
524
  function handleFinal(input, key, state, render, exit) {
476
525
  if (key.return) {
@@ -269,8 +269,9 @@ export function renderItemReview(state, cols, rows) {
269
269
  `${DIM}space${RESET} expand`,
270
270
  `${DIM}q${RESET} overview`,
271
271
  ];
272
- if (overflows)
273
- footerParts.unshift(`${DIM}u/d${RESET} scroll`);
272
+ if (overflows) {
273
+ footerParts.unshift(state.inputMode ? `${DIM}pgup/pgdn${RESET} scroll` : `${DIM}u/d${RESET} scroll`);
274
+ }
274
275
  const footer = ` ${footerParts.join(' ')}`;
275
276
  // Assemble — pad to fill rows so post-body sits at the bottom
276
277
  const lines = [...preLines, ...visibleBody, ...postLines];
@@ -8,6 +8,8 @@ export interface Key {
8
8
  wordRight: boolean;
9
9
  home: boolean;
10
10
  end: boolean;
11
+ pageUp: boolean;
12
+ pageDown: boolean;
11
13
  /** Forward delete (the Del key / \x1b[3~). */
12
14
  del: boolean;
13
15
  return: boolean;
@@ -8,6 +8,8 @@ function emptyKey() {
8
8
  wordRight: false,
9
9
  home: false,
10
10
  end: false,
11
+ pageUp: false,
12
+ pageDown: false,
11
13
  del: false,
12
14
  return: false,
13
15
  newline: false,
@@ -55,6 +57,14 @@ export function parseKeypress(data) {
55
57
  key.end = true;
56
58
  return { input: '', key };
57
59
  }
60
+ if (str === '\x1b[5~') {
61
+ key.pageUp = true;
62
+ return { input: '', key };
63
+ }
64
+ if (str === '\x1b[6~') {
65
+ key.pageDown = true;
66
+ return { input: '', key };
67
+ }
58
68
  if (str === '\x1b[3~') {
59
69
  key.del = true;
60
70
  return { input: '', key };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crouton-kit/humanloop",
3
- "version": "0.3.27",
3
+ "version": "0.3.29",
4
4
  "description": "Human-in-the-loop decision TUI — agents write questions, humans answer them",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",