xiaotime 0.5.12 → 0.6.1
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.js +164 -201
- package/dist/display.js.map +1 -1
- package/dist/index.js +29 -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.js +22 -63
- 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,18 +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) {
|
|
530
|
+
export function printPrompt(_showHint = false) {
|
|
568
531
|
// No-op. The bordered input box (input_box.ts, installed on readline in
|
|
569
532
|
// ui_state.ts) draws the whole prompt — borders, side walls, and the "you ›"
|
|
570
533
|
// prefix — live, with the cursor inside it. Now safe because stdin is in raw
|
|
571
534
|
// mode (the cooked-echo bug that made the box leak ^[[200~/arrows is fixed).
|
|
572
535
|
}
|
|
573
|
-
function printPromptEnd() {
|
|
536
|
+
export function printPromptEnd() {
|
|
574
537
|
// No-op. The input box (input_box.ts) erases itself on submit via its end()
|
|
575
538
|
// hook; the committed "you › …" line is then printed by the prompt loop. A
|
|
576
539
|
// bottom border here would draw over the cleared box.
|
|
@@ -578,37 +541,37 @@ function printPromptEnd() {
|
|
|
578
541
|
// ---------------------------------------------------------------------------
|
|
579
542
|
// Welcome + session list
|
|
580
543
|
// ---------------------------------------------------------------------------
|
|
581
|
-
function printWelcome(sessionId, sessionName, resumed, messageCount, lastMessagePreview) {
|
|
544
|
+
export function printWelcome(sessionId, sessionName, resumed, messageCount, lastMessagePreview) {
|
|
582
545
|
initStatusBar(sessionId, sessionName);
|
|
583
546
|
const name = sessionName || sessionId.slice(0, 8);
|
|
584
547
|
// Shortcut bar — shown ONCE on welcome only
|
|
585
548
|
const w = termWidth();
|
|
586
549
|
const shortcuts = [
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
].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(" · "));
|
|
592
555
|
const shortcutRaw = stripAnsi(shortcuts);
|
|
593
556
|
const shortcutPad = Math.max(0, Math.floor((w - shortcutRaw.length) / 2));
|
|
594
557
|
if (resumed) {
|
|
595
558
|
process.stdout.write("\n" +
|
|
596
|
-
|
|
597
|
-
|
|
559
|
+
chalk.hex("#89b4fa")("↩ " + name) +
|
|
560
|
+
chalk.dim(` ${messageCount} turns`) +
|
|
598
561
|
"\n");
|
|
599
562
|
if (lastMessagePreview) {
|
|
600
563
|
const truncated = lastMessagePreview.length > 60
|
|
601
564
|
? lastMessagePreview.slice(0, 60) + "…"
|
|
602
565
|
: lastMessagePreview;
|
|
603
|
-
process.stdout.write(
|
|
566
|
+
process.stdout.write(chalk.dim(' last: "' + truncated + '"') + "\n");
|
|
604
567
|
}
|
|
605
568
|
process.stdout.write("\n" +
|
|
606
569
|
" ".repeat(shortcutPad) + shortcuts + "\n\n");
|
|
607
570
|
}
|
|
608
571
|
else {
|
|
609
572
|
process.stdout.write("\n" +
|
|
610
|
-
|
|
611
|
-
|
|
573
|
+
chalk.hex("#c0384b").bold(`✦ ${_botName}`) +
|
|
574
|
+
chalk.dim(` ${name}`) +
|
|
612
575
|
"\n\n" +
|
|
613
576
|
" ".repeat(shortcutPad) + shortcuts + "\n\n");
|
|
614
577
|
}
|
|
@@ -621,47 +584,47 @@ function printWelcome(sessionId, sessionName, resumed, messageCount, lastMessage
|
|
|
621
584
|
*/
|
|
622
585
|
function _writeIntroBanner() {
|
|
623
586
|
const accent = "#f9e2af";
|
|
624
|
-
const stripe =
|
|
587
|
+
const stripe = chalk.hex(accent)("│");
|
|
625
588
|
const lines = [
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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.'),
|
|
630
593
|
];
|
|
631
594
|
process.stdout.write(lines.map((l) => ` ${stripe} ${l}`).join("\n") + "\n\n");
|
|
632
595
|
}
|
|
633
|
-
function printError(message) {
|
|
634
|
-
process.stderr.write(
|
|
635
|
-
|
|
636
|
-
|
|
596
|
+
export function printError(message) {
|
|
597
|
+
process.stderr.write(chalk.red("\n✗ ") +
|
|
598
|
+
chalk.bold.red("Error: ") +
|
|
599
|
+
chalk.red(message) +
|
|
637
600
|
"\n\n");
|
|
638
601
|
}
|
|
639
|
-
function printSessionList(sessions) {
|
|
602
|
+
export function printSessionList(sessions) {
|
|
640
603
|
if (sessions.length === 0) {
|
|
641
|
-
console.log(
|
|
604
|
+
console.log(chalk.dim("No sessions found."));
|
|
642
605
|
return;
|
|
643
606
|
}
|
|
644
607
|
const w = termWidth();
|
|
645
608
|
process.stdout.write("\n" +
|
|
646
|
-
|
|
609
|
+
chalk.bold.hex("#c0384b")("Sessions") +
|
|
647
610
|
"\n" +
|
|
648
|
-
|
|
611
|
+
chalk.dim("─".repeat(w)) +
|
|
649
612
|
"\n");
|
|
650
613
|
for (const s of sessions) {
|
|
651
614
|
const name = s.session_name
|
|
652
|
-
?
|
|
653
|
-
:
|
|
615
|
+
? chalk.hex("#89b4fa")(s.session_name)
|
|
616
|
+
: chalk.dim("(unnamed)");
|
|
654
617
|
// Session ID hidden — not useful to non-technical users
|
|
655
|
-
const turns =
|
|
656
|
-
const cost =
|
|
657
|
-
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());
|
|
658
621
|
const status = s.status === "active"
|
|
659
|
-
?
|
|
660
|
-
:
|
|
622
|
+
? chalk.hex("#a6e3a1")("●")
|
|
623
|
+
: chalk.dim("○");
|
|
661
624
|
process.stdout.write(` ${status} ${name}\n`);
|
|
662
625
|
process.stdout.write(` ${turns} ${cost} ${lastActive}\n\n`);
|
|
663
626
|
}
|
|
664
|
-
process.stdout.write(
|
|
627
|
+
process.stdout.write(chalk.dim("Resume: xiaotime dev --session <id>\n\n"));
|
|
665
628
|
}
|
|
666
629
|
// ---------------------------------------------------------------------------
|
|
667
630
|
// Tool call indicators
|
|
@@ -728,7 +691,7 @@ const TOOL_FRIENDLY_NAMES = {
|
|
|
728
691
|
summarize_url: "reading that page...",
|
|
729
692
|
fetch_url: "fetching that page...",
|
|
730
693
|
};
|
|
731
|
-
function friendlyToolLabel(name) {
|
|
694
|
+
export function friendlyToolLabel(name) {
|
|
732
695
|
return TOOL_FRIENDLY_NAMES[name] ?? `working on it...`;
|
|
733
696
|
}
|
|
734
697
|
// ---------------------------------------------------------------------------
|
|
@@ -745,7 +708,7 @@ const ERROR_PATTERNS = [
|
|
|
745
708
|
[/EPIPE/i, "Connection was interrupted. Reconnect and try again."],
|
|
746
709
|
[/WEBSOCKET|ws error/i, "Lost the live connection. Reconnecting..."],
|
|
747
710
|
];
|
|
748
|
-
function friendlyError(raw) {
|
|
711
|
+
export function friendlyError(raw) {
|
|
749
712
|
for (const [pattern, friendly] of ERROR_PATTERNS) {
|
|
750
713
|
if (pattern.test(raw))
|
|
751
714
|
return friendly;
|
|
@@ -757,31 +720,31 @@ function friendlyError(raw) {
|
|
|
757
720
|
// ---------------------------------------------------------------------------
|
|
758
721
|
// Help panel
|
|
759
722
|
// ---------------------------------------------------------------------------
|
|
760
|
-
function printHelp() {
|
|
723
|
+
export function printHelp() {
|
|
761
724
|
const w = termWidth();
|
|
762
|
-
const top =
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
const bottom =
|
|
766
|
-
|
|
767
|
-
|
|
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")("╯");
|
|
768
731
|
const lines = [
|
|
769
|
-
|
|
732
|
+
chalk.bold.hex("#f9e2af")(` ${_botName} — your AI chief of staff`),
|
|
770
733
|
"",
|
|
771
|
-
|
|
734
|
+
chalk.dim(" Just type naturally. Some examples:"),
|
|
772
735
|
"",
|
|
773
|
-
` ${
|
|
774
|
-
` ${
|
|
775
|
-
` ${
|
|
776
|
-
` ${
|
|
777
|
-
` ${
|
|
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")}`,
|
|
778
741
|
"",
|
|
779
|
-
|
|
780
|
-
` ${
|
|
781
|
-
` ${
|
|
782
|
-
` ${
|
|
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`,
|
|
783
746
|
"",
|
|
784
|
-
|
|
747
|
+
chalk.dim(` Type anything to get started. ${_botName} will figure out the rest.`),
|
|
785
748
|
];
|
|
786
749
|
process.stdout.write("\n" + top + "\n");
|
|
787
750
|
for (const l of lines) {
|
|
@@ -792,31 +755,31 @@ function printHelp() {
|
|
|
792
755
|
// ---------------------------------------------------------------------------
|
|
793
756
|
// Disconnect banner
|
|
794
757
|
// ---------------------------------------------------------------------------
|
|
795
|
-
function printDisconnectBanner(reconnecting = true) {
|
|
758
|
+
export function printDisconnectBanner(reconnecting = true) {
|
|
796
759
|
const msg = reconnecting
|
|
797
760
|
? " Lost connection — trying to reconnect..."
|
|
798
761
|
: " Disconnected. Resume with: xiaotime dev";
|
|
799
|
-
process.stdout.write("\n" +
|
|
762
|
+
process.stdout.write("\n" + chalk.dim(msg) + "\n");
|
|
800
763
|
}
|
|
801
764
|
// ---------------------------------------------------------------------------
|
|
802
765
|
// Exit confirmation
|
|
803
766
|
// ---------------------------------------------------------------------------
|
|
804
|
-
function printExitConfirmation() {
|
|
805
|
-
process.stdout.write("\n" +
|
|
806
|
-
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");
|
|
807
770
|
}
|
|
808
|
-
function printToolCallLine(name, detail, durationMs, success = true) {
|
|
771
|
+
export function printToolCallLine(name, detail, durationMs, success = true) {
|
|
809
772
|
setLastTool(name);
|
|
810
|
-
const icon = success ?
|
|
811
|
-
const dur = durationMs !== undefined ?
|
|
812
|
-
const detailStr = detail ?
|
|
813
|
-
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`);
|
|
814
777
|
}
|
|
815
|
-
function printServerToolCall(name, inputSummary, durationMs) {
|
|
778
|
+
export function printServerToolCall(name, inputSummary, durationMs) {
|
|
816
779
|
setLastTool(name);
|
|
817
|
-
const icon =
|
|
818
|
-
const tail = inputSummary ?
|
|
819
|
-
const dur = durationMs !== undefined ?
|
|
820
|
-
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`);
|
|
821
784
|
}
|
|
822
785
|
//# sourceMappingURL=display.js.map
|