demian-cli 1.1.0 → 1.1.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/README.md +6 -0
- package/dist/tui.mjs +2026 -271
- package/dist/vscode-worker.mjs +651 -39
- package/docs/ko/README.md +5 -0
- package/package.json +1 -1
package/dist/tui.mjs
CHANGED
|
@@ -1,13 +1,36 @@
|
|
|
1
1
|
import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
8
|
var __esm = (fn, res) => function __init() {
|
|
5
9
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
10
|
};
|
|
11
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
12
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
13
|
+
};
|
|
7
14
|
var __export = (target, all) => {
|
|
8
15
|
for (var name in all)
|
|
9
16
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
17
|
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
27
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
28
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
29
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
30
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
31
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
32
|
+
mod
|
|
33
|
+
));
|
|
11
34
|
|
|
12
35
|
// src/goals/parser.ts
|
|
13
36
|
function parseGoalCommand(input2) {
|
|
@@ -22790,8 +22813,8 @@ function permissionLabel(req) {
|
|
|
22790
22813
|
if ((req.tool === "write_file" || req.tool === "edit_file" || req.tool === "read_file") && typeof inputObject.path === "string") {
|
|
22791
22814
|
return `${req.tool}: ${inputObject.path}`;
|
|
22792
22815
|
}
|
|
22793
|
-
const
|
|
22794
|
-
if (
|
|
22816
|
+
const path37 = typeof inputObject.path === "string" ? inputObject.path : typeof inputObject.file_path === "string" ? inputObject.file_path : void 0;
|
|
22817
|
+
if (path37) return `${tool}: ${path37}`;
|
|
22795
22818
|
return tool;
|
|
22796
22819
|
}
|
|
22797
22820
|
var init_prompt = __esm({
|
|
@@ -24615,6 +24638,214 @@ var init_catalog = __esm({
|
|
|
24615
24638
|
}
|
|
24616
24639
|
});
|
|
24617
24640
|
|
|
24641
|
+
// node_modules/ansi-regex/index.js
|
|
24642
|
+
function ansiRegex({ onlyFirst = false } = {}) {
|
|
24643
|
+
const ST2 = "(?:\\u0007|\\u001B\\u005C|\\u009C)";
|
|
24644
|
+
const osc = `(?:\\u001B\\][\\s\\S]*?${ST2})`;
|
|
24645
|
+
const csi = "[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]";
|
|
24646
|
+
const pattern = `${osc}|${csi}`;
|
|
24647
|
+
return new RegExp(pattern, onlyFirst ? void 0 : "g");
|
|
24648
|
+
}
|
|
24649
|
+
var init_ansi_regex = __esm({
|
|
24650
|
+
"node_modules/ansi-regex/index.js"() {
|
|
24651
|
+
}
|
|
24652
|
+
});
|
|
24653
|
+
|
|
24654
|
+
// node_modules/strip-ansi/index.js
|
|
24655
|
+
function stripAnsi(string) {
|
|
24656
|
+
if (typeof string !== "string") {
|
|
24657
|
+
throw new TypeError(`Expected a \`string\`, got \`${typeof string}\``);
|
|
24658
|
+
}
|
|
24659
|
+
if (!string.includes("\x1B") && !string.includes("\x9B")) {
|
|
24660
|
+
return string;
|
|
24661
|
+
}
|
|
24662
|
+
return string.replace(regex, "");
|
|
24663
|
+
}
|
|
24664
|
+
var regex;
|
|
24665
|
+
var init_strip_ansi = __esm({
|
|
24666
|
+
"node_modules/strip-ansi/index.js"() {
|
|
24667
|
+
init_ansi_regex();
|
|
24668
|
+
regex = ansiRegex();
|
|
24669
|
+
}
|
|
24670
|
+
});
|
|
24671
|
+
|
|
24672
|
+
// node_modules/get-east-asian-width/lookup-data.js
|
|
24673
|
+
var ambiguousRanges, fullwidthRanges, halfwidthRanges, narrowRanges, wideRanges;
|
|
24674
|
+
var init_lookup_data = __esm({
|
|
24675
|
+
"node_modules/get-east-asian-width/lookup-data.js"() {
|
|
24676
|
+
ambiguousRanges = [161, 161, 164, 164, 167, 168, 170, 170, 173, 174, 176, 180, 182, 186, 188, 191, 198, 198, 208, 208, 215, 216, 222, 225, 230, 230, 232, 234, 236, 237, 240, 240, 242, 243, 247, 250, 252, 252, 254, 254, 257, 257, 273, 273, 275, 275, 283, 283, 294, 295, 299, 299, 305, 307, 312, 312, 319, 322, 324, 324, 328, 331, 333, 333, 338, 339, 358, 359, 363, 363, 462, 462, 464, 464, 466, 466, 468, 468, 470, 470, 472, 472, 474, 474, 476, 476, 593, 593, 609, 609, 708, 708, 711, 711, 713, 715, 717, 717, 720, 720, 728, 731, 733, 733, 735, 735, 768, 879, 913, 929, 931, 937, 945, 961, 963, 969, 1025, 1025, 1040, 1103, 1105, 1105, 8208, 8208, 8211, 8214, 8216, 8217, 8220, 8221, 8224, 8226, 8228, 8231, 8240, 8240, 8242, 8243, 8245, 8245, 8251, 8251, 8254, 8254, 8308, 8308, 8319, 8319, 8321, 8324, 8364, 8364, 8451, 8451, 8453, 8453, 8457, 8457, 8467, 8467, 8470, 8470, 8481, 8482, 8486, 8486, 8491, 8491, 8531, 8532, 8539, 8542, 8544, 8555, 8560, 8569, 8585, 8585, 8592, 8601, 8632, 8633, 8658, 8658, 8660, 8660, 8679, 8679, 8704, 8704, 8706, 8707, 8711, 8712, 8715, 8715, 8719, 8719, 8721, 8721, 8725, 8725, 8730, 8730, 8733, 8736, 8739, 8739, 8741, 8741, 8743, 8748, 8750, 8750, 8756, 8759, 8764, 8765, 8776, 8776, 8780, 8780, 8786, 8786, 8800, 8801, 8804, 8807, 8810, 8811, 8814, 8815, 8834, 8835, 8838, 8839, 8853, 8853, 8857, 8857, 8869, 8869, 8895, 8895, 8978, 8978, 9312, 9449, 9451, 9547, 9552, 9587, 9600, 9615, 9618, 9621, 9632, 9633, 9635, 9641, 9650, 9651, 9654, 9655, 9660, 9661, 9664, 9665, 9670, 9672, 9675, 9675, 9678, 9681, 9698, 9701, 9711, 9711, 9733, 9734, 9737, 9737, 9742, 9743, 9756, 9756, 9758, 9758, 9792, 9792, 9794, 9794, 9824, 9825, 9827, 9829, 9831, 9834, 9836, 9837, 9839, 9839, 9886, 9887, 9919, 9919, 9926, 9933, 9935, 9939, 9941, 9953, 9955, 9955, 9960, 9961, 9963, 9969, 9972, 9972, 9974, 9977, 9979, 9980, 9982, 9983, 10045, 10045, 10102, 10111, 11094, 11097, 12872, 12879, 57344, 63743, 65024, 65039, 65533, 65533, 127232, 127242, 127248, 127277, 127280, 127337, 127344, 127373, 127375, 127376, 127387, 127404, 917760, 917999, 983040, 1048573, 1048576, 1114109];
|
|
24677
|
+
fullwidthRanges = [12288, 12288, 65281, 65376, 65504, 65510];
|
|
24678
|
+
halfwidthRanges = [8361, 8361, 65377, 65470, 65474, 65479, 65482, 65487, 65490, 65495, 65498, 65500, 65512, 65518];
|
|
24679
|
+
narrowRanges = [32, 126, 162, 163, 165, 166, 172, 172, 175, 175, 10214, 10221, 10629, 10630];
|
|
24680
|
+
wideRanges = [4352, 4447, 8986, 8987, 9001, 9002, 9193, 9196, 9200, 9200, 9203, 9203, 9725, 9726, 9748, 9749, 9776, 9783, 9800, 9811, 9855, 9855, 9866, 9871, 9875, 9875, 9889, 9889, 9898, 9899, 9917, 9918, 9924, 9925, 9934, 9934, 9940, 9940, 9962, 9962, 9970, 9971, 9973, 9973, 9978, 9978, 9981, 9981, 9989, 9989, 9994, 9995, 10024, 10024, 10060, 10060, 10062, 10062, 10067, 10069, 10071, 10071, 10133, 10135, 10160, 10160, 10175, 10175, 11035, 11036, 11088, 11088, 11093, 11093, 11904, 11929, 11931, 12019, 12032, 12245, 12272, 12287, 12289, 12350, 12353, 12438, 12441, 12543, 12549, 12591, 12593, 12686, 12688, 12773, 12783, 12830, 12832, 12871, 12880, 42124, 42128, 42182, 43360, 43388, 44032, 55203, 63744, 64255, 65040, 65049, 65072, 65106, 65108, 65126, 65128, 65131, 94176, 94180, 94192, 94198, 94208, 101589, 101631, 101662, 101760, 101874, 110576, 110579, 110581, 110587, 110589, 110590, 110592, 110882, 110898, 110898, 110928, 110930, 110933, 110933, 110948, 110951, 110960, 111355, 119552, 119638, 119648, 119670, 126980, 126980, 127183, 127183, 127374, 127374, 127377, 127386, 127488, 127490, 127504, 127547, 127552, 127560, 127568, 127569, 127584, 127589, 127744, 127776, 127789, 127797, 127799, 127868, 127870, 127891, 127904, 127946, 127951, 127955, 127968, 127984, 127988, 127988, 127992, 128062, 128064, 128064, 128066, 128252, 128255, 128317, 128331, 128334, 128336, 128359, 128378, 128378, 128405, 128406, 128420, 128420, 128507, 128591, 128640, 128709, 128716, 128716, 128720, 128722, 128725, 128728, 128732, 128735, 128747, 128748, 128756, 128764, 128992, 129003, 129008, 129008, 129292, 129338, 129340, 129349, 129351, 129535, 129648, 129660, 129664, 129674, 129678, 129734, 129736, 129736, 129741, 129756, 129759, 129770, 129775, 129784, 131072, 196605, 196608, 262141];
|
|
24681
|
+
}
|
|
24682
|
+
});
|
|
24683
|
+
|
|
24684
|
+
// node_modules/get-east-asian-width/utilities.js
|
|
24685
|
+
var isInRange;
|
|
24686
|
+
var init_utilities = __esm({
|
|
24687
|
+
"node_modules/get-east-asian-width/utilities.js"() {
|
|
24688
|
+
isInRange = (ranges, codePoint) => {
|
|
24689
|
+
let low = 0;
|
|
24690
|
+
let high = Math.floor(ranges.length / 2) - 1;
|
|
24691
|
+
while (low <= high) {
|
|
24692
|
+
const mid = Math.floor((low + high) / 2);
|
|
24693
|
+
const i = mid * 2;
|
|
24694
|
+
if (codePoint < ranges[i]) {
|
|
24695
|
+
high = mid - 1;
|
|
24696
|
+
} else if (codePoint > ranges[i + 1]) {
|
|
24697
|
+
low = mid + 1;
|
|
24698
|
+
} else {
|
|
24699
|
+
return true;
|
|
24700
|
+
}
|
|
24701
|
+
}
|
|
24702
|
+
return false;
|
|
24703
|
+
};
|
|
24704
|
+
}
|
|
24705
|
+
});
|
|
24706
|
+
|
|
24707
|
+
// node_modules/get-east-asian-width/lookup.js
|
|
24708
|
+
function findWideFastPathRange(ranges) {
|
|
24709
|
+
let fastPathStart = ranges[0];
|
|
24710
|
+
let fastPathEnd = ranges[1];
|
|
24711
|
+
for (let index = 0; index < ranges.length; index += 2) {
|
|
24712
|
+
const start = ranges[index];
|
|
24713
|
+
const end = ranges[index + 1];
|
|
24714
|
+
if (commonCjkCodePoint >= start && commonCjkCodePoint <= end) {
|
|
24715
|
+
return [start, end];
|
|
24716
|
+
}
|
|
24717
|
+
if (end - start > fastPathEnd - fastPathStart) {
|
|
24718
|
+
fastPathStart = start;
|
|
24719
|
+
fastPathEnd = end;
|
|
24720
|
+
}
|
|
24721
|
+
}
|
|
24722
|
+
return [fastPathStart, fastPathEnd];
|
|
24723
|
+
}
|
|
24724
|
+
var minimumAmbiguousCodePoint, maximumAmbiguousCodePoint, minimumFullWidthCodePoint, maximumFullWidthCodePoint, minimumHalfWidthCodePoint, maximumHalfWidthCodePoint, minimumNarrowCodePoint, maximumNarrowCodePoint, minimumWideCodePoint, maximumWideCodePoint, commonCjkCodePoint, wideFastPathStart, wideFastPathEnd, isAmbiguous, isFullWidth, isWide;
|
|
24725
|
+
var init_lookup = __esm({
|
|
24726
|
+
"node_modules/get-east-asian-width/lookup.js"() {
|
|
24727
|
+
init_lookup_data();
|
|
24728
|
+
init_utilities();
|
|
24729
|
+
minimumAmbiguousCodePoint = ambiguousRanges[0];
|
|
24730
|
+
maximumAmbiguousCodePoint = ambiguousRanges.at(-1);
|
|
24731
|
+
minimumFullWidthCodePoint = fullwidthRanges[0];
|
|
24732
|
+
maximumFullWidthCodePoint = fullwidthRanges.at(-1);
|
|
24733
|
+
minimumHalfWidthCodePoint = halfwidthRanges[0];
|
|
24734
|
+
maximumHalfWidthCodePoint = halfwidthRanges.at(-1);
|
|
24735
|
+
minimumNarrowCodePoint = narrowRanges[0];
|
|
24736
|
+
maximumNarrowCodePoint = narrowRanges.at(-1);
|
|
24737
|
+
minimumWideCodePoint = wideRanges[0];
|
|
24738
|
+
maximumWideCodePoint = wideRanges.at(-1);
|
|
24739
|
+
commonCjkCodePoint = 19968;
|
|
24740
|
+
[wideFastPathStart, wideFastPathEnd] = findWideFastPathRange(wideRanges);
|
|
24741
|
+
isAmbiguous = (codePoint) => {
|
|
24742
|
+
if (codePoint < minimumAmbiguousCodePoint || codePoint > maximumAmbiguousCodePoint) {
|
|
24743
|
+
return false;
|
|
24744
|
+
}
|
|
24745
|
+
return isInRange(ambiguousRanges, codePoint);
|
|
24746
|
+
};
|
|
24747
|
+
isFullWidth = (codePoint) => {
|
|
24748
|
+
if (codePoint < minimumFullWidthCodePoint || codePoint > maximumFullWidthCodePoint) {
|
|
24749
|
+
return false;
|
|
24750
|
+
}
|
|
24751
|
+
return isInRange(fullwidthRanges, codePoint);
|
|
24752
|
+
};
|
|
24753
|
+
isWide = (codePoint) => {
|
|
24754
|
+
if (codePoint >= wideFastPathStart && codePoint <= wideFastPathEnd) {
|
|
24755
|
+
return true;
|
|
24756
|
+
}
|
|
24757
|
+
if (codePoint < minimumWideCodePoint || codePoint > maximumWideCodePoint) {
|
|
24758
|
+
return false;
|
|
24759
|
+
}
|
|
24760
|
+
return isInRange(wideRanges, codePoint);
|
|
24761
|
+
};
|
|
24762
|
+
}
|
|
24763
|
+
});
|
|
24764
|
+
|
|
24765
|
+
// node_modules/get-east-asian-width/index.js
|
|
24766
|
+
function validate(codePoint) {
|
|
24767
|
+
if (!Number.isSafeInteger(codePoint)) {
|
|
24768
|
+
throw new TypeError(`Expected a code point, got \`${typeof codePoint}\`.`);
|
|
24769
|
+
}
|
|
24770
|
+
}
|
|
24771
|
+
function eastAsianWidth(codePoint, { ambiguousAsWide = false } = {}) {
|
|
24772
|
+
validate(codePoint);
|
|
24773
|
+
if (isFullWidth(codePoint) || isWide(codePoint) || ambiguousAsWide && isAmbiguous(codePoint)) {
|
|
24774
|
+
return 2;
|
|
24775
|
+
}
|
|
24776
|
+
return 1;
|
|
24777
|
+
}
|
|
24778
|
+
var init_get_east_asian_width = __esm({
|
|
24779
|
+
"node_modules/get-east-asian-width/index.js"() {
|
|
24780
|
+
init_lookup();
|
|
24781
|
+
}
|
|
24782
|
+
});
|
|
24783
|
+
|
|
24784
|
+
// node_modules/emoji-regex/index.js
|
|
24785
|
+
var require_emoji_regex = __commonJS({
|
|
24786
|
+
"node_modules/emoji-regex/index.js"(exports, module) {
|
|
24787
|
+
module.exports = () => {
|
|
24788
|
+
return /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26D3\uFE0F?(?:\u200D\uD83D\uDCA5)?|\u26F9(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF43\uDF45-\uDF4A\uDF4C-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDF44(?:\u200D\uD83D\uDFEB)?|\uDF4B(?:\u200D\uD83D\uDFE9)?|\uDFC3(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E-\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4\uDEB5](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE41\uDE43\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED8\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC08(?:\u200D\u2B1B)?|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC26(?:\u200D(?:\u2B1B|\uD83D\uDD25))?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDD1D\uDEEF]\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE]|[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE]|\uDEEF\u200D\uD83D\uDC69\uD83C[\uDFFB-\uDFFE])))?))?|\uDD75(?:\uD83C[\uDFFB-\uDFFF]|\uFE0F)?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?|\uDE42(?:\u200D[\u2194\u2195]\uFE0F?)?|\uDEB6(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3C-\uDD3E\uDDB8\uDDB9\uDDCD\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE8A\uDE8E-\uDEC2\uDEC6\uDEC8\uDECD-\uDEDC\uDEDF-\uDEEA\uDEEF]|\uDDCE(?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D(?:[\u2640\u2642]\uFE0F?(?:\u200D\u27A1\uFE0F?)?|\u27A1\uFE0F?))?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1|\uDDD1\u200D\uD83E\uDDD2(?:\u200D\uD83E\uDDD2)?|\uDDD2(?:\u200D\uD83E\uDDD2)?))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC30\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])|\uD83E(?:[\uDDAF\uDDBC\uDDBD](?:\u200D\u27A1\uFE0F?)?|[\uDDB0-\uDDB3\uDE70]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF]|\uDEEF\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;
|
|
24789
|
+
};
|
|
24790
|
+
}
|
|
24791
|
+
});
|
|
24792
|
+
|
|
24793
|
+
// node_modules/string-width/index.js
|
|
24794
|
+
function stringWidth(string, options = {}) {
|
|
24795
|
+
if (typeof string !== "string" || string.length === 0) {
|
|
24796
|
+
return 0;
|
|
24797
|
+
}
|
|
24798
|
+
const {
|
|
24799
|
+
ambiguousIsNarrow = true,
|
|
24800
|
+
countAnsiEscapeCodes = false
|
|
24801
|
+
} = options;
|
|
24802
|
+
if (!countAnsiEscapeCodes) {
|
|
24803
|
+
string = stripAnsi(string);
|
|
24804
|
+
}
|
|
24805
|
+
if (string.length === 0) {
|
|
24806
|
+
return 0;
|
|
24807
|
+
}
|
|
24808
|
+
let width = 0;
|
|
24809
|
+
const eastAsianWidthOptions = { ambiguousAsWide: !ambiguousIsNarrow };
|
|
24810
|
+
for (const { segment: character } of segmenter.segment(string)) {
|
|
24811
|
+
const codePoint = character.codePointAt(0);
|
|
24812
|
+
if (codePoint <= 31 || codePoint >= 127 && codePoint <= 159) {
|
|
24813
|
+
continue;
|
|
24814
|
+
}
|
|
24815
|
+
if (codePoint >= 8203 && codePoint <= 8207 || codePoint === 65279) {
|
|
24816
|
+
continue;
|
|
24817
|
+
}
|
|
24818
|
+
if (codePoint >= 768 && codePoint <= 879 || codePoint >= 6832 && codePoint <= 6911 || codePoint >= 7616 && codePoint <= 7679 || codePoint >= 8400 && codePoint <= 8447 || codePoint >= 65056 && codePoint <= 65071) {
|
|
24819
|
+
continue;
|
|
24820
|
+
}
|
|
24821
|
+
if (codePoint >= 55296 && codePoint <= 57343) {
|
|
24822
|
+
continue;
|
|
24823
|
+
}
|
|
24824
|
+
if (codePoint >= 65024 && codePoint <= 65039) {
|
|
24825
|
+
continue;
|
|
24826
|
+
}
|
|
24827
|
+
if (defaultIgnorableCodePointRegex.test(character)) {
|
|
24828
|
+
continue;
|
|
24829
|
+
}
|
|
24830
|
+
if ((0, import_emoji_regex.default)().test(character)) {
|
|
24831
|
+
width += 2;
|
|
24832
|
+
continue;
|
|
24833
|
+
}
|
|
24834
|
+
width += eastAsianWidth(codePoint, eastAsianWidthOptions);
|
|
24835
|
+
}
|
|
24836
|
+
return width;
|
|
24837
|
+
}
|
|
24838
|
+
var import_emoji_regex, segmenter, defaultIgnorableCodePointRegex;
|
|
24839
|
+
var init_string_width = __esm({
|
|
24840
|
+
"node_modules/string-width/index.js"() {
|
|
24841
|
+
init_strip_ansi();
|
|
24842
|
+
init_get_east_asian_width();
|
|
24843
|
+
import_emoji_regex = __toESM(require_emoji_regex(), 1);
|
|
24844
|
+
segmenter = new Intl.Segmenter();
|
|
24845
|
+
defaultIgnorableCodePointRegex = new RegExp("^\\p{Default_Ignorable_Code_Point}$", "u");
|
|
24846
|
+
}
|
|
24847
|
+
});
|
|
24848
|
+
|
|
24618
24849
|
// src/permissions/presets.ts
|
|
24619
24850
|
function normalizePermissionPreset(value, fallback = "auto") {
|
|
24620
24851
|
return typeof value === "string" && isPermissionPreset(value) ? value : fallback;
|
|
@@ -24684,6 +24915,26 @@ function isCompactCommand(input2) {
|
|
|
24684
24915
|
function isRetryCommand(input2) {
|
|
24685
24916
|
return input2.trim().toLowerCase() === "/retry";
|
|
24686
24917
|
}
|
|
24918
|
+
function isSessionCommand(input2) {
|
|
24919
|
+
return /^\/(?:session|sessions|conversation|conversations|conv)(?:\s|$)/i.test(input2.trim());
|
|
24920
|
+
}
|
|
24921
|
+
function parseSessionCommand(input2) {
|
|
24922
|
+
const raw = input2.trim();
|
|
24923
|
+
if (!isSessionCommand(raw)) return void 0;
|
|
24924
|
+
const rest = raw.replace(/^\/(?:session|sessions|conversation|conversations|conv)\b/i, "").trim();
|
|
24925
|
+
if (!rest) return { action: "help" };
|
|
24926
|
+
const tokens = shellishSplit2(rest);
|
|
24927
|
+
const action = tokens.shift()?.toLowerCase() ?? "help";
|
|
24928
|
+
if (action === "help" || action === "-h" || action === "--help") return { action: "help" };
|
|
24929
|
+
if (action === "list" || action === "ls") return { action: "list" };
|
|
24930
|
+
if (action === "current" || action === "status") return { action: "current" };
|
|
24931
|
+
if (action === "new" || action === "create") return { action: "new", title: tokens.join(" ").trim() || void 0 };
|
|
24932
|
+
if (action === "switch" || action === "select" || action === "use" || action === "open") return { action: "switch", target: tokens.join(" ").trim() || void 0 };
|
|
24933
|
+
if (action === "delete" || action === "remove" || action === "rm") return { action: "delete", target: tokens.join(" ").trim() || void 0 };
|
|
24934
|
+
if (action === "rename" || action === "name") return { action: "rename", title: tokens.join(" ").trim() || void 0 };
|
|
24935
|
+
if (action === "clear" || action === "reset") return { action: "clear" };
|
|
24936
|
+
return { action: "switch", target: [action, ...tokens].join(" ").trim() };
|
|
24937
|
+
}
|
|
24687
24938
|
function isCoworkCommand(input2) {
|
|
24688
24939
|
return /^\/cowork(?:\s|$)/i.test(input2.trim());
|
|
24689
24940
|
}
|
|
@@ -25592,6 +25843,36 @@ function cloneGoalToolRun(tool) {
|
|
|
25592
25843
|
details: cloneToolRunDetails(tool.details)
|
|
25593
25844
|
};
|
|
25594
25845
|
}
|
|
25846
|
+
function safeConversationSnapshot(snapshot) {
|
|
25847
|
+
if (!snapshot || typeof snapshot !== "object") return {};
|
|
25848
|
+
return {
|
|
25849
|
+
status: snapshot.status ? { ...snapshot.status } : void 0,
|
|
25850
|
+
blocks: Array.isArray(snapshot.blocks) ? snapshot.blocks.map((block) => ({ ...block, lines: [...block.lines ?? []], toolDetails: cloneToolRunDetails(block.toolDetails), goalWork: cloneGoalWork(block.goalWork), cowork: cloneCoworkGroup(block.cowork) })) : [],
|
|
25851
|
+
activity: typeof snapshot.activity === "string" ? snapshot.activity : "restored conversation",
|
|
25852
|
+
warnings: Array.isArray(snapshot.warnings) ? [...snapshot.warnings] : [],
|
|
25853
|
+
finalAnswer: snapshot.finalAnswer,
|
|
25854
|
+
progressNotes: Array.isArray(snapshot.progressNotes) ? snapshot.progressNotes.map((note) => ({ ...note })) : [],
|
|
25855
|
+
turnDiff: snapshot.turnDiff ? cloneDiffSummary(snapshot.turnDiff) : void 0,
|
|
25856
|
+
diffExpanded: snapshot.diffExpanded === true,
|
|
25857
|
+
workPlan: snapshot.workPlan ? {
|
|
25858
|
+
...snapshot.workPlan,
|
|
25859
|
+
steps: snapshot.workPlan.steps.map((step) => ({ ...step }))
|
|
25860
|
+
} : void 0,
|
|
25861
|
+
workPlanExpanded: snapshot.workPlanExpanded === true,
|
|
25862
|
+
goal: snapshot.goal ? { ...snapshot.goal } : void 0,
|
|
25863
|
+
contextEfficiency: snapshot.contextEfficiency ? cloneContextEfficiency(snapshot.contextEfficiency) : void 0,
|
|
25864
|
+
canRetryLastPrompt: snapshot.canRetryLastPrompt === true,
|
|
25865
|
+
pendingClaudeCodePlan: snapshot.pendingClaudeCodePlan ? { ...snapshot.pendingClaudeCodePlan } : void 0
|
|
25866
|
+
};
|
|
25867
|
+
}
|
|
25868
|
+
function nextBlockId(blocks) {
|
|
25869
|
+
let max = 0;
|
|
25870
|
+
for (const block of blocks ?? []) {
|
|
25871
|
+
const match = /^block_(\d+)$/.exec(block.id);
|
|
25872
|
+
if (match) max = Math.max(max, Number(match[1]));
|
|
25873
|
+
}
|
|
25874
|
+
return max;
|
|
25875
|
+
}
|
|
25595
25876
|
function formatDuration2(durationMs) {
|
|
25596
25877
|
if (durationMs < 1e3) return `${durationMs}ms`;
|
|
25597
25878
|
return `${Math.round(durationMs / 1e3)}s`;
|
|
@@ -25625,6 +25906,8 @@ var init_store = __esm({
|
|
|
25625
25906
|
blocks: [],
|
|
25626
25907
|
activity: "starting",
|
|
25627
25908
|
inputMode: "starting",
|
|
25909
|
+
sessionOptions: [],
|
|
25910
|
+
sessionCursor: 0,
|
|
25628
25911
|
providerOptions: [],
|
|
25629
25912
|
providerCursor: 0,
|
|
25630
25913
|
agentOptions: [],
|
|
@@ -25646,6 +25929,7 @@ var init_store = __esm({
|
|
|
25646
25929
|
#blockId = 0;
|
|
25647
25930
|
#stopActiveTask;
|
|
25648
25931
|
#promptResolve;
|
|
25932
|
+
#sessionResolve;
|
|
25649
25933
|
#queuedPrompt;
|
|
25650
25934
|
#exitRequested = false;
|
|
25651
25935
|
#promptHistory = [];
|
|
@@ -25666,6 +25950,7 @@ var init_store = __esm({
|
|
|
25666
25950
|
...this.#state,
|
|
25667
25951
|
status: { ...this.#state.status },
|
|
25668
25952
|
selection: this.#state.selection ? { ...this.#state.selection } : void 0,
|
|
25953
|
+
sessionOptions: this.#state.sessionOptions.map((option) => ({ ...option })),
|
|
25669
25954
|
providerOptions: this.#state.providerOptions.map((option) => ({ ...option })),
|
|
25670
25955
|
agentOptions: this.#state.agentOptions.map((option) => ({ ...option })),
|
|
25671
25956
|
blocks: this.#state.blocks.map((block) => ({ ...block, lines: [...block.lines], toolDetails: cloneToolRunDetails(block.toolDetails), goalWork: cloneGoalWork(block.goalWork), cowork: cloneCoworkGroup(block.cowork) })),
|
|
@@ -25704,6 +25989,7 @@ var init_store = __esm({
|
|
|
25704
25989
|
requestExit() {
|
|
25705
25990
|
this.#exitRequested = true;
|
|
25706
25991
|
if (this.#promptResolve) this.#resolvePrompt("");
|
|
25992
|
+
if (this.#sessionResolve) this.#resolveSession({ kind: "exit" });
|
|
25707
25993
|
this.#stopActiveTask?.();
|
|
25708
25994
|
this.#state.inputMode = "done";
|
|
25709
25995
|
this.#state.done = true;
|
|
@@ -25783,6 +26069,84 @@ var init_store = __esm({
|
|
|
25783
26069
|
this.#state.activity = `context compacted: ${summary.beforeTokenEstimate} -> ${summary.afterTokenEstimate}`;
|
|
25784
26070
|
this.#notify();
|
|
25785
26071
|
}
|
|
26072
|
+
conversationSnapshot() {
|
|
26073
|
+
const snapshot = this.snapshot();
|
|
26074
|
+
return {
|
|
26075
|
+
...snapshot,
|
|
26076
|
+
inputMode: "prompt",
|
|
26077
|
+
promptInput: "",
|
|
26078
|
+
promptError: void 0,
|
|
26079
|
+
streamingText: "",
|
|
26080
|
+
streamingFinalized: true,
|
|
26081
|
+
permission: void 0,
|
|
26082
|
+
done: false
|
|
26083
|
+
};
|
|
26084
|
+
}
|
|
26085
|
+
restoreConversationSnapshot(snapshot, fallback) {
|
|
26086
|
+
this.#resetTransientConversationState();
|
|
26087
|
+
const currentSettings = {
|
|
26088
|
+
selection: this.#state.selection,
|
|
26089
|
+
providerOptions: this.#state.providerOptions,
|
|
26090
|
+
providerCursor: this.#state.providerCursor,
|
|
26091
|
+
agentOptions: this.#state.agentOptions,
|
|
26092
|
+
agentCursor: this.#state.agentCursor,
|
|
26093
|
+
selectedAgent: this.#state.selectedAgent,
|
|
26094
|
+
permissionPreset: this.#state.permissionPreset,
|
|
26095
|
+
permissionPresetCursor: this.#state.permissionPresetCursor,
|
|
26096
|
+
contextEfficiency: this.#state.contextEfficiency
|
|
26097
|
+
};
|
|
26098
|
+
const restoredSelection = snapshot?.selection ? { ...snapshot.selection } : currentSettings.selection;
|
|
26099
|
+
const restoredAgent = snapshot?.selectedAgent ?? snapshot?.status?.agent ?? currentSettings.selectedAgent;
|
|
26100
|
+
const restoredPermissionPreset = normalizePermissionPreset(snapshot?.permissionPreset, currentSettings.permissionPreset);
|
|
26101
|
+
this.#state = {
|
|
26102
|
+
...this.#state,
|
|
26103
|
+
...safeConversationSnapshot(snapshot),
|
|
26104
|
+
...currentSettings,
|
|
26105
|
+
selection: restoredSelection,
|
|
26106
|
+
providerCursor: Math.max(0, currentSettings.providerOptions.findIndex((option) => option.name === restoredSelection?.providerName)),
|
|
26107
|
+
selectedAgent: restoredAgent,
|
|
26108
|
+
agentCursor: Math.max(0, currentSettings.agentOptions.findIndex((option) => option.name === restoredAgent)),
|
|
26109
|
+
permissionPreset: restoredPermissionPreset,
|
|
26110
|
+
permissionPresetCursor: Math.max(0, PERMISSION_PRESETS.indexOf(restoredPermissionPreset)),
|
|
26111
|
+
status: {
|
|
26112
|
+
...snapshot?.status ?? this.#state.status,
|
|
26113
|
+
sessionId: fallback.sessionId,
|
|
26114
|
+
cwd: fallback.cwd,
|
|
26115
|
+
provider: restoredSelection?.providerName ?? snapshot?.status?.provider ?? this.#state.status.provider,
|
|
26116
|
+
model: restoredSelection?.model ?? snapshot?.status?.model ?? this.#state.status.model,
|
|
26117
|
+
agent: restoredAgent ?? snapshot?.status?.agent ?? this.#state.status.agent
|
|
26118
|
+
},
|
|
26119
|
+
inputMode: "prompt",
|
|
26120
|
+
promptInput: "",
|
|
26121
|
+
promptError: void 0,
|
|
26122
|
+
streamingText: "",
|
|
26123
|
+
streamingFinalized: true,
|
|
26124
|
+
permission: void 0,
|
|
26125
|
+
done: false,
|
|
26126
|
+
activity: `conversation: ${fallback.title}`
|
|
26127
|
+
};
|
|
26128
|
+
this.#blockId = nextBlockId(this.#state.blocks);
|
|
26129
|
+
this.#notify();
|
|
26130
|
+
}
|
|
26131
|
+
clearConversation(title = "New session") {
|
|
26132
|
+
this.#resetTransientConversationState();
|
|
26133
|
+
this.#state.blocks = [];
|
|
26134
|
+
this.#state.streamingText = "";
|
|
26135
|
+
this.#state.streamingFinalized = true;
|
|
26136
|
+
this.#state.permission = void 0;
|
|
26137
|
+
this.#state.warnings = [];
|
|
26138
|
+
this.#state.done = false;
|
|
26139
|
+
this.#state.finalAnswer = void 0;
|
|
26140
|
+
this.#state.progressNotes = [];
|
|
26141
|
+
this.#state.turnDiff = void 0;
|
|
26142
|
+
this.#state.diffExpanded = false;
|
|
26143
|
+
this.#state.workPlan = void 0;
|
|
26144
|
+
this.#state.workPlanExpanded = false;
|
|
26145
|
+
this.#state.goal = void 0;
|
|
26146
|
+
this.#state.pendingClaudeCodePlan = void 0;
|
|
26147
|
+
this.#state.activity = `cleared conversation: ${title}`;
|
|
26148
|
+
this.prepareForPrompt("waiting for next message");
|
|
26149
|
+
}
|
|
25786
26150
|
prepareForPrompt(message = "waiting for next message") {
|
|
25787
26151
|
if (this.#exitRequested) return;
|
|
25788
26152
|
this.#state.inputMode = "prompt";
|
|
@@ -25840,7 +26204,45 @@ var init_store = __esm({
|
|
|
25840
26204
|
currentPermissionPreset() {
|
|
25841
26205
|
return this.#state.permissionPreset;
|
|
25842
26206
|
}
|
|
26207
|
+
requestSessionSelection(options) {
|
|
26208
|
+
if (this.#exitRequested) return Promise.resolve({ kind: "exit" });
|
|
26209
|
+
const normalized = options.length > 0 ? options.map((option) => ({ ...option })) : [{ kind: "new", title: "New session", status: "ready", currentWorkspace: true }];
|
|
26210
|
+
return new Promise((resolve) => {
|
|
26211
|
+
this.#sessionResolve = resolve;
|
|
26212
|
+
this.#state.inputMode = "session";
|
|
26213
|
+
this.#state.sessionOptions = normalized;
|
|
26214
|
+
this.#state.sessionCursor = 0;
|
|
26215
|
+
this.#state.promptInput = "";
|
|
26216
|
+
this.#state.promptError = void 0;
|
|
26217
|
+
this.#state.streamingText = "";
|
|
26218
|
+
this.#state.streamingFinalized = true;
|
|
26219
|
+
this.#state.done = false;
|
|
26220
|
+
this.#state.activity = "select session";
|
|
26221
|
+
this.#notify();
|
|
26222
|
+
});
|
|
26223
|
+
}
|
|
26224
|
+
moveSessionCursor(delta) {
|
|
26225
|
+
if (this.#state.inputMode !== "session" || this.#state.sessionOptions.length === 0) return;
|
|
26226
|
+
const count = this.#state.sessionOptions.length;
|
|
26227
|
+
this.#state.sessionCursor = (this.#state.sessionCursor + delta + count) % count;
|
|
26228
|
+
this.#notify();
|
|
26229
|
+
}
|
|
26230
|
+
submitSessionSelection() {
|
|
26231
|
+
if (this.#state.inputMode !== "session") return;
|
|
26232
|
+
const option = this.#state.sessionOptions[this.#state.sessionCursor];
|
|
26233
|
+
if (!option) return;
|
|
26234
|
+
if (option.kind === "new") {
|
|
26235
|
+
this.#resolveSession({ kind: "new" });
|
|
26236
|
+
return;
|
|
26237
|
+
}
|
|
26238
|
+
if (option.id) this.#resolveSession({ kind: "session", id: option.id });
|
|
26239
|
+
}
|
|
26240
|
+
submitNewSessionSelection() {
|
|
26241
|
+
if (this.#state.inputMode !== "session") return;
|
|
26242
|
+
this.#resolveSession({ kind: "new" });
|
|
26243
|
+
}
|
|
25843
26244
|
requestPrompt(initialPrompt) {
|
|
26245
|
+
if (this.#exitRequested) return Promise.resolve("");
|
|
25844
26246
|
const prompt = (initialPrompt ?? "").trim();
|
|
25845
26247
|
if (prompt) {
|
|
25846
26248
|
this.#rememberPrompt(prompt);
|
|
@@ -25881,12 +26283,12 @@ var init_store = __esm({
|
|
|
25881
26283
|
this.#notify();
|
|
25882
26284
|
});
|
|
25883
26285
|
}
|
|
25884
|
-
appendPromptInput(input2) {
|
|
26286
|
+
appendPromptInput(input2, options = {}) {
|
|
25885
26287
|
if (this.#state.inputMode !== "prompt" && this.#state.inputMode !== "running") return;
|
|
25886
26288
|
if (this.#state.inputMode === "prompt") this.#detachPromptHistory();
|
|
25887
26289
|
this.#state.promptInput += input2;
|
|
25888
26290
|
this.#state.promptError = void 0;
|
|
25889
|
-
this.#notify();
|
|
26291
|
+
if (options.notify !== false) this.#notify();
|
|
25890
26292
|
}
|
|
25891
26293
|
navigatePromptHistory(delta) {
|
|
25892
26294
|
if (this.#state.inputMode !== "prompt" || this.#promptHistory.length === 0) return;
|
|
@@ -26041,19 +26443,19 @@ var init_store = __esm({
|
|
|
26041
26443
|
this.#state.activity = "waiting for first message";
|
|
26042
26444
|
this.#notify();
|
|
26043
26445
|
}
|
|
26044
|
-
backspacePromptInput() {
|
|
26446
|
+
backspacePromptInput(options = {}) {
|
|
26045
26447
|
if (this.#state.inputMode !== "prompt" && this.#state.inputMode !== "running") return;
|
|
26046
26448
|
if (this.#state.inputMode === "prompt") this.#detachPromptHistory();
|
|
26047
26449
|
this.#state.promptInput = Array.from(this.#state.promptInput).slice(0, -1).join("");
|
|
26048
26450
|
this.#state.promptError = void 0;
|
|
26049
|
-
this.#notify();
|
|
26451
|
+
if (options.notify !== false) this.#notify();
|
|
26050
26452
|
}
|
|
26051
|
-
clearPromptInput() {
|
|
26453
|
+
clearPromptInput(options = {}) {
|
|
26052
26454
|
if (this.#state.inputMode !== "prompt" && this.#state.inputMode !== "running") return;
|
|
26053
26455
|
if (this.#state.inputMode === "prompt") this.#detachPromptHistory();
|
|
26054
26456
|
this.#state.promptInput = "";
|
|
26055
26457
|
this.#state.promptError = void 0;
|
|
26056
|
-
this.#notify();
|
|
26458
|
+
if (options.notify !== false) this.#notify();
|
|
26057
26459
|
}
|
|
26058
26460
|
usePendingClaudeCodePlan() {
|
|
26059
26461
|
if (this.#state.inputMode !== "prompt") return false;
|
|
@@ -26881,9 +27283,24 @@ var init_store = __esm({
|
|
|
26881
27283
|
resolve(prompt);
|
|
26882
27284
|
this.#notify();
|
|
26883
27285
|
}
|
|
27286
|
+
#resolveSession(selection) {
|
|
27287
|
+
const resolve = this.#sessionResolve;
|
|
27288
|
+
if (!resolve) return;
|
|
27289
|
+
this.#sessionResolve = void 0;
|
|
27290
|
+
if (selection.kind === "exit") {
|
|
27291
|
+
this.#state.inputMode = "done";
|
|
27292
|
+
this.#state.done = true;
|
|
27293
|
+
this.#state.activity = "exiting";
|
|
27294
|
+
} else {
|
|
27295
|
+
this.#state.inputMode = "starting";
|
|
27296
|
+
this.#state.activity = selection.kind === "new" ? "creating session" : "opening session";
|
|
27297
|
+
}
|
|
27298
|
+
this.#notify();
|
|
27299
|
+
resolve(selection);
|
|
27300
|
+
}
|
|
26884
27301
|
#rememberPrompt(prompt) {
|
|
26885
27302
|
const value = prompt.trim();
|
|
26886
|
-
if (!value || isExitCommand(value) || isStopCommand(value) || isCompactCommand(value) || isRetryCommand(value)) return;
|
|
27303
|
+
if (!value || isExitCommand(value) || isStopCommand(value) || isCompactCommand(value) || isRetryCommand(value) || isSessionCommand(value)) return;
|
|
26887
27304
|
if (this.#promptHistory.at(-1) === value) {
|
|
26888
27305
|
this.#state.canRetryLastPrompt = true;
|
|
26889
27306
|
return;
|
|
@@ -26895,6 +27312,20 @@ var init_store = __esm({
|
|
|
26895
27312
|
#lastRetryPrompt() {
|
|
26896
27313
|
return this.#promptHistory.at(-1);
|
|
26897
27314
|
}
|
|
27315
|
+
#resetTransientConversationState() {
|
|
27316
|
+
this.#toolRuns.clear();
|
|
27317
|
+
this.#goalWorkBlocks.clear();
|
|
27318
|
+
this.#coworkBlocks.clear();
|
|
27319
|
+
this.#activeGoalWorkBlockId = void 0;
|
|
27320
|
+
this.#currentGoalNarrationId = void 0;
|
|
27321
|
+
this.#timelineProgressIds.clear();
|
|
27322
|
+
this.#pendingPermissionCallId = void 0;
|
|
27323
|
+
if (this.#pendingPermissionTimeout) clearTimeout(this.#pendingPermissionTimeout);
|
|
27324
|
+
this.#pendingPermissionTimeout = void 0;
|
|
27325
|
+
this.#activeClaudeCodePlan = void 0;
|
|
27326
|
+
this.#promptHistoryCursor = void 0;
|
|
27327
|
+
this.#promptDraft = "";
|
|
27328
|
+
}
|
|
26898
27329
|
#detachPromptHistory() {
|
|
26899
27330
|
this.#promptHistoryCursor = void 0;
|
|
26900
27331
|
this.#promptDraft = "";
|
|
@@ -26982,22 +27413,43 @@ var init_store = __esm({
|
|
|
26982
27413
|
var app_exports = {};
|
|
26983
27414
|
__export(app_exports, {
|
|
26984
27415
|
TuiApp: () => TuiApp,
|
|
27416
|
+
commandPaletteMatches: () => commandPaletteMatches,
|
|
27417
|
+
inputFrameRows: () => inputFrameRows,
|
|
27418
|
+
isCtrlCKeypress: () => isCtrlCKeypress,
|
|
27419
|
+
isCtrlPKeypress: () => isCtrlPKeypress,
|
|
27420
|
+
isPromptNewlineKeypress: () => isPromptNewlineKeypress,
|
|
27421
|
+
sessionHeaderLine: () => sessionHeaderLine,
|
|
27422
|
+
sessionOptionLine: () => sessionOptionLine,
|
|
27423
|
+
slashCommandMatches: () => slashCommandMatches,
|
|
26985
27424
|
textInputForKeypress: () => textInputForKeypress,
|
|
26986
|
-
|
|
27425
|
+
userMessageBubbleWidth: () => userMessageBubbleWidth,
|
|
27426
|
+
workPlanProgressCounts: () => workPlanProgressCounts,
|
|
27427
|
+
wrapBlockLines: () => wrapBlockLines
|
|
26987
27428
|
});
|
|
26988
27429
|
import React, { useEffect, useState } from "react";
|
|
26989
27430
|
import { Box, Text, useApp, useInput } from "ink";
|
|
26990
27431
|
function TuiApp({ store, version = "dev" }) {
|
|
26991
27432
|
const [state, setState] = useState(() => store.snapshot());
|
|
27433
|
+
const [promptInput, setPromptInput] = useState(() => store.snapshot().promptInput);
|
|
26992
27434
|
const [now2, setNow] = useState(() => Date.now());
|
|
26993
27435
|
const [shortcutMode, setShortcutMode] = useState(false);
|
|
27436
|
+
const [slashCommandCursor, setSlashCommandCursor] = useState(0);
|
|
27437
|
+
const [slashCommandClosedPrefix, setSlashCommandClosedPrefix] = useState();
|
|
27438
|
+
const [commandPaletteOpen, setCommandPaletteOpen] = useState(false);
|
|
27439
|
+
const [commandPaletteQuery, setCommandPaletteQuery] = useState("");
|
|
27440
|
+
const [commandPaletteCursor, setCommandPaletteCursor] = useState(0);
|
|
26994
27441
|
const app = useApp();
|
|
26995
27442
|
useEffect(() => {
|
|
26996
|
-
const update = () =>
|
|
27443
|
+
const update = () => {
|
|
27444
|
+
const next = store.snapshot();
|
|
27445
|
+
setState(next);
|
|
27446
|
+
setPromptInput(next.promptInput);
|
|
27447
|
+
};
|
|
26997
27448
|
const unsubscribe = store.subscribe(update);
|
|
26998
27449
|
update();
|
|
26999
27450
|
return unsubscribe;
|
|
27000
27451
|
}, [store]);
|
|
27452
|
+
useEffect(() => enableEnhancedKeyboardInput(), []);
|
|
27001
27453
|
useEffect(() => {
|
|
27002
27454
|
if (!state.workPlan && state.inputMode !== "running" && state.inputMode !== "starting") return;
|
|
27003
27455
|
const timer = setInterval(() => setNow(Date.now()), 450);
|
|
@@ -27006,8 +27458,60 @@ function TuiApp({ store, version = "dev" }) {
|
|
|
27006
27458
|
useEffect(() => {
|
|
27007
27459
|
setShortcutMode(false);
|
|
27008
27460
|
}, [state.inputMode, state.permission !== void 0]);
|
|
27461
|
+
useEffect(() => {
|
|
27462
|
+
setSlashCommandCursor(0);
|
|
27463
|
+
if (slashCommandClosedPrefix && !isSlashCommandClosedForPrompt(promptInput, slashCommandClosedPrefix)) setSlashCommandClosedPrefix(void 0);
|
|
27464
|
+
}, [promptInput, state.inputMode, slashCommandClosedPrefix]);
|
|
27465
|
+
useEffect(() => {
|
|
27466
|
+
setCommandPaletteCursor(0);
|
|
27467
|
+
}, [commandPaletteQuery, state.inputMode]);
|
|
27468
|
+
useEffect(() => {
|
|
27469
|
+
if (commandPaletteOpen && !canUseCommandPalette(state)) setCommandPaletteOpen(false);
|
|
27470
|
+
}, [commandPaletteOpen, state.inputMode, state.permission]);
|
|
27471
|
+
const commandPaletteItems = commandPaletteOpen ? commandPaletteMatches(commandPaletteQuery, state.inputMode, commandPaletteAvailability(state, promptInput)) : [];
|
|
27472
|
+
const commandPaletteItem = commandPaletteItems[Math.min(commandPaletteCursor, Math.max(0, commandPaletteItems.length - 1))];
|
|
27009
27473
|
useInput((input2, key) => {
|
|
27474
|
+
if (isCtrlCKeypress(input2, key)) {
|
|
27475
|
+
store.requestExit();
|
|
27476
|
+
app.exit();
|
|
27477
|
+
return;
|
|
27478
|
+
}
|
|
27479
|
+
if (isCtrlPKeypress(input2, key) && canUseCommandPalette(state)) {
|
|
27480
|
+
setCommandPaletteOpen((open4) => !open4);
|
|
27481
|
+
setCommandPaletteQuery("");
|
|
27482
|
+
setCommandPaletteCursor(0);
|
|
27483
|
+
setShortcutMode(false);
|
|
27484
|
+
setSlashCommandClosedPrefix(promptInput);
|
|
27485
|
+
return;
|
|
27486
|
+
}
|
|
27010
27487
|
const textInput = textInputForKeypress(input2, key);
|
|
27488
|
+
if (commandPaletteOpen) {
|
|
27489
|
+
if (key.escape) {
|
|
27490
|
+
closeCommandPalette(setCommandPaletteOpen, setCommandPaletteQuery, setCommandPaletteCursor);
|
|
27491
|
+
return;
|
|
27492
|
+
}
|
|
27493
|
+
if (key.upArrow) {
|
|
27494
|
+
if (commandPaletteItems.length > 0) setCommandPaletteCursor((cursor) => (cursor - 1 + commandPaletteItems.length) % commandPaletteItems.length);
|
|
27495
|
+
return;
|
|
27496
|
+
}
|
|
27497
|
+
if (key.downArrow) {
|
|
27498
|
+
if (commandPaletteItems.length > 0) setCommandPaletteCursor((cursor) => (cursor + 1) % commandPaletteItems.length);
|
|
27499
|
+
return;
|
|
27500
|
+
}
|
|
27501
|
+
if (key.return) {
|
|
27502
|
+
if (commandPaletteItem) executeCommandPaletteItem({ item: commandPaletteItem, store, app, setPromptInput, setState, close: () => closeCommandPalette(setCommandPaletteOpen, setCommandPaletteQuery, setCommandPaletteCursor) });
|
|
27503
|
+
return;
|
|
27504
|
+
}
|
|
27505
|
+
if (key.backspace || key.delete) {
|
|
27506
|
+
setCommandPaletteQuery((current) => Array.from(current).slice(0, -1).join(""));
|
|
27507
|
+
return;
|
|
27508
|
+
}
|
|
27509
|
+
if (textInput) {
|
|
27510
|
+
setCommandPaletteQuery((current) => `${current}${textInput}`);
|
|
27511
|
+
return;
|
|
27512
|
+
}
|
|
27513
|
+
return;
|
|
27514
|
+
}
|
|
27011
27515
|
if (shortcutMode) {
|
|
27012
27516
|
setShortcutMode(false);
|
|
27013
27517
|
if (key.escape) return;
|
|
@@ -27038,7 +27542,9 @@ function TuiApp({ store, version = "dev" }) {
|
|
|
27038
27542
|
return;
|
|
27039
27543
|
}
|
|
27040
27544
|
if (shortcut === "u" && state.inputMode === "prompt") {
|
|
27041
|
-
store.clearPromptInput();
|
|
27545
|
+
store.clearPromptInput({ notify: false });
|
|
27546
|
+
setPromptInput("");
|
|
27547
|
+
clearPromptErrorPreview(setState);
|
|
27042
27548
|
return;
|
|
27043
27549
|
}
|
|
27044
27550
|
if (shortcut === "d" && state.turnDiff) {
|
|
@@ -27070,6 +27576,31 @@ function TuiApp({ store, version = "dev" }) {
|
|
|
27070
27576
|
if (normalized === "n" || key.return) store.answerPermission({ decision: "deny" });
|
|
27071
27577
|
return;
|
|
27072
27578
|
}
|
|
27579
|
+
if (state.inputMode === "session") {
|
|
27580
|
+
const normalized = input2.toLowerCase();
|
|
27581
|
+
if (key.escape || normalized === "q") {
|
|
27582
|
+
store.requestExit();
|
|
27583
|
+
app.exit();
|
|
27584
|
+
return;
|
|
27585
|
+
}
|
|
27586
|
+
if (normalized === "n") {
|
|
27587
|
+
store.submitNewSessionSelection();
|
|
27588
|
+
return;
|
|
27589
|
+
}
|
|
27590
|
+
if (key.upArrow) {
|
|
27591
|
+
store.moveSessionCursor(-1);
|
|
27592
|
+
return;
|
|
27593
|
+
}
|
|
27594
|
+
if (key.downArrow) {
|
|
27595
|
+
store.moveSessionCursor(1);
|
|
27596
|
+
return;
|
|
27597
|
+
}
|
|
27598
|
+
if (key.return) {
|
|
27599
|
+
store.submitSessionSelection();
|
|
27600
|
+
return;
|
|
27601
|
+
}
|
|
27602
|
+
return;
|
|
27603
|
+
}
|
|
27073
27604
|
if (state.inputMode === "provider") {
|
|
27074
27605
|
if (key.escape) {
|
|
27075
27606
|
store.closeSettings();
|
|
@@ -27145,6 +27676,25 @@ function TuiApp({ store, version = "dev" }) {
|
|
|
27145
27676
|
return;
|
|
27146
27677
|
}
|
|
27147
27678
|
if (state.inputMode === "prompt" || state.inputMode === "running") {
|
|
27679
|
+
const slashCommands2 = visibleSlashCommandMatches(promptInput, state.inputMode, slashCommandClosedPrefix);
|
|
27680
|
+
const slashCommand = slashCommands2[slashCommandCursor] ?? slashCommands2[0];
|
|
27681
|
+
if (slashCommands2.length > 0 && key.escape) {
|
|
27682
|
+
setSlashCommandClosedPrefix(promptInput);
|
|
27683
|
+
return;
|
|
27684
|
+
}
|
|
27685
|
+
if (slashCommands2.length > 0 && key.upArrow) {
|
|
27686
|
+
setSlashCommandCursor((cursor) => (cursor - 1 + slashCommands2.length) % slashCommands2.length);
|
|
27687
|
+
return;
|
|
27688
|
+
}
|
|
27689
|
+
if (slashCommands2.length > 0 && key.downArrow) {
|
|
27690
|
+
setSlashCommandCursor((cursor) => (cursor + 1) % slashCommands2.length);
|
|
27691
|
+
return;
|
|
27692
|
+
}
|
|
27693
|
+
if (slashCommands2.length > 0 && key.tab && slashCommand) {
|
|
27694
|
+
applySlashCommandDraft(store, setPromptInput, slashCommand, setSlashCommandClosedPrefix);
|
|
27695
|
+
clearPromptErrorPreview(setState);
|
|
27696
|
+
return;
|
|
27697
|
+
}
|
|
27148
27698
|
if (state.inputMode === "prompt" && key.upArrow) {
|
|
27149
27699
|
store.navigatePromptHistory(-1);
|
|
27150
27700
|
return;
|
|
@@ -27157,25 +27707,51 @@ function TuiApp({ store, version = "dev" }) {
|
|
|
27157
27707
|
setShortcutMode(true);
|
|
27158
27708
|
return;
|
|
27159
27709
|
}
|
|
27160
|
-
if (key
|
|
27161
|
-
|
|
27710
|
+
if (isPromptNewlineKeypress(input2, key)) {
|
|
27711
|
+
appendPromptDraft(store, setPromptInput, `${textInput}
|
|
27712
|
+
`);
|
|
27713
|
+
clearPromptErrorPreview(setState);
|
|
27714
|
+
return;
|
|
27715
|
+
}
|
|
27716
|
+
if (isPromptSubmitKeypress(input2, key)) {
|
|
27717
|
+
if (!textInput && slashCommand && shouldSelectSlashCommand(promptInput, slashCommand)) {
|
|
27718
|
+
applySlashCommandDraft(store, setPromptInput, slashCommand, setSlashCommandClosedPrefix);
|
|
27719
|
+
clearPromptErrorPreview(setState);
|
|
27720
|
+
return;
|
|
27721
|
+
}
|
|
27722
|
+
if (textInput) appendPromptDraft(store, setPromptInput, textInput);
|
|
27162
27723
|
store.submitPromptInput();
|
|
27163
27724
|
return;
|
|
27164
27725
|
}
|
|
27165
27726
|
if (key.backspace || key.delete) {
|
|
27166
|
-
store.backspacePromptInput();
|
|
27727
|
+
store.backspacePromptInput({ notify: false });
|
|
27728
|
+
setPromptInput((current) => Array.from(current).slice(0, -1).join(""));
|
|
27729
|
+
clearPromptErrorPreview(setState);
|
|
27167
27730
|
return;
|
|
27168
27731
|
}
|
|
27169
|
-
if (textInput)
|
|
27732
|
+
if (textInput) {
|
|
27733
|
+
appendPromptDraft(store, setPromptInput, textInput);
|
|
27734
|
+
clearPromptErrorPreview(setState);
|
|
27735
|
+
}
|
|
27170
27736
|
return;
|
|
27171
27737
|
}
|
|
27172
27738
|
});
|
|
27173
27739
|
const shellProps = { flexDirection: "column", paddingX: 1, minHeight: terminalHeight() };
|
|
27740
|
+
const slashCommands = commandPaletteOpen ? [] : visibleSlashCommandMatches(promptInput, state.inputMode, slashCommandClosedPrefix);
|
|
27741
|
+
const slashCommandPalette = slashCommands.length > 0 ? { items: slashCommands, cursor: Math.min(slashCommandCursor, slashCommands.length - 1) } : void 0;
|
|
27742
|
+
const commandPalette = commandPaletteOpen ? { items: commandPaletteItems, query: commandPaletteQuery, cursor: Math.min(commandPaletteCursor, Math.max(0, commandPaletteItems.length - 1)) } : void 0;
|
|
27743
|
+
if (shouldShowSessionStart(state)) {
|
|
27744
|
+
return React.createElement(
|
|
27745
|
+
Box,
|
|
27746
|
+
shellProps,
|
|
27747
|
+
React.createElement(SessionStart, { state, version })
|
|
27748
|
+
);
|
|
27749
|
+
}
|
|
27174
27750
|
if (shouldShowEmptyState(state)) {
|
|
27175
27751
|
return React.createElement(
|
|
27176
27752
|
Box,
|
|
27177
27753
|
shellProps,
|
|
27178
|
-
React.createElement(EmptyState, { state, version, shortcutMode })
|
|
27754
|
+
React.createElement(EmptyState, { state, version, shortcutMode, promptInput, slashCommandPalette, commandPalette })
|
|
27179
27755
|
);
|
|
27180
27756
|
}
|
|
27181
27757
|
return React.createElement(
|
|
@@ -27186,51 +27762,402 @@ function TuiApp({ store, version = "dev" }) {
|
|
|
27186
27762
|
Box,
|
|
27187
27763
|
{ flexDirection: "column", flexGrow: 1, paddingX: 1 },
|
|
27188
27764
|
React.createElement(shouldShowLoading(state) ? LoadingView : TranscriptView, { state }),
|
|
27189
|
-
React.createElement(DiffAccordion, { state }),
|
|
27190
|
-
React.createElement(WorkPlanPanel, { state, now: now2 }),
|
|
27191
|
-
React.createElement(ActivityBar, { state }),
|
|
27192
|
-
React.createElement(GoalIsland, { state }),
|
|
27193
27765
|
React.createElement(Box, { flexGrow: 1 }),
|
|
27194
|
-
React.createElement(
|
|
27766
|
+
React.createElement(BottomStatusStack, { state, now: now2 }),
|
|
27767
|
+
React.createElement(InteractionPanel, { state, shortcutMode, promptInput, slashCommandPalette, commandPalette })
|
|
27195
27768
|
)
|
|
27196
27769
|
);
|
|
27197
27770
|
}
|
|
27771
|
+
function appendPromptDraft(store, setPromptInput, value) {
|
|
27772
|
+
if (!value) return;
|
|
27773
|
+
store.appendPromptInput(value, { notify: false });
|
|
27774
|
+
setPromptInput((current) => `${current}${value}`);
|
|
27775
|
+
}
|
|
27776
|
+
function clearPromptErrorPreview(setState) {
|
|
27777
|
+
setState((current) => current.promptError ? { ...current, promptError: void 0 } : current);
|
|
27778
|
+
}
|
|
27779
|
+
function applySlashCommandDraft(store, setPromptInput, item, setSlashCommandClosedPrefix) {
|
|
27780
|
+
const next = item.argument ? `${item.insert} ` : item.insert;
|
|
27781
|
+
store.clearPromptInput({ notify: false });
|
|
27782
|
+
store.appendPromptInput(next, { notify: false });
|
|
27783
|
+
setPromptInput(next);
|
|
27784
|
+
setSlashCommandClosedPrefix(next);
|
|
27785
|
+
}
|
|
27786
|
+
function shouldSelectSlashCommand(promptInput, item) {
|
|
27787
|
+
const value = promptInput.trim();
|
|
27788
|
+
if (!value || value.includes(" ")) return false;
|
|
27789
|
+
if (!item.argument && value.toLowerCase() === item.insert.toLowerCase()) return false;
|
|
27790
|
+
return true;
|
|
27791
|
+
}
|
|
27792
|
+
function visibleSlashCommandMatches(promptInput, mode, closedPrefix) {
|
|
27793
|
+
if (closedPrefix && isSlashCommandClosedForPrompt(promptInput, closedPrefix)) return [];
|
|
27794
|
+
return slashCommandMatches(promptInput, mode).slice(0, 7);
|
|
27795
|
+
}
|
|
27796
|
+
function isSlashCommandClosedForPrompt(promptInput, closedPrefix) {
|
|
27797
|
+
return promptInput === closedPrefix || closedPrefix.endsWith(" ") && promptInput.startsWith(closedPrefix);
|
|
27798
|
+
}
|
|
27799
|
+
function slashCommandMatches(promptInput, mode = "prompt") {
|
|
27800
|
+
const query = slashCommandQuery(promptInput);
|
|
27801
|
+
if (query === void 0) return [];
|
|
27802
|
+
return SLASH_COMMANDS.filter((item) => slashCommandActiveInMode(item, mode)).map((item, index) => ({ item, index, score: slashCommandScore(item, query) })).filter((entry) => entry.score < Number.POSITIVE_INFINITY).sort((a, b2) => a.score - b2.score || a.index - b2.index).map((entry) => entry.item);
|
|
27803
|
+
}
|
|
27804
|
+
function slashCommandQuery(promptInput) {
|
|
27805
|
+
const value = promptInput.trimStart();
|
|
27806
|
+
if (!value.startsWith("/") || value.includes("\n")) return void 0;
|
|
27807
|
+
if (/\s/.test(value)) return void 0;
|
|
27808
|
+
return value.slice(1).toLowerCase();
|
|
27809
|
+
}
|
|
27810
|
+
function slashCommandActiveInMode(item, mode) {
|
|
27811
|
+
if (mode !== "prompt" && mode !== "running") return false;
|
|
27812
|
+
return item.mode === "both" || item.mode === mode || !item.mode && mode === "prompt";
|
|
27813
|
+
}
|
|
27814
|
+
function slashCommandScore(item, query) {
|
|
27815
|
+
if (!query) return 0;
|
|
27816
|
+
const command = item.command.slice(1).toLowerCase();
|
|
27817
|
+
const insert = item.insert.slice(1).toLowerCase();
|
|
27818
|
+
const aliases = item.aliases?.map((alias) => alias.toLowerCase()) ?? [];
|
|
27819
|
+
const aliasSearchEnabled = query.length >= 3;
|
|
27820
|
+
if (command.startsWith(query)) return 0;
|
|
27821
|
+
if (insert.startsWith(query)) return 1;
|
|
27822
|
+
if (aliasSearchEnabled && aliases.some((alias) => alias.startsWith(query))) return 2;
|
|
27823
|
+
if (command.includes(query) || insert.includes(query)) return 3;
|
|
27824
|
+
if (aliasSearchEnabled && aliases.some((alias) => alias.includes(query))) return 4;
|
|
27825
|
+
return Number.POSITIVE_INFINITY;
|
|
27826
|
+
}
|
|
27827
|
+
function canUseCommandPalette(state) {
|
|
27828
|
+
return !state.permission && (state.inputMode === "prompt" || state.inputMode === "running");
|
|
27829
|
+
}
|
|
27830
|
+
function commandPaletteAvailability(state, promptInput) {
|
|
27831
|
+
return {
|
|
27832
|
+
hasPromptDraft: Boolean(promptInput.trim()),
|
|
27833
|
+
hasSelection: Boolean(state.selection),
|
|
27834
|
+
hasProviders: state.providerOptions.length > 0,
|
|
27835
|
+
hasAgents: state.agentOptions.length > 0,
|
|
27836
|
+
hasDiff: Boolean(state.turnDiff),
|
|
27837
|
+
hasTools: state.blocks.some((block) => block.kind === "tool"),
|
|
27838
|
+
hasWorkPlan: Boolean(state.workPlan),
|
|
27839
|
+
hasPendingClaudeCodePlan: Boolean(state.pendingClaudeCodePlan),
|
|
27840
|
+
canRetryLastPrompt: state.canRetryLastPrompt
|
|
27841
|
+
};
|
|
27842
|
+
}
|
|
27843
|
+
function commandPaletteMatches(query, mode = "prompt", availability = {}) {
|
|
27844
|
+
const normalized = query.trim().toLowerCase();
|
|
27845
|
+
const items = buildCommandPaletteItems(mode, availability);
|
|
27846
|
+
if (!normalized) return items;
|
|
27847
|
+
return items.map((item, index) => ({ item, index, score: commandPaletteScore(item, normalized) })).filter((entry) => entry.score < Number.POSITIVE_INFINITY).sort((a, b2) => a.score - b2.score || a.index - b2.index).map((entry) => entry.item);
|
|
27848
|
+
}
|
|
27849
|
+
function buildCommandPaletteItems(mode, availability) {
|
|
27850
|
+
if (mode !== "prompt" && mode !== "running") return [];
|
|
27851
|
+
const items = [];
|
|
27852
|
+
const promptReadyForSettings = mode === "prompt" && !availability.hasPromptDraft;
|
|
27853
|
+
if (promptReadyForSettings && availability.hasSelection) {
|
|
27854
|
+
items.push({ id: "switch-model", title: "Switch model", description: "Choose the model for the current provider", group: "Suggested", shortcut: "esc m", action: "open-model", keywords: ["model", "provider model"] });
|
|
27855
|
+
}
|
|
27856
|
+
if (promptReadyForSettings && availability.hasProviders) {
|
|
27857
|
+
items.push({ id: "connect-provider", title: "Connect provider", description: "Change the active provider", group: "Suggested", shortcut: "esc p", action: "open-provider", keywords: ["provider", "connect"] });
|
|
27858
|
+
}
|
|
27859
|
+
if (promptReadyForSettings && availability.hasAgents) {
|
|
27860
|
+
items.push({ id: "switch-agent", title: "Switch agent", description: "Change the active agent profile", group: "Suggested", shortcut: "esc a", action: "open-agent", keywords: ["agent"] });
|
|
27861
|
+
}
|
|
27862
|
+
if (promptReadyForSettings) {
|
|
27863
|
+
items.push({ id: "permission-preset", title: "Permission preset", description: "Choose the next-turn permission behavior", group: "Suggested", shortcut: "esc o", action: "open-permissions", keywords: ["permission", "policy", "approval"] });
|
|
27864
|
+
}
|
|
27865
|
+
for (const command of SLASH_COMMANDS) {
|
|
27866
|
+
if (!slashCommandActiveInMode(command, mode)) continue;
|
|
27867
|
+
if (command.command === "/stop" || command.command === "/exit" || command.command === "/quit" || command.command === "/retry") continue;
|
|
27868
|
+
items.push({
|
|
27869
|
+
id: `slash:${command.command}`,
|
|
27870
|
+
title: commandPaletteSlashTitle(command),
|
|
27871
|
+
description: command.description,
|
|
27872
|
+
group: command.command.startsWith("/session") ? "Session" : "Commands",
|
|
27873
|
+
shortcut: command.command,
|
|
27874
|
+
keywords: [command.command, command.insert, ...command.aliases ?? []],
|
|
27875
|
+
slashCommand: command
|
|
27876
|
+
});
|
|
27877
|
+
}
|
|
27878
|
+
if (mode === "running") {
|
|
27879
|
+
items.push({ id: "stop-task", title: "Stop running task", description: "Cancel the current task", group: "System", shortcut: "/stop", action: "stop", keywords: ["stop", "cancel"] });
|
|
27880
|
+
}
|
|
27881
|
+
if (availability.hasPromptDraft) {
|
|
27882
|
+
items.push({ id: "clear-prompt", title: "Clear prompt", description: "Erase the current input draft", group: "System", shortcut: "esc u", action: "clear-prompt", keywords: ["clear", "draft", "input"] });
|
|
27883
|
+
}
|
|
27884
|
+
if (mode === "prompt" && availability.canRetryLastPrompt) {
|
|
27885
|
+
items.push({ id: "retry-last", title: "Retry last prompt", description: "Run the previous prompt again", group: "System", shortcut: "/retry", action: "retry", keywords: ["retry", "again", "rerun"] });
|
|
27886
|
+
}
|
|
27887
|
+
if (availability.hasPendingClaudeCodePlan) {
|
|
27888
|
+
items.push({ id: "use-claude-code-plan", title: "Use Claude Code plan", description: "Queue the captured plan for execution", group: "System", shortcut: "esc e", action: "use-claude-plan", keywords: ["claude", "plan"] });
|
|
27889
|
+
}
|
|
27890
|
+
if (availability.hasDiff) {
|
|
27891
|
+
items.push({ id: "toggle-diff", title: "Toggle diff", description: "Show or hide the latest file diff", group: "System", shortcut: "esc d", action: "toggle-diff", keywords: ["diff", "changes"] });
|
|
27892
|
+
}
|
|
27893
|
+
if (availability.hasTools) {
|
|
27894
|
+
items.push({ id: "toggle-tools", title: "Toggle tool details", description: "Expand or collapse the latest tool block", group: "System", shortcut: "esc t", action: "toggle-tools", keywords: ["tool", "details"] });
|
|
27895
|
+
}
|
|
27896
|
+
if (availability.hasWorkPlan || mode === "running") {
|
|
27897
|
+
items.push({ id: "toggle-work-plan", title: "Toggle work plan", description: "Show or hide current plan details", group: "System", shortcut: "esc w", action: "toggle-work-plan", keywords: ["plan", "progress"] });
|
|
27898
|
+
}
|
|
27899
|
+
items.push({ id: "exit-app", title: "Exit the app", description: "Close Demian", group: "System", shortcut: "/exit", action: "exit", keywords: ["quit", "close"] });
|
|
27900
|
+
return items;
|
|
27901
|
+
}
|
|
27902
|
+
function commandPaletteSlashTitle(item) {
|
|
27903
|
+
switch (item.command) {
|
|
27904
|
+
case "/cowork":
|
|
27905
|
+
return "Cowork agents";
|
|
27906
|
+
case "/compact":
|
|
27907
|
+
return "Compact context";
|
|
27908
|
+
case "/session":
|
|
27909
|
+
return "Session command";
|
|
27910
|
+
case "/session list":
|
|
27911
|
+
return "List sessions";
|
|
27912
|
+
case "/session new":
|
|
27913
|
+
return "New session";
|
|
27914
|
+
case "/session switch":
|
|
27915
|
+
return "Switch session";
|
|
27916
|
+
case "/session rename":
|
|
27917
|
+
return "Rename session";
|
|
27918
|
+
case "/session delete":
|
|
27919
|
+
return "Delete session";
|
|
27920
|
+
case "/goal":
|
|
27921
|
+
return "Start goal";
|
|
27922
|
+
case "/goal status":
|
|
27923
|
+
return "Goal status";
|
|
27924
|
+
case "/goal clear":
|
|
27925
|
+
return "Clear goal state";
|
|
27926
|
+
case "/ralph-loop":
|
|
27927
|
+
return "Start Ralph loop";
|
|
27928
|
+
case "/cancel-ralph":
|
|
27929
|
+
return "Cancel Ralph loop";
|
|
27930
|
+
default:
|
|
27931
|
+
return item.command;
|
|
27932
|
+
}
|
|
27933
|
+
}
|
|
27934
|
+
function commandPaletteScore(item, query) {
|
|
27935
|
+
const title = item.title.toLowerCase();
|
|
27936
|
+
const shortcut = item.shortcut?.toLowerCase() ?? "";
|
|
27937
|
+
const description = item.description.toLowerCase();
|
|
27938
|
+
const keywords = item.keywords?.map((keyword) => keyword.toLowerCase()) ?? [];
|
|
27939
|
+
if (title.startsWith(query)) return 0;
|
|
27940
|
+
if (shortcut.startsWith(query)) return 1;
|
|
27941
|
+
if (keywords.some((keyword) => keyword.startsWith(query))) return 2;
|
|
27942
|
+
if (title.includes(query)) return 3;
|
|
27943
|
+
if (shortcut.includes(query)) return 4;
|
|
27944
|
+
if (keywords.some((keyword) => keyword.includes(query))) return 5;
|
|
27945
|
+
if (description.includes(query)) return 6;
|
|
27946
|
+
return Number.POSITIVE_INFINITY;
|
|
27947
|
+
}
|
|
27948
|
+
function closeCommandPalette(setCommandPaletteOpen, setCommandPaletteQuery, setCommandPaletteCursor) {
|
|
27949
|
+
setCommandPaletteOpen(false);
|
|
27950
|
+
setCommandPaletteQuery("");
|
|
27951
|
+
setCommandPaletteCursor(0);
|
|
27952
|
+
}
|
|
27953
|
+
function executeCommandPaletteItem({
|
|
27954
|
+
item,
|
|
27955
|
+
store,
|
|
27956
|
+
app,
|
|
27957
|
+
setPromptInput,
|
|
27958
|
+
setState,
|
|
27959
|
+
close
|
|
27960
|
+
}) {
|
|
27961
|
+
close();
|
|
27962
|
+
if (item.slashCommand) {
|
|
27963
|
+
applyCommandPaletteSlashCommand(store, setPromptInput, item.slashCommand);
|
|
27964
|
+
clearPromptErrorPreview(setState);
|
|
27965
|
+
return;
|
|
27966
|
+
}
|
|
27967
|
+
switch (item.action) {
|
|
27968
|
+
case "open-model":
|
|
27969
|
+
store.openModelEditor();
|
|
27970
|
+
return;
|
|
27971
|
+
case "open-provider":
|
|
27972
|
+
store.openProviderSelector();
|
|
27973
|
+
return;
|
|
27974
|
+
case "open-agent":
|
|
27975
|
+
store.openAgentSelector();
|
|
27976
|
+
return;
|
|
27977
|
+
case "open-permissions":
|
|
27978
|
+
store.openPermissionPresetSelector();
|
|
27979
|
+
return;
|
|
27980
|
+
case "clear-prompt":
|
|
27981
|
+
store.clearPromptInput({ notify: false });
|
|
27982
|
+
setPromptInput("");
|
|
27983
|
+
clearPromptErrorPreview(setState);
|
|
27984
|
+
return;
|
|
27985
|
+
case "retry":
|
|
27986
|
+
store.retryLastPrompt();
|
|
27987
|
+
return;
|
|
27988
|
+
case "use-claude-plan":
|
|
27989
|
+
store.usePendingClaudeCodePlan();
|
|
27990
|
+
return;
|
|
27991
|
+
case "toggle-diff":
|
|
27992
|
+
store.toggleDiffExpanded();
|
|
27993
|
+
return;
|
|
27994
|
+
case "toggle-tools":
|
|
27995
|
+
store.toggleLatestToolExpanded();
|
|
27996
|
+
return;
|
|
27997
|
+
case "toggle-work-plan":
|
|
27998
|
+
store.toggleWorkPlanExpanded();
|
|
27999
|
+
return;
|
|
28000
|
+
case "stop":
|
|
28001
|
+
store.stopActiveTask();
|
|
28002
|
+
return;
|
|
28003
|
+
case "exit":
|
|
28004
|
+
store.requestExit();
|
|
28005
|
+
app.exit();
|
|
28006
|
+
return;
|
|
28007
|
+
}
|
|
28008
|
+
}
|
|
28009
|
+
function applyCommandPaletteSlashCommand(store, setPromptInput, item) {
|
|
28010
|
+
const shouldInsert = item.argument && item.command !== "/session new";
|
|
28011
|
+
const next = shouldInsert ? `${item.insert} ` : item.insert;
|
|
28012
|
+
store.clearPromptInput({ notify: false });
|
|
28013
|
+
store.appendPromptInput(next, { notify: false });
|
|
28014
|
+
setPromptInput(next);
|
|
28015
|
+
if (!shouldInsert) store.submitPromptInput();
|
|
28016
|
+
}
|
|
27198
28017
|
function textInputForKeypress(input2, key) {
|
|
27199
28018
|
if (!input2 || key.ctrl || key.tab || key.escape) return "";
|
|
28019
|
+
const csiText = decodeCsiUTextInput(input2);
|
|
28020
|
+
if (csiText !== void 0) return csiText;
|
|
28021
|
+
if (isKnownKeyboardSequence(input2)) return "";
|
|
27200
28022
|
return Array.from(input2).filter((char) => {
|
|
27201
28023
|
const codePoint = char.codePointAt(0) ?? 0;
|
|
27202
28024
|
return codePoint >= 32 && codePoint !== 127;
|
|
27203
28025
|
}).join("");
|
|
27204
28026
|
}
|
|
28027
|
+
function isPromptNewlineKeypress(input2, key) {
|
|
28028
|
+
if (key.return && key.shift) return true;
|
|
28029
|
+
if (isShiftOrOptionEnterSequence(input2)) return true;
|
|
28030
|
+
return input2 === "\r" && !key.return;
|
|
28031
|
+
}
|
|
28032
|
+
function isCtrlCKeypress(input2, key) {
|
|
28033
|
+
if (input2 === "") return true;
|
|
28034
|
+
if (key.ctrl && input2.toLowerCase() === "c") return true;
|
|
28035
|
+
const csi = CSI_U_INPUT.exec(input2);
|
|
28036
|
+
if (!csi) return false;
|
|
28037
|
+
const codePoint = Number(csi[1]);
|
|
28038
|
+
const modifier = Number(csi[2] ?? 1);
|
|
28039
|
+
return (codePoint === 3 || codePoint === 99) && hasControlModifier(modifier);
|
|
28040
|
+
}
|
|
28041
|
+
function isCtrlPKeypress(input2, key) {
|
|
28042
|
+
if (input2 === "") return true;
|
|
28043
|
+
if (key.ctrl && input2.toLowerCase() === "p") return true;
|
|
28044
|
+
const csi = CSI_U_INPUT.exec(input2);
|
|
28045
|
+
if (!csi) return false;
|
|
28046
|
+
const codePoint = Number(csi[1]);
|
|
28047
|
+
const modifier = Number(csi[2] ?? 1);
|
|
28048
|
+
return (codePoint === 16 || codePoint === 112) && hasControlModifier(modifier);
|
|
28049
|
+
}
|
|
28050
|
+
function isPromptSubmitKeypress(input2, key) {
|
|
28051
|
+
return Boolean(key.return) || input2 === "\n";
|
|
28052
|
+
}
|
|
28053
|
+
function isShiftOrOptionEnterSequence(input2) {
|
|
28054
|
+
const csi = CSI_U_INPUT.exec(input2);
|
|
28055
|
+
if (csi) {
|
|
28056
|
+
const codePoint = Number(csi[1]);
|
|
28057
|
+
const modifier = Number(csi[2] ?? 1);
|
|
28058
|
+
return (codePoint === 13 || codePoint === 10) && hasShiftOrOptionModifier(modifier);
|
|
28059
|
+
}
|
|
28060
|
+
const xterm = XTERM_MODIFIED_ENTER_INPUT.exec(input2);
|
|
28061
|
+
return Boolean(xterm && hasShiftOrOptionModifier(Number(xterm[1])));
|
|
28062
|
+
}
|
|
28063
|
+
function decodeCsiUTextInput(input2) {
|
|
28064
|
+
const csi = CSI_U_INPUT.exec(input2);
|
|
28065
|
+
if (!csi) return void 0;
|
|
28066
|
+
const codePoint = Number(csi[1]);
|
|
28067
|
+
const modifier = Number(csi[2] ?? 1);
|
|
28068
|
+
if (!Number.isFinite(codePoint) || codePoint < 32 || codePoint === 127) return "";
|
|
28069
|
+
if (hasControlModifier(modifier) || hasOptionModifier(modifier)) return "";
|
|
28070
|
+
try {
|
|
28071
|
+
return String.fromCodePoint(codePoint);
|
|
28072
|
+
} catch {
|
|
28073
|
+
return "";
|
|
28074
|
+
}
|
|
28075
|
+
}
|
|
28076
|
+
function isKnownKeyboardSequence(input2) {
|
|
28077
|
+
return isShiftOrOptionEnterSequence(input2) || XTERM_MODIFIED_ENTER_INPUT.test(input2);
|
|
28078
|
+
}
|
|
28079
|
+
function hasShiftOrOptionModifier(modifier) {
|
|
28080
|
+
return hasShiftModifier(modifier) || hasOptionModifier(modifier);
|
|
28081
|
+
}
|
|
28082
|
+
function hasShiftModifier(modifier) {
|
|
28083
|
+
return (modifier - 1 & 1) !== 0;
|
|
28084
|
+
}
|
|
28085
|
+
function hasOptionModifier(modifier) {
|
|
28086
|
+
return (modifier - 1 & 2) !== 0;
|
|
28087
|
+
}
|
|
28088
|
+
function hasControlModifier(modifier) {
|
|
28089
|
+
return (modifier - 1 & 4) !== 0;
|
|
28090
|
+
}
|
|
27205
28091
|
function shouldShowLoading(state) {
|
|
27206
28092
|
return state.inputMode === "starting" || state.inputMode === "running" && state.blocks.length === 0 && !state.streamingText;
|
|
27207
28093
|
}
|
|
28094
|
+
function enableEnhancedKeyboardInput() {
|
|
28095
|
+
if (!process.stdout.isTTY) return () => void 0;
|
|
28096
|
+
process.stdout.write("\x1B[>1u");
|
|
28097
|
+
process.stdout.write("\x1B[>4;2m");
|
|
28098
|
+
return () => {
|
|
28099
|
+
process.stdout.write("\x1B[<u");
|
|
28100
|
+
process.stdout.write("\x1B[>4;0m");
|
|
28101
|
+
};
|
|
28102
|
+
}
|
|
27208
28103
|
function shouldShowEmptyState(state) {
|
|
27209
28104
|
return state.inputMode === "prompt" && !state.permission && state.blocks.length === 0 && !state.streamingText && !state.turnDiff && !state.workPlan && !state.goal;
|
|
27210
28105
|
}
|
|
27211
|
-
function
|
|
27212
|
-
|
|
27213
|
-
|
|
27214
|
-
|
|
28106
|
+
function shouldShowSessionStart(state) {
|
|
28107
|
+
return state.inputMode === "session";
|
|
28108
|
+
}
|
|
28109
|
+
function SessionStart({ state, version }) {
|
|
28110
|
+
const topGap = Math.max(1, Math.min(5, Math.floor(terminalHeight() * 0.12)));
|
|
28111
|
+
const width = sessionPanelWidth();
|
|
27215
28112
|
return React.createElement(
|
|
27216
28113
|
Box,
|
|
27217
28114
|
{ flexDirection: "column", flexGrow: 1 },
|
|
27218
28115
|
React.createElement(Box, { height: topGap }),
|
|
27219
28116
|
React.createElement(DemianWordmark),
|
|
27220
|
-
React.createElement(Box, { height:
|
|
28117
|
+
React.createElement(Box, { height: 1 }),
|
|
28118
|
+
React.createElement(SessionSelector, { state }),
|
|
27221
28119
|
React.createElement(
|
|
27222
28120
|
Box,
|
|
27223
|
-
{ alignSelf: "center", width
|
|
27224
|
-
React.createElement(Text, { color:
|
|
28121
|
+
{ alignSelf: "center", width, justifyContent: "space-between", marginTop: 1 },
|
|
28122
|
+
React.createElement(Text, { color: "white" }, "enter open \xB7 n new \xB7 q quit"),
|
|
28123
|
+
React.createElement(Text, { color: "white" }, `v${version}`)
|
|
27225
28124
|
),
|
|
27226
|
-
React.createElement(
|
|
28125
|
+
React.createElement(Box, { flexGrow: 1 })
|
|
28126
|
+
);
|
|
28127
|
+
}
|
|
28128
|
+
function EmptyState({
|
|
28129
|
+
state,
|
|
28130
|
+
version,
|
|
28131
|
+
shortcutMode,
|
|
28132
|
+
promptInput,
|
|
28133
|
+
slashCommandPalette,
|
|
28134
|
+
commandPalette
|
|
28135
|
+
}) {
|
|
28136
|
+
const placeholder = 'Ask anything... "\uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uAD6C\uC870\uB97C \uC54C\uB824\uC918"';
|
|
28137
|
+
const hint = shortcutMode ? shortcutHelp(state) : "enter send \xB7 shift/option+enter newline \xB7 ctrl+p commands \xB7 /session";
|
|
28138
|
+
const hasOverlay = Boolean(slashCommandPalette || commandPalette);
|
|
28139
|
+
const topGap = hasOverlay ? 0 : Math.max(1, Math.min(6, Math.floor(terminalHeight() * 0.12)));
|
|
28140
|
+
return React.createElement(
|
|
28141
|
+
Box,
|
|
28142
|
+
{ flexDirection: "column", flexGrow: 1 },
|
|
28143
|
+
React.createElement(Box, { height: topGap }),
|
|
28144
|
+
React.createElement(DemianWordmark),
|
|
28145
|
+
React.createElement(Box, { height: hasOverlay ? 1 : 2 }),
|
|
28146
|
+
commandPalette ? React.createElement(CommandPalettePanel, { palette: commandPalette }) : null,
|
|
28147
|
+
slashCommandPalette ? React.createElement(SlashCommandPalette, { palette: slashCommandPalette }) : null,
|
|
28148
|
+
React.createElement(InputFrame, {
|
|
28149
|
+
borderColor: shortcutMode ? "cyan" : "blue",
|
|
28150
|
+
cursorColor: "cyan",
|
|
28151
|
+
value: promptInput,
|
|
28152
|
+
placeholder,
|
|
28153
|
+
marginTop: 0
|
|
28154
|
+
}),
|
|
28155
|
+
React.createElement(CommandGuide, { hint, color: shortcutMode ? "cyan" : "gray", error: state.promptError }),
|
|
28156
|
+
hasOverlay ? null : React.createElement(SessionMetaBox, { state, version, marginTop: 2 }),
|
|
27227
28157
|
React.createElement(
|
|
27228
28158
|
Box,
|
|
27229
|
-
{
|
|
27230
|
-
|
|
27231
|
-
),
|
|
27232
|
-
state.promptError ? React.createElement(Box, { alignSelf: "center", width: promptPanelWidth(), marginTop: 1 }, React.createElement(Text, { color: "yellow" }, state.promptError)) : null,
|
|
27233
|
-
React.createElement(Box, { flexGrow: 1 })
|
|
28159
|
+
{ flexGrow: 1 }
|
|
28160
|
+
)
|
|
27234
28161
|
);
|
|
27235
28162
|
}
|
|
27236
28163
|
function SessionMetaBox({ state, version, marginTop = 1 }) {
|
|
@@ -27240,51 +28167,20 @@ function SessionMetaBox({ state, version, marginTop = 1 }) {
|
|
|
27240
28167
|
const model = shorten(state.selection?.model ?? state.status.model ?? "model", compact ? Math.max(18, width - 14) : 30);
|
|
27241
28168
|
const workspace = shorten(state.status.cwd ?? process.cwd(), compact ? Math.max(18, width - 18) : 46);
|
|
27242
28169
|
const rows = compact ? [
|
|
27243
|
-
|
|
27244
|
-
|
|
27245
|
-
|
|
27246
|
-
|
|
27247
|
-
React.createElement(MetaDivider),
|
|
27248
|
-
React.createElement(MetaItem, { label: "perm", value: state.permissionPreset, color: "yellow" })
|
|
27249
|
-
),
|
|
27250
|
-
React.createElement(Box, { key: "model" }, React.createElement(MetaItem, { label: "model", value: model, color: "cyan" })),
|
|
27251
|
-
React.createElement(Box, { key: "workspace" }, React.createElement(MetaItem, { label: "workspace", value: workspace, color: "white" })),
|
|
27252
|
-
version ? React.createElement(Box, { key: "version" }, React.createElement(MetaItem, { label: "version", value: `v${version}`, color: "gray" })) : null
|
|
28170
|
+
`agent ${agent} \xB7 perm ${state.permissionPreset}`,
|
|
28171
|
+
`model ${model}`,
|
|
28172
|
+
`workspace ${workspace}`,
|
|
28173
|
+
version ? `version v${version}` : void 0
|
|
27253
28174
|
].filter(Boolean) : [
|
|
27254
|
-
|
|
27255
|
-
|
|
27256
|
-
{ key: "mode" },
|
|
27257
|
-
React.createElement(MetaItem, { label: "agent", value: agent, color: "green" }),
|
|
27258
|
-
React.createElement(MetaDivider),
|
|
27259
|
-
React.createElement(MetaItem, { label: "model", value: model, color: "cyan" }),
|
|
27260
|
-
React.createElement(MetaDivider),
|
|
27261
|
-
React.createElement(MetaItem, { label: "perm", value: state.permissionPreset, color: "yellow" })
|
|
27262
|
-
),
|
|
27263
|
-
React.createElement(
|
|
27264
|
-
Box,
|
|
27265
|
-
{ key: "workspace" },
|
|
27266
|
-
React.createElement(MetaItem, { label: "workspace", value: workspace, color: "white" }),
|
|
27267
|
-
version ? React.createElement(MetaDivider) : null,
|
|
27268
|
-
version ? React.createElement(MetaItem, { label: "version", value: `v${version}`, color: "gray" }) : null
|
|
27269
|
-
)
|
|
28175
|
+
`agent ${agent} \xB7 model ${model} \xB7 perm ${state.permissionPreset}`,
|
|
28176
|
+
`workspace ${workspace}${version ? ` \xB7 version v${version}` : ""}`
|
|
27270
28177
|
];
|
|
27271
28178
|
return React.createElement(
|
|
27272
28179
|
Box,
|
|
27273
|
-
{ alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "
|
|
27274
|
-
...rows
|
|
27275
|
-
);
|
|
27276
|
-
}
|
|
27277
|
-
function MetaItem({ label, value, color }) {
|
|
27278
|
-
return React.createElement(
|
|
27279
|
-
Text,
|
|
27280
|
-
null,
|
|
27281
|
-
React.createElement(Text, { color: "gray" }, `${label} `),
|
|
27282
|
-
React.createElement(Text, { color }, value)
|
|
28180
|
+
{ alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "#334155", paddingX: 1, marginTop },
|
|
28181
|
+
...rows.map((line, index) => React.createElement(SurfaceLine, { key: index, text: line ?? "", width: width - 4, backgroundColor: SURFACE.status, color: "white" }))
|
|
27283
28182
|
);
|
|
27284
28183
|
}
|
|
27285
|
-
function MetaDivider() {
|
|
27286
|
-
return React.createElement(Text, { color: "gray" }, " \xB7 ");
|
|
27287
|
-
}
|
|
27288
28184
|
function DemianWordmark() {
|
|
27289
28185
|
if (terminalWidth() < 58) {
|
|
27290
28186
|
return React.createElement(Box, { alignSelf: "center" }, React.createElement(Text, { color: "gray", bold: true }, "DEMIAN"));
|
|
@@ -27300,12 +28196,14 @@ function DemianWordmark() {
|
|
|
27300
28196
|
function LoadingView({ state }) {
|
|
27301
28197
|
const title = state.inputMode === "starting" ? "Demian runtime" : "Preparing session";
|
|
27302
28198
|
const message = state.activity || (state.inputMode === "starting" ? "Loading configuration" : "Starting session");
|
|
28199
|
+
const width = statusSurfaceWidth();
|
|
28200
|
+
const contentWidth = Math.max(24, width - 4);
|
|
27303
28201
|
return React.createElement(
|
|
27304
28202
|
Box,
|
|
27305
|
-
{ flexDirection: "column", marginTop: 1, borderStyle: "double", borderColor: "cyan", paddingX: 1, paddingY: 1 },
|
|
27306
|
-
React.createElement(
|
|
27307
|
-
React.createElement(
|
|
27308
|
-
React.createElement(
|
|
28203
|
+
{ alignSelf: "center", width, flexDirection: "column", marginTop: 1, borderStyle: "double", borderColor: "cyan", paddingX: 1, paddingY: 1 },
|
|
28204
|
+
React.createElement(SurfaceLine, { text: title, width: contentWidth, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
|
|
28205
|
+
React.createElement(SurfaceLine, { text: message, width: contentWidth, backgroundColor: SURFACE.status, color: "white" }),
|
|
28206
|
+
React.createElement(SurfaceLine, { text: "Loading providers, tools, workspace state, and permissions.", width: contentWidth, backgroundColor: SURFACE.status, color: "gray" })
|
|
27309
28207
|
);
|
|
27310
28208
|
}
|
|
27311
28209
|
function contextEfficiencySummary(state) {
|
|
@@ -27361,6 +28259,7 @@ function tuiMode(state) {
|
|
|
27361
28259
|
if (state.done) return { label: "done", color: "green" };
|
|
27362
28260
|
if (state.permission) return { label: "approval", color: "yellow" };
|
|
27363
28261
|
if (state.inputMode === "starting") return { label: "booting", color: "cyan" };
|
|
28262
|
+
if (state.inputMode === "session") return { label: "sessions", color: "magenta" };
|
|
27364
28263
|
if (state.inputMode === "running") return { label: "running", color: "cyan" };
|
|
27365
28264
|
if (state.inputMode === "provider" || state.inputMode === "agent" || state.inputMode === "model" || state.inputMode === "permissionPreset") return { label: "settings", color: "magenta" };
|
|
27366
28265
|
if (state.inputMode === "prompt") return { label: "ready", color: "green" };
|
|
@@ -27369,51 +28268,71 @@ function tuiMode(state) {
|
|
|
27369
28268
|
function TranscriptView({ state }) {
|
|
27370
28269
|
const blocks = state.blocks.slice(-12);
|
|
27371
28270
|
const streaming = !state.streamingFinalized && state.streamingText ? { kind: "assistant", title: "Assistant streaming", lines: streamingLines(state.streamingText) } : void 0;
|
|
28271
|
+
const width = transcriptPanelWidth();
|
|
28272
|
+
const contentWidth = Math.max(24, width - 2);
|
|
27372
28273
|
return React.createElement(
|
|
27373
28274
|
Box,
|
|
27374
|
-
{
|
|
27375
|
-
...blocks.map((block) => React.createElement(BlockView, { key: block.id
|
|
27376
|
-
streaming ? React.createElement(BlockView, { key: "streaming", block: streaming }) : null
|
|
28275
|
+
{ alignSelf: "center", width, flexDirection: "column", marginTop: 1 },
|
|
28276
|
+
...blocks.map((block, index) => React.createElement(BlockView, { key: `${block.id}-${index}`, block, width: contentWidth })),
|
|
28277
|
+
streaming ? React.createElement(BlockView, { key: "streaming", block: streaming, width: contentWidth }) : null
|
|
27377
28278
|
);
|
|
27378
28279
|
}
|
|
27379
|
-
function BlockView({ block }) {
|
|
27380
|
-
if (block.kind === "tool") return React.createElement(ToolBlockView, { block });
|
|
27381
|
-
if (block.kind === "goal-work") return React.createElement(GoalWorkBlockView, { block });
|
|
27382
|
-
if (block.kind === "cowork") return React.createElement(CoworkBlockView, { block });
|
|
28280
|
+
function BlockView({ block, width }) {
|
|
28281
|
+
if (block.kind === "tool") return React.createElement(ToolBlockView, { block, width });
|
|
28282
|
+
if (block.kind === "goal-work") return React.createElement(GoalWorkBlockView, { block, width });
|
|
28283
|
+
if (block.kind === "cowork") return React.createElement(CoworkBlockView, { block, width });
|
|
28284
|
+
if (block.kind === "user") return React.createElement(UserBlockView, { block, width });
|
|
27383
28285
|
const color = block.kind === "user" ? "green" : block.kind === "assistant" ? "white" : block.kind === "warning" ? "yellow" : "magenta";
|
|
28286
|
+
const lines = wrapBlockLines(block.lines, width, 80);
|
|
27384
28287
|
return React.createElement(
|
|
27385
28288
|
Box,
|
|
27386
28289
|
{ flexDirection: "column", marginBottom: 1 },
|
|
27387
|
-
React.createElement(Text, { color, bold: true }, block.title),
|
|
27388
|
-
...
|
|
28290
|
+
React.createElement(Text, { color, bold: true }, fitToWidth(block.title, width)),
|
|
28291
|
+
...lines.map((line, index) => React.createElement(Text, { key: index }, line || " "))
|
|
27389
28292
|
);
|
|
27390
28293
|
}
|
|
27391
|
-
function
|
|
28294
|
+
function UserBlockView({ block, width }) {
|
|
28295
|
+
const lines = normalizedBlockLines(block.lines).slice(0, 80);
|
|
28296
|
+
const bubbleWidth = userMessageBubbleWidth(lines, width);
|
|
28297
|
+
const contentWidth = Math.max(8, bubbleWidth - 4);
|
|
28298
|
+
const wrappedLines = wrapBlockLines(lines, contentWidth, 80);
|
|
28299
|
+
return React.createElement(
|
|
28300
|
+
Box,
|
|
28301
|
+
{ alignSelf: "flex-end", width: bubbleWidth, flexDirection: "column", marginBottom: 1, marginLeft: 2 },
|
|
28302
|
+
React.createElement(
|
|
28303
|
+
Box,
|
|
28304
|
+
{ flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1 },
|
|
28305
|
+
React.createElement(
|
|
28306
|
+
Box,
|
|
28307
|
+
{ justifyContent: "flex-end" },
|
|
28308
|
+
React.createElement(Text, { color: "blue", bold: true }, "You")
|
|
28309
|
+
),
|
|
28310
|
+
...wrappedLines.map((line, index) => React.createElement(Text, { key: index, color: "white" }, line || " "))
|
|
28311
|
+
)
|
|
28312
|
+
);
|
|
28313
|
+
}
|
|
28314
|
+
function CoworkBlockView({ block, width }) {
|
|
27392
28315
|
const group = block.cowork;
|
|
27393
28316
|
const warning = group?.status && group.status !== "running" && group.status !== "completed";
|
|
27394
28317
|
const color = warning ? "yellow" : group?.status === "running" ? "cyan" : "gray";
|
|
28318
|
+
const contentWidth = Math.max(16, width - 4);
|
|
27395
28319
|
return React.createElement(
|
|
27396
28320
|
Box,
|
|
27397
|
-
{ flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
|
|
27398
|
-
React.createElement(
|
|
27399
|
-
|
|
27400
|
-
null,
|
|
27401
|
-
React.createElement(Text, { color, bold: true }, "[cowork] "),
|
|
27402
|
-
React.createElement(Text, { color: "white", bold: true }, block.title),
|
|
27403
|
-
block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
|
|
27404
|
-
),
|
|
27405
|
-
React.createElement(CoworkDetailsView, { block })
|
|
28321
|
+
{ width, flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
|
|
28322
|
+
React.createElement(SurfaceLine, { text: `[cowork] ${block.title}${block.meta ? ` \xB7 ${block.meta}` : ""}`, width: contentWidth, backgroundColor: SURFACE.status, color, bold: true }),
|
|
28323
|
+
React.createElement(CoworkDetailsView, { block, width: contentWidth })
|
|
27406
28324
|
);
|
|
27407
28325
|
}
|
|
27408
|
-
function CoworkDetailsView({ block }) {
|
|
28326
|
+
function CoworkDetailsView({ block, width }) {
|
|
27409
28327
|
const group = block.cowork;
|
|
27410
|
-
if (!group) return React.createElement(GoalFallbackLines, { lines: block.lines });
|
|
28328
|
+
if (!group) return React.createElement(GoalFallbackLines, { lines: block.lines, width });
|
|
27411
28329
|
const expanded = block.expanded !== false;
|
|
27412
28330
|
const lines = expanded ? block.lines : block.lines.filter((line) => line.startsWith("Status:") || line.startsWith("Members:") || line.startsWith("Summary:")).slice(0, 4);
|
|
28331
|
+
const wrappedLines = wrapBlockLines(lines, width, 100);
|
|
27413
28332
|
return React.createElement(
|
|
27414
28333
|
Box,
|
|
27415
28334
|
{ flexDirection: "column", marginTop: 1 },
|
|
27416
|
-
...
|
|
28335
|
+
...wrappedLines.map((line, index) => React.createElement(Text, { key: index, color: coworkLineColor(line) }, line || " "))
|
|
27417
28336
|
);
|
|
27418
28337
|
}
|
|
27419
28338
|
function coworkLineColor(line) {
|
|
@@ -27421,22 +28340,17 @@ function coworkLineColor(line) {
|
|
|
27421
28340
|
if (line.startsWith(" ")) return "gray";
|
|
27422
28341
|
return void 0;
|
|
27423
28342
|
}
|
|
27424
|
-
function GoalWorkBlockView({ block }) {
|
|
28343
|
+
function GoalWorkBlockView({ block, width }) {
|
|
27425
28344
|
const work = block.goalWork;
|
|
28345
|
+
const contentWidth = Math.max(16, width - 4);
|
|
27426
28346
|
return React.createElement(
|
|
27427
28347
|
Box,
|
|
27428
|
-
{ flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 },
|
|
27429
|
-
React.createElement(
|
|
27430
|
-
|
|
27431
|
-
null,
|
|
27432
|
-
React.createElement(Text, { color: "cyan", bold: true }, "[goal] "),
|
|
27433
|
-
React.createElement(Text, { color: "white", bold: true }, block.title),
|
|
27434
|
-
block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
|
|
27435
|
-
),
|
|
27436
|
-
work ? React.createElement(GoalWorkDetailsView, { work }) : React.createElement(GoalFallbackLines, { lines: block.lines })
|
|
28348
|
+
{ width, flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 },
|
|
28349
|
+
React.createElement(SurfaceLine, { text: `[goal] ${block.title}${block.meta ? ` \xB7 ${block.meta}` : ""}`, width: contentWidth, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
|
|
28350
|
+
work ? React.createElement(GoalWorkDetailsView, { work, width: contentWidth }) : React.createElement(GoalFallbackLines, { lines: block.lines, width: contentWidth })
|
|
27437
28351
|
);
|
|
27438
28352
|
}
|
|
27439
|
-
function GoalWorkDetailsView({ work }) {
|
|
28353
|
+
function GoalWorkDetailsView({ work, width }) {
|
|
27440
28354
|
const status = work.completedAt ? "completed" : "running";
|
|
27441
28355
|
const diffLines = work.diff && work.diff.files.length > 0 ? [
|
|
27442
28356
|
`Changes: ${work.diff.files.length} ${work.diff.files.length === 1 ? "file" : "files"} +${work.diff.addedLines} -${work.diff.removedLines}`,
|
|
@@ -27445,33 +28359,34 @@ function GoalWorkDetailsView({ work }) {
|
|
|
27445
28359
|
return React.createElement(
|
|
27446
28360
|
Box,
|
|
27447
28361
|
{ flexDirection: "column", marginTop: 1 },
|
|
27448
|
-
React.createElement(Text, { color: "gray" },
|
|
27449
|
-
React.createElement(Text, { color: "gray" },
|
|
27450
|
-
...diffLines.map((line, index) => React.createElement(Text, { key: `diff-${index}`, color: line.startsWith(" ") ? "gray" : "white" }, line)),
|
|
28362
|
+
...wrapBlockLines([`Goal: ${work.goalId}`, `Status: ${status}`], width, 4).map((line, index) => React.createElement(Text, { key: `meta-${index}`, color: "gray" }, line)),
|
|
28363
|
+
...wrapBlockLines(diffLines, width, 20).map((line, index) => React.createElement(Text, { key: `diff-${index}`, color: line.startsWith(" ") ? "gray" : "white" }, line)),
|
|
27451
28364
|
...work.narrations.flatMap((narration, index) => [
|
|
27452
28365
|
React.createElement(
|
|
27453
28366
|
Box,
|
|
27454
28367
|
{ key: `narration-${narration.narrationId}`, flexDirection: "column", marginTop: index === 0 && diffLines.length === 0 ? 1 : 1 },
|
|
27455
|
-
...narration.lines
|
|
27456
|
-
narration.tools.length > 0 ? React.createElement(GoalToolGroupView, { key: `${narration.narrationId}-tools`, tools: narration.tools }) : null
|
|
28368
|
+
...wrapBlockLines(narration.lines, width, 40).map((line, lineIndex) => React.createElement(Text, { key: lineIndex, color: "white" }, line || " ")),
|
|
28369
|
+
narration.tools.length > 0 ? React.createElement(GoalToolGroupView, { key: `${narration.narrationId}-tools`, tools: narration.tools, width }) : null
|
|
27457
28370
|
)
|
|
27458
28371
|
]),
|
|
27459
|
-
work.orphanTools.length > 0 ? React.createElement(GoalToolGroupView, { tools: work.orphanTools, title: "Tools" }) : null
|
|
28372
|
+
work.orphanTools.length > 0 ? React.createElement(GoalToolGroupView, { tools: work.orphanTools, title: "Tools", width }) : null
|
|
27460
28373
|
);
|
|
27461
28374
|
}
|
|
27462
|
-
function GoalToolGroupView({ tools, title }) {
|
|
28375
|
+
function GoalToolGroupView({ tools, title, width }) {
|
|
28376
|
+
const nestedWidth = Math.max(24, width - 2);
|
|
27463
28377
|
return React.createElement(
|
|
27464
28378
|
Box,
|
|
27465
28379
|
{ flexDirection: "column", marginTop: 1, marginLeft: 2 },
|
|
27466
28380
|
title ? React.createElement(Text, { color: "gray" }, title) : null,
|
|
27467
|
-
...tools.map((tool) => React.createElement(ToolBlockView, { key: tool.callId, block: goalToolAsBlock(tool) }))
|
|
28381
|
+
...tools.map((tool) => React.createElement(ToolBlockView, { key: tool.callId, block: goalToolAsBlock(tool), width: nestedWidth }))
|
|
27468
28382
|
);
|
|
27469
28383
|
}
|
|
27470
|
-
function GoalFallbackLines({ lines }) {
|
|
28384
|
+
function GoalFallbackLines({ lines, width }) {
|
|
28385
|
+
const wrappedLines = wrapBlockLines(lines, width, 120);
|
|
27471
28386
|
return React.createElement(
|
|
27472
28387
|
Box,
|
|
27473
28388
|
{ flexDirection: "column", marginTop: 1 },
|
|
27474
|
-
...
|
|
28389
|
+
...wrappedLines.map((line, index) => React.createElement(Text, { key: index, color: line.startsWith(" ") || line.startsWith(" ") ? "gray" : void 0 }, line || " "))
|
|
27475
28390
|
);
|
|
27476
28391
|
}
|
|
27477
28392
|
function goalToolAsBlock(tool) {
|
|
@@ -27485,38 +28400,33 @@ function goalToolAsBlock(tool) {
|
|
|
27485
28400
|
expanded: false
|
|
27486
28401
|
};
|
|
27487
28402
|
}
|
|
27488
|
-
function ToolBlockView({ block }) {
|
|
28403
|
+
function ToolBlockView({ block, width }) {
|
|
27489
28404
|
const status = block.toolStatus ?? "requested";
|
|
27490
28405
|
const color = status === "completed" ? "green" : status === "failed" || status === "denied" ? "red" : status === "permission" ? "yellow" : status === "running" ? "cyan" : "magenta";
|
|
27491
28406
|
const badge = status === "completed" ? "ok" : status === "failed" || status === "denied" ? "!" : status === "permission" ? "?" : status === "running" ? "..." : ">";
|
|
28407
|
+
const contentWidth = Math.max(16, width - 4);
|
|
28408
|
+
const header = `[${badge}] ${block.expanded ? "[-]" : "[+]"} ${block.title}${block.meta ? ` \xB7 ${block.meta}` : ""}`;
|
|
27492
28409
|
return React.createElement(
|
|
27493
28410
|
Box,
|
|
27494
|
-
{ flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
|
|
27495
|
-
React.createElement(
|
|
27496
|
-
|
|
27497
|
-
null,
|
|
27498
|
-
React.createElement(Text, { color, bold: true }, `[${badge}] `),
|
|
27499
|
-
React.createElement(Text, { color: "gray" }, block.expanded ? "[-] " : "[+] "),
|
|
27500
|
-
React.createElement(Text, { color: "white", bold: true }, block.title),
|
|
27501
|
-
block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
|
|
27502
|
-
),
|
|
27503
|
-
block.expanded ? React.createElement(ToolDetailsView, { details: block.toolDetails, fallbackLines: block.lines }) : null
|
|
28411
|
+
{ width, flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
|
|
28412
|
+
React.createElement(SurfaceLine, { text: header, width: contentWidth, backgroundColor: SURFACE.status, color, bold: true }),
|
|
28413
|
+
block.expanded ? React.createElement(ToolDetailsView, { details: block.toolDetails, fallbackLines: block.lines, width: contentWidth }) : null
|
|
27504
28414
|
);
|
|
27505
28415
|
}
|
|
27506
|
-
function ToolDetailsView({ details, fallbackLines }) {
|
|
28416
|
+
function ToolDetailsView({ details, fallbackLines, width }) {
|
|
27507
28417
|
if (!details) {
|
|
27508
28418
|
return React.createElement(
|
|
27509
28419
|
Box,
|
|
27510
28420
|
{ flexDirection: "column", marginTop: 1 },
|
|
27511
|
-
...fallbackLines
|
|
28421
|
+
...wrapBlockLines(fallbackLines, width, 80).map((line, index) => React.createElement(Text, { key: index, color: index === 0 ? "gray" : void 0 }, line || " "))
|
|
27512
28422
|
);
|
|
27513
28423
|
}
|
|
27514
28424
|
return React.createElement(
|
|
27515
28425
|
Box,
|
|
27516
28426
|
{ flexDirection: "column", marginTop: 1 },
|
|
27517
|
-
React.createElement(Text, { color: "white" },
|
|
28427
|
+
...wrapBlockLines([details.summary], width, 4).map((line, index) => React.createElement(Text, { key: `summary-${index}`, color: "white" }, line || " ")),
|
|
27518
28428
|
details.chips.length > 0 ? React.createElement(ToolChipLine, { chips: details.chips }) : null,
|
|
27519
|
-
...details.sections.slice(0, 8).map((section, index) => React.createElement(ToolSectionView, { key: index, section }))
|
|
28429
|
+
...details.sections.slice(0, 8).map((section, index) => React.createElement(ToolSectionView, { key: index, section, width }))
|
|
27520
28430
|
);
|
|
27521
28431
|
}
|
|
27522
28432
|
function ToolChipLine({ chips }) {
|
|
@@ -27529,26 +28439,36 @@ function ToolChipLine({ chips }) {
|
|
|
27529
28439
|
].filter(Boolean))
|
|
27530
28440
|
);
|
|
27531
28441
|
}
|
|
27532
|
-
function ToolSectionView({ section }) {
|
|
28442
|
+
function ToolSectionView({ section, width }) {
|
|
27533
28443
|
const rows = section.rows ?? [];
|
|
27534
28444
|
const lines = section.lines ?? [];
|
|
28445
|
+
const bodyWidth = Math.max(8, width - 2);
|
|
27535
28446
|
const body = rows.length > 0 || lines.length > 0 ? [
|
|
27536
|
-
...rows.map((row, index) => React.createElement(ToolRowView, { key: `row-${index}`, row })),
|
|
27537
|
-
...lines.
|
|
27538
|
-
] : section.emptyText ? [React.createElement(Text, { key:
|
|
28447
|
+
...rows.map((row, index) => React.createElement(ToolRowView, { key: `row-${index}`, row, width: bodyWidth })),
|
|
28448
|
+
...wrapBlockLines(lines.map((line) => ` ${line || " "}`), bodyWidth, 40).map((line, index) => React.createElement(Text, { key: `line-${index}`, color: section.code ? "gray" : "white" }, line))
|
|
28449
|
+
] : section.emptyText ? wrapBlockLines([` ${section.emptyText}`], bodyWidth, 2).map((line, index) => React.createElement(Text, { key: `empty-${index}`, color: "gray" }, line)) : [];
|
|
27539
28450
|
return React.createElement(
|
|
27540
28451
|
Box,
|
|
27541
28452
|
{ flexDirection: "column", marginTop: 1 },
|
|
27542
|
-
React.createElement(Text, { color: toneColor(section.tone) ?? "cyan", bold: true }, section.title),
|
|
28453
|
+
React.createElement(Text, { color: toneColor(section.tone) ?? "cyan", bold: true }, fitToWidth(section.title, width)),
|
|
27543
28454
|
...body
|
|
27544
28455
|
);
|
|
27545
28456
|
}
|
|
27546
|
-
function ToolRowView({ row }) {
|
|
28457
|
+
function ToolRowView({ row, width }) {
|
|
28458
|
+
const label = ` ${padLabel(row.label)} `;
|
|
28459
|
+
const valueWidth = Math.max(8, width - stringWidth(label));
|
|
28460
|
+
const valueLines = wrapBlockLines([row.value], valueWidth, 6);
|
|
27547
28461
|
return React.createElement(
|
|
27548
28462
|
Box,
|
|
27549
|
-
|
|
27550
|
-
|
|
27551
|
-
|
|
28463
|
+
{ flexDirection: "column" },
|
|
28464
|
+
...valueLines.map(
|
|
28465
|
+
(line, index) => React.createElement(
|
|
28466
|
+
Box,
|
|
28467
|
+
{ key: index },
|
|
28468
|
+
React.createElement(Text, { color: "gray" }, index === 0 ? label : padToWidth("", stringWidth(label))),
|
|
28469
|
+
React.createElement(Text, { color: toneColor(row.tone) ?? (row.code ? "cyan" : "white") }, line || " ")
|
|
28470
|
+
)
|
|
28471
|
+
)
|
|
27552
28472
|
);
|
|
27553
28473
|
}
|
|
27554
28474
|
function padLabel(value) {
|
|
@@ -27562,22 +28482,33 @@ function toneColor(tone) {
|
|
|
27562
28482
|
if (tone === "neutral") return "gray";
|
|
27563
28483
|
return void 0;
|
|
27564
28484
|
}
|
|
28485
|
+
function BottomStatusStack({ state, now: now2 }) {
|
|
28486
|
+
if (!shouldShowBottomStatusStack(state)) return null;
|
|
28487
|
+
return React.createElement(
|
|
28488
|
+
Box,
|
|
28489
|
+
{ alignSelf: "center", width: statusSurfaceWidth(), flexDirection: "column", marginBottom: 1 },
|
|
28490
|
+
React.createElement(GoalIsland, { state }),
|
|
28491
|
+
React.createElement(DiffAccordion, { state }),
|
|
28492
|
+
React.createElement(WorkPlanPanel, { state, now: now2 }),
|
|
28493
|
+
React.createElement(ActivityBar, { state })
|
|
28494
|
+
);
|
|
28495
|
+
}
|
|
28496
|
+
function shouldShowBottomStatusStack(state) {
|
|
28497
|
+
return Boolean(state.goal || state.turnDiff && state.turnDiff.files.length > 0 || state.workPlan || state.inputMode === "running" || shouldShowActivity(state));
|
|
28498
|
+
}
|
|
27565
28499
|
function ActivityBar({ state }) {
|
|
27566
28500
|
if (!shouldShowActivity(state)) return null;
|
|
27567
28501
|
const warning = state.warnings.at(-1);
|
|
27568
28502
|
const context = contextEfficiencySummary(state);
|
|
27569
28503
|
const color = state.done ? "green" : state.inputMode === "running" ? "cyan" : "blue";
|
|
28504
|
+
const width = statusSurfaceWidth();
|
|
28505
|
+
const contentWidth = Math.max(24, width - 4);
|
|
28506
|
+
const summary = `Activity ${state.activity}${context ? ` | ${context}` : ""}`;
|
|
27570
28507
|
return React.createElement(
|
|
27571
28508
|
Box,
|
|
27572
|
-
{ borderStyle: "round", borderColor: color, paddingX: 1, flexDirection: "column" },
|
|
27573
|
-
React.createElement(
|
|
27574
|
-
|
|
27575
|
-
null,
|
|
27576
|
-
React.createElement(Text, { color, bold: true }, "Activity "),
|
|
27577
|
-
React.createElement(Text, { color: state.done ? "green" : "white" }, state.activity),
|
|
27578
|
-
context ? React.createElement(Text, { color: "gray" }, ` | ${context}`) : null
|
|
27579
|
-
),
|
|
27580
|
-
warning ? React.createElement(Text, { color: "yellow" }, ` \xB7 ${warning}`) : null
|
|
28509
|
+
{ alignSelf: "center", width, borderStyle: "round", borderColor: color, paddingX: 1, flexDirection: "column" },
|
|
28510
|
+
React.createElement(SurfaceLine, { text: summary, width: contentWidth, backgroundColor: SURFACE.status, color: state.done ? "green" : color, bold: true }),
|
|
28511
|
+
warning ? React.createElement(SurfaceLine, { text: `! ${warning}`, width: contentWidth, backgroundColor: SURFACE.status, color: "yellow" }) : null
|
|
27581
28512
|
);
|
|
27582
28513
|
}
|
|
27583
28514
|
function shouldShowActivity(state) {
|
|
@@ -27589,18 +28520,15 @@ function GoalIsland({ state }) {
|
|
|
27589
28520
|
const color = goalIslandColor(goal.status);
|
|
27590
28521
|
const progress = goal.maxIterations > 0 ? `${goal.iteration}/${goal.maxIterations}` : "active";
|
|
27591
28522
|
const decision = goal.decision ? ` | ${goalDecisionLabel(goal.decision)}` : "";
|
|
27592
|
-
const
|
|
28523
|
+
const width = statusSurfaceWidth();
|
|
28524
|
+
const contentWidth = Math.max(24, width - 6);
|
|
28525
|
+
const reason = goal.reason ? compactText(goal.reason, contentWidth) : void 0;
|
|
28526
|
+
const titleLine = `Goal ${goal.title ?? goal.objective} | ${goalStatusLabel(goal.status)} | iter ${progress}${decision}`;
|
|
27593
28527
|
return React.createElement(
|
|
27594
28528
|
Box,
|
|
27595
|
-
{ alignSelf: "center", borderStyle: "round", borderColor: color, paddingX: 2, marginTop: 1, flexDirection: "column" },
|
|
27596
|
-
React.createElement(
|
|
27597
|
-
|
|
27598
|
-
null,
|
|
27599
|
-
React.createElement(Text, { color, bold: true }, "Goal "),
|
|
27600
|
-
React.createElement(Text, { color: "white", bold: true }, compactText(goal.title ?? goal.objective, 60)),
|
|
27601
|
-
React.createElement(Text, { color: "gray" }, ` | ${goalStatusLabel(goal.status)} | iter ${progress}${decision}`)
|
|
27602
|
-
),
|
|
27603
|
-
goal.title ? React.createElement(Text, { color: "gray" }, compactText(goal.objective, 88)) : null,
|
|
28529
|
+
{ alignSelf: "center", width, borderStyle: "round", borderColor: color, paddingX: 2, marginTop: 1, flexDirection: "column" },
|
|
28530
|
+
React.createElement(SurfaceLine, { text: titleLine, width: contentWidth, backgroundColor: SURFACE.status, color, bold: true }),
|
|
28531
|
+
goal.title ? React.createElement(Text, { color: "gray" }, fitToWidth(goal.objective, contentWidth)) : null,
|
|
27604
28532
|
reason ? React.createElement(Text, { color: "gray" }, reason) : null
|
|
27605
28533
|
);
|
|
27606
28534
|
}
|
|
@@ -27630,57 +28558,43 @@ function DiffAccordion({ state }) {
|
|
|
27630
28558
|
const indicator = state.diffExpanded ? "[-]" : "[+]";
|
|
27631
28559
|
const visibleFiles = diff.files.slice(0, 8);
|
|
27632
28560
|
const remaining = diff.files.length - visibleFiles.length;
|
|
28561
|
+
const width = statusSurfaceWidth();
|
|
28562
|
+
const contentWidth = Math.max(24, width - 4);
|
|
27633
28563
|
return React.createElement(
|
|
27634
28564
|
Box,
|
|
27635
|
-
{ flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1 },
|
|
27636
|
-
React.createElement(
|
|
27637
|
-
Box,
|
|
27638
|
-
null,
|
|
27639
|
-
React.createElement(Text, { color: "cyan", bold: true }, `${indicator} Diff `),
|
|
27640
|
-
React.createElement(Text, { color: "white" }, summary),
|
|
27641
|
-
React.createElement(Text, { color: "gray" }, " | esc then d toggle")
|
|
27642
|
-
),
|
|
28565
|
+
{ alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1 },
|
|
28566
|
+
React.createElement(SurfaceLine, { text: `${indicator} Diff ${summary} | esc then d toggle`, width: contentWidth, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
|
|
27643
28567
|
state.diffExpanded ? React.createElement(
|
|
27644
28568
|
Box,
|
|
27645
28569
|
{ flexDirection: "column", marginTop: 1 },
|
|
27646
|
-
...visibleFiles.map((file) => React.createElement(DiffFileCard, { key: file.path, file })),
|
|
28570
|
+
...visibleFiles.map((file) => React.createElement(DiffFileCard, { key: file.path, file, width: contentWidth })),
|
|
27647
28571
|
remaining > 0 ? React.createElement(Text, { key: "remaining", color: "gray" }, `... ${remaining} more files`) : null
|
|
27648
28572
|
) : null
|
|
27649
28573
|
);
|
|
27650
28574
|
}
|
|
27651
|
-
function DiffFileCard({ file }) {
|
|
28575
|
+
function DiffFileCard({ file, width }) {
|
|
27652
28576
|
const kind = file.kind === "add" ? "add" : file.kind === "delete" ? "delete" : "modified";
|
|
27653
28577
|
const kindColor = file.kind === "add" ? "green" : file.kind === "delete" ? "red" : "yellow";
|
|
28578
|
+
const line = `[file] ${file.path} \xB7 ${kind} +${file.addedLines} -${file.removedLines}`;
|
|
27654
28579
|
return React.createElement(
|
|
27655
28580
|
Box,
|
|
27656
|
-
{ borderStyle: "single", borderColor: "gray", paddingX: 1, marginBottom: 1 },
|
|
27657
|
-
React.createElement(Text, { color:
|
|
27658
|
-
React.createElement(Text, { color: "white", bold: true }, file.path),
|
|
27659
|
-
React.createElement(Text, { color: "gray" }, " \xB7 "),
|
|
27660
|
-
React.createElement(Text, { color: kindColor }, kind),
|
|
27661
|
-
React.createElement(Text, { color: "gray" }, " "),
|
|
27662
|
-
React.createElement(Text, { color: "green" }, `+${file.addedLines}`),
|
|
27663
|
-
React.createElement(Text, { color: "gray" }, " "),
|
|
27664
|
-
React.createElement(Text, { color: "red" }, `-${file.removedLines}`)
|
|
28581
|
+
{ width, borderStyle: "single", borderColor: "gray", paddingX: 1, marginBottom: 1 },
|
|
28582
|
+
React.createElement(Text, { color: kindColor, bold: true }, fitToWidth(line, Math.max(8, width - 4)))
|
|
27665
28583
|
);
|
|
27666
28584
|
}
|
|
27667
28585
|
function WorkPlanPanel({ state, now: now2 }) {
|
|
27668
28586
|
const plan = state.workPlan;
|
|
27669
28587
|
const steps = plan?.steps ?? [];
|
|
27670
28588
|
const expanded = state.workPlanExpanded || steps.some((step) => step.status === "blocked" || step.status === "failed");
|
|
28589
|
+
const width = statusSurfaceWidth();
|
|
28590
|
+
const contentWidth = Math.max(24, width - 4);
|
|
27671
28591
|
if (steps.length === 0) {
|
|
27672
28592
|
if (state.inputMode !== "running") return null;
|
|
27673
28593
|
return React.createElement(
|
|
27674
28594
|
Box,
|
|
27675
|
-
{ flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1 },
|
|
27676
|
-
React.createElement(
|
|
27677
|
-
|
|
27678
|
-
null,
|
|
27679
|
-
React.createElement(Text, { color: "cyan", bold: true }, `${expanded ? "[-]" : "[+]"} Plan `),
|
|
27680
|
-
React.createElement(Text, { color: "white" }, "Thinking"),
|
|
27681
|
-
React.createElement(Text, { color: "gray" }, " | esc then w toggle")
|
|
27682
|
-
),
|
|
27683
|
-
expanded ? React.createElement(Text, { color: "gray" }, "Demian is inspecting context and preparing a step-by-step plan.") : null
|
|
28595
|
+
{ alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1 },
|
|
28596
|
+
React.createElement(SurfaceLine, { text: `${expanded ? "[-]" : "[+]"} Plan Thinking | esc then w toggle`, width: contentWidth, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
|
|
28597
|
+
expanded ? React.createElement(Text, { color: "gray" }, fitToWidth("Demian is inspecting context and preparing a step-by-step plan.", contentWidth)) : null
|
|
27684
28598
|
);
|
|
27685
28599
|
}
|
|
27686
28600
|
const phase = workPlanPhase(state);
|
|
@@ -27693,57 +28607,63 @@ function WorkPlanPanel({ state, now: now2 }) {
|
|
|
27693
28607
|
const elapsed = plan ? planElapsed(plan, now2) : void 0;
|
|
27694
28608
|
return React.createElement(
|
|
27695
28609
|
Box,
|
|
27696
|
-
{ flexDirection: "column", borderStyle: "single", borderColor: phase.color, paddingX: 1 },
|
|
27697
|
-
React.createElement(
|
|
27698
|
-
|
|
27699
|
-
|
|
27700
|
-
|
|
27701
|
-
|
|
27702
|
-
|
|
27703
|
-
|
|
27704
|
-
blocked ? React.createElement(Text, { color: "red" }, ` | ${blocked} blocked`) : null,
|
|
27705
|
-
React.createElement(Text, { color: "gray" }, " | esc then w toggle")
|
|
27706
|
-
),
|
|
28610
|
+
{ alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: phase.color, paddingX: 1 },
|
|
28611
|
+
React.createElement(SurfaceLine, {
|
|
28612
|
+
text: `${expanded ? "[-]" : "[+]"} ${phase.label} ${plan?.title ?? "Main goal"}${elapsed ? ` (${elapsed})` : ""} | ${planProgressGraph(progress.resolved, progress.total)} ${progress.resolved}/${progress.total}${blocked ? ` | ${blocked} blocked` : ""} | esc then w toggle`,
|
|
28613
|
+
width: contentWidth,
|
|
28614
|
+
backgroundColor: SURFACE.status,
|
|
28615
|
+
color: phase.color,
|
|
28616
|
+
bold: true
|
|
28617
|
+
}),
|
|
27707
28618
|
expanded ? React.createElement(
|
|
27708
28619
|
Box,
|
|
27709
28620
|
{ flexDirection: "column", marginTop: 1 },
|
|
27710
|
-
plan?.summary ? React.createElement(WorkPlanInfoLine, { label: "Plan", value: plan.summary }) : null,
|
|
28621
|
+
plan?.summary ? React.createElement(WorkPlanInfoLine, { label: "Plan", value: plan.summary, width: contentWidth }) : null,
|
|
27711
28622
|
active ? React.createElement(WorkPlanInfoLine, {
|
|
27712
28623
|
label: "Now",
|
|
27713
28624
|
value: `${activeIndex + 1}/${steps.length} ${active.title}`,
|
|
27714
28625
|
meta: stepElapsed(active, now2),
|
|
27715
|
-
color: "yellow"
|
|
28626
|
+
color: "yellow",
|
|
28627
|
+
width: contentWidth
|
|
27716
28628
|
}) : null
|
|
27717
28629
|
) : null,
|
|
27718
28630
|
expanded ? React.createElement(
|
|
27719
28631
|
Box,
|
|
27720
28632
|
{ flexDirection: "column", marginTop: 1 },
|
|
27721
|
-
...visibleSteps.map((step) => React.createElement(WorkPlanStepLine, { key: step.id, step, active: step.id === active?.id, now: now2 }))
|
|
28633
|
+
...visibleSteps.map((step) => React.createElement(WorkPlanStepLine, { key: step.id, step, active: step.id === active?.id, now: now2, width: contentWidth }))
|
|
27722
28634
|
) : null,
|
|
27723
|
-
...expanded ? notes.map((note) => React.createElement(WorkPlanInfoLine, { key: note.id, label: "Update", value: note.message, color: noteColor(note.level) })) : []
|
|
28635
|
+
...expanded ? notes.map((note) => React.createElement(WorkPlanInfoLine, { key: note.id, label: "Update", value: note.message, color: noteColor(note.level), width: contentWidth })) : []
|
|
27724
28636
|
);
|
|
27725
28637
|
}
|
|
27726
|
-
function WorkPlanInfoLine({ label, value, meta, color = "gray" }) {
|
|
28638
|
+
function WorkPlanInfoLine({ label, value, meta, color = "gray", width }) {
|
|
28639
|
+
const prefix = `[${label}] `;
|
|
28640
|
+
const valueWidth = Math.max(8, width - stringWidth(prefix) - (meta ? stringWidth(` (${meta})`) : 0));
|
|
28641
|
+
const valueLines = wrapBlockLines([value], valueWidth, 4);
|
|
27727
28642
|
return React.createElement(
|
|
27728
28643
|
Box,
|
|
27729
|
-
|
|
27730
|
-
|
|
27731
|
-
|
|
27732
|
-
|
|
28644
|
+
{ flexDirection: "column" },
|
|
28645
|
+
...valueLines.map(
|
|
28646
|
+
(line, index) => React.createElement(
|
|
28647
|
+
Box,
|
|
28648
|
+
{ key: index },
|
|
28649
|
+
React.createElement(Text, { color: "gray" }, index === 0 ? prefix : padToWidth("", stringWidth(prefix))),
|
|
28650
|
+
React.createElement(Text, { color }, line),
|
|
28651
|
+
index === 0 && meta ? React.createElement(Text, { color: "gray" }, ` (${meta})`) : null
|
|
28652
|
+
)
|
|
28653
|
+
)
|
|
27733
28654
|
);
|
|
27734
28655
|
}
|
|
27735
|
-
function WorkPlanStepLine({ step, active, now: now2 }) {
|
|
28656
|
+
function WorkPlanStepLine({ step, active, now: now2, width }) {
|
|
27736
28657
|
const detail = [step.detail, step.agent ? `agent ${step.agent}` : void 0].filter(Boolean).join(" | ");
|
|
27737
28658
|
const elapsed = stepElapsed(step, now2);
|
|
28659
|
+
const title = `${stepGlyph(step.status)} ${step.title}${elapsed ? ` (${elapsed})` : ""}`;
|
|
27738
28660
|
return React.createElement(
|
|
27739
28661
|
Box,
|
|
27740
28662
|
{ flexDirection: "column" },
|
|
27741
|
-
|
|
27742
|
-
Text,
|
|
27743
|
-
{ color: stepColor(step.status), bold: active || step.status === "in_progress" },
|
|
27744
|
-
`${stepGlyph(step.status)} ${step.title}${elapsed ? ` (${elapsed})` : ""}`
|
|
28663
|
+
...wrapBlockLines([title], width, 3).map(
|
|
28664
|
+
(line, index) => React.createElement(Text, { key: `title-${index}`, color: stepColor(step.status), bold: active || step.status === "in_progress" }, line)
|
|
27745
28665
|
),
|
|
27746
|
-
detail ? React.createElement(Text, { color: "gray" },
|
|
28666
|
+
detail ? wrapBlockLines([` ${detail}`], width, 4).map((line, index) => React.createElement(Text, { key: `detail-${index}`, color: "gray" }, line)) : null
|
|
27747
28667
|
);
|
|
27748
28668
|
}
|
|
27749
28669
|
function workPlanPhase(state) {
|
|
@@ -27823,23 +28743,34 @@ function formatElapsed2(ms2) {
|
|
|
27823
28743
|
if (minutes > 0) return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
|
|
27824
28744
|
return `${seconds}s`;
|
|
27825
28745
|
}
|
|
27826
|
-
function
|
|
28746
|
+
function formatSessionAge(updatedAt) {
|
|
28747
|
+
if (!updatedAt || !Number.isFinite(updatedAt)) return "-";
|
|
28748
|
+
const seconds = Math.max(0, Math.floor((Date.now() - updatedAt) / 1e3));
|
|
28749
|
+
if (seconds < 60) return `${seconds}s ago`;
|
|
28750
|
+
const minutes = Math.floor(seconds / 60);
|
|
28751
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
28752
|
+
const hours = Math.floor(minutes / 60);
|
|
28753
|
+
if (hours < 48) return `${hours}h ago`;
|
|
28754
|
+
return `${Math.floor(hours / 24)}d ago`;
|
|
28755
|
+
}
|
|
28756
|
+
function InteractionPanel({ state, shortcutMode, promptInput, slashCommandPalette, commandPalette }) {
|
|
27827
28757
|
if (state.inputMode === "starting") return React.createElement(LoadingBar);
|
|
28758
|
+
if (state.inputMode === "session") return React.createElement(SessionSelector, { state });
|
|
27828
28759
|
if (state.permission) return React.createElement(PermissionBar, { state });
|
|
27829
28760
|
if (state.inputMode === "provider") return React.createElement(ProviderSelector, { state });
|
|
27830
28761
|
if (state.inputMode === "agent") return React.createElement(AgentSelector, { state });
|
|
27831
28762
|
if (state.inputMode === "permissionPreset") return React.createElement(PermissionPresetSelector, { state });
|
|
27832
28763
|
if (state.inputMode === "model") return React.createElement(ModelEditor, { state });
|
|
27833
|
-
if (state.inputMode === "running") return React.createElement(CommandBar, { state, shortcutMode });
|
|
27834
|
-
if (state.inputMode === "prompt") return React.createElement(PromptBar, { state, shortcutMode });
|
|
28764
|
+
if (state.inputMode === "running") return React.createElement(CommandBar, { state, shortcutMode, promptInput, slashCommandPalette, commandPalette });
|
|
28765
|
+
if (state.inputMode === "prompt") return React.createElement(PromptBar, { state, shortcutMode, promptInput, slashCommandPalette, commandPalette });
|
|
27835
28766
|
return React.createElement(PermissionBar, { state });
|
|
27836
28767
|
}
|
|
27837
28768
|
function LoadingBar() {
|
|
27838
28769
|
return React.createElement(
|
|
27839
28770
|
Box,
|
|
27840
28771
|
{ flexDirection: "column", borderStyle: "double", paddingX: 1 },
|
|
27841
|
-
React.createElement(
|
|
27842
|
-
React.createElement(
|
|
28772
|
+
React.createElement(SurfaceLine, { text: "loading", width: promptPanelWidth() - 4, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
|
|
28773
|
+
React.createElement(SurfaceLine, { text: "demian is preparing the session | type /exit after loading to quit", width: promptPanelWidth() - 4, backgroundColor: SURFACE.status, color: "gray" })
|
|
27843
28774
|
);
|
|
27844
28775
|
}
|
|
27845
28776
|
function shortcutHelp(state) {
|
|
@@ -27854,46 +28785,258 @@ function shortcutHelp(state) {
|
|
|
27854
28785
|
parts.push("q quit");
|
|
27855
28786
|
return `shortcut: ${parts.join(" | ")}`;
|
|
27856
28787
|
}
|
|
27857
|
-
function PromptBar({ state, shortcutMode }) {
|
|
27858
|
-
const
|
|
27859
|
-
const hint = shortcutMode ? shortcutHelp(state) : "enter send | esc shortcuts | up/down history | /cowork | /compact | /retry | /exit";
|
|
28788
|
+
function PromptBar({ state, shortcutMode, promptInput, slashCommandPalette, commandPalette }) {
|
|
28789
|
+
const hint = shortcutMode ? shortcutHelp(state) : "enter send | shift/option+enter newline | ctrl+p commands | esc shortcuts | up/down history | /session | /compact | /retry | /exit";
|
|
27860
28790
|
return React.createElement(
|
|
27861
28791
|
Box,
|
|
27862
28792
|
{ alignSelf: "center", width: promptPanelWidth(), flexDirection: "column", marginTop: 1 },
|
|
27863
|
-
React.createElement(
|
|
27864
|
-
React.createElement(
|
|
28793
|
+
commandPalette ? React.createElement(CommandPalettePanel, { palette: commandPalette }) : null,
|
|
28794
|
+
commandPalette ? null : React.createElement(SessionMetaBox, { state, marginTop: 0 }),
|
|
28795
|
+
slashCommandPalette ? React.createElement(SlashCommandPalette, { palette: slashCommandPalette }) : null,
|
|
28796
|
+
React.createElement(InputFrame, {
|
|
28797
|
+
borderColor: shortcutMode ? "cyan" : "blue",
|
|
28798
|
+
cursorColor: "cyan",
|
|
28799
|
+
value: promptInput,
|
|
28800
|
+
placeholder: "Type first message and press Enter",
|
|
28801
|
+
marginTop: 1
|
|
28802
|
+
}),
|
|
28803
|
+
React.createElement(CommandGuide, { hint, color: shortcutMode ? "cyan" : "gray", error: state.promptError })
|
|
28804
|
+
);
|
|
28805
|
+
}
|
|
28806
|
+
function CommandBar({ state, shortcutMode, promptInput, slashCommandPalette, commandPalette }) {
|
|
28807
|
+
const hint = shortcutMode ? shortcutHelp(state) : "running | shift/option+enter newline | ctrl+p commands | /stop stop | /exit quit | esc shortcuts";
|
|
28808
|
+
return React.createElement(
|
|
28809
|
+
Box,
|
|
28810
|
+
{ alignSelf: "center", width: promptPanelWidth(), flexDirection: "column", marginTop: 1 },
|
|
28811
|
+
commandPalette ? React.createElement(CommandPalettePanel, { palette: commandPalette }) : null,
|
|
28812
|
+
commandPalette ? null : React.createElement(SessionMetaBox, { state, marginTop: 0 }),
|
|
28813
|
+
slashCommandPalette ? React.createElement(SlashCommandPalette, { palette: slashCommandPalette }) : null,
|
|
28814
|
+
React.createElement(InputFrame, {
|
|
28815
|
+
borderColor: shortcutMode ? "cyan" : "yellow",
|
|
28816
|
+
cursorColor: "yellow",
|
|
28817
|
+
value: promptInput,
|
|
28818
|
+
placeholder: "Type /stop to stop or /exit to quit",
|
|
28819
|
+
marginTop: 1
|
|
28820
|
+
}),
|
|
28821
|
+
React.createElement(CommandGuide, { hint, color: shortcutMode ? "cyan" : "gray", error: state.promptError })
|
|
28822
|
+
);
|
|
28823
|
+
}
|
|
28824
|
+
function CommandPalettePanel({ palette }) {
|
|
28825
|
+
const width = commandPalettePanelWidth();
|
|
28826
|
+
const contentWidth = Math.max(32, width - 4);
|
|
28827
|
+
const maxRows = commandPaletteMaxRows();
|
|
28828
|
+
const selectedCursor = Math.min(palette.cursor, Math.max(0, palette.items.length - 1));
|
|
28829
|
+
const start = Math.max(0, Math.min(selectedCursor - maxRows + 1, Math.max(0, palette.items.length - maxRows)));
|
|
28830
|
+
const visibleItems = palette.items.slice(start, start + maxRows);
|
|
28831
|
+
const visibleCursor = selectedCursor - start;
|
|
28832
|
+
return React.createElement(
|
|
28833
|
+
Box,
|
|
28834
|
+
{ alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "#374151", paddingX: 1, paddingY: 1, marginTop: 1 },
|
|
28835
|
+
React.createElement(CommandPaletteHeader, { width: contentWidth }),
|
|
28836
|
+
React.createElement(CommandPaletteSearchLine, { query: palette.query, width: contentWidth }),
|
|
28837
|
+
React.createElement(SurfaceLine, { text: "", width: contentWidth, backgroundColor: SURFACE.dialog }),
|
|
28838
|
+
start > 0 ? React.createElement(SurfaceLine, { text: `+ ${start} above`, width: contentWidth, backgroundColor: SURFACE.dialog, color: "gray" }) : null,
|
|
28839
|
+
...commandPaletteRenderedRows(visibleItems, visibleCursor, contentWidth),
|
|
28840
|
+
palette.items.length === 0 ? React.createElement(SurfaceLine, { text: "No commands", width: contentWidth, backgroundColor: SURFACE.dialog, color: "gray" }) : null,
|
|
28841
|
+
palette.items.length > start + visibleItems.length ? React.createElement(SurfaceLine, { text: `+ ${palette.items.length - start - visibleItems.length} more`, width: contentWidth, backgroundColor: SURFACE.dialog, color: "gray" }) : null
|
|
28842
|
+
);
|
|
28843
|
+
}
|
|
28844
|
+
function CommandPaletteHeader({ width }) {
|
|
28845
|
+
const label = "Commands";
|
|
28846
|
+
const esc = "esc";
|
|
28847
|
+
const gap = Math.max(1, width - stringWidth(label) - stringWidth(esc));
|
|
28848
|
+
return React.createElement(
|
|
28849
|
+
Text,
|
|
28850
|
+
{ backgroundColor: SURFACE.dialog, color: "white", bold: true },
|
|
28851
|
+
`${label}${" ".repeat(gap)}${esc}`
|
|
28852
|
+
);
|
|
28853
|
+
}
|
|
28854
|
+
function CommandPaletteSearchLine({ query, width }) {
|
|
28855
|
+
const text = query || "Search";
|
|
28856
|
+
const textColor = query ? "white" : "gray";
|
|
28857
|
+
const textWidth = Math.max(0, width - 1);
|
|
28858
|
+
return React.createElement(
|
|
28859
|
+
Box,
|
|
28860
|
+
null,
|
|
28861
|
+
React.createElement(CursorCell, { cursorColor: "#f4a261" }),
|
|
28862
|
+
React.createElement(Text, { color: textColor, backgroundColor: SURFACE.dialog }, padToWidth(fitToWidth(text, textWidth), textWidth))
|
|
28863
|
+
);
|
|
28864
|
+
}
|
|
28865
|
+
function commandPaletteRenderedRows(items, cursor, width) {
|
|
28866
|
+
const rows = [];
|
|
28867
|
+
let lastGroup;
|
|
28868
|
+
items.forEach((item, index) => {
|
|
28869
|
+
if (item.group !== lastGroup) {
|
|
28870
|
+
if (rows.length > 0) rows.push(React.createElement(SurfaceLine, { key: `gap-${item.group}-${index}`, text: "", width, backgroundColor: SURFACE.dialog }));
|
|
28871
|
+
rows.push(React.createElement(SurfaceLine, { key: `group-${item.group}-${index}`, text: item.group, width, backgroundColor: SURFACE.dialog, color: "magenta", bold: true }));
|
|
28872
|
+
lastGroup = item.group;
|
|
28873
|
+
}
|
|
28874
|
+
rows.push(React.createElement(CommandPaletteRow, { key: item.id, item, selected: index === cursor, width }));
|
|
28875
|
+
});
|
|
28876
|
+
return rows;
|
|
28877
|
+
}
|
|
28878
|
+
function CommandPaletteRow({ item, selected, width }) {
|
|
28879
|
+
const shortcutWidth = Math.min(18, Math.max(8, Math.floor(width * 0.22)));
|
|
28880
|
+
const titleWidth = Math.min(26, Math.max(16, Math.floor(width * 0.34)));
|
|
28881
|
+
const descriptionWidth = Math.max(0, width - titleWidth - shortcutWidth - 2);
|
|
28882
|
+
const line = [
|
|
28883
|
+
padCell(item.title, titleWidth),
|
|
28884
|
+
padCell(item.description, descriptionWidth),
|
|
28885
|
+
padCell(item.shortcut ?? "", shortcutWidth, "start")
|
|
28886
|
+
].join(" ");
|
|
28887
|
+
return React.createElement(
|
|
28888
|
+
Text,
|
|
28889
|
+
{
|
|
28890
|
+
color: selected ? "black" : "white",
|
|
28891
|
+
backgroundColor: selected ? "#f4a261" : SURFACE.dialog,
|
|
28892
|
+
bold: selected
|
|
28893
|
+
},
|
|
28894
|
+
padToWidth(line, width)
|
|
28895
|
+
);
|
|
28896
|
+
}
|
|
28897
|
+
function SlashCommandPalette({ palette }) {
|
|
28898
|
+
const width = promptPanelWidth();
|
|
28899
|
+
const contentWidth = Math.max(24, width - 4);
|
|
28900
|
+
return React.createElement(
|
|
28901
|
+
Box,
|
|
28902
|
+
{ alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "blue", paddingX: 1, marginTop: 1 },
|
|
28903
|
+
...palette.items.map((item, index) => {
|
|
28904
|
+
const selected = index === palette.cursor;
|
|
28905
|
+
return React.createElement(
|
|
28906
|
+
Text,
|
|
28907
|
+
{
|
|
28908
|
+
key: item.command,
|
|
28909
|
+
color: selected ? "black" : "white",
|
|
28910
|
+
backgroundColor: selected ? "#f4a261" : SURFACE.dialog,
|
|
28911
|
+
bold: selected
|
|
28912
|
+
},
|
|
28913
|
+
slashCommandLine(item, contentWidth)
|
|
28914
|
+
);
|
|
28915
|
+
})
|
|
28916
|
+
);
|
|
28917
|
+
}
|
|
28918
|
+
function slashCommandLine(item, width) {
|
|
28919
|
+
const commandWidth = Math.max(12, Math.min(22, Math.floor(width * 0.34)));
|
|
28920
|
+
const descriptionWidth = Math.max(0, width - commandWidth - 1);
|
|
28921
|
+
return `${padCell(item.command, commandWidth)} ${padCell(item.description, descriptionWidth)}`;
|
|
28922
|
+
}
|
|
28923
|
+
function InputFrame({
|
|
28924
|
+
borderColor,
|
|
28925
|
+
cursorColor,
|
|
28926
|
+
value,
|
|
28927
|
+
placeholder,
|
|
28928
|
+
marginTop = 1
|
|
28929
|
+
}) {
|
|
28930
|
+
const width = promptPanelWidth();
|
|
28931
|
+
const contentWidth = Math.max(18, width - 2);
|
|
28932
|
+
const rows = inputFrameRows(value, placeholder, contentWidth);
|
|
28933
|
+
return React.createElement(
|
|
28934
|
+
Box,
|
|
28935
|
+
{
|
|
28936
|
+
alignSelf: "center",
|
|
28937
|
+
width,
|
|
28938
|
+
flexDirection: "column",
|
|
28939
|
+
borderStyle: "double",
|
|
28940
|
+
borderTopColor: borderColor,
|
|
28941
|
+
borderLeftColor: borderColor,
|
|
28942
|
+
borderRightColor: "gray",
|
|
28943
|
+
borderBottomColor: "gray",
|
|
28944
|
+
marginTop
|
|
28945
|
+
},
|
|
28946
|
+
...rows.map((row, index) => React.createElement(InputFrameLine, { key: index, row, width: contentWidth, cursorColor }))
|
|
28947
|
+
);
|
|
28948
|
+
}
|
|
28949
|
+
function InputFrameLine({ row, width, cursorColor }) {
|
|
28950
|
+
if (row.cursorBeforeText) {
|
|
28951
|
+
const cursor2 = row.cursor ? React.createElement(CursorCell, { cursorColor }) : React.createElement(Text, { backgroundColor: SURFACE.input }, " ");
|
|
28952
|
+
const textWidth2 = Math.max(0, width - 1);
|
|
28953
|
+
return React.createElement(
|
|
27865
28954
|
Box,
|
|
27866
|
-
|
|
27867
|
-
|
|
27868
|
-
|
|
27869
|
-
|
|
27870
|
-
|
|
27871
|
-
|
|
27872
|
-
|
|
27873
|
-
|
|
27874
|
-
|
|
28955
|
+
null,
|
|
28956
|
+
cursor2,
|
|
28957
|
+
React.createElement(Text, { color: row.placeholder ? "gray" : "white", backgroundColor: SURFACE.input }, padToWidth(row.text, textWidth2))
|
|
28958
|
+
);
|
|
28959
|
+
}
|
|
28960
|
+
const cursor = row.cursor ? React.createElement(CursorCell, { cursorColor }) : null;
|
|
28961
|
+
const textWidth = row.cursor ? Math.max(0, width - 1) : width;
|
|
28962
|
+
const text = fitToWidth(row.text, textWidth);
|
|
28963
|
+
const fillWidth = Math.max(0, textWidth - stringWidth(text));
|
|
28964
|
+
return React.createElement(
|
|
28965
|
+
Box,
|
|
28966
|
+
null,
|
|
28967
|
+
React.createElement(Text, { color: row.placeholder ? "gray" : "white", backgroundColor: SURFACE.input }, text),
|
|
28968
|
+
cursor,
|
|
28969
|
+
React.createElement(Text, { backgroundColor: SURFACE.input }, padToWidth("", fillWidth))
|
|
27875
28970
|
);
|
|
27876
28971
|
}
|
|
27877
|
-
function
|
|
27878
|
-
|
|
27879
|
-
|
|
28972
|
+
function CursorCell({ cursorColor }) {
|
|
28973
|
+
return React.createElement(Text, { color: "black", backgroundColor: cursorColor, bold: true }, "\x1B[5m \x1B[25m");
|
|
28974
|
+
}
|
|
28975
|
+
function CommandGuide({ hint, color, error }) {
|
|
27880
28976
|
return React.createElement(
|
|
27881
28977
|
Box,
|
|
27882
28978
|
{ alignSelf: "center", width: promptPanelWidth(), flexDirection: "column", marginTop: 1 },
|
|
27883
|
-
React.createElement(
|
|
28979
|
+
error ? React.createElement(Text, { color: "yellow" }, error) : null,
|
|
27884
28980
|
React.createElement(
|
|
27885
28981
|
Box,
|
|
27886
|
-
{
|
|
27887
|
-
React.createElement(
|
|
27888
|
-
Box,
|
|
27889
|
-
null,
|
|
27890
|
-
React.createElement(Text, { color: "yellow", bold: true }, ": "),
|
|
27891
|
-
React.createElement(Text, { color: state.promptInput ? "white" : "gray" }, value)
|
|
27892
|
-
),
|
|
27893
|
-
state.promptError ? React.createElement(Text, { color: "yellow" }, state.promptError) : React.createElement(Text, { color: shortcutMode ? "cyan" : "gray" }, hint)
|
|
28982
|
+
{ justifyContent: "flex-end" },
|
|
28983
|
+
React.createElement(Text, { color }, hint)
|
|
27894
28984
|
)
|
|
27895
28985
|
);
|
|
27896
28986
|
}
|
|
28987
|
+
function SessionSelector({ state }) {
|
|
28988
|
+
const items = state.sessionOptions;
|
|
28989
|
+
const width = sessionPanelWidth();
|
|
28990
|
+
const contentWidth = Math.max(36, width - 6);
|
|
28991
|
+
return React.createElement(
|
|
28992
|
+
DialogFrame,
|
|
28993
|
+
{ title: "Start Session", accent: "magenta", width },
|
|
28994
|
+
React.createElement(Text, { color: "gray" }, sessionHeaderLine(contentWidth)),
|
|
28995
|
+
...items.map((item, index) => {
|
|
28996
|
+
const selected = index === state.sessionCursor;
|
|
28997
|
+
const color = selected ? "cyan" : item.kind === "new" ? "green" : item.currentWorkspace ? "white" : "gray";
|
|
28998
|
+
return React.createElement(
|
|
28999
|
+
Text,
|
|
29000
|
+
{ key: item.kind === "new" ? "new-session" : item.id, color, bold: selected },
|
|
29001
|
+
sessionOptionLine(item, index, selected, contentWidth)
|
|
29002
|
+
);
|
|
29003
|
+
}),
|
|
29004
|
+
items.length === 0 ? React.createElement(Text, { color: "gray" }, "No saved sessions. Press n to create one.") : null
|
|
29005
|
+
);
|
|
29006
|
+
}
|
|
29007
|
+
function sessionSelectorColumns(width) {
|
|
29008
|
+
const contentWidth = Math.max(24, width);
|
|
29009
|
+
const compact = contentWidth < 52;
|
|
29010
|
+
const stateWidth = compact ? 6 : 8;
|
|
29011
|
+
const updatedWidth = compact ? 8 : 10;
|
|
29012
|
+
const available = Math.max(0, contentWidth - stateWidth - updatedWidth - 5);
|
|
29013
|
+
const titleMin = Math.min(compact ? 8 : 14, available);
|
|
29014
|
+
const titleMax = compact ? 20 : 42;
|
|
29015
|
+
const titleWidth = Math.min(available, Math.max(titleMin, Math.min(titleMax, Math.floor(available * (compact ? 0.52 : 0.52)))));
|
|
29016
|
+
const workspaceWidth = Math.max(0, available - titleWidth);
|
|
29017
|
+
return { title: titleWidth, state: stateWidth, updated: updatedWidth, workspace: workspaceWidth };
|
|
29018
|
+
}
|
|
29019
|
+
function sessionHeaderLine(width) {
|
|
29020
|
+
const columns = sessionSelectorColumns(width);
|
|
29021
|
+
return sessionSelectorLine(" ", "Session", "State", "Updated", "Workspace", columns);
|
|
29022
|
+
}
|
|
29023
|
+
function sessionOptionLine(item, index, selected, width) {
|
|
29024
|
+
const pointer = selected ? ">" : " ";
|
|
29025
|
+
const columns = sessionSelectorColumns(width);
|
|
29026
|
+
if (item.kind === "new") {
|
|
29027
|
+
return sessionSelectorLine(pointer, "+ New session", "ready", "-", item.cwd ?? "current workspace", columns);
|
|
29028
|
+
}
|
|
29029
|
+
const workspace = item.currentWorkspace ? "current workspace" : item.cwd ?? "-";
|
|
29030
|
+
return sessionSelectorLine(pointer, `${index + 1}. ${item.title}`, item.status, formatSessionAge(item.updatedAt), workspace, columns);
|
|
29031
|
+
}
|
|
29032
|
+
function sessionSelectorLine(pointer, title, state, updated, workspace, columns) {
|
|
29033
|
+
return [
|
|
29034
|
+
`${pointer} ${padCell(title, columns.title)}`,
|
|
29035
|
+
padCell(state, columns.state),
|
|
29036
|
+
padCell(updated, columns.updated),
|
|
29037
|
+
padCell(workspace, columns.workspace, "start")
|
|
29038
|
+
].join(" ");
|
|
29039
|
+
}
|
|
27897
29040
|
function ProviderSelector({ state }) {
|
|
27898
29041
|
const items = state.providerOptions;
|
|
27899
29042
|
return React.createElement(
|
|
@@ -27974,11 +29117,11 @@ function PermissionBar({ state }) {
|
|
|
27974
29117
|
...permissionShortcutLines().map((line, index) => React.createElement(Text, { key: `shortcut-${index}`, color: "cyan", bold: true }, line))
|
|
27975
29118
|
);
|
|
27976
29119
|
}
|
|
27977
|
-
function DialogFrame({ title, accent, children }) {
|
|
29120
|
+
function DialogFrame({ title, accent, children, width = dialogPanelWidth() }) {
|
|
27978
29121
|
return React.createElement(
|
|
27979
29122
|
Box,
|
|
27980
|
-
{ alignSelf: "center", width
|
|
27981
|
-
React.createElement(
|
|
29123
|
+
{ alignSelf: "center", width, flexDirection: "column", borderStyle: "round", borderColor: accent, paddingX: 2, paddingY: 1, marginTop: 1 },
|
|
29124
|
+
React.createElement(SurfaceLine, { text: title, width: width - 6, backgroundColor: SURFACE.dialog, color: accent, bold: true }),
|
|
27982
29125
|
React.createElement(Box, { height: 1 }),
|
|
27983
29126
|
children
|
|
27984
29127
|
);
|
|
@@ -27989,25 +29132,188 @@ function providerStatusLabel(item) {
|
|
|
27989
29132
|
if (item.catalog?.status === "unavailable") return "offline";
|
|
27990
29133
|
return "n/a";
|
|
27991
29134
|
}
|
|
29135
|
+
function SurfaceLine({ text, width, backgroundColor, color = "white", bold = false }) {
|
|
29136
|
+
return React.createElement(Text, { color, backgroundColor, bold, wrap: "truncate-end" }, padToWidth(text, width));
|
|
29137
|
+
}
|
|
29138
|
+
function inputFrameRows(value, placeholder, width) {
|
|
29139
|
+
const contentWidth = Math.max(8, width);
|
|
29140
|
+
const textWidthWithCursor = Math.max(1, contentWidth - 1);
|
|
29141
|
+
if (!value) {
|
|
29142
|
+
const line = fitToWidth(` ${placeholder}`, textWidthWithCursor);
|
|
29143
|
+
return [
|
|
29144
|
+
{ text: line, placeholder: true, cursor: true, cursorBeforeText: true },
|
|
29145
|
+
...Array.from({ length: 2 }, () => ({ text: "", placeholder: false, cursor: false, cursorBeforeText: false }))
|
|
29146
|
+
];
|
|
29147
|
+
}
|
|
29148
|
+
const rawLines = value.split(/\n/);
|
|
29149
|
+
const wrapped = rawLines.flatMap((line) => wrapInputLine(line, textWidthWithCursor));
|
|
29150
|
+
const rows = wrapped.map((line) => ({ text: line, placeholder: false, cursor: false, cursorBeforeText: false }));
|
|
29151
|
+
const last = rows.at(-1);
|
|
29152
|
+
if (last) last.cursor = true;
|
|
29153
|
+
else rows.push({ text: "", placeholder: false, cursor: true, cursorBeforeText: false });
|
|
29154
|
+
while (rows.length < 3) rows.push({ text: "", placeholder: false, cursor: false, cursorBeforeText: false });
|
|
29155
|
+
return rows.slice(-6);
|
|
29156
|
+
}
|
|
29157
|
+
function wrapInputLine(value, width) {
|
|
29158
|
+
const target = Math.max(1, width);
|
|
29159
|
+
if (value === "") return [""];
|
|
29160
|
+
const lines = [];
|
|
29161
|
+
let current = "";
|
|
29162
|
+
for (const char of Array.from(value)) {
|
|
29163
|
+
if (stringWidth(current) + stringWidth(char) > target && current) {
|
|
29164
|
+
lines.push(current);
|
|
29165
|
+
current = char;
|
|
29166
|
+
} else {
|
|
29167
|
+
current += char;
|
|
29168
|
+
}
|
|
29169
|
+
}
|
|
29170
|
+
lines.push(current);
|
|
29171
|
+
return lines;
|
|
29172
|
+
}
|
|
29173
|
+
function wrapBlockLines(lines, width, maxLines = Number.POSITIVE_INFINITY) {
|
|
29174
|
+
const target = Math.max(8, width);
|
|
29175
|
+
const wrapped = [];
|
|
29176
|
+
for (const line of normalizedBlockLines(lines)) {
|
|
29177
|
+
if (wrapped.length >= maxLines) break;
|
|
29178
|
+
const chunks = wrapDisplayLine(line, target);
|
|
29179
|
+
for (const chunk of chunks) {
|
|
29180
|
+
if (wrapped.length >= maxLines) break;
|
|
29181
|
+
wrapped.push(chunk);
|
|
29182
|
+
}
|
|
29183
|
+
}
|
|
29184
|
+
return wrapped.length > 0 ? wrapped : [""];
|
|
29185
|
+
}
|
|
29186
|
+
function wrapDisplayLine(value, width) {
|
|
29187
|
+
const target = Math.max(1, width);
|
|
29188
|
+
if (value === "") return [""];
|
|
29189
|
+
if (shouldTruncateDisplayLine(value)) return [fitToWidth(value, target)];
|
|
29190
|
+
const chars = Array.from(value);
|
|
29191
|
+
const lines = [];
|
|
29192
|
+
let start = 0;
|
|
29193
|
+
while (start < chars.length) {
|
|
29194
|
+
let current = "";
|
|
29195
|
+
let end = start;
|
|
29196
|
+
let breakAt = -1;
|
|
29197
|
+
for (let index = start; index < chars.length; index += 1) {
|
|
29198
|
+
const next = chars[index] ?? "";
|
|
29199
|
+
if (stringWidth(current) + stringWidth(next) > target && current) break;
|
|
29200
|
+
current += next;
|
|
29201
|
+
end = index + 1;
|
|
29202
|
+
if (isSoftWrapBreak(next)) breakAt = end;
|
|
29203
|
+
}
|
|
29204
|
+
if (end >= chars.length) {
|
|
29205
|
+
lines.push(current);
|
|
29206
|
+
break;
|
|
29207
|
+
}
|
|
29208
|
+
if (breakAt > start && stringWidth(chars.slice(start, breakAt).join("").trimEnd()) >= Math.floor(target * 0.45)) {
|
|
29209
|
+
const line = chars.slice(start, breakAt).join("").trimEnd();
|
|
29210
|
+
lines.push(line || current);
|
|
29211
|
+
start = breakAt;
|
|
29212
|
+
while (chars[start] === " ") start += 1;
|
|
29213
|
+
} else {
|
|
29214
|
+
lines.push(current);
|
|
29215
|
+
start = end;
|
|
29216
|
+
}
|
|
29217
|
+
}
|
|
29218
|
+
return lines;
|
|
29219
|
+
}
|
|
29220
|
+
function shouldTruncateDisplayLine(value) {
|
|
29221
|
+
return /^[╭╰╮╯│]/u.test(value.trimStart());
|
|
29222
|
+
}
|
|
29223
|
+
function isSoftWrapBreak(value) {
|
|
29224
|
+
return /\s/u.test(value) || value === "/" || value === "-";
|
|
29225
|
+
}
|
|
29226
|
+
function padToWidth(value, width) {
|
|
29227
|
+
const target = Math.max(0, width);
|
|
29228
|
+
const current = stringWidth(value);
|
|
29229
|
+
if (current >= target) return value;
|
|
29230
|
+
return `${value}${" ".repeat(target - current)}`;
|
|
29231
|
+
}
|
|
29232
|
+
function padCell(value, width, truncate2 = "end") {
|
|
29233
|
+
const text = truncate2 === "start" ? truncateStartToWidth(value, width) : truncateEndToWidth(value, width);
|
|
29234
|
+
return padToWidth(text, width);
|
|
29235
|
+
}
|
|
29236
|
+
function fitToWidth(value, width) {
|
|
29237
|
+
const target = Math.max(0, width);
|
|
29238
|
+
if (stringWidth(value) <= target) return value;
|
|
29239
|
+
let current = "";
|
|
29240
|
+
for (const char of Array.from(value)) {
|
|
29241
|
+
if (stringWidth(current) + stringWidth(char) > target) break;
|
|
29242
|
+
current += char;
|
|
29243
|
+
}
|
|
29244
|
+
return current;
|
|
29245
|
+
}
|
|
29246
|
+
function truncateEndToWidth(value, width) {
|
|
29247
|
+
const target = Math.max(0, width);
|
|
29248
|
+
if (stringWidth(value) <= target) return value;
|
|
29249
|
+
const marker = "\u2026";
|
|
29250
|
+
const markerWidth = stringWidth(marker);
|
|
29251
|
+
if (target <= markerWidth) return fitToWidth(marker, target);
|
|
29252
|
+
return `${fitToWidth(value, target - markerWidth)}${marker}`;
|
|
29253
|
+
}
|
|
29254
|
+
function truncateStartToWidth(value, width) {
|
|
29255
|
+
const target = Math.max(0, width);
|
|
29256
|
+
if (stringWidth(value) <= target) return value;
|
|
29257
|
+
const marker = "\u2026";
|
|
29258
|
+
const markerWidth = stringWidth(marker);
|
|
29259
|
+
if (target <= markerWidth) return fitToWidth(marker, target);
|
|
29260
|
+
let current = "";
|
|
29261
|
+
for (const char of Array.from(value).reverse()) {
|
|
29262
|
+
if (stringWidth(current) + stringWidth(char) > target - markerWidth) break;
|
|
29263
|
+
current = `${char}${current}`;
|
|
29264
|
+
}
|
|
29265
|
+
return `${marker}${current}`;
|
|
29266
|
+
}
|
|
27992
29267
|
function shorten(value, max) {
|
|
27993
29268
|
if (value.length <= max) return value;
|
|
27994
29269
|
return `\u2026${value.slice(value.length - max + 1)}`;
|
|
27995
29270
|
}
|
|
27996
29271
|
function terminalHeight() {
|
|
27997
29272
|
const rows = process.stdout.rows;
|
|
27998
|
-
return typeof rows === "number" && Number.isFinite(rows) && rows > 0 ? Math.max(
|
|
29273
|
+
return typeof rows === "number" && Number.isFinite(rows) && rows > 0 ? Math.max(12, rows - 3) : 24;
|
|
27999
29274
|
}
|
|
28000
29275
|
function terminalWidth() {
|
|
28001
29276
|
const columns = process.stdout.columns;
|
|
28002
29277
|
return typeof columns === "number" && Number.isFinite(columns) && columns > 0 ? Math.max(48, columns) : 100;
|
|
28003
29278
|
}
|
|
28004
29279
|
function promptPanelWidth() {
|
|
28005
|
-
|
|
28006
|
-
|
|
29280
|
+
return responsivePanelWidth({ min: 40, max: 96, margin: 8, ratio: 0.86 });
|
|
29281
|
+
}
|
|
29282
|
+
function statusSurfaceWidth() {
|
|
29283
|
+
return responsivePanelWidth({ min: 36, max: 112, margin: 8, ratio: 0.95 });
|
|
29284
|
+
}
|
|
29285
|
+
function transcriptPanelWidth() {
|
|
29286
|
+
return responsivePanelWidth({ min: 48, max: 118, margin: 8, ratio: 0.82 });
|
|
29287
|
+
}
|
|
29288
|
+
function userMessageBubbleWidth(lines, columns = terminalWidth()) {
|
|
29289
|
+
const available = Math.max(18, columns - 4);
|
|
29290
|
+
const maxWidth = Math.max(18, Math.min(84, available, Math.floor(columns * 0.68)));
|
|
29291
|
+
const minWidth = Math.min(maxWidth, 18);
|
|
29292
|
+
const contentWidth = Math.max(0, ...normalizedBlockLines(lines).map((line) => stringWidth(line)));
|
|
29293
|
+
return Math.max(minWidth, Math.min(maxWidth, contentWidth + 4));
|
|
29294
|
+
}
|
|
29295
|
+
function normalizedBlockLines(lines) {
|
|
29296
|
+
const normalized = lines.flatMap((line) => String(line ?? "").split(/\r?\n/));
|
|
29297
|
+
return normalized.length > 0 ? normalized : [""];
|
|
28007
29298
|
}
|
|
28008
29299
|
function dialogPanelWidth() {
|
|
29300
|
+
return responsivePanelWidth({ min: 52, max: 98, margin: 10, ratio: 0.82 });
|
|
29301
|
+
}
|
|
29302
|
+
function sessionPanelWidth() {
|
|
29303
|
+
return responsivePanelWidth({ min: 72, max: 118, margin: 6, ratio: 0.92 });
|
|
29304
|
+
}
|
|
29305
|
+
function commandPalettePanelWidth() {
|
|
29306
|
+
return responsivePanelWidth({ min: 56, max: 88, margin: 10, ratio: 0.74 });
|
|
29307
|
+
}
|
|
29308
|
+
function commandPaletteMaxRows() {
|
|
29309
|
+
return Math.max(6, Math.min(16, terminalHeight() - 12));
|
|
29310
|
+
}
|
|
29311
|
+
function responsivePanelWidth({ min, max, margin, ratio }) {
|
|
28009
29312
|
const columns = terminalWidth();
|
|
28010
|
-
|
|
29313
|
+
const available = Math.max(24, columns - margin);
|
|
29314
|
+
const preferred = Math.min(max, Math.max(min, Math.floor(columns * ratio)));
|
|
29315
|
+
const minimumWithinTerminal = Math.min(min, available);
|
|
29316
|
+
return Math.max(minimumWithinTerminal, Math.min(preferred, available));
|
|
28011
29317
|
}
|
|
28012
29318
|
function formatTokens(value) {
|
|
28013
29319
|
const tokens = typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.round(value)) : 0;
|
|
@@ -28022,13 +29328,40 @@ function clamp01(value) {
|
|
|
28022
29328
|
if (!Number.isFinite(value)) return 0;
|
|
28023
29329
|
return Math.max(0, Math.min(1, value));
|
|
28024
29330
|
}
|
|
28025
|
-
var DEMIAN_WORDMARK_LINES;
|
|
29331
|
+
var SURFACE, CSI_U_INPUT, XTERM_MODIFIED_ENTER_INPUT, SLASH_COMMANDS, DEMIAN_WORDMARK_LINES;
|
|
28026
29332
|
var init_app = __esm({
|
|
28027
29333
|
"src/ui/tui/app.ts"() {
|
|
28028
29334
|
"use strict";
|
|
29335
|
+
init_string_width();
|
|
28029
29336
|
init_store();
|
|
28030
29337
|
init_presets();
|
|
28031
29338
|
init_tool_summary();
|
|
29339
|
+
SURFACE = {
|
|
29340
|
+
input: "#050505",
|
|
29341
|
+
status: "#101820",
|
|
29342
|
+
dialog: "#15121e"
|
|
29343
|
+
};
|
|
29344
|
+
CSI_U_INPUT = /^\x1b?\[(\d+)(?:;(\d+))?u$/;
|
|
29345
|
+
XTERM_MODIFIED_ENTER_INPUT = /^\x1b?\[27;([2-4]);13~$/;
|
|
29346
|
+
SLASH_COMMANDS = [
|
|
29347
|
+
{ command: "/cowork", insert: "/cowork", argument: true, mode: "prompt", description: "Run cowork sub agents on a task", aliases: ["agent", "parallel", "review"] },
|
|
29348
|
+
{ command: "/compact", insert: "/compact", mode: "prompt", description: "Compact current conversation context", aliases: ["context", "compress"] },
|
|
29349
|
+
{ command: "/retry", insert: "/retry", mode: "prompt", description: "Retry the last task", aliases: ["again", "rerun"] },
|
|
29350
|
+
{ command: "/session", insert: "/session", argument: true, mode: "prompt", description: "Manage saved conversations", aliases: ["sessions", "conversation", "conv"] },
|
|
29351
|
+
{ command: "/session list", insert: "/session list", mode: "prompt", description: "List saved conversations", aliases: ["sessions", "ls"] },
|
|
29352
|
+
{ command: "/session new", insert: "/session new", argument: true, mode: "prompt", description: "Create a new conversation", aliases: ["new", "create"] },
|
|
29353
|
+
{ command: "/session switch", insert: "/session switch", argument: true, mode: "prompt", description: "Switch to a saved conversation", aliases: ["open", "select", "use"] },
|
|
29354
|
+
{ command: "/session rename", insert: "/session rename", argument: true, mode: "prompt", description: "Rename the current conversation", aliases: ["name"] },
|
|
29355
|
+
{ command: "/session delete", insert: "/session delete", argument: true, mode: "prompt", description: "Delete a saved conversation", aliases: ["remove", "rm"] },
|
|
29356
|
+
{ command: "/goal", insert: "/goal", argument: true, mode: "prompt", description: "Start or inspect a goal loop", aliases: ["task", "objective"] },
|
|
29357
|
+
{ command: "/goal status", insert: "/goal status", mode: "prompt", description: "Show active goal status", aliases: ["status"] },
|
|
29358
|
+
{ command: "/goal clear", insert: "/goal clear", mode: "prompt", description: "Clear visible goal state", aliases: ["reset"] },
|
|
29359
|
+
{ command: "/ralph-loop", insert: "/ralph-loop", argument: true, mode: "prompt", description: "Start a goal loop with Ralph mode", aliases: ["ralph"] },
|
|
29360
|
+
{ command: "/cancel-ralph", insert: "/cancel-ralph", mode: "prompt", description: "Pause the active Ralph loop", aliases: ["cancel", "pause"] },
|
|
29361
|
+
{ command: "/stop", insert: "/stop", mode: "running", description: "Stop the running task", aliases: ["cancel"] },
|
|
29362
|
+
{ command: "/exit", insert: "/exit", mode: "both", description: "Exit Demian", aliases: ["quit", "close"] },
|
|
29363
|
+
{ command: "/quit", insert: "/quit", mode: "both", description: "Exit Demian", aliases: ["exit", "close"] }
|
|
29364
|
+
];
|
|
28032
29365
|
DEMIAN_WORDMARK_LINES = [
|
|
28033
29366
|
" _ _ ",
|
|
28034
29367
|
" __| | ___ _ __ ___ (_) __ _ _ __ ",
|
|
@@ -32056,8 +33389,8 @@ async function summarizeGoalTitleWithProvider(options) {
|
|
|
32056
33389
|
}
|
|
32057
33390
|
function normalizeGoalTitle(value, objective) {
|
|
32058
33391
|
const raw = typeof value === "string" ? value : "";
|
|
32059
|
-
const
|
|
32060
|
-
const cleaned = stripDecorations(
|
|
33392
|
+
const firstLine2 = raw.split(/\r?\n/).find((line) => line.trim()) ?? "";
|
|
33393
|
+
const cleaned = stripDecorations(firstLine2);
|
|
32061
33394
|
return truncateGoalTitle(cleaned || fallbackGoalTitle(objective));
|
|
32062
33395
|
}
|
|
32063
33396
|
function fallbackGoalTitle(objective) {
|
|
@@ -32763,17 +34096,17 @@ function findDependencyCycle(group) {
|
|
|
32763
34096
|
const byId = new Map(group.map((member) => [member.memberId, member]));
|
|
32764
34097
|
const visiting = /* @__PURE__ */ new Set();
|
|
32765
34098
|
const visited = /* @__PURE__ */ new Set();
|
|
32766
|
-
const
|
|
34099
|
+
const path37 = [];
|
|
32767
34100
|
const visit = (id) => {
|
|
32768
|
-
if (visiting.has(id)) return [...
|
|
34101
|
+
if (visiting.has(id)) return [...path37.slice(path37.indexOf(id)), id];
|
|
32769
34102
|
if (visited.has(id)) return void 0;
|
|
32770
34103
|
visiting.add(id);
|
|
32771
|
-
|
|
34104
|
+
path37.push(id);
|
|
32772
34105
|
for (const dep of byId.get(id)?.dependsOn ?? []) {
|
|
32773
34106
|
const cycle = visit(dep);
|
|
32774
34107
|
if (cycle) return cycle;
|
|
32775
34108
|
}
|
|
32776
|
-
|
|
34109
|
+
path37.pop();
|
|
32777
34110
|
visiting.delete(id);
|
|
32778
34111
|
visited.add(id);
|
|
32779
34112
|
return void 0;
|
|
@@ -34157,14 +35490,224 @@ var init_settings = __esm({
|
|
|
34157
35490
|
}
|
|
34158
35491
|
});
|
|
34159
35492
|
|
|
35493
|
+
// src/ui/conversations.ts
|
|
35494
|
+
import { mkdir as mkdir15, readFile as readFile18, readdir as readdir4, rm as rm4, writeFile as writeFile15 } from "node:fs/promises";
|
|
35495
|
+
import path35 from "node:path";
|
|
35496
|
+
function createConversationRecord(input2) {
|
|
35497
|
+
const timestamp = input2.now ?? Date.now();
|
|
35498
|
+
return {
|
|
35499
|
+
id: sanitizeConversationId(input2.id),
|
|
35500
|
+
title: input2.title?.trim() || "New session",
|
|
35501
|
+
createdAt: timestamp,
|
|
35502
|
+
updatedAt: timestamp,
|
|
35503
|
+
cwd: path35.resolve(input2.cwd),
|
|
35504
|
+
modelHistory: cleanModelHistory(input2.history ?? []),
|
|
35505
|
+
snapshot: input2.snapshot
|
|
35506
|
+
};
|
|
35507
|
+
}
|
|
35508
|
+
async function loadConversationIndex(storageDir = defaultDemianStorageDir()) {
|
|
35509
|
+
const index = await readJson(path35.join(storageDir, CONVERSATION_INDEX_FILE));
|
|
35510
|
+
const conversations = Array.isArray(index?.conversations) ? index.conversations.map((item) => {
|
|
35511
|
+
if (!item || typeof item !== "object") return void 0;
|
|
35512
|
+
const object2 = item;
|
|
35513
|
+
const id = typeof object2.id === "string" ? sanitizeConversationId(object2.id) : "";
|
|
35514
|
+
if (!id) return void 0;
|
|
35515
|
+
return {
|
|
35516
|
+
id,
|
|
35517
|
+
title: typeof object2.title === "string" && object2.title.trim() ? object2.title.trim() : "New session",
|
|
35518
|
+
updatedAt: numberOrNow(object2.updatedAt),
|
|
35519
|
+
cwd: typeof object2.cwd === "string" ? object2.cwd : void 0
|
|
35520
|
+
};
|
|
35521
|
+
}).filter((item) => Boolean(item)) : [];
|
|
35522
|
+
return {
|
|
35523
|
+
selectedSessionId: typeof index?.selectedSessionId === "string" ? sanitizeConversationId(index.selectedSessionId) : void 0,
|
|
35524
|
+
conversations
|
|
35525
|
+
};
|
|
35526
|
+
}
|
|
35527
|
+
async function loadConversationRecords(storageDir = defaultDemianStorageDir()) {
|
|
35528
|
+
const index = await loadConversationIndex(storageDir);
|
|
35529
|
+
const ids = new Set(index.conversations.map((item) => item.id));
|
|
35530
|
+
for (const id of await listConversationRecordIds(storageDir)) ids.add(id);
|
|
35531
|
+
const records = (await Promise.all(
|
|
35532
|
+
[...ids].map(async (id) => {
|
|
35533
|
+
const item = await readJson(conversationRecordPath(storageDir, id));
|
|
35534
|
+
return normalizeConversationRecord(item, id);
|
|
35535
|
+
})
|
|
35536
|
+
)).filter((item) => Boolean(item));
|
|
35537
|
+
records.sort((a, b2) => b2.updatedAt - a.updatedAt);
|
|
35538
|
+
return { selectedSessionId: index.selectedSessionId, records };
|
|
35539
|
+
}
|
|
35540
|
+
async function saveConversationRecords(storageDir, records, selectedSessionId) {
|
|
35541
|
+
const root = storageDir ?? defaultDemianStorageDir();
|
|
35542
|
+
const kept = [...records].sort((a, b2) => b2.updatedAt - a.updatedAt).slice(0, MAX_STORED_CONVERSATIONS).map((record) => ({ ...record, id: sanitizeConversationId(record.id), modelHistory: cleanModelHistory(record.modelHistory) }));
|
|
35543
|
+
await mkdir15(path35.join(root, CONVERSATIONS_DIR), { recursive: true });
|
|
35544
|
+
for (const record of kept) {
|
|
35545
|
+
await writeJson(conversationRecordPath(root, record.id), {
|
|
35546
|
+
version: 1,
|
|
35547
|
+
id: record.id,
|
|
35548
|
+
title: record.title,
|
|
35549
|
+
createdAt: record.createdAt,
|
|
35550
|
+
updatedAt: record.updatedAt,
|
|
35551
|
+
cwd: record.cwd,
|
|
35552
|
+
modelHistory: record.modelHistory,
|
|
35553
|
+
snapshot: record.snapshot
|
|
35554
|
+
});
|
|
35555
|
+
}
|
|
35556
|
+
await writeJson(path35.join(root, CONVERSATION_INDEX_FILE), {
|
|
35557
|
+
version: 1,
|
|
35558
|
+
selectedSessionId,
|
|
35559
|
+
conversations: kept.map((record) => ({
|
|
35560
|
+
id: record.id,
|
|
35561
|
+
title: record.title,
|
|
35562
|
+
updatedAt: record.updatedAt,
|
|
35563
|
+
cwd: record.cwd,
|
|
35564
|
+
path: conversationDir(root, record.id)
|
|
35565
|
+
}))
|
|
35566
|
+
});
|
|
35567
|
+
}
|
|
35568
|
+
async function deleteConversationRecord(storageDir, id) {
|
|
35569
|
+
const root = storageDir ?? defaultDemianStorageDir();
|
|
35570
|
+
await rm4(conversationDir(root, id), { recursive: true, force: true });
|
|
35571
|
+
}
|
|
35572
|
+
function findConversation(records, target) {
|
|
35573
|
+
const value = target?.trim();
|
|
35574
|
+
if (!value) return void 0;
|
|
35575
|
+
const index = Number(value);
|
|
35576
|
+
if (Number.isInteger(index) && index >= 1 && index <= records.length) return records[index - 1];
|
|
35577
|
+
const normalized = value.toLowerCase();
|
|
35578
|
+
return records.find((record) => record.id === value || record.id.startsWith(value)) ?? records.find((record) => record.title.toLowerCase() === normalized) ?? records.find((record) => record.title.toLowerCase().includes(normalized));
|
|
35579
|
+
}
|
|
35580
|
+
function sortConversationRecords(records, cwd) {
|
|
35581
|
+
const resolvedCwd = path35.resolve(cwd);
|
|
35582
|
+
return [...records].sort((a, b2) => {
|
|
35583
|
+
const aCurrent = isConversationForCwd(a, resolvedCwd) ? 0 : 1;
|
|
35584
|
+
const bCurrent = isConversationForCwd(b2, resolvedCwd) ? 0 : 1;
|
|
35585
|
+
if (aCurrent !== bCurrent) return aCurrent - bCurrent;
|
|
35586
|
+
const statusDelta = conversationStatusRank(conversationRuntimeStatus(a, resolvedCwd)) - conversationStatusRank(conversationRuntimeStatus(b2, resolvedCwd));
|
|
35587
|
+
if (statusDelta !== 0) return statusDelta;
|
|
35588
|
+
return b2.updatedAt - a.updatedAt;
|
|
35589
|
+
});
|
|
35590
|
+
}
|
|
35591
|
+
function conversationRuntimeStatus(record, cwd) {
|
|
35592
|
+
if (record.snapshot?.inputMode === "running") return "running";
|
|
35593
|
+
return isConversationForCwd(record, cwd) ? "ready" : "stored";
|
|
35594
|
+
}
|
|
35595
|
+
function isConversationForCwd(record, cwd) {
|
|
35596
|
+
return path35.resolve(record.cwd) === path35.resolve(cwd);
|
|
35597
|
+
}
|
|
35598
|
+
function conversationSummaryLine(record, index, activeId) {
|
|
35599
|
+
const active = record.id === activeId ? "*" : " ";
|
|
35600
|
+
const age = formatRelativeAge(Date.now() - record.updatedAt);
|
|
35601
|
+
return `${active} ${index + 1}. ${record.title} ${record.id} ${age} ${record.cwd}`;
|
|
35602
|
+
}
|
|
35603
|
+
function conversationStatusRank(status) {
|
|
35604
|
+
if (status === "running") return 0;
|
|
35605
|
+
if (status === "ready") return 1;
|
|
35606
|
+
return 2;
|
|
35607
|
+
}
|
|
35608
|
+
function titleFromHistory(history, fallback = "New session") {
|
|
35609
|
+
const firstUser = history.find((message) => message.role === "user" && typeof message.content === "string");
|
|
35610
|
+
return firstLine(firstUser?.content ?? fallback);
|
|
35611
|
+
}
|
|
35612
|
+
function cleanModelHistory(history) {
|
|
35613
|
+
return history.filter((message) => !isInternalModelHistoryMessage(message)).slice(-MAX_MODEL_HISTORY);
|
|
35614
|
+
}
|
|
35615
|
+
function conversationDir(storageDir, id) {
|
|
35616
|
+
return path35.join(storageDir, CONVERSATIONS_DIR, sanitizeConversationId(id));
|
|
35617
|
+
}
|
|
35618
|
+
function conversationRecordPath(storageDir, id) {
|
|
35619
|
+
return path35.join(conversationDir(storageDir, id), CONVERSATION_FILE);
|
|
35620
|
+
}
|
|
35621
|
+
async function listConversationRecordIds(storageDir) {
|
|
35622
|
+
try {
|
|
35623
|
+
const entries = await readdir4(path35.join(storageDir, CONVERSATIONS_DIR), { withFileTypes: true });
|
|
35624
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => sanitizeConversationId(entry.name)).filter(Boolean);
|
|
35625
|
+
} catch {
|
|
35626
|
+
return [];
|
|
35627
|
+
}
|
|
35628
|
+
}
|
|
35629
|
+
async function readJson(filePath) {
|
|
35630
|
+
try {
|
|
35631
|
+
return JSON.parse(await readFile18(filePath, "utf8"));
|
|
35632
|
+
} catch {
|
|
35633
|
+
return void 0;
|
|
35634
|
+
}
|
|
35635
|
+
}
|
|
35636
|
+
async function writeJson(filePath, value) {
|
|
35637
|
+
await mkdir15(path35.dirname(filePath), { recursive: true });
|
|
35638
|
+
await writeFile15(filePath, `${JSON.stringify(value, null, 2)}
|
|
35639
|
+
`, "utf8");
|
|
35640
|
+
}
|
|
35641
|
+
function normalizeConversationRecord(value, fallbackId) {
|
|
35642
|
+
if (!value || typeof value !== "object") return void 0;
|
|
35643
|
+
const object2 = value;
|
|
35644
|
+
const id = sanitizeConversationId(typeof object2.id === "string" ? object2.id : fallbackId);
|
|
35645
|
+
if (!id) return void 0;
|
|
35646
|
+
const history = Array.isArray(object2.modelHistory) ? object2.modelHistory.filter(isMessage) : [];
|
|
35647
|
+
const snapshot = object2.snapshot && typeof object2.snapshot === "object" && !Array.isArray(object2.snapshot) ? object2.snapshot : void 0;
|
|
35648
|
+
return {
|
|
35649
|
+
id,
|
|
35650
|
+
title: typeof object2.title === "string" && object2.title.trim() ? object2.title.trim() : titleFromHistory(history),
|
|
35651
|
+
createdAt: numberOrNow(object2.createdAt),
|
|
35652
|
+
updatedAt: numberOrNow(object2.updatedAt),
|
|
35653
|
+
cwd: typeof object2.cwd === "string" && object2.cwd.trim() ? object2.cwd : process.cwd(),
|
|
35654
|
+
modelHistory: cleanModelHistory(history),
|
|
35655
|
+
snapshot
|
|
35656
|
+
};
|
|
35657
|
+
}
|
|
35658
|
+
function isMessage(value) {
|
|
35659
|
+
if (!value || typeof value !== "object") return false;
|
|
35660
|
+
const message = value;
|
|
35661
|
+
if (message.role === "user") return typeof message.content === "string" || Array.isArray(message.content);
|
|
35662
|
+
if (message.role === "assistant") return message.content === void 0 || message.content === null || typeof message.content === "string" || Array.isArray(message.toolCalls);
|
|
35663
|
+
if (message.role === "tool") return typeof message.toolCallId === "string" && typeof message.name === "string" && typeof message.content === "string";
|
|
35664
|
+
if (message.role === "system") return typeof message.content === "string";
|
|
35665
|
+
return false;
|
|
35666
|
+
}
|
|
35667
|
+
function isInternalModelHistoryMessage(message) {
|
|
35668
|
+
return message.role === "user" && typeof message.content === "string" && /^You are running as sub agent:/i.test(message.content.trim());
|
|
35669
|
+
}
|
|
35670
|
+
function sanitizeConversationId(id) {
|
|
35671
|
+
return String(id || "conversation").replace(/[^a-zA-Z0-9._-]+/g, "_") || "conversation";
|
|
35672
|
+
}
|
|
35673
|
+
function numberOrNow(value) {
|
|
35674
|
+
return typeof value === "number" && Number.isFinite(value) ? value : Date.now();
|
|
35675
|
+
}
|
|
35676
|
+
function firstLine(value) {
|
|
35677
|
+
const line = value.replace(/\s+/g, " ").trim();
|
|
35678
|
+
if (!line) return "New session";
|
|
35679
|
+
return line.length > 60 ? `${line.slice(0, 57)}...` : line;
|
|
35680
|
+
}
|
|
35681
|
+
function formatRelativeAge(ms2) {
|
|
35682
|
+
const seconds = Math.max(0, Math.floor(ms2 / 1e3));
|
|
35683
|
+
if (seconds < 60) return `${seconds}s ago`;
|
|
35684
|
+
const minutes = Math.floor(seconds / 60);
|
|
35685
|
+
if (minutes < 60) return `${minutes}m ago`;
|
|
35686
|
+
const hours = Math.floor(minutes / 60);
|
|
35687
|
+
if (hours < 48) return `${hours}h ago`;
|
|
35688
|
+
return `${Math.floor(hours / 24)}d ago`;
|
|
35689
|
+
}
|
|
35690
|
+
var CONVERSATIONS_DIR, CONVERSATION_INDEX_FILE, CONVERSATION_FILE, MAX_STORED_CONVERSATIONS, MAX_MODEL_HISTORY;
|
|
35691
|
+
var init_conversations = __esm({
|
|
35692
|
+
"src/ui/conversations.ts"() {
|
|
35693
|
+
"use strict";
|
|
35694
|
+
init_transcript();
|
|
35695
|
+
CONVERSATIONS_DIR = "conversations";
|
|
35696
|
+
CONVERSATION_INDEX_FILE = "conversations.json";
|
|
35697
|
+
CONVERSATION_FILE = "conversation.json";
|
|
35698
|
+
MAX_STORED_CONVERSATIONS = 40;
|
|
35699
|
+
MAX_MODEL_HISTORY = 80;
|
|
35700
|
+
}
|
|
35701
|
+
});
|
|
35702
|
+
|
|
34160
35703
|
// src/ui/tui/controller.ts
|
|
34161
35704
|
var controller_exports = {};
|
|
34162
35705
|
__export(controller_exports, {
|
|
34163
35706
|
runTuiSession: () => runTuiSession
|
|
34164
35707
|
});
|
|
34165
|
-
import
|
|
35708
|
+
import path36 from "node:path";
|
|
34166
35709
|
async function runTuiSession(flags, store) {
|
|
34167
|
-
const cwd =
|
|
35710
|
+
const cwd = path36.resolve(flags.cwd ?? process.cwd());
|
|
34168
35711
|
const eventBus = new EventBus();
|
|
34169
35712
|
eventBus.subscribe((event) => store.handleEvent(event));
|
|
34170
35713
|
const loadedConfig = await loadConfig({ cwd, configPath: flags.configPath });
|
|
@@ -34196,10 +35739,20 @@ async function runTuiSession(flags, store) {
|
|
|
34196
35739
|
}
|
|
34197
35740
|
});
|
|
34198
35741
|
let nextPrompt = flags.prompt;
|
|
34199
|
-
|
|
35742
|
+
const conversationsEnabled = flags.conversationManagement === true;
|
|
35743
|
+
const conversationState = conversationsEnabled ? await initializeConversationState(cwd, flags) : void 0;
|
|
35744
|
+
let currentConversation = conversationState?.current;
|
|
35745
|
+
const conversationRecords = conversationState?.records ?? /* @__PURE__ */ new Map();
|
|
35746
|
+
const shouldShowStartupSessionSelector = conversationsEnabled && !flags.prompt.trim() && !flags.sessionId;
|
|
35747
|
+
let history = flags.initialHistory ? [...flags.initialHistory] : currentConversation?.modelHistory ? [...currentConversation.modelHistory] : [];
|
|
34200
35748
|
let lastExternalSessionKey;
|
|
34201
|
-
|
|
34202
|
-
const
|
|
35749
|
+
let externalSessions = new ClaudeCodeSessionMap();
|
|
35750
|
+
const runtimeByConversation = /* @__PURE__ */ new Map();
|
|
35751
|
+
let rootSessionId = currentConversation?.id ?? flags.sessionId ?? createRootSessionId();
|
|
35752
|
+
if (currentConversation && !shouldShowStartupSessionSelector) {
|
|
35753
|
+
store.restoreConversationSnapshot(currentConversation.snapshot, { sessionId: currentConversation.id, title: currentConversation.title, cwd: currentConversation.cwd });
|
|
35754
|
+
runtimeByConversation.set(currentConversation.id, { externalSessions, lastExternalSessionKey });
|
|
35755
|
+
}
|
|
34203
35756
|
const goalTitleGenerator = async (input2) => {
|
|
34204
35757
|
const selection = store.currentSelection();
|
|
34205
35758
|
const runtime = resolveProviderRuntimeConfig(config, selection);
|
|
@@ -34217,6 +35770,14 @@ async function runTuiSession(flags, store) {
|
|
|
34217
35770
|
if (resolved.kind === "external-agent") return input2.objective.trim().split(/\s+/).slice(0, 8).join(" ");
|
|
34218
35771
|
return summarizeGoalTitleWithProvider({ ...input2, provider: resolved.provider, model: resolved.model });
|
|
34219
35772
|
};
|
|
35773
|
+
if (shouldShowStartupSessionSelector) {
|
|
35774
|
+
const selected = await store.requestSessionSelection(startupSessionOptions());
|
|
35775
|
+
if (selected.kind === "exit" || store.exitRequested()) {
|
|
35776
|
+
await saveCurrentSelection();
|
|
35777
|
+
return 0;
|
|
35778
|
+
}
|
|
35779
|
+
await applyStartupSessionSelection(selected);
|
|
35780
|
+
}
|
|
34220
35781
|
for (; ; ) {
|
|
34221
35782
|
const prompt = await store.requestPrompt(nextPrompt);
|
|
34222
35783
|
nextPrompt = void 0;
|
|
@@ -34225,11 +35786,17 @@ async function runTuiSession(flags, store) {
|
|
|
34225
35786
|
return 0;
|
|
34226
35787
|
}
|
|
34227
35788
|
if (!prompt) return 0;
|
|
35789
|
+
const sessionCommand = parseSessionCommand(prompt);
|
|
35790
|
+
if (sessionCommand) {
|
|
35791
|
+
await handleSessionCommand(sessionCommand);
|
|
35792
|
+
continue;
|
|
35793
|
+
}
|
|
34228
35794
|
if (isCompactCommand(prompt)) {
|
|
34229
35795
|
const result = compactInteractiveHistory(history, config.context.main);
|
|
34230
35796
|
history = result.messages;
|
|
34231
35797
|
store.prepareForPrompt("waiting for next message");
|
|
34232
35798
|
store.markHistoryCompacted(result);
|
|
35799
|
+
await persistCurrentConversation();
|
|
34233
35800
|
continue;
|
|
34234
35801
|
}
|
|
34235
35802
|
const mode = resolveAgentMode(config, flags.mode);
|
|
@@ -34381,6 +35948,7 @@ async function runTuiSession(flags, store) {
|
|
|
34381
35948
|
history = interactiveHistoryFromRunMessages(result.messages);
|
|
34382
35949
|
lastExternalSessionKey = externalSessionKey ?? lastExternalSessionKey;
|
|
34383
35950
|
}
|
|
35951
|
+
await persistCurrentConversation();
|
|
34384
35952
|
} catch (error) {
|
|
34385
35953
|
store.setStopTask(void 0);
|
|
34386
35954
|
if (activeAbort?.signal.aborted) {
|
|
@@ -34393,6 +35961,7 @@ async function runTuiSession(flags, store) {
|
|
|
34393
35961
|
store.setStopTask(void 0);
|
|
34394
35962
|
}
|
|
34395
35963
|
if (store.exitRequested()) {
|
|
35964
|
+
await persistCurrentConversation();
|
|
34396
35965
|
await saveCurrentSelection();
|
|
34397
35966
|
return 0;
|
|
34398
35967
|
}
|
|
@@ -34401,6 +35970,161 @@ async function runTuiSession(flags, store) {
|
|
|
34401
35970
|
async function saveCurrentSelection() {
|
|
34402
35971
|
await saveSelection(store.currentSelection());
|
|
34403
35972
|
}
|
|
35973
|
+
async function handleSessionCommand(command) {
|
|
35974
|
+
if (!conversationsEnabled) {
|
|
35975
|
+
store.showSystemMessage("Sessions", "Session management is available in demian-cli TUI, but this embedded runtime lets the host manage sessions.");
|
|
35976
|
+
store.prepareForPrompt("waiting for next message");
|
|
35977
|
+
return;
|
|
35978
|
+
}
|
|
35979
|
+
if (!currentConversation) {
|
|
35980
|
+
currentConversation = createConversationRecord({ id: flags.sessionId ?? createRootSessionId(), cwd });
|
|
35981
|
+
conversationRecords.set(currentConversation.id, currentConversation);
|
|
35982
|
+
}
|
|
35983
|
+
if (command.action === "help") {
|
|
35984
|
+
store.showSystemMessage("Sessions", sessionUsage());
|
|
35985
|
+
store.prepareForPrompt("waiting for next message");
|
|
35986
|
+
return;
|
|
35987
|
+
}
|
|
35988
|
+
if (command.action === "list") {
|
|
35989
|
+
store.showSystemMessage("Sessions", sessionListMessage());
|
|
35990
|
+
store.prepareForPrompt("waiting for next message");
|
|
35991
|
+
return;
|
|
35992
|
+
}
|
|
35993
|
+
if (command.action === "current") {
|
|
35994
|
+
store.showSystemMessage("Current Session", conversationSummaryLine(currentConversation, sortedConversations().findIndex((item) => item.id === currentConversation?.id), currentConversation.id));
|
|
35995
|
+
store.prepareForPrompt("waiting for next message");
|
|
35996
|
+
return;
|
|
35997
|
+
}
|
|
35998
|
+
if (command.action === "new") {
|
|
35999
|
+
await persistCurrentConversation();
|
|
36000
|
+
const next = createConversationRecord({ id: createRootSessionId(), cwd, title: command.title });
|
|
36001
|
+
conversationRecords.set(next.id, next);
|
|
36002
|
+
await switchConversation(next);
|
|
36003
|
+
store.prepareForPrompt(`new session: ${next.title}`);
|
|
36004
|
+
await persistCurrentConversation();
|
|
36005
|
+
return;
|
|
36006
|
+
}
|
|
36007
|
+
if (command.action === "switch") {
|
|
36008
|
+
const target = findConversation(sortedConversations(), command.target);
|
|
36009
|
+
if (!target) {
|
|
36010
|
+
store.showSystemMessage("Sessions", `No session matched "${command.target ?? ""}".
|
|
36011
|
+
|
|
36012
|
+
${sessionListMessage()}`);
|
|
36013
|
+
store.prepareForPrompt("waiting for next message");
|
|
36014
|
+
return;
|
|
36015
|
+
}
|
|
36016
|
+
await persistCurrentConversation();
|
|
36017
|
+
await switchConversation(target);
|
|
36018
|
+
store.prepareForPrompt(`switched session: ${target.title}`);
|
|
36019
|
+
await persistCurrentConversation();
|
|
36020
|
+
return;
|
|
36021
|
+
}
|
|
36022
|
+
if (command.action === "delete") {
|
|
36023
|
+
const target = findConversation(sortedConversations(), command.target);
|
|
36024
|
+
if (!target) {
|
|
36025
|
+
store.showSystemMessage("Sessions", `No session matched "${command.target ?? ""}".`);
|
|
36026
|
+
store.prepareForPrompt("waiting for next message");
|
|
36027
|
+
return;
|
|
36028
|
+
}
|
|
36029
|
+
conversationRecords.delete(target.id);
|
|
36030
|
+
runtimeByConversation.delete(target.id);
|
|
36031
|
+
await deleteConversationRecord(flags.conversationStorageDir, target.id);
|
|
36032
|
+
if (currentConversation?.id === target.id) {
|
|
36033
|
+
const next = sortedConversations()[0] ?? createConversationRecord({ id: createRootSessionId(), cwd });
|
|
36034
|
+
conversationRecords.set(next.id, next);
|
|
36035
|
+
await switchConversation(next);
|
|
36036
|
+
}
|
|
36037
|
+
store.prepareForPrompt(`deleted session: ${target.title}`);
|
|
36038
|
+
await persistCurrentConversation();
|
|
36039
|
+
return;
|
|
36040
|
+
}
|
|
36041
|
+
if (command.action === "rename") {
|
|
36042
|
+
const title = command.title?.trim();
|
|
36043
|
+
if (!title) {
|
|
36044
|
+
store.showSystemMessage("Sessions", "Usage: /session rename <title>");
|
|
36045
|
+
store.prepareForPrompt("waiting for next message");
|
|
36046
|
+
return;
|
|
36047
|
+
}
|
|
36048
|
+
currentConversation.title = title;
|
|
36049
|
+
currentConversation.updatedAt = Date.now();
|
|
36050
|
+
store.prepareForPrompt(`renamed session: ${title}`);
|
|
36051
|
+
await persistCurrentConversation();
|
|
36052
|
+
return;
|
|
36053
|
+
}
|
|
36054
|
+
if (command.action === "clear") {
|
|
36055
|
+
history = [];
|
|
36056
|
+
currentConversation.modelHistory = [];
|
|
36057
|
+
currentConversation.snapshot = void 0;
|
|
36058
|
+
currentConversation.title = "New session";
|
|
36059
|
+
currentConversation.updatedAt = Date.now();
|
|
36060
|
+
store.clearConversation(currentConversation.title);
|
|
36061
|
+
store.prepareForPrompt("cleared current conversation");
|
|
36062
|
+
await persistCurrentConversation();
|
|
36063
|
+
}
|
|
36064
|
+
}
|
|
36065
|
+
function startupSessionOptions() {
|
|
36066
|
+
const records = sortedConversations();
|
|
36067
|
+
const sessionOptions = records.map((record) => ({
|
|
36068
|
+
kind: "session",
|
|
36069
|
+
id: record.id,
|
|
36070
|
+
title: record.title,
|
|
36071
|
+
cwd: record.cwd,
|
|
36072
|
+
status: conversationRuntimeStatus(record, cwd),
|
|
36073
|
+
updatedAt: record.updatedAt,
|
|
36074
|
+
currentWorkspace: path36.resolve(record.cwd) === cwd
|
|
36075
|
+
}));
|
|
36076
|
+
return [...sessionOptions, { kind: "new", title: "New session", cwd, status: "ready", currentWorkspace: true }];
|
|
36077
|
+
}
|
|
36078
|
+
async function applyStartupSessionSelection(selection) {
|
|
36079
|
+
if (selection.kind === "new") {
|
|
36080
|
+
const next = createConversationRecord({ id: createRootSessionId(), cwd });
|
|
36081
|
+
conversationRecords.set(next.id, next);
|
|
36082
|
+
await switchConversation(next);
|
|
36083
|
+
store.prepareForPrompt("new session ready");
|
|
36084
|
+
await saveConversationRecords(flags.conversationStorageDir, [...conversationRecords.values()], next.id);
|
|
36085
|
+
return;
|
|
36086
|
+
}
|
|
36087
|
+
const target = conversationRecords.get(selection.id) ?? findConversation(sortedConversations(), selection.id);
|
|
36088
|
+
if (!target) {
|
|
36089
|
+
const next = createConversationRecord({ id: createRootSessionId(), cwd });
|
|
36090
|
+
conversationRecords.set(next.id, next);
|
|
36091
|
+
await switchConversation(next);
|
|
36092
|
+
store.prepareForPrompt("new session ready");
|
|
36093
|
+
await saveConversationRecords(flags.conversationStorageDir, [...conversationRecords.values()], next.id);
|
|
36094
|
+
return;
|
|
36095
|
+
}
|
|
36096
|
+
await switchConversation(target);
|
|
36097
|
+
store.prepareForPrompt(`session ready: ${target.title}`);
|
|
36098
|
+
await saveConversationRecords(flags.conversationStorageDir, [...conversationRecords.values()], target.id);
|
|
36099
|
+
}
|
|
36100
|
+
async function switchConversation(record) {
|
|
36101
|
+
currentConversation = record;
|
|
36102
|
+
rootSessionId = record.id;
|
|
36103
|
+
history = [...record.modelHistory];
|
|
36104
|
+
const runtime = runtimeByConversation.get(record.id) ?? { externalSessions: new ClaudeCodeSessionMap(), lastExternalSessionKey: void 0 };
|
|
36105
|
+
externalSessions = runtime.externalSessions;
|
|
36106
|
+
lastExternalSessionKey = runtime.lastExternalSessionKey;
|
|
36107
|
+
runtimeByConversation.set(record.id, runtime);
|
|
36108
|
+
store.restoreConversationSnapshot(record.snapshot, { sessionId: record.id, title: record.title, cwd: record.cwd || cwd });
|
|
36109
|
+
}
|
|
36110
|
+
async function persistCurrentConversation() {
|
|
36111
|
+
if (!conversationsEnabled || !currentConversation) return;
|
|
36112
|
+
currentConversation.modelHistory = cleanModelHistory(history);
|
|
36113
|
+
if (currentConversation.title === "New session" && currentConversation.modelHistory.length > 0) currentConversation.title = titleFromHistory(currentConversation.modelHistory);
|
|
36114
|
+
currentConversation.snapshot = store.conversationSnapshot();
|
|
36115
|
+
currentConversation.updatedAt = Date.now();
|
|
36116
|
+
conversationRecords.set(currentConversation.id, currentConversation);
|
|
36117
|
+
runtimeByConversation.set(currentConversation.id, { externalSessions, lastExternalSessionKey });
|
|
36118
|
+
await saveConversationRecords(flags.conversationStorageDir, [...conversationRecords.values()], currentConversation.id);
|
|
36119
|
+
}
|
|
36120
|
+
function sortedConversations() {
|
|
36121
|
+
return sortConversationRecords([...conversationRecords.values()], cwd);
|
|
36122
|
+
}
|
|
36123
|
+
function sessionListMessage() {
|
|
36124
|
+
const records = sortedConversations();
|
|
36125
|
+
if (!records.length) return "No saved sessions.";
|
|
36126
|
+
return ["Saved sessions:", ...records.map((record, index) => conversationSummaryLine(record, index, currentConversation?.id)), "", "Use /session switch <number|id|title> to open one."].join("\n");
|
|
36127
|
+
}
|
|
34404
36128
|
async function saveSelection(selection) {
|
|
34405
36129
|
if (!shouldPersistSelection(selection)) return;
|
|
34406
36130
|
const key = preferenceKey(selection);
|
|
@@ -34412,6 +36136,34 @@ async function runTuiSession(flags, store) {
|
|
|
34412
36136
|
function isGoalStateClearingAction(action) {
|
|
34413
36137
|
return action === "status" || action === "pause" || action === "resume";
|
|
34414
36138
|
}
|
|
36139
|
+
async function initializeConversationState(cwd, flags) {
|
|
36140
|
+
const loaded = await loadConversationRecords(flags.conversationStorageDir);
|
|
36141
|
+
const records = new Map(loaded.records.map((record) => [record.id, record]));
|
|
36142
|
+
const shouldResumeSelected = !flags.prompt.trim();
|
|
36143
|
+
const orderedRecords = sortConversationRecords([...records.values()], cwd);
|
|
36144
|
+
const preferred = (flags.sessionId ? findConversation(orderedRecords, flags.sessionId) : void 0) ?? (shouldResumeSelected && loaded.selectedSessionId ? findConversation(orderedRecords, loaded.selectedSessionId) : void 0) ?? (shouldResumeSelected ? orderedRecords[0] : void 0);
|
|
36145
|
+
const current = preferred ?? (flags.prompt.trim() || flags.sessionId || flags.initialHistory?.length ? createConversationRecord({
|
|
36146
|
+
id: flags.sessionId ?? createRootSessionId(),
|
|
36147
|
+
cwd,
|
|
36148
|
+
history: flags.initialHistory
|
|
36149
|
+
}) : void 0);
|
|
36150
|
+
if (current && flags.initialHistory?.length) current.modelHistory = cleanModelHistory(flags.initialHistory);
|
|
36151
|
+
if (current) records.set(current.id, current);
|
|
36152
|
+
return { records, current };
|
|
36153
|
+
}
|
|
36154
|
+
function sessionUsage() {
|
|
36155
|
+
return [
|
|
36156
|
+
"Usage:",
|
|
36157
|
+
" /session list",
|
|
36158
|
+
" /session new [title]",
|
|
36159
|
+
" /session switch <number|id|title>",
|
|
36160
|
+
" /session rename <title>",
|
|
36161
|
+
" /session delete <number|id|title>",
|
|
36162
|
+
" /session clear",
|
|
36163
|
+
"",
|
|
36164
|
+
"Aliases: /sessions, /conversation, /conversations, /conv"
|
|
36165
|
+
].join("\n");
|
|
36166
|
+
}
|
|
34415
36167
|
var init_controller = __esm({
|
|
34416
36168
|
"src/ui/tui/controller.ts"() {
|
|
34417
36169
|
"use strict";
|
|
@@ -34432,6 +36184,7 @@ var init_controller = __esm({
|
|
|
34432
36184
|
init_history();
|
|
34433
36185
|
init_preferences();
|
|
34434
36186
|
init_settings();
|
|
36187
|
+
init_conversations();
|
|
34435
36188
|
}
|
|
34436
36189
|
});
|
|
34437
36190
|
|
|
@@ -35247,8 +37000,8 @@ async function fileExists2(filePath) {
|
|
|
35247
37000
|
}
|
|
35248
37001
|
async function readJsonSafe(filePath) {
|
|
35249
37002
|
try {
|
|
35250
|
-
const { readFile:
|
|
35251
|
-
const text = await
|
|
37003
|
+
const { readFile: readFile19 } = await import("node:fs/promises");
|
|
37004
|
+
const text = await readFile19(filePath, "utf8");
|
|
35252
37005
|
return JSON.parse(text);
|
|
35253
37006
|
} catch {
|
|
35254
37007
|
return void 0;
|
|
@@ -35389,7 +37142,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
35389
37142
|
const store = new TuiStore2();
|
|
35390
37143
|
const instance = render(React2.createElement(TuiApp2, { store, version: packageVersion() }));
|
|
35391
37144
|
try {
|
|
35392
|
-
const code = await runTuiSession2(flags, store);
|
|
37145
|
+
const code = await runTuiSession2({ ...flags, conversationManagement: true }, store);
|
|
35393
37146
|
setTimeout(() => instance.unmount(), 100);
|
|
35394
37147
|
await instance.waitUntilExit();
|
|
35395
37148
|
return code;
|
|
@@ -35542,6 +37295,8 @@ Default:
|
|
|
35542
37295
|
After each answer, the TUI returns to standby for the next message.
|
|
35543
37296
|
Use /cowork <task> to explicitly ask Demian to coordinate cowork sub agents in multi-agent mode.
|
|
35544
37297
|
Use /compact to compact current history, /stop to stop active work, and /exit or /quit to close the TUI.
|
|
37298
|
+
Use /session list, /session new, /session switch <number|id|title>, /session rename <title>,
|
|
37299
|
+
and /session delete <number|id|title> to manage saved CLI conversations.
|
|
35545
37300
|
Press Esc then q to quit, Esc then s to stop a running task, and Esc then u to clear the composer.
|
|
35546
37301
|
Tool approvals show the requested command/path in a permission dialog.
|
|
35547
37302
|
Press y to allow once, a to always allow the grant scope, or n/Enter to deny.
|