@qxbyte/muse 0.1.2 → 0.1.3
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/cli.js +1218 -186
- package/dist/cli.js.map +1 -1
- package/dist/index.js +85 -27
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5,14 +5,24 @@ import { Command } from "commander";
|
|
|
5
5
|
import { render } from "ink";
|
|
6
6
|
|
|
7
7
|
// src/app.tsx
|
|
8
|
-
import { useCallback, useEffect as useEffect5, useMemo as useMemo2, useReducer, useRef, useState as
|
|
9
|
-
import { Box as
|
|
8
|
+
import { useCallback, useEffect as useEffect5, useMemo as useMemo2, useReducer, useRef, useState as useState8 } from "react";
|
|
9
|
+
import { Box as Box13, Text as Text15, useApp, useInput as useInput5, useStdout as useStdout2 } from "ink";
|
|
10
10
|
|
|
11
11
|
// src/components/BgTextInput.tsx
|
|
12
12
|
import { useState, useEffect } from "react";
|
|
13
13
|
import { Text, useInput } from "ink";
|
|
14
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
15
|
var BLINK_MS = 530;
|
|
16
|
+
var PASTE_CHAR_THRESHOLD = 200;
|
|
17
|
+
function looksLikePaste(input) {
|
|
18
|
+
return input.includes("\n") || input.includes("\r") || input.length > PASTE_CHAR_THRESHOLD;
|
|
19
|
+
}
|
|
20
|
+
function stripBracketedPaste(s) {
|
|
21
|
+
return s.replace(/\x1b\[20[01]~/g, "");
|
|
22
|
+
}
|
|
23
|
+
function normalizeLineEndings(s) {
|
|
24
|
+
return s.replace(/\r\n?/g, "\n");
|
|
25
|
+
}
|
|
16
26
|
function BgTextInput({
|
|
17
27
|
value,
|
|
18
28
|
onChange,
|
|
@@ -20,7 +30,9 @@ function BgTextInput({
|
|
|
20
30
|
width,
|
|
21
31
|
backgroundColor,
|
|
22
32
|
color,
|
|
23
|
-
isActive = true
|
|
33
|
+
isActive = true,
|
|
34
|
+
onPaste,
|
|
35
|
+
placeholder
|
|
24
36
|
}) {
|
|
25
37
|
const [cursor, setCursor] = useState(value.length);
|
|
26
38
|
const [blinkOn, setBlinkOn] = useState(true);
|
|
@@ -66,17 +78,35 @@ function BgTextInput({
|
|
|
66
78
|
return;
|
|
67
79
|
}
|
|
68
80
|
if (input && !key.return) {
|
|
69
|
-
const
|
|
81
|
+
const cleaned = normalizeLineEndings(stripBracketedPaste(input));
|
|
82
|
+
if (!cleaned) return;
|
|
83
|
+
const insertion = onPaste && looksLikePaste(cleaned) ? onPaste(cleaned) : cleaned;
|
|
84
|
+
const next = value.slice(0, cursor) + insertion + value.slice(cursor);
|
|
70
85
|
onChange(next);
|
|
71
|
-
setCursor((c) => c +
|
|
86
|
+
setCursor((c) => c + insertion.length);
|
|
72
87
|
}
|
|
73
88
|
},
|
|
74
89
|
{ isActive }
|
|
75
90
|
);
|
|
76
|
-
const
|
|
91
|
+
const showCursor = isActive && blinkOn;
|
|
92
|
+
if (value.length === 0 && placeholder) {
|
|
93
|
+
const maxW = Math.max(0, width - 1);
|
|
94
|
+
let truncated = placeholder;
|
|
95
|
+
while (stringWidth(truncated) > maxW && truncated.length > 0) {
|
|
96
|
+
truncated = truncated.slice(0, -1);
|
|
97
|
+
}
|
|
98
|
+
const usedW = 1 + stringWidth(truncated);
|
|
99
|
+
const padLen2 = Math.max(0, width - usedW);
|
|
100
|
+
return /* @__PURE__ */ jsxs(Text, { backgroundColor, color, children: [
|
|
101
|
+
showCursor ? /* @__PURE__ */ jsx(Text, { backgroundColor: "blue", color, dimColor: true, children: " " }) : /* @__PURE__ */ jsx(Text, { backgroundColor, color, children: " " }),
|
|
102
|
+
/* @__PURE__ */ jsx(Text, { backgroundColor, dimColor: true, children: truncated }),
|
|
103
|
+
" ".repeat(padLen2)
|
|
104
|
+
] });
|
|
105
|
+
}
|
|
106
|
+
const displayValue = value.replace(/[\n\r]/g, "\u21B5");
|
|
107
|
+
const view = computeViewport(displayValue, cursor, width);
|
|
77
108
|
const at = view.atChar;
|
|
78
109
|
const padLen = Math.max(0, width - view.consumedWidth);
|
|
79
|
-
const showCursor = isActive && blinkOn;
|
|
80
110
|
return /* @__PURE__ */ jsxs(Text, { backgroundColor, color, children: [
|
|
81
111
|
view.before,
|
|
82
112
|
showCursor ? /* @__PURE__ */ jsx(Text, { backgroundColor: "blue", color, dimColor: true, children: at }) : /* @__PURE__ */ jsx(Text, { backgroundColor, color, children: at }),
|
|
@@ -242,37 +272,533 @@ function pickBanner(width, props) {
|
|
|
242
272
|
|
|
243
273
|
// src/components/MessageView.tsx
|
|
244
274
|
import { useMemo } from "react";
|
|
245
|
-
import { Box as Box2, Text as Text3 } from "ink";
|
|
275
|
+
import { Box as Box2, Text as Text3, useStdout } from "ink";
|
|
276
|
+
|
|
277
|
+
// node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
278
|
+
var ANSI_BACKGROUND_OFFSET = 10;
|
|
279
|
+
var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
|
|
280
|
+
var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
|
|
281
|
+
var wrapAnsi16m = (offset = 0) => (red, green, blue) => `\x1B[${38 + offset};2;${red};${green};${blue}m`;
|
|
282
|
+
var styles = {
|
|
283
|
+
modifier: {
|
|
284
|
+
reset: [0, 0],
|
|
285
|
+
// 21 isn't widely supported and 22 does the same thing
|
|
286
|
+
bold: [1, 22],
|
|
287
|
+
dim: [2, 22],
|
|
288
|
+
italic: [3, 23],
|
|
289
|
+
underline: [4, 24],
|
|
290
|
+
overline: [53, 55],
|
|
291
|
+
inverse: [7, 27],
|
|
292
|
+
hidden: [8, 28],
|
|
293
|
+
strikethrough: [9, 29]
|
|
294
|
+
},
|
|
295
|
+
color: {
|
|
296
|
+
black: [30, 39],
|
|
297
|
+
red: [31, 39],
|
|
298
|
+
green: [32, 39],
|
|
299
|
+
yellow: [33, 39],
|
|
300
|
+
blue: [34, 39],
|
|
301
|
+
magenta: [35, 39],
|
|
302
|
+
cyan: [36, 39],
|
|
303
|
+
white: [37, 39],
|
|
304
|
+
// Bright color
|
|
305
|
+
blackBright: [90, 39],
|
|
306
|
+
gray: [90, 39],
|
|
307
|
+
// Alias of `blackBright`
|
|
308
|
+
grey: [90, 39],
|
|
309
|
+
// Alias of `blackBright`
|
|
310
|
+
redBright: [91, 39],
|
|
311
|
+
greenBright: [92, 39],
|
|
312
|
+
yellowBright: [93, 39],
|
|
313
|
+
blueBright: [94, 39],
|
|
314
|
+
magentaBright: [95, 39],
|
|
315
|
+
cyanBright: [96, 39],
|
|
316
|
+
whiteBright: [97, 39]
|
|
317
|
+
},
|
|
318
|
+
bgColor: {
|
|
319
|
+
bgBlack: [40, 49],
|
|
320
|
+
bgRed: [41, 49],
|
|
321
|
+
bgGreen: [42, 49],
|
|
322
|
+
bgYellow: [43, 49],
|
|
323
|
+
bgBlue: [44, 49],
|
|
324
|
+
bgMagenta: [45, 49],
|
|
325
|
+
bgCyan: [46, 49],
|
|
326
|
+
bgWhite: [47, 49],
|
|
327
|
+
// Bright color
|
|
328
|
+
bgBlackBright: [100, 49],
|
|
329
|
+
bgGray: [100, 49],
|
|
330
|
+
// Alias of `bgBlackBright`
|
|
331
|
+
bgGrey: [100, 49],
|
|
332
|
+
// Alias of `bgBlackBright`
|
|
333
|
+
bgRedBright: [101, 49],
|
|
334
|
+
bgGreenBright: [102, 49],
|
|
335
|
+
bgYellowBright: [103, 49],
|
|
336
|
+
bgBlueBright: [104, 49],
|
|
337
|
+
bgMagentaBright: [105, 49],
|
|
338
|
+
bgCyanBright: [106, 49],
|
|
339
|
+
bgWhiteBright: [107, 49]
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
var modifierNames = Object.keys(styles.modifier);
|
|
343
|
+
var foregroundColorNames = Object.keys(styles.color);
|
|
344
|
+
var backgroundColorNames = Object.keys(styles.bgColor);
|
|
345
|
+
var colorNames = [...foregroundColorNames, ...backgroundColorNames];
|
|
346
|
+
function assembleStyles() {
|
|
347
|
+
const codes = /* @__PURE__ */ new Map();
|
|
348
|
+
for (const [groupName, group] of Object.entries(styles)) {
|
|
349
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
350
|
+
styles[styleName] = {
|
|
351
|
+
open: `\x1B[${style[0]}m`,
|
|
352
|
+
close: `\x1B[${style[1]}m`
|
|
353
|
+
};
|
|
354
|
+
group[styleName] = styles[styleName];
|
|
355
|
+
codes.set(style[0], style[1]);
|
|
356
|
+
}
|
|
357
|
+
Object.defineProperty(styles, groupName, {
|
|
358
|
+
value: group,
|
|
359
|
+
enumerable: false
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
Object.defineProperty(styles, "codes", {
|
|
363
|
+
value: codes,
|
|
364
|
+
enumerable: false
|
|
365
|
+
});
|
|
366
|
+
styles.color.close = "\x1B[39m";
|
|
367
|
+
styles.bgColor.close = "\x1B[49m";
|
|
368
|
+
styles.color.ansi = wrapAnsi16();
|
|
369
|
+
styles.color.ansi256 = wrapAnsi256();
|
|
370
|
+
styles.color.ansi16m = wrapAnsi16m();
|
|
371
|
+
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
372
|
+
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
373
|
+
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
374
|
+
Object.defineProperties(styles, {
|
|
375
|
+
rgbToAnsi256: {
|
|
376
|
+
value(red, green, blue) {
|
|
377
|
+
if (red === green && green === blue) {
|
|
378
|
+
if (red < 8) {
|
|
379
|
+
return 16;
|
|
380
|
+
}
|
|
381
|
+
if (red > 248) {
|
|
382
|
+
return 231;
|
|
383
|
+
}
|
|
384
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
385
|
+
}
|
|
386
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
387
|
+
},
|
|
388
|
+
enumerable: false
|
|
389
|
+
},
|
|
390
|
+
hexToRgb: {
|
|
391
|
+
value(hex) {
|
|
392
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
393
|
+
if (!matches) {
|
|
394
|
+
return [0, 0, 0];
|
|
395
|
+
}
|
|
396
|
+
let [colorString] = matches;
|
|
397
|
+
if (colorString.length === 3) {
|
|
398
|
+
colorString = [...colorString].map((character) => character + character).join("");
|
|
399
|
+
}
|
|
400
|
+
const integer = Number.parseInt(colorString, 16);
|
|
401
|
+
return [
|
|
402
|
+
/* eslint-disable no-bitwise */
|
|
403
|
+
integer >> 16 & 255,
|
|
404
|
+
integer >> 8 & 255,
|
|
405
|
+
integer & 255
|
|
406
|
+
/* eslint-enable no-bitwise */
|
|
407
|
+
];
|
|
408
|
+
},
|
|
409
|
+
enumerable: false
|
|
410
|
+
},
|
|
411
|
+
hexToAnsi256: {
|
|
412
|
+
value: (hex) => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
|
|
413
|
+
enumerable: false
|
|
414
|
+
},
|
|
415
|
+
ansi256ToAnsi: {
|
|
416
|
+
value(code) {
|
|
417
|
+
if (code < 8) {
|
|
418
|
+
return 30 + code;
|
|
419
|
+
}
|
|
420
|
+
if (code < 16) {
|
|
421
|
+
return 90 + (code - 8);
|
|
422
|
+
}
|
|
423
|
+
let red;
|
|
424
|
+
let green;
|
|
425
|
+
let blue;
|
|
426
|
+
if (code >= 232) {
|
|
427
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
428
|
+
green = red;
|
|
429
|
+
blue = red;
|
|
430
|
+
} else {
|
|
431
|
+
code -= 16;
|
|
432
|
+
const remainder = code % 36;
|
|
433
|
+
red = Math.floor(code / 36) / 5;
|
|
434
|
+
green = Math.floor(remainder / 6) / 5;
|
|
435
|
+
blue = remainder % 6 / 5;
|
|
436
|
+
}
|
|
437
|
+
const value = Math.max(red, green, blue) * 2;
|
|
438
|
+
if (value === 0) {
|
|
439
|
+
return 30;
|
|
440
|
+
}
|
|
441
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
442
|
+
if (value === 2) {
|
|
443
|
+
result += 60;
|
|
444
|
+
}
|
|
445
|
+
return result;
|
|
446
|
+
},
|
|
447
|
+
enumerable: false
|
|
448
|
+
},
|
|
449
|
+
rgbToAnsi: {
|
|
450
|
+
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
|
|
451
|
+
enumerable: false
|
|
452
|
+
},
|
|
453
|
+
hexToAnsi: {
|
|
454
|
+
value: (hex) => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
|
|
455
|
+
enumerable: false
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
return styles;
|
|
459
|
+
}
|
|
460
|
+
var ansiStyles = assembleStyles();
|
|
461
|
+
var ansi_styles_default = ansiStyles;
|
|
462
|
+
|
|
463
|
+
// node_modules/chalk/source/vendor/supports-color/index.js
|
|
464
|
+
import process2 from "process";
|
|
465
|
+
import os from "os";
|
|
466
|
+
import tty from "tty";
|
|
467
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process2.argv) {
|
|
468
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
469
|
+
const position = argv.indexOf(prefix + flag);
|
|
470
|
+
const terminatorPosition = argv.indexOf("--");
|
|
471
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
472
|
+
}
|
|
473
|
+
var { env } = process2;
|
|
474
|
+
var flagForceColor;
|
|
475
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
476
|
+
flagForceColor = 0;
|
|
477
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
478
|
+
flagForceColor = 1;
|
|
479
|
+
}
|
|
480
|
+
function envForceColor() {
|
|
481
|
+
if ("FORCE_COLOR" in env) {
|
|
482
|
+
if (env.FORCE_COLOR === "true") {
|
|
483
|
+
return 1;
|
|
484
|
+
}
|
|
485
|
+
if (env.FORCE_COLOR === "false") {
|
|
486
|
+
return 0;
|
|
487
|
+
}
|
|
488
|
+
return env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function translateLevel(level) {
|
|
492
|
+
if (level === 0) {
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
return {
|
|
496
|
+
level,
|
|
497
|
+
hasBasic: true,
|
|
498
|
+
has256: level >= 2,
|
|
499
|
+
has16m: level >= 3
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
503
|
+
const noFlagForceColor = envForceColor();
|
|
504
|
+
if (noFlagForceColor !== void 0) {
|
|
505
|
+
flagForceColor = noFlagForceColor;
|
|
506
|
+
}
|
|
507
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
508
|
+
if (forceColor === 0) {
|
|
509
|
+
return 0;
|
|
510
|
+
}
|
|
511
|
+
if (sniffFlags) {
|
|
512
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
513
|
+
return 3;
|
|
514
|
+
}
|
|
515
|
+
if (hasFlag("color=256")) {
|
|
516
|
+
return 2;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if ("TF_BUILD" in env && "AGENT_NAME" in env) {
|
|
520
|
+
return 1;
|
|
521
|
+
}
|
|
522
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
523
|
+
return 0;
|
|
524
|
+
}
|
|
525
|
+
const min = forceColor || 0;
|
|
526
|
+
if (env.TERM === "dumb") {
|
|
527
|
+
return min;
|
|
528
|
+
}
|
|
529
|
+
if (process2.platform === "win32") {
|
|
530
|
+
const osRelease = os.release().split(".");
|
|
531
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
532
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
533
|
+
}
|
|
534
|
+
return 1;
|
|
535
|
+
}
|
|
536
|
+
if ("CI" in env) {
|
|
537
|
+
if (["GITHUB_ACTIONS", "GITEA_ACTIONS", "CIRCLECI"].some((key) => key in env)) {
|
|
538
|
+
return 3;
|
|
539
|
+
}
|
|
540
|
+
if (["TRAVIS", "APPVEYOR", "GITLAB_CI", "BUILDKITE", "DRONE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
541
|
+
return 1;
|
|
542
|
+
}
|
|
543
|
+
return min;
|
|
544
|
+
}
|
|
545
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
546
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
547
|
+
}
|
|
548
|
+
if (env.COLORTERM === "truecolor") {
|
|
549
|
+
return 3;
|
|
550
|
+
}
|
|
551
|
+
if (env.TERM === "xterm-kitty") {
|
|
552
|
+
return 3;
|
|
553
|
+
}
|
|
554
|
+
if (env.TERM === "xterm-ghostty") {
|
|
555
|
+
return 3;
|
|
556
|
+
}
|
|
557
|
+
if (env.TERM === "wezterm") {
|
|
558
|
+
return 3;
|
|
559
|
+
}
|
|
560
|
+
if ("TERM_PROGRAM" in env) {
|
|
561
|
+
const version = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
562
|
+
switch (env.TERM_PROGRAM) {
|
|
563
|
+
case "iTerm.app": {
|
|
564
|
+
return version >= 3 ? 3 : 2;
|
|
565
|
+
}
|
|
566
|
+
case "Apple_Terminal": {
|
|
567
|
+
return 2;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
572
|
+
return 2;
|
|
573
|
+
}
|
|
574
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
575
|
+
return 1;
|
|
576
|
+
}
|
|
577
|
+
if ("COLORTERM" in env) {
|
|
578
|
+
return 1;
|
|
579
|
+
}
|
|
580
|
+
return min;
|
|
581
|
+
}
|
|
582
|
+
function createSupportsColor(stream, options = {}) {
|
|
583
|
+
const level = _supportsColor(stream, {
|
|
584
|
+
streamIsTTY: stream && stream.isTTY,
|
|
585
|
+
...options
|
|
586
|
+
});
|
|
587
|
+
return translateLevel(level);
|
|
588
|
+
}
|
|
589
|
+
var supportsColor = {
|
|
590
|
+
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
591
|
+
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
592
|
+
};
|
|
593
|
+
var supports_color_default = supportsColor;
|
|
594
|
+
|
|
595
|
+
// node_modules/chalk/source/utilities.js
|
|
596
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
597
|
+
let index = string.indexOf(substring);
|
|
598
|
+
if (index === -1) {
|
|
599
|
+
return string;
|
|
600
|
+
}
|
|
601
|
+
const substringLength = substring.length;
|
|
602
|
+
let endIndex = 0;
|
|
603
|
+
let returnValue = "";
|
|
604
|
+
do {
|
|
605
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
606
|
+
endIndex = index + substringLength;
|
|
607
|
+
index = string.indexOf(substring, endIndex);
|
|
608
|
+
} while (index !== -1);
|
|
609
|
+
returnValue += string.slice(endIndex);
|
|
610
|
+
return returnValue;
|
|
611
|
+
}
|
|
612
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
613
|
+
let endIndex = 0;
|
|
614
|
+
let returnValue = "";
|
|
615
|
+
do {
|
|
616
|
+
const gotCR = string[index - 1] === "\r";
|
|
617
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
618
|
+
endIndex = index + 1;
|
|
619
|
+
index = string.indexOf("\n", endIndex);
|
|
620
|
+
} while (index !== -1);
|
|
621
|
+
returnValue += string.slice(endIndex);
|
|
622
|
+
return returnValue;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// node_modules/chalk/source/index.js
|
|
626
|
+
var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
|
|
627
|
+
var GENERATOR = /* @__PURE__ */ Symbol("GENERATOR");
|
|
628
|
+
var STYLER = /* @__PURE__ */ Symbol("STYLER");
|
|
629
|
+
var IS_EMPTY = /* @__PURE__ */ Symbol("IS_EMPTY");
|
|
630
|
+
var levelMapping = [
|
|
631
|
+
"ansi",
|
|
632
|
+
"ansi",
|
|
633
|
+
"ansi256",
|
|
634
|
+
"ansi16m"
|
|
635
|
+
];
|
|
636
|
+
var styles2 = /* @__PURE__ */ Object.create(null);
|
|
637
|
+
var applyOptions = (object, options = {}) => {
|
|
638
|
+
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
|
|
639
|
+
throw new Error("The `level` option should be an integer from 0 to 3");
|
|
640
|
+
}
|
|
641
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
642
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
643
|
+
};
|
|
644
|
+
var chalkFactory = (options) => {
|
|
645
|
+
const chalk2 = (...strings) => strings.join(" ");
|
|
646
|
+
applyOptions(chalk2, options);
|
|
647
|
+
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
648
|
+
return chalk2;
|
|
649
|
+
};
|
|
650
|
+
function createChalk(options) {
|
|
651
|
+
return chalkFactory(options);
|
|
652
|
+
}
|
|
653
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
654
|
+
for (const [styleName, style] of Object.entries(ansi_styles_default)) {
|
|
655
|
+
styles2[styleName] = {
|
|
656
|
+
get() {
|
|
657
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
658
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
659
|
+
return builder;
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
styles2.visible = {
|
|
664
|
+
get() {
|
|
665
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
666
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
667
|
+
return builder;
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
var getModelAnsi = (model, level, type, ...arguments_) => {
|
|
671
|
+
if (model === "rgb") {
|
|
672
|
+
if (level === "ansi16m") {
|
|
673
|
+
return ansi_styles_default[type].ansi16m(...arguments_);
|
|
674
|
+
}
|
|
675
|
+
if (level === "ansi256") {
|
|
676
|
+
return ansi_styles_default[type].ansi256(ansi_styles_default.rgbToAnsi256(...arguments_));
|
|
677
|
+
}
|
|
678
|
+
return ansi_styles_default[type].ansi(ansi_styles_default.rgbToAnsi(...arguments_));
|
|
679
|
+
}
|
|
680
|
+
if (model === "hex") {
|
|
681
|
+
return getModelAnsi("rgb", level, type, ...ansi_styles_default.hexToRgb(...arguments_));
|
|
682
|
+
}
|
|
683
|
+
return ansi_styles_default[type][model](...arguments_);
|
|
684
|
+
};
|
|
685
|
+
var usedModels = ["rgb", "hex", "ansi256"];
|
|
686
|
+
for (const model of usedModels) {
|
|
687
|
+
styles2[model] = {
|
|
688
|
+
get() {
|
|
689
|
+
const { level } = this;
|
|
690
|
+
return function(...arguments_) {
|
|
691
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansi_styles_default.color.close, this[STYLER]);
|
|
692
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
697
|
+
styles2[bgModel] = {
|
|
698
|
+
get() {
|
|
699
|
+
const { level } = this;
|
|
700
|
+
return function(...arguments_) {
|
|
701
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansi_styles_default.bgColor.close, this[STYLER]);
|
|
702
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
var proto = Object.defineProperties(() => {
|
|
708
|
+
}, {
|
|
709
|
+
...styles2,
|
|
710
|
+
level: {
|
|
711
|
+
enumerable: true,
|
|
712
|
+
get() {
|
|
713
|
+
return this[GENERATOR].level;
|
|
714
|
+
},
|
|
715
|
+
set(level) {
|
|
716
|
+
this[GENERATOR].level = level;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
var createStyler = (open, close, parent) => {
|
|
721
|
+
let openAll;
|
|
722
|
+
let closeAll;
|
|
723
|
+
if (parent === void 0) {
|
|
724
|
+
openAll = open;
|
|
725
|
+
closeAll = close;
|
|
726
|
+
} else {
|
|
727
|
+
openAll = parent.openAll + open;
|
|
728
|
+
closeAll = close + parent.closeAll;
|
|
729
|
+
}
|
|
730
|
+
return {
|
|
731
|
+
open,
|
|
732
|
+
close,
|
|
733
|
+
openAll,
|
|
734
|
+
closeAll,
|
|
735
|
+
parent
|
|
736
|
+
};
|
|
737
|
+
};
|
|
738
|
+
var createBuilder = (self, _styler, _isEmpty) => {
|
|
739
|
+
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
740
|
+
Object.setPrototypeOf(builder, proto);
|
|
741
|
+
builder[GENERATOR] = self;
|
|
742
|
+
builder[STYLER] = _styler;
|
|
743
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
744
|
+
return builder;
|
|
745
|
+
};
|
|
746
|
+
var applyStyle = (self, string) => {
|
|
747
|
+
if (self.level <= 0 || !string) {
|
|
748
|
+
return self[IS_EMPTY] ? "" : string;
|
|
749
|
+
}
|
|
750
|
+
let styler = self[STYLER];
|
|
751
|
+
if (styler === void 0) {
|
|
752
|
+
return string;
|
|
753
|
+
}
|
|
754
|
+
const { openAll, closeAll } = styler;
|
|
755
|
+
if (string.includes("\x1B")) {
|
|
756
|
+
while (styler !== void 0) {
|
|
757
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
758
|
+
styler = styler.parent;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
const lfIndex = string.indexOf("\n");
|
|
762
|
+
if (lfIndex !== -1) {
|
|
763
|
+
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
764
|
+
}
|
|
765
|
+
return openAll + string + closeAll;
|
|
766
|
+
};
|
|
767
|
+
Object.defineProperties(createChalk.prototype, styles2);
|
|
768
|
+
var chalk = createChalk();
|
|
769
|
+
var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
770
|
+
var source_default = chalk;
|
|
771
|
+
|
|
772
|
+
// src/components/MessageView.tsx
|
|
246
773
|
import { marked } from "marked";
|
|
247
774
|
import { markedTerminal } from "marked-terminal";
|
|
248
775
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
776
|
+
if (source_default.level === 0) source_default.level = 3;
|
|
249
777
|
marked.use(markedTerminal());
|
|
250
778
|
function renderMarkdown(text) {
|
|
251
779
|
try {
|
|
252
|
-
|
|
253
|
-
|
|
780
|
+
let out = marked.parse(text);
|
|
781
|
+
out = out.replace(/\n+$/, "");
|
|
782
|
+
out = out.replace(/\*\*([^\n*]+?)\*\*/g, (_, body) => `\x1B[1m${body}\x1B[22m`);
|
|
783
|
+
out = out.replace(/(?<![*\\\x1b])\*([^\n*]+?)\*(?!\*)/g, (_, body) => `\x1B[3m${body}\x1B[23m`);
|
|
784
|
+
out = out.replace(/\x1b\[0m/g, "");
|
|
785
|
+
return out;
|
|
254
786
|
} catch {
|
|
255
787
|
return text;
|
|
256
788
|
}
|
|
257
789
|
}
|
|
258
|
-
function MessageView({
|
|
790
|
+
function MessageView({
|
|
791
|
+
message,
|
|
792
|
+
resultsByCallId
|
|
793
|
+
}) {
|
|
259
794
|
switch (message.role) {
|
|
260
795
|
case "user":
|
|
261
796
|
return /* @__PURE__ */ jsx3(UserMessage, { content: typeof message.content === "string" ? message.content : flattenText(message.content) });
|
|
262
797
|
case "assistant":
|
|
263
|
-
return /* @__PURE__ */ jsx3(AssistantMessage, { content: message.content });
|
|
798
|
+
return /* @__PURE__ */ jsx3(AssistantMessage, { content: message.content, resultsByCallId });
|
|
264
799
|
case "tool":
|
|
265
800
|
if (message.toolName === "TodoWrite") return null;
|
|
266
|
-
return /* @__PURE__ */ jsx3(
|
|
267
|
-
ToolResultLine,
|
|
268
|
-
{
|
|
269
|
-
isError: message.isError ?? false,
|
|
270
|
-
content: message.content,
|
|
271
|
-
diff: message.diff,
|
|
272
|
-
summary: message.summary,
|
|
273
|
-
kind: message.kind
|
|
274
|
-
}
|
|
275
|
-
);
|
|
801
|
+
return /* @__PURE__ */ jsx3(ToolResultTree, { result: message, standalone: true });
|
|
276
802
|
case "system":
|
|
277
803
|
return null;
|
|
278
804
|
}
|
|
@@ -281,13 +807,38 @@ function flattenText(parts) {
|
|
|
281
807
|
return parts.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
282
808
|
}
|
|
283
809
|
var DOT = "\u23FA";
|
|
810
|
+
var USER_BG = "#262626";
|
|
284
811
|
function UserMessage({ content }) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
812
|
+
const { stdout } = useStdout();
|
|
813
|
+
const termWidth = stdout?.columns ?? 80;
|
|
814
|
+
const bandWidth = Math.max(1, termWidth - 1);
|
|
815
|
+
const PREFIX = " \u203A ";
|
|
816
|
+
const PREFIX_W = 3;
|
|
817
|
+
const rendered = useMemo(() => renderMarkdown(content), [content]);
|
|
818
|
+
const lines = rendered.split("\n");
|
|
819
|
+
const bg = source_default.bgHex(USER_BG);
|
|
820
|
+
const prefixStyle = source_default.gray.bold;
|
|
821
|
+
const padRow = bg(" ".repeat(bandWidth));
|
|
822
|
+
return /* @__PURE__ */ jsxs3(Box2, { flexDirection: "column", marginTop: 1, children: [
|
|
823
|
+
/* @__PURE__ */ jsx3(Text3, { children: padRow }),
|
|
824
|
+
lines.map((line, i) => {
|
|
825
|
+
const visible = stringWidth(stripAnsi(line));
|
|
826
|
+
const padLen = Math.max(0, bandWidth - PREFIX_W - visible);
|
|
827
|
+
const prefix = i === 0 ? PREFIX : " ";
|
|
828
|
+
const fullLine = bg(prefixStyle(prefix) + line + " ".repeat(padLen));
|
|
829
|
+
return /* @__PURE__ */ jsx3(Text3, { children: fullLine }, i);
|
|
830
|
+
}),
|
|
831
|
+
/* @__PURE__ */ jsx3(Text3, { children: padRow })
|
|
288
832
|
] });
|
|
289
833
|
}
|
|
290
|
-
|
|
834
|
+
var ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
835
|
+
function stripAnsi(s) {
|
|
836
|
+
return s.replace(ANSI_RE, "");
|
|
837
|
+
}
|
|
838
|
+
function AssistantMessage({
|
|
839
|
+
content,
|
|
840
|
+
resultsByCallId
|
|
841
|
+
}) {
|
|
291
842
|
return /* @__PURE__ */ jsx3(Box2, { flexDirection: "column", marginTop: 1, children: content.map((part, i) => {
|
|
292
843
|
if (part.type === "text") {
|
|
293
844
|
return /* @__PURE__ */ jsx3(AssistantTextPart, { text: part.text }, i);
|
|
@@ -296,7 +847,8 @@ function AssistantMessage({ content }) {
|
|
|
296
847
|
if (part.name === "TodoWrite") {
|
|
297
848
|
return /* @__PURE__ */ jsx3(TodoList, { todos: extractTodos(part.args) }, i);
|
|
298
849
|
}
|
|
299
|
-
|
|
850
|
+
const result = resultsByCallId?.get(part.id);
|
|
851
|
+
return /* @__PURE__ */ jsx3(ToolCallBlock, { name: part.name, args: part.args, result }, i);
|
|
300
852
|
}
|
|
301
853
|
return null;
|
|
302
854
|
}) });
|
|
@@ -360,36 +912,50 @@ function TodoRow({ todo }) {
|
|
|
360
912
|
] });
|
|
361
913
|
}
|
|
362
914
|
}
|
|
363
|
-
function
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
summary,
|
|
368
|
-
kind
|
|
915
|
+
function ToolCallBlock({
|
|
916
|
+
name,
|
|
917
|
+
args,
|
|
918
|
+
result
|
|
369
919
|
}) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const
|
|
920
|
+
return /* @__PURE__ */ jsxs3(Box2, { flexDirection: "column", children: [
|
|
921
|
+
/* @__PURE__ */ jsx3(ToolCallLine, { name, args }),
|
|
922
|
+
result && /* @__PURE__ */ jsx3(ToolResultTree, { result })
|
|
923
|
+
] });
|
|
924
|
+
}
|
|
925
|
+
var MAX_RESULT_LINES = 5;
|
|
926
|
+
function ToolResultTree({ result, standalone = false }) {
|
|
927
|
+
const isError = result.isError ?? false;
|
|
928
|
+
const effective = result.kind ?? (isError ? "error" : "success");
|
|
378
929
|
const dotColor = effective === "error" ? "red" : effective === "warn" ? "yellowBright" : "green";
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
930
|
+
const cleaned = stripWrapperTags(result.content);
|
|
931
|
+
const rawLines = cleaned.split("\n");
|
|
932
|
+
while (rawLines.length > 0 && rawLines[rawLines.length - 1].trim() === "") rawLines.pop();
|
|
933
|
+
while (rawLines.length > 0 && rawLines[0].trim() === "") rawLines.shift();
|
|
934
|
+
let displayLines;
|
|
935
|
+
let omitted = 0;
|
|
936
|
+
if (result.summary) {
|
|
937
|
+
const extra = rawLines.length > 1 ? ` (+${rawLines.length - 1} lines)` : "";
|
|
938
|
+
displayLines = [result.summary + extra];
|
|
939
|
+
} else if (rawLines.length === 0) {
|
|
940
|
+
displayLines = ["(no output)"];
|
|
941
|
+
} else if (rawLines.length <= MAX_RESULT_LINES) {
|
|
942
|
+
displayLines = rawLines;
|
|
943
|
+
} else {
|
|
944
|
+
displayLines = rawLines.slice(0, MAX_RESULT_LINES);
|
|
945
|
+
omitted = rawLines.length - MAX_RESULT_LINES;
|
|
946
|
+
}
|
|
947
|
+
return /* @__PURE__ */ jsxs3(Box2, { flexDirection: "column", marginLeft: 2, marginTop: standalone ? 1 : 0, children: [
|
|
948
|
+
displayLines.map((line, i) => /* @__PURE__ */ jsxs3(Box2, { flexDirection: "row", children: [
|
|
949
|
+
/* @__PURE__ */ jsx3(Text3, { color: i === 0 ? dotColor : void 0, children: i === 0 ? "\u2514 " : " " }),
|
|
950
|
+
/* @__PURE__ */ jsx3(Box2, { flexGrow: 1, minWidth: 0, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, wrap: "truncate-end", children: line || " " }) })
|
|
951
|
+
] }, i)),
|
|
952
|
+
omitted > 0 && /* @__PURE__ */ jsx3(Box2, { marginLeft: 2, children: /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: `(+${omitted} more lines)` }) }),
|
|
953
|
+
result.diff && /* @__PURE__ */ jsx3(DiffBlock, { diff: result.diff })
|
|
391
954
|
] });
|
|
392
955
|
}
|
|
956
|
+
function stripWrapperTags(content) {
|
|
957
|
+
return content.split("\n").filter((l) => !/^<\/?(stdout|stderr|timeout|exit_code)>\s*$/.test(l.trim())).join("\n");
|
|
958
|
+
}
|
|
393
959
|
function DiffBlock({ diff }) {
|
|
394
960
|
const lines = diff.split("\n");
|
|
395
961
|
const start = lines.findIndex((l) => l.startsWith("@@"));
|
|
@@ -676,9 +1242,340 @@ function formatTime(iso) {
|
|
|
676
1242
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
677
1243
|
}
|
|
678
1244
|
|
|
679
|
-
// src/components/
|
|
680
|
-
import {
|
|
1245
|
+
// src/components/QuestionPicker.tsx
|
|
1246
|
+
import { useState as useState4 } from "react";
|
|
1247
|
+
import { Box as Box7, Text as Text8, useInput as useInput4 } from "ink";
|
|
681
1248
|
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1249
|
+
var POINTER_COLOR2 = "#A855F7";
|
|
1250
|
+
var FOCUS_BG = "#5B5598";
|
|
1251
|
+
var FOCUS_FG = "white";
|
|
1252
|
+
var SUBMIT_COLOR = "green";
|
|
1253
|
+
var NOTES_LABEL_COLOR = "yellow";
|
|
1254
|
+
var PREVIEW_BORDER = "gray";
|
|
1255
|
+
var TAB_GAP = 3;
|
|
1256
|
+
var PREVIEW_MIN_WIDTH = 28;
|
|
1257
|
+
function QuestionPicker({ request }) {
|
|
1258
|
+
const { questions } = request;
|
|
1259
|
+
const N = questions.length;
|
|
1260
|
+
const hasTabs = N > 1;
|
|
1261
|
+
const submitTabIndex = N;
|
|
1262
|
+
const [tabIndex, setTabIndex] = useState4(0);
|
|
1263
|
+
const [states, setStates] = useState4(
|
|
1264
|
+
() => questions.map(() => ({
|
|
1265
|
+
optionIndex: 0,
|
|
1266
|
+
selected: /* @__PURE__ */ new Set(),
|
|
1267
|
+
notes: "",
|
|
1268
|
+
notesEditing: false,
|
|
1269
|
+
notesDraft: ""
|
|
1270
|
+
}))
|
|
1271
|
+
);
|
|
1272
|
+
const currentQ = tabIndex < N ? questions[tabIndex] : null;
|
|
1273
|
+
const isMulti = currentQ?.multiSelect === true;
|
|
1274
|
+
const onSubmitChip = hasTabs && tabIndex === submitTabIndex;
|
|
1275
|
+
const anyPreview = !!currentQ?.options.some((o) => o.preview);
|
|
1276
|
+
const focusedOpt = currentQ?.options[states[tabIndex]?.optionIndex ?? 0];
|
|
1277
|
+
const focusedPreview = anyPreview ? focusedOpt?.preview ?? "" : "";
|
|
1278
|
+
const buildResponses = (cancelled) => {
|
|
1279
|
+
if (cancelled) return questions.map(() => ({ cancelled: true, selections: [] }));
|
|
1280
|
+
return questions.map((q, qi) => ({
|
|
1281
|
+
cancelled: false,
|
|
1282
|
+
selections: Array.from(states[qi].selected).sort((a, b) => a - b).map((i) => q.options[i].label),
|
|
1283
|
+
notes: states[qi].notes
|
|
1284
|
+
}));
|
|
1285
|
+
};
|
|
1286
|
+
const submit = () => request.resolve(buildResponses(false));
|
|
1287
|
+
const cancel = () => request.resolve(buildResponses(true));
|
|
1288
|
+
const updateState = (qi, mut) => {
|
|
1289
|
+
setStates((prev) => {
|
|
1290
|
+
const next = [...prev];
|
|
1291
|
+
next[qi] = mut(prev[qi]);
|
|
1292
|
+
return next;
|
|
1293
|
+
});
|
|
1294
|
+
};
|
|
1295
|
+
const toggleOption = (qi, oi) => {
|
|
1296
|
+
updateState(qi, (s) => {
|
|
1297
|
+
const sel = new Set(s.selected);
|
|
1298
|
+
if (sel.has(oi)) sel.delete(oi);
|
|
1299
|
+
else sel.add(oi);
|
|
1300
|
+
return { ...s, selected: sel };
|
|
1301
|
+
});
|
|
1302
|
+
};
|
|
1303
|
+
const selectSingleOption = (qi, oi) => {
|
|
1304
|
+
updateState(qi, (s) => ({ ...s, selected: /* @__PURE__ */ new Set([oi]) }));
|
|
1305
|
+
if (!hasTabs) {
|
|
1306
|
+
request.resolve([
|
|
1307
|
+
{
|
|
1308
|
+
cancelled: false,
|
|
1309
|
+
selections: [questions[0].options[oi].label],
|
|
1310
|
+
notes: states[0].notes
|
|
1311
|
+
}
|
|
1312
|
+
]);
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
if (qi < N - 1) setTabIndex(qi + 1);
|
|
1316
|
+
else setTabIndex(submitTabIndex);
|
|
1317
|
+
};
|
|
1318
|
+
const singleQMultiSubmitRowIndex = !hasTabs && isMulti ? currentQ.options.length : -1;
|
|
1319
|
+
const optionRowCount = !hasTabs && isMulti ? currentQ.options.length + 1 : currentQ?.options.length ?? 0;
|
|
1320
|
+
const currentNotesEditing = tabIndex < N ? states[tabIndex].notesEditing : false;
|
|
1321
|
+
useInput4((input, key) => {
|
|
1322
|
+
if (currentNotesEditing) {
|
|
1323
|
+
if (key.escape) {
|
|
1324
|
+
updateState(tabIndex, (s2) => ({ ...s2, notesEditing: false, notesDraft: "" }));
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
if (key.return) {
|
|
1328
|
+
updateState(tabIndex, (s2) => ({
|
|
1329
|
+
...s2,
|
|
1330
|
+
notesEditing: false,
|
|
1331
|
+
notes: s2.notesDraft,
|
|
1332
|
+
notesDraft: ""
|
|
1333
|
+
}));
|
|
1334
|
+
return;
|
|
1335
|
+
}
|
|
1336
|
+
if (key.backspace || key.delete) {
|
|
1337
|
+
updateState(tabIndex, (s2) => ({
|
|
1338
|
+
...s2,
|
|
1339
|
+
notesDraft: s2.notesDraft.slice(0, -1)
|
|
1340
|
+
}));
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
if (key.ctrl || key.tab || key.upArrow || key.downArrow || key.leftArrow || key.rightArrow || key.meta) {
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
if (input) {
|
|
1347
|
+
updateState(tabIndex, (s2) => ({ ...s2, notesDraft: s2.notesDraft + input }));
|
|
1348
|
+
}
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
if (key.escape) {
|
|
1352
|
+
cancel();
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
if (hasTabs && (key.tab || key.leftArrow || key.rightArrow)) {
|
|
1356
|
+
if (key.leftArrow || key.shift && key.tab) {
|
|
1357
|
+
setTabIndex((t) => Math.max(0, t - 1));
|
|
1358
|
+
} else {
|
|
1359
|
+
setTabIndex((t) => Math.min(submitTabIndex, t + 1));
|
|
1360
|
+
}
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
if (onSubmitChip) {
|
|
1364
|
+
if (key.return) submit();
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
const qi = tabIndex;
|
|
1368
|
+
const s = states[qi];
|
|
1369
|
+
if (key.upArrow) {
|
|
1370
|
+
updateState(qi, (st) => ({ ...st, optionIndex: Math.max(0, st.optionIndex - 1) }));
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
if (key.downArrow) {
|
|
1374
|
+
updateState(qi, (st) => ({
|
|
1375
|
+
...st,
|
|
1376
|
+
optionIndex: Math.min(optionRowCount - 1, st.optionIndex + 1)
|
|
1377
|
+
}));
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
if (input === "n" && !key.ctrl && !key.meta) {
|
|
1381
|
+
updateState(qi, (st) => ({
|
|
1382
|
+
...st,
|
|
1383
|
+
notesEditing: true,
|
|
1384
|
+
notesDraft: st.notes
|
|
1385
|
+
}));
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
if (key.return) {
|
|
1389
|
+
if (!hasTabs && isMulti && s.optionIndex === singleQMultiSubmitRowIndex) {
|
|
1390
|
+
submit();
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
if (isMulti) toggleOption(qi, s.optionIndex);
|
|
1394
|
+
else selectSingleOption(qi, s.optionIndex);
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
if (isMulti && input === " " && s.optionIndex !== singleQMultiSubmitRowIndex) {
|
|
1398
|
+
toggleOption(qi, s.optionIndex);
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
1402
|
+
/* @__PURE__ */ jsx8(Divider, {}),
|
|
1403
|
+
hasTabs && /* @__PURE__ */ jsx8(Box7, { marginTop: 0, children: /* @__PURE__ */ jsx8(TabBar, { questions, states, tabIndex }) }),
|
|
1404
|
+
tabIndex < N && /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
1405
|
+
/* @__PURE__ */ jsx8(Text8, { children: questions[tabIndex].question }),
|
|
1406
|
+
/* @__PURE__ */ jsxs8(Box7, { flexDirection: "row", marginTop: 1, children: [
|
|
1407
|
+
/* @__PURE__ */ jsx8(Box7, { flexDirection: "column", flexGrow: anyPreview ? 0 : 1, flexShrink: 0, marginRight: anyPreview ? 2 : 0, children: /* @__PURE__ */ jsx8(
|
|
1408
|
+
OptionsList,
|
|
1409
|
+
{
|
|
1410
|
+
options: questions[tabIndex].options,
|
|
1411
|
+
focusedIndex: states[tabIndex].optionIndex,
|
|
1412
|
+
selected: states[tabIndex].selected,
|
|
1413
|
+
isMulti,
|
|
1414
|
+
submitRowIndex: singleQMultiSubmitRowIndex
|
|
1415
|
+
}
|
|
1416
|
+
) }),
|
|
1417
|
+
anyPreview && /* @__PURE__ */ jsx8(Box7, { flexGrow: 1, minWidth: PREVIEW_MIN_WIDTH, children: /* @__PURE__ */ jsx8(PreviewPanel, { content: focusedPreview }) })
|
|
1418
|
+
] }),
|
|
1419
|
+
/* @__PURE__ */ jsx8(
|
|
1420
|
+
NotesLine,
|
|
1421
|
+
{
|
|
1422
|
+
notes: states[tabIndex].notes,
|
|
1423
|
+
editing: states[tabIndex].notesEditing,
|
|
1424
|
+
draft: states[tabIndex].notesDraft
|
|
1425
|
+
}
|
|
1426
|
+
)
|
|
1427
|
+
] }),
|
|
1428
|
+
onSubmitChip && /* @__PURE__ */ jsx8(Box7, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx8(SubmitPreview, { questions, states }) }),
|
|
1429
|
+
/* @__PURE__ */ jsx8(Divider, {}),
|
|
1430
|
+
/* @__PURE__ */ jsx8(Box7, { children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: hintLine(hasTabs, isMulti, currentNotesEditing) }) })
|
|
1431
|
+
] });
|
|
1432
|
+
}
|
|
1433
|
+
function Divider() {
|
|
1434
|
+
return /* @__PURE__ */ jsx8(Box7, { borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: "gray" });
|
|
1435
|
+
}
|
|
1436
|
+
function TabBar({
|
|
1437
|
+
questions,
|
|
1438
|
+
states,
|
|
1439
|
+
tabIndex
|
|
1440
|
+
}) {
|
|
1441
|
+
const submitIndex = questions.length;
|
|
1442
|
+
const canLeft = tabIndex > 0;
|
|
1443
|
+
const canRight = tabIndex < submitIndex;
|
|
1444
|
+
return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
1445
|
+
/* @__PURE__ */ jsx8(Box7, { marginRight: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: !canLeft, children: "\u2190" }) }),
|
|
1446
|
+
questions.map((q, i) => {
|
|
1447
|
+
const focused = i === tabIndex;
|
|
1448
|
+
const isMulti = q.multiSelect === true;
|
|
1449
|
+
const count = states[i].selected.size;
|
|
1450
|
+
const answered = count > 0;
|
|
1451
|
+
const mark = answered ? isMulti ? `[${count}]` : "\u2714" : "\u25A1";
|
|
1452
|
+
return /* @__PURE__ */ jsx8(Box7, { marginRight: TAB_GAP, children: /* @__PURE__ */ jsx8(
|
|
1453
|
+
Text8,
|
|
1454
|
+
{
|
|
1455
|
+
backgroundColor: focused ? FOCUS_BG : void 0,
|
|
1456
|
+
color: focused ? FOCUS_FG : void 0,
|
|
1457
|
+
bold: focused,
|
|
1458
|
+
dimColor: !focused,
|
|
1459
|
+
children: ` ${mark} ${q.header} `
|
|
1460
|
+
}
|
|
1461
|
+
) }, i);
|
|
1462
|
+
}),
|
|
1463
|
+
/* @__PURE__ */ jsx8(Box7, { marginRight: 1, children: /* @__PURE__ */ jsx8(
|
|
1464
|
+
Text8,
|
|
1465
|
+
{
|
|
1466
|
+
backgroundColor: tabIndex === submitIndex ? FOCUS_BG : void 0,
|
|
1467
|
+
color: tabIndex === submitIndex ? FOCUS_FG : SUBMIT_COLOR,
|
|
1468
|
+
bold: tabIndex === submitIndex,
|
|
1469
|
+
dimColor: tabIndex !== submitIndex,
|
|
1470
|
+
children: " \u2714 Submit "
|
|
1471
|
+
}
|
|
1472
|
+
) }),
|
|
1473
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: !canRight, children: "\u2192" })
|
|
1474
|
+
] });
|
|
1475
|
+
}
|
|
1476
|
+
function OptionsList({
|
|
1477
|
+
options,
|
|
1478
|
+
focusedIndex,
|
|
1479
|
+
selected,
|
|
1480
|
+
isMulti,
|
|
1481
|
+
submitRowIndex
|
|
1482
|
+
}) {
|
|
1483
|
+
return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", children: [
|
|
1484
|
+
options.map((opt, i) => {
|
|
1485
|
+
const focused = i === focusedIndex;
|
|
1486
|
+
const checked = selected.has(i);
|
|
1487
|
+
return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", children: [
|
|
1488
|
+
/* @__PURE__ */ jsxs8(Box7, { flexDirection: "row", children: [
|
|
1489
|
+
/* @__PURE__ */ jsx8(Text8, { color: POINTER_COLOR2, bold: true, children: focused ? "\u203A " : " " }),
|
|
1490
|
+
isMulti && /* @__PURE__ */ jsx8(Text8, { color: checked ? "green" : void 0, children: checked ? "[x] " : "[ ] " }),
|
|
1491
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: `${i + 1}. ` }),
|
|
1492
|
+
/* @__PURE__ */ jsx8(Text8, { color: focused ? POINTER_COLOR2 : void 0, bold: focused, children: opt.label })
|
|
1493
|
+
] }),
|
|
1494
|
+
opt.description && /* @__PURE__ */ jsx8(Box7, { marginLeft: isMulti ? 6 : 5, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, wrap: "truncate-end", children: opt.description }) })
|
|
1495
|
+
] }, i);
|
|
1496
|
+
}),
|
|
1497
|
+
submitRowIndex >= 0 && /* @__PURE__ */ jsxs8(Box7, { flexDirection: "row", marginTop: 1, children: [
|
|
1498
|
+
/* @__PURE__ */ jsx8(Text8, { color: POINTER_COLOR2, bold: true, children: focusedIndex === submitRowIndex ? "\u203A " : " " }),
|
|
1499
|
+
/* @__PURE__ */ jsx8(
|
|
1500
|
+
Text8,
|
|
1501
|
+
{
|
|
1502
|
+
color: focusedIndex === submitRowIndex ? SUBMIT_COLOR : void 0,
|
|
1503
|
+
bold: focusedIndex === submitRowIndex,
|
|
1504
|
+
dimColor: focusedIndex !== submitRowIndex,
|
|
1505
|
+
children: `\u2500\u2500 Submit (${selected.size} selected)`
|
|
1506
|
+
}
|
|
1507
|
+
)
|
|
1508
|
+
] })
|
|
1509
|
+
] });
|
|
1510
|
+
}
|
|
1511
|
+
function PreviewPanel({ content }) {
|
|
1512
|
+
const lines = content ? content.split("\n") : ["(no preview)"];
|
|
1513
|
+
return /* @__PURE__ */ jsx8(
|
|
1514
|
+
Box7,
|
|
1515
|
+
{
|
|
1516
|
+
borderStyle: "round",
|
|
1517
|
+
borderColor: PREVIEW_BORDER,
|
|
1518
|
+
flexDirection: "column",
|
|
1519
|
+
paddingX: 1,
|
|
1520
|
+
flexGrow: 1,
|
|
1521
|
+
children: lines.map((line, i) => /* @__PURE__ */ jsx8(Text8, { wrap: "truncate-end", dimColor: !content, children: line || " " }, i))
|
|
1522
|
+
}
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
function NotesLine({
|
|
1526
|
+
notes,
|
|
1527
|
+
editing,
|
|
1528
|
+
draft
|
|
1529
|
+
}) {
|
|
1530
|
+
if (editing) {
|
|
1531
|
+
return /* @__PURE__ */ jsxs8(Box7, { marginTop: 1, flexDirection: "row", children: [
|
|
1532
|
+
/* @__PURE__ */ jsx8(Text8, { color: NOTES_LABEL_COLOR, bold: true, children: "Notes: " }),
|
|
1533
|
+
/* @__PURE__ */ jsx8(Text8, { children: draft }),
|
|
1534
|
+
/* @__PURE__ */ jsx8(Text8, { color: POINTER_COLOR2, children: "\u258E" }),
|
|
1535
|
+
/* @__PURE__ */ jsx8(Box7, { flexGrow: 1, marginLeft: 2, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "(Enter to save \xB7 Esc to discard)" }) })
|
|
1536
|
+
] });
|
|
1537
|
+
}
|
|
1538
|
+
return /* @__PURE__ */ jsxs8(Box7, { marginTop: 1, flexDirection: "row", justifyContent: "center", children: [
|
|
1539
|
+
/* @__PURE__ */ jsx8(Text8, { color: NOTES_LABEL_COLOR, bold: true, children: "Notes: " }),
|
|
1540
|
+
notes ? /* @__PURE__ */ jsx8(Text8, { children: notes }) : /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "press n to add notes" })
|
|
1541
|
+
] });
|
|
1542
|
+
}
|
|
1543
|
+
function SubmitPreview({
|
|
1544
|
+
questions,
|
|
1545
|
+
states
|
|
1546
|
+
}) {
|
|
1547
|
+
return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", children: [
|
|
1548
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, children: "Review" }),
|
|
1549
|
+
questions.map((q, qi) => {
|
|
1550
|
+
const sel = Array.from(states[qi].selected).sort((a, b) => a - b).map((i) => q.options[i].label);
|
|
1551
|
+
const notes = states[qi].notes.trim();
|
|
1552
|
+
return /* @__PURE__ */ jsxs8(Box7, { flexDirection: "column", marginLeft: 2, children: [
|
|
1553
|
+
/* @__PURE__ */ jsxs8(Box7, { flexDirection: "row", children: [
|
|
1554
|
+
/* @__PURE__ */ jsx8(Text8, { color: "yellow", children: `${q.header}: ` }),
|
|
1555
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: sel.length === 0, children: sel.length > 0 ? sel.join(", ") : "(no answer)" })
|
|
1556
|
+
] }),
|
|
1557
|
+
notes && /* @__PURE__ */ jsxs8(Box7, { marginLeft: 2, flexDirection: "row", children: [
|
|
1558
|
+
/* @__PURE__ */ jsx8(Text8, { color: NOTES_LABEL_COLOR, children: "notes: " }),
|
|
1559
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: notes })
|
|
1560
|
+
] })
|
|
1561
|
+
] }, qi);
|
|
1562
|
+
})
|
|
1563
|
+
] });
|
|
1564
|
+
}
|
|
1565
|
+
function hintLine(hasTabs, isMulti, editingNotes) {
|
|
1566
|
+
if (editingNotes) {
|
|
1567
|
+
return "Enter to save \xB7 Esc to discard \xB7 backspace to delete";
|
|
1568
|
+
}
|
|
1569
|
+
const parts = ["Enter to select", "\u2191/\u2193 to navigate", "n to add notes"];
|
|
1570
|
+
if (hasTabs) parts.push("Tab to switch questions");
|
|
1571
|
+
if (isMulti) parts.push("Space to toggle");
|
|
1572
|
+
parts.push("Esc to cancel");
|
|
1573
|
+
return parts.join(" \xB7 ");
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
// src/components/SlashAutocomplete.tsx
|
|
1577
|
+
import { Box as Box8, Text as Text9 } from "ink";
|
|
1578
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
682
1579
|
var DEFAULT_MAX = 10;
|
|
683
1580
|
var SLASH_COLOR = "#A855F7";
|
|
684
1581
|
function SlashAutocomplete({ matches, index, maxVisible = DEFAULT_MAX }) {
|
|
@@ -687,33 +1584,33 @@ function SlashAutocomplete({ matches, index, maxVisible = DEFAULT_MAX }) {
|
|
|
687
1584
|
const end = Math.min(matches.length, start + maxVisible);
|
|
688
1585
|
const visible = matches.slice(start, end);
|
|
689
1586
|
const nameWidth = Math.max(...matches.map((c) => c.name.length));
|
|
690
|
-
return /* @__PURE__ */
|
|
1587
|
+
return /* @__PURE__ */ jsxs9(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
691
1588
|
visible.map((cmd, i) => {
|
|
692
1589
|
const realIndex = start + i;
|
|
693
|
-
return /* @__PURE__ */
|
|
1590
|
+
return /* @__PURE__ */ jsx9(Row, { cmd, focused: realIndex === index, nameWidth }, cmd.name);
|
|
694
1591
|
}),
|
|
695
|
-
matches.length > visible.length && /* @__PURE__ */
|
|
1592
|
+
matches.length > visible.length && /* @__PURE__ */ jsx9(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
696
1593
|
"\u2191\u2193 select \xB7 Tab/Enter accept \xB7 Esc cancel (",
|
|
697
1594
|
matches.length - visible.length,
|
|
698
1595
|
" more)"
|
|
699
1596
|
] }) }),
|
|
700
|
-
matches.length <= visible.length && /* @__PURE__ */
|
|
1597
|
+
matches.length <= visible.length && /* @__PURE__ */ jsx9(Box8, { marginLeft: 2, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u2191\u2193 select \xB7 Tab/Enter accept \xB7 Esc cancel" }) })
|
|
701
1598
|
] });
|
|
702
1599
|
}
|
|
703
1600
|
function Row({ cmd, focused, nameWidth }) {
|
|
704
1601
|
const padded = cmd.name.padEnd(nameWidth);
|
|
705
|
-
return /* @__PURE__ */
|
|
706
|
-
/* @__PURE__ */
|
|
1602
|
+
return /* @__PURE__ */ jsxs9(Box8, { flexDirection: "row", children: [
|
|
1603
|
+
/* @__PURE__ */ jsxs9(Text9, { color: focused ? SLASH_COLOR : void 0, bold: focused, children: [
|
|
707
1604
|
"/",
|
|
708
1605
|
padded
|
|
709
1606
|
] }),
|
|
710
|
-
/* @__PURE__ */
|
|
711
|
-
/* @__PURE__ */
|
|
1607
|
+
/* @__PURE__ */ jsx9(Text9, { children: " " }),
|
|
1608
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: cmd.description })
|
|
712
1609
|
] });
|
|
713
1610
|
}
|
|
714
1611
|
|
|
715
1612
|
// src/components/PermissionModeBar.tsx
|
|
716
|
-
import { Box as
|
|
1613
|
+
import { Box as Box9, Text as Text10 } from "ink";
|
|
717
1614
|
|
|
718
1615
|
// src/permission/index.ts
|
|
719
1616
|
var MODE_CYCLE = [
|
|
@@ -821,7 +1718,7 @@ var PermissionGate = class {
|
|
|
821
1718
|
};
|
|
822
1719
|
|
|
823
1720
|
// src/components/PermissionModeBar.tsx
|
|
824
|
-
import { jsx as
|
|
1721
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
825
1722
|
function PermissionModeBar({ mode, compact }) {
|
|
826
1723
|
const color = MODE_COLOR[mode];
|
|
827
1724
|
const label = MODE_LABEL[mode];
|
|
@@ -833,23 +1730,23 @@ function PermissionModeBar({ mode, compact }) {
|
|
|
833
1730
|
plan: "[plan]",
|
|
834
1731
|
bypassPermissions: "[bypass]"
|
|
835
1732
|
};
|
|
836
|
-
return /* @__PURE__ */
|
|
837
|
-
/* @__PURE__ */
|
|
838
|
-
/* @__PURE__ */
|
|
1733
|
+
return /* @__PURE__ */ jsxs10(Box9, { flexDirection: "row", children: [
|
|
1734
|
+
/* @__PURE__ */ jsx10(Text10, { color, bold: isBypass, children: short[mode] }),
|
|
1735
|
+
/* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " shift+tab" })
|
|
839
1736
|
] });
|
|
840
1737
|
}
|
|
841
|
-
return /* @__PURE__ */
|
|
842
|
-
/* @__PURE__ */
|
|
1738
|
+
return /* @__PURE__ */ jsxs10(Box9, { flexDirection: "row", children: [
|
|
1739
|
+
/* @__PURE__ */ jsxs10(Text10, { color, bold: isBypass, children: [
|
|
843
1740
|
"\u25B8\u25B8 ",
|
|
844
1741
|
label
|
|
845
1742
|
] }),
|
|
846
|
-
/* @__PURE__ */
|
|
1743
|
+
/* @__PURE__ */ jsx10(Text10, { dimColor: true, children: " (shift+tab to cycle)" })
|
|
847
1744
|
] });
|
|
848
1745
|
}
|
|
849
1746
|
|
|
850
1747
|
// src/components/FooterStatus.tsx
|
|
851
|
-
import { Box as
|
|
852
|
-
import { Fragment, jsx as
|
|
1748
|
+
import { Box as Box10, Text as Text11 } from "ink";
|
|
1749
|
+
import { Fragment, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
853
1750
|
var BAR_TOTAL_WIDE = 10;
|
|
854
1751
|
var BAR_TOTAL_COMPACT = 6;
|
|
855
1752
|
function FooterStatus({
|
|
@@ -865,57 +1762,57 @@ function FooterStatus({
|
|
|
865
1762
|
const hasCtx = contextWindow > 0;
|
|
866
1763
|
const pct = hasCtx ? Math.min(100, Math.round(lastInputTokens / contextWindow * 100)) : 0;
|
|
867
1764
|
const ctxColor = pct >= 90 ? "red" : pct >= 70 ? "yellow" : "green";
|
|
868
|
-
const SEP = /* @__PURE__ */
|
|
869
|
-
const SEP_DOT = /* @__PURE__ */
|
|
1765
|
+
const SEP = /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: " \u2502 " });
|
|
1766
|
+
const SEP_DOT = /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: " \xB7 " });
|
|
870
1767
|
const renderBar = (barW) => {
|
|
871
1768
|
const filled = Math.round(pct / 100 * barW);
|
|
872
1769
|
const empty = barW - filled;
|
|
873
|
-
return /* @__PURE__ */
|
|
874
|
-
filled > 0 && /* @__PURE__ */
|
|
875
|
-
empty > 0 && /* @__PURE__ */
|
|
1770
|
+
return /* @__PURE__ */ jsxs11(Fragment, { children: [
|
|
1771
|
+
filled > 0 && /* @__PURE__ */ jsx11(Text11, { color: ctxColor, children: "\u2588".repeat(filled) }),
|
|
1772
|
+
empty > 0 && /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u2591".repeat(empty) })
|
|
876
1773
|
] });
|
|
877
1774
|
};
|
|
878
1775
|
if (termWidth < 60) {
|
|
879
|
-
return /* @__PURE__ */
|
|
880
|
-
/* @__PURE__ */
|
|
1776
|
+
return /* @__PURE__ */ jsxs11(Box10, { flexDirection: "row", children: [
|
|
1777
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", bold: true, children: sid }),
|
|
881
1778
|
SEP_DOT,
|
|
882
|
-
/* @__PURE__ */
|
|
883
|
-
hasCtx && /* @__PURE__ */
|
|
1779
|
+
/* @__PURE__ */ jsx11(Text11, { color: "magenta", children: model }),
|
|
1780
|
+
hasCtx && /* @__PURE__ */ jsxs11(Fragment, { children: [
|
|
884
1781
|
SEP_DOT,
|
|
885
1782
|
renderBar(BAR_TOTAL_COMPACT),
|
|
886
|
-
/* @__PURE__ */
|
|
1783
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: ` ${pct}%` })
|
|
887
1784
|
] })
|
|
888
1785
|
] });
|
|
889
1786
|
}
|
|
890
1787
|
if (termWidth < 100) {
|
|
891
|
-
return /* @__PURE__ */
|
|
892
|
-
/* @__PURE__ */
|
|
1788
|
+
return /* @__PURE__ */ jsxs11(Box10, { flexDirection: "row", children: [
|
|
1789
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", bold: true, children: `@${sid}` }),
|
|
893
1790
|
SEP,
|
|
894
|
-
/* @__PURE__ */
|
|
895
|
-
hasCtx && /* @__PURE__ */
|
|
1791
|
+
/* @__PURE__ */ jsx11(Text11, { color: "magenta", children: model }),
|
|
1792
|
+
hasCtx && /* @__PURE__ */ jsxs11(Fragment, { children: [
|
|
896
1793
|
SEP,
|
|
897
|
-
/* @__PURE__ */
|
|
1794
|
+
/* @__PURE__ */ jsx11(Text11, { children: "ctx: " }),
|
|
898
1795
|
renderBar(BAR_TOTAL_COMPACT),
|
|
899
|
-
/* @__PURE__ */
|
|
1796
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: ` ${pct}%` })
|
|
900
1797
|
] })
|
|
901
1798
|
] });
|
|
902
1799
|
}
|
|
903
|
-
return /* @__PURE__ */
|
|
904
|
-
/* @__PURE__ */
|
|
1800
|
+
return /* @__PURE__ */ jsxs11(Box10, { flexDirection: "row", children: [
|
|
1801
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", bold: true, children: `@${sid}` }),
|
|
905
1802
|
SEP,
|
|
906
|
-
/* @__PURE__ */
|
|
907
|
-
hasCtx && /* @__PURE__ */
|
|
1803
|
+
/* @__PURE__ */ jsx11(Text11, { color: "magenta", children: model }),
|
|
1804
|
+
hasCtx && /* @__PURE__ */ jsxs11(Fragment, { children: [
|
|
908
1805
|
SEP,
|
|
909
|
-
/* @__PURE__ */
|
|
1806
|
+
/* @__PURE__ */ jsx11(Text11, { children: "ctx: " }),
|
|
910
1807
|
renderBar(BAR_TOTAL_WIDE),
|
|
911
|
-
/* @__PURE__ */
|
|
912
|
-
/* @__PURE__ */
|
|
1808
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: ` ${pct}%` }),
|
|
1809
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: ` ${formatTokens(lastInputTokens)}/${formatTokens(contextWindow)}` })
|
|
913
1810
|
] }),
|
|
914
1811
|
SEP,
|
|
915
|
-
/* @__PURE__ */
|
|
916
|
-
/* @__PURE__ */
|
|
917
|
-
/* @__PURE__ */
|
|
918
|
-
/* @__PURE__ */
|
|
1812
|
+
/* @__PURE__ */ jsx11(Text11, { children: "tok: " }),
|
|
1813
|
+
/* @__PURE__ */ jsx11(Text11, { color: "green", children: `\u2191${formatTokens(sessionInputTokens)}` }),
|
|
1814
|
+
/* @__PURE__ */ jsx11(Text11, { children: " " }),
|
|
1815
|
+
/* @__PURE__ */ jsx11(Text11, { color: "blueBright", children: `\u2193${formatTokens(sessionOutputTokens)}` })
|
|
919
1816
|
] });
|
|
920
1817
|
}
|
|
921
1818
|
function formatTokens(n) {
|
|
@@ -926,14 +1823,14 @@ function formatTokens(n) {
|
|
|
926
1823
|
}
|
|
927
1824
|
|
|
928
1825
|
// src/components/ProgressBanner.tsx
|
|
929
|
-
import { useEffect as useEffect2, useState as
|
|
930
|
-
import { Box as
|
|
931
|
-
import { jsx as
|
|
1826
|
+
import { useEffect as useEffect2, useState as useState5 } from "react";
|
|
1827
|
+
import { Box as Box11, Text as Text12 } from "ink";
|
|
1828
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
932
1829
|
var BAR_WIDTH = 42;
|
|
933
1830
|
var TICK_MS = 400;
|
|
934
1831
|
var TIP_ROTATE_SEC = 5;
|
|
935
1832
|
function ProgressBanner({ state }) {
|
|
936
|
-
const [now, setNow] =
|
|
1833
|
+
const [now, setNow] = useState5(Date.now());
|
|
937
1834
|
useEffect2(() => {
|
|
938
1835
|
const t = setInterval(() => setNow(Date.now()), TICK_MS);
|
|
939
1836
|
return () => clearInterval(t);
|
|
@@ -944,60 +1841,60 @@ function ProgressBanner({ state }) {
|
|
|
944
1841
|
const empty = BAR_WIDTH - filled;
|
|
945
1842
|
const bar = "\u25B0".repeat(filled) + "\u25B1".repeat(empty);
|
|
946
1843
|
const tip = state.tips.length ? state.tips[Math.floor(elapsedSec / TIP_ROTATE_SEC) % state.tips.length] : "";
|
|
947
|
-
return /* @__PURE__ */
|
|
948
|
-
/* @__PURE__ */
|
|
949
|
-
/* @__PURE__ */
|
|
950
|
-
/* @__PURE__ */
|
|
1844
|
+
return /* @__PURE__ */ jsxs12(Box11, { flexDirection: "column", marginTop: 1, children: [
|
|
1845
|
+
/* @__PURE__ */ jsxs12(Box11, { children: [
|
|
1846
|
+
/* @__PURE__ */ jsx12(Text12, { color: "cyan", bold: true, children: "\u2726 " }),
|
|
1847
|
+
/* @__PURE__ */ jsxs12(Text12, { color: "cyan", children: [
|
|
951
1848
|
state.title,
|
|
952
1849
|
"..."
|
|
953
1850
|
] }),
|
|
954
|
-
/* @__PURE__ */
|
|
1851
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: ` (${elapsedSec}s)` })
|
|
955
1852
|
] }),
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
/* @__PURE__ */
|
|
958
|
-
/* @__PURE__ */
|
|
1853
|
+
/* @__PURE__ */ jsxs12(Box11, { marginLeft: 2, children: [
|
|
1854
|
+
/* @__PURE__ */ jsx12(Text12, { color: "cyan", children: bar }),
|
|
1855
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: ` ${percent}%` })
|
|
959
1856
|
] }),
|
|
960
|
-
tip && /* @__PURE__ */
|
|
1857
|
+
tip && /* @__PURE__ */ jsx12(Box11, { marginLeft: 2, children: /* @__PURE__ */ jsx12(Text12, { dimColor: true, children: `\u2514 Tip: ${tip}` }) })
|
|
961
1858
|
] });
|
|
962
1859
|
}
|
|
963
1860
|
|
|
964
1861
|
// src/components/StatusLine.tsx
|
|
965
|
-
import { useEffect as useEffect4, useState as
|
|
966
|
-
import { Box as
|
|
1862
|
+
import { useEffect as useEffect4, useState as useState7 } from "react";
|
|
1863
|
+
import { Box as Box12, Text as Text14 } from "ink";
|
|
967
1864
|
|
|
968
1865
|
// src/components/Shimmer.tsx
|
|
969
|
-
import { useEffect as useEffect3, useState as
|
|
970
|
-
import { Text as
|
|
971
|
-
import { jsx as
|
|
1866
|
+
import { useEffect as useEffect3, useState as useState6 } from "react";
|
|
1867
|
+
import { Text as Text13 } from "ink";
|
|
1868
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
972
1869
|
var FRAME_MS = 100;
|
|
973
1870
|
var TRAIL = 4;
|
|
974
1871
|
function Shimmer({ text, bold = true }) {
|
|
975
1872
|
const chars = Array.from(text);
|
|
976
1873
|
const cycle = chars.length + TRAIL;
|
|
977
|
-
const [phase, setPhase] =
|
|
1874
|
+
const [phase, setPhase] = useState6(0);
|
|
978
1875
|
useEffect3(() => {
|
|
979
1876
|
const id = setInterval(() => {
|
|
980
1877
|
setPhase((p) => (p + 1) % cycle);
|
|
981
1878
|
}, FRAME_MS);
|
|
982
1879
|
return () => clearInterval(id);
|
|
983
1880
|
}, [cycle]);
|
|
984
|
-
return /* @__PURE__ */
|
|
1881
|
+
return /* @__PURE__ */ jsx13(Text13, { children: chars.map((ch, i) => {
|
|
985
1882
|
const d = Math.abs(i - phase);
|
|
986
1883
|
if (d === 0) {
|
|
987
|
-
return /* @__PURE__ */
|
|
1884
|
+
return /* @__PURE__ */ jsx13(Text13, { color: "white", bold, children: ch }, i);
|
|
988
1885
|
}
|
|
989
1886
|
if (d === 1) {
|
|
990
|
-
return /* @__PURE__ */
|
|
1887
|
+
return /* @__PURE__ */ jsx13(Text13, { color: "white", children: ch }, i);
|
|
991
1888
|
}
|
|
992
|
-
return /* @__PURE__ */
|
|
1889
|
+
return /* @__PURE__ */ jsx13(Text13, { color: "gray", dimColor: true, children: ch }, i);
|
|
993
1890
|
}) });
|
|
994
1891
|
}
|
|
995
1892
|
|
|
996
1893
|
// src/components/StatusLine.tsx
|
|
997
|
-
import { jsx as
|
|
1894
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
998
1895
|
var TICK_MS2 = 400;
|
|
999
1896
|
function StatusLine({ startTime, firstTextTime, inputTokens, runningTool, lang }) {
|
|
1000
|
-
const [now, setNow] =
|
|
1897
|
+
const [now, setNow] = useState7(Date.now());
|
|
1001
1898
|
useEffect4(() => {
|
|
1002
1899
|
const t = setInterval(() => setNow(Date.now()), TICK_MS2);
|
|
1003
1900
|
return () => clearInterval(t);
|
|
@@ -1014,15 +1911,15 @@ function StatusLine({ startTime, firstTextTime, inputTokens, runningTool, lang }
|
|
|
1014
1911
|
lang === "zh-CN" ? `\u601D\u8003 ${formatDuration(thinkSec)}` : `thought for ${formatDuration(thinkSec)}`
|
|
1015
1912
|
);
|
|
1016
1913
|
}
|
|
1017
|
-
return /* @__PURE__ */
|
|
1018
|
-
/* @__PURE__ */
|
|
1019
|
-
/* @__PURE__ */
|
|
1020
|
-
/* @__PURE__ */
|
|
1021
|
-
/* @__PURE__ */
|
|
1914
|
+
return /* @__PURE__ */ jsxs13(Box12, { flexDirection: "column", marginTop: 1, children: [
|
|
1915
|
+
/* @__PURE__ */ jsxs13(Box12, { flexDirection: "row", children: [
|
|
1916
|
+
/* @__PURE__ */ jsx14(Text14, { color: "gray", children: "\u25CF " }),
|
|
1917
|
+
/* @__PURE__ */ jsx14(Shimmer, { text: mainLabel }),
|
|
1918
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: ` (${parts.join(" \xB7 ")})` })
|
|
1022
1919
|
] }),
|
|
1023
|
-
runningTool && /* @__PURE__ */
|
|
1024
|
-
/* @__PURE__ */
|
|
1025
|
-
/* @__PURE__ */
|
|
1920
|
+
runningTool && /* @__PURE__ */ jsxs13(Box12, { flexDirection: "row", marginLeft: 2, marginTop: 0, children: [
|
|
1921
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "\u21B3 " }),
|
|
1922
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", children: runningTool })
|
|
1026
1923
|
] })
|
|
1027
1924
|
] });
|
|
1028
1925
|
}
|
|
@@ -1597,6 +2494,7 @@ ${todoSection}` : this.ctx.systemPrompt;
|
|
|
1597
2494
|
this.ctx.events?.onTurnEnd?.();
|
|
1598
2495
|
return;
|
|
1599
2496
|
}
|
|
2497
|
+
this.ctx.events?.onAssistantTurn?.();
|
|
1600
2498
|
for (const call of toolCallsToRun) {
|
|
1601
2499
|
await this.runToolCall(call);
|
|
1602
2500
|
}
|
|
@@ -1677,7 +2575,8 @@ ${todoSection}` : this.ctx.systemPrompt;
|
|
|
1677
2575
|
abortSignal: this.ctx.abortSignal,
|
|
1678
2576
|
askPermission: async () => true,
|
|
1679
2577
|
// 已在外层处理
|
|
1680
|
-
todos: this.todos
|
|
2578
|
+
todos: this.todos,
|
|
2579
|
+
askQuestions: this.ctx.events?.onAskQuestions ? (qs) => this.ctx.events.onAskQuestions(qs) : void 0
|
|
1681
2580
|
};
|
|
1682
2581
|
const result = await this.ctx.tools.execute(call.name, call.args, toolCtx);
|
|
1683
2582
|
this.recordToolResult(call.id, call.name, result.content, result.isError ?? false, result.summary, result.diff, result.kind);
|
|
@@ -2834,7 +3733,7 @@ var BUILTIN_SLASH_COMMANDS = [
|
|
|
2834
3733
|
];
|
|
2835
3734
|
|
|
2836
3735
|
// src/app.tsx
|
|
2837
|
-
import { jsx as
|
|
3736
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2838
3737
|
function reducer(state, action) {
|
|
2839
3738
|
switch (action.type) {
|
|
2840
3739
|
case "user_submit":
|
|
@@ -2891,14 +3790,14 @@ function App({
|
|
|
2891
3790
|
initialMessages
|
|
2892
3791
|
}) {
|
|
2893
3792
|
const { exit } = useApp();
|
|
2894
|
-
const { stdout } =
|
|
3793
|
+
const { stdout } = useStdout2();
|
|
2895
3794
|
const termWidth = stdout?.columns ?? 80;
|
|
2896
|
-
const [llm, setLLM] =
|
|
2897
|
-
const [permissions, setPermissions] =
|
|
2898
|
-
const [settings, setSettings] =
|
|
2899
|
-
const [settingsSources, setSettingsSources] =
|
|
2900
|
-
const [modelsRegistry, setModelsRegistry] =
|
|
2901
|
-
const [mode, setMode] =
|
|
3795
|
+
const [llm, setLLM] = useState8(initialLLM);
|
|
3796
|
+
const [permissions, setPermissions] = useState8(initialPermissions);
|
|
3797
|
+
const [settings, setSettings] = useState8(initialSettings);
|
|
3798
|
+
const [settingsSources, setSettingsSources] = useState8(initialSources);
|
|
3799
|
+
const [modelsRegistry, setModelsRegistry] = useState8(initialModelsRegistry);
|
|
3800
|
+
const [mode, setMode] = useState8(initialPermissions.getMode());
|
|
2902
3801
|
const [state, dispatch] = useReducer(reducer, {
|
|
2903
3802
|
history: initialMessages ?? [],
|
|
2904
3803
|
streamingText: "",
|
|
@@ -2912,20 +3811,32 @@ function App({
|
|
|
2912
3811
|
turnInputTokens: 0
|
|
2913
3812
|
});
|
|
2914
3813
|
const messagesRef = useRef(initialMessages ?? []);
|
|
2915
|
-
const [input, setInput] =
|
|
2916
|
-
const [inputRemountKey, setInputRemountKey] =
|
|
3814
|
+
const [input, setInput] = useState8("");
|
|
3815
|
+
const [inputRemountKey, setInputRemountKey] = useState8(0);
|
|
2917
3816
|
const commitInput = (value) => {
|
|
2918
3817
|
setInput(value);
|
|
2919
3818
|
setInputRemountKey((k) => k + 1);
|
|
2920
3819
|
};
|
|
2921
|
-
const
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
const
|
|
3820
|
+
const pasteRegistryRef = useRef({
|
|
3821
|
+
map: /* @__PURE__ */ new Map(),
|
|
3822
|
+
nextId: 1
|
|
3823
|
+
});
|
|
3824
|
+
const handlePaste = useCallback((chunk) => {
|
|
3825
|
+
const reg = pasteRegistryRef.current;
|
|
3826
|
+
const id = reg.nextId++;
|
|
3827
|
+
reg.map.set(id, chunk);
|
|
3828
|
+
const lines = chunk.split("\n").length;
|
|
3829
|
+
return `[Pasted text #${id} +${lines} lines]`;
|
|
3830
|
+
}, []);
|
|
3831
|
+
const [pending, setPending] = useState8(null);
|
|
3832
|
+
const [picker, setPicker] = useState8(null);
|
|
3833
|
+
const [sessionPicker, setSessionPicker] = useState8(null);
|
|
3834
|
+
const [questionPicker, setQuestionPicker] = useState8(null);
|
|
3835
|
+
const [autocompleteIndex, setAutocompleteIndex] = useState8(0);
|
|
3836
|
+
const [progress, setProgress] = useState8(null);
|
|
2926
3837
|
const agentRef = useRef(null);
|
|
2927
3838
|
const queuedInputsRef = useRef([]);
|
|
2928
|
-
const [queuedInputs, setQueuedInputs] =
|
|
3839
|
+
const [queuedInputs, setQueuedInputs] = useState8([]);
|
|
2929
3840
|
const enqueueInput = (text) => {
|
|
2930
3841
|
queuedInputsRef.current.push(text);
|
|
2931
3842
|
setQueuedInputs([...queuedInputsRef.current]);
|
|
@@ -2979,7 +3890,7 @@ function App({
|
|
|
2979
3890
|
useEffect5(() => {
|
|
2980
3891
|
return () => resetTerminalTitle();
|
|
2981
3892
|
}, []);
|
|
2982
|
-
const [memoryIndex, setMemoryIndex] =
|
|
3893
|
+
const [memoryIndex, setMemoryIndex] = useState8("");
|
|
2983
3894
|
useEffect5(() => {
|
|
2984
3895
|
let cancelled = false;
|
|
2985
3896
|
loadMemoryIndex(cwd).then((idx) => {
|
|
@@ -3008,7 +3919,22 @@ function App({
|
|
|
3008
3919
|
events: {
|
|
3009
3920
|
onText: (delta) => dispatch({ type: "stream_delta", delta }),
|
|
3010
3921
|
onToolCallStart: (_id, name) => dispatch({ type: "tool_start", name }),
|
|
3011
|
-
|
|
3922
|
+
// assistant 流刚结束、这一批 calls 已落到 messages 但 tool 还没开始执行:
|
|
3923
|
+
// 立刻同步 history,让所有 ⏺ Tool(...) 调用头一次性显示出来(之前要等第一个
|
|
3924
|
+
// result 才能见到任何东西,看起来像"卡死了")
|
|
3925
|
+
onAssistantTurn: () => {
|
|
3926
|
+
const msgs = [...agent.getMessages()];
|
|
3927
|
+
messagesRef.current = msgs;
|
|
3928
|
+
dispatch({ type: "history_set", messages: msgs });
|
|
3929
|
+
dispatch({ type: "stream_reset" });
|
|
3930
|
+
},
|
|
3931
|
+
// 每个 tool result 到位就同步:result 立刻挂到对应 ⏺ 调用的 └ 树枝下方
|
|
3932
|
+
onToolResult: () => {
|
|
3933
|
+
const msgs = [...agent.getMessages()];
|
|
3934
|
+
messagesRef.current = msgs;
|
|
3935
|
+
dispatch({ type: "history_set", messages: msgs });
|
|
3936
|
+
dispatch({ type: "set_status", status: "streaming" });
|
|
3937
|
+
},
|
|
3012
3938
|
onUsage: (usage) => dispatch({ type: "add_usage", usage }),
|
|
3013
3939
|
onTurnEnd: () => {
|
|
3014
3940
|
const msgs = [...agent.getMessages()];
|
|
@@ -3020,7 +3946,8 @@ function App({
|
|
|
3020
3946
|
if (next) {
|
|
3021
3947
|
setTimeout(() => {
|
|
3022
3948
|
dispatch({ type: "user_submit" });
|
|
3023
|
-
|
|
3949
|
+
const expanded = expandPastes(next, pasteRegistryRef.current.map);
|
|
3950
|
+
agent.runTurn(expanded).catch((err) => {
|
|
3024
3951
|
const m = err instanceof Error ? err.message : String(err);
|
|
3025
3952
|
dispatch({ type: "stream_delta", delta: `
|
|
3026
3953
|
[error] ${m}
|
|
@@ -3038,13 +3965,16 @@ function App({
|
|
|
3038
3965
|
},
|
|
3039
3966
|
onPermissionRequest: (toolName, args, summary) => new Promise((resolve6) => {
|
|
3040
3967
|
setPending({ toolName, args, summary, resolve: resolve6 });
|
|
3968
|
+
}),
|
|
3969
|
+
onAskQuestions: (questions) => new Promise((resolve6) => {
|
|
3970
|
+
setQuestionPicker({ questions, resolve: resolve6 });
|
|
3041
3971
|
})
|
|
3042
3972
|
}
|
|
3043
3973
|
});
|
|
3044
3974
|
agent.setMessages(messagesRef.current);
|
|
3045
3975
|
agentRef.current = agent;
|
|
3046
3976
|
}, [llm, tools, permissions, session, cwd, lang, memoryIndex]);
|
|
3047
|
-
|
|
3977
|
+
useInput5(
|
|
3048
3978
|
(inputKey, key) => {
|
|
3049
3979
|
if (key.ctrl && inputKey === "c") {
|
|
3050
3980
|
exit();
|
|
@@ -3087,9 +4017,11 @@ function App({
|
|
|
3087
4017
|
},
|
|
3088
4018
|
// 模型在跑时也要响应键盘(让用户能 Ctrl+C / Shift+Tab / autocomplete 导航);
|
|
3089
4019
|
// 仅模态弹起时让出键盘所有权
|
|
3090
|
-
{ isActive: !pending && !picker && !sessionPicker }
|
|
4020
|
+
{ isActive: !pending && !picker && !sessionPicker && !questionPicker }
|
|
3091
4021
|
);
|
|
3092
|
-
const acceptingInput = pending === null && picker === null && sessionPicker === null;
|
|
4022
|
+
const acceptingInput = pending === null && picker === null && sessionPicker === null && questionPicker === null;
|
|
4023
|
+
const inputVisible = pending === null && picker === null && sessionPicker === null;
|
|
4024
|
+
const inputPlaceholder = questionPicker ? "Chat about this" : void 0;
|
|
3093
4025
|
const actions = useMemo2(
|
|
3094
4026
|
() => ({
|
|
3095
4027
|
setMessages: (msgs) => {
|
|
@@ -3221,8 +4153,15 @@ function App({
|
|
|
3221
4153
|
return;
|
|
3222
4154
|
}
|
|
3223
4155
|
dispatch({ type: "user_submit" });
|
|
4156
|
+
const expanded = expandPastes(trimmed, pasteRegistryRef.current.map);
|
|
4157
|
+
{
|
|
4158
|
+
const userMsg = { role: "user", content: expanded };
|
|
4159
|
+
const next = [...messagesRef.current, userMsg];
|
|
4160
|
+
messagesRef.current = next;
|
|
4161
|
+
dispatch({ type: "history_set", messages: next });
|
|
4162
|
+
}
|
|
3224
4163
|
try {
|
|
3225
|
-
await agentRef.current?.runTurn(
|
|
4164
|
+
await agentRef.current?.runTurn(expanded);
|
|
3226
4165
|
} catch (err) {
|
|
3227
4166
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3228
4167
|
dispatch({ type: "stream_delta", delta: `
|
|
@@ -3249,19 +4188,35 @@ function App({
|
|
|
3249
4188
|
}
|
|
3250
4189
|
}
|
|
3251
4190
|
const banner = !showBanner ? null : pickBanner(termWidth, { version: "0.1.0", model: llm.model, cwd: shortCwd(cwd) });
|
|
3252
|
-
|
|
4191
|
+
const { resultsByCallId, inlinedIds } = useMemo2(() => {
|
|
4192
|
+
const byId = /* @__PURE__ */ new Map();
|
|
4193
|
+
const used = /* @__PURE__ */ new Set();
|
|
4194
|
+
for (const m of state.history) {
|
|
4195
|
+
if (m.role === "tool" && m.toolUseId) byId.set(m.toolUseId, m);
|
|
4196
|
+
if (m.role === "assistant" && Array.isArray(m.content)) {
|
|
4197
|
+
for (const p of m.content) {
|
|
4198
|
+
if (p.type === "tool_use") used.add(p.id);
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
return { resultsByCallId: byId, inlinedIds: used };
|
|
4203
|
+
}, [state.history]);
|
|
4204
|
+
return /* @__PURE__ */ jsxs14(Box13, { flexDirection: "column", children: [
|
|
3253
4205
|
banner,
|
|
3254
|
-
/* @__PURE__ */
|
|
3255
|
-
state.history.map((msg, i) =>
|
|
3256
|
-
|
|
3257
|
-
/* @__PURE__ */
|
|
4206
|
+
/* @__PURE__ */ jsxs14(Box13, { flexDirection: "column", marginTop: 1, children: [
|
|
4207
|
+
state.history.map((msg, i) => {
|
|
4208
|
+
if (msg.role === "tool" && inlinedIds.has(msg.toolUseId)) return null;
|
|
4209
|
+
return /* @__PURE__ */ jsx15(MessageView, { message: msg, resultsByCallId }, i);
|
|
4210
|
+
}),
|
|
4211
|
+
state.streamingText && /* @__PURE__ */ jsxs14(Box13, { flexDirection: "row", marginTop: 1, children: [
|
|
4212
|
+
/* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
|
|
3258
4213
|
DOT,
|
|
3259
4214
|
" "
|
|
3260
4215
|
] }),
|
|
3261
|
-
/* @__PURE__ */
|
|
4216
|
+
/* @__PURE__ */ jsx15(Box13, { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsx15(Text15, { children: state.streamingText }) })
|
|
3262
4217
|
] })
|
|
3263
4218
|
] }),
|
|
3264
|
-
pending && /* @__PURE__ */
|
|
4219
|
+
pending && /* @__PURE__ */ jsx15(
|
|
3265
4220
|
PermissionPrompt,
|
|
3266
4221
|
{
|
|
3267
4222
|
request: {
|
|
@@ -3273,7 +4228,7 @@ function App({
|
|
|
3273
4228
|
}
|
|
3274
4229
|
}
|
|
3275
4230
|
),
|
|
3276
|
-
picker && /* @__PURE__ */
|
|
4231
|
+
picker && /* @__PURE__ */ jsx15(
|
|
3277
4232
|
ModelSelector,
|
|
3278
4233
|
{
|
|
3279
4234
|
request: {
|
|
@@ -3285,7 +4240,7 @@ function App({
|
|
|
3285
4240
|
}
|
|
3286
4241
|
}
|
|
3287
4242
|
),
|
|
3288
|
-
sessionPicker && /* @__PURE__ */
|
|
4243
|
+
sessionPicker && /* @__PURE__ */ jsx15(
|
|
3289
4244
|
SessionSelector,
|
|
3290
4245
|
{
|
|
3291
4246
|
request: {
|
|
@@ -3297,7 +4252,19 @@ function App({
|
|
|
3297
4252
|
}
|
|
3298
4253
|
}
|
|
3299
4254
|
),
|
|
3300
|
-
|
|
4255
|
+
questionPicker && /* @__PURE__ */ jsx15(
|
|
4256
|
+
QuestionPicker,
|
|
4257
|
+
{
|
|
4258
|
+
request: {
|
|
4259
|
+
questions: questionPicker.questions,
|
|
4260
|
+
resolve: (responses) => {
|
|
4261
|
+
questionPicker.resolve(responses);
|
|
4262
|
+
setQuestionPicker(null);
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4266
|
+
),
|
|
4267
|
+
state.status !== "idle" && /* @__PURE__ */ jsx15(
|
|
3301
4268
|
StatusLine,
|
|
3302
4269
|
{
|
|
3303
4270
|
startTime: state.turnStartTime,
|
|
@@ -3307,17 +4274,17 @@ function App({
|
|
|
3307
4274
|
lang
|
|
3308
4275
|
}
|
|
3309
4276
|
),
|
|
3310
|
-
progress && /* @__PURE__ */
|
|
3311
|
-
|
|
3312
|
-
queuedInputs.length > 0 && /* @__PURE__ */
|
|
3313
|
-
queuedInputs.map((q, i) => /* @__PURE__ */
|
|
3314
|
-
/* @__PURE__ */
|
|
4277
|
+
progress && /* @__PURE__ */ jsx15(ProgressBanner, { state: progress }),
|
|
4278
|
+
inputVisible && /* @__PURE__ */ jsxs14(Box13, { flexDirection: "column", children: [
|
|
4279
|
+
queuedInputs.length > 0 && /* @__PURE__ */ jsxs14(Box13, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: [
|
|
4280
|
+
queuedInputs.map((q, i) => /* @__PURE__ */ jsx15(Text15, { color: "yellow", dimColor: true, children: `\u21B3 queued: ${q.length > 60 ? q.slice(0, 60) + "\u2026" : q}` }, i)),
|
|
4281
|
+
/* @__PURE__ */ jsx15(Text15, { dimColor: true, children: ` (will send after current turn \xB7 ${queuedInputs.length} pending)` })
|
|
3315
4282
|
] }),
|
|
3316
|
-
/* @__PURE__ */
|
|
3317
|
-
/* @__PURE__ */
|
|
3318
|
-
/* @__PURE__ */
|
|
3319
|
-
/* @__PURE__ */
|
|
3320
|
-
/* @__PURE__ */
|
|
4283
|
+
/* @__PURE__ */ jsxs14(Box13, { marginTop: 1, flexDirection: "column", children: [
|
|
4284
|
+
/* @__PURE__ */ jsx15(Text15, { backgroundColor: "#1c1c1c", children: " ".repeat(Math.max(1, termWidth - 1)) }),
|
|
4285
|
+
/* @__PURE__ */ jsxs14(Box13, { flexDirection: "row", children: [
|
|
4286
|
+
/* @__PURE__ */ jsx15(Text15, { backgroundColor: "#1c1c1c", color: "gray", bold: true, children: " \u203A " }),
|
|
4287
|
+
/* @__PURE__ */ jsx15(
|
|
3321
4288
|
BgTextInput,
|
|
3322
4289
|
{
|
|
3323
4290
|
value: input,
|
|
@@ -3325,17 +4292,19 @@ function App({
|
|
|
3325
4292
|
onSubmit: handleSubmit,
|
|
3326
4293
|
width: Math.max(10, termWidth - 4),
|
|
3327
4294
|
backgroundColor: "#1c1c1c",
|
|
3328
|
-
isActive: acceptingInput
|
|
4295
|
+
isActive: acceptingInput,
|
|
4296
|
+
onPaste: handlePaste,
|
|
4297
|
+
placeholder: inputPlaceholder
|
|
3329
4298
|
},
|
|
3330
4299
|
inputRemountKey
|
|
3331
4300
|
)
|
|
3332
4301
|
] }),
|
|
3333
|
-
/* @__PURE__ */
|
|
4302
|
+
/* @__PURE__ */ jsx15(Text15, { backgroundColor: "#1c1c1c", children: " ".repeat(Math.max(1, termWidth - 1)) })
|
|
3334
4303
|
] }),
|
|
3335
|
-
autocomplete && autocomplete.matches.length > 0 && /* @__PURE__ */
|
|
4304
|
+
autocomplete && autocomplete.matches.length > 0 && /* @__PURE__ */ jsx15(SlashAutocomplete, { matches: autocomplete.matches, index: autocompleteIndex })
|
|
3336
4305
|
] }),
|
|
3337
|
-
/* @__PURE__ */
|
|
3338
|
-
/* @__PURE__ */
|
|
4306
|
+
/* @__PURE__ */ jsxs14(Box13, { flexDirection: "column", children: [
|
|
4307
|
+
/* @__PURE__ */ jsx15(
|
|
3339
4308
|
FooterStatus,
|
|
3340
4309
|
{
|
|
3341
4310
|
sessionId: session.meta.id,
|
|
@@ -3347,7 +4316,7 @@ function App({
|
|
|
3347
4316
|
termWidth
|
|
3348
4317
|
}
|
|
3349
4318
|
),
|
|
3350
|
-
/* @__PURE__ */
|
|
4319
|
+
/* @__PURE__ */ jsx15(PermissionModeBar, { mode, compact: termWidth < 60 })
|
|
3351
4320
|
] })
|
|
3352
4321
|
] });
|
|
3353
4322
|
}
|
|
@@ -3361,6 +4330,13 @@ function extractUserInputs(messages) {
|
|
|
3361
4330
|
}
|
|
3362
4331
|
return out;
|
|
3363
4332
|
}
|
|
4333
|
+
var PASTE_PLACEHOLDER_RE = /\[Pasted text #(\d+) \+\d+ lines\]/g;
|
|
4334
|
+
function expandPastes(value, map) {
|
|
4335
|
+
return value.replace(PASTE_PLACEHOLDER_RE, (full, id) => {
|
|
4336
|
+
const text = map.get(Number(id));
|
|
4337
|
+
return text ?? full;
|
|
4338
|
+
});
|
|
4339
|
+
}
|
|
3364
4340
|
function shortCwd(cwd) {
|
|
3365
4341
|
const home = homedir8();
|
|
3366
4342
|
if (cwd === home) return "~";
|
|
@@ -4159,6 +5135,61 @@ var MemoryReadTool = defineTool({
|
|
|
4159
5135
|
}
|
|
4160
5136
|
});
|
|
4161
5137
|
|
|
5138
|
+
// src/tools/builtin/ask-user-question.ts
|
|
5139
|
+
import { z as z12 } from "zod";
|
|
5140
|
+
var AskQuestionOptionSchema = z12.object({
|
|
5141
|
+
label: z12.string().min(1).describe("Option text shown to the user. Concise (1-5 words)."),
|
|
5142
|
+
description: z12.string().optional().describe("Optional one-line explanation of what this option means."),
|
|
5143
|
+
preview: z12.string().optional().describe(
|
|
5144
|
+
"Optional rich preview rendered in a right-side panel when this option is focused. Use for code/diagram/config snippets that help compare options visually. Multi-line text supported."
|
|
5145
|
+
)
|
|
5146
|
+
});
|
|
5147
|
+
var AskQuestionSchema = z12.object({
|
|
5148
|
+
question: z12.string().min(1).describe("Full question text (end with ?)."),
|
|
5149
|
+
header: z12.string().min(1).max(16).describe("Very short label (chip), max 12 chars. E.g. 'Auth method'."),
|
|
5150
|
+
options: z12.array(AskQuestionOptionSchema).min(2).max(4).describe("2-4 options. Mutually exclusive unless multiSelect=true."),
|
|
5151
|
+
multiSelect: z12.boolean().optional().describe("Allow multiple selections. Default false.")
|
|
5152
|
+
});
|
|
5153
|
+
var AskUserQuestionArgs = z12.object({
|
|
5154
|
+
questions: z12.array(AskQuestionSchema).min(1).max(4).describe("1-4 questions to ask the user sequentially.")
|
|
5155
|
+
});
|
|
5156
|
+
var AskUserQuestionTool = defineTool({
|
|
5157
|
+
name: "AskUserQuestion",
|
|
5158
|
+
description: "Ask the user one or more multiple-choice questions when their input is needed to proceed. Each question has 2-4 options. Use multiSelect=true for non-mutually-exclusive choices. Prefer this over plain-text questions when the answer space is bounded. If the user presses Esc, the entire batch is treated as cancelled.",
|
|
5159
|
+
parameters: AskUserQuestionArgs,
|
|
5160
|
+
permission: "read",
|
|
5161
|
+
summarize: (args) => `AskUserQuestion(${args.questions.length} question${args.questions.length === 1 ? "" : "s"})`,
|
|
5162
|
+
async execute(args, ctx) {
|
|
5163
|
+
if (!ctx.askQuestions) {
|
|
5164
|
+
return {
|
|
5165
|
+
content: "AskUserQuestion is unavailable: this agent run has no question handler. (Internal bug; tell the user.)",
|
|
5166
|
+
isError: true
|
|
5167
|
+
};
|
|
5168
|
+
}
|
|
5169
|
+
const responses = await ctx.askQuestions(args.questions);
|
|
5170
|
+
if (responses.length > 0 && responses[0].cancelled) {
|
|
5171
|
+
return {
|
|
5172
|
+
content: "User cancelled (Esc). No answers were collected.",
|
|
5173
|
+
isError: false
|
|
5174
|
+
};
|
|
5175
|
+
}
|
|
5176
|
+
const blocks = args.questions.map((q, qi) => {
|
|
5177
|
+
const r = responses[qi];
|
|
5178
|
+
const sel = r?.selections ?? [];
|
|
5179
|
+
const ans = sel.length === 0 ? "(no answer)" : sel.join(", ");
|
|
5180
|
+
const notes = r?.notes?.trim();
|
|
5181
|
+
return notes ? `Q: ${q.question}
|
|
5182
|
+
A: ${ans}
|
|
5183
|
+
Notes: ${notes}` : `Q: ${q.question}
|
|
5184
|
+
A: ${ans}`;
|
|
5185
|
+
});
|
|
5186
|
+
return {
|
|
5187
|
+
content: blocks.join("\n\n"),
|
|
5188
|
+
summary: `Asked ${args.questions.length} question${args.questions.length === 1 ? "" : "s"}`
|
|
5189
|
+
};
|
|
5190
|
+
}
|
|
5191
|
+
});
|
|
5192
|
+
|
|
4162
5193
|
// src/tools/builtin/index.ts
|
|
4163
5194
|
var BUILTIN_TOOLS = [
|
|
4164
5195
|
ReadTool,
|
|
@@ -4170,11 +5201,12 @@ var BUILTIN_TOOLS = [
|
|
|
4170
5201
|
TodoWriteTool,
|
|
4171
5202
|
WebFetchTool,
|
|
4172
5203
|
MemoryReadTool,
|
|
4173
|
-
MemoryWriteTool
|
|
5204
|
+
MemoryWriteTool,
|
|
5205
|
+
AskUserQuestionTool
|
|
4174
5206
|
];
|
|
4175
5207
|
|
|
4176
5208
|
// src/cli.tsx
|
|
4177
|
-
import { jsx as
|
|
5209
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
4178
5210
|
var VERSION = "0.1.0";
|
|
4179
5211
|
async function main() {
|
|
4180
5212
|
const program = new Command();
|
|
@@ -4267,7 +5299,7 @@ async function main() {
|
|
|
4267
5299
|
return;
|
|
4268
5300
|
}
|
|
4269
5301
|
const { waitUntilExit } = render(
|
|
4270
|
-
/* @__PURE__ */
|
|
5302
|
+
/* @__PURE__ */ jsx16(
|
|
4271
5303
|
App,
|
|
4272
5304
|
{
|
|
4273
5305
|
llm,
|