demian-cli 1.1.0 → 1.1.1

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