myshell-tools 2.0.0-alpha.0 → 2.1.0

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 (60) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +6 -3
  3. package/dist/cli.js +85 -30
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/doctor.d.ts +3 -2
  6. package/dist/commands/doctor.js +9 -5
  7. package/dist/commands/doctor.js.map +1 -1
  8. package/dist/commands/login.d.ts +20 -0
  9. package/dist/commands/login.js +60 -0
  10. package/dist/commands/login.js.map +1 -0
  11. package/dist/core/orchestrate.js +80 -28
  12. package/dist/core/orchestrate.js.map +1 -1
  13. package/dist/core/policy.d.ts +10 -0
  14. package/dist/core/policy.js +40 -0
  15. package/dist/core/policy.js.map +1 -1
  16. package/dist/core/review.d.ts +5 -0
  17. package/dist/core/review.js +2 -2
  18. package/dist/core/review.js.map +1 -1
  19. package/dist/infra/atomic.d.ts +0 -3
  20. package/dist/infra/atomic.js +1 -1
  21. package/dist/infra/atomic.js.map +1 -1
  22. package/dist/infra/config.d.ts +23 -0
  23. package/dist/infra/config.js +64 -0
  24. package/dist/infra/config.js.map +1 -0
  25. package/dist/infra/conversation-store.d.ts +42 -0
  26. package/dist/infra/conversation-store.js +14 -0
  27. package/dist/infra/conversation-store.js.map +1 -0
  28. package/dist/infra/conversations.d.ts +18 -0
  29. package/dist/infra/conversations.js +296 -0
  30. package/dist/infra/conversations.js.map +1 -0
  31. package/dist/infra/insights.d.ts +66 -0
  32. package/dist/infra/insights.js +105 -0
  33. package/dist/infra/insights.js.map +1 -0
  34. package/dist/infra/ledger.d.ts +4 -6
  35. package/dist/infra/ledger.js.map +1 -1
  36. package/dist/interface/menu.d.ts +112 -0
  37. package/dist/interface/menu.js +622 -0
  38. package/dist/interface/menu.js.map +1 -0
  39. package/dist/providers/claude.d.ts +4 -13
  40. package/dist/providers/claude.js +5 -4
  41. package/dist/providers/claude.js.map +1 -1
  42. package/dist/providers/codex.d.ts +6 -12
  43. package/dist/providers/codex.js +6 -4
  44. package/dist/providers/codex.js.map +1 -1
  45. package/dist/providers/detect.d.ts +63 -14
  46. package/dist/providers/detect.js +123 -27
  47. package/dist/providers/detect.js.map +1 -1
  48. package/dist/ui/tui.d.ts +127 -0
  49. package/dist/ui/tui.js +316 -0
  50. package/dist/ui/tui.js.map +1 -0
  51. package/package.json +4 -1
  52. package/dist/core/index.d.ts +0 -13
  53. package/dist/core/index.js +0 -12
  54. package/dist/core/index.js.map +0 -1
  55. package/dist/infra/index.d.ts +0 -9
  56. package/dist/infra/index.js +0 -7
  57. package/dist/infra/index.js.map +0 -1
  58. package/dist/providers/index.d.ts +0 -9
  59. package/dist/providers/index.js +0 -7
  60. package/dist/providers/index.js.map +0 -1
