dsh-ssh-tui 0.5.3 → 0.5.5

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 (57) hide show
  1. package/README.en.md +36 -10
  2. package/README.md +21 -12
  3. package/lib/approval-reviewer.js +56 -15
  4. package/lib/approval-reviewer.js.map +1 -1
  5. package/lib/auto-approval.js +251 -35
  6. package/lib/auto-approval.js.map +1 -1
  7. package/lib/copy-text.js +62 -0
  8. package/lib/copy-text.js.map +1 -0
  9. package/lib/dsh-compat.js +142 -1
  10. package/lib/dsh-compat.js.map +1 -1
  11. package/lib/footer.js +337 -0
  12. package/lib/footer.js.map +1 -0
  13. package/lib/i18n/en.js +62 -3
  14. package/lib/i18n/en.js.map +1 -1
  15. package/lib/i18n/zh.js +62 -3
  16. package/lib/i18n/zh.js.map +1 -1
  17. package/lib/index.js +7 -5
  18. package/lib/index.js.map +1 -1
  19. package/lib/json-args.js +30 -0
  20. package/lib/json-args.js.map +1 -0
  21. package/lib/paint.js +288 -0
  22. package/lib/paint.js.map +1 -0
  23. package/lib/picker.js +453 -66
  24. package/lib/picker.js.map +1 -1
  25. package/lib/plan.js +369 -0
  26. package/lib/plan.js.map +1 -0
  27. package/lib/quota.js +408 -0
  28. package/lib/quota.js.map +1 -0
  29. package/lib/session-index.js +80 -0
  30. package/lib/session-index.js.map +1 -0
  31. package/lib/session-list.js +210 -88
  32. package/lib/session-list.js.map +1 -1
  33. package/lib/term-text.js +953 -0
  34. package/lib/term-text.js.map +1 -0
  35. package/lib/tool-present.js +744 -0
  36. package/lib/tool-present.js.map +1 -0
  37. package/lib/transcript-types.js +6 -0
  38. package/lib/transcript-types.js.map +1 -0
  39. package/lib/tui.js +643 -3299
  40. package/lib/tui.js.map +1 -1
  41. package/lib/types/approval-reviewer.d.ts +8 -2
  42. package/lib/types/auto-approval.d.ts +28 -0
  43. package/lib/types/copy-text.d.ts +9 -0
  44. package/lib/types/dsh-compat.d.ts +78 -6
  45. package/lib/types/footer.d.ts +155 -0
  46. package/lib/types/json-args.d.ts +7 -0
  47. package/lib/types/paint.d.ts +80 -0
  48. package/lib/types/picker.d.ts +101 -7
  49. package/lib/types/plan.d.ts +80 -0
  50. package/lib/types/quota.d.ts +94 -0
  51. package/lib/types/session-index.d.ts +32 -0
  52. package/lib/types/session-list.d.ts +35 -2
  53. package/lib/types/term-text.d.ts +149 -0
  54. package/lib/types/tool-present.d.ts +165 -0
  55. package/lib/types/transcript-types.d.ts +152 -0
  56. package/lib/types/tui.d.ts +53 -723
  57. package/package.json +20 -18
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paint.js","sourceRoot":"","sources":["../src/paint.ts"],"names":[],"mappings":"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"}
package/lib/picker.js CHANGED
@@ -1,35 +1,321 @@
1
1
  /**
2
- * Startup history-session picker: a small raw-mode selector shown BEFORE the
3
- * main TUI mounts, so launching without an explicit session id lands on a
4
- * choice instead of a fresh main screen.
2
+ * Startup history-session picker: a raw-mode selector shown BEFORE the main
3
+ * TUI mounts, so launching without an explicit session id lands on a choice
4
+ * instead of a fresh main screen.
5
+ *
6
+ * The list itself is not capped. The visible page is always nine rows so
7
+ * digits 1-9 map onto every on-screen item. Arrow keys move a highlight,
8
+ * typing filters by title / id / cwd, and Enter confirms the focused row.
5
9
  */
6
10
  import { StringDecoder } from 'node:string_decoder';
