@bahulam/code 2.6.14 → 2.6.16

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.
@@ -30,6 +30,8 @@ import {
30
30
  resumeModeLabel,
31
31
  resumeTailTurnCount,
32
32
  startResumeProgress,
33
+ writeOverlayFrame,
34
+ eraseOverlayFrame,
33
35
  } from './repl-format.mjs';
34
36
  import { TarangStreamClient } from '../core/stream-client.mjs';
35
37
  import { getRecentSessions, getSessionDetail, buildResumeHistory, combineResumeSummaries } from '../core/local-store.mjs';
@@ -86,9 +88,6 @@ export async function pickResumableSession(resumable, ctx) {
86
88
  let renderedLines = 0;
87
89
 
88
90
  const renderMenu = () => {
89
- if (renderedLines > 0) {
90
- process.stderr.write(`\x1b[${renderedLines}F\r\x1b[J`);
91
- }
92
91
  if (selected < offset) offset = selected;
93
92
  if (selected >= offset + pageSize) offset = selected - pageSize + 1;
94
93
 
@@ -119,13 +118,19 @@ export async function pickResumableSession(resumable, ctx) {
119
118
  ` ${c.dim(`↑↓ move · Enter resume · P preview · Esc cancel · ${selected + 1}/${resumable.length}`)}`,
120
119
  cols - 1
121
120
  ));
122
- process.stderr.write(lines.join('\n') + '\n');
121
+ writeOverlayFrame(renderedLines, lines);
123
122
  renderedLines = lines.length;
124
123
  };
125
124
 
126
125
  const cleanup = (value) => {
127
126
  process.stdin.removeListener('data', onData);
128
127
  process.stdin.setRawMode(wasRaw || false);
128
+ // Collapse the list to one line: picked → which session; preview →
129
+ // erase only (preview overlay paints next); cancel → caller reports.
130
+ const picked = value?.action === 'resume' ? value.session : null;
131
+ eraseOverlayFrame(renderedLines, picked
132
+ ? ` ${c.green('↺')} ${c.brand(picked.project || '(unknown)')} ${c.dim(`· ${picked.messageCount} msgs · resuming…`)}`
133
+ : '');
129
134
  if (rl) rl.resume();
130
135
  resolve(value);
131
136
  };
