demian-cli 1.0.9 → 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 +2236 -307
- package/dist/vscode-worker.mjs +654 -41
- 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;
|
|
@@ -25727,7 +26013,7 @@ var init_store = __esm({
|
|
|
25727
26013
|
}
|
|
25728
26014
|
markTaskFailed(message) {
|
|
25729
26015
|
const lines = [message];
|
|
25730
|
-
if (this.#lastRetryPrompt()) lines.push("Press
|
|
26016
|
+
if (this.#lastRetryPrompt()) lines.push("Press Esc then r or type /retry to run the last task again.");
|
|
25731
26017
|
this.#append({ kind: "warning", title: "Task Failed", lines });
|
|
25732
26018
|
this.#state.status.reason = "error";
|
|
25733
26019
|
this.#state.inputMode = this.#exitRequested ? "done" : "prompt";
|
|
@@ -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,47 +27413,160 @@ 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
|
-
function TuiApp({ store }) {
|
|
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());
|
|
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);
|
|
26993
27441
|
const app = useApp();
|
|
26994
27442
|
useEffect(() => {
|
|
26995
|
-
const update = () =>
|
|
27443
|
+
const update = () => {
|
|
27444
|
+
const next = store.snapshot();
|
|
27445
|
+
setState(next);
|
|
27446
|
+
setPromptInput(next.promptInput);
|
|
27447
|
+
};
|
|
26996
27448
|
const unsubscribe = store.subscribe(update);
|
|
26997
27449
|
update();
|
|
26998
27450
|
return unsubscribe;
|
|
26999
27451
|
}, [store]);
|
|
27452
|
+
useEffect(() => enableEnhancedKeyboardInput(), []);
|
|
27000
27453
|
useEffect(() => {
|
|
27001
27454
|
if (!state.workPlan && state.inputMode !== "running" && state.inputMode !== "starting") return;
|
|
27002
27455
|
const timer = setInterval(() => setNow(Date.now()), 450);
|
|
27003
27456
|
return () => clearInterval(timer);
|
|
27004
27457
|
}, [state.workPlan?.planId, state.inputMode]);
|
|
27458
|
+
useEffect(() => {
|
|
27459
|
+
setShortcutMode(false);
|
|
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))];
|
|
27005
27473
|
useInput((input2, key) => {
|
|
27006
|
-
|
|
27007
|
-
if (key.ctrl && input2 === "c") {
|
|
27474
|
+
if (isCtrlCKeypress(input2, key)) {
|
|
27008
27475
|
store.requestExit();
|
|
27009
27476
|
app.exit();
|
|
27010
27477
|
return;
|
|
27011
27478
|
}
|
|
27012
|
-
if (key
|
|
27013
|
-
|
|
27014
|
-
|
|
27015
|
-
|
|
27016
|
-
|
|
27017
|
-
|
|
27479
|
+
if (isCtrlPKeypress(input2, key) && canUseCommandPalette(state)) {
|
|
27480
|
+
setCommandPaletteOpen((open4) => !open4);
|
|
27481
|
+
setCommandPaletteQuery("");
|
|
27482
|
+
setCommandPaletteCursor(0);
|
|
27483
|
+
setShortcutMode(false);
|
|
27484
|
+
setSlashCommandClosedPrefix(promptInput);
|
|
27018
27485
|
return;
|
|
27019
27486
|
}
|
|
27020
|
-
|
|
27021
|
-
|
|
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
|
+
}
|
|
27022
27513
|
return;
|
|
27023
27514
|
}
|
|
27024
|
-
if (
|
|
27025
|
-
|
|
27515
|
+
if (shortcutMode) {
|
|
27516
|
+
setShortcutMode(false);
|
|
27517
|
+
if (key.escape) return;
|
|
27518
|
+
const shortcut = input2.toLowerCase();
|
|
27519
|
+
if (shortcut === "q") {
|
|
27520
|
+
store.requestExit();
|
|
27521
|
+
app.exit();
|
|
27522
|
+
return;
|
|
27523
|
+
}
|
|
27524
|
+
if (shortcut === "s" && state.inputMode === "running") {
|
|
27525
|
+
store.stopActiveTask();
|
|
27526
|
+
return;
|
|
27527
|
+
}
|
|
27528
|
+
if (shortcut === "p" && state.inputMode === "prompt") {
|
|
27529
|
+
store.openProviderSelector();
|
|
27530
|
+
return;
|
|
27531
|
+
}
|
|
27532
|
+
if (shortcut === "a" && state.inputMode === "prompt") {
|
|
27533
|
+
store.openAgentSelector();
|
|
27534
|
+
return;
|
|
27535
|
+
}
|
|
27536
|
+
if (shortcut === "m" && state.inputMode === "prompt") {
|
|
27537
|
+
store.openModelEditor();
|
|
27538
|
+
return;
|
|
27539
|
+
}
|
|
27540
|
+
if (shortcut === "o" && state.inputMode === "prompt") {
|
|
27541
|
+
store.openPermissionPresetSelector();
|
|
27542
|
+
return;
|
|
27543
|
+
}
|
|
27544
|
+
if (shortcut === "u" && state.inputMode === "prompt") {
|
|
27545
|
+
store.clearPromptInput({ notify: false });
|
|
27546
|
+
setPromptInput("");
|
|
27547
|
+
clearPromptErrorPreview(setState);
|
|
27548
|
+
return;
|
|
27549
|
+
}
|
|
27550
|
+
if (shortcut === "d" && state.turnDiff) {
|
|
27551
|
+
store.toggleDiffExpanded();
|
|
27552
|
+
return;
|
|
27553
|
+
}
|
|
27554
|
+
if (shortcut === "t" && state.blocks.some((block) => block.kind === "tool")) {
|
|
27555
|
+
store.toggleLatestToolExpanded();
|
|
27556
|
+
return;
|
|
27557
|
+
}
|
|
27558
|
+
if (shortcut === "w" && (state.workPlan || state.inputMode === "running")) {
|
|
27559
|
+
store.toggleWorkPlanExpanded();
|
|
27560
|
+
return;
|
|
27561
|
+
}
|
|
27562
|
+
if (shortcut === "e" && state.pendingClaudeCodePlan) {
|
|
27563
|
+
store.usePendingClaudeCodePlan();
|
|
27564
|
+
return;
|
|
27565
|
+
}
|
|
27566
|
+
if (shortcut === "r" && state.canRetryLastPrompt) {
|
|
27567
|
+
store.retryLastPrompt();
|
|
27568
|
+
return;
|
|
27569
|
+
}
|
|
27026
27570
|
return;
|
|
27027
27571
|
}
|
|
27028
27572
|
if (state.permission) {
|
|
@@ -27032,6 +27576,31 @@ function TuiApp({ store }) {
|
|
|
27032
27576
|
if (normalized === "n" || key.return) store.answerPermission({ decision: "deny" });
|
|
27033
27577
|
return;
|
|
27034
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
|
+
}
|
|
27035
27604
|
if (state.inputMode === "provider") {
|
|
27036
27605
|
if (key.escape) {
|
|
27037
27606
|
store.closeSettings();
|
|
@@ -27094,10 +27663,6 @@ function TuiApp({ store }) {
|
|
|
27094
27663
|
store.closeSettings();
|
|
27095
27664
|
return;
|
|
27096
27665
|
}
|
|
27097
|
-
if (key.ctrl && input2 === "u") {
|
|
27098
|
-
store.clearModelInput();
|
|
27099
|
-
return;
|
|
27100
|
-
}
|
|
27101
27666
|
if (key.return) {
|
|
27102
27667
|
if (textInput) store.appendModelInput(textInput);
|
|
27103
27668
|
store.submitModelInput();
|
|
@@ -27111,83 +27676,534 @@ function TuiApp({ store }) {
|
|
|
27111
27676
|
return;
|
|
27112
27677
|
}
|
|
27113
27678
|
if (state.inputMode === "prompt" || state.inputMode === "running") {
|
|
27114
|
-
|
|
27115
|
-
|
|
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);
|
|
27116
27683
|
return;
|
|
27117
27684
|
}
|
|
27118
|
-
if (
|
|
27119
|
-
|
|
27685
|
+
if (slashCommands2.length > 0 && key.upArrow) {
|
|
27686
|
+
setSlashCommandCursor((cursor) => (cursor - 1 + slashCommands2.length) % slashCommands2.length);
|
|
27120
27687
|
return;
|
|
27121
27688
|
}
|
|
27122
|
-
if (
|
|
27123
|
-
|
|
27689
|
+
if (slashCommands2.length > 0 && key.downArrow) {
|
|
27690
|
+
setSlashCommandCursor((cursor) => (cursor + 1) % slashCommands2.length);
|
|
27124
27691
|
return;
|
|
27125
27692
|
}
|
|
27126
|
-
if (
|
|
27127
|
-
store
|
|
27693
|
+
if (slashCommands2.length > 0 && key.tab && slashCommand) {
|
|
27694
|
+
applySlashCommandDraft(store, setPromptInput, slashCommand, setSlashCommandClosedPrefix);
|
|
27695
|
+
clearPromptErrorPreview(setState);
|
|
27128
27696
|
return;
|
|
27129
27697
|
}
|
|
27130
|
-
if (
|
|
27131
|
-
store.
|
|
27698
|
+
if (state.inputMode === "prompt" && key.upArrow) {
|
|
27699
|
+
store.navigatePromptHistory(-1);
|
|
27132
27700
|
return;
|
|
27133
27701
|
}
|
|
27134
|
-
if (
|
|
27135
|
-
store.
|
|
27702
|
+
if (state.inputMode === "prompt" && key.downArrow) {
|
|
27703
|
+
store.navigatePromptHistory(1);
|
|
27136
27704
|
return;
|
|
27137
27705
|
}
|
|
27138
|
-
if (
|
|
27139
|
-
|
|
27706
|
+
if (key.escape) {
|
|
27707
|
+
setShortcutMode(true);
|
|
27140
27708
|
return;
|
|
27141
27709
|
}
|
|
27142
|
-
if (
|
|
27143
|
-
store
|
|
27710
|
+
if (isPromptNewlineKeypress(input2, key)) {
|
|
27711
|
+
appendPromptDraft(store, setPromptInput, `${textInput}
|
|
27712
|
+
`);
|
|
27713
|
+
clearPromptErrorPreview(setState);
|
|
27144
27714
|
return;
|
|
27145
27715
|
}
|
|
27146
|
-
if (key
|
|
27147
|
-
if (textInput
|
|
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);
|
|
27148
27723
|
store.submitPromptInput();
|
|
27149
27724
|
return;
|
|
27150
27725
|
}
|
|
27151
27726
|
if (key.backspace || key.delete) {
|
|
27152
|
-
store.backspacePromptInput();
|
|
27727
|
+
store.backspacePromptInput({ notify: false });
|
|
27728
|
+
setPromptInput((current) => Array.from(current).slice(0, -1).join(""));
|
|
27729
|
+
clearPromptErrorPreview(setState);
|
|
27153
27730
|
return;
|
|
27154
27731
|
}
|
|
27155
|
-
if (textInput)
|
|
27732
|
+
if (textInput) {
|
|
27733
|
+
appendPromptDraft(store, setPromptInput, textInput);
|
|
27734
|
+
clearPromptErrorPreview(setState);
|
|
27735
|
+
}
|
|
27156
27736
|
return;
|
|
27157
27737
|
}
|
|
27158
27738
|
});
|
|
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
|
+
}
|
|
27750
|
+
if (shouldShowEmptyState(state)) {
|
|
27751
|
+
return React.createElement(
|
|
27752
|
+
Box,
|
|
27753
|
+
shellProps,
|
|
27754
|
+
React.createElement(EmptyState, { state, version, shortcutMode, promptInput, slashCommandPalette, commandPalette })
|
|
27755
|
+
);
|
|
27756
|
+
}
|
|
27159
27757
|
return React.createElement(
|
|
27160
27758
|
Box,
|
|
27161
|
-
|
|
27162
|
-
React.createElement(StatusBar, { state, now: now2 }),
|
|
27163
|
-
React.createElement(
|
|
27164
|
-
|
|
27165
|
-
|
|
27166
|
-
|
|
27167
|
-
|
|
27168
|
-
|
|
27169
|
-
|
|
27759
|
+
shellProps,
|
|
27760
|
+
React.createElement(StatusBar, { state, now: now2, version }),
|
|
27761
|
+
React.createElement(
|
|
27762
|
+
Box,
|
|
27763
|
+
{ flexDirection: "column", flexGrow: 1, paddingX: 1 },
|
|
27764
|
+
React.createElement(shouldShowLoading(state) ? LoadingView : TranscriptView, { state }),
|
|
27765
|
+
React.createElement(Box, { flexGrow: 1 }),
|
|
27766
|
+
React.createElement(BottomStatusStack, { state, now: now2 }),
|
|
27767
|
+
React.createElement(InteractionPanel, { state, shortcutMode, promptInput, slashCommandPalette, commandPalette })
|
|
27768
|
+
)
|
|
27170
27769
|
);
|
|
27171
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
|
+
}
|
|
27172
28017
|
function textInputForKeypress(input2, key) {
|
|
27173
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 "";
|
|
27174
28022
|
return Array.from(input2).filter((char) => {
|
|
27175
28023
|
const codePoint = char.codePointAt(0) ?? 0;
|
|
27176
28024
|
return codePoint >= 32 && codePoint !== 127;
|
|
27177
28025
|
}).join("");
|
|
27178
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
|
+
}
|
|
27179
28091
|
function shouldShowLoading(state) {
|
|
27180
28092
|
return state.inputMode === "starting" || state.inputMode === "running" && state.blocks.length === 0 && !state.streamingText;
|
|
27181
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
|
+
}
|
|
28103
|
+
function shouldShowEmptyState(state) {
|
|
28104
|
+
return state.inputMode === "prompt" && !state.permission && state.blocks.length === 0 && !state.streamingText && !state.turnDiff && !state.workPlan && !state.goal;
|
|
28105
|
+
}
|
|
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();
|
|
28112
|
+
return React.createElement(
|
|
28113
|
+
Box,
|
|
28114
|
+
{ flexDirection: "column", flexGrow: 1 },
|
|
28115
|
+
React.createElement(Box, { height: topGap }),
|
|
28116
|
+
React.createElement(DemianWordmark),
|
|
28117
|
+
React.createElement(Box, { height: 1 }),
|
|
28118
|
+
React.createElement(SessionSelector, { state }),
|
|
28119
|
+
React.createElement(
|
|
28120
|
+
Box,
|
|
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}`)
|
|
28124
|
+
),
|
|
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 }),
|
|
28157
|
+
React.createElement(
|
|
28158
|
+
Box,
|
|
28159
|
+
{ flexGrow: 1 }
|
|
28160
|
+
)
|
|
28161
|
+
);
|
|
28162
|
+
}
|
|
28163
|
+
function SessionMetaBox({ state, version, marginTop = 1 }) {
|
|
28164
|
+
const width = promptPanelWidth();
|
|
28165
|
+
const compact = width < 68;
|
|
28166
|
+
const agent = shorten(state.selectedAgent ?? state.status.agent ?? "general", compact ? 14 : 18);
|
|
28167
|
+
const model = shorten(state.selection?.model ?? state.status.model ?? "model", compact ? Math.max(18, width - 14) : 30);
|
|
28168
|
+
const workspace = shorten(state.status.cwd ?? process.cwd(), compact ? Math.max(18, width - 18) : 46);
|
|
28169
|
+
const rows = compact ? [
|
|
28170
|
+
`agent ${agent} \xB7 perm ${state.permissionPreset}`,
|
|
28171
|
+
`model ${model}`,
|
|
28172
|
+
`workspace ${workspace}`,
|
|
28173
|
+
version ? `version v${version}` : void 0
|
|
28174
|
+
].filter(Boolean) : [
|
|
28175
|
+
`agent ${agent} \xB7 model ${model} \xB7 perm ${state.permissionPreset}`,
|
|
28176
|
+
`workspace ${workspace}${version ? ` \xB7 version v${version}` : ""}`
|
|
28177
|
+
];
|
|
28178
|
+
return React.createElement(
|
|
28179
|
+
Box,
|
|
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" }))
|
|
28182
|
+
);
|
|
28183
|
+
}
|
|
28184
|
+
function DemianWordmark() {
|
|
28185
|
+
if (terminalWidth() < 58) {
|
|
28186
|
+
return React.createElement(Box, { alignSelf: "center" }, React.createElement(Text, { color: "gray", bold: true }, "DEMIAN"));
|
|
28187
|
+
}
|
|
28188
|
+
return React.createElement(
|
|
28189
|
+
Box,
|
|
28190
|
+
{ alignSelf: "center", flexDirection: "column" },
|
|
28191
|
+
...DEMIAN_WORDMARK_LINES.map(
|
|
28192
|
+
(line, index) => React.createElement(Text, { key: index, color: index < 2 ? "gray" : "white", bold: true }, line)
|
|
28193
|
+
)
|
|
28194
|
+
);
|
|
28195
|
+
}
|
|
27182
28196
|
function LoadingView({ state }) {
|
|
27183
|
-
const title = state.inputMode === "starting" ? "
|
|
28197
|
+
const title = state.inputMode === "starting" ? "Demian runtime" : "Preparing session";
|
|
27184
28198
|
const message = state.activity || (state.inputMode === "starting" ? "Loading configuration" : "Starting session");
|
|
28199
|
+
const width = statusSurfaceWidth();
|
|
28200
|
+
const contentWidth = Math.max(24, width - 4);
|
|
27185
28201
|
return React.createElement(
|
|
27186
28202
|
Box,
|
|
27187
|
-
{ flexDirection: "column", marginTop: 1, borderStyle: "
|
|
27188
|
-
React.createElement(
|
|
27189
|
-
React.createElement(
|
|
27190
|
-
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" })
|
|
27191
28207
|
);
|
|
27192
28208
|
}
|
|
27193
28209
|
function contextEfficiencySummary(state) {
|
|
@@ -27207,103 +28223,116 @@ function contextEfficiencySummary(state) {
|
|
|
27207
28223
|
].filter(Boolean);
|
|
27208
28224
|
return parts.join(" | ");
|
|
27209
28225
|
}
|
|
27210
|
-
function StatusBar({ state, now: now2 }) {
|
|
28226
|
+
function StatusBar({ state, now: now2, version }) {
|
|
27211
28227
|
const status = state.status;
|
|
27212
|
-
const
|
|
27213
|
-
|
|
27214
|
-
|
|
27215
|
-
|
|
27216
|
-
status.agent ? `agent ${status.agent}` : void 0,
|
|
27217
|
-
status.cwd ? `cwd ${shorten(status.cwd, 48)}` : void 0,
|
|
27218
|
-
status.externalSessionId ? `cc session ${shorten(status.externalSessionId, 18)}` : void 0,
|
|
27219
|
-
status.reason ? `reason ${status.reason}` : void 0
|
|
27220
|
-
].filter(Boolean);
|
|
28228
|
+
const mode = tuiMode(state);
|
|
28229
|
+
const provider = state.selection?.providerName ?? status.provider;
|
|
28230
|
+
const model = state.selection?.model ?? status.model ?? "-";
|
|
28231
|
+
const meta = [provider, shorten(model, 32), state.permissionPreset, `v${version}`].filter(Boolean).join(" \xB7 ");
|
|
27221
28232
|
return React.createElement(
|
|
27222
28233
|
Box,
|
|
27223
|
-
{
|
|
27224
|
-
React.createElement(
|
|
27225
|
-
|
|
27226
|
-
|
|
28234
|
+
{ paddingX: 1, marginBottom: 1, justifyContent: "space-between" },
|
|
28235
|
+
React.createElement(
|
|
28236
|
+
Text,
|
|
28237
|
+
null,
|
|
28238
|
+
React.createElement(DemianTuiMark, { active: state.inputMode === "starting" || state.inputMode === "running", now: now2 }),
|
|
28239
|
+
React.createElement(Text, { color: "cyan", bold: true }, " Demian")
|
|
28240
|
+
),
|
|
28241
|
+
React.createElement(
|
|
28242
|
+
Text,
|
|
28243
|
+
null,
|
|
28244
|
+
React.createElement(Text, { color: mode.color }, mode.label),
|
|
28245
|
+
React.createElement(Text, { color: "gray" }, ` \xB7 ${meta}`)
|
|
28246
|
+
)
|
|
27227
28247
|
);
|
|
27228
28248
|
}
|
|
27229
28249
|
function DemianTuiMark({ active, now: now2 }) {
|
|
27230
28250
|
const frame = active ? Math.floor(now2 / 450) % 4 : 0;
|
|
27231
|
-
const
|
|
27232
|
-
const face = frame === 2 ? "o" : "*";
|
|
28251
|
+
const mark = active ? ["D>", "D*", "D+", "D*"][frame] : "D>";
|
|
27233
28252
|
return React.createElement(
|
|
27234
28253
|
Text,
|
|
27235
28254
|
{ color: "yellow", bold: true },
|
|
27236
|
-
`[${
|
|
28255
|
+
`[${mark}]`
|
|
27237
28256
|
);
|
|
27238
28257
|
}
|
|
27239
|
-
function
|
|
27240
|
-
|
|
27241
|
-
|
|
27242
|
-
if (
|
|
27243
|
-
|
|
27244
|
-
}
|
|
27245
|
-
|
|
27246
|
-
|
|
27247
|
-
return
|
|
27248
|
-
}
|
|
27249
|
-
function SettingsBar({ state }) {
|
|
27250
|
-
const selection = state.selection;
|
|
27251
|
-
if (!selection) return null;
|
|
27252
|
-
const help = state.inputMode === "provider" ? "up/down select | enter apply | esc cancel" : state.inputMode === "agent" ? "up/down select | enter apply | esc cancel" : state.inputMode === "permissionPreset" ? "up/down select | enter apply | esc cancel" : state.inputMode === "model" ? "type model | enter apply | esc cancel" : "p provider | a agent | m model | o permissions | up/down history | /cowork task | /compact compact | enter send | ctrl+c exit";
|
|
27253
|
-
return React.createElement(
|
|
27254
|
-
Box,
|
|
27255
|
-
{ borderStyle: "single", paddingX: 1 },
|
|
27256
|
-
React.createElement(Text, null, `agent ${state.selectedAgent ?? state.status.agent ?? "?"} | provider ${selection.providerName} (${selection.providerSource}) | model ${selection.model} (${selection.modelSource}) | permission ${state.permissionPreset} | ${help}`)
|
|
27257
|
-
);
|
|
28258
|
+
function tuiMode(state) {
|
|
28259
|
+
if (state.done) return { label: "done", color: "green" };
|
|
28260
|
+
if (state.permission) return { label: "approval", color: "yellow" };
|
|
28261
|
+
if (state.inputMode === "starting") return { label: "booting", color: "cyan" };
|
|
28262
|
+
if (state.inputMode === "session") return { label: "sessions", color: "magenta" };
|
|
28263
|
+
if (state.inputMode === "running") return { label: "running", color: "cyan" };
|
|
28264
|
+
if (state.inputMode === "provider" || state.inputMode === "agent" || state.inputMode === "model" || state.inputMode === "permissionPreset") return { label: "settings", color: "magenta" };
|
|
28265
|
+
if (state.inputMode === "prompt") return { label: "ready", color: "green" };
|
|
28266
|
+
return { label: state.inputMode, color: "gray" };
|
|
27258
28267
|
}
|
|
27259
28268
|
function TranscriptView({ state }) {
|
|
27260
28269
|
const blocks = state.blocks.slice(-12);
|
|
27261
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);
|
|
27262
28273
|
return React.createElement(
|
|
27263
28274
|
Box,
|
|
27264
|
-
{ flexDirection: "column", marginTop: 1 },
|
|
27265
|
-
...blocks.map((block) => React.createElement(BlockView, { key: block.id
|
|
27266
|
-
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
|
|
27267
28278
|
);
|
|
27268
28279
|
}
|
|
27269
|
-
function BlockView({ block }) {
|
|
27270
|
-
if (block.kind === "tool") return React.createElement(ToolBlockView, { block });
|
|
27271
|
-
if (block.kind === "goal-work") return React.createElement(GoalWorkBlockView, { block });
|
|
27272
|
-
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 });
|
|
27273
28285
|
const color = block.kind === "user" ? "green" : block.kind === "assistant" ? "white" : block.kind === "warning" ? "yellow" : "magenta";
|
|
28286
|
+
const lines = wrapBlockLines(block.lines, width, 80);
|
|
27274
28287
|
return React.createElement(
|
|
27275
28288
|
Box,
|
|
27276
28289
|
{ flexDirection: "column", marginBottom: 1 },
|
|
27277
|
-
React.createElement(Text, { color, bold: true }, block.title),
|
|
27278
|
-
...
|
|
28290
|
+
React.createElement(Text, { color, bold: true }, fitToWidth(block.title, width)),
|
|
28291
|
+
...lines.map((line, index) => React.createElement(Text, { key: index }, line || " "))
|
|
28292
|
+
);
|
|
28293
|
+
}
|
|
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
|
+
)
|
|
27279
28312
|
);
|
|
27280
28313
|
}
|
|
27281
|
-
function CoworkBlockView({ block }) {
|
|
28314
|
+
function CoworkBlockView({ block, width }) {
|
|
27282
28315
|
const group = block.cowork;
|
|
27283
28316
|
const warning = group?.status && group.status !== "running" && group.status !== "completed";
|
|
27284
28317
|
const color = warning ? "yellow" : group?.status === "running" ? "cyan" : "gray";
|
|
28318
|
+
const contentWidth = Math.max(16, width - 4);
|
|
27285
28319
|
return React.createElement(
|
|
27286
28320
|
Box,
|
|
27287
|
-
{ flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
|
|
27288
|
-
React.createElement(
|
|
27289
|
-
|
|
27290
|
-
null,
|
|
27291
|
-
React.createElement(Text, { color, bold: true }, "[cowork] "),
|
|
27292
|
-
React.createElement(Text, { color: "white", bold: true }, block.title),
|
|
27293
|
-
block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
|
|
27294
|
-
),
|
|
27295
|
-
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 })
|
|
27296
28324
|
);
|
|
27297
28325
|
}
|
|
27298
|
-
function CoworkDetailsView({ block }) {
|
|
28326
|
+
function CoworkDetailsView({ block, width }) {
|
|
27299
28327
|
const group = block.cowork;
|
|
27300
|
-
if (!group) return React.createElement(GoalFallbackLines, { lines: block.lines });
|
|
28328
|
+
if (!group) return React.createElement(GoalFallbackLines, { lines: block.lines, width });
|
|
27301
28329
|
const expanded = block.expanded !== false;
|
|
27302
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);
|
|
27303
28332
|
return React.createElement(
|
|
27304
28333
|
Box,
|
|
27305
28334
|
{ flexDirection: "column", marginTop: 1 },
|
|
27306
|
-
...
|
|
28335
|
+
...wrappedLines.map((line, index) => React.createElement(Text, { key: index, color: coworkLineColor(line) }, line || " "))
|
|
27307
28336
|
);
|
|
27308
28337
|
}
|
|
27309
28338
|
function coworkLineColor(line) {
|
|
@@ -27311,22 +28340,17 @@ function coworkLineColor(line) {
|
|
|
27311
28340
|
if (line.startsWith(" ")) return "gray";
|
|
27312
28341
|
return void 0;
|
|
27313
28342
|
}
|
|
27314
|
-
function GoalWorkBlockView({ block }) {
|
|
28343
|
+
function GoalWorkBlockView({ block, width }) {
|
|
27315
28344
|
const work = block.goalWork;
|
|
28345
|
+
const contentWidth = Math.max(16, width - 4);
|
|
27316
28346
|
return React.createElement(
|
|
27317
28347
|
Box,
|
|
27318
|
-
{ flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 },
|
|
27319
|
-
React.createElement(
|
|
27320
|
-
|
|
27321
|
-
null,
|
|
27322
|
-
React.createElement(Text, { color: "cyan", bold: true }, "[goal] "),
|
|
27323
|
-
React.createElement(Text, { color: "white", bold: true }, block.title),
|
|
27324
|
-
block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
|
|
27325
|
-
),
|
|
27326
|
-
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 })
|
|
27327
28351
|
);
|
|
27328
28352
|
}
|
|
27329
|
-
function GoalWorkDetailsView({ work }) {
|
|
28353
|
+
function GoalWorkDetailsView({ work, width }) {
|
|
27330
28354
|
const status = work.completedAt ? "completed" : "running";
|
|
27331
28355
|
const diffLines = work.diff && work.diff.files.length > 0 ? [
|
|
27332
28356
|
`Changes: ${work.diff.files.length} ${work.diff.files.length === 1 ? "file" : "files"} +${work.diff.addedLines} -${work.diff.removedLines}`,
|
|
@@ -27335,33 +28359,34 @@ function GoalWorkDetailsView({ work }) {
|
|
|
27335
28359
|
return React.createElement(
|
|
27336
28360
|
Box,
|
|
27337
28361
|
{ flexDirection: "column", marginTop: 1 },
|
|
27338
|
-
React.createElement(Text, { color: "gray" },
|
|
27339
|
-
React.createElement(Text, { color: "gray" },
|
|
27340
|
-
...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)),
|
|
27341
28364
|
...work.narrations.flatMap((narration, index) => [
|
|
27342
28365
|
React.createElement(
|
|
27343
28366
|
Box,
|
|
27344
28367
|
{ key: `narration-${narration.narrationId}`, flexDirection: "column", marginTop: index === 0 && diffLines.length === 0 ? 1 : 1 },
|
|
27345
|
-
...narration.lines
|
|
27346
|
-
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
|
|
27347
28370
|
)
|
|
27348
28371
|
]),
|
|
27349
|
-
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
|
|
27350
28373
|
);
|
|
27351
28374
|
}
|
|
27352
|
-
function GoalToolGroupView({ tools, title }) {
|
|
28375
|
+
function GoalToolGroupView({ tools, title, width }) {
|
|
28376
|
+
const nestedWidth = Math.max(24, width - 2);
|
|
27353
28377
|
return React.createElement(
|
|
27354
28378
|
Box,
|
|
27355
28379
|
{ flexDirection: "column", marginTop: 1, marginLeft: 2 },
|
|
27356
28380
|
title ? React.createElement(Text, { color: "gray" }, title) : null,
|
|
27357
|
-
...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 }))
|
|
27358
28382
|
);
|
|
27359
28383
|
}
|
|
27360
|
-
function GoalFallbackLines({ lines }) {
|
|
28384
|
+
function GoalFallbackLines({ lines, width }) {
|
|
28385
|
+
const wrappedLines = wrapBlockLines(lines, width, 120);
|
|
27361
28386
|
return React.createElement(
|
|
27362
28387
|
Box,
|
|
27363
28388
|
{ flexDirection: "column", marginTop: 1 },
|
|
27364
|
-
...
|
|
28389
|
+
...wrappedLines.map((line, index) => React.createElement(Text, { key: index, color: line.startsWith(" ") || line.startsWith(" ") ? "gray" : void 0 }, line || " "))
|
|
27365
28390
|
);
|
|
27366
28391
|
}
|
|
27367
28392
|
function goalToolAsBlock(tool) {
|
|
@@ -27375,38 +28400,33 @@ function goalToolAsBlock(tool) {
|
|
|
27375
28400
|
expanded: false
|
|
27376
28401
|
};
|
|
27377
28402
|
}
|
|
27378
|
-
function ToolBlockView({ block }) {
|
|
28403
|
+
function ToolBlockView({ block, width }) {
|
|
27379
28404
|
const status = block.toolStatus ?? "requested";
|
|
27380
28405
|
const color = status === "completed" ? "green" : status === "failed" || status === "denied" ? "red" : status === "permission" ? "yellow" : status === "running" ? "cyan" : "magenta";
|
|
27381
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}` : ""}`;
|
|
27382
28409
|
return React.createElement(
|
|
27383
28410
|
Box,
|
|
27384
|
-
{ flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
|
|
27385
|
-
React.createElement(
|
|
27386
|
-
|
|
27387
|
-
null,
|
|
27388
|
-
React.createElement(Text, { color, bold: true }, `[${badge}] `),
|
|
27389
|
-
React.createElement(Text, { color: "gray" }, block.expanded ? "[-] " : "[+] "),
|
|
27390
|
-
React.createElement(Text, { color: "white", bold: true }, block.title),
|
|
27391
|
-
block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
|
|
27392
|
-
),
|
|
27393
|
-
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
|
|
27394
28414
|
);
|
|
27395
28415
|
}
|
|
27396
|
-
function ToolDetailsView({ details, fallbackLines }) {
|
|
28416
|
+
function ToolDetailsView({ details, fallbackLines, width }) {
|
|
27397
28417
|
if (!details) {
|
|
27398
28418
|
return React.createElement(
|
|
27399
28419
|
Box,
|
|
27400
28420
|
{ flexDirection: "column", marginTop: 1 },
|
|
27401
|
-
...fallbackLines
|
|
28421
|
+
...wrapBlockLines(fallbackLines, width, 80).map((line, index) => React.createElement(Text, { key: index, color: index === 0 ? "gray" : void 0 }, line || " "))
|
|
27402
28422
|
);
|
|
27403
28423
|
}
|
|
27404
28424
|
return React.createElement(
|
|
27405
28425
|
Box,
|
|
27406
28426
|
{ flexDirection: "column", marginTop: 1 },
|
|
27407
|
-
React.createElement(Text, { color: "white" },
|
|
28427
|
+
...wrapBlockLines([details.summary], width, 4).map((line, index) => React.createElement(Text, { key: `summary-${index}`, color: "white" }, line || " ")),
|
|
27408
28428
|
details.chips.length > 0 ? React.createElement(ToolChipLine, { chips: details.chips }) : null,
|
|
27409
|
-
...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 }))
|
|
27410
28430
|
);
|
|
27411
28431
|
}
|
|
27412
28432
|
function ToolChipLine({ chips }) {
|
|
@@ -27419,26 +28439,36 @@ function ToolChipLine({ chips }) {
|
|
|
27419
28439
|
].filter(Boolean))
|
|
27420
28440
|
);
|
|
27421
28441
|
}
|
|
27422
|
-
function ToolSectionView({ section }) {
|
|
28442
|
+
function ToolSectionView({ section, width }) {
|
|
27423
28443
|
const rows = section.rows ?? [];
|
|
27424
28444
|
const lines = section.lines ?? [];
|
|
28445
|
+
const bodyWidth = Math.max(8, width - 2);
|
|
27425
28446
|
const body = rows.length > 0 || lines.length > 0 ? [
|
|
27426
|
-
...rows.map((row, index) => React.createElement(ToolRowView, { key: `row-${index}`, row })),
|
|
27427
|
-
...lines.
|
|
27428
|
-
] : 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)) : [];
|
|
27429
28450
|
return React.createElement(
|
|
27430
28451
|
Box,
|
|
27431
28452
|
{ flexDirection: "column", marginTop: 1 },
|
|
27432
|
-
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)),
|
|
27433
28454
|
...body
|
|
27434
28455
|
);
|
|
27435
28456
|
}
|
|
27436
|
-
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);
|
|
27437
28461
|
return React.createElement(
|
|
27438
28462
|
Box,
|
|
27439
|
-
|
|
27440
|
-
|
|
27441
|
-
|
|
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
|
+
)
|
|
27442
28472
|
);
|
|
27443
28473
|
}
|
|
27444
28474
|
function padLabel(value) {
|
|
@@ -27452,40 +28482,53 @@ function toneColor(tone) {
|
|
|
27452
28482
|
if (tone === "neutral") return "gray";
|
|
27453
28483
|
return void 0;
|
|
27454
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
|
+
}
|
|
27455
28499
|
function ActivityBar({ state }) {
|
|
28500
|
+
if (!shouldShowActivity(state)) return null;
|
|
27456
28501
|
const warning = state.warnings.at(-1);
|
|
27457
28502
|
const context = contextEfficiencySummary(state);
|
|
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}` : ""}`;
|
|
27458
28507
|
return React.createElement(
|
|
27459
28508
|
Box,
|
|
27460
|
-
{
|
|
27461
|
-
React.createElement(
|
|
27462
|
-
|
|
27463
|
-
null,
|
|
27464
|
-
React.createElement(Text, { color: state.done ? "green" : "blue", bold: true }, "Progress "),
|
|
27465
|
-
React.createElement(Text, { color: state.done ? "green" : "white" }, state.activity),
|
|
27466
|
-
context ? React.createElement(Text, { color: "gray" }, ` | ${context}`) : null
|
|
27467
|
-
),
|
|
27468
|
-
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
|
|
27469
28512
|
);
|
|
27470
28513
|
}
|
|
28514
|
+
function shouldShowActivity(state) {
|
|
28515
|
+
return state.inputMode === "running" || state.done || state.warnings.length > 0 || Boolean(state.contextEfficiency);
|
|
28516
|
+
}
|
|
27471
28517
|
function GoalIsland({ state }) {
|
|
27472
28518
|
const goal = state.goal;
|
|
27473
28519
|
if (!goal) return null;
|
|
27474
28520
|
const color = goalIslandColor(goal.status);
|
|
27475
28521
|
const progress = goal.maxIterations > 0 ? `${goal.iteration}/${goal.maxIterations}` : "active";
|
|
27476
28522
|
const decision = goal.decision ? ` | ${goalDecisionLabel(goal.decision)}` : "";
|
|
27477
|
-
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}`;
|
|
27478
28527
|
return React.createElement(
|
|
27479
28528
|
Box,
|
|
27480
|
-
{ alignSelf: "center", borderStyle: "round", borderColor: color, paddingX: 2, marginTop: 1, flexDirection: "column" },
|
|
27481
|
-
React.createElement(
|
|
27482
|
-
|
|
27483
|
-
null,
|
|
27484
|
-
React.createElement(Text, { color, bold: true }, "Goal "),
|
|
27485
|
-
React.createElement(Text, { color: "white", bold: true }, compactText(goal.title ?? goal.objective, 60)),
|
|
27486
|
-
React.createElement(Text, { color: "gray" }, ` | ${goalStatusLabel(goal.status)} | iter ${progress}${decision}`)
|
|
27487
|
-
),
|
|
27488
|
-
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,
|
|
27489
28532
|
reason ? React.createElement(Text, { color: "gray" }, reason) : null
|
|
27490
28533
|
);
|
|
27491
28534
|
}
|
|
@@ -27515,57 +28558,43 @@ function DiffAccordion({ state }) {
|
|
|
27515
28558
|
const indicator = state.diffExpanded ? "[-]" : "[+]";
|
|
27516
28559
|
const visibleFiles = diff.files.slice(0, 8);
|
|
27517
28560
|
const remaining = diff.files.length - visibleFiles.length;
|
|
28561
|
+
const width = statusSurfaceWidth();
|
|
28562
|
+
const contentWidth = Math.max(24, width - 4);
|
|
27518
28563
|
return React.createElement(
|
|
27519
28564
|
Box,
|
|
27520
|
-
{ flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1 },
|
|
27521
|
-
React.createElement(
|
|
27522
|
-
Box,
|
|
27523
|
-
null,
|
|
27524
|
-
React.createElement(Text, { color: "cyan", bold: true }, `${indicator} Diff `),
|
|
27525
|
-
React.createElement(Text, { color: "white" }, summary),
|
|
27526
|
-
React.createElement(Text, { color: "gray" }, " | tab toggle")
|
|
27527
|
-
),
|
|
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 }),
|
|
27528
28567
|
state.diffExpanded ? React.createElement(
|
|
27529
28568
|
Box,
|
|
27530
28569
|
{ flexDirection: "column", marginTop: 1 },
|
|
27531
|
-
...visibleFiles.map((file) => React.createElement(DiffFileCard, { key: file.path, file })),
|
|
28570
|
+
...visibleFiles.map((file) => React.createElement(DiffFileCard, { key: file.path, file, width: contentWidth })),
|
|
27532
28571
|
remaining > 0 ? React.createElement(Text, { key: "remaining", color: "gray" }, `... ${remaining} more files`) : null
|
|
27533
28572
|
) : null
|
|
27534
28573
|
);
|
|
27535
28574
|
}
|
|
27536
|
-
function DiffFileCard({ file }) {
|
|
28575
|
+
function DiffFileCard({ file, width }) {
|
|
27537
28576
|
const kind = file.kind === "add" ? "add" : file.kind === "delete" ? "delete" : "modified";
|
|
27538
28577
|
const kindColor = file.kind === "add" ? "green" : file.kind === "delete" ? "red" : "yellow";
|
|
28578
|
+
const line = `[file] ${file.path} \xB7 ${kind} +${file.addedLines} -${file.removedLines}`;
|
|
27539
28579
|
return React.createElement(
|
|
27540
28580
|
Box,
|
|
27541
|
-
{ borderStyle: "single", borderColor: "gray", paddingX: 1, marginBottom: 1 },
|
|
27542
|
-
React.createElement(Text, { color:
|
|
27543
|
-
React.createElement(Text, { color: "white", bold: true }, file.path),
|
|
27544
|
-
React.createElement(Text, { color: "gray" }, " \xB7 "),
|
|
27545
|
-
React.createElement(Text, { color: kindColor }, kind),
|
|
27546
|
-
React.createElement(Text, { color: "gray" }, " "),
|
|
27547
|
-
React.createElement(Text, { color: "green" }, `+${file.addedLines}`),
|
|
27548
|
-
React.createElement(Text, { color: "gray" }, " "),
|
|
27549
|
-
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)))
|
|
27550
28583
|
);
|
|
27551
28584
|
}
|
|
27552
28585
|
function WorkPlanPanel({ state, now: now2 }) {
|
|
27553
28586
|
const plan = state.workPlan;
|
|
27554
28587
|
const steps = plan?.steps ?? [];
|
|
27555
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);
|
|
27556
28591
|
if (steps.length === 0) {
|
|
27557
28592
|
if (state.inputMode !== "running") return null;
|
|
27558
28593
|
return React.createElement(
|
|
27559
28594
|
Box,
|
|
27560
|
-
{ flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1 },
|
|
27561
|
-
React.createElement(
|
|
27562
|
-
|
|
27563
|
-
null,
|
|
27564
|
-
React.createElement(Text, { color: "cyan", bold: true }, `${expanded ? "[-]" : "[+]"} Plan `),
|
|
27565
|
-
React.createElement(Text, { color: "white" }, "Thinking"),
|
|
27566
|
-
React.createElement(Text, { color: "gray" }, " | ctrl+p toggle")
|
|
27567
|
-
),
|
|
27568
|
-
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
|
|
27569
28598
|
);
|
|
27570
28599
|
}
|
|
27571
28600
|
const phase = workPlanPhase(state);
|
|
@@ -27578,57 +28607,63 @@ function WorkPlanPanel({ state, now: now2 }) {
|
|
|
27578
28607
|
const elapsed = plan ? planElapsed(plan, now2) : void 0;
|
|
27579
28608
|
return React.createElement(
|
|
27580
28609
|
Box,
|
|
27581
|
-
{ flexDirection: "column", borderStyle: "single", borderColor: phase.color, paddingX: 1 },
|
|
27582
|
-
React.createElement(
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
blocked ? React.createElement(Text, { color: "red" }, ` | ${blocked} blocked`) : null,
|
|
27590
|
-
React.createElement(Text, { color: "gray" }, " | ctrl+p toggle")
|
|
27591
|
-
),
|
|
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
|
+
}),
|
|
27592
28618
|
expanded ? React.createElement(
|
|
27593
28619
|
Box,
|
|
27594
28620
|
{ flexDirection: "column", marginTop: 1 },
|
|
27595
|
-
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,
|
|
27596
28622
|
active ? React.createElement(WorkPlanInfoLine, {
|
|
27597
28623
|
label: "Now",
|
|
27598
28624
|
value: `${activeIndex + 1}/${steps.length} ${active.title}`,
|
|
27599
28625
|
meta: stepElapsed(active, now2),
|
|
27600
|
-
color: "yellow"
|
|
28626
|
+
color: "yellow",
|
|
28627
|
+
width: contentWidth
|
|
27601
28628
|
}) : null
|
|
27602
28629
|
) : null,
|
|
27603
28630
|
expanded ? React.createElement(
|
|
27604
28631
|
Box,
|
|
27605
28632
|
{ flexDirection: "column", marginTop: 1 },
|
|
27606
|
-
...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 }))
|
|
27607
28634
|
) : null,
|
|
27608
|
-
...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 })) : []
|
|
27609
28636
|
);
|
|
27610
28637
|
}
|
|
27611
|
-
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);
|
|
27612
28642
|
return React.createElement(
|
|
27613
28643
|
Box,
|
|
27614
|
-
|
|
27615
|
-
|
|
27616
|
-
|
|
27617
|
-
|
|
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
|
+
)
|
|
27618
28654
|
);
|
|
27619
28655
|
}
|
|
27620
|
-
function WorkPlanStepLine({ step, active, now: now2 }) {
|
|
28656
|
+
function WorkPlanStepLine({ step, active, now: now2, width }) {
|
|
27621
28657
|
const detail = [step.detail, step.agent ? `agent ${step.agent}` : void 0].filter(Boolean).join(" | ");
|
|
27622
28658
|
const elapsed = stepElapsed(step, now2);
|
|
28659
|
+
const title = `${stepGlyph(step.status)} ${step.title}${elapsed ? ` (${elapsed})` : ""}`;
|
|
27623
28660
|
return React.createElement(
|
|
27624
28661
|
Box,
|
|
27625
28662
|
{ flexDirection: "column" },
|
|
27626
|
-
|
|
27627
|
-
Text,
|
|
27628
|
-
{ color: stepColor(step.status), bold: active || step.status === "in_progress" },
|
|
27629
|
-
`${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)
|
|
27630
28665
|
),
|
|
27631
|
-
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
|
|
27632
28667
|
);
|
|
27633
28668
|
}
|
|
27634
28669
|
function workPlanPhase(state) {
|
|
@@ -27708,74 +28743,311 @@ function formatElapsed2(ms2) {
|
|
|
27708
28743
|
if (minutes > 0) return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
|
|
27709
28744
|
return `${seconds}s`;
|
|
27710
28745
|
}
|
|
27711
|
-
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 }) {
|
|
27712
28757
|
if (state.inputMode === "starting") return React.createElement(LoadingBar);
|
|
28758
|
+
if (state.inputMode === "session") return React.createElement(SessionSelector, { state });
|
|
27713
28759
|
if (state.permission) return React.createElement(PermissionBar, { state });
|
|
27714
28760
|
if (state.inputMode === "provider") return React.createElement(ProviderSelector, { state });
|
|
27715
28761
|
if (state.inputMode === "agent") return React.createElement(AgentSelector, { state });
|
|
27716
28762
|
if (state.inputMode === "permissionPreset") return React.createElement(PermissionPresetSelector, { state });
|
|
27717
28763
|
if (state.inputMode === "model") return React.createElement(ModelEditor, { state });
|
|
27718
|
-
if (state.inputMode === "running") return React.createElement(CommandBar, { state });
|
|
27719
|
-
if (state.inputMode === "prompt") return React.createElement(PromptBar, { state });
|
|
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 });
|
|
27720
28766
|
return React.createElement(PermissionBar, { state });
|
|
27721
28767
|
}
|
|
27722
28768
|
function LoadingBar() {
|
|
27723
28769
|
return React.createElement(
|
|
27724
28770
|
Box,
|
|
27725
28771
|
{ flexDirection: "column", borderStyle: "double", paddingX: 1 },
|
|
27726
|
-
React.createElement(
|
|
27727
|
-
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" })
|
|
27728
28774
|
);
|
|
27729
28775
|
}
|
|
27730
|
-
function
|
|
27731
|
-
const
|
|
27732
|
-
|
|
27733
|
-
|
|
27734
|
-
|
|
27735
|
-
|
|
27736
|
-
|
|
28776
|
+
function shortcutHelp(state) {
|
|
28777
|
+
const parts = ["esc cancel"];
|
|
28778
|
+
if (state.inputMode === "prompt") parts.push("p provider", "a agent", "m model", "o permissions", "u clear");
|
|
28779
|
+
if (state.inputMode === "running") parts.push("s stop");
|
|
28780
|
+
if (state.turnDiff) parts.push("d diff");
|
|
28781
|
+
if (state.blocks.some((block) => block.kind === "tool")) parts.push("t tools");
|
|
28782
|
+
if (state.workPlan || state.inputMode === "running") parts.push("w plan");
|
|
28783
|
+
if (state.pendingClaudeCodePlan) parts.push("e use CC plan");
|
|
28784
|
+
if (state.canRetryLastPrompt) parts.push("r retry");
|
|
28785
|
+
parts.push("q quit");
|
|
28786
|
+
return `shortcut: ${parts.join(" | ")}`;
|
|
28787
|
+
}
|
|
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";
|
|
27737
28790
|
return React.createElement(
|
|
27738
28791
|
Box,
|
|
27739
|
-
{
|
|
27740
|
-
React.createElement(
|
|
28792
|
+
{ alignSelf: "center", width: promptPanelWidth(), flexDirection: "column", marginTop: 1 },
|
|
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(
|
|
27741
28954
|
Box,
|
|
27742
28955
|
null,
|
|
27743
|
-
|
|
27744
|
-
React.createElement(Text, { color: "gray"
|
|
27745
|
-
|
|
27746
|
-
|
|
27747
|
-
|
|
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))
|
|
27748
28970
|
);
|
|
27749
28971
|
}
|
|
27750
|
-
function
|
|
27751
|
-
|
|
27752
|
-
|
|
27753
|
-
|
|
27754
|
-
const planHelp = state.workPlan || state.inputMode === "running" ? " | ctrl+p plan" : "";
|
|
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 }) {
|
|
27755
28976
|
return React.createElement(
|
|
27756
28977
|
Box,
|
|
27757
|
-
{
|
|
28978
|
+
{ alignSelf: "center", width: promptPanelWidth(), flexDirection: "column", marginTop: 1 },
|
|
28979
|
+
error ? React.createElement(Text, { color: "yellow" }, error) : null,
|
|
27758
28980
|
React.createElement(
|
|
27759
28981
|
Box,
|
|
27760
|
-
|
|
27761
|
-
React.createElement(Text, { color
|
|
27762
|
-
|
|
27763
|
-
|
|
27764
|
-
|
|
27765
|
-
|
|
28982
|
+
{ justifyContent: "flex-end" },
|
|
28983
|
+
React.createElement(Text, { color }, hint)
|
|
28984
|
+
)
|
|
28985
|
+
);
|
|
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
|
|
27766
29005
|
);
|
|
27767
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
|
+
}
|
|
27768
29040
|
function ProviderSelector({ state }) {
|
|
27769
29041
|
const items = state.providerOptions;
|
|
27770
29042
|
return React.createElement(
|
|
27771
|
-
|
|
27772
|
-
{
|
|
27773
|
-
React.createElement(Text, { color: "
|
|
29043
|
+
DialogFrame,
|
|
29044
|
+
{ title: "Providers", accent: "magenta" },
|
|
29045
|
+
React.createElement(Text, { color: "gray" }, `${"Provider".padEnd(22)} ${"Model".padEnd(30)} Status`),
|
|
27774
29046
|
...items.map(
|
|
27775
29047
|
(item, index) => React.createElement(
|
|
27776
29048
|
Text,
|
|
27777
29049
|
{ key: item.name, color: index === state.providerCursor ? "cyan" : item.available === false ? "gray" : "white", bold: index === state.providerCursor },
|
|
27778
|
-
`${index === state.providerCursor ? ">" : " "} ${item.label ?? item.name}
|
|
29050
|
+
`${index === state.providerCursor ? ">" : " "} ${shorten(item.label ?? item.name, 20).padEnd(20)} ${shorten((item.modelLabel ?? item.model) || "-", 30).padEnd(30)} ${providerStatusLabel(item)}`
|
|
27779
29051
|
)
|
|
27780
29052
|
),
|
|
27781
29053
|
React.createElement(Text, { color: "gray" }, "up/down select | enter apply | esc cancel")
|
|
@@ -27784,9 +29056,8 @@ function ProviderSelector({ state }) {
|
|
|
27784
29056
|
function AgentSelector({ state }) {
|
|
27785
29057
|
const items = state.agentOptions;
|
|
27786
29058
|
return React.createElement(
|
|
27787
|
-
|
|
27788
|
-
{
|
|
27789
|
-
React.createElement(Text, { color: "cyan", bold: true }, "Select agent"),
|
|
29059
|
+
DialogFrame,
|
|
29060
|
+
{ title: "Agents", accent: "magenta" },
|
|
27790
29061
|
...items.map(
|
|
27791
29062
|
(item, index) => React.createElement(
|
|
27792
29063
|
Text,
|
|
@@ -27799,9 +29070,8 @@ function AgentSelector({ state }) {
|
|
|
27799
29070
|
}
|
|
27800
29071
|
function PermissionPresetSelector({ state }) {
|
|
27801
29072
|
return React.createElement(
|
|
27802
|
-
|
|
27803
|
-
{
|
|
27804
|
-
React.createElement(Text, { color: "cyan", bold: true }, "Default permission"),
|
|
29073
|
+
DialogFrame,
|
|
29074
|
+
{ title: "Default Permission", accent: "magenta" },
|
|
27805
29075
|
...PERMISSION_PRESETS.map(
|
|
27806
29076
|
(item, index) => React.createElement(
|
|
27807
29077
|
Text,
|
|
@@ -27822,16 +29092,15 @@ function ModelEditor({ state }) {
|
|
|
27822
29092
|
const current = state.selection?.model ?? "";
|
|
27823
29093
|
const value = state.modelInput || `Keep ${current}`;
|
|
27824
29094
|
return React.createElement(
|
|
27825
|
-
|
|
27826
|
-
{
|
|
27827
|
-
React.createElement(Text, { color: "cyan", bold: true }, "Model"),
|
|
29095
|
+
DialogFrame,
|
|
29096
|
+
{ title: "Model", accent: "magenta" },
|
|
27828
29097
|
React.createElement(
|
|
27829
29098
|
Box,
|
|
27830
29099
|
null,
|
|
27831
29100
|
React.createElement(Text, { color: "cyan", bold: true }, "> "),
|
|
27832
29101
|
React.createElement(Text, { color: state.modelInput ? "white" : "gray" }, value)
|
|
27833
29102
|
),
|
|
27834
|
-
state.settingsError ? React.createElement(Text, { color: "yellow" }, state.settingsError) : React.createElement(Text, { color: "gray" }, "enter apply |
|
|
29103
|
+
state.settingsError ? React.createElement(Text, { color: "yellow" }, state.settingsError) : React.createElement(Text, { color: "gray" }, "enter apply | backspace edit | esc cancel")
|
|
27835
29104
|
);
|
|
27836
29105
|
}
|
|
27837
29106
|
function PermissionBar({ state }) {
|
|
@@ -27841,18 +29110,211 @@ function PermissionBar({ state }) {
|
|
|
27841
29110
|
}
|
|
27842
29111
|
const detailLines = describeToolInput(pending.request.tool, pending.request.input);
|
|
27843
29112
|
return React.createElement(
|
|
27844
|
-
|
|
27845
|
-
{
|
|
27846
|
-
React.createElement(Text, { color: "yellow", bold: true }, "Permission required"),
|
|
29113
|
+
DialogFrame,
|
|
29114
|
+
{ title: "Permission Required", accent: "yellow" },
|
|
27847
29115
|
React.createElement(Text, null, `Allow ${toolLabel(pending.request.tool, pending.request.input)}?`),
|
|
27848
29116
|
...detailLines.map((line, index) => React.createElement(Text, { key: index, color: "white" }, line)),
|
|
27849
29117
|
...permissionShortcutLines().map((line, index) => React.createElement(Text, { key: `shortcut-${index}`, color: "cyan", bold: true }, line))
|
|
27850
29118
|
);
|
|
27851
29119
|
}
|
|
29120
|
+
function DialogFrame({ title, accent, children, width = dialogPanelWidth() }) {
|
|
29121
|
+
return React.createElement(
|
|
29122
|
+
Box,
|
|
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 }),
|
|
29125
|
+
React.createElement(Box, { height: 1 }),
|
|
29126
|
+
children
|
|
29127
|
+
);
|
|
29128
|
+
}
|
|
29129
|
+
function providerStatusLabel(item) {
|
|
29130
|
+
if (item.available !== false) return "ready";
|
|
29131
|
+
if (item.catalog?.status === "missing-auth") return "auth";
|
|
29132
|
+
if (item.catalog?.status === "unavailable") return "offline";
|
|
29133
|
+
return "n/a";
|
|
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
|
+
}
|
|
27852
29267
|
function shorten(value, max) {
|
|
27853
29268
|
if (value.length <= max) return value;
|
|
27854
29269
|
return `\u2026${value.slice(value.length - max + 1)}`;
|
|
27855
29270
|
}
|
|
29271
|
+
function terminalHeight() {
|
|
29272
|
+
const rows = process.stdout.rows;
|
|
29273
|
+
return typeof rows === "number" && Number.isFinite(rows) && rows > 0 ? Math.max(12, rows - 3) : 24;
|
|
29274
|
+
}
|
|
29275
|
+
function terminalWidth() {
|
|
29276
|
+
const columns = process.stdout.columns;
|
|
29277
|
+
return typeof columns === "number" && Number.isFinite(columns) && columns > 0 ? Math.max(48, columns) : 100;
|
|
29278
|
+
}
|
|
29279
|
+
function promptPanelWidth() {
|
|
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 : [""];
|
|
29298
|
+
}
|
|
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 }) {
|
|
29312
|
+
const columns = terminalWidth();
|
|
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));
|
|
29317
|
+
}
|
|
27856
29318
|
function formatTokens(value) {
|
|
27857
29319
|
const tokens = typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.round(value)) : 0;
|
|
27858
29320
|
if (tokens >= 1e6) return `${trimDecimal2(tokens / 1e6)}m`;
|
|
@@ -27866,12 +29328,47 @@ function clamp01(value) {
|
|
|
27866
29328
|
if (!Number.isFinite(value)) return 0;
|
|
27867
29329
|
return Math.max(0, Math.min(1, value));
|
|
27868
29330
|
}
|
|
29331
|
+
var SURFACE, CSI_U_INPUT, XTERM_MODIFIED_ENTER_INPUT, SLASH_COMMANDS, DEMIAN_WORDMARK_LINES;
|
|
27869
29332
|
var init_app = __esm({
|
|
27870
29333
|
"src/ui/tui/app.ts"() {
|
|
27871
29334
|
"use strict";
|
|
29335
|
+
init_string_width();
|
|
27872
29336
|
init_store();
|
|
27873
29337
|
init_presets();
|
|
27874
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
|
+
];
|
|
29365
|
+
DEMIAN_WORDMARK_LINES = [
|
|
29366
|
+
" _ _ ",
|
|
29367
|
+
" __| | ___ _ __ ___ (_) __ _ _ __ ",
|
|
29368
|
+
" / _` |/ _ \\ '_ ` _ \\| |/ _` | '_ \\ ",
|
|
29369
|
+
"| (_| | __/ | | | | | | (_| | | | |",
|
|
29370
|
+
" \\__,_|\\___|_| |_| |_|_|\\__,_|_| |_|"
|
|
29371
|
+
];
|
|
27875
29372
|
}
|
|
27876
29373
|
});
|
|
27877
29374
|
|
|
@@ -31892,8 +33389,8 @@ async function summarizeGoalTitleWithProvider(options) {
|
|
|
31892
33389
|
}
|
|
31893
33390
|
function normalizeGoalTitle(value, objective) {
|
|
31894
33391
|
const raw = typeof value === "string" ? value : "";
|
|
31895
|
-
const
|
|
31896
|
-
const cleaned = stripDecorations(
|
|
33392
|
+
const firstLine2 = raw.split(/\r?\n/).find((line) => line.trim()) ?? "";
|
|
33393
|
+
const cleaned = stripDecorations(firstLine2);
|
|
31897
33394
|
return truncateGoalTitle(cleaned || fallbackGoalTitle(objective));
|
|
31898
33395
|
}
|
|
31899
33396
|
function fallbackGoalTitle(objective) {
|
|
@@ -32599,17 +34096,17 @@ function findDependencyCycle(group) {
|
|
|
32599
34096
|
const byId = new Map(group.map((member) => [member.memberId, member]));
|
|
32600
34097
|
const visiting = /* @__PURE__ */ new Set();
|
|
32601
34098
|
const visited = /* @__PURE__ */ new Set();
|
|
32602
|
-
const
|
|
34099
|
+
const path37 = [];
|
|
32603
34100
|
const visit = (id) => {
|
|
32604
|
-
if (visiting.has(id)) return [...
|
|
34101
|
+
if (visiting.has(id)) return [...path37.slice(path37.indexOf(id)), id];
|
|
32605
34102
|
if (visited.has(id)) return void 0;
|
|
32606
34103
|
visiting.add(id);
|
|
32607
|
-
|
|
34104
|
+
path37.push(id);
|
|
32608
34105
|
for (const dep of byId.get(id)?.dependsOn ?? []) {
|
|
32609
34106
|
const cycle = visit(dep);
|
|
32610
34107
|
if (cycle) return cycle;
|
|
32611
34108
|
}
|
|
32612
|
-
|
|
34109
|
+
path37.pop();
|
|
32613
34110
|
visiting.delete(id);
|
|
32614
34111
|
visited.add(id);
|
|
32615
34112
|
return void 0;
|
|
@@ -33993,14 +35490,224 @@ var init_settings = __esm({
|
|
|
33993
35490
|
}
|
|
33994
35491
|
});
|
|
33995
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
|
+
|
|
33996
35703
|
// src/ui/tui/controller.ts
|
|
33997
35704
|
var controller_exports = {};
|
|
33998
35705
|
__export(controller_exports, {
|
|
33999
35706
|
runTuiSession: () => runTuiSession
|
|
34000
35707
|
});
|
|
34001
|
-
import
|
|
35708
|
+
import path36 from "node:path";
|
|
34002
35709
|
async function runTuiSession(flags, store) {
|
|
34003
|
-
const cwd =
|
|
35710
|
+
const cwd = path36.resolve(flags.cwd ?? process.cwd());
|
|
34004
35711
|
const eventBus = new EventBus();
|
|
34005
35712
|
eventBus.subscribe((event) => store.handleEvent(event));
|
|
34006
35713
|
const loadedConfig = await loadConfig({ cwd, configPath: flags.configPath });
|
|
@@ -34032,10 +35739,20 @@ async function runTuiSession(flags, store) {
|
|
|
34032
35739
|
}
|
|
34033
35740
|
});
|
|
34034
35741
|
let nextPrompt = flags.prompt;
|
|
34035
|
-
|
|
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] : [];
|
|
34036
35748
|
let lastExternalSessionKey;
|
|
34037
|
-
|
|
34038
|
-
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
|
+
}
|
|
34039
35756
|
const goalTitleGenerator = async (input2) => {
|
|
34040
35757
|
const selection = store.currentSelection();
|
|
34041
35758
|
const runtime = resolveProviderRuntimeConfig(config, selection);
|
|
@@ -34053,6 +35770,14 @@ async function runTuiSession(flags, store) {
|
|
|
34053
35770
|
if (resolved.kind === "external-agent") return input2.objective.trim().split(/\s+/).slice(0, 8).join(" ");
|
|
34054
35771
|
return summarizeGoalTitleWithProvider({ ...input2, provider: resolved.provider, model: resolved.model });
|
|
34055
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
|
+
}
|
|
34056
35781
|
for (; ; ) {
|
|
34057
35782
|
const prompt = await store.requestPrompt(nextPrompt);
|
|
34058
35783
|
nextPrompt = void 0;
|
|
@@ -34061,11 +35786,17 @@ async function runTuiSession(flags, store) {
|
|
|
34061
35786
|
return 0;
|
|
34062
35787
|
}
|
|
34063
35788
|
if (!prompt) return 0;
|
|
35789
|
+
const sessionCommand = parseSessionCommand(prompt);
|
|
35790
|
+
if (sessionCommand) {
|
|
35791
|
+
await handleSessionCommand(sessionCommand);
|
|
35792
|
+
continue;
|
|
35793
|
+
}
|
|
34064
35794
|
if (isCompactCommand(prompt)) {
|
|
34065
35795
|
const result = compactInteractiveHistory(history, config.context.main);
|
|
34066
35796
|
history = result.messages;
|
|
34067
35797
|
store.prepareForPrompt("waiting for next message");
|
|
34068
35798
|
store.markHistoryCompacted(result);
|
|
35799
|
+
await persistCurrentConversation();
|
|
34069
35800
|
continue;
|
|
34070
35801
|
}
|
|
34071
35802
|
const mode = resolveAgentMode(config, flags.mode);
|
|
@@ -34217,6 +35948,7 @@ async function runTuiSession(flags, store) {
|
|
|
34217
35948
|
history = interactiveHistoryFromRunMessages(result.messages);
|
|
34218
35949
|
lastExternalSessionKey = externalSessionKey ?? lastExternalSessionKey;
|
|
34219
35950
|
}
|
|
35951
|
+
await persistCurrentConversation();
|
|
34220
35952
|
} catch (error) {
|
|
34221
35953
|
store.setStopTask(void 0);
|
|
34222
35954
|
if (activeAbort?.signal.aborted) {
|
|
@@ -34229,6 +35961,7 @@ async function runTuiSession(flags, store) {
|
|
|
34229
35961
|
store.setStopTask(void 0);
|
|
34230
35962
|
}
|
|
34231
35963
|
if (store.exitRequested()) {
|
|
35964
|
+
await persistCurrentConversation();
|
|
34232
35965
|
await saveCurrentSelection();
|
|
34233
35966
|
return 0;
|
|
34234
35967
|
}
|
|
@@ -34237,6 +35970,161 @@ async function runTuiSession(flags, store) {
|
|
|
34237
35970
|
async function saveCurrentSelection() {
|
|
34238
35971
|
await saveSelection(store.currentSelection());
|
|
34239
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
|
+
}
|
|
34240
36128
|
async function saveSelection(selection) {
|
|
34241
36129
|
if (!shouldPersistSelection(selection)) return;
|
|
34242
36130
|
const key = preferenceKey(selection);
|
|
@@ -34248,6 +36136,34 @@ async function runTuiSession(flags, store) {
|
|
|
34248
36136
|
function isGoalStateClearingAction(action) {
|
|
34249
36137
|
return action === "status" || action === "pause" || action === "resume";
|
|
34250
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
|
+
}
|
|
34251
36167
|
var init_controller = __esm({
|
|
34252
36168
|
"src/ui/tui/controller.ts"() {
|
|
34253
36169
|
"use strict";
|
|
@@ -34268,11 +36184,13 @@ var init_controller = __esm({
|
|
|
34268
36184
|
init_history();
|
|
34269
36185
|
init_preferences();
|
|
34270
36186
|
init_settings();
|
|
36187
|
+
init_conversations();
|
|
34271
36188
|
}
|
|
34272
36189
|
});
|
|
34273
36190
|
|
|
34274
36191
|
// src/tui.ts
|
|
34275
36192
|
init_parser();
|
|
36193
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
34276
36194
|
|
|
34277
36195
|
// src/doctor/policies.ts
|
|
34278
36196
|
import { existsSync } from "node:fs";
|
|
@@ -35082,8 +37000,8 @@ async function fileExists2(filePath) {
|
|
|
35082
37000
|
}
|
|
35083
37001
|
async function readJsonSafe(filePath) {
|
|
35084
37002
|
try {
|
|
35085
|
-
const { readFile:
|
|
35086
|
-
const text = await
|
|
37003
|
+
const { readFile: readFile19 } = await import("node:fs/promises");
|
|
37004
|
+
const text = await readFile19(filePath, "utf8");
|
|
35087
37005
|
return JSON.parse(text);
|
|
35088
37006
|
} catch {
|
|
35089
37007
|
return void 0;
|
|
@@ -35222,9 +37140,9 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
35222
37140
|
]);
|
|
35223
37141
|
const React2 = ReactModule.default;
|
|
35224
37142
|
const store = new TuiStore2();
|
|
35225
|
-
const instance = render(React2.createElement(TuiApp2, { store }));
|
|
37143
|
+
const instance = render(React2.createElement(TuiApp2, { store, version: packageVersion() }));
|
|
35226
37144
|
try {
|
|
35227
|
-
const code = await runTuiSession2(flags, store);
|
|
37145
|
+
const code = await runTuiSession2({ ...flags, conversationManagement: true }, store);
|
|
35228
37146
|
setTimeout(() => instance.unmount(), 100);
|
|
35229
37147
|
await instance.waitUntilExit();
|
|
35230
37148
|
return code;
|
|
@@ -35241,6 +37159,14 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
35241
37159
|
throw error;
|
|
35242
37160
|
}
|
|
35243
37161
|
}
|
|
37162
|
+
function packageVersion() {
|
|
37163
|
+
try {
|
|
37164
|
+
const metadata = JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8"));
|
|
37165
|
+
return typeof metadata.version === "string" && metadata.version.trim() ? metadata.version : "dev";
|
|
37166
|
+
} catch {
|
|
37167
|
+
return "dev";
|
|
37168
|
+
}
|
|
37169
|
+
}
|
|
35244
37170
|
function parseArgs(argv) {
|
|
35245
37171
|
const out = { prompt: "", transcript: true, images: [] };
|
|
35246
37172
|
const rest = [];
|
|
@@ -35361,15 +37287,18 @@ Usage:
|
|
|
35361
37287
|
Default:
|
|
35362
37288
|
demian and demian-cli launch the Ink terminal UI.
|
|
35363
37289
|
The TUI shows provider/model defaults before asking for the first message.
|
|
35364
|
-
Press p to select provider, m to edit model, then Enter to send.
|
|
35365
|
-
Press a to select the main agent before sending a message.
|
|
35366
|
-
Press o to select the default permission preset: deny, ask, auto, or full.
|
|
37290
|
+
Press Esc then p to select provider, Esc then m to edit model, then Enter to send.
|
|
37291
|
+
Press Esc then a to select the main agent before sending a message.
|
|
37292
|
+
Press Esc then o to select the default permission preset: deny, ask, auto, or full.
|
|
35367
37293
|
Press up/down in the message composer to recall previous prompts.
|
|
35368
|
-
Provider/model selections are remembered in
|
|
37294
|
+
Provider/model selections are remembered in ~/.demian/preferences.json.
|
|
35369
37295
|
After each answer, the TUI returns to standby for the next message.
|
|
35370
37296
|
Use /cowork <task> to explicitly ask Demian to coordinate cowork sub agents in multi-agent mode.
|
|
35371
37297
|
Use /compact to compact current history, /stop to stop active work, and /exit or /quit to close the TUI.
|
|
35372
|
-
|
|
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.
|
|
37300
|
+
Press Esc then q to quit, Esc then s to stop a running task, and Esc then u to clear the composer.
|
|
37301
|
+
Tool approvals show the requested command/path in a permission dialog.
|
|
35373
37302
|
Press y to allow once, a to always allow the grant scope, or n/Enter to deny.
|
|
35374
37303
|
Prompt arguments are still accepted as a compatibility shortcut.
|
|
35375
37304
|
|