xiaotime 0.5.11 → 0.6.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/dist/ansi_tags.js +1 -4
- package/dist/ansi_tags.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +11 -50
- package/dist/auth.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -11
- package/dist/config.js.map +1 -1
- package/dist/display.d.ts.map +1 -1
- package/dist/display.js +168 -210
- package/dist/display.js.map +1 -1
- package/dist/index.js +27 -25
- package/dist/index.js.map +1 -1
- package/dist/ink/App.d.ts +9 -0
- package/dist/ink/App.d.ts.map +1 -0
- package/dist/ink/App.js +152 -0
- package/dist/ink/App.js.map +1 -0
- package/dist/ink/execToolInk.d.ts +13 -0
- package/dist/ink/execToolInk.d.ts.map +1 -0
- package/dist/ink/execToolInk.js +239 -0
- package/dist/ink/execToolInk.js.map +1 -0
- package/dist/ink/runSessionInk.d.ts +2 -0
- package/dist/ink/runSessionInk.d.ts.map +1 -0
- package/dist/ink/runSessionInk.js +184 -0
- package/dist/ink/runSessionInk.js.map +1 -0
- package/dist/ink/store.d.ts +102 -0
- package/dist/ink/store.d.ts.map +1 -0
- package/dist/ink/store.js +144 -0
- package/dist/ink/store.js.map +1 -0
- package/dist/input_box.js +9 -16
- package/dist/input_box.js.map +1 -1
- package/dist/projectContext.d.ts +38 -0
- package/dist/projectContext.d.ts.map +1 -0
- package/dist/projectContext.js +135 -0
- package/dist/projectContext.js.map +1 -0
- package/dist/session.js +8 -14
- package/dist/session.js.map +1 -1
- package/dist/session_match.js +1 -4
- package/dist/session_match.js.map +1 -1
- package/dist/settings.js +8 -48
- package/dist/settings.js.map +1 -1
- package/dist/sidebar.js +13 -20
- package/dist/sidebar.js.map +1 -1
- package/dist/tool_result_client.js +6 -11
- package/dist/tool_result_client.js.map +1 -1
- package/dist/tools.d.ts +5 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +33 -71
- package/dist/tools.js.map +1 -1
- package/dist/ui_state.d.ts +1 -0
- package/dist/ui_state.d.ts.map +1 -1
- package/dist/ui_state.js +33 -61
- package/dist/ui_state.js.map +1 -1
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +77 -111
- package/dist/ws.js.map +1 -1
- package/package.json +8 -2
package/dist/display.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Output formatting — streaming text, session list, status bar, tool lines.
|
|
4
3
|
*
|
|
@@ -28,44 +27,8 @@
|
|
|
28
27
|
* - Tool call errors render as red-bordered box instead of inline text
|
|
29
28
|
* - Removed "Junior is thinking..." spinner label
|
|
30
29
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.setBotName = setBotName;
|
|
36
|
-
exports.getBotName = getBotName;
|
|
37
|
-
exports.initStatusBar = initStatusBar;
|
|
38
|
-
exports.setConnected = setConnected;
|
|
39
|
-
exports.incrementTurn = incrementTurn;
|
|
40
|
-
exports.setLastTool = setLastTool;
|
|
41
|
-
exports.updateStatusBarCost = updateStatusBarCost;
|
|
42
|
-
exports.startSpinner = startSpinner;
|
|
43
|
-
exports.stopSpinner = stopSpinner;
|
|
44
|
-
exports.startToolLine = startToolLine;
|
|
45
|
-
exports.finishToolLine = finishToolLine;
|
|
46
|
-
exports.printToolError = printToolError;
|
|
47
|
-
exports.printFileDiff = printFileDiff;
|
|
48
|
-
exports.printApprovalPrompt = printApprovalPrompt;
|
|
49
|
-
exports.printTextDelta = printTextDelta;
|
|
50
|
-
exports.printTurnStart = printTurnStart;
|
|
51
|
-
exports.printThinkingStart = printThinkingStart;
|
|
52
|
-
exports.printThinkingStop = printThinkingStop;
|
|
53
|
-
exports.printTurnEnd = printTurnEnd;
|
|
54
|
-
exports.consumeFirstPrompt = consumeFirstPrompt;
|
|
55
|
-
exports.printPrompt = printPrompt;
|
|
56
|
-
exports.printPromptEnd = printPromptEnd;
|
|
57
|
-
exports.printWelcome = printWelcome;
|
|
58
|
-
exports.printError = printError;
|
|
59
|
-
exports.printSessionList = printSessionList;
|
|
60
|
-
exports.friendlyToolLabel = friendlyToolLabel;
|
|
61
|
-
exports.friendlyError = friendlyError;
|
|
62
|
-
exports.printHelp = printHelp;
|
|
63
|
-
exports.printDisconnectBanner = printDisconnectBanner;
|
|
64
|
-
exports.printExitConfirmation = printExitConfirmation;
|
|
65
|
-
exports.printToolCallLine = printToolCallLine;
|
|
66
|
-
exports.printServerToolCall = printServerToolCall;
|
|
67
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
68
|
-
const cli_highlight_1 = require("cli-highlight");
|
|
30
|
+
import chalk from "chalk";
|
|
31
|
+
import { highlight, supportsLanguage } from "cli-highlight";
|
|
69
32
|
// Assistant display name. NEVER hardcode "Junior" — DoctorWhiskers/Harvey and
|
|
70
33
|
// every other tenant render their own assistant name in the same UI. Sourced
|
|
71
34
|
// from XIAOTIME_BOT_NAME, with a neutral fallback, and overridable at runtime
|
|
@@ -86,22 +49,22 @@ function _sanitizeName(raw) {
|
|
|
86
49
|
.slice(0, 40);
|
|
87
50
|
}
|
|
88
51
|
let _botName = _sanitizeName(process.env.XIAOTIME_BOT_NAME) || "Assistant";
|
|
89
|
-
function setBotName(name) {
|
|
52
|
+
export function setBotName(name) {
|
|
90
53
|
const n = _sanitizeName(name);
|
|
91
54
|
if (n)
|
|
92
55
|
_botName = n;
|
|
93
56
|
}
|
|
94
|
-
function getBotName() {
|
|
57
|
+
export function getBotName() {
|
|
95
58
|
return _botName;
|
|
96
59
|
}
|
|
97
60
|
// Force color output — Termius and some SSH clients report level 0
|
|
98
61
|
// even when the terminal supports 256 colors.
|
|
99
|
-
if (
|
|
62
|
+
if (chalk.level === 0 &&
|
|
100
63
|
(process.env.TERM?.includes("256color") ||
|
|
101
64
|
process.env.TERM?.includes("xterm") ||
|
|
102
65
|
process.env.COLORTERM ||
|
|
103
66
|
process.env.FORCE_COLOR)) {
|
|
104
|
-
|
|
67
|
+
chalk.level = 2;
|
|
105
68
|
}
|
|
106
69
|
// ---------------------------------------------------------------------------
|
|
107
70
|
// Terminal geometry helpers
|
|
@@ -155,7 +118,7 @@ const FILE_PATH_RE = /(?<![`\w])((?:\/[\w.\-]+)+(?:\/[\w.\-]+)?|\.{1,2}\/[\w.\-/
|
|
|
155
118
|
function _linkifyPaths(text) {
|
|
156
119
|
return text.replace(FILE_PATH_RE, (match) => {
|
|
157
120
|
const url = match.startsWith("/") ? `file://${match}` : `file://${process.cwd()}/${match}`;
|
|
158
|
-
return
|
|
121
|
+
return chalk.underline(osc8Link(url, match));
|
|
159
122
|
});
|
|
160
123
|
}
|
|
161
124
|
// ---------------------------------------------------------------------------
|
|
@@ -164,37 +127,37 @@ function _linkifyPaths(text) {
|
|
|
164
127
|
function renderMarkdownLine(line) {
|
|
165
128
|
const h3 = line.match(/^### (.+)$/);
|
|
166
129
|
if (h3)
|
|
167
|
-
return
|
|
130
|
+
return chalk.bold.hex("#94e2d5")(h3[1]);
|
|
168
131
|
const h2 = line.match(/^## (.+)$/);
|
|
169
132
|
if (h2)
|
|
170
|
-
return
|
|
133
|
+
return chalk.bold.hex("#89b4fa")(h2[1]);
|
|
171
134
|
const h1 = line.match(/^# (.+)$/);
|
|
172
135
|
if (h1)
|
|
173
|
-
return
|
|
136
|
+
return chalk.bold.hex("#c0384b")(h1[1]);
|
|
174
137
|
if (/^---+$/.test(line) || /^\*\*\*+$/.test(line)) {
|
|
175
|
-
return
|
|
138
|
+
return chalk.dim("─".repeat(termWidth()));
|
|
176
139
|
}
|
|
177
140
|
if (line.startsWith("> ")) {
|
|
178
|
-
return
|
|
141
|
+
return chalk.dim.italic(" │ " + line.slice(2));
|
|
179
142
|
}
|
|
180
143
|
const bullet = line.match(/^(\s*)[*\-+] (.+)$/);
|
|
181
144
|
if (bullet) {
|
|
182
|
-
return `${bullet[1]}${
|
|
145
|
+
return `${bullet[1]}${chalk.hex("#f38ba8")("•")} ${_renderInline(bullet[2])}`;
|
|
183
146
|
}
|
|
184
147
|
const numbered = line.match(/^(\s*)(\d+)\. (.+)$/);
|
|
185
148
|
if (numbered) {
|
|
186
|
-
return `${numbered[1]}${
|
|
149
|
+
return `${numbered[1]}${chalk.dim(numbered[2] + ".")} ${_renderInline(numbered[3])}`;
|
|
187
150
|
}
|
|
188
151
|
return _renderInline(line);
|
|
189
152
|
}
|
|
190
153
|
function _renderInline(text) {
|
|
191
|
-
text = text.replace(/\*\*\*(.+?)\*\*\*/g, (_m, t) =>
|
|
192
|
-
text = text.replace(/\*\*(.+?)\*\*/g, (_m, t) =>
|
|
193
|
-
text = text.replace(/\*(.+?)\*/g, (_m, t) =>
|
|
194
|
-
text = text.replace(/_(.+?)_/g, (_m, t) =>
|
|
154
|
+
text = text.replace(/\*\*\*(.+?)\*\*\*/g, (_m, t) => chalk.bold.italic(t));
|
|
155
|
+
text = text.replace(/\*\*(.+?)\*\*/g, (_m, t) => chalk.bold(t));
|
|
156
|
+
text = text.replace(/\*(.+?)\*/g, (_m, t) => chalk.italic(t));
|
|
157
|
+
text = text.replace(/_(.+?)_/g, (_m, t) => chalk.italic(t));
|
|
195
158
|
// Inline code — subtle background tint (#313244 = Catppuccin surface0, text stays readable)
|
|
196
|
-
text = text.replace(/`([^`]+)`/g, (_m, t) =>
|
|
197
|
-
text = text.replace(/\[(.+?)\]\((.+?)\)/g, (_m, label, url) => `${
|
|
159
|
+
text = text.replace(/`([^`]+)`/g, (_m, t) => chalk.bgHex("#313244").hex("#cdd6f4")(` ${t} `));
|
|
160
|
+
text = text.replace(/\[(.+?)\]\((.+?)\)/g, (_m, label, url) => `${chalk.hex("#89b4fa")(label)} ${chalk.dim(`(${url})`)}`);
|
|
198
161
|
// Linkify file paths (only outside code spans — already consumed above)
|
|
199
162
|
text = _linkifyPaths(text);
|
|
200
163
|
return text;
|
|
@@ -221,19 +184,19 @@ function stripAnsi(s) {
|
|
|
221
184
|
function _renderStatusBarLine() {
|
|
222
185
|
const w = termWidth();
|
|
223
186
|
const dot = _statusBar.connected
|
|
224
|
-
?
|
|
225
|
-
:
|
|
226
|
-
const tenant =
|
|
187
|
+
? chalk.hex("#a6e3a1")("●")
|
|
188
|
+
: chalk.dim("○");
|
|
189
|
+
const tenant = chalk.hex("#c0384b")(_statusBar.tenant);
|
|
227
190
|
const session = _statusBar.sessionName
|
|
228
|
-
?
|
|
229
|
-
:
|
|
230
|
-
const turns =
|
|
191
|
+
? chalk.hex("#89b4fa")(_statusBar.sessionName)
|
|
192
|
+
: chalk.dim(_statusBar.sessionId.slice(0, 8) || "…");
|
|
193
|
+
const turns = chalk.dim(`${_statusBar.turnCount} turns`);
|
|
231
194
|
const lastTool = _statusBar.lastTool
|
|
232
|
-
?
|
|
233
|
-
:
|
|
234
|
-
const sep =
|
|
195
|
+
? chalk.dim(`↳ ${_statusBar.lastTool}`)
|
|
196
|
+
: chalk.dim("ready");
|
|
197
|
+
const sep = chalk.dim(" · ");
|
|
235
198
|
const left = ` ${dot} ${tenant}${sep}${session}${sep}${turns}${sep}${lastTool}`;
|
|
236
|
-
const right =
|
|
199
|
+
const right = chalk.hex("#c0384b")("Xiaotime Labs") + " ";
|
|
237
200
|
const leftRaw = stripAnsi(left);
|
|
238
201
|
const rightRaw = stripAnsi(right);
|
|
239
202
|
const pad = Math.max(0, w - leftRaw.length - rightRaw.length);
|
|
@@ -254,7 +217,7 @@ function _renderStatusBarLine() {
|
|
|
254
217
|
function _drawStickyBar() {
|
|
255
218
|
// no-op — see note above. Status state is tracked; nothing is painted.
|
|
256
219
|
}
|
|
257
|
-
function initStatusBar(sessionId, sessionName, tenant) {
|
|
220
|
+
export function initStatusBar(sessionId, sessionName, tenant) {
|
|
258
221
|
_statusBar.sessionId = sessionId;
|
|
259
222
|
_statusBar.sessionName = sessionName;
|
|
260
223
|
if (tenant)
|
|
@@ -262,19 +225,19 @@ function initStatusBar(sessionId, sessionName, tenant) {
|
|
|
262
225
|
_statusBar.connected = false;
|
|
263
226
|
_drawStickyBar();
|
|
264
227
|
}
|
|
265
|
-
function setConnected(connected) {
|
|
228
|
+
export function setConnected(connected) {
|
|
266
229
|
_statusBar.connected = connected;
|
|
267
230
|
_drawStickyBar();
|
|
268
231
|
}
|
|
269
|
-
function incrementTurn() {
|
|
232
|
+
export function incrementTurn() {
|
|
270
233
|
_statusBar.turnCount += 1;
|
|
271
234
|
_drawStickyBar();
|
|
272
235
|
}
|
|
273
|
-
function setLastTool(toolName) {
|
|
236
|
+
export function setLastTool(toolName) {
|
|
274
237
|
_statusBar.lastTool = toolName;
|
|
275
238
|
_drawStickyBar();
|
|
276
239
|
}
|
|
277
|
-
function updateStatusBarCost(_turnCostUsd) {
|
|
240
|
+
export function updateStatusBarCost(_turnCostUsd) {
|
|
278
241
|
// no-op — cost not shown in bar
|
|
279
242
|
}
|
|
280
243
|
// ---------------------------------------------------------------------------
|
|
@@ -288,7 +251,7 @@ let _spinnerActive = false;
|
|
|
288
251
|
function _clearSpinnerLine() {
|
|
289
252
|
process.stdout.write("\x1b[2K\r");
|
|
290
253
|
}
|
|
291
|
-
function startSpinner(label) {
|
|
254
|
+
export function startSpinner(label) {
|
|
292
255
|
if (_spinnerActive)
|
|
293
256
|
stopSpinner();
|
|
294
257
|
_spinnerLabel = label;
|
|
@@ -297,13 +260,13 @@ function startSpinner(label) {
|
|
|
297
260
|
_spinnerInterval = setInterval(() => {
|
|
298
261
|
if (!_spinnerActive)
|
|
299
262
|
return;
|
|
300
|
-
const frame =
|
|
263
|
+
const frame = chalk.hex("#c0384b")(SPINNER_FRAMES[_spinnerFrame % SPINNER_FRAMES.length]);
|
|
301
264
|
_spinnerFrame++;
|
|
302
|
-
const labelPart = _spinnerLabel ? ` ${
|
|
265
|
+
const labelPart = _spinnerLabel ? ` ${chalk.dim(_spinnerLabel)}` : "";
|
|
303
266
|
process.stdout.write(`\r ${frame}${labelPart}`);
|
|
304
267
|
}, 80);
|
|
305
268
|
}
|
|
306
|
-
function stopSpinner(finalLabel, success = true) {
|
|
269
|
+
export function stopSpinner(finalLabel, success = true) {
|
|
307
270
|
if (_spinnerInterval) {
|
|
308
271
|
clearInterval(_spinnerInterval);
|
|
309
272
|
_spinnerInterval = null;
|
|
@@ -311,21 +274,21 @@ function stopSpinner(finalLabel, success = true) {
|
|
|
311
274
|
_spinnerActive = false;
|
|
312
275
|
_clearSpinnerLine();
|
|
313
276
|
if (finalLabel) {
|
|
314
|
-
const icon = success ?
|
|
315
|
-
process.stdout.write(` ${icon} ${
|
|
277
|
+
const icon = success ? chalk.hex("#a6e3a1")("✓") : chalk.hex("#f38ba8")("✗");
|
|
278
|
+
process.stdout.write(` ${icon} ${chalk.dim(finalLabel)}\n`);
|
|
316
279
|
}
|
|
317
280
|
}
|
|
318
281
|
let _activeTool = null;
|
|
319
|
-
function startToolLine(name, detail) {
|
|
282
|
+
export function startToolLine(name, detail) {
|
|
320
283
|
if (_activeTool)
|
|
321
284
|
finishToolLine(true);
|
|
322
285
|
setLastTool(name);
|
|
323
286
|
let frame = 0;
|
|
324
287
|
const spinnerInterval = setInterval(() => {
|
|
325
|
-
const f =
|
|
288
|
+
const f = chalk.hex("#89b4fa")(SPINNER_FRAMES[frame % SPINNER_FRAMES.length]);
|
|
326
289
|
const friendly = friendlyToolLabel(name);
|
|
327
|
-
const detailStr = detail ?
|
|
328
|
-
process.stdout.write(`\r ${f} ${
|
|
290
|
+
const detailStr = detail ? chalk.dim(` ${detail}`) : "";
|
|
291
|
+
process.stdout.write(`\r ${f} ${chalk.dim(friendly)}${detailStr}`);
|
|
329
292
|
frame++;
|
|
330
293
|
}, 80);
|
|
331
294
|
_activeTool = {
|
|
@@ -336,7 +299,7 @@ function startToolLine(name, detail) {
|
|
|
336
299
|
frame: 0,
|
|
337
300
|
};
|
|
338
301
|
}
|
|
339
|
-
function finishToolLine(success = true, errorMessage) {
|
|
302
|
+
export function finishToolLine(success = true, errorMessage) {
|
|
340
303
|
if (!_activeTool)
|
|
341
304
|
return;
|
|
342
305
|
clearInterval(_activeTool.spinnerInterval);
|
|
@@ -347,28 +310,28 @@ function finishToolLine(success = true, errorMessage) {
|
|
|
347
310
|
printToolError(_activeTool.name, errorMessage, elapsed);
|
|
348
311
|
}
|
|
349
312
|
else {
|
|
350
|
-
const icon = success ?
|
|
351
|
-
const detailStr = _activeTool.detail ?
|
|
352
|
-
const dur =
|
|
313
|
+
const icon = success ? chalk.hex("#a6e3a1")("✓") : chalk.hex("#f38ba8")("✗");
|
|
314
|
+
const detailStr = _activeTool.detail ? chalk.dim(` ${_activeTool.detail}`) : "";
|
|
315
|
+
const dur = chalk.dim(` ${elapsed}ms`);
|
|
353
316
|
const friendlyLabel = friendlyToolLabel(_activeTool.name);
|
|
354
|
-
process.stdout.write(`\r\x1b[2K ${icon} ${
|
|
317
|
+
process.stdout.write(`\r\x1b[2K ${icon} ${chalk.dim(friendlyLabel)}${detailStr}${dur}\n`);
|
|
355
318
|
}
|
|
356
319
|
_activeTool = null;
|
|
357
320
|
}
|
|
358
321
|
// ---------------------------------------------------------------------------
|
|
359
322
|
// Tool error — red bordered box
|
|
360
323
|
// ---------------------------------------------------------------------------
|
|
361
|
-
function printToolError(toolName, errorMessage, durationMs) {
|
|
324
|
+
export function printToolError(toolName, errorMessage, durationMs) {
|
|
362
325
|
const w = termWidth();
|
|
363
|
-
const top =
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const bottom =
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
const dur = durationMs !== undefined ?
|
|
370
|
-
const titleLine =
|
|
371
|
-
const bodyLines = wordWrap(errorMessage, w - 4).map((l) =>
|
|
326
|
+
const top = chalk.hex("#f38ba8")("╭") +
|
|
327
|
+
chalk.hex("#f38ba8")("─".repeat(w - 2)) +
|
|
328
|
+
chalk.hex("#f38ba8")("╮");
|
|
329
|
+
const bottom = chalk.hex("#f38ba8")("╰") +
|
|
330
|
+
chalk.hex("#f38ba8")("─".repeat(w - 2)) +
|
|
331
|
+
chalk.hex("#f38ba8")("╯");
|
|
332
|
+
const dur = durationMs !== undefined ? chalk.dim(` ${durationMs}ms`) : "";
|
|
333
|
+
const titleLine = chalk.bold.hex("#f38ba8")(` ✗ ${toolName}${dur}`);
|
|
334
|
+
const bodyLines = wordWrap(errorMessage, w - 4).map((l) => chalk.hex("#f38ba8")(" " + l));
|
|
372
335
|
process.stdout.write("\n" + top + "\n");
|
|
373
336
|
process.stdout.write(titleLine + "\n");
|
|
374
337
|
for (const l of bodyLines) {
|
|
@@ -379,20 +342,20 @@ function printToolError(toolName, errorMessage, durationMs) {
|
|
|
379
342
|
// ---------------------------------------------------------------------------
|
|
380
343
|
// Diff view for write_file
|
|
381
344
|
// ---------------------------------------------------------------------------
|
|
382
|
-
function printFileDiff(path, before, after) {
|
|
345
|
+
export function printFileDiff(path, before, after) {
|
|
383
346
|
const w = termWidth();
|
|
384
|
-
const label =
|
|
347
|
+
const label = chalk.dim(` write_file ${path} `);
|
|
385
348
|
const labelRaw = ` write_file ${path} `;
|
|
386
|
-
const rule =
|
|
349
|
+
const rule = chalk.dim("─".repeat(Math.max(0, w - labelRaw.length)));
|
|
387
350
|
process.stdout.write("\n" + rule + label + "\n");
|
|
388
351
|
if (!before) {
|
|
389
352
|
// New file — show all lines as added
|
|
390
353
|
const lines = after.split("\n").slice(0, 20);
|
|
391
354
|
for (const line of lines) {
|
|
392
|
-
process.stdout.write(
|
|
355
|
+
process.stdout.write(chalk.hex("#a6e3a1")("+ " + line) + "\n");
|
|
393
356
|
}
|
|
394
357
|
if (after.split("\n").length > 20) {
|
|
395
|
-
process.stdout.write(
|
|
358
|
+
process.stdout.write(chalk.dim(` … ${after.split("\n").length - 20} more lines\n`));
|
|
396
359
|
}
|
|
397
360
|
}
|
|
398
361
|
else {
|
|
@@ -404,39 +367,39 @@ function printFileDiff(path, before, after) {
|
|
|
404
367
|
const b = beforeLines[i];
|
|
405
368
|
const a = afterLines[i];
|
|
406
369
|
if (b === undefined) {
|
|
407
|
-
process.stdout.write(
|
|
370
|
+
process.stdout.write(chalk.hex("#a6e3a1")("+ " + a) + "\n");
|
|
408
371
|
shown++;
|
|
409
372
|
}
|
|
410
373
|
else if (a === undefined) {
|
|
411
|
-
process.stdout.write(
|
|
374
|
+
process.stdout.write(chalk.hex("#f38ba8")("- " + b) + "\n");
|
|
412
375
|
shown++;
|
|
413
376
|
}
|
|
414
377
|
else if (b !== a) {
|
|
415
|
-
process.stdout.write(
|
|
416
|
-
process.stdout.write(
|
|
378
|
+
process.stdout.write(chalk.hex("#f38ba8")("- " + b) + "\n");
|
|
379
|
+
process.stdout.write(chalk.hex("#a6e3a1")("+ " + a) + "\n");
|
|
417
380
|
shown += 2;
|
|
418
381
|
}
|
|
419
382
|
}
|
|
420
383
|
const totalDiff = Math.abs(afterLines.length - beforeLines.length);
|
|
421
384
|
if (totalDiff > maxLines) {
|
|
422
|
-
process.stdout.write(
|
|
385
|
+
process.stdout.write(chalk.dim(` … ${totalDiff - maxLines} more changes\n`));
|
|
423
386
|
}
|
|
424
387
|
}
|
|
425
|
-
process.stdout.write(
|
|
388
|
+
process.stdout.write(chalk.dim("─".repeat(w)) + "\n\n");
|
|
426
389
|
}
|
|
427
390
|
// ---------------------------------------------------------------------------
|
|
428
391
|
// Approval prompt — yellow bordered box
|
|
429
392
|
// ---------------------------------------------------------------------------
|
|
430
|
-
function printApprovalPrompt(title, body) {
|
|
393
|
+
export function printApprovalPrompt(title, body) {
|
|
431
394
|
const w = termWidth();
|
|
432
|
-
const top =
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const bottom =
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const titleLine =
|
|
439
|
-
const bodyLines = wordWrap(body, w - 4).map((l) =>
|
|
395
|
+
const top = chalk.hex("#f9e2af")("╭") +
|
|
396
|
+
chalk.hex("#f9e2af")("─".repeat(w - 2)) +
|
|
397
|
+
chalk.hex("#f9e2af")("╮");
|
|
398
|
+
const bottom = chalk.hex("#f9e2af")("╰") +
|
|
399
|
+
chalk.hex("#f9e2af")("─".repeat(w - 2)) +
|
|
400
|
+
chalk.hex("#f9e2af")("╯");
|
|
401
|
+
const titleLine = chalk.bold.hex("#f9e2af")(" " + title);
|
|
402
|
+
const bodyLines = wordWrap(body, w - 4).map((l) => chalk.hex("#f9e2af")(" " + l));
|
|
440
403
|
process.stdout.write("\n" + top + "\n");
|
|
441
404
|
process.stdout.write(titleLine + "\n");
|
|
442
405
|
for (const l of bodyLines) {
|
|
@@ -452,7 +415,7 @@ let _inCodeFence = false;
|
|
|
452
415
|
let _codeFenceLang = "";
|
|
453
416
|
let _codeFenceBuffer = [];
|
|
454
417
|
let _turnHasContent = false;
|
|
455
|
-
function printTextDelta(text) {
|
|
418
|
+
export function printTextDelta(text) {
|
|
456
419
|
// Stop spinner on first token
|
|
457
420
|
if (_spinnerActive)
|
|
458
421
|
stopSpinner();
|
|
@@ -476,9 +439,9 @@ function _writeLine(line) {
|
|
|
476
439
|
_codeFenceBuffer = [];
|
|
477
440
|
const w = termWidth();
|
|
478
441
|
const lang = _codeFenceLang !== "plaintext" ? _codeFenceLang : "";
|
|
479
|
-
const label = lang ?
|
|
442
|
+
const label = lang ? chalk.dim(` ${lang} `) : "";
|
|
480
443
|
const labelRaw = lang ? ` ${lang} ` : "";
|
|
481
|
-
const rule =
|
|
444
|
+
const rule = chalk.dim("─".repeat(Math.max(0, w - labelRaw.length)));
|
|
482
445
|
process.stdout.write(rule + label + "\n");
|
|
483
446
|
return;
|
|
484
447
|
}
|
|
@@ -498,16 +461,16 @@ function _writeLine(line) {
|
|
|
498
461
|
else {
|
|
499
462
|
if (line === "```") {
|
|
500
463
|
const code = _codeFenceBuffer.join("\n");
|
|
501
|
-
const language = _codeFenceLang &&
|
|
464
|
+
const language = _codeFenceLang && supportsLanguage(_codeFenceLang)
|
|
502
465
|
? _codeFenceLang
|
|
503
466
|
: "plaintext";
|
|
504
467
|
try {
|
|
505
|
-
process.stdout.write(
|
|
468
|
+
process.stdout.write(highlight(code, { language, ignoreIllegals: true }) + "\n");
|
|
506
469
|
}
|
|
507
470
|
catch {
|
|
508
|
-
process.stdout.write(
|
|
471
|
+
process.stdout.write(chalk.dim(code) + "\n");
|
|
509
472
|
}
|
|
510
|
-
process.stdout.write(
|
|
473
|
+
process.stdout.write(chalk.dim("─".repeat(termWidth())) + "\n");
|
|
511
474
|
_inCodeFence = false;
|
|
512
475
|
_codeFenceLang = "";
|
|
513
476
|
_codeFenceBuffer = [];
|
|
@@ -520,21 +483,21 @@ function _writeLine(line) {
|
|
|
520
483
|
// ---------------------------------------------------------------------------
|
|
521
484
|
// Turn lifecycle
|
|
522
485
|
// ---------------------------------------------------------------------------
|
|
523
|
-
function printTurnStart() {
|
|
486
|
+
export function printTurnStart() {
|
|
524
487
|
process.stdout.write("\x1b[?25l"); // hide cursor
|
|
525
488
|
process.stdout.write("\n" +
|
|
526
|
-
|
|
527
|
-
|
|
489
|
+
chalk.hex("#c0384b")(_botName) +
|
|
490
|
+
chalk.dim(" › ") +
|
|
528
491
|
"\n");
|
|
529
492
|
_turnHasContent = false;
|
|
530
493
|
}
|
|
531
|
-
function printThinkingStart() {
|
|
494
|
+
export function printThinkingStart() {
|
|
532
495
|
startSpinner("");
|
|
533
496
|
}
|
|
534
|
-
function printThinkingStop() {
|
|
497
|
+
export function printThinkingStop() {
|
|
535
498
|
stopSpinner();
|
|
536
499
|
}
|
|
537
|
-
function printTurnEnd(costUsd) {
|
|
500
|
+
export function printTurnEnd(costUsd) {
|
|
538
501
|
process.stdout.write("\x1b[?25h"); // restore cursor
|
|
539
502
|
// Stop any lingering spinner or tool line
|
|
540
503
|
if (_spinnerActive)
|
|
@@ -559,23 +522,18 @@ function printTurnEnd(costUsd) {
|
|
|
559
522
|
// First-launch state — show placeholder hint on very first prompt
|
|
560
523
|
// ---------------------------------------------------------------------------
|
|
561
524
|
let _isFirstPrompt = true;
|
|
562
|
-
function consumeFirstPrompt() {
|
|
525
|
+
export function consumeFirstPrompt() {
|
|
563
526
|
const was = _isFirstPrompt;
|
|
564
527
|
_isFirstPrompt = false;
|
|
565
528
|
return was;
|
|
566
529
|
}
|
|
567
|
-
function printPrompt(_showHint = false) {
|
|
568
|
-
//
|
|
569
|
-
//
|
|
570
|
-
//
|
|
571
|
-
//
|
|
572
|
-
// so it was reverted. A real Claude-Code-style input (paste/image/multiline)
|
|
573
|
-
// needs a proper TUI input layer, not a readline override; that's the rebuild.
|
|
574
|
-
process.stdout.write("\n" +
|
|
575
|
-
chalk_1.default.bold.hex("#c0384b")("you") +
|
|
576
|
-
chalk_1.default.dim(" › "));
|
|
530
|
+
export function printPrompt(_showHint = false) {
|
|
531
|
+
// No-op. The bordered input box (input_box.ts, installed on readline in
|
|
532
|
+
// ui_state.ts) draws the whole prompt — borders, side walls, and the "you ›"
|
|
533
|
+
// prefix — live, with the cursor inside it. Now safe because stdin is in raw
|
|
534
|
+
// mode (the cooked-echo bug that made the box leak ^[[200~/arrows is fixed).
|
|
577
535
|
}
|
|
578
|
-
function printPromptEnd() {
|
|
536
|
+
export function printPromptEnd() {
|
|
579
537
|
// No-op. The input box (input_box.ts) erases itself on submit via its end()
|
|
580
538
|
// hook; the committed "you › …" line is then printed by the prompt loop. A
|
|
581
539
|
// bottom border here would draw over the cleared box.
|
|
@@ -583,37 +541,37 @@ function printPromptEnd() {
|
|
|
583
541
|
// ---------------------------------------------------------------------------
|
|
584
542
|
// Welcome + session list
|
|
585
543
|
// ---------------------------------------------------------------------------
|
|
586
|
-
function printWelcome(sessionId, sessionName, resumed, messageCount, lastMessagePreview) {
|
|
544
|
+
export function printWelcome(sessionId, sessionName, resumed, messageCount, lastMessagePreview) {
|
|
587
545
|
initStatusBar(sessionId, sessionName);
|
|
588
546
|
const name = sessionName || sessionId.slice(0, 8);
|
|
589
547
|
// Shortcut bar — shown ONCE on welcome only
|
|
590
548
|
const w = termWidth();
|
|
591
549
|
const shortcuts = [
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
].join(
|
|
550
|
+
chalk.dim("ctrl+c") + " " + chalk.hex("#6c7086")("exit"),
|
|
551
|
+
chalk.dim("ctrl+r") + " " + chalk.hex("#6c7086")("sessions"),
|
|
552
|
+
chalk.dim("ctrl+l") + " " + chalk.hex("#6c7086")("clear"),
|
|
553
|
+
chalk.dim("↑↓") + " " + chalk.hex("#6c7086")("history"),
|
|
554
|
+
].join(chalk.dim(" · "));
|
|
597
555
|
const shortcutRaw = stripAnsi(shortcuts);
|
|
598
556
|
const shortcutPad = Math.max(0, Math.floor((w - shortcutRaw.length) / 2));
|
|
599
557
|
if (resumed) {
|
|
600
558
|
process.stdout.write("\n" +
|
|
601
|
-
|
|
602
|
-
|
|
559
|
+
chalk.hex("#89b4fa")("↩ " + name) +
|
|
560
|
+
chalk.dim(` ${messageCount} turns`) +
|
|
603
561
|
"\n");
|
|
604
562
|
if (lastMessagePreview) {
|
|
605
563
|
const truncated = lastMessagePreview.length > 60
|
|
606
564
|
? lastMessagePreview.slice(0, 60) + "…"
|
|
607
565
|
: lastMessagePreview;
|
|
608
|
-
process.stdout.write(
|
|
566
|
+
process.stdout.write(chalk.dim(' last: "' + truncated + '"') + "\n");
|
|
609
567
|
}
|
|
610
568
|
process.stdout.write("\n" +
|
|
611
569
|
" ".repeat(shortcutPad) + shortcuts + "\n\n");
|
|
612
570
|
}
|
|
613
571
|
else {
|
|
614
572
|
process.stdout.write("\n" +
|
|
615
|
-
|
|
616
|
-
|
|
573
|
+
chalk.hex("#c0384b").bold(`✦ ${_botName}`) +
|
|
574
|
+
chalk.dim(` ${name}`) +
|
|
617
575
|
"\n\n" +
|
|
618
576
|
" ".repeat(shortcutPad) + shortcuts + "\n\n");
|
|
619
577
|
}
|
|
@@ -626,47 +584,47 @@ function printWelcome(sessionId, sessionName, resumed, messageCount, lastMessage
|
|
|
626
584
|
*/
|
|
627
585
|
function _writeIntroBanner() {
|
|
628
586
|
const accent = "#f9e2af";
|
|
629
|
-
const stripe =
|
|
587
|
+
const stripe = chalk.hex(accent)("│");
|
|
630
588
|
const lines = [
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
589
|
+
chalk.bold.hex(accent)("How to use"),
|
|
590
|
+
chalk.dim(`Just talk to ${getBotName()} like a teammate — ask a question, request a`),
|
|
591
|
+
chalk.dim("draft, or say what you need done. It asks before changing files or"),
|
|
592
|
+
chalk.dim('sending anything. Type "help" for examples.'),
|
|
635
593
|
];
|
|
636
594
|
process.stdout.write(lines.map((l) => ` ${stripe} ${l}`).join("\n") + "\n\n");
|
|
637
595
|
}
|
|
638
|
-
function printError(message) {
|
|
639
|
-
process.stderr.write(
|
|
640
|
-
|
|
641
|
-
|
|
596
|
+
export function printError(message) {
|
|
597
|
+
process.stderr.write(chalk.red("\n✗ ") +
|
|
598
|
+
chalk.bold.red("Error: ") +
|
|
599
|
+
chalk.red(message) +
|
|
642
600
|
"\n\n");
|
|
643
601
|
}
|
|
644
|
-
function printSessionList(sessions) {
|
|
602
|
+
export function printSessionList(sessions) {
|
|
645
603
|
if (sessions.length === 0) {
|
|
646
|
-
console.log(
|
|
604
|
+
console.log(chalk.dim("No sessions found."));
|
|
647
605
|
return;
|
|
648
606
|
}
|
|
649
607
|
const w = termWidth();
|
|
650
608
|
process.stdout.write("\n" +
|
|
651
|
-
|
|
609
|
+
chalk.bold.hex("#c0384b")("Sessions") +
|
|
652
610
|
"\n" +
|
|
653
|
-
|
|
611
|
+
chalk.dim("─".repeat(w)) +
|
|
654
612
|
"\n");
|
|
655
613
|
for (const s of sessions) {
|
|
656
614
|
const name = s.session_name
|
|
657
|
-
?
|
|
658
|
-
:
|
|
615
|
+
? chalk.hex("#89b4fa")(s.session_name)
|
|
616
|
+
: chalk.dim("(unnamed)");
|
|
659
617
|
// Session ID hidden — not useful to non-technical users
|
|
660
|
-
const turns =
|
|
661
|
-
const cost =
|
|
662
|
-
const lastActive =
|
|
618
|
+
const turns = chalk.dim(`${s.message_count} turns`);
|
|
619
|
+
const cost = chalk.dim(`$${Number(s.total_cost_usd).toFixed(4)}`);
|
|
620
|
+
const lastActive = chalk.dim(new Date(s.last_active_at).toLocaleString());
|
|
663
621
|
const status = s.status === "active"
|
|
664
|
-
?
|
|
665
|
-
:
|
|
622
|
+
? chalk.hex("#a6e3a1")("●")
|
|
623
|
+
: chalk.dim("○");
|
|
666
624
|
process.stdout.write(` ${status} ${name}\n`);
|
|
667
625
|
process.stdout.write(` ${turns} ${cost} ${lastActive}\n\n`);
|
|
668
626
|
}
|
|
669
|
-
process.stdout.write(
|
|
627
|
+
process.stdout.write(chalk.dim("Resume: xiaotime dev --session <id>\n\n"));
|
|
670
628
|
}
|
|
671
629
|
// ---------------------------------------------------------------------------
|
|
672
630
|
// Tool call indicators
|
|
@@ -733,7 +691,7 @@ const TOOL_FRIENDLY_NAMES = {
|
|
|
733
691
|
summarize_url: "reading that page...",
|
|
734
692
|
fetch_url: "fetching that page...",
|
|
735
693
|
};
|
|
736
|
-
function friendlyToolLabel(name) {
|
|
694
|
+
export function friendlyToolLabel(name) {
|
|
737
695
|
return TOOL_FRIENDLY_NAMES[name] ?? `working on it...`;
|
|
738
696
|
}
|
|
739
697
|
// ---------------------------------------------------------------------------
|
|
@@ -750,7 +708,7 @@ const ERROR_PATTERNS = [
|
|
|
750
708
|
[/EPIPE/i, "Connection was interrupted. Reconnect and try again."],
|
|
751
709
|
[/WEBSOCKET|ws error/i, "Lost the live connection. Reconnecting..."],
|
|
752
710
|
];
|
|
753
|
-
function friendlyError(raw) {
|
|
711
|
+
export function friendlyError(raw) {
|
|
754
712
|
for (const [pattern, friendly] of ERROR_PATTERNS) {
|
|
755
713
|
if (pattern.test(raw))
|
|
756
714
|
return friendly;
|
|
@@ -762,31 +720,31 @@ function friendlyError(raw) {
|
|
|
762
720
|
// ---------------------------------------------------------------------------
|
|
763
721
|
// Help panel
|
|
764
722
|
// ---------------------------------------------------------------------------
|
|
765
|
-
function printHelp() {
|
|
723
|
+
export function printHelp() {
|
|
766
724
|
const w = termWidth();
|
|
767
|
-
const top =
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
const bottom =
|
|
771
|
-
|
|
772
|
-
|
|
725
|
+
const top = chalk.hex("#f9e2af")("╭") +
|
|
726
|
+
chalk.hex("#f9e2af")("─".repeat(w - 2)) +
|
|
727
|
+
chalk.hex("#f9e2af")("╮");
|
|
728
|
+
const bottom = chalk.hex("#f9e2af")("╰") +
|
|
729
|
+
chalk.hex("#f9e2af")("─".repeat(w - 2)) +
|
|
730
|
+
chalk.hex("#f9e2af")("╯");
|
|
773
731
|
const lines = [
|
|
774
|
-
|
|
732
|
+
chalk.bold.hex("#f9e2af")(` ${_botName} — your AI chief of staff`),
|
|
775
733
|
"",
|
|
776
|
-
|
|
734
|
+
chalk.dim(" Just type naturally. Some examples:"),
|
|
777
735
|
"",
|
|
778
|
-
` ${
|
|
779
|
-
` ${
|
|
780
|
-
` ${
|
|
781
|
-
` ${
|
|
782
|
-
` ${
|
|
736
|
+
` ${chalk.hex("#89b4fa")("what's on my calendar today")}`,
|
|
737
|
+
` ${chalk.hex("#89b4fa")("draft a follow-up email to Acme")}`,
|
|
738
|
+
` ${chalk.hex("#89b4fa")("look up Banner Health")}`,
|
|
739
|
+
` ${chalk.hex("#89b4fa")("what signals do I have this week")}`,
|
|
740
|
+
` ${chalk.hex("#89b4fa")("research CrowdStrike")}`,
|
|
783
741
|
"",
|
|
784
|
-
|
|
785
|
-
` ${
|
|
786
|
-
` ${
|
|
787
|
-
` ${
|
|
742
|
+
chalk.dim(" Keyboard shortcuts:"),
|
|
743
|
+
` ${chalk.dim("ctrl+c")} exit ${chalk.dim("ctrl+r")} switch sessions`,
|
|
744
|
+
` ${chalk.dim("ctrl+l")} clear screen ${chalk.dim("ctrl+u")} scroll history`,
|
|
745
|
+
` ${chalk.dim("↑ ↓")} message history`,
|
|
788
746
|
"",
|
|
789
|
-
|
|
747
|
+
chalk.dim(` Type anything to get started. ${_botName} will figure out the rest.`),
|
|
790
748
|
];
|
|
791
749
|
process.stdout.write("\n" + top + "\n");
|
|
792
750
|
for (const l of lines) {
|
|
@@ -797,31 +755,31 @@ function printHelp() {
|
|
|
797
755
|
// ---------------------------------------------------------------------------
|
|
798
756
|
// Disconnect banner
|
|
799
757
|
// ---------------------------------------------------------------------------
|
|
800
|
-
function printDisconnectBanner(reconnecting = true) {
|
|
758
|
+
export function printDisconnectBanner(reconnecting = true) {
|
|
801
759
|
const msg = reconnecting
|
|
802
760
|
? " Lost connection — trying to reconnect..."
|
|
803
761
|
: " Disconnected. Resume with: xiaotime dev";
|
|
804
|
-
process.stdout.write("\n" +
|
|
762
|
+
process.stdout.write("\n" + chalk.dim(msg) + "\n");
|
|
805
763
|
}
|
|
806
764
|
// ---------------------------------------------------------------------------
|
|
807
765
|
// Exit confirmation
|
|
808
766
|
// ---------------------------------------------------------------------------
|
|
809
|
-
function printExitConfirmation() {
|
|
810
|
-
process.stdout.write("\n" +
|
|
811
|
-
process.stdout.write(
|
|
767
|
+
export function printExitConfirmation() {
|
|
768
|
+
process.stdout.write("\n" + chalk.hex("#f9e2af")(" Session paused. Your conversation is saved.") + "\n");
|
|
769
|
+
process.stdout.write(chalk.dim(" Resume anytime with: xiaotime dev") + "\n\n");
|
|
812
770
|
}
|
|
813
|
-
function printToolCallLine(name, detail, durationMs, success = true) {
|
|
771
|
+
export function printToolCallLine(name, detail, durationMs, success = true) {
|
|
814
772
|
setLastTool(name);
|
|
815
|
-
const icon = success ?
|
|
816
|
-
const dur = durationMs !== undefined ?
|
|
817
|
-
const detailStr = detail ?
|
|
818
|
-
process.stdout.write(` ${icon} ${
|
|
773
|
+
const icon = success ? chalk.hex("#a6e3a1")("✓") : chalk.hex("#f38ba8")("✗");
|
|
774
|
+
const dur = durationMs !== undefined ? chalk.dim(` ${durationMs}ms`) : "";
|
|
775
|
+
const detailStr = detail ? chalk.dim(` ${detail}`) : "";
|
|
776
|
+
process.stdout.write(` ${icon} ${chalk.dim(name)}${detailStr}${dur}\n`);
|
|
819
777
|
}
|
|
820
|
-
function printServerToolCall(name, inputSummary, durationMs) {
|
|
778
|
+
export function printServerToolCall(name, inputSummary, durationMs) {
|
|
821
779
|
setLastTool(name);
|
|
822
|
-
const icon =
|
|
823
|
-
const tail = inputSummary ?
|
|
824
|
-
const dur = durationMs !== undefined ?
|
|
825
|
-
process.stdout.write(` ${icon} ${
|
|
780
|
+
const icon = chalk.hex("#a6e3a1")("✓");
|
|
781
|
+
const tail = inputSummary ? chalk.dim(` ${inputSummary}`) : "";
|
|
782
|
+
const dur = durationMs !== undefined ? chalk.dim(` ${durationMs}ms`) : "";
|
|
783
|
+
process.stdout.write(` ${icon} ${chalk.dim(name)}${tail}${dur}\n`);
|
|
826
784
|
}
|
|
827
785
|
//# sourceMappingURL=display.js.map
|