@@ -183,7 +188,6 @@ export async function chooseThresholdMode(ctx, decision) {
183
188
  let renderedLines = 0;
184
189
 
185
190
  const render = () => {
186
- if (renderedLines > 0) process.stderr.write(`\x1b[${renderedLines}F\r\x1b[J`);
187
191
  const cols = Math.max(60, process.stderr.columns || 120);
188
192
  const pct = Math.round(decision.usageRatio * 100);
189
193
  const projected = formatCtxTokens(decision.projected);
@@ -221,13 +225,16 @@ export async function chooseThresholdMode(ctx, decision) {
221
225
  }
222
226
  lines.push('');
223
227
  lines.push(fitAnsiLine(` ${c.dim('↑↓ move · Enter pick · f/s/1/2 shortcut · Esc cancel')}`, cols - 1));
224
- process.stderr.write(lines.join('\n') + '\n');
228
+ writeOverlayFrame(renderedLines, lines);
225
229
  renderedLines = lines.length;
226
230
  };
227
231
 
228
232
  const cleanup = (value) => {
229
233
  process.stdin.removeListener('data', onData);
230
234
  process.stdin.setRawMode(wasRaw || false);
235
+ eraseOverlayFrame(renderedLines, value
236
+ ? ` ${c.dim('mode:')} ${c.brand(resumeModeLabel(value))}`
237
+ : '');
231
238
  if (rl) rl.resume();
232
239
  resolve(value);
233
240
  };
@@ -281,7 +288,6 @@ export async function previewResumeSession(session, ctx) {
281
288
  let scrollOffset = 0;
282
289
 
283
290
  const render = () => {
284
- if (renderedLines > 0) process.stderr.write(`\x1b[${renderedLines}F\r\x1b[J`);
285
291
  const cols = Math.max(60, process.stderr.columns || 120);
286
292
  const rows = Math.max(10, Math.min((process.stderr.rows || 30) - 6, 20));
287
293
  const contentLines = (history.summary || '').split('\n');
@@ -305,13 +311,14 @@ export async function previewResumeSession(session, ctx) {
305
311
  }
306
312
  lines.push('');
307
313
  lines.push(fitAnsiLine(` ${c.dim(`↑↓/PgUp/PgDn scroll · f/s/1/2 switch mode · Enter resume this · q back · ${scrollOffset + 1}-${Math.min(scrollOffset + rows, totalLines)}/${totalLines}`)}`, cols - 1));
308
- process.stderr.write(lines.join('\n') + '\n');
314
+ writeOverlayFrame(renderedLines, lines);
309
315
  renderedLines = lines.length;
310
316
  };
311
317
 
312
318
  const cleanup = (value) => {
313
319
  process.stdin.removeListener('data', onData);
314
320
  process.stdin.setRawMode(wasRaw || false);
321
+ eraseOverlayFrame(renderedLines);
315
322
  if (rl) rl.resume();
316
323
  resolve(value);
317
324
  };
@@ -343,9 +350,12 @@ export async function previewResumeSession(session, ctx) {
343
350
  */
344
351
  export async function confirmCwdSwitch(ctx, savedPath, currentPath) {
345
352
  if (!process.stdin.isTTY) return 'switch';
346
- process.stderr.write(`\n ${c.dim('This session lives in another repo:')}\n`);
347
- process.stderr.write(` ${c.dim('→')} ${c.brand(savedPath)} ${c.dim(`(current cwd: ${currentPath})`)}\n`);
348
- process.stderr.write(` ${c.dim('[Enter]')} switch cwd and resume · ${c.dim('[s]')} stay here and resume anyway · ${c.dim('[n]')} cancel `);
353
+ const frame = [
354
+ ` ${c.dim('This session lives in another repo:')}`,
355
+ ` ${c.dim('')} ${c.brand(savedPath)} ${c.dim(`(current cwd: ${currentPath})`)}`,
356
+ ` ${c.dim('[Enter]')} switch cwd and resume · ${c.dim('[s]')} stay here and resume anyway · ${c.dim('[n]')} cancel`,
357
+ ];
358
+ writeOverlayFrame(0, frame);
349
359
  const rl = ctx._rl || null;
350
360
  if (rl) rl.pause();
351
361
  return await new Promise((resolve) => {
@@ -353,8 +363,13 @@ export async function confirmCwdSwitch(ctx, savedPath, currentPath) {
353
363
  const cleanup = (value) => {
354
364
  process.stdin.removeListener('data', onData);
355
365
  process.stdin.setRawMode(wasRaw || false);
366
+ const summary = value === 'switch'
367
+ ? ` ${c.dim('cwd →')} ${c.brand(savedPath)}`
368
+ : value === 'stay'
369
+ ? ` ${c.dim(`staying in ${currentPath}`)}`
370
+ : '';
371
+ eraseOverlayFrame(frame.length, summary);
356
372
  if (rl) rl.resume();
357
- process.stderr.write('\n');
358
373
  resolve(value);
359
374
  };
360
375
  const onData = (data) => {
@@ -39,6 +39,7 @@ export const runtime = {
39
39
  pendingHead: null, // { callId, head, indent } buffered until result arrives
40
40
  lastRenderedBlock: null, // 'tool' | 'content' | 'thinking' | 'status' | 'plan' | null
41
41
  renderedToolResults: new Set(),
42
+ renderedFileDiffPreviews: new Set(),
42
43
 
43
44
  // Explore-run collapse (read/list/search/index bursts as concise progress).
44
45
  exploreRun: { counts: {}, recent: [], lineActive: false, lastPrintedSummary: '', lastPrintedTotal: 0, lastPrintedAt: 0 },
@@ -48,6 +49,19 @@ export const runtime = {
48
49
  spinInterval: null,
49
50
  spinText: '',
50
51
  spinFrame: 0,
52
+ // Activity phase tracking — elapsed time + progress counters on the
53
+ // status line. spinPhase changes reset spinStartedAt; text updates
54
+ // within the same phase keep the clock running so "thinking · 14s"
55
+ // and "explore agent · 32s · 12 calls" count up live.
56
+ spinPhase: null, // 'thinking' | 'status' | `tool:<id>` | `sub:<type>` | null
57
+ spinStartedAt: 0, // Date.now() when the current phase began
58
+ spinToolCalls: 0, // per-phase tool-call counter (sub-agents)
59
+
60
+ // Sub-agent live tool window: while a sub-agent runs (queue active),
61
+ // its inner tool calls stream into a fixed-height status block (last
62
+ // N lines under the spinner) instead of appending to the transcript.
63
+ // Full detail stays on the recorded cards (/expand, /last, `d`).
64
+ subAgentWindow: { active: false, lines: [] },
51
65
  };
52
66
 
53
67
  // Full session state for the current CLI process. Set by the REPL loop
@@ -89,6 +103,8 @@ export const session = {
89
103
  totalCost: 0, // accumulated session cost (USD)
90
104
  costAccurate: false, // true if backend provides per-model breakdown
91
105
  modelOverrides: {}, // session-local role -> model overrides sent to backend
106
+ modelMode: null, // named mode (fast|thinking|extra|max) sent as model_mode
107
+ routePreference: null, // --route platform|byok; controls catalog validation only
92
108
  isByok: false, // set from session_info; hides cost + credits when true
93
109
  // ── Subscription / credit state (server-authoritative; set from
94
110
  // session_info + complete events) ──