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.
- package/CHANGELOG.md +13 -1
- package/README.md +6 -3
- package/dist/cli.js +85 -30
- package/dist/cli.js.map +1 -1
- package/dist/commands/doctor.d.ts +3 -2
- package/dist/commands/doctor.js +9 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/login.d.ts +20 -0
- package/dist/commands/login.js +60 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/core/orchestrate.js +80 -28
- package/dist/core/orchestrate.js.map +1 -1
- package/dist/core/policy.d.ts +10 -0
- package/dist/core/policy.js +40 -0
- package/dist/core/policy.js.map +1 -1
- package/dist/core/review.d.ts +5 -0
- package/dist/core/review.js +2 -2
- package/dist/core/review.js.map +1 -1
- package/dist/infra/atomic.d.ts +0 -3
- package/dist/infra/atomic.js +1 -1
- package/dist/infra/atomic.js.map +1 -1
- package/dist/infra/config.d.ts +23 -0
- package/dist/infra/config.js +64 -0
- package/dist/infra/config.js.map +1 -0
- package/dist/infra/conversation-store.d.ts +42 -0
- package/dist/infra/conversation-store.js +14 -0
- package/dist/infra/conversation-store.js.map +1 -0
- package/dist/infra/conversations.d.ts +18 -0
- package/dist/infra/conversations.js +296 -0
- package/dist/infra/conversations.js.map +1 -0
- package/dist/infra/insights.d.ts +66 -0
- package/dist/infra/insights.js +105 -0
- package/dist/infra/insights.js.map +1 -0
- package/dist/infra/ledger.d.ts +4 -6
- package/dist/infra/ledger.js.map +1 -1
- package/dist/interface/menu.d.ts +112 -0
- package/dist/interface/menu.js +622 -0
- package/dist/interface/menu.js.map +1 -0
- package/dist/providers/claude.d.ts +4 -13
- package/dist/providers/claude.js +5 -4
- package/dist/providers/claude.js.map +1 -1
- package/dist/providers/codex.d.ts +6 -12
- package/dist/providers/codex.js +6 -4
- package/dist/providers/codex.js.map +1 -1
- package/dist/providers/detect.d.ts +63 -14
- package/dist/providers/detect.js +123 -27
- package/dist/providers/detect.js.map +1 -1
- package/dist/ui/tui.d.ts +127 -0
- package/dist/ui/tui.js +316 -0
- package/dist/ui/tui.js.map +1 -0
- package/package.json +4 -1
- package/dist/core/index.d.ts +0 -13
- package/dist/core/index.js +0 -12
- package/dist/core/index.js.map +0 -1
- package/dist/infra/index.d.ts +0 -9
- package/dist/infra/index.js +0 -7
- package/dist/infra/index.js.map +0 -1
- package/dist/providers/index.d.ts +0 -9
- package/dist/providers/index.js +0 -7
- 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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"}
|