7
- import { formatSessionTime, listResumableSessions } from './session-list.js';
8
- import { isEscapePrefix, truncateToWidth } from './tui.js';
11
+ import { formatSessionTime, listResumableSessionsProgressive } from './session-list.js';
12
+ import { composePaintOutput, isEscapePrefix, pickerWindowStart } from './paint.js';
13
+ import { truncateToWidth } from './term-text.js';
9
14
  import { t } from './i18n/index.js';
10
15
  /**
11
- * Show the picker and wait for one digit, Enter (new session), or a lone
12
- * Esc/Ctrl+C (cancel). Incomplete CSI/SS3 sequences are buffered briefly so
13
- * arrow keys are ignored instead of cancelling. Restores the terminal before
14
- * resolving; an AbortSignal cancels and restores as well.
16
+ * Visible rows in the sliding window. Locked to nine so every on-screen
17
+ * session has a 1-9 shortcut; remaining history is reached with ↑/↓ / filter.
18
+ */
19
+ export const SESSION_PICKER_WINDOW = 9;
20
+ /** Digit shortcuts into the current window when the filter is empty. */
21
+ export const PICKER_QUICK_KEYS = '123456789';
22
+ /** Haystack used by the filter: title, id, cwd, and a live pid when attached. */
23
+ export function sessionSearchHaystack(session) {
24
+ const parts = [session.label, session.id, session.cwd];
25
+ if (session.attach !== undefined) {
26
+ parts.push(String(session.attach.pid), 'pid');
27
+ }
28
+ return parts.join('\n').toLowerCase();
29
+ }
30
+ /** Whether one session matches a whitespace-separated query (every token). */
31
+ export function sessionMatchesQuery(session, query) {
32
+ const tokens = query.trim().toLowerCase().split(/\s+/u).filter(token => token !== '');
33
+ if (tokens.length === 0)
34
+ return true;
35
+ const haystack = sessionSearchHaystack(session);
36
+ return tokens.every(token => haystack.includes(token));
37
+ }
38
+ /** Sessions still visible under the current filter, in list order. */
39
+ export function filterResumableSessions(sessions, query) {
40
+ if (query.trim() === '')
41
+ return [...sessions];
42
+ return sessions.filter(session => sessionMatchesQuery(session, query));
43
+ }
44
+ /** Keep `cursor` inside `[0, total)`. Empty lists pin to 0. */
45
+ export function clampPickerCursor(cursor, total) {
46
+ if (total <= 0)
47
+ return 0;
48
+ return Math.max(0, Math.min(total - 1, cursor));
49
+ }
50
+ /**
51
+ * How many session rows to show. Prefer a full page of nine so 1-9 always
52
+ * map onto every on-screen item. Shrink only when the tty cannot fit that
53
+ * page (title + filter + nine items + hints).
54
+ */
55
+ export function pickerCapacity(rows) {
56
+ const chrome = 7;
57
+ const perItem = 2;
58
+ const available = Math.max(0, rows - chrome);
59
+ return Math.max(1, Math.min(SESSION_PICKER_WINDOW, Math.floor(available / perItem)));
60
+ }
61
+ /** Whether two picker states would paint the same frame. */
62
+ export function pickerStateUnchanged(previous, next) {
63
+ return previous.query === next.query
64
+ && previous.cursor === next.cursor
65
+ && previous.filterActive === next.filterActive
66
+ && previous.sessions === next.sessions
67
+ && previous.loading === next.loading;
68
+ }
69
+ function resultFor(session) {
70
+ return session.attach === undefined
71
+ ? { kind: 'resume', id: session.id }
72
+ : { kind: 'attach', id: session.id, sock: session.attach.sock };
73
+ }
74
+ function continueWith(state) {
75
+ return { kind: 'continue', state };
76
+ }
77
+ function dropLastCodePoint(text) {
78
+ const points = Array.from(text);
79
+ points.pop();
80
+ return points.join('');
81
+ }
82
+ function retainCursor(previousId, filtered, fallback) {
83
+ if (previousId !== undefined) {
84
+ const kept = filtered.findIndex(session => session.id === previousId);
85
+ if (kept >= 0)
86
+ return kept;
87
+ }
88
+ return clampPickerCursor(fallback, filtered.length);
89
+ }
90
+ /**
91
+ * Apply one picker action. Pure: the TTY layer maps keystrokes onto this, and
92
+ * tests drive it without stdin.
93
+ */
94
+ export function stepPicker(state, action, windowSize = SESSION_PICKER_WINDOW) {
95
+ const filtered = filterResumableSessions(state.sessions, state.query);
96
+ const focused = filtered[state.cursor];
97
+ switch (action.type) {
98
+ case 'move': {
99
+ const cursor = clampPickerCursor(state.cursor + action.delta, filtered.length);
100
+ if (cursor === state.cursor)
101
+ return continueWith(state);
102
+ return continueWith({ ...state, cursor });
103
+ }
104
+ case 'page': {
105
+ const cursor = clampPickerCursor(state.cursor + action.delta * Math.max(1, windowSize), filtered.length);
106
+ if (cursor === state.cursor)
107
+ return continueWith(state);
108
+ return continueWith({ ...state, cursor });
109
+ }
110
+ case 'home': {
111
+ if (state.cursor === 0)
112
+ return continueWith(state);
113
+ return continueWith({ ...state, cursor: 0 });
114
+ }
115
+ case 'end': {
116
+ const cursor = Math.max(0, filtered.length - 1);
117
+ if (cursor === state.cursor)
118
+ return continueWith(state);
119
+ return continueWith({ ...state, cursor });
120
+ }
121
+ case 'type': {
122
+ if (action.text === '')
123
+ return continueWith(state);
124
+ const query = `${state.query}${action.text}`;
125
+ const next = filterResumableSessions(state.sessions, query);
126
+ return continueWith({
127
+ ...state,
128
+ query,
129
+ filterActive: true,
130
+ cursor: retainCursor(focused?.id, next, 0),
131
+ });
132
+ }
133
+ case 'backspace': {
134
+ if (state.query === '' && !state.filterActive)
135
+ return continueWith(state);
136
+ if (state.query === '') {
137
+ return continueWith({ ...state, filterActive: false });
138
+ }
139
+ const query = dropLastCodePoint(state.query);
140
+ const next = filterResumableSessions(state.sessions, query);
141
+ return continueWith({
142
+ ...state,
143
+ query,
144
+ filterActive: query !== '',
145
+ cursor: retainCursor(focused?.id, next, state.cursor),
146
+ });
147
+ }
148
+ case 'clearQuery': {
149
+ if (state.query === '' && !state.filterActive)
150
+ return continueWith(state);
151
+ return continueWith({
152
+ ...state,
153
+ query: '',
154
+ filterActive: false,
155
+ cursor: retainCursor(focused?.id, state.sessions, state.cursor),
156
+ });
157
+ }
158
+ case 'startFilter':
159
+ if (state.filterActive)
160
+ return continueWith(state);
161
+ return continueWith({ ...state, filterActive: true });
162
+ case 'quick': {
163
+ if (state.filterActive || state.query !== '') {
164
+ return stepPicker(state, { type: 'type', text: action.key }, windowSize);
165
+ }
166
+ const index = PICKER_QUICK_KEYS.indexOf(action.key);
167
+ if (index < 0)
168
+ return continueWith(state);
169
+ const start = pickerWindowStart(state.cursor, filtered.length, windowSize);
170
+ const session = filtered[start + index];
171
+ if (session === undefined)
172
+ return continueWith(state);
173
+ return { kind: 'done', result: resultFor(session) };
174
+ }
175
+ case 'submit': {
176
+ const session = filtered[state.cursor];
177
+ if (session === undefined)
178
+ return continueWith(state);
179
+ return { kind: 'done', result: resultFor(session) };
180
+ }
181
+ case 'new':
182
+ return { kind: 'done', result: { kind: 'new' } };
183
+ case 'escape':
184
+ if (state.query !== '' || state.filterActive) {
185
+ return stepPicker(state, { type: 'clearQuery' }, windowSize);
186
+ }
187
+ return { kind: 'done', result: null };
188
+ case 'cancel':
189
+ return { kind: 'done', result: null };
190
+ }
191
+ }
192
+ /** Map one decoded stdin chunk (or a complete CSI sequence) to actions. */
193
+ export function actionsForInput(text, state = { query: '', filterActive: false }) {
194
+ if (text === '\x1b[A'
195
+ || text === '\x1bOA'
196
+ || text === '\x10') {
197
+ return [{ type: 'move', delta: -1 }];
198
+ }
199
+ if (text === '\x1b[B'
200
+ || text === '\x1bOB'
201
+ || text === '\x0e') {
202
+ return [{ type: 'move', delta: 1 }];
203
+ }
204
+ if (text === '\x1b[5~')
205
+ return [{ type: 'page', delta: -1 }];
206
+ if (text === '\x1b[6~')
207
+ return [{ type: 'page', delta: 1 }];
208
+ if (text === '\x1b[H' || text === '\x1b[1~')
209
+ return [{ type: 'home' }];
210
+ if (text === '\x1b[F' || text === '\x1b[4~')
211
+ return [{ type: 'end' }];
212
+ if (text === '\x1b' || text === '\x03')
213
+ return [{ type: text === '\x03' ? 'cancel' : 'escape' }];
214
+ if (text.startsWith('\x1b'))
215
+ return [];
216
+ const filtering = state.filterActive || state.query !== '';
217
+ const actions = [];
218
+ for (const char of text) {
219
+ if (char === '\x03') {
220
+ actions.push({ type: 'cancel' });
221
+ continue;
222
+ }
223
+ if (char === '\x1b') {
224
+ actions.push({ type: 'escape' });
225
+ continue;
226
+ }
227
+ if (char === '\r' || char === '\n') {
228
+ actions.push({ type: 'submit' });
229
+ continue;
230
+ }
231
+ if (char === '\x7f' || char === '\x08') {
232
+ actions.push({ type: 'backspace' });
233
+ continue;
234
+ }
235
+ if (char === '\x15' || char === '\x17') {
236
+ actions.push({ type: 'clearQuery' });
237
+ continue;
238
+ }
239
+ if (char === '\x10') {
240
+ actions.push({ type: 'move', delta: -1 });
241
+ continue;
242
+ }
243
+ if (char === '\x0e') {
244
+ actions.push({ type: 'move', delta: 1 });
245
+ continue;
246
+ }
247
+ if (char === '\x06') {
248
+ actions.push({ type: 'startFilter' });
249
+ continue;
250
+ }
251
+ if (char === '/' && !filtering) {
252
+ actions.push({ type: 'startFilter' });
253
+ continue;
254
+ }
255
+ if (char === '0' && !filtering) {
256
+ actions.push({ type: 'new' });
257
+ continue;
258
+ }
259
+ if (char >= '1' && char <= '9' && !filtering) {
260
+ actions.push({ type: 'quick', key: char });
261
+ continue;
262
+ }
263
+ if (char >= ' ' && char !== '\x7f') {
264
+ actions.push({ type: 'type', text: char });
265
+ }
266
+ }
267
+ return actions;
268
+ }
269
+ /** Split a decoded stdin chunk into CSI/SS3 sequences and individual characters. */
270
+ export function splitPickerInput(text) {
271
+ const units = [];
272
+ let index = 0;
273
+ while (index < text.length) {
274
+ if (text[index] !== '\x1b') {
275
+ units.push(text[index] ?? '');
276
+ index += 1;
277
+ continue;
278
+ }
279
+ const rest = text.slice(index);
280
+ const sequence = /^(?:\x1b\[[A-DHF]|\x1b\[[1-6]~|\x1bO[A-D]|\x1b)/u.exec(rest)?.[0];
281
+ if (sequence === undefined) {
282
+ units.push('\x1b');
283
+ index += 1;
284
+ continue;
285
+ }
286
+ units.push(sequence);
287
+ index += sequence.length;
288
+ }
289
+ return units;
290
+ }
291
+ /**
292
+ * Feed a decoded stdin chunk through the picker. CSI / SS3 sequences are one
293
+ * unit; ordinary text is applied character by character so a pasted "fix 2"
294
+ * types the digit instead of treating it as a 1-9 shortcut.
295
+ */
296
+ export function feedPicker(state, text, windowSize = SESSION_PICKER_WINDOW) {
297
+ let current = state;
298
+ for (const unit of splitPickerInput(text)) {
299
+ for (const action of actionsForInput(unit, current)) {
300
+ const step = stepPicker(current, action, windowSize);
301
+ if (step.kind === 'done')
302
+ return step;
303
+ current = step.state;
304
+ }
305
+ }
306
+ return continueWith(current);
307
+ }
308
+ /**
309
+ * Show the picker and wait for a selection, a new-session request, or cancel.
310
+ * Restores the terminal before resolving; an AbortSignal cancels as well.
15
311
  * @param ctx - boot context supplying sessionPersistence.
16
312
  * @param color - whether to apply ANSI colors.
17
313
  * @param signal - optional abort signal (fiber dispose) to cancel the picker.
18
314
  * @returns the selection, or null when cancelled.
19
315
  */
20
316
  export async function showSessionPicker(ctx, color, signal) {
21
- const persistence = ctx.get('sessionPersistence');
22
- if (persistence === undefined) {
23
- process.stderr.write('dsh-ssh-tui: sessionPersistence service is unavailable\n');
24
- return { kind: 'new' };
25
- }
26
- const sessions = await listResumableSessions(persistence, '');
27
317
  if (signal?.aborted)
28
318
  return null;
29
- if (sessions.length === 0) {
30
- process.stdout.write('dsh-ssh-tui: no resumable history sessions; starting a fresh session.\n');
31
- return { kind: 'new' };
32
- }
33
319
  const useAltScreen = process.env.DSH_TUI_NO_ALT_SCREEN !== '1'
34
320
  && process.env.DSH_TUI_NO_ALT_SCREEN !== 'true';
35
321
  const decoder = new StringDecoder('utf8');
@@ -37,35 +323,97 @@ export async function showSessionPicker(ctx, color, signal) {
37
323
  process.stdin.resume();
38
324
  process.stdout.write(`${useAltScreen ? '\x1b[?1049h' : ''}\x1b[?25l`);
39
325
  const style = (text, code) => color ? `\x1b[${code}m${text}\x1b[0m` : text;
40
- const render = () => {
41
- const width = Math.max(20, process.stdout.columns || 80);
326
+ let state = { sessions: [], query: '', cursor: 0, filterActive: false, loading: true };
327
+ let previousRows = [];
328
+ let previousWidth = 0;
329
+ let previousHeight = 0;
330
+ const paintLines = (width, height) => {
331
+ const windowSize = pickerCapacity(height);
332
+ const filtered = filterResumableSessions(state.sessions, state.query);
333
+ const start = pickerWindowStart(state.cursor, filtered.length, windowSize);
334
+ const end = Math.min(filtered.length, start + windowSize);
42
335
  const lines = [
43
336
  style(truncateToWidth(t('picker.title'), width), '1'),
44
337
  '─'.repeat(width),
45
338
  ];
46
- sessions.forEach((session, index) => {
47
- lines.push(style(truncateToWidth(`${index + 1} ${session.label}`, width), '1'));
48
- const attachNote = session.attach === undefined
49
- ? ''
50
- : t('picker.attachable', {
51
- pid: session.attach.pid,
52
- status: session.attach.state === 'running-detached'
53
- ? t('picker.attachRunning')
54
- : t('picker.attachPaused'),
55
- });
56
- const meta = `${session.unreadable === true ? t('resume.unreadable') : ''}${formatSessionTime(session.updatedAt)} · ${session.cwd}`;
57
- if (attachNote !== '') {
58
- lines.push(` ${style(truncateToWidth(attachNote, Math.max(1, width - 3)), '32')}`);
59
- }
60
- lines.push(` ${style(truncateToWidth(meta, Math.max(1, width - 3)), '90')}`);
61
- });
62
- lines.push('');
63
- lines.push(`${style('0', '36')} / ${style('Enter', '36')} ${t('picker.new')}`);
64
- lines.push(`${style('Esc', '36')} ${t('picker.cancel')}`);
65
- process.stdout.write('\x1b[2J\x1b[H');
66
- for (const line of lines) {
67
- process.stdout.write(`${line}\x1b[0m\x1b[K\n`);
339
+ const filtering = state.filterActive || state.query !== '';
340
+ const filterLine = !filtering
341
+ ? t('picker.filterHint')
342
+ : t('picker.filter', { query: state.query === '' ? '' : `${state.query}▌` });
343
+ lines.push(style(truncateToWidth(filterLine, width), filtering ? '36' : '90'));
344
+ lines.push(style(truncateToWidth(t('picker.count', {
345
+ shown: filtered.length,
346
+ total: state.sessions.length,
347
+ }) + (state.loading === true ? t('picker.loading') : ''), width), '90'));
348
+ if (filtered.length === 0) {
349
+ const empty = state.loading === true
350
+ ? t('picker.loadingList')
351
+ : state.query === ''
352
+ ? t('picker.noneYet')
353
+ : t('picker.noMatch', { query: state.query });
354
+ lines.push(style(truncateToWidth(empty, width), '33'));
355
+ }
356
+ else {
357
+ if (start > 0) {
358
+ lines.push(style(truncateToWidth(t('picker.moreAbove', { count: start }), width), '90'));
359
+ }
360
+ for (let index = start; index < end; index += 1) {
361
+ const session = filtered[index];
362
+ if (session === undefined)
363
+ continue;
364
+ const quick = PICKER_QUICK_KEYS[index - start];
365
+ const focused = index === state.cursor;
366
+ const marker = focused ? '›' : ' ';
367
+ const key = quick ?? ' ';
368
+ const label = `${marker}${key} ${session.label}`;
369
+ lines.push(style(truncateToWidth(label, width), focused ? '1;7' : '1'));
370
+ const attachNote = session.attach === undefined
371
+ ? ''
372
+ : t('picker.attachable', {
373
+ pid: session.attach.pid,
374
+ status: session.attach.state === 'running-detached'
375
+ ? t('picker.attachRunning')
376
+ : t('picker.attachPaused'),
377
+ });
378
+ const meta = `${session.unreadable === true ? t('resume.unreadable') : ''}${formatSessionTime(session.updatedAt)} · ${session.cwd}`;
379
+ if (attachNote !== '') {
380
+ lines.push(` ${style(truncateToWidth(attachNote, Math.max(1, width - 3)), '32')}`);
381
+ }
382
+ lines.push(` ${style(truncateToWidth(meta, Math.max(1, width - 3)), '90')}`);
383
+ }
384
+ if (end < filtered.length) {
385
+ lines.push(style(truncateToWidth(t('picker.moreBelow', { count: filtered.length - end }), width), '90'));
386
+ }
68
387
  }
388
+ lines.push('');
389
+ lines.push(style(truncateToWidth(filtering ? t('picker.hintFilter') : t('picker.hint'), width), '36'));
390
+ lines.push(filtering
391
+ ? `${style('Esc', '36')} ${t('picker.cancel')}`
392
+ : `${style('0', '36')} ${t('picker.new')} · ${style('Esc', '36')} ${t('picker.cancel')}`);
393
+ return lines;
394
+ };
395
+ const render = (force = false) => {
396
+ const width = Math.max(20, process.stdout.columns || 80);
397
+ const height = Math.max(12, process.stdout.rows || 24);
398
+ const paintRows = paintLines(width, height);
399
+ const sizeChanged = force || width !== previousWidth || height !== previousHeight;
400
+ const frame = composePaintOutput({
401
+ width,
402
+ height,
403
+ paintRows,
404
+ previousRows,
405
+ sizeChanged,
406
+ chromeChanged: false,
407
+ chromeStart: paintRows.length,
408
+ cursorRow: 1,
409
+ cursorColumn: 1,
410
+ hideCursor: true,
411
+ });
412
+ if (frame !== '')
413
+ process.stdout.write(frame);
414
+ previousRows = paintRows;
415
+ previousWidth = width;
416
+ previousHeight = height;
69
417
  };
70
418
  return new Promise((resolve) => {
71
419
  let done = false;
@@ -79,6 +427,7 @@ export async function showSessionPicker(ctx, color, signal) {
79
427
  clearTimeout(escapeTimer);
80
428
  signal?.removeEventListener('abort', onAbort);
81
429
  process.stdin.removeListener('data', onData);
430
+ process.stdout.removeListener('resize', render);
82
431
  try {
83
432
  process.stdin.setRawMode(false);
84
433
  }
@@ -92,6 +441,22 @@ export async function showSessionPicker(ctx, color, signal) {
92
441
  const onAbort = () => {
93
442
  cleanup(null);
94
443
  };
444
+ const applyChunk = (text) => {
445
+ const windowSize = pickerCapacity(Math.max(12, process.stdout.rows || 24));
446
+ const previous = state;
447
+ const step = feedPicker(state, text, windowSize);
448
+ if (step.kind === 'done') {
449
+ cleanup(step.result);
450
+ return;
451
+ }
452
+ state = step.state;
453
+ if (done)
454
+ return;
455
+ // Held ↑/↓ at the ends used to ED2-clear the whole screen every repeat.
456
+ if (pickerStateUnchanged(previous, state))
457
+ return;
458
+ render();
459
+ };
95
460
  const onData = (chunk) => {
96
461
  const combined = escapeBuffer + decoder.write(chunk);
97
462
  escapeBuffer = '';
@@ -99,10 +464,10 @@ export async function showSessionPicker(ctx, color, signal) {
99
464
  clearTimeout(escapeTimer);
100
465
  escapeTimer = undefined;
101
466
  }
102
- // Ignore complete navigation / function-key sequences.
103
467
  if (/^\x1b\[[A-DHF]$/u.test(combined)
104
468
  || /^\x1b\[[1-6]~$/u.test(combined)
105
469
  || /^\x1bO[A-D]$/u.test(combined)) {
470
+ applyChunk(combined);
106
471
  return;
107
472
  }
108
473
  if (isEscapePrefix(combined)) {
@@ -111,8 +476,7 @@ export async function showSessionPicker(ctx, color, signal) {
111
476
  escapeTimer = undefined;
112
477
  const pending = escapeBuffer;
113
478
  escapeBuffer = '';
114
- if (pending === '\x1b')
115
- cleanup(null);
479
+ applyChunk(pending);
116
480
  }, 60);
117
481
  return;
118
482
  }
@@ -120,25 +484,7 @@ export async function showSessionPicker(ctx, color, signal) {
120
484
  // Unknown / complete escape sequence — ignore rather than cancel.
121
485
  return;
122
486
  }
123
- for (const char of combined) {
124
- if (char === '\x03') {
125
- cleanup(null);
126
- return;
127
- }
128
- if (char === '\r' || char === '\n' || char === '0') {
129
- cleanup({ kind: 'new' });
130
- return;
131
- }
132
- if (char >= '1' && char <= '9') {
133
- const session = sessions[Number(char) - 1];
134
- if (session !== undefined) {
135
- cleanup(session.attach === undefined
136
- ? { kind: 'resume', id: session.id }
137
- : { kind: 'attach', id: session.id, sock: session.attach.sock });
138
- return;
139
- }
140
- }
141
- }
487
+ applyChunk(combined);
142
488
  };
143
489
  if (signal?.aborted) {
144
490
  cleanup(null);
@@ -146,7 +492,48 @@ export async function showSessionPicker(ctx, color, signal) {
146
492
  }
147
493
  signal?.addEventListener('abort', onAbort, { once: true });
148
494
  process.stdin.on('data', onData);
149
- render();
495
+ process.stdout.on('resize', () => { render(true); });
496
+ render(true);
497
+ const applyListing = (listing) => {
498
+ if (done)
499
+ return;
500
+ const focusedId = filterResumableSessions(state.sessions, state.query)[state.cursor]?.id;
501
+ const nextFiltered = filterResumableSessions(listing.sessions, state.query);
502
+ state = {
503
+ ...state,
504
+ sessions: listing.sessions,
505
+ loading: listing.pending,
506
+ cursor: retainCursor(focusedId, nextFiltered, state.cursor),
507
+ };
508
+ render();
509
+ };
510
+ const startListing = async () => {
511
+ let persistence = ctx.get('sessionPersistence');
512
+ if (persistence === undefined) {
513
+ await ctx.get('loader')?.await();
514
+ if (done || signal?.aborted)
515
+ return;
516
+ persistence = ctx.get('sessionPersistence');
517
+ }
518
+ if (persistence === undefined) {
519
+ process.stderr.write(t('picker.noPersistence'));
520
+ cleanup({ kind: 'new' });
521
+ return;
522
+ }
523
+ const listing = await listResumableSessionsProgressive(persistence, '', {
524
+ onUpdate: applyListing,
525
+ });
526
+ if (done)
527
+ return;
528
+ if (listing.complete.length === 0 && state.query === '') {
529
+ cleanup({ kind: 'new' });
530
+ process.stdout.write(t('picker.none'));
531
+ }
532
+ };
533
+ void startListing().catch(() => {
534
+ if (!done)
535
+ cleanup({ kind: 'new' });
536
+ });
150
537
  });
151
538
  }
152
539
  //# sourceMappingURL=picker.js.map