demian-cli 1.0.9 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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;
@@ -25727,7 +26013,7 @@ var init_store = __esm({
25727
26013
  }
25728
26014
  markTaskFailed(message) {
25729
26015
  const lines = [message];
25730
- if (this.#lastRetryPrompt()) lines.push("Press ctrl+r or type /retry to run the last task again.");
26016
+ if (this.#lastRetryPrompt()) lines.push("Press Esc then r or type /retry to run the last task again.");
25731
26017
  this.#append({ kind: "warning", title: "Task Failed", lines });
25732
26018
  this.#state.status.reason = "error";
25733
26019
  this.#state.inputMode = this.#exitRequested ? "done" : "prompt";
@@ -25783,6 +26069,84 @@ var init_store = __esm({
25783
26069
  this.#state.activity = `context compacted: ${summary.beforeTokenEstimate} -> ${summary.afterTokenEstimate}`;
25784
26070
  this.#notify();
25785
26071
  }
26072
+ conversationSnapshot() {
26073
+ const snapshot = this.snapshot();
26074
+ return {
26075
+ ...snapshot,
26076
+ inputMode: "prompt",
26077
+ promptInput: "",
26078
+ promptError: void 0,
26079
+ streamingText: "",
26080
+ streamingFinalized: true,
26081
+ permission: void 0,
26082
+ done: false
26083
+ };
26084
+ }
26085
+ restoreConversationSnapshot(snapshot, fallback) {
26086
+ this.#resetTransientConversationState();
26087
+ const currentSettings = {
26088
+ selection: this.#state.selection,
26089
+ providerOptions: this.#state.providerOptions,
26090
+ providerCursor: this.#state.providerCursor,
26091
+ agentOptions: this.#state.agentOptions,
26092
+ agentCursor: this.#state.agentCursor,
26093
+ selectedAgent: this.#state.selectedAgent,
26094
+ permissionPreset: this.#state.permissionPreset,
26095
+ permissionPresetCursor: this.#state.permissionPresetCursor,
26096
+ contextEfficiency: this.#state.contextEfficiency
26097
+ };
26098
+ const restoredSelection = snapshot?.selection ? { ...snapshot.selection } : currentSettings.selection;
26099
+ const restoredAgent = snapshot?.selectedAgent ?? snapshot?.status?.agent ?? currentSettings.selectedAgent;
26100
+ const restoredPermissionPreset = normalizePermissionPreset(snapshot?.permissionPreset, currentSettings.permissionPreset);
26101
+ this.#state = {
26102
+ ...this.#state,
26103
+ ...safeConversationSnapshot(snapshot),
26104
+ ...currentSettings,
26105
+ selection: restoredSelection,
26106
+ providerCursor: Math.max(0, currentSettings.providerOptions.findIndex((option) => option.name === restoredSelection?.providerName)),
26107
+ selectedAgent: restoredAgent,
26108
+ agentCursor: Math.max(0, currentSettings.agentOptions.findIndex((option) => option.name === restoredAgent)),
26109
+ permissionPreset: restoredPermissionPreset,
26110
+ permissionPresetCursor: Math.max(0, PERMISSION_PRESETS.indexOf(restoredPermissionPreset)),
26111
+ status: {
26112
+ ...snapshot?.status ?? this.#state.status,
26113
+ sessionId: fallback.sessionId,
26114
+ cwd: fallback.cwd,
26115
+ provider: restoredSelection?.providerName ?? snapshot?.status?.provider ?? this.#state.status.provider,
26116
+ model: restoredSelection?.model ?? snapshot?.status?.model ?? this.#state.status.model,
26117
+ agent: restoredAgent ?? snapshot?.status?.agent ?? this.#state.status.agent
26118
+ },
26119
+ inputMode: "prompt",
26120
+ promptInput: "",
26121
+ promptError: void 0,
26122
+ streamingText: "",
26123
+ streamingFinalized: true,
26124
+ permission: void 0,
26125
+ done: false,
26126
+ activity: `conversation: ${fallback.title}`
26127
+ };
26128
+ this.#blockId = nextBlockId(this.#state.blocks);
26129
+ this.#notify();
26130
+ }
26131
+ clearConversation(title = "New session") {
26132
+ this.#resetTransientConversationState();
26133
+ this.#state.blocks = [];
26134
+ this.#state.streamingText = "";
26135
+ this.#state.streamingFinalized = true;
26136
+ this.#state.permission = void 0;
26137
+ this.#state.warnings = [];
26138
+ this.#state.done = false;
26139
+ this.#state.finalAnswer = void 0;
26140
+ this.#state.progressNotes = [];
26141
+ this.#state.turnDiff = void 0;
26142
+ this.#state.diffExpanded = false;
26143
+ this.#state.workPlan = void 0;
26144
+ this.#state.workPlanExpanded = false;
26145
+ this.#state.goal = void 0;
26146
+ this.#state.pendingClaudeCodePlan = void 0;
26147
+ this.#state.activity = `cleared conversation: ${title}`;
26148
+ this.prepareForPrompt("waiting for next message");
26149
+ }
25786
26150
  prepareForPrompt(message = "waiting for next message") {
25787
26151
  if (this.#exitRequested) return;
25788
26152
  this.#state.inputMode = "prompt";
@@ -25840,7 +26204,45 @@ var init_store = __esm({
25840
26204
  currentPermissionPreset() {
25841
26205
  return this.#state.permissionPreset;
25842
26206
  }
26207
+ requestSessionSelection(options) {
26208
+ if (this.#exitRequested) return Promise.resolve({ kind: "exit" });
26209
+ const normalized = options.length > 0 ? options.map((option) => ({ ...option })) : [{ kind: "new", title: "New session", status: "ready", currentWorkspace: true }];
26210
+ return new Promise((resolve) => {
26211
+ this.#sessionResolve = resolve;
26212
+ this.#state.inputMode = "session";
26213
+ this.#state.sessionOptions = normalized;
26214
+ this.#state.sessionCursor = 0;
26215
+ this.#state.promptInput = "";
26216
+ this.#state.promptError = void 0;
26217
+ this.#state.streamingText = "";
26218
+ this.#state.streamingFinalized = true;
26219
+ this.#state.done = false;
26220
+ this.#state.activity = "select session";
26221
+ this.#notify();
26222
+ });
26223
+ }
26224
+ moveSessionCursor(delta) {
26225
+ if (this.#state.inputMode !== "session" || this.#state.sessionOptions.length === 0) return;
26226
+ const count = this.#state.sessionOptions.length;
26227
+ this.#state.sessionCursor = (this.#state.sessionCursor + delta + count) % count;
26228
+ this.#notify();
26229
+ }
26230
+ submitSessionSelection() {
26231
+ if (this.#state.inputMode !== "session") return;
26232
+ const option = this.#state.sessionOptions[this.#state.sessionCursor];
26233
+ if (!option) return;
26234
+ if (option.kind === "new") {
26235
+ this.#resolveSession({ kind: "new" });
26236
+ return;
26237
+ }
26238
+ if (option.id) this.#resolveSession({ kind: "session", id: option.id });
26239
+ }
26240
+ submitNewSessionSelection() {
26241
+ if (this.#state.inputMode !== "session") return;
26242
+ this.#resolveSession({ kind: "new" });
26243
+ }
25843
26244
  requestPrompt(initialPrompt) {
26245
+ if (this.#exitRequested) return Promise.resolve("");
25844
26246
  const prompt = (initialPrompt ?? "").trim();
25845
26247
  if (prompt) {
25846
26248
  this.#rememberPrompt(prompt);
@@ -25881,12 +26283,12 @@ var init_store = __esm({
25881
26283
  this.#notify();
25882
26284
  });
25883
26285
  }
25884
- appendPromptInput(input2) {
26286
+ appendPromptInput(input2, options = {}) {
25885
26287
  if (this.#state.inputMode !== "prompt" && this.#state.inputMode !== "running") return;
25886
26288
  if (this.#state.inputMode === "prompt") this.#detachPromptHistory();
25887
26289
  this.#state.promptInput += input2;
25888
26290
  this.#state.promptError = void 0;
25889
- this.#notify();
26291
+ if (options.notify !== false) this.#notify();
25890
26292
  }
25891
26293
  navigatePromptHistory(delta) {
25892
26294
  if (this.#state.inputMode !== "prompt" || this.#promptHistory.length === 0) return;
@@ -26041,19 +26443,19 @@ var init_store = __esm({
26041
26443
  this.#state.activity = "waiting for first message";
26042
26444
  this.#notify();
26043
26445
  }
26044
- backspacePromptInput() {
26446
+ backspacePromptInput(options = {}) {
26045
26447
  if (this.#state.inputMode !== "prompt" && this.#state.inputMode !== "running") return;
26046
26448
  if (this.#state.inputMode === "prompt") this.#detachPromptHistory();
26047
26449
  this.#state.promptInput = Array.from(this.#state.promptInput).slice(0, -1).join("");
26048
26450
  this.#state.promptError = void 0;
26049
- this.#notify();
26451
+ if (options.notify !== false) this.#notify();
26050
26452
  }
26051
- clearPromptInput() {
26453
+ clearPromptInput(options = {}) {
26052
26454
  if (this.#state.inputMode !== "prompt" && this.#state.inputMode !== "running") return;
26053
26455
  if (this.#state.inputMode === "prompt") this.#detachPromptHistory();
26054
26456
  this.#state.promptInput = "";
26055
26457
  this.#state.promptError = void 0;
26056
- this.#notify();
26458
+ if (options.notify !== false) this.#notify();
26057
26459
  }
26058
26460
  usePendingClaudeCodePlan() {
26059
26461
  if (this.#state.inputMode !== "prompt") return false;
@@ -26881,9 +27283,24 @@ var init_store = __esm({
26881
27283
  resolve(prompt);
26882
27284
  this.#notify();
26883
27285
  }
27286
+ #resolveSession(selection) {
27287
+ const resolve = this.#sessionResolve;
27288
+ if (!resolve) return;
27289
+ this.#sessionResolve = void 0;
27290
+ if (selection.kind === "exit") {
27291
+ this.#state.inputMode = "done";
27292
+ this.#state.done = true;
27293
+ this.#state.activity = "exiting";
27294
+ } else {
27295
+ this.#state.inputMode = "starting";
27296
+ this.#state.activity = selection.kind === "new" ? "creating session" : "opening session";
27297
+ }
27298
+ this.#notify();
27299
+ resolve(selection);
27300
+ }
26884
27301
  #rememberPrompt(prompt) {
26885
27302
  const value = prompt.trim();
26886
- if (!value || isExitCommand(value) || isStopCommand(value) || isCompactCommand(value) || isRetryCommand(value)) return;
27303
+ if (!value || isExitCommand(value) || isStopCommand(value) || isCompactCommand(value) || isRetryCommand(value) || isSessionCommand(value)) return;
26887
27304
  if (this.#promptHistory.at(-1) === value) {
26888
27305
  this.#state.canRetryLastPrompt = true;
26889
27306
  return;
@@ -26895,6 +27312,20 @@ var init_store = __esm({
26895
27312
  #lastRetryPrompt() {
26896
27313
  return this.#promptHistory.at(-1);
26897
27314
  }
27315
+ #resetTransientConversationState() {
27316
+ this.#toolRuns.clear();
27317
+ this.#goalWorkBlocks.clear();
27318
+ this.#coworkBlocks.clear();
27319
+ this.#activeGoalWorkBlockId = void 0;
27320
+ this.#currentGoalNarrationId = void 0;
27321
+ this.#timelineProgressIds.clear();
27322
+ this.#pendingPermissionCallId = void 0;
27323
+ if (this.#pendingPermissionTimeout) clearTimeout(this.#pendingPermissionTimeout);
27324
+ this.#pendingPermissionTimeout = void 0;
27325
+ this.#activeClaudeCodePlan = void 0;
27326
+ this.#promptHistoryCursor = void 0;
27327
+ this.#promptDraft = "";
27328
+ }
26898
27329
  #detachPromptHistory() {
26899
27330
  this.#promptHistoryCursor = void 0;
26900
27331
  this.#promptDraft = "";
@@ -26982,47 +27413,160 @@ var init_store = __esm({
26982
27413
  var app_exports = {};
26983
27414
  __export(app_exports, {
26984
27415
  TuiApp: () => TuiApp,
27416
+ commandPaletteMatches: () => commandPaletteMatches,
27417
+ inputFrameRows: () => inputFrameRows,
27418
+ isCtrlCKeypress: () => isCtrlCKeypress,
27419
+ isCtrlPKeypress: () => isCtrlPKeypress,
27420
+ isPromptNewlineKeypress: () => isPromptNewlineKeypress,
27421
+ sessionHeaderLine: () => sessionHeaderLine,
27422
+ sessionOptionLine: () => sessionOptionLine,
27423
+ slashCommandMatches: () => slashCommandMatches,
26985
27424
  textInputForKeypress: () => textInputForKeypress,
26986
- 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
- function TuiApp({ store }) {
27431
+ function TuiApp({ store, version = "dev" }) {
26991
27432
  const [state, setState] = useState(() => store.snapshot());
27433
+ const [promptInput, setPromptInput] = useState(() => store.snapshot().promptInput);
26992
27434
  const [now2, setNow] = useState(() => Date.now());
27435
+ const [shortcutMode, setShortcutMode] = useState(false);
27436
+ const [slashCommandCursor, setSlashCommandCursor] = useState(0);
27437
+ const [slashCommandClosedPrefix, setSlashCommandClosedPrefix] = useState();
27438
+ const [commandPaletteOpen, setCommandPaletteOpen] = useState(false);
27439
+ const [commandPaletteQuery, setCommandPaletteQuery] = useState("");
27440
+ const [commandPaletteCursor, setCommandPaletteCursor] = useState(0);
26993
27441
  const app = useApp();
26994
27442
  useEffect(() => {
26995
- const update = () => setState(store.snapshot());
27443
+ const update = () => {
27444
+ const next = store.snapshot();
27445
+ setState(next);
27446
+ setPromptInput(next.promptInput);
27447
+ };
26996
27448
  const unsubscribe = store.subscribe(update);
26997
27449
  update();
26998
27450
  return unsubscribe;
26999
27451
  }, [store]);
27452
+ useEffect(() => enableEnhancedKeyboardInput(), []);
27000
27453
  useEffect(() => {
27001
27454
  if (!state.workPlan && state.inputMode !== "running" && state.inputMode !== "starting") return;
27002
27455
  const timer = setInterval(() => setNow(Date.now()), 450);
27003
27456
  return () => clearInterval(timer);
27004
27457
  }, [state.workPlan?.planId, state.inputMode]);
27458
+ useEffect(() => {
27459
+ setShortcutMode(false);
27460
+ }, [state.inputMode, state.permission !== void 0]);
27461
+ useEffect(() => {
27462
+ setSlashCommandCursor(0);
27463
+ if (slashCommandClosedPrefix && !isSlashCommandClosedForPrompt(promptInput, slashCommandClosedPrefix)) setSlashCommandClosedPrefix(void 0);
27464
+ }, [promptInput, state.inputMode, slashCommandClosedPrefix]);
27465
+ useEffect(() => {
27466
+ setCommandPaletteCursor(0);
27467
+ }, [commandPaletteQuery, state.inputMode]);
27468
+ useEffect(() => {
27469
+ if (commandPaletteOpen && !canUseCommandPalette(state)) setCommandPaletteOpen(false);
27470
+ }, [commandPaletteOpen, state.inputMode, state.permission]);
27471
+ const commandPaletteItems = commandPaletteOpen ? commandPaletteMatches(commandPaletteQuery, state.inputMode, commandPaletteAvailability(state, promptInput)) : [];
27472
+ const commandPaletteItem = commandPaletteItems[Math.min(commandPaletteCursor, Math.max(0, commandPaletteItems.length - 1))];
27005
27473
  useInput((input2, key) => {
27006
- const textInput = textInputForKeypress(input2, key);
27007
- if (key.ctrl && input2 === "c") {
27474
+ if (isCtrlCKeypress(input2, key)) {
27008
27475
  store.requestExit();
27009
27476
  app.exit();
27010
27477
  return;
27011
27478
  }
27012
- if (key.ctrl && input2 === "t") {
27013
- store.toggleLatestToolExpanded();
27014
- return;
27015
- }
27016
- if (key.ctrl && input2 === "p") {
27017
- store.toggleWorkPlanExpanded();
27479
+ if (isCtrlPKeypress(input2, key) && canUseCommandPalette(state)) {
27480
+ setCommandPaletteOpen((open4) => !open4);
27481
+ setCommandPaletteQuery("");
27482
+ setCommandPaletteCursor(0);
27483
+ setShortcutMode(false);
27484
+ setSlashCommandClosedPrefix(promptInput);
27018
27485
  return;
27019
27486
  }
27020
- if (key.ctrl && input2 === "r") {
27021
- store.retryLastPrompt();
27487
+ const textInput = textInputForKeypress(input2, key);
27488
+ if (commandPaletteOpen) {
27489
+ if (key.escape) {
27490
+ closeCommandPalette(setCommandPaletteOpen, setCommandPaletteQuery, setCommandPaletteCursor);
27491
+ return;
27492
+ }
27493
+ if (key.upArrow) {
27494
+ if (commandPaletteItems.length > 0) setCommandPaletteCursor((cursor) => (cursor - 1 + commandPaletteItems.length) % commandPaletteItems.length);
27495
+ return;
27496
+ }
27497
+ if (key.downArrow) {
27498
+ if (commandPaletteItems.length > 0) setCommandPaletteCursor((cursor) => (cursor + 1) % commandPaletteItems.length);
27499
+ return;
27500
+ }
27501
+ if (key.return) {
27502
+ if (commandPaletteItem) executeCommandPaletteItem({ item: commandPaletteItem, store, app, setPromptInput, setState, close: () => closeCommandPalette(setCommandPaletteOpen, setCommandPaletteQuery, setCommandPaletteCursor) });
27503
+ return;
27504
+ }
27505
+ if (key.backspace || key.delete) {
27506
+ setCommandPaletteQuery((current) => Array.from(current).slice(0, -1).join(""));
27507
+ return;
27508
+ }
27509
+ if (textInput) {
27510
+ setCommandPaletteQuery((current) => `${current}${textInput}`);
27511
+ return;
27512
+ }
27022
27513
  return;
27023
27514
  }
27024
- if (key.ctrl && input2 === "e") {
27025
- store.usePendingClaudeCodePlan();
27515
+ if (shortcutMode) {
27516
+ setShortcutMode(false);
27517
+ if (key.escape) return;
27518
+ const shortcut = input2.toLowerCase();
27519
+ if (shortcut === "q") {
27520
+ store.requestExit();
27521
+ app.exit();
27522
+ return;
27523
+ }
27524
+ if (shortcut === "s" && state.inputMode === "running") {
27525
+ store.stopActiveTask();
27526
+ return;
27527
+ }
27528
+ if (shortcut === "p" && state.inputMode === "prompt") {
27529
+ store.openProviderSelector();
27530
+ return;
27531
+ }
27532
+ if (shortcut === "a" && state.inputMode === "prompt") {
27533
+ store.openAgentSelector();
27534
+ return;
27535
+ }
27536
+ if (shortcut === "m" && state.inputMode === "prompt") {
27537
+ store.openModelEditor();
27538
+ return;
27539
+ }
27540
+ if (shortcut === "o" && state.inputMode === "prompt") {
27541
+ store.openPermissionPresetSelector();
27542
+ return;
27543
+ }
27544
+ if (shortcut === "u" && state.inputMode === "prompt") {
27545
+ store.clearPromptInput({ notify: false });
27546
+ setPromptInput("");
27547
+ clearPromptErrorPreview(setState);
27548
+ return;
27549
+ }
27550
+ if (shortcut === "d" && state.turnDiff) {
27551
+ store.toggleDiffExpanded();
27552
+ return;
27553
+ }
27554
+ if (shortcut === "t" && state.blocks.some((block) => block.kind === "tool")) {
27555
+ store.toggleLatestToolExpanded();
27556
+ return;
27557
+ }
27558
+ if (shortcut === "w" && (state.workPlan || state.inputMode === "running")) {
27559
+ store.toggleWorkPlanExpanded();
27560
+ return;
27561
+ }
27562
+ if (shortcut === "e" && state.pendingClaudeCodePlan) {
27563
+ store.usePendingClaudeCodePlan();
27564
+ return;
27565
+ }
27566
+ if (shortcut === "r" && state.canRetryLastPrompt) {
27567
+ store.retryLastPrompt();
27568
+ return;
27569
+ }
27026
27570
  return;
27027
27571
  }
27028
27572
  if (state.permission) {
@@ -27032,6 +27576,31 @@ function TuiApp({ store }) {
27032
27576
  if (normalized === "n" || key.return) store.answerPermission({ decision: "deny" });
27033
27577
  return;
27034
27578
  }
27579
+ if (state.inputMode === "session") {
27580
+ const normalized = input2.toLowerCase();
27581
+ if (key.escape || normalized === "q") {
27582
+ store.requestExit();
27583
+ app.exit();
27584
+ return;
27585
+ }
27586
+ if (normalized === "n") {
27587
+ store.submitNewSessionSelection();
27588
+ return;
27589
+ }
27590
+ if (key.upArrow) {
27591
+ store.moveSessionCursor(-1);
27592
+ return;
27593
+ }
27594
+ if (key.downArrow) {
27595
+ store.moveSessionCursor(1);
27596
+ return;
27597
+ }
27598
+ if (key.return) {
27599
+ store.submitSessionSelection();
27600
+ return;
27601
+ }
27602
+ return;
27603
+ }
27035
27604
  if (state.inputMode === "provider") {
27036
27605
  if (key.escape) {
27037
27606
  store.closeSettings();
@@ -27094,10 +27663,6 @@ function TuiApp({ store }) {
27094
27663
  store.closeSettings();
27095
27664
  return;
27096
27665
  }
27097
- if (key.ctrl && input2 === "u") {
27098
- store.clearModelInput();
27099
- return;
27100
- }
27101
27666
  if (key.return) {
27102
27667
  if (textInput) store.appendModelInput(textInput);
27103
27668
  store.submitModelInput();
@@ -27111,83 +27676,534 @@ function TuiApp({ store }) {
27111
27676
  return;
27112
27677
  }
27113
27678
  if (state.inputMode === "prompt" || state.inputMode === "running") {
27114
- if (key.tab && state.turnDiff) {
27115
- store.toggleDiffExpanded();
27679
+ const slashCommands2 = visibleSlashCommandMatches(promptInput, state.inputMode, slashCommandClosedPrefix);
27680
+ const slashCommand = slashCommands2[slashCommandCursor] ?? slashCommands2[0];
27681
+ if (slashCommands2.length > 0 && key.escape) {
27682
+ setSlashCommandClosedPrefix(promptInput);
27116
27683
  return;
27117
27684
  }
27118
- if (state.inputMode === "prompt" && key.upArrow) {
27119
- store.navigatePromptHistory(-1);
27685
+ if (slashCommands2.length > 0 && key.upArrow) {
27686
+ setSlashCommandCursor((cursor) => (cursor - 1 + slashCommands2.length) % slashCommands2.length);
27120
27687
  return;
27121
27688
  }
27122
- if (state.inputMode === "prompt" && key.downArrow) {
27123
- store.navigatePromptHistory(1);
27689
+ if (slashCommands2.length > 0 && key.downArrow) {
27690
+ setSlashCommandCursor((cursor) => (cursor + 1) % slashCommands2.length);
27124
27691
  return;
27125
27692
  }
27126
- if (!key.return && state.inputMode === "prompt" && !state.promptInput && input2 === "p") {
27127
- store.openProviderSelector();
27693
+ if (slashCommands2.length > 0 && key.tab && slashCommand) {
27694
+ applySlashCommandDraft(store, setPromptInput, slashCommand, setSlashCommandClosedPrefix);
27695
+ clearPromptErrorPreview(setState);
27128
27696
  return;
27129
27697
  }
27130
- if (!key.return && state.inputMode === "prompt" && !state.promptInput && input2 === "a") {
27131
- store.openAgentSelector();
27698
+ if (state.inputMode === "prompt" && key.upArrow) {
27699
+ store.navigatePromptHistory(-1);
27132
27700
  return;
27133
27701
  }
27134
- if (!key.return && state.inputMode === "prompt" && !state.promptInput && input2 === "m") {
27135
- store.openModelEditor();
27702
+ if (state.inputMode === "prompt" && key.downArrow) {
27703
+ store.navigatePromptHistory(1);
27136
27704
  return;
27137
27705
  }
27138
- if (!key.return && state.inputMode === "prompt" && !state.promptInput && input2 === "o") {
27139
- store.openPermissionPresetSelector();
27706
+ if (key.escape) {
27707
+ setShortcutMode(true);
27140
27708
  return;
27141
27709
  }
27142
- if (key.ctrl && input2 === "u") {
27143
- store.clearPromptInput();
27710
+ if (isPromptNewlineKeypress(input2, key)) {
27711
+ appendPromptDraft(store, setPromptInput, `${textInput}
27712
+ `);
27713
+ clearPromptErrorPreview(setState);
27144
27714
  return;
27145
27715
  }
27146
- if (key.return) {
27147
- if (textInput) store.appendPromptInput(textInput);
27716
+ if (isPromptSubmitKeypress(input2, key)) {
27717
+ if (!textInput && slashCommand && shouldSelectSlashCommand(promptInput, slashCommand)) {
27718
+ applySlashCommandDraft(store, setPromptInput, slashCommand, setSlashCommandClosedPrefix);
27719
+ clearPromptErrorPreview(setState);
27720
+ return;
27721
+ }
27722
+ if (textInput) appendPromptDraft(store, setPromptInput, textInput);
27148
27723
  store.submitPromptInput();
27149
27724
  return;
27150
27725
  }
27151
27726
  if (key.backspace || key.delete) {
27152
- store.backspacePromptInput();
27727
+ store.backspacePromptInput({ notify: false });
27728
+ setPromptInput((current) => Array.from(current).slice(0, -1).join(""));
27729
+ clearPromptErrorPreview(setState);
27153
27730
  return;
27154
27731
  }
27155
- if (textInput) store.appendPromptInput(textInput);
27732
+ if (textInput) {
27733
+ appendPromptDraft(store, setPromptInput, textInput);
27734
+ clearPromptErrorPreview(setState);
27735
+ }
27156
27736
  return;
27157
27737
  }
27158
27738
  });
27739
+ const shellProps = { flexDirection: "column", paddingX: 1, minHeight: terminalHeight() };
27740
+ const slashCommands = commandPaletteOpen ? [] : visibleSlashCommandMatches(promptInput, state.inputMode, slashCommandClosedPrefix);
27741
+ const slashCommandPalette = slashCommands.length > 0 ? { items: slashCommands, cursor: Math.min(slashCommandCursor, slashCommands.length - 1) } : void 0;
27742
+ const commandPalette = commandPaletteOpen ? { items: commandPaletteItems, query: commandPaletteQuery, cursor: Math.min(commandPaletteCursor, Math.max(0, commandPaletteItems.length - 1)) } : void 0;
27743
+ if (shouldShowSessionStart(state)) {
27744
+ return React.createElement(
27745
+ Box,
27746
+ shellProps,
27747
+ React.createElement(SessionStart, { state, version })
27748
+ );
27749
+ }
27750
+ if (shouldShowEmptyState(state)) {
27751
+ return React.createElement(
27752
+ Box,
27753
+ shellProps,
27754
+ React.createElement(EmptyState, { state, version, shortcutMode, promptInput, slashCommandPalette, commandPalette })
27755
+ );
27756
+ }
27159
27757
  return React.createElement(
27160
27758
  Box,
27161
- { flexDirection: "column", paddingX: 1 },
27162
- React.createElement(StatusBar, { state, now: now2 }),
27163
- React.createElement(SettingsBar, { state }),
27164
- React.createElement(shouldShowLoading(state) ? LoadingView : TranscriptView, { state }),
27165
- React.createElement(DiffAccordion, { state }),
27166
- React.createElement(WorkPlanPanel, { state, now: now2 }),
27167
- React.createElement(ActivityBar, { state }),
27168
- React.createElement(GoalIsland, { state }),
27169
- React.createElement(BottomBar, { state })
27759
+ shellProps,
27760
+ React.createElement(StatusBar, { state, now: now2, version }),
27761
+ React.createElement(
27762
+ Box,
27763
+ { flexDirection: "column", flexGrow: 1, paddingX: 1 },
27764
+ React.createElement(shouldShowLoading(state) ? LoadingView : TranscriptView, { state }),
27765
+ React.createElement(Box, { flexGrow: 1 }),
27766
+ React.createElement(BottomStatusStack, { state, now: now2 }),
27767
+ React.createElement(InteractionPanel, { state, shortcutMode, promptInput, slashCommandPalette, commandPalette })
27768
+ )
27170
27769
  );
27171
27770
  }
27771
+ function appendPromptDraft(store, setPromptInput, value) {
27772
+ if (!value) return;
27773
+ store.appendPromptInput(value, { notify: false });
27774
+ setPromptInput((current) => `${current}${value}`);
27775
+ }
27776
+ function clearPromptErrorPreview(setState) {
27777
+ setState((current) => current.promptError ? { ...current, promptError: void 0 } : current);
27778
+ }
27779
+ function applySlashCommandDraft(store, setPromptInput, item, setSlashCommandClosedPrefix) {
27780
+ const next = item.argument ? `${item.insert} ` : item.insert;
27781
+ store.clearPromptInput({ notify: false });
27782
+ store.appendPromptInput(next, { notify: false });
27783
+ setPromptInput(next);
27784
+ setSlashCommandClosedPrefix(next);
27785
+ }
27786
+ function shouldSelectSlashCommand(promptInput, item) {
27787
+ const value = promptInput.trim();
27788
+ if (!value || value.includes(" ")) return false;
27789
+ if (!item.argument && value.toLowerCase() === item.insert.toLowerCase()) return false;
27790
+ return true;
27791
+ }
27792
+ function visibleSlashCommandMatches(promptInput, mode, closedPrefix) {
27793
+ if (closedPrefix && isSlashCommandClosedForPrompt(promptInput, closedPrefix)) return [];
27794
+ return slashCommandMatches(promptInput, mode).slice(0, 7);
27795
+ }
27796
+ function isSlashCommandClosedForPrompt(promptInput, closedPrefix) {
27797
+ return promptInput === closedPrefix || closedPrefix.endsWith(" ") && promptInput.startsWith(closedPrefix);
27798
+ }
27799
+ function slashCommandMatches(promptInput, mode = "prompt") {
27800
+ const query = slashCommandQuery(promptInput);
27801
+ if (query === void 0) return [];
27802
+ return SLASH_COMMANDS.filter((item) => slashCommandActiveInMode(item, mode)).map((item, index) => ({ item, index, score: slashCommandScore(item, query) })).filter((entry) => entry.score < Number.POSITIVE_INFINITY).sort((a, b2) => a.score - b2.score || a.index - b2.index).map((entry) => entry.item);
27803
+ }
27804
+ function slashCommandQuery(promptInput) {
27805
+ const value = promptInput.trimStart();
27806
+ if (!value.startsWith("/") || value.includes("\n")) return void 0;
27807
+ if (/\s/.test(value)) return void 0;
27808
+ return value.slice(1).toLowerCase();
27809
+ }
27810
+ function slashCommandActiveInMode(item, mode) {
27811
+ if (mode !== "prompt" && mode !== "running") return false;
27812
+ return item.mode === "both" || item.mode === mode || !item.mode && mode === "prompt";
27813
+ }
27814
+ function slashCommandScore(item, query) {
27815
+ if (!query) return 0;
27816
+ const command = item.command.slice(1).toLowerCase();
27817
+ const insert = item.insert.slice(1).toLowerCase();
27818
+ const aliases = item.aliases?.map((alias) => alias.toLowerCase()) ?? [];
27819
+ const aliasSearchEnabled = query.length >= 3;
27820
+ if (command.startsWith(query)) return 0;
27821
+ if (insert.startsWith(query)) return 1;
27822
+ if (aliasSearchEnabled && aliases.some((alias) => alias.startsWith(query))) return 2;
27823
+ if (command.includes(query) || insert.includes(query)) return 3;
27824
+ if (aliasSearchEnabled && aliases.some((alias) => alias.includes(query))) return 4;
27825
+ return Number.POSITIVE_INFINITY;
27826
+ }
27827
+ function canUseCommandPalette(state) {
27828
+ return !state.permission && (state.inputMode === "prompt" || state.inputMode === "running");
27829
+ }
27830
+ function commandPaletteAvailability(state, promptInput) {
27831
+ return {
27832
+ hasPromptDraft: Boolean(promptInput.trim()),
27833
+ hasSelection: Boolean(state.selection),
27834
+ hasProviders: state.providerOptions.length > 0,
27835
+ hasAgents: state.agentOptions.length > 0,
27836
+ hasDiff: Boolean(state.turnDiff),
27837
+ hasTools: state.blocks.some((block) => block.kind === "tool"),
27838
+ hasWorkPlan: Boolean(state.workPlan),
27839
+ hasPendingClaudeCodePlan: Boolean(state.pendingClaudeCodePlan),
27840
+ canRetryLastPrompt: state.canRetryLastPrompt
27841
+ };
27842
+ }
27843
+ function commandPaletteMatches(query, mode = "prompt", availability = {}) {
27844
+ const normalized = query.trim().toLowerCase();
27845
+ const items = buildCommandPaletteItems(mode, availability);
27846
+ if (!normalized) return items;
27847
+ return items.map((item, index) => ({ item, index, score: commandPaletteScore(item, normalized) })).filter((entry) => entry.score < Number.POSITIVE_INFINITY).sort((a, b2) => a.score - b2.score || a.index - b2.index).map((entry) => entry.item);
27848
+ }
27849
+ function buildCommandPaletteItems(mode, availability) {
27850
+ if (mode !== "prompt" && mode !== "running") return [];
27851
+ const items = [];
27852
+ const promptReadyForSettings = mode === "prompt" && !availability.hasPromptDraft;
27853
+ if (promptReadyForSettings && availability.hasSelection) {
27854
+ items.push({ id: "switch-model", title: "Switch model", description: "Choose the model for the current provider", group: "Suggested", shortcut: "esc m", action: "open-model", keywords: ["model", "provider model"] });
27855
+ }
27856
+ if (promptReadyForSettings && availability.hasProviders) {
27857
+ items.push({ id: "connect-provider", title: "Connect provider", description: "Change the active provider", group: "Suggested", shortcut: "esc p", action: "open-provider", keywords: ["provider", "connect"] });
27858
+ }
27859
+ if (promptReadyForSettings && availability.hasAgents) {
27860
+ items.push({ id: "switch-agent", title: "Switch agent", description: "Change the active agent profile", group: "Suggested", shortcut: "esc a", action: "open-agent", keywords: ["agent"] });
27861
+ }
27862
+ if (promptReadyForSettings) {
27863
+ items.push({ id: "permission-preset", title: "Permission preset", description: "Choose the next-turn permission behavior", group: "Suggested", shortcut: "esc o", action: "open-permissions", keywords: ["permission", "policy", "approval"] });
27864
+ }
27865
+ for (const command of SLASH_COMMANDS) {
27866
+ if (!slashCommandActiveInMode(command, mode)) continue;
27867
+ if (command.command === "/stop" || command.command === "/exit" || command.command === "/quit" || command.command === "/retry") continue;
27868
+ items.push({
27869
+ id: `slash:${command.command}`,
27870
+ title: commandPaletteSlashTitle(command),
27871
+ description: command.description,
27872
+ group: command.command.startsWith("/session") ? "Session" : "Commands",
27873
+ shortcut: command.command,
27874
+ keywords: [command.command, command.insert, ...command.aliases ?? []],
27875
+ slashCommand: command
27876
+ });
27877
+ }
27878
+ if (mode === "running") {
27879
+ items.push({ id: "stop-task", title: "Stop running task", description: "Cancel the current task", group: "System", shortcut: "/stop", action: "stop", keywords: ["stop", "cancel"] });
27880
+ }
27881
+ if (availability.hasPromptDraft) {
27882
+ items.push({ id: "clear-prompt", title: "Clear prompt", description: "Erase the current input draft", group: "System", shortcut: "esc u", action: "clear-prompt", keywords: ["clear", "draft", "input"] });
27883
+ }
27884
+ if (mode === "prompt" && availability.canRetryLastPrompt) {
27885
+ items.push({ id: "retry-last", title: "Retry last prompt", description: "Run the previous prompt again", group: "System", shortcut: "/retry", action: "retry", keywords: ["retry", "again", "rerun"] });
27886
+ }
27887
+ if (availability.hasPendingClaudeCodePlan) {
27888
+ items.push({ id: "use-claude-code-plan", title: "Use Claude Code plan", description: "Queue the captured plan for execution", group: "System", shortcut: "esc e", action: "use-claude-plan", keywords: ["claude", "plan"] });
27889
+ }
27890
+ if (availability.hasDiff) {
27891
+ items.push({ id: "toggle-diff", title: "Toggle diff", description: "Show or hide the latest file diff", group: "System", shortcut: "esc d", action: "toggle-diff", keywords: ["diff", "changes"] });
27892
+ }
27893
+ if (availability.hasTools) {
27894
+ items.push({ id: "toggle-tools", title: "Toggle tool details", description: "Expand or collapse the latest tool block", group: "System", shortcut: "esc t", action: "toggle-tools", keywords: ["tool", "details"] });
27895
+ }
27896
+ if (availability.hasWorkPlan || mode === "running") {
27897
+ items.push({ id: "toggle-work-plan", title: "Toggle work plan", description: "Show or hide current plan details", group: "System", shortcut: "esc w", action: "toggle-work-plan", keywords: ["plan", "progress"] });
27898
+ }
27899
+ items.push({ id: "exit-app", title: "Exit the app", description: "Close Demian", group: "System", shortcut: "/exit", action: "exit", keywords: ["quit", "close"] });
27900
+ return items;
27901
+ }
27902
+ function commandPaletteSlashTitle(item) {
27903
+ switch (item.command) {
27904
+ case "/cowork":
27905
+ return "Cowork agents";
27906
+ case "/compact":
27907
+ return "Compact context";
27908
+ case "/session":
27909
+ return "Session command";
27910
+ case "/session list":
27911
+ return "List sessions";
27912
+ case "/session new":
27913
+ return "New session";
27914
+ case "/session switch":
27915
+ return "Switch session";
27916
+ case "/session rename":
27917
+ return "Rename session";
27918
+ case "/session delete":
27919
+ return "Delete session";
27920
+ case "/goal":
27921
+ return "Start goal";
27922
+ case "/goal status":
27923
+ return "Goal status";
27924
+ case "/goal clear":
27925
+ return "Clear goal state";
27926
+ case "/ralph-loop":
27927
+ return "Start Ralph loop";
27928
+ case "/cancel-ralph":
27929
+ return "Cancel Ralph loop";
27930
+ default:
27931
+ return item.command;
27932
+ }
27933
+ }
27934
+ function commandPaletteScore(item, query) {
27935
+ const title = item.title.toLowerCase();
27936
+ const shortcut = item.shortcut?.toLowerCase() ?? "";
27937
+ const description = item.description.toLowerCase();
27938
+ const keywords = item.keywords?.map((keyword) => keyword.toLowerCase()) ?? [];
27939
+ if (title.startsWith(query)) return 0;
27940
+ if (shortcut.startsWith(query)) return 1;
27941
+ if (keywords.some((keyword) => keyword.startsWith(query))) return 2;
27942
+ if (title.includes(query)) return 3;
27943
+ if (shortcut.includes(query)) return 4;
27944
+ if (keywords.some((keyword) => keyword.includes(query))) return 5;
27945
+ if (description.includes(query)) return 6;
27946
+ return Number.POSITIVE_INFINITY;
27947
+ }
27948
+ function closeCommandPalette(setCommandPaletteOpen, setCommandPaletteQuery, setCommandPaletteCursor) {
27949
+ setCommandPaletteOpen(false);
27950
+ setCommandPaletteQuery("");
27951
+ setCommandPaletteCursor(0);
27952
+ }
27953
+ function executeCommandPaletteItem({
27954
+ item,
27955
+ store,
27956
+ app,
27957
+ setPromptInput,
27958
+ setState,
27959
+ close
27960
+ }) {
27961
+ close();
27962
+ if (item.slashCommand) {
27963
+ applyCommandPaletteSlashCommand(store, setPromptInput, item.slashCommand);
27964
+ clearPromptErrorPreview(setState);
27965
+ return;
27966
+ }
27967
+ switch (item.action) {
27968
+ case "open-model":
27969
+ store.openModelEditor();
27970
+ return;
27971
+ case "open-provider":
27972
+ store.openProviderSelector();
27973
+ return;
27974
+ case "open-agent":
27975
+ store.openAgentSelector();
27976
+ return;
27977
+ case "open-permissions":
27978
+ store.openPermissionPresetSelector();
27979
+ return;
27980
+ case "clear-prompt":
27981
+ store.clearPromptInput({ notify: false });
27982
+ setPromptInput("");
27983
+ clearPromptErrorPreview(setState);
27984
+ return;
27985
+ case "retry":
27986
+ store.retryLastPrompt();
27987
+ return;
27988
+ case "use-claude-plan":
27989
+ store.usePendingClaudeCodePlan();
27990
+ return;
27991
+ case "toggle-diff":
27992
+ store.toggleDiffExpanded();
27993
+ return;
27994
+ case "toggle-tools":
27995
+ store.toggleLatestToolExpanded();
27996
+ return;
27997
+ case "toggle-work-plan":
27998
+ store.toggleWorkPlanExpanded();
27999
+ return;
28000
+ case "stop":
28001
+ store.stopActiveTask();
28002
+ return;
28003
+ case "exit":
28004
+ store.requestExit();
28005
+ app.exit();
28006
+ return;
28007
+ }
28008
+ }
28009
+ function applyCommandPaletteSlashCommand(store, setPromptInput, item) {
28010
+ const shouldInsert = item.argument && item.command !== "/session new";
28011
+ const next = shouldInsert ? `${item.insert} ` : item.insert;
28012
+ store.clearPromptInput({ notify: false });
28013
+ store.appendPromptInput(next, { notify: false });
28014
+ setPromptInput(next);
28015
+ if (!shouldInsert) store.submitPromptInput();
28016
+ }
27172
28017
  function textInputForKeypress(input2, key) {
27173
28018
  if (!input2 || key.ctrl || key.tab || key.escape) return "";
28019
+ const csiText = decodeCsiUTextInput(input2);
28020
+ if (csiText !== void 0) return csiText;
28021
+ if (isKnownKeyboardSequence(input2)) return "";
27174
28022
  return Array.from(input2).filter((char) => {
27175
28023
  const codePoint = char.codePointAt(0) ?? 0;
27176
28024
  return codePoint >= 32 && codePoint !== 127;
27177
28025
  }).join("");
27178
28026
  }
28027
+ function isPromptNewlineKeypress(input2, key) {
28028
+ if (key.return && key.shift) return true;
28029
+ if (isShiftOrOptionEnterSequence(input2)) return true;
28030
+ return input2 === "\r" && !key.return;
28031
+ }
28032
+ function isCtrlCKeypress(input2, key) {
28033
+ if (input2 === "") return true;
28034
+ if (key.ctrl && input2.toLowerCase() === "c") return true;
28035
+ const csi = CSI_U_INPUT.exec(input2);
28036
+ if (!csi) return false;
28037
+ const codePoint = Number(csi[1]);
28038
+ const modifier = Number(csi[2] ?? 1);
28039
+ return (codePoint === 3 || codePoint === 99) && hasControlModifier(modifier);
28040
+ }
28041
+ function isCtrlPKeypress(input2, key) {
28042
+ if (input2 === "") return true;
28043
+ if (key.ctrl && input2.toLowerCase() === "p") return true;
28044
+ const csi = CSI_U_INPUT.exec(input2);
28045
+ if (!csi) return false;
28046
+ const codePoint = Number(csi[1]);
28047
+ const modifier = Number(csi[2] ?? 1);
28048
+ return (codePoint === 16 || codePoint === 112) && hasControlModifier(modifier);
28049
+ }
28050
+ function isPromptSubmitKeypress(input2, key) {
28051
+ return Boolean(key.return) || input2 === "\n";
28052
+ }
28053
+ function isShiftOrOptionEnterSequence(input2) {
28054
+ const csi = CSI_U_INPUT.exec(input2);
28055
+ if (csi) {
28056
+ const codePoint = Number(csi[1]);
28057
+ const modifier = Number(csi[2] ?? 1);
28058
+ return (codePoint === 13 || codePoint === 10) && hasShiftOrOptionModifier(modifier);
28059
+ }
28060
+ const xterm = XTERM_MODIFIED_ENTER_INPUT.exec(input2);
28061
+ return Boolean(xterm && hasShiftOrOptionModifier(Number(xterm[1])));
28062
+ }
28063
+ function decodeCsiUTextInput(input2) {
28064
+ const csi = CSI_U_INPUT.exec(input2);
28065
+ if (!csi) return void 0;
28066
+ const codePoint = Number(csi[1]);
28067
+ const modifier = Number(csi[2] ?? 1);
28068
+ if (!Number.isFinite(codePoint) || codePoint < 32 || codePoint === 127) return "";
28069
+ if (hasControlModifier(modifier) || hasOptionModifier(modifier)) return "";
28070
+ try {
28071
+ return String.fromCodePoint(codePoint);
28072
+ } catch {
28073
+ return "";
28074
+ }
28075
+ }
28076
+ function isKnownKeyboardSequence(input2) {
28077
+ return isShiftOrOptionEnterSequence(input2) || XTERM_MODIFIED_ENTER_INPUT.test(input2);
28078
+ }
28079
+ function hasShiftOrOptionModifier(modifier) {
28080
+ return hasShiftModifier(modifier) || hasOptionModifier(modifier);
28081
+ }
28082
+ function hasShiftModifier(modifier) {
28083
+ return (modifier - 1 & 1) !== 0;
28084
+ }
28085
+ function hasOptionModifier(modifier) {
28086
+ return (modifier - 1 & 2) !== 0;
28087
+ }
28088
+ function hasControlModifier(modifier) {
28089
+ return (modifier - 1 & 4) !== 0;
28090
+ }
27179
28091
  function shouldShowLoading(state) {
27180
28092
  return state.inputMode === "starting" || state.inputMode === "running" && state.blocks.length === 0 && !state.streamingText;
27181
28093
  }
28094
+ function enableEnhancedKeyboardInput() {
28095
+ if (!process.stdout.isTTY) return () => void 0;
28096
+ process.stdout.write("\x1B[>1u");
28097
+ process.stdout.write("\x1B[>4;2m");
28098
+ return () => {
28099
+ process.stdout.write("\x1B[<u");
28100
+ process.stdout.write("\x1B[>4;0m");
28101
+ };
28102
+ }
28103
+ function shouldShowEmptyState(state) {
28104
+ return state.inputMode === "prompt" && !state.permission && state.blocks.length === 0 && !state.streamingText && !state.turnDiff && !state.workPlan && !state.goal;
28105
+ }
28106
+ function shouldShowSessionStart(state) {
28107
+ return state.inputMode === "session";
28108
+ }
28109
+ function SessionStart({ state, version }) {
28110
+ const topGap = Math.max(1, Math.min(5, Math.floor(terminalHeight() * 0.12)));
28111
+ const width = sessionPanelWidth();
28112
+ return React.createElement(
28113
+ Box,
28114
+ { flexDirection: "column", flexGrow: 1 },
28115
+ React.createElement(Box, { height: topGap }),
28116
+ React.createElement(DemianWordmark),
28117
+ React.createElement(Box, { height: 1 }),
28118
+ React.createElement(SessionSelector, { state }),
28119
+ React.createElement(
28120
+ Box,
28121
+ { alignSelf: "center", width, justifyContent: "space-between", marginTop: 1 },
28122
+ React.createElement(Text, { color: "white" }, "enter open \xB7 n new \xB7 q quit"),
28123
+ React.createElement(Text, { color: "white" }, `v${version}`)
28124
+ ),
28125
+ React.createElement(Box, { flexGrow: 1 })
28126
+ );
28127
+ }
28128
+ function EmptyState({
28129
+ state,
28130
+ version,
28131
+ shortcutMode,
28132
+ promptInput,
28133
+ slashCommandPalette,
28134
+ commandPalette
28135
+ }) {
28136
+ const placeholder = 'Ask anything... "\uC774 \uD504\uB85C\uC81D\uD2B8\uC758 \uAD6C\uC870\uB97C \uC54C\uB824\uC918"';
28137
+ const hint = shortcutMode ? shortcutHelp(state) : "enter send \xB7 shift/option+enter newline \xB7 ctrl+p commands \xB7 /session";
28138
+ const hasOverlay = Boolean(slashCommandPalette || commandPalette);
28139
+ const topGap = hasOverlay ? 0 : Math.max(1, Math.min(6, Math.floor(terminalHeight() * 0.12)));
28140
+ return React.createElement(
28141
+ Box,
28142
+ { flexDirection: "column", flexGrow: 1 },
28143
+ React.createElement(Box, { height: topGap }),
28144
+ React.createElement(DemianWordmark),
28145
+ React.createElement(Box, { height: hasOverlay ? 1 : 2 }),
28146
+ commandPalette ? React.createElement(CommandPalettePanel, { palette: commandPalette }) : null,
28147
+ slashCommandPalette ? React.createElement(SlashCommandPalette, { palette: slashCommandPalette }) : null,
28148
+ React.createElement(InputFrame, {
28149
+ borderColor: shortcutMode ? "cyan" : "blue",
28150
+ cursorColor: "cyan",
28151
+ value: promptInput,
28152
+ placeholder,
28153
+ marginTop: 0
28154
+ }),
28155
+ React.createElement(CommandGuide, { hint, color: shortcutMode ? "cyan" : "gray", error: state.promptError }),
28156
+ hasOverlay ? null : React.createElement(SessionMetaBox, { state, version, marginTop: 2 }),
28157
+ React.createElement(
28158
+ Box,
28159
+ { flexGrow: 1 }
28160
+ )
28161
+ );
28162
+ }
28163
+ function SessionMetaBox({ state, version, marginTop = 1 }) {
28164
+ const width = promptPanelWidth();
28165
+ const compact = width < 68;
28166
+ const agent = shorten(state.selectedAgent ?? state.status.agent ?? "general", compact ? 14 : 18);
28167
+ const model = shorten(state.selection?.model ?? state.status.model ?? "model", compact ? Math.max(18, width - 14) : 30);
28168
+ const workspace = shorten(state.status.cwd ?? process.cwd(), compact ? Math.max(18, width - 18) : 46);
28169
+ const rows = compact ? [
28170
+ `agent ${agent} \xB7 perm ${state.permissionPreset}`,
28171
+ `model ${model}`,
28172
+ `workspace ${workspace}`,
28173
+ version ? `version v${version}` : void 0
28174
+ ].filter(Boolean) : [
28175
+ `agent ${agent} \xB7 model ${model} \xB7 perm ${state.permissionPreset}`,
28176
+ `workspace ${workspace}${version ? ` \xB7 version v${version}` : ""}`
28177
+ ];
28178
+ return React.createElement(
28179
+ Box,
28180
+ { alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "#334155", paddingX: 1, marginTop },
28181
+ ...rows.map((line, index) => React.createElement(SurfaceLine, { key: index, text: line ?? "", width: width - 4, backgroundColor: SURFACE.status, color: "white" }))
28182
+ );
28183
+ }
28184
+ function DemianWordmark() {
28185
+ if (terminalWidth() < 58) {
28186
+ return React.createElement(Box, { alignSelf: "center" }, React.createElement(Text, { color: "gray", bold: true }, "DEMIAN"));
28187
+ }
28188
+ return React.createElement(
28189
+ Box,
28190
+ { alignSelf: "center", flexDirection: "column" },
28191
+ ...DEMIAN_WORDMARK_LINES.map(
28192
+ (line, index) => React.createElement(Text, { key: index, color: index < 2 ? "gray" : "white", bold: true }, line)
28193
+ )
28194
+ );
28195
+ }
27182
28196
  function LoadingView({ state }) {
27183
- const title = state.inputMode === "starting" ? "Loading Demian" : "Preparing session";
28197
+ const title = state.inputMode === "starting" ? "Demian runtime" : "Preparing session";
27184
28198
  const message = state.activity || (state.inputMode === "starting" ? "Loading configuration" : "Starting session");
28199
+ const width = statusSurfaceWidth();
28200
+ const contentWidth = Math.max(24, width - 4);
27185
28201
  return React.createElement(
27186
28202
  Box,
27187
- { flexDirection: "column", marginTop: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1, paddingY: 1 },
27188
- React.createElement(Text, { color: "cyan", bold: true }, title),
27189
- React.createElement(Text, { color: "white" }, message),
27190
- React.createElement(Text, { color: "gray" }, "Please wait while demian gets ready.")
28203
+ { alignSelf: "center", width, flexDirection: "column", marginTop: 1, borderStyle: "double", borderColor: "cyan", paddingX: 1, paddingY: 1 },
28204
+ React.createElement(SurfaceLine, { text: title, width: contentWidth, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
28205
+ React.createElement(SurfaceLine, { text: message, width: contentWidth, backgroundColor: SURFACE.status, color: "white" }),
28206
+ React.createElement(SurfaceLine, { text: "Loading providers, tools, workspace state, and permissions.", width: contentWidth, backgroundColor: SURFACE.status, color: "gray" })
27191
28207
  );
27192
28208
  }
27193
28209
  function contextEfficiencySummary(state) {
@@ -27207,103 +28223,116 @@ function contextEfficiencySummary(state) {
27207
28223
  ].filter(Boolean);
27208
28224
  return parts.join(" | ");
27209
28225
  }
27210
- function StatusBar({ state, now: now2 }) {
28226
+ function StatusBar({ state, now: now2, version }) {
27211
28227
  const status = state.status;
27212
- const items = [
27213
- claudeCodeBadge(state),
27214
- status.provider ? `provider ${status.provider}` : void 0,
27215
- status.model ? `model ${status.model}` : void 0,
27216
- status.agent ? `agent ${status.agent}` : void 0,
27217
- status.cwd ? `cwd ${shorten(status.cwd, 48)}` : void 0,
27218
- status.externalSessionId ? `cc session ${shorten(status.externalSessionId, 18)}` : void 0,
27219
- status.reason ? `reason ${status.reason}` : void 0
27220
- ].filter(Boolean);
28228
+ const mode = tuiMode(state);
28229
+ const provider = state.selection?.providerName ?? status.provider;
28230
+ const model = state.selection?.model ?? status.model ?? "-";
28231
+ const meta = [provider, shorten(model, 32), state.permissionPreset, `v${version}`].filter(Boolean).join(" \xB7 ");
27221
28232
  return React.createElement(
27222
28233
  Box,
27223
- { borderStyle: "round", paddingX: 1 },
27224
- React.createElement(DemianTuiMark, { active: state.inputMode === "starting" || state.inputMode === "running", now: now2 }),
27225
- React.createElement(Text, { color: "cyan", bold: true }, " demian "),
27226
- React.createElement(Text, { color: "gray" }, items.join(" \xB7 "))
28234
+ { paddingX: 1, marginBottom: 1, justifyContent: "space-between" },
28235
+ React.createElement(
28236
+ Text,
28237
+ null,
28238
+ React.createElement(DemianTuiMark, { active: state.inputMode === "starting" || state.inputMode === "running", now: now2 }),
28239
+ React.createElement(Text, { color: "cyan", bold: true }, " Demian")
28240
+ ),
28241
+ React.createElement(
28242
+ Text,
28243
+ null,
28244
+ React.createElement(Text, { color: mode.color }, mode.label),
28245
+ React.createElement(Text, { color: "gray" }, ` \xB7 ${meta}`)
28246
+ )
27227
28247
  );
27228
28248
  }
27229
28249
  function DemianTuiMark({ active, now: now2 }) {
27230
28250
  const frame = active ? Math.floor(now2 / 450) % 4 : 0;
27231
- const shell = frame === 1 ? "<" : frame === 3 ? ">" : "^";
27232
- const face = frame === 2 ? "o" : "*";
28251
+ const mark = active ? ["D>", "D*", "D+", "D*"][frame] : "D>";
27233
28252
  return React.createElement(
27234
28253
  Text,
27235
28254
  { color: "yellow", bold: true },
27236
- `[${shell}${face}]`
28255
+ `[${mark}]`
27237
28256
  );
27238
28257
  }
27239
- function claudeCodeBadge(state) {
27240
- const option = selectedProviderOption(state);
27241
- const isClaudeCode = state.status.runtime === "claudecode" || option?.type === "claudecode" || state.status.provider === "claudecode" || state.selection?.providerName === "claudecode";
27242
- if (!isClaudeCode) return void 0;
27243
- return option?.ga === true ? "[CC]" : "[CC Preview]";
27244
- }
27245
- function selectedProviderOption(state) {
27246
- const providerName = state.selection?.providerName ?? state.status.provider;
27247
- return providerName ? state.providerOptions.find((option) => option.name === providerName) : void 0;
27248
- }
27249
- function SettingsBar({ state }) {
27250
- const selection = state.selection;
27251
- if (!selection) return null;
27252
- const help = state.inputMode === "provider" ? "up/down select | enter apply | esc cancel" : state.inputMode === "agent" ? "up/down select | enter apply | esc cancel" : state.inputMode === "permissionPreset" ? "up/down select | enter apply | esc cancel" : state.inputMode === "model" ? "type model | enter apply | esc cancel" : "p provider | a agent | m model | o permissions | up/down history | /cowork task | /compact compact | enter send | ctrl+c exit";
27253
- return React.createElement(
27254
- Box,
27255
- { borderStyle: "single", paddingX: 1 },
27256
- React.createElement(Text, null, `agent ${state.selectedAgent ?? state.status.agent ?? "?"} | provider ${selection.providerName} (${selection.providerSource}) | model ${selection.model} (${selection.modelSource}) | permission ${state.permissionPreset} | ${help}`)
27257
- );
28258
+ function tuiMode(state) {
28259
+ if (state.done) return { label: "done", color: "green" };
28260
+ if (state.permission) return { label: "approval", color: "yellow" };
28261
+ if (state.inputMode === "starting") return { label: "booting", color: "cyan" };
28262
+ if (state.inputMode === "session") return { label: "sessions", color: "magenta" };
28263
+ if (state.inputMode === "running") return { label: "running", color: "cyan" };
28264
+ if (state.inputMode === "provider" || state.inputMode === "agent" || state.inputMode === "model" || state.inputMode === "permissionPreset") return { label: "settings", color: "magenta" };
28265
+ if (state.inputMode === "prompt") return { label: "ready", color: "green" };
28266
+ return { label: state.inputMode, color: "gray" };
27258
28267
  }
27259
28268
  function TranscriptView({ state }) {
27260
28269
  const blocks = state.blocks.slice(-12);
27261
28270
  const streaming = !state.streamingFinalized && state.streamingText ? { kind: "assistant", title: "Assistant streaming", lines: streamingLines(state.streamingText) } : void 0;
28271
+ const width = transcriptPanelWidth();
28272
+ const contentWidth = Math.max(24, width - 2);
27262
28273
  return React.createElement(
27263
28274
  Box,
27264
- { flexDirection: "column", marginTop: 1 },
27265
- ...blocks.map((block) => React.createElement(BlockView, { key: block.id, block })),
27266
- streaming ? React.createElement(BlockView, { key: "streaming", block: streaming }) : null
28275
+ { alignSelf: "center", width, flexDirection: "column", marginTop: 1 },
28276
+ ...blocks.map((block, index) => React.createElement(BlockView, { key: `${block.id}-${index}`, block, width: contentWidth })),
28277
+ streaming ? React.createElement(BlockView, { key: "streaming", block: streaming, width: contentWidth }) : null
27267
28278
  );
27268
28279
  }
27269
- function BlockView({ block }) {
27270
- if (block.kind === "tool") return React.createElement(ToolBlockView, { block });
27271
- if (block.kind === "goal-work") return React.createElement(GoalWorkBlockView, { block });
27272
- if (block.kind === "cowork") return React.createElement(CoworkBlockView, { block });
28280
+ function BlockView({ block, width }) {
28281
+ if (block.kind === "tool") return React.createElement(ToolBlockView, { block, width });
28282
+ if (block.kind === "goal-work") return React.createElement(GoalWorkBlockView, { block, width });
28283
+ if (block.kind === "cowork") return React.createElement(CoworkBlockView, { block, width });
28284
+ if (block.kind === "user") return React.createElement(UserBlockView, { block, width });
27273
28285
  const color = block.kind === "user" ? "green" : block.kind === "assistant" ? "white" : block.kind === "warning" ? "yellow" : "magenta";
28286
+ const lines = wrapBlockLines(block.lines, width, 80);
27274
28287
  return React.createElement(
27275
28288
  Box,
27276
28289
  { flexDirection: "column", marginBottom: 1 },
27277
- React.createElement(Text, { color, bold: true }, block.title),
27278
- ...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 || " "))
28292
+ );
28293
+ }
28294
+ function UserBlockView({ block, width }) {
28295
+ const lines = normalizedBlockLines(block.lines).slice(0, 80);
28296
+ const bubbleWidth = userMessageBubbleWidth(lines, width);
28297
+ const contentWidth = Math.max(8, bubbleWidth - 4);
28298
+ const wrappedLines = wrapBlockLines(lines, contentWidth, 80);
28299
+ return React.createElement(
28300
+ Box,
28301
+ { alignSelf: "flex-end", width: bubbleWidth, flexDirection: "column", marginBottom: 1, marginLeft: 2 },
28302
+ React.createElement(
28303
+ Box,
28304
+ { flexDirection: "column", borderStyle: "round", borderColor: "blue", paddingX: 1 },
28305
+ React.createElement(
28306
+ Box,
28307
+ { justifyContent: "flex-end" },
28308
+ React.createElement(Text, { color: "blue", bold: true }, "You")
28309
+ ),
28310
+ ...wrappedLines.map((line, index) => React.createElement(Text, { key: index, color: "white" }, line || " "))
28311
+ )
27279
28312
  );
27280
28313
  }
27281
- function CoworkBlockView({ block }) {
28314
+ function CoworkBlockView({ block, width }) {
27282
28315
  const group = block.cowork;
27283
28316
  const warning = group?.status && group.status !== "running" && group.status !== "completed";
27284
28317
  const color = warning ? "yellow" : group?.status === "running" ? "cyan" : "gray";
28318
+ const contentWidth = Math.max(16, width - 4);
27285
28319
  return React.createElement(
27286
28320
  Box,
27287
- { flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
27288
- React.createElement(
27289
- Box,
27290
- null,
27291
- React.createElement(Text, { color, bold: true }, "[cowork] "),
27292
- React.createElement(Text, { color: "white", bold: true }, block.title),
27293
- block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
27294
- ),
27295
- React.createElement(CoworkDetailsView, { block })
28321
+ { width, flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
28322
+ React.createElement(SurfaceLine, { text: `[cowork] ${block.title}${block.meta ? ` \xB7 ${block.meta}` : ""}`, width: contentWidth, backgroundColor: SURFACE.status, color, bold: true }),
28323
+ React.createElement(CoworkDetailsView, { block, width: contentWidth })
27296
28324
  );
27297
28325
  }
27298
- function CoworkDetailsView({ block }) {
28326
+ function CoworkDetailsView({ block, width }) {
27299
28327
  const group = block.cowork;
27300
- if (!group) return React.createElement(GoalFallbackLines, { lines: block.lines });
28328
+ if (!group) return React.createElement(GoalFallbackLines, { lines: block.lines, width });
27301
28329
  const expanded = block.expanded !== false;
27302
28330
  const lines = expanded ? block.lines : block.lines.filter((line) => line.startsWith("Status:") || line.startsWith("Members:") || line.startsWith("Summary:")).slice(0, 4);
28331
+ const wrappedLines = wrapBlockLines(lines, width, 100);
27303
28332
  return React.createElement(
27304
28333
  Box,
27305
28334
  { flexDirection: "column", marginTop: 1 },
27306
- ...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 || " "))
27307
28336
  );
27308
28337
  }
27309
28338
  function coworkLineColor(line) {
@@ -27311,22 +28340,17 @@ function coworkLineColor(line) {
27311
28340
  if (line.startsWith(" ")) return "gray";
27312
28341
  return void 0;
27313
28342
  }
27314
- function GoalWorkBlockView({ block }) {
28343
+ function GoalWorkBlockView({ block, width }) {
27315
28344
  const work = block.goalWork;
28345
+ const contentWidth = Math.max(16, width - 4);
27316
28346
  return React.createElement(
27317
28347
  Box,
27318
- { flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 },
27319
- React.createElement(
27320
- Box,
27321
- null,
27322
- React.createElement(Text, { color: "cyan", bold: true }, "[goal] "),
27323
- React.createElement(Text, { color: "white", bold: true }, block.title),
27324
- block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
27325
- ),
27326
- work ? React.createElement(GoalWorkDetailsView, { work }) : React.createElement(GoalFallbackLines, { lines: block.lines })
28348
+ { width, flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: "cyan", paddingX: 1 },
28349
+ React.createElement(SurfaceLine, { text: `[goal] ${block.title}${block.meta ? ` \xB7 ${block.meta}` : ""}`, width: contentWidth, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
28350
+ work ? React.createElement(GoalWorkDetailsView, { work, width: contentWidth }) : React.createElement(GoalFallbackLines, { lines: block.lines, width: contentWidth })
27327
28351
  );
27328
28352
  }
27329
- function GoalWorkDetailsView({ work }) {
28353
+ function GoalWorkDetailsView({ work, width }) {
27330
28354
  const status = work.completedAt ? "completed" : "running";
27331
28355
  const diffLines = work.diff && work.diff.files.length > 0 ? [
27332
28356
  `Changes: ${work.diff.files.length} ${work.diff.files.length === 1 ? "file" : "files"} +${work.diff.addedLines} -${work.diff.removedLines}`,
@@ -27335,33 +28359,34 @@ function GoalWorkDetailsView({ work }) {
27335
28359
  return React.createElement(
27336
28360
  Box,
27337
28361
  { flexDirection: "column", marginTop: 1 },
27338
- React.createElement(Text, { color: "gray" }, `Goal: ${work.goalId}`),
27339
- React.createElement(Text, { color: "gray" }, `Status: ${status}`),
27340
- ...diffLines.map((line, index) => React.createElement(Text, { key: `diff-${index}`, color: line.startsWith(" ") ? "gray" : "white" }, line)),
28362
+ ...wrapBlockLines([`Goal: ${work.goalId}`, `Status: ${status}`], width, 4).map((line, index) => React.createElement(Text, { key: `meta-${index}`, color: "gray" }, line)),
28363
+ ...wrapBlockLines(diffLines, width, 20).map((line, index) => React.createElement(Text, { key: `diff-${index}`, color: line.startsWith(" ") ? "gray" : "white" }, line)),
27341
28364
  ...work.narrations.flatMap((narration, index) => [
27342
28365
  React.createElement(
27343
28366
  Box,
27344
28367
  { key: `narration-${narration.narrationId}`, flexDirection: "column", marginTop: index === 0 && diffLines.length === 0 ? 1 : 1 },
27345
- ...narration.lines.slice(0, 40).map((line, lineIndex) => React.createElement(Text, { key: lineIndex, color: "white" }, line || " ")),
27346
- narration.tools.length > 0 ? React.createElement(GoalToolGroupView, { key: `${narration.narrationId}-tools`, tools: narration.tools }) : null
28368
+ ...wrapBlockLines(narration.lines, width, 40).map((line, lineIndex) => React.createElement(Text, { key: lineIndex, color: "white" }, line || " ")),
28369
+ narration.tools.length > 0 ? React.createElement(GoalToolGroupView, { key: `${narration.narrationId}-tools`, tools: narration.tools, width }) : null
27347
28370
  )
27348
28371
  ]),
27349
- work.orphanTools.length > 0 ? React.createElement(GoalToolGroupView, { tools: work.orphanTools, title: "Tools" }) : null
28372
+ work.orphanTools.length > 0 ? React.createElement(GoalToolGroupView, { tools: work.orphanTools, title: "Tools", width }) : null
27350
28373
  );
27351
28374
  }
27352
- function GoalToolGroupView({ tools, title }) {
28375
+ function GoalToolGroupView({ tools, title, width }) {
28376
+ const nestedWidth = Math.max(24, width - 2);
27353
28377
  return React.createElement(
27354
28378
  Box,
27355
28379
  { flexDirection: "column", marginTop: 1, marginLeft: 2 },
27356
28380
  title ? React.createElement(Text, { color: "gray" }, title) : null,
27357
- ...tools.map((tool) => React.createElement(ToolBlockView, { key: tool.callId, block: goalToolAsBlock(tool) }))
28381
+ ...tools.map((tool) => React.createElement(ToolBlockView, { key: tool.callId, block: goalToolAsBlock(tool), width: nestedWidth }))
27358
28382
  );
27359
28383
  }
27360
- function GoalFallbackLines({ lines }) {
28384
+ function GoalFallbackLines({ lines, width }) {
28385
+ const wrappedLines = wrapBlockLines(lines, width, 120);
27361
28386
  return React.createElement(
27362
28387
  Box,
27363
28388
  { flexDirection: "column", marginTop: 1 },
27364
- ...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 || " "))
27365
28390
  );
27366
28391
  }
27367
28392
  function goalToolAsBlock(tool) {
@@ -27375,38 +28400,33 @@ function goalToolAsBlock(tool) {
27375
28400
  expanded: false
27376
28401
  };
27377
28402
  }
27378
- function ToolBlockView({ block }) {
28403
+ function ToolBlockView({ block, width }) {
27379
28404
  const status = block.toolStatus ?? "requested";
27380
28405
  const color = status === "completed" ? "green" : status === "failed" || status === "denied" ? "red" : status === "permission" ? "yellow" : status === "running" ? "cyan" : "magenta";
27381
28406
  const badge = status === "completed" ? "ok" : status === "failed" || status === "denied" ? "!" : status === "permission" ? "?" : status === "running" ? "..." : ">";
28407
+ const contentWidth = Math.max(16, width - 4);
28408
+ const header = `[${badge}] ${block.expanded ? "[-]" : "[+]"} ${block.title}${block.meta ? ` \xB7 ${block.meta}` : ""}`;
27382
28409
  return React.createElement(
27383
28410
  Box,
27384
- { flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
27385
- React.createElement(
27386
- Box,
27387
- null,
27388
- React.createElement(Text, { color, bold: true }, `[${badge}] `),
27389
- React.createElement(Text, { color: "gray" }, block.expanded ? "[-] " : "[+] "),
27390
- React.createElement(Text, { color: "white", bold: true }, block.title),
27391
- block.meta ? React.createElement(Text, { color: "gray" }, ` \xB7 ${block.meta}`) : null
27392
- ),
27393
- block.expanded ? React.createElement(ToolDetailsView, { details: block.toolDetails, fallbackLines: block.lines }) : null
28411
+ { width, flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: color, paddingX: 1 },
28412
+ React.createElement(SurfaceLine, { text: header, width: contentWidth, backgroundColor: SURFACE.status, color, bold: true }),
28413
+ block.expanded ? React.createElement(ToolDetailsView, { details: block.toolDetails, fallbackLines: block.lines, width: contentWidth }) : null
27394
28414
  );
27395
28415
  }
27396
- function ToolDetailsView({ details, fallbackLines }) {
28416
+ function ToolDetailsView({ details, fallbackLines, width }) {
27397
28417
  if (!details) {
27398
28418
  return React.createElement(
27399
28419
  Box,
27400
28420
  { flexDirection: "column", marginTop: 1 },
27401
- ...fallbackLines.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 || " "))
27402
28422
  );
27403
28423
  }
27404
28424
  return React.createElement(
27405
28425
  Box,
27406
28426
  { flexDirection: "column", marginTop: 1 },
27407
- 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 || " ")),
27408
28428
  details.chips.length > 0 ? React.createElement(ToolChipLine, { chips: details.chips }) : null,
27409
- ...details.sections.slice(0, 8).map((section, index) => React.createElement(ToolSectionView, { key: index, section }))
28429
+ ...details.sections.slice(0, 8).map((section, index) => React.createElement(ToolSectionView, { key: index, section, width }))
27410
28430
  );
27411
28431
  }
27412
28432
  function ToolChipLine({ chips }) {
@@ -27419,26 +28439,36 @@ function ToolChipLine({ chips }) {
27419
28439
  ].filter(Boolean))
27420
28440
  );
27421
28441
  }
27422
- function ToolSectionView({ section }) {
28442
+ function ToolSectionView({ section, width }) {
27423
28443
  const rows = section.rows ?? [];
27424
28444
  const lines = section.lines ?? [];
28445
+ const bodyWidth = Math.max(8, width - 2);
27425
28446
  const body = rows.length > 0 || lines.length > 0 ? [
27426
- ...rows.map((row, index) => React.createElement(ToolRowView, { key: `row-${index}`, row })),
27427
- ...lines.slice(0, 40).map((line, index) => React.createElement(Text, { key: `line-${index}`, color: section.code ? "gray" : "white" }, ` ${line || " "}`))
27428
- ] : 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)) : [];
27429
28450
  return React.createElement(
27430
28451
  Box,
27431
28452
  { flexDirection: "column", marginTop: 1 },
27432
- React.createElement(Text, { color: toneColor(section.tone) ?? "cyan", bold: true }, section.title),
28453
+ React.createElement(Text, { color: toneColor(section.tone) ?? "cyan", bold: true }, fitToWidth(section.title, width)),
27433
28454
  ...body
27434
28455
  );
27435
28456
  }
27436
- function ToolRowView({ row }) {
28457
+ function ToolRowView({ row, width }) {
28458
+ const label = ` ${padLabel(row.label)} `;
28459
+ const valueWidth = Math.max(8, width - stringWidth(label));
28460
+ const valueLines = wrapBlockLines([row.value], valueWidth, 6);
27437
28461
  return React.createElement(
27438
28462
  Box,
27439
- null,
27440
- React.createElement(Text, { color: "gray" }, ` ${padLabel(row.label)} `),
27441
- 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
+ )
27442
28472
  );
27443
28473
  }
27444
28474
  function padLabel(value) {
@@ -27452,40 +28482,53 @@ function toneColor(tone) {
27452
28482
  if (tone === "neutral") return "gray";
27453
28483
  return void 0;
27454
28484
  }
28485
+ function BottomStatusStack({ state, now: now2 }) {
28486
+ if (!shouldShowBottomStatusStack(state)) return null;
28487
+ return React.createElement(
28488
+ Box,
28489
+ { alignSelf: "center", width: statusSurfaceWidth(), flexDirection: "column", marginBottom: 1 },
28490
+ React.createElement(GoalIsland, { state }),
28491
+ React.createElement(DiffAccordion, { state }),
28492
+ React.createElement(WorkPlanPanel, { state, now: now2 }),
28493
+ React.createElement(ActivityBar, { state })
28494
+ );
28495
+ }
28496
+ function shouldShowBottomStatusStack(state) {
28497
+ return Boolean(state.goal || state.turnDiff && state.turnDiff.files.length > 0 || state.workPlan || state.inputMode === "running" || shouldShowActivity(state));
28498
+ }
27455
28499
  function ActivityBar({ state }) {
28500
+ if (!shouldShowActivity(state)) return null;
27456
28501
  const warning = state.warnings.at(-1);
27457
28502
  const context = contextEfficiencySummary(state);
28503
+ const color = state.done ? "green" : state.inputMode === "running" ? "cyan" : "blue";
28504
+ const width = statusSurfaceWidth();
28505
+ const contentWidth = Math.max(24, width - 4);
28506
+ const summary = `Activity ${state.activity}${context ? ` | ${context}` : ""}`;
27458
28507
  return React.createElement(
27459
28508
  Box,
27460
- { borderStyle: "round", borderColor: state.done ? "green" : "blue", paddingX: 1, flexDirection: "column" },
27461
- React.createElement(
27462
- Box,
27463
- null,
27464
- React.createElement(Text, { color: state.done ? "green" : "blue", bold: true }, "Progress "),
27465
- React.createElement(Text, { color: state.done ? "green" : "white" }, state.activity),
27466
- context ? React.createElement(Text, { color: "gray" }, ` | ${context}`) : null
27467
- ),
27468
- warning ? React.createElement(Text, { color: "yellow" }, ` \xB7 ${warning}`) : null
28509
+ { alignSelf: "center", width, borderStyle: "round", borderColor: color, paddingX: 1, flexDirection: "column" },
28510
+ React.createElement(SurfaceLine, { text: summary, width: contentWidth, backgroundColor: SURFACE.status, color: state.done ? "green" : color, bold: true }),
28511
+ warning ? React.createElement(SurfaceLine, { text: `! ${warning}`, width: contentWidth, backgroundColor: SURFACE.status, color: "yellow" }) : null
27469
28512
  );
27470
28513
  }
28514
+ function shouldShowActivity(state) {
28515
+ return state.inputMode === "running" || state.done || state.warnings.length > 0 || Boolean(state.contextEfficiency);
28516
+ }
27471
28517
  function GoalIsland({ state }) {
27472
28518
  const goal = state.goal;
27473
28519
  if (!goal) return null;
27474
28520
  const color = goalIslandColor(goal.status);
27475
28521
  const progress = goal.maxIterations > 0 ? `${goal.iteration}/${goal.maxIterations}` : "active";
27476
28522
  const decision = goal.decision ? ` | ${goalDecisionLabel(goal.decision)}` : "";
27477
- const 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}`;
27478
28527
  return React.createElement(
27479
28528
  Box,
27480
- { alignSelf: "center", borderStyle: "round", borderColor: color, paddingX: 2, marginTop: 1, flexDirection: "column" },
27481
- React.createElement(
27482
- Box,
27483
- null,
27484
- React.createElement(Text, { color, bold: true }, "Goal "),
27485
- React.createElement(Text, { color: "white", bold: true }, compactText(goal.title ?? goal.objective, 60)),
27486
- React.createElement(Text, { color: "gray" }, ` | ${goalStatusLabel(goal.status)} | iter ${progress}${decision}`)
27487
- ),
27488
- goal.title ? React.createElement(Text, { color: "gray" }, compactText(goal.objective, 88)) : null,
28529
+ { alignSelf: "center", width, borderStyle: "round", borderColor: color, paddingX: 2, marginTop: 1, flexDirection: "column" },
28530
+ React.createElement(SurfaceLine, { text: titleLine, width: contentWidth, backgroundColor: SURFACE.status, color, bold: true }),
28531
+ goal.title ? React.createElement(Text, { color: "gray" }, fitToWidth(goal.objective, contentWidth)) : null,
27489
28532
  reason ? React.createElement(Text, { color: "gray" }, reason) : null
27490
28533
  );
27491
28534
  }
@@ -27515,57 +28558,43 @@ function DiffAccordion({ state }) {
27515
28558
  const indicator = state.diffExpanded ? "[-]" : "[+]";
27516
28559
  const visibleFiles = diff.files.slice(0, 8);
27517
28560
  const remaining = diff.files.length - visibleFiles.length;
28561
+ const width = statusSurfaceWidth();
28562
+ const contentWidth = Math.max(24, width - 4);
27518
28563
  return React.createElement(
27519
28564
  Box,
27520
- { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1 },
27521
- React.createElement(
27522
- Box,
27523
- null,
27524
- React.createElement(Text, { color: "cyan", bold: true }, `${indicator} Diff `),
27525
- React.createElement(Text, { color: "white" }, summary),
27526
- React.createElement(Text, { color: "gray" }, " | tab toggle")
27527
- ),
28565
+ { alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1 },
28566
+ React.createElement(SurfaceLine, { text: `${indicator} Diff ${summary} | esc then d toggle`, width: contentWidth, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
27528
28567
  state.diffExpanded ? React.createElement(
27529
28568
  Box,
27530
28569
  { flexDirection: "column", marginTop: 1 },
27531
- ...visibleFiles.map((file) => React.createElement(DiffFileCard, { key: file.path, file })),
28570
+ ...visibleFiles.map((file) => React.createElement(DiffFileCard, { key: file.path, file, width: contentWidth })),
27532
28571
  remaining > 0 ? React.createElement(Text, { key: "remaining", color: "gray" }, `... ${remaining} more files`) : null
27533
28572
  ) : null
27534
28573
  );
27535
28574
  }
27536
- function DiffFileCard({ file }) {
28575
+ function DiffFileCard({ file, width }) {
27537
28576
  const kind = file.kind === "add" ? "add" : file.kind === "delete" ? "delete" : "modified";
27538
28577
  const kindColor = file.kind === "add" ? "green" : file.kind === "delete" ? "red" : "yellow";
28578
+ const line = `[file] ${file.path} \xB7 ${kind} +${file.addedLines} -${file.removedLines}`;
27539
28579
  return React.createElement(
27540
28580
  Box,
27541
- { borderStyle: "single", borderColor: "gray", paddingX: 1, marginBottom: 1 },
27542
- React.createElement(Text, { color: "cyan", bold: true }, "[file] "),
27543
- React.createElement(Text, { color: "white", bold: true }, file.path),
27544
- React.createElement(Text, { color: "gray" }, " \xB7 "),
27545
- React.createElement(Text, { color: kindColor }, kind),
27546
- React.createElement(Text, { color: "gray" }, " "),
27547
- React.createElement(Text, { color: "green" }, `+${file.addedLines}`),
27548
- React.createElement(Text, { color: "gray" }, " "),
27549
- React.createElement(Text, { color: "red" }, `-${file.removedLines}`)
28581
+ { width, borderStyle: "single", borderColor: "gray", paddingX: 1, marginBottom: 1 },
28582
+ React.createElement(Text, { color: kindColor, bold: true }, fitToWidth(line, Math.max(8, width - 4)))
27550
28583
  );
27551
28584
  }
27552
28585
  function WorkPlanPanel({ state, now: now2 }) {
27553
28586
  const plan = state.workPlan;
27554
28587
  const steps = plan?.steps ?? [];
27555
28588
  const expanded = state.workPlanExpanded || steps.some((step) => step.status === "blocked" || step.status === "failed");
28589
+ const width = statusSurfaceWidth();
28590
+ const contentWidth = Math.max(24, width - 4);
27556
28591
  if (steps.length === 0) {
27557
28592
  if (state.inputMode !== "running") return null;
27558
28593
  return React.createElement(
27559
28594
  Box,
27560
- { flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1 },
27561
- React.createElement(
27562
- Box,
27563
- null,
27564
- React.createElement(Text, { color: "cyan", bold: true }, `${expanded ? "[-]" : "[+]"} Plan `),
27565
- React.createElement(Text, { color: "white" }, "Thinking"),
27566
- React.createElement(Text, { color: "gray" }, " | ctrl+p toggle")
27567
- ),
27568
- expanded ? React.createElement(Text, { color: "gray" }, "Demian is inspecting context and preparing a step-by-step plan.") : null
28595
+ { alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1 },
28596
+ React.createElement(SurfaceLine, { text: `${expanded ? "[-]" : "[+]"} Plan Thinking | esc then w toggle`, width: contentWidth, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
28597
+ expanded ? React.createElement(Text, { color: "gray" }, fitToWidth("Demian is inspecting context and preparing a step-by-step plan.", contentWidth)) : null
27569
28598
  );
27570
28599
  }
27571
28600
  const phase = workPlanPhase(state);
@@ -27578,57 +28607,63 @@ function WorkPlanPanel({ state, now: now2 }) {
27578
28607
  const elapsed = plan ? planElapsed(plan, now2) : void 0;
27579
28608
  return React.createElement(
27580
28609
  Box,
27581
- { flexDirection: "column", borderStyle: "single", borderColor: phase.color, paddingX: 1 },
27582
- React.createElement(
27583
- Box,
27584
- null,
27585
- React.createElement(Text, { color: phase.color, bold: true }, `${expanded ? "[-]" : "[+]"} ${phase.label} `),
27586
- React.createElement(Text, { color: "white", bold: true }, plan?.title ?? "Main goal"),
27587
- elapsed ? React.createElement(Text, { color: "gray" }, ` (${elapsed})`) : null,
27588
- React.createElement(Text, { color: "gray" }, ` | ${planProgressGraph(progress.resolved, progress.total)} ${progress.resolved}/${progress.total}`),
27589
- blocked ? React.createElement(Text, { color: "red" }, ` | ${blocked} blocked`) : null,
27590
- React.createElement(Text, { color: "gray" }, " | ctrl+p toggle")
27591
- ),
28610
+ { alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: phase.color, paddingX: 1 },
28611
+ React.createElement(SurfaceLine, {
28612
+ text: `${expanded ? "[-]" : "[+]"} ${phase.label} ${plan?.title ?? "Main goal"}${elapsed ? ` (${elapsed})` : ""} | ${planProgressGraph(progress.resolved, progress.total)} ${progress.resolved}/${progress.total}${blocked ? ` | ${blocked} blocked` : ""} | esc then w toggle`,
28613
+ width: contentWidth,
28614
+ backgroundColor: SURFACE.status,
28615
+ color: phase.color,
28616
+ bold: true
28617
+ }),
27592
28618
  expanded ? React.createElement(
27593
28619
  Box,
27594
28620
  { flexDirection: "column", marginTop: 1 },
27595
- plan?.summary ? React.createElement(WorkPlanInfoLine, { label: "Plan", value: plan.summary }) : null,
28621
+ plan?.summary ? React.createElement(WorkPlanInfoLine, { label: "Plan", value: plan.summary, width: contentWidth }) : null,
27596
28622
  active ? React.createElement(WorkPlanInfoLine, {
27597
28623
  label: "Now",
27598
28624
  value: `${activeIndex + 1}/${steps.length} ${active.title}`,
27599
28625
  meta: stepElapsed(active, now2),
27600
- color: "yellow"
28626
+ color: "yellow",
28627
+ width: contentWidth
27601
28628
  }) : null
27602
28629
  ) : null,
27603
28630
  expanded ? React.createElement(
27604
28631
  Box,
27605
28632
  { flexDirection: "column", marginTop: 1 },
27606
- ...visibleSteps.map((step) => React.createElement(WorkPlanStepLine, { key: step.id, step, active: step.id === active?.id, now: now2 }))
28633
+ ...visibleSteps.map((step) => React.createElement(WorkPlanStepLine, { key: step.id, step, active: step.id === active?.id, now: now2, width: contentWidth }))
27607
28634
  ) : null,
27608
- ...expanded ? notes.map((note) => React.createElement(WorkPlanInfoLine, { key: note.id, label: "Update", value: note.message, color: noteColor(note.level) })) : []
28635
+ ...expanded ? notes.map((note) => React.createElement(WorkPlanInfoLine, { key: note.id, label: "Update", value: note.message, color: noteColor(note.level), width: contentWidth })) : []
27609
28636
  );
27610
28637
  }
27611
- function WorkPlanInfoLine({ label, value, meta, color = "gray" }) {
28638
+ function WorkPlanInfoLine({ label, value, meta, color = "gray", width }) {
28639
+ const prefix = `[${label}] `;
28640
+ const valueWidth = Math.max(8, width - stringWidth(prefix) - (meta ? stringWidth(` (${meta})`) : 0));
28641
+ const valueLines = wrapBlockLines([value], valueWidth, 4);
27612
28642
  return React.createElement(
27613
28643
  Box,
27614
- null,
27615
- React.createElement(Text, { color: "gray" }, `[${label}] `),
27616
- React.createElement(Text, { color }, value),
27617
- 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
+ )
27618
28654
  );
27619
28655
  }
27620
- function WorkPlanStepLine({ step, active, now: now2 }) {
28656
+ function WorkPlanStepLine({ step, active, now: now2, width }) {
27621
28657
  const detail = [step.detail, step.agent ? `agent ${step.agent}` : void 0].filter(Boolean).join(" | ");
27622
28658
  const elapsed = stepElapsed(step, now2);
28659
+ const title = `${stepGlyph(step.status)} ${step.title}${elapsed ? ` (${elapsed})` : ""}`;
27623
28660
  return React.createElement(
27624
28661
  Box,
27625
28662
  { flexDirection: "column" },
27626
- React.createElement(
27627
- Text,
27628
- { color: stepColor(step.status), bold: active || step.status === "in_progress" },
27629
- `${stepGlyph(step.status)} ${step.title}${elapsed ? ` (${elapsed})` : ""}`
28663
+ ...wrapBlockLines([title], width, 3).map(
28664
+ (line, index) => React.createElement(Text, { key: `title-${index}`, color: stepColor(step.status), bold: active || step.status === "in_progress" }, line)
27630
28665
  ),
27631
- detail ? React.createElement(Text, { color: "gray" }, ` ${detail}`) : null
28666
+ detail ? wrapBlockLines([` ${detail}`], width, 4).map((line, index) => React.createElement(Text, { key: `detail-${index}`, color: "gray" }, line)) : null
27632
28667
  );
27633
28668
  }
27634
28669
  function workPlanPhase(state) {
@@ -27708,74 +28743,311 @@ function formatElapsed2(ms2) {
27708
28743
  if (minutes > 0) return `${minutes}m ${String(seconds).padStart(2, "0")}s`;
27709
28744
  return `${seconds}s`;
27710
28745
  }
27711
- function BottomBar({ state }) {
28746
+ function formatSessionAge(updatedAt) {
28747
+ if (!updatedAt || !Number.isFinite(updatedAt)) return "-";
28748
+ const seconds = Math.max(0, Math.floor((Date.now() - updatedAt) / 1e3));
28749
+ if (seconds < 60) return `${seconds}s ago`;
28750
+ const minutes = Math.floor(seconds / 60);
28751
+ if (minutes < 60) return `${minutes}m ago`;
28752
+ const hours = Math.floor(minutes / 60);
28753
+ if (hours < 48) return `${hours}h ago`;
28754
+ return `${Math.floor(hours / 24)}d ago`;
28755
+ }
28756
+ function InteractionPanel({ state, shortcutMode, promptInput, slashCommandPalette, commandPalette }) {
27712
28757
  if (state.inputMode === "starting") return React.createElement(LoadingBar);
28758
+ if (state.inputMode === "session") return React.createElement(SessionSelector, { state });
27713
28759
  if (state.permission) return React.createElement(PermissionBar, { state });
27714
28760
  if (state.inputMode === "provider") return React.createElement(ProviderSelector, { state });
27715
28761
  if (state.inputMode === "agent") return React.createElement(AgentSelector, { state });
27716
28762
  if (state.inputMode === "permissionPreset") return React.createElement(PermissionPresetSelector, { state });
27717
28763
  if (state.inputMode === "model") return React.createElement(ModelEditor, { state });
27718
- if (state.inputMode === "running") return React.createElement(CommandBar, { state });
27719
- if (state.inputMode === "prompt") return React.createElement(PromptBar, { state });
28764
+ if (state.inputMode === "running") return React.createElement(CommandBar, { state, shortcutMode, promptInput, slashCommandPalette, commandPalette });
28765
+ if (state.inputMode === "prompt") return React.createElement(PromptBar, { state, shortcutMode, promptInput, slashCommandPalette, commandPalette });
27720
28766
  return React.createElement(PermissionBar, { state });
27721
28767
  }
27722
28768
  function LoadingBar() {
27723
28769
  return React.createElement(
27724
28770
  Box,
27725
28771
  { flexDirection: "column", borderStyle: "double", paddingX: 1 },
27726
- React.createElement(Text, { color: "cyan", bold: true }, "loading"),
27727
- React.createElement(Text, { color: "gray" }, "demian is preparing the session | ctrl+c exit")
28772
+ React.createElement(SurfaceLine, { text: "loading", width: promptPanelWidth() - 4, backgroundColor: SURFACE.status, color: "cyan", bold: true }),
28773
+ React.createElement(SurfaceLine, { text: "demian is preparing the session | type /exit after loading to quit", width: promptPanelWidth() - 4, backgroundColor: SURFACE.status, color: "gray" })
27728
28774
  );
27729
28775
  }
27730
- function PromptBar({ state }) {
27731
- const value = state.promptInput || "Type first message and press Enter";
27732
- const diffHelp = state.turnDiff ? " | tab diff" : "";
27733
- const toolHelp = state.blocks.some((block) => block.kind === "tool") ? " | ctrl+t tools" : "";
27734
- const planHelp = state.workPlan || state.inputMode === "running" ? " | ctrl+p plan" : "";
27735
- const claudeCodePlanHelp = state.pendingClaudeCodePlan ? " | ctrl+e use CC plan" : "";
27736
- const retryHelp = state.canRetryLastPrompt ? " | ctrl+r retry" : "";
28776
+ function shortcutHelp(state) {
28777
+ const parts = ["esc cancel"];
28778
+ if (state.inputMode === "prompt") parts.push("p provider", "a agent", "m model", "o permissions", "u clear");
28779
+ if (state.inputMode === "running") parts.push("s stop");
28780
+ if (state.turnDiff) parts.push("d diff");
28781
+ if (state.blocks.some((block) => block.kind === "tool")) parts.push("t tools");
28782
+ if (state.workPlan || state.inputMode === "running") parts.push("w plan");
28783
+ if (state.pendingClaudeCodePlan) parts.push("e use CC plan");
28784
+ if (state.canRetryLastPrompt) parts.push("r retry");
28785
+ parts.push("q quit");
28786
+ return `shortcut: ${parts.join(" | ")}`;
28787
+ }
28788
+ function PromptBar({ state, shortcutMode, promptInput, slashCommandPalette, commandPalette }) {
28789
+ const hint = shortcutMode ? shortcutHelp(state) : "enter send | shift/option+enter newline | ctrl+p commands | esc shortcuts | up/down history | /session | /compact | /retry | /exit";
27737
28790
  return React.createElement(
27738
28791
  Box,
27739
- { flexDirection: "column", borderStyle: "single", paddingX: 1 },
27740
- React.createElement(
28792
+ { alignSelf: "center", width: promptPanelWidth(), flexDirection: "column", marginTop: 1 },
28793
+ commandPalette ? React.createElement(CommandPalettePanel, { palette: commandPalette }) : null,
28794
+ commandPalette ? null : React.createElement(SessionMetaBox, { state, marginTop: 0 }),
28795
+ slashCommandPalette ? React.createElement(SlashCommandPalette, { palette: slashCommandPalette }) : null,
28796
+ React.createElement(InputFrame, {
28797
+ borderColor: shortcutMode ? "cyan" : "blue",
28798
+ cursorColor: "cyan",
28799
+ value: promptInput,
28800
+ placeholder: "Type first message and press Enter",
28801
+ marginTop: 1
28802
+ }),
28803
+ React.createElement(CommandGuide, { hint, color: shortcutMode ? "cyan" : "gray", error: state.promptError })
28804
+ );
28805
+ }
28806
+ function CommandBar({ state, shortcutMode, promptInput, slashCommandPalette, commandPalette }) {
28807
+ const hint = shortcutMode ? shortcutHelp(state) : "running | shift/option+enter newline | ctrl+p commands | /stop stop | /exit quit | esc shortcuts";
28808
+ return React.createElement(
28809
+ Box,
28810
+ { alignSelf: "center", width: promptPanelWidth(), flexDirection: "column", marginTop: 1 },
28811
+ commandPalette ? React.createElement(CommandPalettePanel, { palette: commandPalette }) : null,
28812
+ commandPalette ? null : React.createElement(SessionMetaBox, { state, marginTop: 0 }),
28813
+ slashCommandPalette ? React.createElement(SlashCommandPalette, { palette: slashCommandPalette }) : null,
28814
+ React.createElement(InputFrame, {
28815
+ borderColor: shortcutMode ? "cyan" : "yellow",
28816
+ cursorColor: "yellow",
28817
+ value: promptInput,
28818
+ placeholder: "Type /stop to stop or /exit to quit",
28819
+ marginTop: 1
28820
+ }),
28821
+ React.createElement(CommandGuide, { hint, color: shortcutMode ? "cyan" : "gray", error: state.promptError })
28822
+ );
28823
+ }
28824
+ function CommandPalettePanel({ palette }) {
28825
+ const width = commandPalettePanelWidth();
28826
+ const contentWidth = Math.max(32, width - 4);
28827
+ const maxRows = commandPaletteMaxRows();
28828
+ const selectedCursor = Math.min(palette.cursor, Math.max(0, palette.items.length - 1));
28829
+ const start = Math.max(0, Math.min(selectedCursor - maxRows + 1, Math.max(0, palette.items.length - maxRows)));
28830
+ const visibleItems = palette.items.slice(start, start + maxRows);
28831
+ const visibleCursor = selectedCursor - start;
28832
+ return React.createElement(
28833
+ Box,
28834
+ { alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "#374151", paddingX: 1, paddingY: 1, marginTop: 1 },
28835
+ React.createElement(CommandPaletteHeader, { width: contentWidth }),
28836
+ React.createElement(CommandPaletteSearchLine, { query: palette.query, width: contentWidth }),
28837
+ React.createElement(SurfaceLine, { text: "", width: contentWidth, backgroundColor: SURFACE.dialog }),
28838
+ start > 0 ? React.createElement(SurfaceLine, { text: `+ ${start} above`, width: contentWidth, backgroundColor: SURFACE.dialog, color: "gray" }) : null,
28839
+ ...commandPaletteRenderedRows(visibleItems, visibleCursor, contentWidth),
28840
+ palette.items.length === 0 ? React.createElement(SurfaceLine, { text: "No commands", width: contentWidth, backgroundColor: SURFACE.dialog, color: "gray" }) : null,
28841
+ palette.items.length > start + visibleItems.length ? React.createElement(SurfaceLine, { text: `+ ${palette.items.length - start - visibleItems.length} more`, width: contentWidth, backgroundColor: SURFACE.dialog, color: "gray" }) : null
28842
+ );
28843
+ }
28844
+ function CommandPaletteHeader({ width }) {
28845
+ const label = "Commands";
28846
+ const esc = "esc";
28847
+ const gap = Math.max(1, width - stringWidth(label) - stringWidth(esc));
28848
+ return React.createElement(
28849
+ Text,
28850
+ { backgroundColor: SURFACE.dialog, color: "white", bold: true },
28851
+ `${label}${" ".repeat(gap)}${esc}`
28852
+ );
28853
+ }
28854
+ function CommandPaletteSearchLine({ query, width }) {
28855
+ const text = query || "Search";
28856
+ const textColor = query ? "white" : "gray";
28857
+ const textWidth = Math.max(0, width - 1);
28858
+ return React.createElement(
28859
+ Box,
28860
+ null,
28861
+ React.createElement(CursorCell, { cursorColor: "#f4a261" }),
28862
+ React.createElement(Text, { color: textColor, backgroundColor: SURFACE.dialog }, padToWidth(fitToWidth(text, textWidth), textWidth))
28863
+ );
28864
+ }
28865
+ function commandPaletteRenderedRows(items, cursor, width) {
28866
+ const rows = [];
28867
+ let lastGroup;
28868
+ items.forEach((item, index) => {
28869
+ if (item.group !== lastGroup) {
28870
+ if (rows.length > 0) rows.push(React.createElement(SurfaceLine, { key: `gap-${item.group}-${index}`, text: "", width, backgroundColor: SURFACE.dialog }));
28871
+ rows.push(React.createElement(SurfaceLine, { key: `group-${item.group}-${index}`, text: item.group, width, backgroundColor: SURFACE.dialog, color: "magenta", bold: true }));
28872
+ lastGroup = item.group;
28873
+ }
28874
+ rows.push(React.createElement(CommandPaletteRow, { key: item.id, item, selected: index === cursor, width }));
28875
+ });
28876
+ return rows;
28877
+ }
28878
+ function CommandPaletteRow({ item, selected, width }) {
28879
+ const shortcutWidth = Math.min(18, Math.max(8, Math.floor(width * 0.22)));
28880
+ const titleWidth = Math.min(26, Math.max(16, Math.floor(width * 0.34)));
28881
+ const descriptionWidth = Math.max(0, width - titleWidth - shortcutWidth - 2);
28882
+ const line = [
28883
+ padCell(item.title, titleWidth),
28884
+ padCell(item.description, descriptionWidth),
28885
+ padCell(item.shortcut ?? "", shortcutWidth, "start")
28886
+ ].join(" ");
28887
+ return React.createElement(
28888
+ Text,
28889
+ {
28890
+ color: selected ? "black" : "white",
28891
+ backgroundColor: selected ? "#f4a261" : SURFACE.dialog,
28892
+ bold: selected
28893
+ },
28894
+ padToWidth(line, width)
28895
+ );
28896
+ }
28897
+ function SlashCommandPalette({ palette }) {
28898
+ const width = promptPanelWidth();
28899
+ const contentWidth = Math.max(24, width - 4);
28900
+ return React.createElement(
28901
+ Box,
28902
+ { alignSelf: "center", width, flexDirection: "column", borderStyle: "single", borderColor: "blue", paddingX: 1, marginTop: 1 },
28903
+ ...palette.items.map((item, index) => {
28904
+ const selected = index === palette.cursor;
28905
+ return React.createElement(
28906
+ Text,
28907
+ {
28908
+ key: item.command,
28909
+ color: selected ? "black" : "white",
28910
+ backgroundColor: selected ? "#f4a261" : SURFACE.dialog,
28911
+ bold: selected
28912
+ },
28913
+ slashCommandLine(item, contentWidth)
28914
+ );
28915
+ })
28916
+ );
28917
+ }
28918
+ function slashCommandLine(item, width) {
28919
+ const commandWidth = Math.max(12, Math.min(22, Math.floor(width * 0.34)));
28920
+ const descriptionWidth = Math.max(0, width - commandWidth - 1);
28921
+ return `${padCell(item.command, commandWidth)} ${padCell(item.description, descriptionWidth)}`;
28922
+ }
28923
+ function InputFrame({
28924
+ borderColor,
28925
+ cursorColor,
28926
+ value,
28927
+ placeholder,
28928
+ marginTop = 1
28929
+ }) {
28930
+ const width = promptPanelWidth();
28931
+ const contentWidth = Math.max(18, width - 2);
28932
+ const rows = inputFrameRows(value, placeholder, contentWidth);
28933
+ return React.createElement(
28934
+ Box,
28935
+ {
28936
+ alignSelf: "center",
28937
+ width,
28938
+ flexDirection: "column",
28939
+ borderStyle: "double",
28940
+ borderTopColor: borderColor,
28941
+ borderLeftColor: borderColor,
28942
+ borderRightColor: "gray",
28943
+ borderBottomColor: "gray",
28944
+ marginTop
28945
+ },
28946
+ ...rows.map((row, index) => React.createElement(InputFrameLine, { key: index, row, width: contentWidth, cursorColor }))
28947
+ );
28948
+ }
28949
+ function InputFrameLine({ row, width, cursorColor }) {
28950
+ if (row.cursorBeforeText) {
28951
+ const cursor2 = row.cursor ? React.createElement(CursorCell, { cursorColor }) : React.createElement(Text, { backgroundColor: SURFACE.input }, " ");
28952
+ const textWidth2 = Math.max(0, width - 1);
28953
+ return React.createElement(
27741
28954
  Box,
27742
28955
  null,
27743
- React.createElement(Text, { color: "cyan", bold: true }, "> "),
27744
- React.createElement(Text, { color: "gray" }, `[perm:${state.permissionPreset}] `),
27745
- React.createElement(Text, { color: state.promptInput ? "white" : "gray" }, value)
27746
- ),
27747
- state.promptError ? React.createElement(Text, { color: "yellow" }, state.promptError) : React.createElement(Text, { color: "gray" }, `enter send | up/down history | p/a/m/o settings | /cowork | /compact | /retry | /exit | ctrl+u clear${diffHelp}${toolHelp}${planHelp}${claudeCodePlanHelp}${retryHelp}`)
28956
+ cursor2,
28957
+ React.createElement(Text, { color: row.placeholder ? "gray" : "white", backgroundColor: SURFACE.input }, padToWidth(row.text, textWidth2))
28958
+ );
28959
+ }
28960
+ const cursor = row.cursor ? React.createElement(CursorCell, { cursorColor }) : null;
28961
+ const textWidth = row.cursor ? Math.max(0, width - 1) : width;
28962
+ const text = fitToWidth(row.text, textWidth);
28963
+ const fillWidth = Math.max(0, textWidth - stringWidth(text));
28964
+ return React.createElement(
28965
+ Box,
28966
+ null,
28967
+ React.createElement(Text, { color: row.placeholder ? "gray" : "white", backgroundColor: SURFACE.input }, text),
28968
+ cursor,
28969
+ React.createElement(Text, { backgroundColor: SURFACE.input }, padToWidth("", fillWidth))
27748
28970
  );
27749
28971
  }
27750
- function CommandBar({ state }) {
27751
- const value = state.promptInput || "Type /stop to stop or /exit to quit";
27752
- const diffHelp = state.turnDiff ? " | tab diff" : "";
27753
- const toolHelp = state.blocks.some((block) => block.kind === "tool") ? " | ctrl+t tools" : "";
27754
- const planHelp = state.workPlan || state.inputMode === "running" ? " | ctrl+p plan" : "";
28972
+ function CursorCell({ cursorColor }) {
28973
+ return React.createElement(Text, { color: "black", backgroundColor: cursorColor, bold: true }, "\x1B[5m \x1B[25m");
28974
+ }
28975
+ function CommandGuide({ hint, color, error }) {
27755
28976
  return React.createElement(
27756
28977
  Box,
27757
- { flexDirection: "column", borderStyle: "single", paddingX: 1 },
28978
+ { alignSelf: "center", width: promptPanelWidth(), flexDirection: "column", marginTop: 1 },
28979
+ error ? React.createElement(Text, { color: "yellow" }, error) : null,
27758
28980
  React.createElement(
27759
28981
  Box,
27760
- null,
27761
- React.createElement(Text, { color: "yellow", bold: true }, ": "),
27762
- React.createElement(Text, { color: "gray" }, `[perm:${state.permissionPreset}] `),
27763
- React.createElement(Text, { color: state.promptInput ? "white" : "gray" }, value)
27764
- ),
27765
- state.promptError ? React.createElement(Text, { color: "yellow" }, state.promptError) : React.createElement(Text, { color: "gray" }, `running | /stop stop | /exit quit${diffHelp}${toolHelp}${planHelp}`)
28982
+ { justifyContent: "flex-end" },
28983
+ React.createElement(Text, { color }, hint)
28984
+ )
28985
+ );
28986
+ }
28987
+ function SessionSelector({ state }) {
28988
+ const items = state.sessionOptions;
28989
+ const width = sessionPanelWidth();
28990
+ const contentWidth = Math.max(36, width - 6);
28991
+ return React.createElement(
28992
+ DialogFrame,
28993
+ { title: "Start Session", accent: "magenta", width },
28994
+ React.createElement(Text, { color: "gray" }, sessionHeaderLine(contentWidth)),
28995
+ ...items.map((item, index) => {
28996
+ const selected = index === state.sessionCursor;
28997
+ const color = selected ? "cyan" : item.kind === "new" ? "green" : item.currentWorkspace ? "white" : "gray";
28998
+ return React.createElement(
28999
+ Text,
29000
+ { key: item.kind === "new" ? "new-session" : item.id, color, bold: selected },
29001
+ sessionOptionLine(item, index, selected, contentWidth)
29002
+ );
29003
+ }),
29004
+ items.length === 0 ? React.createElement(Text, { color: "gray" }, "No saved sessions. Press n to create one.") : null
27766
29005
  );
27767
29006
  }
29007
+ function sessionSelectorColumns(width) {
29008
+ const contentWidth = Math.max(24, width);
29009
+ const compact = contentWidth < 52;
29010
+ const stateWidth = compact ? 6 : 8;
29011
+ const updatedWidth = compact ? 8 : 10;
29012
+ const available = Math.max(0, contentWidth - stateWidth - updatedWidth - 5);
29013
+ const titleMin = Math.min(compact ? 8 : 14, available);
29014
+ const titleMax = compact ? 20 : 42;
29015
+ const titleWidth = Math.min(available, Math.max(titleMin, Math.min(titleMax, Math.floor(available * (compact ? 0.52 : 0.52)))));
29016
+ const workspaceWidth = Math.max(0, available - titleWidth);
29017
+ return { title: titleWidth, state: stateWidth, updated: updatedWidth, workspace: workspaceWidth };
29018
+ }
29019
+ function sessionHeaderLine(width) {
29020
+ const columns = sessionSelectorColumns(width);
29021
+ return sessionSelectorLine(" ", "Session", "State", "Updated", "Workspace", columns);
29022
+ }
29023
+ function sessionOptionLine(item, index, selected, width) {
29024
+ const pointer = selected ? ">" : " ";
29025
+ const columns = sessionSelectorColumns(width);
29026
+ if (item.kind === "new") {
29027
+ return sessionSelectorLine(pointer, "+ New session", "ready", "-", item.cwd ?? "current workspace", columns);
29028
+ }
29029
+ const workspace = item.currentWorkspace ? "current workspace" : item.cwd ?? "-";
29030
+ return sessionSelectorLine(pointer, `${index + 1}. ${item.title}`, item.status, formatSessionAge(item.updatedAt), workspace, columns);
29031
+ }
29032
+ function sessionSelectorLine(pointer, title, state, updated, workspace, columns) {
29033
+ return [
29034
+ `${pointer} ${padCell(title, columns.title)}`,
29035
+ padCell(state, columns.state),
29036
+ padCell(updated, columns.updated),
29037
+ padCell(workspace, columns.workspace, "start")
29038
+ ].join(" ");
29039
+ }
27768
29040
  function ProviderSelector({ state }) {
27769
29041
  const items = state.providerOptions;
27770
29042
  return React.createElement(
27771
- Box,
27772
- { flexDirection: "column", borderStyle: "double", paddingX: 1 },
27773
- React.createElement(Text, { color: "cyan", bold: true }, "Select provider"),
29043
+ DialogFrame,
29044
+ { title: "Providers", accent: "magenta" },
29045
+ React.createElement(Text, { color: "gray" }, `${"Provider".padEnd(22)} ${"Model".padEnd(30)} Status`),
27774
29046
  ...items.map(
27775
29047
  (item, index) => React.createElement(
27776
29048
  Text,
27777
29049
  { key: item.name, color: index === state.providerCursor ? "cyan" : item.available === false ? "gray" : "white", bold: index === state.providerCursor },
27778
- `${index === state.providerCursor ? ">" : " "} ${item.label ?? item.name} model ${item.modelLabel ?? item.model}`
29050
+ `${index === state.providerCursor ? ">" : " "} ${shorten(item.label ?? item.name, 20).padEnd(20)} ${shorten((item.modelLabel ?? item.model) || "-", 30).padEnd(30)} ${providerStatusLabel(item)}`
27779
29051
  )
27780
29052
  ),
27781
29053
  React.createElement(Text, { color: "gray" }, "up/down select | enter apply | esc cancel")
@@ -27784,9 +29056,8 @@ function ProviderSelector({ state }) {
27784
29056
  function AgentSelector({ state }) {
27785
29057
  const items = state.agentOptions;
27786
29058
  return React.createElement(
27787
- Box,
27788
- { flexDirection: "column", borderStyle: "double", paddingX: 1 },
27789
- React.createElement(Text, { color: "cyan", bold: true }, "Select agent"),
29059
+ DialogFrame,
29060
+ { title: "Agents", accent: "magenta" },
27790
29061
  ...items.map(
27791
29062
  (item, index) => React.createElement(
27792
29063
  Text,
@@ -27799,9 +29070,8 @@ function AgentSelector({ state }) {
27799
29070
  }
27800
29071
  function PermissionPresetSelector({ state }) {
27801
29072
  return React.createElement(
27802
- Box,
27803
- { flexDirection: "column", borderStyle: "double", paddingX: 1 },
27804
- React.createElement(Text, { color: "cyan", bold: true }, "Default permission"),
29073
+ DialogFrame,
29074
+ { title: "Default Permission", accent: "magenta" },
27805
29075
  ...PERMISSION_PRESETS.map(
27806
29076
  (item, index) => React.createElement(
27807
29077
  Text,
@@ -27822,16 +29092,15 @@ function ModelEditor({ state }) {
27822
29092
  const current = state.selection?.model ?? "";
27823
29093
  const value = state.modelInput || `Keep ${current}`;
27824
29094
  return React.createElement(
27825
- Box,
27826
- { flexDirection: "column", borderStyle: "double", paddingX: 1 },
27827
- React.createElement(Text, { color: "cyan", bold: true }, "Model"),
29095
+ DialogFrame,
29096
+ { title: "Model", accent: "magenta" },
27828
29097
  React.createElement(
27829
29098
  Box,
27830
29099
  null,
27831
29100
  React.createElement(Text, { color: "cyan", bold: true }, "> "),
27832
29101
  React.createElement(Text, { color: state.modelInput ? "white" : "gray" }, value)
27833
29102
  ),
27834
- state.settingsError ? React.createElement(Text, { color: "yellow" }, state.settingsError) : React.createElement(Text, { color: "gray" }, "enter apply | ctrl+u clear | esc cancel")
29103
+ state.settingsError ? React.createElement(Text, { color: "yellow" }, state.settingsError) : React.createElement(Text, { color: "gray" }, "enter apply | backspace edit | esc cancel")
27835
29104
  );
27836
29105
  }
27837
29106
  function PermissionBar({ state }) {
@@ -27841,18 +29110,211 @@ function PermissionBar({ state }) {
27841
29110
  }
27842
29111
  const detailLines = describeToolInput(pending.request.tool, pending.request.input);
27843
29112
  return React.createElement(
27844
- Box,
27845
- { flexDirection: "column", borderStyle: "double", paddingX: 1 },
27846
- React.createElement(Text, { color: "yellow", bold: true }, "Permission required"),
29113
+ DialogFrame,
29114
+ { title: "Permission Required", accent: "yellow" },
27847
29115
  React.createElement(Text, null, `Allow ${toolLabel(pending.request.tool, pending.request.input)}?`),
27848
29116
  ...detailLines.map((line, index) => React.createElement(Text, { key: index, color: "white" }, line)),
27849
29117
  ...permissionShortcutLines().map((line, index) => React.createElement(Text, { key: `shortcut-${index}`, color: "cyan", bold: true }, line))
27850
29118
  );
27851
29119
  }
29120
+ function DialogFrame({ title, accent, children, width = dialogPanelWidth() }) {
29121
+ return React.createElement(
29122
+ Box,
29123
+ { alignSelf: "center", width, flexDirection: "column", borderStyle: "round", borderColor: accent, paddingX: 2, paddingY: 1, marginTop: 1 },
29124
+ React.createElement(SurfaceLine, { text: title, width: width - 6, backgroundColor: SURFACE.dialog, color: accent, bold: true }),
29125
+ React.createElement(Box, { height: 1 }),
29126
+ children
29127
+ );
29128
+ }
29129
+ function providerStatusLabel(item) {
29130
+ if (item.available !== false) return "ready";
29131
+ if (item.catalog?.status === "missing-auth") return "auth";
29132
+ if (item.catalog?.status === "unavailable") return "offline";
29133
+ return "n/a";
29134
+ }
29135
+ function SurfaceLine({ text, width, backgroundColor, color = "white", bold = false }) {
29136
+ return React.createElement(Text, { color, backgroundColor, bold, wrap: "truncate-end" }, padToWidth(text, width));
29137
+ }
29138
+ function inputFrameRows(value, placeholder, width) {
29139
+ const contentWidth = Math.max(8, width);
29140
+ const textWidthWithCursor = Math.max(1, contentWidth - 1);
29141
+ if (!value) {
29142
+ const line = fitToWidth(` ${placeholder}`, textWidthWithCursor);
29143
+ return [
29144
+ { text: line, placeholder: true, cursor: true, cursorBeforeText: true },
29145
+ ...Array.from({ length: 2 }, () => ({ text: "", placeholder: false, cursor: false, cursorBeforeText: false }))
29146
+ ];
29147
+ }
29148
+ const rawLines = value.split(/\n/);
29149
+ const wrapped = rawLines.flatMap((line) => wrapInputLine(line, textWidthWithCursor));
29150
+ const rows = wrapped.map((line) => ({ text: line, placeholder: false, cursor: false, cursorBeforeText: false }));
29151
+ const last = rows.at(-1);
29152
+ if (last) last.cursor = true;
29153
+ else rows.push({ text: "", placeholder: false, cursor: true, cursorBeforeText: false });
29154
+ while (rows.length < 3) rows.push({ text: "", placeholder: false, cursor: false, cursorBeforeText: false });
29155
+ return rows.slice(-6);
29156
+ }
29157
+ function wrapInputLine(value, width) {
29158
+ const target = Math.max(1, width);
29159
+ if (value === "") return [""];
29160
+ const lines = [];
29161
+ let current = "";
29162
+ for (const char of Array.from(value)) {
29163
+ if (stringWidth(current) + stringWidth(char) > target && current) {
29164
+ lines.push(current);
29165
+ current = char;
29166
+ } else {
29167
+ current += char;
29168
+ }
29169
+ }
29170
+ lines.push(current);
29171
+ return lines;
29172
+ }
29173
+ function wrapBlockLines(lines, width, maxLines = Number.POSITIVE_INFINITY) {
29174
+ const target = Math.max(8, width);
29175
+ const wrapped = [];
29176
+ for (const line of normalizedBlockLines(lines)) {
29177
+ if (wrapped.length >= maxLines) break;
29178
+ const chunks = wrapDisplayLine(line, target);
29179
+ for (const chunk of chunks) {
29180
+ if (wrapped.length >= maxLines) break;
29181
+ wrapped.push(chunk);
29182
+ }
29183
+ }
29184
+ return wrapped.length > 0 ? wrapped : [""];
29185
+ }
29186
+ function wrapDisplayLine(value, width) {
29187
+ const target = Math.max(1, width);
29188
+ if (value === "") return [""];
29189
+ if (shouldTruncateDisplayLine(value)) return [fitToWidth(value, target)];
29190
+ const chars = Array.from(value);
29191
+ const lines = [];
29192
+ let start = 0;
29193
+ while (start < chars.length) {
29194
+ let current = "";
29195
+ let end = start;
29196
+ let breakAt = -1;
29197
+ for (let index = start; index < chars.length; index += 1) {
29198
+ const next = chars[index] ?? "";
29199
+ if (stringWidth(current) + stringWidth(next) > target && current) break;
29200
+ current += next;
29201
+ end = index + 1;
29202
+ if (isSoftWrapBreak(next)) breakAt = end;
29203
+ }
29204
+ if (end >= chars.length) {
29205
+ lines.push(current);
29206
+ break;
29207
+ }
29208
+ if (breakAt > start && stringWidth(chars.slice(start, breakAt).join("").trimEnd()) >= Math.floor(target * 0.45)) {
29209
+ const line = chars.slice(start, breakAt).join("").trimEnd();
29210
+ lines.push(line || current);
29211
+ start = breakAt;
29212
+ while (chars[start] === " ") start += 1;
29213
+ } else {
29214
+ lines.push(current);
29215
+ start = end;
29216
+ }
29217
+ }
29218
+ return lines;
29219
+ }
29220
+ function shouldTruncateDisplayLine(value) {
29221
+ return /^[╭╰╮╯│]/u.test(value.trimStart());
29222
+ }
29223
+ function isSoftWrapBreak(value) {
29224
+ return /\s/u.test(value) || value === "/" || value === "-";
29225
+ }
29226
+ function padToWidth(value, width) {
29227
+ const target = Math.max(0, width);
29228
+ const current = stringWidth(value);
29229
+ if (current >= target) return value;
29230
+ return `${value}${" ".repeat(target - current)}`;
29231
+ }
29232
+ function padCell(value, width, truncate2 = "end") {
29233
+ const text = truncate2 === "start" ? truncateStartToWidth(value, width) : truncateEndToWidth(value, width);
29234
+ return padToWidth(text, width);
29235
+ }
29236
+ function fitToWidth(value, width) {
29237
+ const target = Math.max(0, width);
29238
+ if (stringWidth(value) <= target) return value;
29239
+ let current = "";
29240
+ for (const char of Array.from(value)) {
29241
+ if (stringWidth(current) + stringWidth(char) > target) break;
29242
+ current += char;
29243
+ }
29244
+ return current;
29245
+ }
29246
+ function truncateEndToWidth(value, width) {
29247
+ const target = Math.max(0, width);
29248
+ if (stringWidth(value) <= target) return value;
29249
+ const marker = "\u2026";
29250
+ const markerWidth = stringWidth(marker);
29251
+ if (target <= markerWidth) return fitToWidth(marker, target);
29252
+ return `${fitToWidth(value, target - markerWidth)}${marker}`;
29253
+ }
29254
+ function truncateStartToWidth(value, width) {
29255
+ const target = Math.max(0, width);
29256
+ if (stringWidth(value) <= target) return value;
29257
+ const marker = "\u2026";
29258
+ const markerWidth = stringWidth(marker);
29259
+ if (target <= markerWidth) return fitToWidth(marker, target);
29260
+ let current = "";
29261
+ for (const char of Array.from(value).reverse()) {
29262
+ if (stringWidth(current) + stringWidth(char) > target - markerWidth) break;
29263
+ current = `${char}${current}`;
29264
+ }
29265
+ return `${marker}${current}`;
29266
+ }
27852
29267
  function shorten(value, max) {
27853
29268
  if (value.length <= max) return value;
27854
29269
  return `\u2026${value.slice(value.length - max + 1)}`;
27855
29270
  }
29271
+ function terminalHeight() {
29272
+ const rows = process.stdout.rows;
29273
+ return typeof rows === "number" && Number.isFinite(rows) && rows > 0 ? Math.max(12, rows - 3) : 24;
29274
+ }
29275
+ function terminalWidth() {
29276
+ const columns = process.stdout.columns;
29277
+ return typeof columns === "number" && Number.isFinite(columns) && columns > 0 ? Math.max(48, columns) : 100;
29278
+ }
29279
+ function promptPanelWidth() {
29280
+ return responsivePanelWidth({ min: 40, max: 96, margin: 8, ratio: 0.86 });
29281
+ }
29282
+ function statusSurfaceWidth() {
29283
+ return responsivePanelWidth({ min: 36, max: 112, margin: 8, ratio: 0.95 });
29284
+ }
29285
+ function transcriptPanelWidth() {
29286
+ return responsivePanelWidth({ min: 48, max: 118, margin: 8, ratio: 0.82 });
29287
+ }
29288
+ function userMessageBubbleWidth(lines, columns = terminalWidth()) {
29289
+ const available = Math.max(18, columns - 4);
29290
+ const maxWidth = Math.max(18, Math.min(84, available, Math.floor(columns * 0.68)));
29291
+ const minWidth = Math.min(maxWidth, 18);
29292
+ const contentWidth = Math.max(0, ...normalizedBlockLines(lines).map((line) => stringWidth(line)));
29293
+ return Math.max(minWidth, Math.min(maxWidth, contentWidth + 4));
29294
+ }
29295
+ function normalizedBlockLines(lines) {
29296
+ const normalized = lines.flatMap((line) => String(line ?? "").split(/\r?\n/));
29297
+ return normalized.length > 0 ? normalized : [""];
29298
+ }
29299
+ function dialogPanelWidth() {
29300
+ return responsivePanelWidth({ min: 52, max: 98, margin: 10, ratio: 0.82 });
29301
+ }
29302
+ function sessionPanelWidth() {
29303
+ return responsivePanelWidth({ min: 72, max: 118, margin: 6, ratio: 0.92 });
29304
+ }
29305
+ function commandPalettePanelWidth() {
29306
+ return responsivePanelWidth({ min: 56, max: 88, margin: 10, ratio: 0.74 });
29307
+ }
29308
+ function commandPaletteMaxRows() {
29309
+ return Math.max(6, Math.min(16, terminalHeight() - 12));
29310
+ }
29311
+ function responsivePanelWidth({ min, max, margin, ratio }) {
29312
+ const columns = terminalWidth();
29313
+ const available = Math.max(24, columns - margin);
29314
+ const preferred = Math.min(max, Math.max(min, Math.floor(columns * ratio)));
29315
+ const minimumWithinTerminal = Math.min(min, available);
29316
+ return Math.max(minimumWithinTerminal, Math.min(preferred, available));
29317
+ }
27856
29318
  function formatTokens(value) {
27857
29319
  const tokens = typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.round(value)) : 0;
27858
29320
  if (tokens >= 1e6) return `${trimDecimal2(tokens / 1e6)}m`;
@@ -27866,12 +29328,47 @@ function clamp01(value) {
27866
29328
  if (!Number.isFinite(value)) return 0;
27867
29329
  return Math.max(0, Math.min(1, value));
27868
29330
  }
29331
+ var SURFACE, CSI_U_INPUT, XTERM_MODIFIED_ENTER_INPUT, SLASH_COMMANDS, DEMIAN_WORDMARK_LINES;
27869
29332
  var init_app = __esm({
27870
29333
  "src/ui/tui/app.ts"() {
27871
29334
  "use strict";
29335
+ init_string_width();
27872
29336
  init_store();
27873
29337
  init_presets();
27874
29338
  init_tool_summary();
29339
+ SURFACE = {
29340
+ input: "#050505",
29341
+ status: "#101820",
29342
+ dialog: "#15121e"
29343
+ };
29344
+ CSI_U_INPUT = /^\x1b?\[(\d+)(?:;(\d+))?u$/;
29345
+ XTERM_MODIFIED_ENTER_INPUT = /^\x1b?\[27;([2-4]);13~$/;
29346
+ SLASH_COMMANDS = [
29347
+ { command: "/cowork", insert: "/cowork", argument: true, mode: "prompt", description: "Run cowork sub agents on a task", aliases: ["agent", "parallel", "review"] },
29348
+ { command: "/compact", insert: "/compact", mode: "prompt", description: "Compact current conversation context", aliases: ["context", "compress"] },
29349
+ { command: "/retry", insert: "/retry", mode: "prompt", description: "Retry the last task", aliases: ["again", "rerun"] },
29350
+ { command: "/session", insert: "/session", argument: true, mode: "prompt", description: "Manage saved conversations", aliases: ["sessions", "conversation", "conv"] },
29351
+ { command: "/session list", insert: "/session list", mode: "prompt", description: "List saved conversations", aliases: ["sessions", "ls"] },
29352
+ { command: "/session new", insert: "/session new", argument: true, mode: "prompt", description: "Create a new conversation", aliases: ["new", "create"] },
29353
+ { command: "/session switch", insert: "/session switch", argument: true, mode: "prompt", description: "Switch to a saved conversation", aliases: ["open", "select", "use"] },
29354
+ { command: "/session rename", insert: "/session rename", argument: true, mode: "prompt", description: "Rename the current conversation", aliases: ["name"] },
29355
+ { command: "/session delete", insert: "/session delete", argument: true, mode: "prompt", description: "Delete a saved conversation", aliases: ["remove", "rm"] },
29356
+ { command: "/goal", insert: "/goal", argument: true, mode: "prompt", description: "Start or inspect a goal loop", aliases: ["task", "objective"] },
29357
+ { command: "/goal status", insert: "/goal status", mode: "prompt", description: "Show active goal status", aliases: ["status"] },
29358
+ { command: "/goal clear", insert: "/goal clear", mode: "prompt", description: "Clear visible goal state", aliases: ["reset"] },
29359
+ { command: "/ralph-loop", insert: "/ralph-loop", argument: true, mode: "prompt", description: "Start a goal loop with Ralph mode", aliases: ["ralph"] },
29360
+ { command: "/cancel-ralph", insert: "/cancel-ralph", mode: "prompt", description: "Pause the active Ralph loop", aliases: ["cancel", "pause"] },
29361
+ { command: "/stop", insert: "/stop", mode: "running", description: "Stop the running task", aliases: ["cancel"] },
29362
+ { command: "/exit", insert: "/exit", mode: "both", description: "Exit Demian", aliases: ["quit", "close"] },
29363
+ { command: "/quit", insert: "/quit", mode: "both", description: "Exit Demian", aliases: ["exit", "close"] }
29364
+ ];
29365
+ DEMIAN_WORDMARK_LINES = [
29366
+ " _ _ ",
29367
+ " __| | ___ _ __ ___ (_) __ _ _ __ ",
29368
+ " / _` |/ _ \\ '_ ` _ \\| |/ _` | '_ \\ ",
29369
+ "| (_| | __/ | | | | | | (_| | | | |",
29370
+ " \\__,_|\\___|_| |_| |_|_|\\__,_|_| |_|"
29371
+ ];
27875
29372
  }
27876
29373
  });
27877
29374
 
@@ -31892,8 +33389,8 @@ async function summarizeGoalTitleWithProvider(options) {
31892
33389
  }
31893
33390
  function normalizeGoalTitle(value, objective) {
31894
33391
  const raw = typeof value === "string" ? value : "";
31895
- const firstLine = raw.split(/\r?\n/).find((line) => line.trim()) ?? "";
31896
- const cleaned = stripDecorations(firstLine);
33392
+ const firstLine2 = raw.split(/\r?\n/).find((line) => line.trim()) ?? "";
33393
+ const cleaned = stripDecorations(firstLine2);
31897
33394
  return truncateGoalTitle(cleaned || fallbackGoalTitle(objective));
31898
33395
  }
31899
33396
  function fallbackGoalTitle(objective) {
@@ -32599,17 +34096,17 @@ function findDependencyCycle(group) {
32599
34096
  const byId = new Map(group.map((member) => [member.memberId, member]));
32600
34097
  const visiting = /* @__PURE__ */ new Set();
32601
34098
  const visited = /* @__PURE__ */ new Set();
32602
- const path36 = [];
34099
+ const path37 = [];
32603
34100
  const visit = (id) => {
32604
- if (visiting.has(id)) return [...path36.slice(path36.indexOf(id)), id];
34101
+ if (visiting.has(id)) return [...path37.slice(path37.indexOf(id)), id];
32605
34102
  if (visited.has(id)) return void 0;
32606
34103
  visiting.add(id);
32607
- path36.push(id);
34104
+ path37.push(id);
32608
34105
  for (const dep of byId.get(id)?.dependsOn ?? []) {
32609
34106
  const cycle = visit(dep);
32610
34107
  if (cycle) return cycle;
32611
34108
  }
32612
- path36.pop();
34109
+ path37.pop();
32613
34110
  visiting.delete(id);
32614
34111
  visited.add(id);
32615
34112
  return void 0;
@@ -33993,14 +35490,224 @@ var init_settings = __esm({
33993
35490
  }
33994
35491
  });
33995
35492
 
35493
+ // src/ui/conversations.ts
35494
+ import { mkdir as mkdir15, readFile as readFile18, readdir as readdir4, rm as rm4, writeFile as writeFile15 } from "node:fs/promises";
35495
+ import path35 from "node:path";
35496
+ function createConversationRecord(input2) {
35497
+ const timestamp = input2.now ?? Date.now();
35498
+ return {
35499
+ id: sanitizeConversationId(input2.id),
35500
+ title: input2.title?.trim() || "New session",
35501
+ createdAt: timestamp,
35502
+ updatedAt: timestamp,
35503
+ cwd: path35.resolve(input2.cwd),
35504
+ modelHistory: cleanModelHistory(input2.history ?? []),
35505
+ snapshot: input2.snapshot
35506
+ };
35507
+ }
35508
+ async function loadConversationIndex(storageDir = defaultDemianStorageDir()) {
35509
+ const index = await readJson(path35.join(storageDir, CONVERSATION_INDEX_FILE));
35510
+ const conversations = Array.isArray(index?.conversations) ? index.conversations.map((item) => {
35511
+ if (!item || typeof item !== "object") return void 0;
35512
+ const object2 = item;
35513
+ const id = typeof object2.id === "string" ? sanitizeConversationId(object2.id) : "";
35514
+ if (!id) return void 0;
35515
+ return {
35516
+ id,
35517
+ title: typeof object2.title === "string" && object2.title.trim() ? object2.title.trim() : "New session",
35518
+ updatedAt: numberOrNow(object2.updatedAt),
35519
+ cwd: typeof object2.cwd === "string" ? object2.cwd : void 0
35520
+ };
35521
+ }).filter((item) => Boolean(item)) : [];
35522
+ return {
35523
+ selectedSessionId: typeof index?.selectedSessionId === "string" ? sanitizeConversationId(index.selectedSessionId) : void 0,
35524
+ conversations
35525
+ };
35526
+ }
35527
+ async function loadConversationRecords(storageDir = defaultDemianStorageDir()) {
35528
+ const index = await loadConversationIndex(storageDir);
35529
+ const ids = new Set(index.conversations.map((item) => item.id));
35530
+ for (const id of await listConversationRecordIds(storageDir)) ids.add(id);
35531
+ const records = (await Promise.all(
35532
+ [...ids].map(async (id) => {
35533
+ const item = await readJson(conversationRecordPath(storageDir, id));
35534
+ return normalizeConversationRecord(item, id);
35535
+ })
35536
+ )).filter((item) => Boolean(item));
35537
+ records.sort((a, b2) => b2.updatedAt - a.updatedAt);
35538
+ return { selectedSessionId: index.selectedSessionId, records };
35539
+ }
35540
+ async function saveConversationRecords(storageDir, records, selectedSessionId) {
35541
+ const root = storageDir ?? defaultDemianStorageDir();
35542
+ const kept = [...records].sort((a, b2) => b2.updatedAt - a.updatedAt).slice(0, MAX_STORED_CONVERSATIONS).map((record) => ({ ...record, id: sanitizeConversationId(record.id), modelHistory: cleanModelHistory(record.modelHistory) }));
35543
+ await mkdir15(path35.join(root, CONVERSATIONS_DIR), { recursive: true });
35544
+ for (const record of kept) {
35545
+ await writeJson(conversationRecordPath(root, record.id), {
35546
+ version: 1,
35547
+ id: record.id,
35548
+ title: record.title,
35549
+ createdAt: record.createdAt,
35550
+ updatedAt: record.updatedAt,
35551
+ cwd: record.cwd,
35552
+ modelHistory: record.modelHistory,
35553
+ snapshot: record.snapshot
35554
+ });
35555
+ }
35556
+ await writeJson(path35.join(root, CONVERSATION_INDEX_FILE), {
35557
+ version: 1,
35558
+ selectedSessionId,
35559
+ conversations: kept.map((record) => ({
35560
+ id: record.id,
35561
+ title: record.title,
35562
+ updatedAt: record.updatedAt,
35563
+ cwd: record.cwd,
35564
+ path: conversationDir(root, record.id)
35565
+ }))
35566
+ });
35567
+ }
35568
+ async function deleteConversationRecord(storageDir, id) {
35569
+ const root = storageDir ?? defaultDemianStorageDir();
35570
+ await rm4(conversationDir(root, id), { recursive: true, force: true });
35571
+ }
35572
+ function findConversation(records, target) {
35573
+ const value = target?.trim();
35574
+ if (!value) return void 0;
35575
+ const index = Number(value);
35576
+ if (Number.isInteger(index) && index >= 1 && index <= records.length) return records[index - 1];
35577
+ const normalized = value.toLowerCase();
35578
+ return records.find((record) => record.id === value || record.id.startsWith(value)) ?? records.find((record) => record.title.toLowerCase() === normalized) ?? records.find((record) => record.title.toLowerCase().includes(normalized));
35579
+ }
35580
+ function sortConversationRecords(records, cwd) {
35581
+ const resolvedCwd = path35.resolve(cwd);
35582
+ return [...records].sort((a, b2) => {
35583
+ const aCurrent = isConversationForCwd(a, resolvedCwd) ? 0 : 1;
35584
+ const bCurrent = isConversationForCwd(b2, resolvedCwd) ? 0 : 1;
35585
+ if (aCurrent !== bCurrent) return aCurrent - bCurrent;
35586
+ const statusDelta = conversationStatusRank(conversationRuntimeStatus(a, resolvedCwd)) - conversationStatusRank(conversationRuntimeStatus(b2, resolvedCwd));
35587
+ if (statusDelta !== 0) return statusDelta;
35588
+ return b2.updatedAt - a.updatedAt;
35589
+ });
35590
+ }
35591
+ function conversationRuntimeStatus(record, cwd) {
35592
+ if (record.snapshot?.inputMode === "running") return "running";
35593
+ return isConversationForCwd(record, cwd) ? "ready" : "stored";
35594
+ }
35595
+ function isConversationForCwd(record, cwd) {
35596
+ return path35.resolve(record.cwd) === path35.resolve(cwd);
35597
+ }
35598
+ function conversationSummaryLine(record, index, activeId) {
35599
+ const active = record.id === activeId ? "*" : " ";
35600
+ const age = formatRelativeAge(Date.now() - record.updatedAt);
35601
+ return `${active} ${index + 1}. ${record.title} ${record.id} ${age} ${record.cwd}`;
35602
+ }
35603
+ function conversationStatusRank(status) {
35604
+ if (status === "running") return 0;
35605
+ if (status === "ready") return 1;
35606
+ return 2;
35607
+ }
35608
+ function titleFromHistory(history, fallback = "New session") {
35609
+ const firstUser = history.find((message) => message.role === "user" && typeof message.content === "string");
35610
+ return firstLine(firstUser?.content ?? fallback);
35611
+ }
35612
+ function cleanModelHistory(history) {
35613
+ return history.filter((message) => !isInternalModelHistoryMessage(message)).slice(-MAX_MODEL_HISTORY);
35614
+ }
35615
+ function conversationDir(storageDir, id) {
35616
+ return path35.join(storageDir, CONVERSATIONS_DIR, sanitizeConversationId(id));
35617
+ }
35618
+ function conversationRecordPath(storageDir, id) {
35619
+ return path35.join(conversationDir(storageDir, id), CONVERSATION_FILE);
35620
+ }
35621
+ async function listConversationRecordIds(storageDir) {
35622
+ try {
35623
+ const entries = await readdir4(path35.join(storageDir, CONVERSATIONS_DIR), { withFileTypes: true });
35624
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => sanitizeConversationId(entry.name)).filter(Boolean);
35625
+ } catch {
35626
+ return [];
35627
+ }
35628
+ }
35629
+ async function readJson(filePath) {
35630
+ try {
35631
+ return JSON.parse(await readFile18(filePath, "utf8"));
35632
+ } catch {
35633
+ return void 0;
35634
+ }
35635
+ }
35636
+ async function writeJson(filePath, value) {
35637
+ await mkdir15(path35.dirname(filePath), { recursive: true });
35638
+ await writeFile15(filePath, `${JSON.stringify(value, null, 2)}
35639
+ `, "utf8");
35640
+ }
35641
+ function normalizeConversationRecord(value, fallbackId) {
35642
+ if (!value || typeof value !== "object") return void 0;
35643
+ const object2 = value;
35644
+ const id = sanitizeConversationId(typeof object2.id === "string" ? object2.id : fallbackId);
35645
+ if (!id) return void 0;
35646
+ const history = Array.isArray(object2.modelHistory) ? object2.modelHistory.filter(isMessage) : [];
35647
+ const snapshot = object2.snapshot && typeof object2.snapshot === "object" && !Array.isArray(object2.snapshot) ? object2.snapshot : void 0;
35648
+ return {
35649
+ id,
35650
+ title: typeof object2.title === "string" && object2.title.trim() ? object2.title.trim() : titleFromHistory(history),
35651
+ createdAt: numberOrNow(object2.createdAt),
35652
+ updatedAt: numberOrNow(object2.updatedAt),
35653
+ cwd: typeof object2.cwd === "string" && object2.cwd.trim() ? object2.cwd : process.cwd(),
35654
+ modelHistory: cleanModelHistory(history),
35655
+ snapshot
35656
+ };
35657
+ }
35658
+ function isMessage(value) {
35659
+ if (!value || typeof value !== "object") return false;
35660
+ const message = value;
35661
+ if (message.role === "user") return typeof message.content === "string" || Array.isArray(message.content);
35662
+ if (message.role === "assistant") return message.content === void 0 || message.content === null || typeof message.content === "string" || Array.isArray(message.toolCalls);
35663
+ if (message.role === "tool") return typeof message.toolCallId === "string" && typeof message.name === "string" && typeof message.content === "string";
35664
+ if (message.role === "system") return typeof message.content === "string";
35665
+ return false;
35666
+ }
35667
+ function isInternalModelHistoryMessage(message) {
35668
+ return message.role === "user" && typeof message.content === "string" && /^You are running as sub agent:/i.test(message.content.trim());
35669
+ }
35670
+ function sanitizeConversationId(id) {
35671
+ return String(id || "conversation").replace(/[^a-zA-Z0-9._-]+/g, "_") || "conversation";
35672
+ }
35673
+ function numberOrNow(value) {
35674
+ return typeof value === "number" && Number.isFinite(value) ? value : Date.now();
35675
+ }
35676
+ function firstLine(value) {
35677
+ const line = value.replace(/\s+/g, " ").trim();
35678
+ if (!line) return "New session";
35679
+ return line.length > 60 ? `${line.slice(0, 57)}...` : line;
35680
+ }
35681
+ function formatRelativeAge(ms2) {
35682
+ const seconds = Math.max(0, Math.floor(ms2 / 1e3));
35683
+ if (seconds < 60) return `${seconds}s ago`;
35684
+ const minutes = Math.floor(seconds / 60);
35685
+ if (minutes < 60) return `${minutes}m ago`;
35686
+ const hours = Math.floor(minutes / 60);
35687
+ if (hours < 48) return `${hours}h ago`;
35688
+ return `${Math.floor(hours / 24)}d ago`;
35689
+ }
35690
+ var CONVERSATIONS_DIR, CONVERSATION_INDEX_FILE, CONVERSATION_FILE, MAX_STORED_CONVERSATIONS, MAX_MODEL_HISTORY;
35691
+ var init_conversations = __esm({
35692
+ "src/ui/conversations.ts"() {
35693
+ "use strict";
35694
+ init_transcript();
35695
+ CONVERSATIONS_DIR = "conversations";
35696
+ CONVERSATION_INDEX_FILE = "conversations.json";
35697
+ CONVERSATION_FILE = "conversation.json";
35698
+ MAX_STORED_CONVERSATIONS = 40;
35699
+ MAX_MODEL_HISTORY = 80;
35700
+ }
35701
+ });
35702
+
33996
35703
  // src/ui/tui/controller.ts
33997
35704
  var controller_exports = {};
33998
35705
  __export(controller_exports, {
33999
35706
  runTuiSession: () => runTuiSession
34000
35707
  });
34001
- import path35 from "node:path";
35708
+ import path36 from "node:path";
34002
35709
  async function runTuiSession(flags, store) {
34003
- const cwd = path35.resolve(flags.cwd ?? process.cwd());
35710
+ const cwd = path36.resolve(flags.cwd ?? process.cwd());
34004
35711
  const eventBus = new EventBus();
34005
35712
  eventBus.subscribe((event) => store.handleEvent(event));
34006
35713
  const loadedConfig = await loadConfig({ cwd, configPath: flags.configPath });
@@ -34032,10 +35739,20 @@ async function runTuiSession(flags, store) {
34032
35739
  }
34033
35740
  });
34034
35741
  let nextPrompt = flags.prompt;
34035
- 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] : [];
34036
35748
  let lastExternalSessionKey;
34037
- const externalSessions = new ClaudeCodeSessionMap();
34038
- 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
+ }
34039
35756
  const goalTitleGenerator = async (input2) => {
34040
35757
  const selection = store.currentSelection();
34041
35758
  const runtime = resolveProviderRuntimeConfig(config, selection);
@@ -34053,6 +35770,14 @@ async function runTuiSession(flags, store) {
34053
35770
  if (resolved.kind === "external-agent") return input2.objective.trim().split(/\s+/).slice(0, 8).join(" ");
34054
35771
  return summarizeGoalTitleWithProvider({ ...input2, provider: resolved.provider, model: resolved.model });
34055
35772
  };
35773
+ if (shouldShowStartupSessionSelector) {
35774
+ const selected = await store.requestSessionSelection(startupSessionOptions());
35775
+ if (selected.kind === "exit" || store.exitRequested()) {
35776
+ await saveCurrentSelection();
35777
+ return 0;
35778
+ }
35779
+ await applyStartupSessionSelection(selected);
35780
+ }
34056
35781
  for (; ; ) {
34057
35782
  const prompt = await store.requestPrompt(nextPrompt);
34058
35783
  nextPrompt = void 0;
@@ -34061,11 +35786,17 @@ async function runTuiSession(flags, store) {
34061
35786
  return 0;
34062
35787
  }
34063
35788
  if (!prompt) return 0;
35789
+ const sessionCommand = parseSessionCommand(prompt);
35790
+ if (sessionCommand) {
35791
+ await handleSessionCommand(sessionCommand);
35792
+ continue;
35793
+ }
34064
35794
  if (isCompactCommand(prompt)) {
34065
35795
  const result = compactInteractiveHistory(history, config.context.main);
34066
35796
  history = result.messages;
34067
35797
  store.prepareForPrompt("waiting for next message");
34068
35798
  store.markHistoryCompacted(result);
35799
+ await persistCurrentConversation();
34069
35800
  continue;
34070
35801
  }
34071
35802
  const mode = resolveAgentMode(config, flags.mode);
@@ -34217,6 +35948,7 @@ async function runTuiSession(flags, store) {
34217
35948
  history = interactiveHistoryFromRunMessages(result.messages);
34218
35949
  lastExternalSessionKey = externalSessionKey ?? lastExternalSessionKey;
34219
35950
  }
35951
+ await persistCurrentConversation();
34220
35952
  } catch (error) {
34221
35953
  store.setStopTask(void 0);
34222
35954
  if (activeAbort?.signal.aborted) {
@@ -34229,6 +35961,7 @@ async function runTuiSession(flags, store) {
34229
35961
  store.setStopTask(void 0);
34230
35962
  }
34231
35963
  if (store.exitRequested()) {
35964
+ await persistCurrentConversation();
34232
35965
  await saveCurrentSelection();
34233
35966
  return 0;
34234
35967
  }
@@ -34237,6 +35970,161 @@ async function runTuiSession(flags, store) {
34237
35970
  async function saveCurrentSelection() {
34238
35971
  await saveSelection(store.currentSelection());
34239
35972
  }
35973
+ async function handleSessionCommand(command) {
35974
+ if (!conversationsEnabled) {
35975
+ store.showSystemMessage("Sessions", "Session management is available in demian-cli TUI, but this embedded runtime lets the host manage sessions.");
35976
+ store.prepareForPrompt("waiting for next message");
35977
+ return;
35978
+ }
35979
+ if (!currentConversation) {
35980
+ currentConversation = createConversationRecord({ id: flags.sessionId ?? createRootSessionId(), cwd });
35981
+ conversationRecords.set(currentConversation.id, currentConversation);
35982
+ }
35983
+ if (command.action === "help") {
35984
+ store.showSystemMessage("Sessions", sessionUsage());
35985
+ store.prepareForPrompt("waiting for next message");
35986
+ return;
35987
+ }
35988
+ if (command.action === "list") {
35989
+ store.showSystemMessage("Sessions", sessionListMessage());
35990
+ store.prepareForPrompt("waiting for next message");
35991
+ return;
35992
+ }
35993
+ if (command.action === "current") {
35994
+ store.showSystemMessage("Current Session", conversationSummaryLine(currentConversation, sortedConversations().findIndex((item) => item.id === currentConversation?.id), currentConversation.id));
35995
+ store.prepareForPrompt("waiting for next message");
35996
+ return;
35997
+ }
35998
+ if (command.action === "new") {
35999
+ await persistCurrentConversation();
36000
+ const next = createConversationRecord({ id: createRootSessionId(), cwd, title: command.title });
36001
+ conversationRecords.set(next.id, next);
36002
+ await switchConversation(next);
36003
+ store.prepareForPrompt(`new session: ${next.title}`);
36004
+ await persistCurrentConversation();
36005
+ return;
36006
+ }
36007
+ if (command.action === "switch") {
36008
+ const target = findConversation(sortedConversations(), command.target);
36009
+ if (!target) {
36010
+ store.showSystemMessage("Sessions", `No session matched "${command.target ?? ""}".
36011
+
36012
+ ${sessionListMessage()}`);
36013
+ store.prepareForPrompt("waiting for next message");
36014
+ return;
36015
+ }
36016
+ await persistCurrentConversation();
36017
+ await switchConversation(target);
36018
+ store.prepareForPrompt(`switched session: ${target.title}`);
36019
+ await persistCurrentConversation();
36020
+ return;
36021
+ }
36022
+ if (command.action === "delete") {
36023
+ const target = findConversation(sortedConversations(), command.target);
36024
+ if (!target) {
36025
+ store.showSystemMessage("Sessions", `No session matched "${command.target ?? ""}".`);
36026
+ store.prepareForPrompt("waiting for next message");
36027
+ return;
36028
+ }
36029
+ conversationRecords.delete(target.id);
36030
+ runtimeByConversation.delete(target.id);
36031
+ await deleteConversationRecord(flags.conversationStorageDir, target.id);
36032
+ if (currentConversation?.id === target.id) {
36033
+ const next = sortedConversations()[0] ?? createConversationRecord({ id: createRootSessionId(), cwd });
36034
+ conversationRecords.set(next.id, next);
36035
+ await switchConversation(next);
36036
+ }
36037
+ store.prepareForPrompt(`deleted session: ${target.title}`);
36038
+ await persistCurrentConversation();
36039
+ return;
36040
+ }
36041
+ if (command.action === "rename") {
36042
+ const title = command.title?.trim();
36043
+ if (!title) {
36044
+ store.showSystemMessage("Sessions", "Usage: /session rename <title>");
36045
+ store.prepareForPrompt("waiting for next message");
36046
+ return;
36047
+ }
36048
+ currentConversation.title = title;
36049
+ currentConversation.updatedAt = Date.now();
36050
+ store.prepareForPrompt(`renamed session: ${title}`);
36051
+ await persistCurrentConversation();
36052
+ return;
36053
+ }
36054
+ if (command.action === "clear") {
36055
+ history = [];
36056
+ currentConversation.modelHistory = [];
36057
+ currentConversation.snapshot = void 0;
36058
+ currentConversation.title = "New session";
36059
+ currentConversation.updatedAt = Date.now();
36060
+ store.clearConversation(currentConversation.title);
36061
+ store.prepareForPrompt("cleared current conversation");
36062
+ await persistCurrentConversation();
36063
+ }
36064
+ }
36065
+ function startupSessionOptions() {
36066
+ const records = sortedConversations();
36067
+ const sessionOptions = records.map((record) => ({
36068
+ kind: "session",
36069
+ id: record.id,
36070
+ title: record.title,
36071
+ cwd: record.cwd,
36072
+ status: conversationRuntimeStatus(record, cwd),
36073
+ updatedAt: record.updatedAt,
36074
+ currentWorkspace: path36.resolve(record.cwd) === cwd
36075
+ }));
36076
+ return [...sessionOptions, { kind: "new", title: "New session", cwd, status: "ready", currentWorkspace: true }];
36077
+ }
36078
+ async function applyStartupSessionSelection(selection) {
36079
+ if (selection.kind === "new") {
36080
+ const next = createConversationRecord({ id: createRootSessionId(), cwd });
36081
+ conversationRecords.set(next.id, next);
36082
+ await switchConversation(next);
36083
+ store.prepareForPrompt("new session ready");
36084
+ await saveConversationRecords(flags.conversationStorageDir, [...conversationRecords.values()], next.id);
36085
+ return;
36086
+ }
36087
+ const target = conversationRecords.get(selection.id) ?? findConversation(sortedConversations(), selection.id);
36088
+ if (!target) {
36089
+ const next = createConversationRecord({ id: createRootSessionId(), cwd });
36090
+ conversationRecords.set(next.id, next);
36091
+ await switchConversation(next);
36092
+ store.prepareForPrompt("new session ready");
36093
+ await saveConversationRecords(flags.conversationStorageDir, [...conversationRecords.values()], next.id);
36094
+ return;
36095
+ }
36096
+ await switchConversation(target);
36097
+ store.prepareForPrompt(`session ready: ${target.title}`);
36098
+ await saveConversationRecords(flags.conversationStorageDir, [...conversationRecords.values()], target.id);
36099
+ }
36100
+ async function switchConversation(record) {
36101
+ currentConversation = record;
36102
+ rootSessionId = record.id;
36103
+ history = [...record.modelHistory];
36104
+ const runtime = runtimeByConversation.get(record.id) ?? { externalSessions: new ClaudeCodeSessionMap(), lastExternalSessionKey: void 0 };
36105
+ externalSessions = runtime.externalSessions;
36106
+ lastExternalSessionKey = runtime.lastExternalSessionKey;
36107
+ runtimeByConversation.set(record.id, runtime);
36108
+ store.restoreConversationSnapshot(record.snapshot, { sessionId: record.id, title: record.title, cwd: record.cwd || cwd });
36109
+ }
36110
+ async function persistCurrentConversation() {
36111
+ if (!conversationsEnabled || !currentConversation) return;
36112
+ currentConversation.modelHistory = cleanModelHistory(history);
36113
+ if (currentConversation.title === "New session" && currentConversation.modelHistory.length > 0) currentConversation.title = titleFromHistory(currentConversation.modelHistory);
36114
+ currentConversation.snapshot = store.conversationSnapshot();
36115
+ currentConversation.updatedAt = Date.now();
36116
+ conversationRecords.set(currentConversation.id, currentConversation);
36117
+ runtimeByConversation.set(currentConversation.id, { externalSessions, lastExternalSessionKey });
36118
+ await saveConversationRecords(flags.conversationStorageDir, [...conversationRecords.values()], currentConversation.id);
36119
+ }
36120
+ function sortedConversations() {
36121
+ return sortConversationRecords([...conversationRecords.values()], cwd);
36122
+ }
36123
+ function sessionListMessage() {
36124
+ const records = sortedConversations();
36125
+ if (!records.length) return "No saved sessions.";
36126
+ return ["Saved sessions:", ...records.map((record, index) => conversationSummaryLine(record, index, currentConversation?.id)), "", "Use /session switch <number|id|title> to open one."].join("\n");
36127
+ }
34240
36128
  async function saveSelection(selection) {
34241
36129
  if (!shouldPersistSelection(selection)) return;
34242
36130
  const key = preferenceKey(selection);
@@ -34248,6 +36136,34 @@ async function runTuiSession(flags, store) {
34248
36136
  function isGoalStateClearingAction(action) {
34249
36137
  return action === "status" || action === "pause" || action === "resume";
34250
36138
  }
36139
+ async function initializeConversationState(cwd, flags) {
36140
+ const loaded = await loadConversationRecords(flags.conversationStorageDir);
36141
+ const records = new Map(loaded.records.map((record) => [record.id, record]));
36142
+ const shouldResumeSelected = !flags.prompt.trim();
36143
+ const orderedRecords = sortConversationRecords([...records.values()], cwd);
36144
+ const preferred = (flags.sessionId ? findConversation(orderedRecords, flags.sessionId) : void 0) ?? (shouldResumeSelected && loaded.selectedSessionId ? findConversation(orderedRecords, loaded.selectedSessionId) : void 0) ?? (shouldResumeSelected ? orderedRecords[0] : void 0);
36145
+ const current = preferred ?? (flags.prompt.trim() || flags.sessionId || flags.initialHistory?.length ? createConversationRecord({
36146
+ id: flags.sessionId ?? createRootSessionId(),
36147
+ cwd,
36148
+ history: flags.initialHistory
36149
+ }) : void 0);
36150
+ if (current && flags.initialHistory?.length) current.modelHistory = cleanModelHistory(flags.initialHistory);
36151
+ if (current) records.set(current.id, current);
36152
+ return { records, current };
36153
+ }
36154
+ function sessionUsage() {
36155
+ return [
36156
+ "Usage:",
36157
+ " /session list",
36158
+ " /session new [title]",
36159
+ " /session switch <number|id|title>",
36160
+ " /session rename <title>",
36161
+ " /session delete <number|id|title>",
36162
+ " /session clear",
36163
+ "",
36164
+ "Aliases: /sessions, /conversation, /conversations, /conv"
36165
+ ].join("\n");
36166
+ }
34251
36167
  var init_controller = __esm({
34252
36168
  "src/ui/tui/controller.ts"() {
34253
36169
  "use strict";
@@ -34268,11 +36184,13 @@ var init_controller = __esm({
34268
36184
  init_history();
34269
36185
  init_preferences();
34270
36186
  init_settings();
36187
+ init_conversations();
34271
36188
  }
34272
36189
  });
34273
36190
 
34274
36191
  // src/tui.ts
34275
36192
  init_parser();
36193
+ import { readFileSync as readFileSync2 } from "node:fs";
34276
36194
 
34277
36195
  // src/doctor/policies.ts
34278
36196
  import { existsSync } from "node:fs";
@@ -35082,8 +37000,8 @@ async function fileExists2(filePath) {
35082
37000
  }
35083
37001
  async function readJsonSafe(filePath) {
35084
37002
  try {
35085
- const { readFile: readFile18 } = await import("node:fs/promises");
35086
- const text = await readFile18(filePath, "utf8");
37003
+ const { readFile: readFile19 } = await import("node:fs/promises");
37004
+ const text = await readFile19(filePath, "utf8");
35087
37005
  return JSON.parse(text);
35088
37006
  } catch {
35089
37007
  return void 0;
@@ -35222,9 +37140,9 @@ async function main(argv = process.argv.slice(2)) {
35222
37140
  ]);
35223
37141
  const React2 = ReactModule.default;
35224
37142
  const store = new TuiStore2();
35225
- const instance = render(React2.createElement(TuiApp2, { store }));
37143
+ const instance = render(React2.createElement(TuiApp2, { store, version: packageVersion() }));
35226
37144
  try {
35227
- const code = await runTuiSession2(flags, store);
37145
+ const code = await runTuiSession2({ ...flags, conversationManagement: true }, store);
35228
37146
  setTimeout(() => instance.unmount(), 100);
35229
37147
  await instance.waitUntilExit();
35230
37148
  return code;
@@ -35241,6 +37159,14 @@ async function main(argv = process.argv.slice(2)) {
35241
37159
  throw error;
35242
37160
  }
35243
37161
  }
37162
+ function packageVersion() {
37163
+ try {
37164
+ const metadata = JSON.parse(readFileSync2(new URL("../package.json", import.meta.url), "utf8"));
37165
+ return typeof metadata.version === "string" && metadata.version.trim() ? metadata.version : "dev";
37166
+ } catch {
37167
+ return "dev";
37168
+ }
37169
+ }
35244
37170
  function parseArgs(argv) {
35245
37171
  const out = { prompt: "", transcript: true, images: [] };
35246
37172
  const rest = [];
@@ -35361,15 +37287,18 @@ Usage:
35361
37287
  Default:
35362
37288
  demian and demian-cli launch the Ink terminal UI.
35363
37289
  The TUI shows provider/model defaults before asking for the first message.
35364
- Press p to select provider, m to edit model, then Enter to send.
35365
- Press a to select the main agent before sending a message.
35366
- Press o to select the default permission preset: deny, ask, auto, or full.
37290
+ Press Esc then p to select provider, Esc then m to edit model, then Enter to send.
37291
+ Press Esc then a to select the main agent before sending a message.
37292
+ Press Esc then o to select the default permission preset: deny, ask, auto, or full.
35367
37293
  Press up/down in the message composer to recall previous prompts.
35368
- Provider/model selections are remembered in .demian/preferences.json.
37294
+ Provider/model selections are remembered in ~/.demian/preferences.json.
35369
37295
  After each answer, the TUI returns to standby for the next message.
35370
37296
  Use /cowork <task> to explicitly ask Demian to coordinate cowork sub agents in multi-agent mode.
35371
37297
  Use /compact to compact current history, /stop to stop active work, and /exit or /quit to close the TUI.
35372
- Tool approvals show the requested command/path in the bottom bar.
37298
+ Use /session list, /session new, /session switch <number|id|title>, /session rename <title>,
37299
+ and /session delete <number|id|title> to manage saved CLI conversations.
37300
+ Press Esc then q to quit, Esc then s to stop a running task, and Esc then u to clear the composer.
37301
+ Tool approvals show the requested command/path in a permission dialog.
35373
37302
  Press y to allow once, a to always allow the grant scope, or n/Enter to deny.
35374
37303
  Prompt arguments are still accepted as a compatibility shortcut.
35375
37304