@@ -0,0 +1,622 @@
1
+ /**
2
+ * src/interface/menu.ts — Sessions-first interactive control panel.
3
+ *
4
+ * Implements the dual-brain UX design bible:
5
+ * - A boxed header with provider status (real, from EnvironmentStatus).
6
+ * - Recent conversations (up to 7, relative timestamps from the store).
7
+ * - A sectioned menu with letter-key dispatch.
8
+ * - First-run welcome / 10-second setup flow.
9
+ * - Per-conversation chat loop backed by runTask().
10
+ *
11
+ * Architecture rules:
12
+ * - NO process.exit() — caller (cli.ts) owns process lifetime.
13
+ * - NO Math.random() — all ids / timestamps via injected Clock.
14
+ * - NO fabricated data — every displayed value is real (env, store, clock).
15
+ * - NO digit-% literals — percentages are always computed, never hardcoded.
16
+ * - All rendering goes through ui/tui.ts primitives.
17
+ */
18
+ import readline from 'node:readline';
19
+ import { saveConfig } from '../infra/config.js';
20
+ import { readLedger } from '../infra/ledger.js';
21
+ import { summarizeSpend, formatUsd } from '../infra/insights.js';
22
+ import { detectEnvironment, getInstallCommand } from '../providers/detect.js';
23
+ import { DEFAULT_POLICY, POLICY_PRESETS } from '../core/policy.js';
24
+ import { runTask } from './run.js';
25
+ import { runLogin } from '../commands/login.js';
26
+ import { runDoctor } from '../commands/doctor.js';
27
+ import { runCost } from '../commands/cost.js';
28
+ import { box, separator, menu, prompt } from '../ui/tui.js';
29
+ // ---------------------------------------------------------------------------
30
+ // Pure helpers — exported for unit tests
31
+ // ---------------------------------------------------------------------------
32
+ /**
33
+ * Return the shell alias hint the user can add to their shell profile to make
34
+ * `myshell-tools` the default command-line assistant.
35
+ *
36
+ * This is a pure, I/O-free helper — it never reads or writes any file. The
37
+ * caller is responsible for printing the result. No claim is made that the
38
+ * system has been changed; the output is a copy-pasteable suggestion only.
39
+ *
40
+ * @param shell - The value of `process.env.SHELL` (e.g. '/bin/bash'), or
41
+ * empty/undefined on Windows where SHELL is absent.
42
+ * @param platform - The `process.platform` string (e.g. 'win32', 'linux').
43
+ * @returns A human-readable string containing the exact alias line to add.
44
+ */
45
+ export function defaultAliasHint(shell, platform) {
46
+ if (platform === 'win32') {
47
+ return ('Add to your PowerShell profile ($PROFILE):\n' +
48
+ " function mst { myshell-tools @args }");
49
+ }
50
+ const shellName = typeof shell === 'string' && shell.length > 0
51
+ ? shell.split('/').at(-1) ?? 'bash'
52
+ : 'bash';
53
+ if (shellName === 'fish') {
54
+ return ('Add to ~/.config/fish/config.fish:\n' +
55
+ ' alias mst="myshell-tools"');
56
+ }
57
+ const rcFile = shellName === 'zsh' ? '~/.zshrc' : '~/.bashrc';
58
+ return (`Add to ${rcFile}:\n` +
59
+ ' alias mst="myshell-tools"');
60
+ }
61
+ /**
62
+ * Format a relative time string from a past epoch-ms to a now epoch-ms.
63
+ * Returns "just now", "Nm ago" (minutes), "Nh ago" (hours), or "Nd ago" (days).
64
+ * All arithmetic is pure — no Date, no Math.random.
65
+ */
66
+ export function relativeTime(thenMs, nowMs) {
67
+ const diffMs = Math.max(0, nowMs - thenMs);
68
+ const seconds = Math.floor(diffMs / 1000);
69
+ if (seconds < 60)
70
+ return 'just now';
71
+ const minutes = Math.floor(diffMs / (60 * 1000));
72
+ if (minutes < 60)
73
+ return `${minutes}m ago`;
74
+ const hours = Math.floor(diffMs / (60 * 60 * 1000));
75
+ if (hours < 24)
76
+ return `${hours}h ago`;
77
+ const days = Math.floor(diffMs / (24 * 60 * 60 * 1000));
78
+ return `${days}d ago`;
79
+ }
80
+ /**
81
+ * Build the header box lines (provider status) from real EnvironmentStatus.
82
+ * Returns string[] safe to pass as the `lines` arg to box().
83
+ *
84
+ * Per-provider logic (uses REAL authenticated + plan fields):
85
+ * ✅ when ps.installed && ps.authenticated
86
+ * ⚠️ when ps.installed && !ps.authenticated (append " not signed in")
87
+ * ❌ when !ps.installed (append install command)
88
+ * Plan label appended when ps.plan is non-null (e.g. " (Max x5)").
89
+ */
90
+ export function renderHeaderLines(env, _version) {
91
+ const lines = [];
92
+ for (const ps of [env.claude, env.codex]) {
93
+ const planSuffix = ps.plan != null ? ` (${ps.plan})` : '';
94
+ if (!ps.installed) {
95
+ lines.push(`❌ ${ps.id}: not installed — ${getInstallCommand(ps.id)}`);
96
+ }
97
+ else if (ps.authenticated) {
98
+ lines.push(`✅ ${ps.id}: ready${planSuffix}`);
99
+ }
100
+ else {
101
+ lines.push(`⚠️ ${ps.id}: not signed in${planSuffix}`);
102
+ }
103
+ }
104
+ return lines;
105
+ }
106
+ /**
107
+ * Render the budget/spend status line shown beneath the provider header.
108
+ *
109
+ * Uses real numbers only — all values come from the SpendSummary which is
110
+ * derived from `readLedger`. No digit-% literals appear in this function; it
111
+ * shows dollar amounts only.
112
+ *
113
+ * @param spend - Output of summarizeSpend() over real ledger entries.
114
+ * @param color - When false, no ANSI escape codes are emitted.
115
+ */
116
+ export function renderBudgetLine(spend, _color) {
117
+ if (spend.calls === 0) {
118
+ return 'Today: ' + formatUsd(0) + ' · no runs yet';
119
+ }
120
+ const todayPart = 'Today: ' + formatUsd(spend.todayUsd) + ' · ' + String(spend.calls) + ' calls';
121
+ const totalPart = 'Total: ' + formatUsd(spend.totalUsd);
122
+ return todayPart + ' · ' + totalPart;
123
+ }
124
+ /**
125
+ * Build the conversation list lines from real ConversationMeta[].
126
+ * Format: "[N] <pin> <relative-time> <title>[ [<category>]]"
127
+ *
128
+ * Pin prefix: "📌 " for pinned, " " (3 spaces) for alignment when not pinned.
129
+ * Category suffix: " [<category>]" appended when category is set, omitted otherwise.
130
+ * Returns string[] (no ANSI — pure string building, safe for tests).
131
+ */
132
+ export function renderConversationList(metas, nowMs) {
133
+ return metas.slice(0, 7).map((m, i) => {
134
+ const thenMs = new Date(m.updatedAt).getTime();
135
+ const rel = relativeTime(thenMs, nowMs);
136
+ const idx = i + 1;
137
+ const pin = m.pinned ? '📌 ' : ' ';
138
+ const categorySuffix = m.category != null ? ` [${m.category}]` : '';
139
+ return `[${idx}] ${pin}${rel} ${m.title}${categorySuffix}`;
140
+ });
141
+ }
142
+ /**
143
+ * Build a {@link LineReader} backed by a single `node:readline` interface.
144
+ *
145
+ * Lines that arrive before they are awaited are buffered (fixing the eager
146
+ * pipe-drain line loss); awaiters that arrive before a line block on a queued
147
+ * resolver. On `close`, every pending and future awaiter resolves to `null`.
148
+ */
149
+ function createLineReader(rl) {
150
+ // Lines received but not yet consumed by a nextLine() caller.
151
+ const buffered = [];
152
+ // nextLine() callers waiting for a line that hasn't arrived yet.
153
+ const waiters = [];
154
+ let closed = false;
155
+ rl.on('line', (raw) => {
156
+ const line = raw.trim();
157
+ const waiter = waiters.shift();
158
+ if (waiter !== undefined) {
159
+ waiter(line);
160
+ }
161
+ else {
162
+ buffered.push(line);
163
+ }
164
+ });
165
+ rl.on('close', () => {
166
+ closed = true;
167
+ // Drain every pending awaiter with the EOF sentinel.
168
+ while (waiters.length > 0) {
169
+ const waiter = waiters.shift();
170
+ if (waiter !== undefined)
171
+ waiter(null);
172
+ }
173
+ });
174
+ return {
175
+ nextLine() {
176
+ // Deliver any buffered line first (FIFO).
177
+ if (buffered.length > 0) {
178
+ const next = buffered.shift();
179
+ return Promise.resolve(next ?? null);
180
+ }
181
+ // Once closed with nothing buffered, every call yields EOF — never throws.
182
+ if (closed) {
183
+ return Promise.resolve(null);
184
+ }
185
+ return new Promise((resolve) => {
186
+ waiters.push(resolve);
187
+ });
188
+ },
189
+ close() {
190
+ rl.close();
191
+ },
192
+ };
193
+ }
194
+ // ---------------------------------------------------------------------------
195
+ // Welcome screen (first run)
196
+ // ---------------------------------------------------------------------------
197
+ async function runWelcome(ctx, out, readLine, mutableConfig) {
198
+ const headerLines = renderHeaderLines(ctx.env, ctx.version);
199
+ out.write('\n' + box(`🧠 myshell-tools v${ctx.version} — Setup`, headerLines) + '\n\n');
200
+ out.write(' [Enter] Save & go\n');
201
+ out.write(' [l] Sign in to providers\n');
202
+ out.write(' [c] Customize mode\n\n');
203
+ out.write('> ');
204
+ const key = await readLine();
205
+ // EOF during setup — save bare onboarded config and return
206
+ if (key === null) {
207
+ const saved = {
208
+ onboarded: true,
209
+ setAsDefault: false,
210
+ ...(mutableConfig.mode !== undefined ? { mode: mutableConfig.mode } : {}),
211
+ };
212
+ await saveConfig(saved);
213
+ return saved;
214
+ }
215
+ let updated = mutableConfig;
216
+ if (key === 'l') {
217
+ const loginCode = await runLogin(out);
218
+ if (loginCode !== 0) {
219
+ out.write('[warn] Login did not complete cleanly.\n');
220
+ }
221
+ }
222
+ else if (key === 'c') {
223
+ updated = await runModeSelect(updated, out, readLine);
224
+ }
225
+ // [Enter] or anything else → fall through to save & go
226
+ out.write('Set myshell-tools as your default shell tool? (y/n) ');
227
+ const defaultAns = await readLine();
228
+ // EOF before answer → treat as "no"
229
+ const setAsDefault = (defaultAns ?? '').toLowerCase() === 'y';
230
+ const saved = {
231
+ onboarded: true,
232
+ setAsDefault,
233
+ ...(updated.mode !== undefined ? { mode: updated.mode } : {}),
234
+ };
235
+ await saveConfig(saved);
236
+ // When the user opted in, print the alias hint so the prompt is honest.
237
+ if (setAsDefault) {
238
+ const hint = defaultAliasHint(process.env['SHELL'], process.platform);
239
+ out.write('\n[info] To make myshell-tools your default, ' + hint + '\n\n');
240
+ }
241
+ return saved;
242
+ }
243
+ // ---------------------------------------------------------------------------
244
+ // Settings screen
245
+ // ---------------------------------------------------------------------------
246
+ async function runModeSelect(config, out, readLine) {
247
+ const currentMode = config.mode ?? 'balanced';
248
+ const settingsLines = [
249
+ '',
250
+ 'Mode:',
251
+ ` [1] cost-saver${currentMode === 'cost-saver' ? ' (active)' : ''}`,
252
+ ` [2] balanced${currentMode === 'balanced' ? ' (active)' : ''}`,
253
+ ` [3] quality-first${currentMode === 'quality-first' ? ' (active)' : ''}`,
254
+ '',
255
+ ];
256
+ out.write('\n' + box('Settings', settingsLines) + '\n\n');
257
+ out.write('[1/2/3 to change, Enter to keep] ');
258
+ const key = await readLine();
259
+ // EOF → keep current mode
260
+ let newMode = config.mode;
261
+ if (key === '1')
262
+ newMode = 'cost-saver';
263
+ else if (key === '2')
264
+ newMode = 'balanced';
265
+ else if (key === '3')
266
+ newMode = 'quality-first';
267
+ const updated = {
268
+ onboarded: config.onboarded,
269
+ setAsDefault: config.setAsDefault,
270
+ ...(newMode !== undefined ? { mode: newMode } : {}),
271
+ };
272
+ await saveConfig(updated);
273
+ out.write(`Mode set to: ${newMode ?? 'balanced'}\n`);
274
+ return updated;
275
+ }
276
+ async function runSettings(ctx, mutableCtx, out, readLine) {
277
+ mutableCtx.config = await runModeSelect(mutableCtx.config, out, readLine);
278
+ }
279
+ // ---------------------------------------------------------------------------
280
+ // Manage conversations screen
281
+ // ---------------------------------------------------------------------------
282
+ async function runManage(ctx, out, readLine) {
283
+ // Inner helper to re-fetch and re-render the conversation list.
284
+ async function renderList() {
285
+ const latest = await ctx.store.list();
286
+ const nowMs = ctx.clock.now();
287
+ const lines = renderConversationList(latest, nowMs);
288
+ out.write('\n' + separator('Conversations') + '\n');
289
+ for (const line of lines) {
290
+ out.write(` ${line}\n`);
291
+ }
292
+ out.write('\n [p] Pin/unpin [t] Set category [r] Rename [x] Delete [Enter] Back\n\n');
293
+ return latest;
294
+ }
295
+ let metas = await ctx.store.list();
296
+ if (metas.length === 0) {
297
+ out.write('No conversations yet.\n');
298
+ out.write('[Enter to go back] ');
299
+ await readLine();
300
+ return;
301
+ }
302
+ metas = await renderList();
303
+ out.write('> ');
304
+ const key = await readLine();
305
+ // EOF → treat as back
306
+ if (key === null)
307
+ return;
308
+ if (key === 'p') {
309
+ out.write('Pin/unpin conversation number: ');
310
+ const numStr = await readLine();
311
+ const num = parseInt(numStr ?? '', 10);
312
+ if (!Number.isNaN(num) && num >= 1 && num <= metas.length) {
313
+ const conv = metas[num - 1];
314
+ if (conv !== undefined) {
315
+ const newPinned = !conv.pinned;
316
+ await ctx.store.setPinned(conv.id, newPinned);
317
+ out.write(newPinned ? `📌 Pinned "${conv.title}"\n` : `Unpinned "${conv.title}"\n`);
318
+ await renderList();
319
+ }
320
+ }
321
+ }
322
+ else if (key === 't') {
323
+ out.write('Set category for conversation number: ');
324
+ const numStr = await readLine();
325
+ const num = parseInt(numStr ?? '', 10);
326
+ if (!Number.isNaN(num) && num >= 1 && num <= metas.length) {
327
+ const conv = metas[num - 1];
328
+ if (conv !== undefined) {
329
+ out.write(`Category tag for "${conv.title}" (empty to clear): `);
330
+ const tag = await readLine() ?? '';
331
+ await ctx.store.setCategory(conv.id, tag.length > 0 ? tag : null);
332
+ out.write(tag.length > 0 ? `Category set to "${tag}"\n` : 'Category cleared.\n');
333
+ await renderList();
334
+ }
335
+ }
336
+ }
337
+ else if (key === 'r') {
338
+ out.write('Rename conversation number: ');
339
+ const numStr = await readLine();
340
+ const num = parseInt(numStr ?? '', 10);
341
+ if (!Number.isNaN(num) && num >= 1 && num <= metas.length) {
342
+ const conv = metas[num - 1];
343
+ if (conv !== undefined) {
344
+ out.write(`New name for "${conv.title}": `);
345
+ const newTitle = await readLine() ?? '';
346
+ if (newTitle.length > 0) {
347
+ await ctx.store.rename(conv.id, newTitle);
348
+ out.write(`Renamed to "${newTitle}"\n`);
349
+ await renderList();
350
+ }
351
+ }
352
+ }
353
+ }
354
+ else if (key === 'x') {
355
+ out.write('Delete conversation number: ');
356
+ const numStr = await readLine();
357
+ const num = parseInt(numStr ?? '', 10);
358
+ if (!Number.isNaN(num) && num >= 1 && num <= metas.length) {
359
+ const conv = metas[num - 1];
360
+ if (conv !== undefined) {
361
+ out.write(`Delete "${conv.title}"? (y/n) `);
362
+ const confirmAns = await readLine();
363
+ if ((confirmAns ?? '').toLowerCase() === 'y') {
364
+ await ctx.store.remove(conv.id);
365
+ out.write('Deleted.\n');
366
+ }
367
+ }
368
+ }
369
+ }
370
+ // else: back
371
+ }
372
+ // ---------------------------------------------------------------------------
373
+ // Chat loop
374
+ // ---------------------------------------------------------------------------
375
+ async function runChatLoop(ctx, mutableCtx, convId, out, readLine) {
376
+ // Print a short recap of the conversation (last entry) if history exists
377
+ const history = await ctx.store.load(convId);
378
+ if (history.length > 0) {
379
+ const last = history[history.length - 1];
380
+ if (last !== undefined) {
381
+ out.write(`\n Resuming — last message (${last.role}): ${last.content.slice(0, 80)}${last.content.length > 80 ? '…' : ''}\n\n`);
382
+ }
383
+ }
384
+ out.write(prompt('task or /help', out.color) + '\n');
385
+ let currentAc = null;
386
+ // Handle SIGINT: cancel in-flight task or return to menu
387
+ const sigintHandler = () => {
388
+ if (currentAc !== null) {
389
+ currentAc.abort();
390
+ out.write('\n[warn] Task cancelled.\n');
391
+ currentAc = null;
392
+ }
393
+ else {
394
+ out.write('\n[info] Use /back or /exit to return to the menu.\n');
395
+ }
396
+ };
397
+ process.on('SIGINT', sigintHandler);
398
+ try {
399
+ while (true) {
400
+ out.write('myshell-tools> ');
401
+ const line = await readLine();
402
+ // EOF → exit the chat loop gracefully
403
+ if (line === null)
404
+ break;
405
+ if (line.length === 0)
406
+ continue;
407
+ if (line === '/exit' || line === '/back') {
408
+ break;
409
+ }
410
+ if (line === '/help') {
411
+ out.write(' /back or /exit — return to main menu\n' +
412
+ ' /help — show this help\n' +
413
+ ' <anything> — run as a task in this conversation\n');
414
+ continue;
415
+ }
416
+ const policy = mutableCtx.config.mode !== undefined
417
+ ? POLICY_PRESETS[mutableCtx.config.mode]
418
+ : DEFAULT_POLICY;
419
+ const deps = {
420
+ clock: ctx.clock,
421
+ session: ctx.store.writer(convId),
422
+ ledger: ctx.ledger,
423
+ policy,
424
+ providers: ctx.providers,
425
+ cwd: ctx.cwd,
426
+ sandbox: ctx.sandbox,
427
+ timeoutMs: ctx.timeoutMs,
428
+ };
429
+ const ac = new AbortController();
430
+ currentAc = ac;
431
+ await runTask(line, deps, out, ac.signal);
432
+ currentAc = null;
433
+ }
434
+ }
435
+ finally {
436
+ process.removeListener('SIGINT', sigintHandler);
437
+ }
438
+ }
439
+ // ---------------------------------------------------------------------------
440
+ // Main screen render
441
+ // ---------------------------------------------------------------------------
442
+ async function renderMainScreen(ctx, mutableCtx, metas, out) {
443
+ out.write('\n');
444
+ // Header box — always box(), 🧠 emoji, real provider data
445
+ const headerLines = renderHeaderLines(mutableCtx.env, ctx.version);
446
+ out.write(box(`🧠 myshell-tools v${ctx.version}`, headerLines) + '\n\n');
447
+ // Budget line — real ledger data, never fabricated
448
+ const entries = await readLedger(ctx.cwd);
449
+ const spend = summarizeSpend(entries, ctx.clock.isoNow());
450
+ out.write(' ' + renderBudgetLine(spend, out.color) + '\n\n');
451
+ // Recent conversations — separator() then list
452
+ out.write(separator('Recent Conversations') + '\n');
453
+ const nowMs = ctx.clock.now();
454
+ const convLines = renderConversationList(metas, nowMs);
455
+ if (convLines.length === 0) {
456
+ out.write(' (no conversations yet — press n to start one)\n');
457
+ }
458
+ else {
459
+ for (const line of convLines) {
460
+ out.write(` ${line}\n`);
461
+ }
462
+ }
463
+ out.write('\n');
464
+ // Menu — sectioned via menu()
465
+ out.write(menu([
466
+ { key: 'c', label: 'Continue last conversation', section: 'Conversations' },
467
+ { key: 'n', label: 'New conversation', section: 'Conversations' },
468
+ { key: '1-9', label: 'Resume numbered conversation', section: 'Conversations' },
469
+ { key: 'e', label: 'Manage conversations', section: 'Conversations' },
470
+ { key: 'j', label: 'Login Claude', section: 'Auth' },
471
+ { key: 'k', label: 'Login Codex', section: 'Auth' },
472
+ { key: 's', label: 'Settings', section: 'Options' },
473
+ { key: 'd', label: 'Doctor', section: 'Options' },
474
+ { key: '$', label: 'Cost', section: 'Options' },
475
+ { key: 'q', label: 'Quit', section: 'Options' },
476
+ ]) + '\n\n');
477
+ }
478
+ // ---------------------------------------------------------------------------
479
+ // startMenu — public entry point
480
+ // ---------------------------------------------------------------------------
481
+ /**
482
+ * Start the sessions-first interactive menu.
483
+ *
484
+ * Follows the dual-brain UX design bible:
485
+ * A. First run: welcome / 10-second setup → mark onboarded.
486
+ * B. Main screen loop: header + recent conversations + sectioned menu.
487
+ * C. Per-conversation chat loop backed by runTask().
488
+ *
489
+ * Never calls process.exit() — resolves when the user presses [q] or when
490
+ * stdin reaches EOF (resolves cleanly, no ERR_USE_AFTER_CLOSE thrown).
491
+ *
492
+ * When `ctx.readLine` is provided (e.g. in tests), it is used directly in
493
+ * place of a real readline interface. When absent, a readline interface is
494
+ * created from `process.stdin` as usual; the `close` event is wired up so
495
+ * that EOF resolves gracefully instead of throwing.
496
+ */
497
+ export async function startMenu(ctx, out) {
498
+ // Build the readLine function — either injected (for tests) or backed by a
499
+ // real readline interface driven by the event-driven LineReader queue.
500
+ let readLine;
501
+ let lineReader = null;
502
+ if (ctx.readLine !== undefined) {
503
+ // Injected reader — no real readline needed.
504
+ readLine = ctx.readLine;
505
+ }
506
+ else {
507
+ // Create ONE readline interface for the whole menu lifecycle and drive it
508
+ // through the event-driven queue (NOT per-prompt rl.question). This buffers
509
+ // lines that arrive before they're awaited (fixing pipe eager-drain loss)
510
+ // and resolves to `null` on EOF instead of throwing ERR_USE_AFTER_CLOSE.
511
+ const rl = readline.createInterface({
512
+ input: process.stdin,
513
+ output: process.stdout,
514
+ terminal: out.isTty,
515
+ });
516
+ lineReader = createLineReader(rl);
517
+ const reader = lineReader;
518
+ // All prompt text is already written to `out` before readLine() is called.
519
+ readLine = () => reader.nextLine();
520
+ }
521
+ // Mutable local copy of config & env — updated as the user changes settings /
522
+ // re-authenticates without mutating the immutable ctx parameter.
523
+ const mutableCtx = {
524
+ config: ctx.config,
525
+ env: ctx.env,
526
+ };
527
+ try {
528
+ // ---- A. First-run welcome -----------------------------------------------
529
+ if (!mutableCtx.config.onboarded) {
530
+ mutableCtx.config = await runWelcome(ctx, out, readLine, mutableCtx.config);
531
+ }
532
+ // ---- B. Main screen loop -------------------------------------------------
533
+ while (true) {
534
+ const metas = await ctx.store.list();
535
+ await renderMainScreen(ctx, mutableCtx, metas, out);
536
+ out.write('> ');
537
+ const key = await readLine();
538
+ // ---- EOF / close — exit gracefully (FIX 1: no ERR_USE_AFTER_CLOSE) ----
539
+ if (key === null) {
540
+ break;
541
+ }
542
+ // ---- [q] Quit -----------------------------------------------------------
543
+ if (key === 'q') {
544
+ break;
545
+ }
546
+ // ---- [n] New conversation -----------------------------------------------
547
+ if (key === 'n') {
548
+ out.write('First message (becomes the title): ');
549
+ const firstMsg = await readLine();
550
+ if (firstMsg !== null && firstMsg.length > 0) {
551
+ const meta = await ctx.store.create(firstMsg);
552
+ await runChatLoop(ctx, mutableCtx, meta.id, out, readLine);
553
+ }
554
+ continue;
555
+ }
556
+ // ---- [c] Continue most-recent conversation ------------------------------
557
+ if (key === 'c') {
558
+ const all = await ctx.store.list();
559
+ const latest = all[0];
560
+ if (latest !== undefined) {
561
+ await runChatLoop(ctx, mutableCtx, latest.id, out, readLine);
562
+ }
563
+ else {
564
+ out.write('No conversations yet. Press n to start one.\n');
565
+ }
566
+ continue;
567
+ }
568
+ // ---- [1-9] Resume numbered conversation ---------------------------------
569
+ const digit = parseInt(key, 10);
570
+ if (!Number.isNaN(digit) && digit >= 1 && digit <= 9) {
571
+ const target = metas[digit - 1];
572
+ if (target !== undefined) {
573
+ await runChatLoop(ctx, mutableCtx, target.id, out, readLine);
574
+ }
575
+ else {
576
+ out.write(`No conversation at position ${digit}.\n`);
577
+ }
578
+ continue;
579
+ }
580
+ // ---- [e] Manage conversations -------------------------------------------
581
+ if (key === 'e') {
582
+ await runManage(ctx, out, readLine);
583
+ continue;
584
+ }
585
+ // ---- [j] Login Claude ---------------------------------------------------
586
+ if (key === 'j') {
587
+ await runLogin(out, 'claude');
588
+ mutableCtx.env = await detectEnvironment();
589
+ continue;
590
+ }
591
+ // ---- [k] Login Codex ----------------------------------------------------
592
+ if (key === 'k') {
593
+ await runLogin(out, 'codex');
594
+ mutableCtx.env = await detectEnvironment();
595
+ continue;
596
+ }
597
+ // ---- [s] Settings -------------------------------------------------------
598
+ if (key === 's') {
599
+ await runSettings(ctx, mutableCtx, out, readLine);
600
+ continue;
601
+ }
602
+ // ---- [d] Doctor ---------------------------------------------------------
603
+ if (key === 'd') {
604
+ await runDoctor(out);
605
+ continue;
606
+ }
607
+ // ---- [$] Cost -----------------------------------------------------------
608
+ if (key === '$') {
609
+ await runCost(ctx.cwd, out);
610
+ continue;
611
+ }
612
+ // ---- Unknown key --------------------------------------------------------
613
+ if (key.length > 0) {
614
+ out.write(`Unknown option: "${key}". Press q to quit.\n`);
615
+ }
616
+ }
617
+ }
618
+ finally {
619
+ lineReader?.close();
620
+ }
621
+ }
622
+ //# sourceMappingURL=menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menu.js","sourceRoot":"","sources":["../../src/interface/menu.ts"],"names":[],"mappings":"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"}