@crazyhappyone/dsh-tui 0.1.0-alpha.20 → 0.1.0-alpha.23

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.
Files changed (2) hide show
  1. package/dist/index.js +391 -194
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -47391,7 +47391,7 @@ var GRAPHEME$2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
47391
47391
  function escapeContent(text4) {
47392
47392
  return text4.replace(/[\u0000-\u0008\u000B-\u001F\u007F]/g, (char) => `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`).replace(/\u001B/g, "\\x1b");
47393
47393
  }
47394
- var WIDE_SYMBOLS_OR_EMOJIS = /[\u26A0\u26A1\u2699\u2139\u23F1\u2328\u2709\u270F\u2712\u2702\u26C8\u2764\u2B50]/gu;
47394
+ var WIDE_SYMBOLS_OR_EMOJIS = /[\u26A0\u2699\u2139\u23F1\u2328\u2709\u270F\u2712\u2702\u26C8\u2764]/gu;
47395
47395
  function displayWidth(text4) {
47396
47396
  if (text4 === "") return 0;
47397
47397
  let cols = 0;
@@ -47407,10 +47407,11 @@ function displayWidth(text4) {
47407
47407
  }
47408
47408
  if (simple) return cols;
47409
47409
  const base = stringWidth(text4);
47410
- if (!/[\u26A0\u26A1\u2699\u2139\u23F1\u2328\u2709\u270F\u2712\u2702\u26C8\u2764\u2B50]/u.test(text4)) return base;
47410
+ if (!/[\u26A0\u2699\u2139\u23F1\u2328\u2709\u270F\u2712\u2702\u26C8\u2764]/u.test(text4)) return base;
47411
47411
  let extra = 0;
47412
47412
  for (const match of text4.matchAll(WIDE_SYMBOLS_OR_EMOJIS)) {
47413
- if (text4.charCodeAt(match.index + 1) === 65039) continue;
47413
+ const nextCode = text4.charCodeAt(match.index + 1);
47414
+ if (nextCode === 65039 || nextCode === 65038) continue;
47414
47415
  extra += 1;
47415
47416
  }
47416
47417
  return base + extra;
@@ -47429,13 +47430,22 @@ function wcwidthSafeSlice(text4, maxCols) {
47429
47430
  }
47430
47431
  return text4.slice(0, end);
47431
47432
  }
47433
+ var NARROW_TO_WIDE_EMOJIS = {
47434
+ "\u26A0": "\u{1F6A8}",
47435
+ "\u2139": "\u{1F4A1}",
47436
+ "\u2699": "\u{1F527}",
47437
+ "\u23F1": "\u23F0",
47438
+ "\u2709": "\u{1F4E7}",
47439
+ "\u270F": "\u{1F4DD}"
47440
+ };
47432
47441
  function formatSymbolSpacing(text4) {
47433
47442
  if (text4 === "" || /^[\x20-\x7e]*$/u.test(text4)) return text4;
47434
- let res = text4.replace(/([\u26A0\u2699\u2139\u23F1\u2328\u2709\u270F\u2712\u2702\u26C8\u2764])(?!\uFE0F)/gu, "$1\uFE0F");
47435
- res = res.replace(/([\u2460-\u24F4\u2776-\u2793\u3251-\u325F\u32B1-\u32BF])([\u4E00-\u9FFF\u3400-\u4DBF])/gu, "$1 $2");
47436
- res = res.replace(/([\u4E00-\u9FFF\u3400-\u4DBF])([\u2460-\u24F4\u2776-\u2793\u3251-\u325F\u32B1-\u32BF])/gu, "$1 $2");
47437
- res = res.replace(/([\u{1F300}-\u{1FAFF}\u2600-\u27BF]\uFE0F?)([\u4E00-\u9FFF\u3400-\u4DBF])/gu, "$1 $2");
47438
- res = res.replace(/([\u4E00-\u9FFF\u3400-\u4DBF])([\u{1F300}-\u{1FAFF}\u2600-\u27BF])/gu, "$1 $2");
47443
+ let res = text4.replace(/([\u26A0\u2699\u2139\u23F1\u2709\u270F])[\uFE0E\uFE0F]?/gu, (_, ch) => NARROW_TO_WIDE_EMOJIS[ch] ?? ch);
47444
+ res = res.replace(/([\u2328\u2712\u2702\u26C8\u2764])(?!\uFE0F|\uFE0E)/gu, "$1\uFE0F");
47445
+ res = res.replace(/([\u2460-\u24F4\u2776-\u2793\u3251-\u325F\u32B1-\u32BF])([\u4E00-\u9FFF\u3400-\u4DBF\u3000-\u303F\uFF01-\uFF60])/gu, "$1 $2");
47446
+ res = res.replace(/([\u4E00-\u9FFF\u3400-\u4DBF\u3000-\u303F\uFF01-\uFF60])([\u2460-\u24F4\u2776-\u2793\u3251-\u325F\u32B1-\u32BF])/gu, "$1 $2");
47447
+ res = res.replace(/([\u{1F300}-\u{1FAFF}\u2600-\u27BF][\uFE0E\uFE0F]?)([\u4E00-\u9FFF\u3400-\u4DBF\u3000-\u303F\uFF01-\uFF60])/gu, "$1 $2");
47448
+ res = res.replace(/([\u4E00-\u9FFF\u3400-\u4DBF\u3000-\u303F\uFF01-\uFF60])([\u{1F300}-\u{1FAFF}\u2600-\u27BF])/gu, "$1 $2");
47439
47449
  return res;
47440
47450
  }
47441
47451
  function displayColumnSlice(text4, startCol, endCol) {
@@ -50013,110 +50023,6 @@ function blockPositionRange(node2) {
50013
50023
  end: position2.end.offset ?? -1
50014
50024
  };
50015
50025
  }
50016
- function formatSeconds(ms) {
50017
- return (ms / 1e3).toFixed(1);
50018
- }
50019
- function thinkingHeader(durationMs, expanded) {
50020
- return paintRow([styled(`${expanded ? "\u25BE " : ""}\u273B \u601D\u8003 (${formatSeconds(durationMs)}s)`, "fgDim")]);
50021
- }
50022
- function bodyRow(line2, key) {
50023
- return (0, import_jsx_runtime.jsx)(Text, { children: paintRow([styled(` ${escapeContent(line2)}`, "fgDim")]) }, key);
50024
- }
50025
- function ReasoningBlock({ text: text4, collapsed, durationMs, live = false, maxCols }) {
50026
- const { columns } = use_window_size_default();
50027
- if (collapsed || text4 === "") return null;
50028
- const body = wrapDisplayLines(escapeContent(text4), Math.max(1, (maxCols ?? columns) - 4));
50029
- return (0, import_jsx_runtime.jsxs)(Box_default, {
50030
- flexDirection: "column",
50031
- width: "100%",
50032
- children: [(0, import_jsx_runtime.jsx)(Text, { children: thinkingHeader(durationMs, !live) }), body.map((line2, index2) => bodyRow(line2, index2))]
50033
- });
50034
- }
50035
- function indexedRows(length, read) {
50036
- const offset = (index2) => Math.min(length, Math.max(0, index2 < 0 ? length + Math.trunc(index2) : Math.trunc(index2)));
50037
- return Object.freeze({
50038
- length,
50039
- at(index2) {
50040
- const integer = Math.trunc(index2);
50041
- const absolute = integer < 0 ? length + integer : integer;
50042
- return absolute < 0 || absolute >= length ? void 0 : read(absolute);
50043
- },
50044
- slice(start = 0, end = length) {
50045
- const out = [];
50046
- const last = offset(end);
50047
- for (let index2 = offset(start); index2 < last; index2 += 1) out.push(read(index2));
50048
- return out;
50049
- }
50050
- });
50051
- }
50052
- var RowSequence = class {
50053
- segments = [];
50054
- size = 0;
50055
- /** Number of rows appended so far, without materializing them. */
50056
- get length() {
50057
- return this.size;
50058
- }
50059
- /**
50060
- * Append a source using its known height.
50061
- * @param rows - immutable source or ordinary readonly array.
50062
- */
50063
- append(rows) {
50064
- if (rows.length === 0) return;
50065
- this.segments.push({
50066
- start: this.size,
50067
- end: this.size + rows.length,
50068
- rows
50069
- });
50070
- this.size += rows.length;
50071
- }
50072
- /**
50073
- * Append one already materialized spacer or heading.
50074
- * @param row - the row to append.
50075
- */
50076
- push(row) {
50077
- this.append([row]);
50078
- }
50079
- /**
50080
- * Publish an immutable segment directory independent of later builder edits.
50081
- * @returns random-access rows; only at/slice invoke the underlying sources.
50082
- */
50083
- build() {
50084
- const segments = this.segments.slice();
50085
- const length = this.size;
50086
- const locate = (index2) => {
50087
- let low = 0;
50088
- let high = segments.length;
50089
- while (low < high) {
50090
- const middle = Math.floor((low + high) / 2);
50091
- if (segments[middle].end <= index2) low = middle + 1;
50092
- else high = middle;
50093
- }
50094
- return low;
50095
- };
50096
- const offset = (index2) => Math.min(length, Math.max(0, index2 < 0 ? length + Math.trunc(index2) : Math.trunc(index2)));
50097
- return Object.freeze({
50098
- length,
50099
- at(index2) {
50100
- const integer = Math.trunc(index2);
50101
- const absolute = integer < 0 ? length + integer : integer;
50102
- if (absolute < 0 || absolute >= length) return void 0;
50103
- const segment2 = segments[locate(absolute)];
50104
- return segment2.rows.at(absolute - segment2.start);
50105
- },
50106
- slice(start = 0, end = length) {
50107
- const first = offset(start);
50108
- const last = offset(end);
50109
- const out = [];
50110
- for (let index2 = locate(first); index2 < segments.length; index2 += 1) {
50111
- const segment2 = segments[index2];
50112
- if (segment2.start >= last) break;
50113
- for (const row of segment2.rows.slice(Math.max(0, first - segment2.start), Math.min(segment2.rows.length, last - segment2.start))) out.push(row);
50114
- }
50115
- return out;
50116
- }
50117
- });
50118
- }
50119
- };
50120
50026
  var dictionaries = {
50121
50027
  "zh-CN": {
50122
50028
  on: "\u5F00",
@@ -50200,18 +50106,20 @@ var dictionaries = {
50200
50106
  function tuiCopy(key, locale = "zh-CN") {
50201
50107
  return dictionaries[locale][key];
50202
50108
  }
50203
- var SWIMMING_FISH_FRAMES = [
50204
- ">o ",
50205
- " >o ",
50206
- " >o ",
50207
- " >o",
50208
- " >",
50209
- " ",
50210
- " \xB7 ",
50211
- "o "
50109
+ var BRAILLE_SPINNER_FRAMES = [
50110
+ "\u280B",
50111
+ "\u2819",
50112
+ "\u2839",
50113
+ "\u2838",
50114
+ "\u283C",
50115
+ "\u2834",
50116
+ "\u2826",
50117
+ "\u2827",
50118
+ "\u2807",
50119
+ "\u280F"
50212
50120
  ];
50213
- function getSwimmingFishFrame(liveMs) {
50214
- return SWIMMING_FISH_FRAMES[Math.floor(Math.max(0, liveMs ?? 0) / 150) % SWIMMING_FISH_FRAMES.length] ?? SWIMMING_FISH_FRAMES[0];
50121
+ function getBrailleSpinnerFrame(liveMs) {
50122
+ return BRAILLE_SPINNER_FRAMES[Math.floor(Math.max(0, liveMs ?? 0) / 100) % BRAILLE_SPINNER_FRAMES.length] ?? BRAILLE_SPINNER_FRAMES[0];
50215
50123
  }
50216
50124
  var GENERATION_TIPS_ZH = [
50217
50125
  "\u63D0\u793A\uFF1ACtrl+E \u5C55\u5F00\u5DE5\u5177\u5361 \xB7 /tools \u67E5\u770B\u5B8C\u6574\u8F93\u51FA",
@@ -50231,6 +50139,110 @@ function getBilingualTip(liveMs, locale = "zh-CN") {
50231
50139
  const tips = locale === "en-US" ? GENERATION_TIPS_EN : GENERATION_TIPS_ZH;
50232
50140
  return tips[Math.floor(Math.max(0, liveMs ?? 0) / 4e3) % tips.length] ?? tips[0];
50233
50141
  }
50142
+ function formatSeconds(ms) {
50143
+ return (ms / 1e3).toFixed(1);
50144
+ }
50145
+ function thinkingHeader(durationMs, expanded, live = false) {
50146
+ return paintRow([styled(`${expanded ? "\u25BE " : ""}${live ? getBrailleSpinnerFrame(durationMs) : "\u273B"} \u601D\u8003 (${formatSeconds(durationMs)}s)`, "fgDim")]);
50147
+ }
50148
+ function bodyRow(line2, key) {
50149
+ return (0, import_jsx_runtime.jsx)(Text, { children: paintRow([styled(` ${escapeContent(line2)}`, "fgDim")]) }, key);
50150
+ }
50151
+ function ReasoningBlock({ text: text4, collapsed, durationMs, live = false, maxCols }) {
50152
+ const { columns } = use_window_size_default();
50153
+ if (collapsed || text4 === "") return null;
50154
+ const body = wrapDisplayLines(escapeContent(text4), Math.max(1, (maxCols ?? columns) - 4));
50155
+ return (0, import_jsx_runtime.jsxs)(Box_default, {
50156
+ flexDirection: "column",
50157
+ width: "100%",
50158
+ children: [(0, import_jsx_runtime.jsx)(Text, { children: thinkingHeader(durationMs, !live, live) }), body.map((line2, index2) => bodyRow(line2, index2))]
50159
+ });
50160
+ }
50161
+ function indexedRows(length, read) {
50162
+ const offset = (index2) => Math.min(length, Math.max(0, index2 < 0 ? length + Math.trunc(index2) : Math.trunc(index2)));
50163
+ return Object.freeze({
50164
+ length,
50165
+ at(index2) {
50166
+ const integer = Math.trunc(index2);
50167
+ const absolute = integer < 0 ? length + integer : integer;
50168
+ return absolute < 0 || absolute >= length ? void 0 : read(absolute);
50169
+ },
50170
+ slice(start = 0, end = length) {
50171
+ const out = [];
50172
+ const last = offset(end);
50173
+ for (let index2 = offset(start); index2 < last; index2 += 1) out.push(read(index2));
50174
+ return out;
50175
+ }
50176
+ });
50177
+ }
50178
+ var RowSequence = class {
50179
+ segments = [];
50180
+ size = 0;
50181
+ /** Number of rows appended so far, without materializing them. */
50182
+ get length() {
50183
+ return this.size;
50184
+ }
50185
+ /**
50186
+ * Append a source using its known height.
50187
+ * @param rows - immutable source or ordinary readonly array.
50188
+ */
50189
+ append(rows) {
50190
+ if (rows.length === 0) return;
50191
+ this.segments.push({
50192
+ start: this.size,
50193
+ end: this.size + rows.length,
50194
+ rows
50195
+ });
50196
+ this.size += rows.length;
50197
+ }
50198
+ /**
50199
+ * Append one already materialized spacer or heading.
50200
+ * @param row - the row to append.
50201
+ */
50202
+ push(row) {
50203
+ this.append([row]);
50204
+ }
50205
+ /**
50206
+ * Publish an immutable segment directory independent of later builder edits.
50207
+ * @returns random-access rows; only at/slice invoke the underlying sources.
50208
+ */
50209
+ build() {
50210
+ const segments = this.segments.slice();
50211
+ const length = this.size;
50212
+ const locate = (index2) => {
50213
+ let low = 0;
50214
+ let high = segments.length;
50215
+ while (low < high) {
50216
+ const middle = Math.floor((low + high) / 2);
50217
+ if (segments[middle].end <= index2) low = middle + 1;
50218
+ else high = middle;
50219
+ }
50220
+ return low;
50221
+ };
50222
+ const offset = (index2) => Math.min(length, Math.max(0, index2 < 0 ? length + Math.trunc(index2) : Math.trunc(index2)));
50223
+ return Object.freeze({
50224
+ length,
50225
+ at(index2) {
50226
+ const integer = Math.trunc(index2);
50227
+ const absolute = integer < 0 ? length + integer : integer;
50228
+ if (absolute < 0 || absolute >= length) return void 0;
50229
+ const segment2 = segments[locate(absolute)];
50230
+ return segment2.rows.at(absolute - segment2.start);
50231
+ },
50232
+ slice(start = 0, end = length) {
50233
+ const first = offset(start);
50234
+ const last = offset(end);
50235
+ const out = [];
50236
+ for (let index2 = locate(first); index2 < segments.length; index2 += 1) {
50237
+ const segment2 = segments[index2];
50238
+ if (segment2.start >= last) break;
50239
+ for (const row of segment2.rows.slice(Math.max(0, first - segment2.start), Math.min(segment2.rows.length, last - segment2.start))) out.push(row);
50240
+ }
50241
+ return out;
50242
+ }
50243
+ });
50244
+ }
50245
+ };
50234
50246
  var graphemes$1 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
50235
50247
  function textLines(text4, prefix = "") {
50236
50248
  let length = 1;
@@ -53239,7 +53251,8 @@ function projectReasoningEntry(entry, scope) {
53239
53251
  sourceLength: entry.source.length,
53240
53252
  lines: []
53241
53253
  };
53242
- const lines = [lineForText(`${live ? "" : "\u25BE "}\u273B \u601D\u8003 (${secondsLabel}s)`, "fgDim", false, 0)];
53254
+ const icon = live ? getBrailleSpinnerFrame(reasoningDurationMs) : "\u273B";
53255
+ const lines = [lineForText(`${live ? "" : "\u25BE "}${icon} \u601D\u8003 (${secondsLabel}s)`, "fgDim", false, 0)];
53243
53256
  const body = wrapDisplayLines(escapeContent(entry.source), Math.max(1, scope.width - 4));
53244
53257
  for (const row of body) lines.push(lineForText(` ${row}`, "fgDim", false, lines.length));
53245
53258
  return {
@@ -55016,7 +55029,7 @@ function StreamView({ model, presenters, brandTier = "plain", brandAnimation = f
55016
55029
  id,
55017
55030
  kind: "active-placeholder",
55018
55031
  source: "",
55019
- meta: { activePlaceholder: `${getSwimmingFishFrame(liveMs)} \u25CF \u6B63\u5728\u5904\u7406\u2026 (${formatSeconds(liveMs)}s)` }
55032
+ meta: { activePlaceholder: `${getBrailleSpinnerFrame(liveMs)} \u25CF \u6B63\u5728\u5904\u7406\u2026 (${formatSeconds(liveMs)}s)` }
55020
55033
  }, blockRowsScope, void 0, true).lines,
55021
55034
  ranges: [],
55022
55035
  storeBlocks
@@ -55790,14 +55803,14 @@ function StreamView({ model, presenters, brandTier = "plain", brandAnimation = f
55790
55803
  const visibleParts = displayedParts(rawParts, reasoningExpanded);
55791
55804
  if (generating && visibleParts.length === 0) {
55792
55805
  const liveMs = liveDurationMs ?? turn.reasoningDurationMs;
55793
- const fish = getSwimmingFishFrame(liveMs);
55806
+ const spinner = getBrailleSpinnerFrame(liveMs);
55794
55807
  const tip = getBilingualTip(liveMs, locale);
55795
55808
  return (0, import_jsx_runtime.jsxs)(Box_default, {
55796
55809
  flexDirection: "column",
55797
55810
  width: "100%",
55798
55811
  flexShrink: 0,
55799
55812
  children: [(0, import_jsx_runtime.jsx)(Text, { children: paintRow([
55800
- styled(fish, "accentText", void 0, true),
55813
+ styled(spinner, "accentText", void 0, true),
55801
55814
  styled(" \u25CF ", "accentText", void 0, true),
55802
55815
  styled(`\u6B63\u5728\u5904\u7406\u2026 (${formatSeconds(liveMs)}s)`, "fg")
55803
55816
  ]) }), (0, import_jsx_runtime.jsx)(Text, { children: paintRow([styled(` \u2514 ${tip}`, "fgDim")]) })]
@@ -56081,9 +56094,9 @@ function SessionPane({ rows, selectedIndex, currentId, confirmDelete, deleteUnav
56081
56094
  !showControls ? null : confirmDelete ? (0, import_jsx_runtime.jsx)(Text, {
56082
56095
  wrap: "truncate",
56083
56096
  children: styled(`\u518D\u6309 d \u786E\u8BA4\u5220\u9664\u300C${escapeContent(selected?.title ?? "")}\u300D`, "error")
56084
- }) : deleteUnavailable ? (0, import_jsx_runtime.jsx)(Text, {
56097
+ }) : deleteUnavailable ? (0, import_jsx_runtime.jsxs)(Text, {
56085
56098
  wrap: "truncate",
56086
- children: styled(escapeContent("\u5220\u9664\u4E0D\u53EF\u7528\uFF08\u540E\u7AEF\u80FD\u529B\u7F3A\u5931\uFF09"), "error")
56099
+ children: [styled(escapeContent("\u2191\u2193/jk \u9009\u62E9 \xB7 Enter \u5207\u6362 \xB7 r \u91CD\u547D\u540D \xB7 g s \u5173\u95ED \xB7 "), "fgDim"), styled(escapeContent("\u5220\u9664\u4E0D\u53EF\u7528\uFF08\u540E\u7AEF\u80FD\u529B\u7F3A\u5931\uFF09"), "error")]
56087
56100
  }) : (0, import_jsx_runtime.jsx)(Text, {
56088
56101
  wrap: "truncate",
56089
56102
  children: styled(escapeContent("\u2191\u2193/jk \u9009\u62E9 \xB7 Enter \u5207\u6362 \xB7 r \u91CD\u547D\u540D \xB7 d \u5220\u9664 \xB7 g s \u5173\u95ED"), "fgDim")
@@ -56694,6 +56707,25 @@ function moveCaretByGrapheme(text4, caretIndex, direction) {
56694
56707
  for (const part of GRAPHEME.segment(text4.slice(caret))) return caret + part.segment.length;
56695
56708
  return text4.length;
56696
56709
  }
56710
+ function moveCaretUpLine(text4, caretIndex) {
56711
+ const caret = clampCaretIndex(text4, caretIndex);
56712
+ const prevNewline = text4.lastIndexOf("\n", caret - 1);
56713
+ if (prevNewline === -1) return void 0;
56714
+ const col = caret - (prevNewline + 1);
56715
+ const lineBeforeStart = text4.lastIndexOf("\n", prevNewline - 1) + 1;
56716
+ const lineBeforeLength = prevNewline - lineBeforeStart;
56717
+ return lineBeforeStart + Math.min(col, lineBeforeLength);
56718
+ }
56719
+ function moveCaretDownLine(text4, caretIndex) {
56720
+ const caret = clampCaretIndex(text4, caretIndex);
56721
+ const nextNewline = text4.indexOf("\n", caret);
56722
+ if (nextNewline === -1) return void 0;
56723
+ const col = caret - (text4.lastIndexOf("\n", caret - 1) + 1);
56724
+ let nextLineEnd = text4.indexOf("\n", nextNewline + 1);
56725
+ if (nextLineEnd === -1) nextLineEnd = text4.length;
56726
+ const nextLineLength = nextLineEnd - (nextNewline + 1);
56727
+ return nextNewline + 1 + Math.min(col, nextLineLength);
56728
+ }
56697
56729
  function composerFrameAnchor(text4, caretIndex, options) {
56698
56730
  const caret = composerCursorPosition(text4, caretIndex);
56699
56731
  const lineCount = Math.max(1, text4.split("\n").length);
@@ -57582,7 +57614,9 @@ function holdComposer(state, action) {
57582
57614
  mentionDismissed: state.mentionDismissed,
57583
57615
  commandSelectedIndex: state.commandSelectedIndex,
57584
57616
  commandDismissed: state.commandDismissed,
57585
- caretIndex: state.caretIndex
57617
+ caretIndex: state.caretIndex,
57618
+ historyIndex: state.historyIndex,
57619
+ historyDraft: state.historyDraft
57586
57620
  };
57587
57621
  }
57588
57622
  function draftKeyEffect(state, key, keyInfo, actions) {
@@ -57666,7 +57700,7 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
57666
57700
  candidateCount: 0,
57667
57701
  selectedIndex: 0,
57668
57702
  selectedCandidate: void 0
57669
- }, queuedDraft = {}, compaction = { available: false }) {
57703
+ }, queuedDraft = {}, compaction = { available: false }, inputHistory = []) {
57670
57704
  const commandMode = (state.commandQuery !== void 0 || state.text.startsWith("/")) && state.commandDismissed !== true;
57671
57705
  activeMentionQuery(state.text);
57672
57706
  const agentHubOpen = overlays.agentHub?.open === true;
@@ -57920,6 +57954,20 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
57920
57954
  prefixG: false,
57921
57955
  renaming: state.renaming
57922
57956
  };
57957
+ if (state.historyIndex !== void 0) {
57958
+ const restored = state.historyDraft ?? "";
57959
+ return {
57960
+ kind: "dispatch",
57961
+ action: { kind: "none" },
57962
+ text: restored,
57963
+ commandQuery: void 0,
57964
+ prefixG: false,
57965
+ renaming: state.renaming,
57966
+ caretIndex: restored.length,
57967
+ historyIndex: void 0,
57968
+ historyDraft: void 0
57969
+ };
57970
+ }
57923
57971
  return {
57924
57972
  kind: "dispatch",
57925
57973
  action: { kind: "none" },
@@ -58102,7 +58150,9 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
58102
58150
  mentionDismissed: false,
58103
58151
  commandSelectedIndex: 0,
58104
58152
  commandDismissed: false,
58105
- caretIndex: previous3
58153
+ caretIndex: previous3,
58154
+ historyIndex: state.historyIndex,
58155
+ historyDraft: state.historyDraft
58106
58156
  };
58107
58157
  }
58108
58158
  if ((key === " " || keyInfo.tab) && keyInfo.shift) {
@@ -58504,7 +58554,9 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
58504
58554
  commandQuery: state.commandQuery,
58505
58555
  prefixG: false,
58506
58556
  renaming: state.renaming,
58507
- caretIndex: moveCaretByGrapheme(state.text, caret, keyInfo.leftArrow ? -1 : 1)
58557
+ caretIndex: moveCaretByGrapheme(state.text, caret, keyInfo.leftArrow ? -1 : 1),
58558
+ historyIndex: state.historyIndex,
58559
+ historyDraft: state.historyDraft
58508
58560
  };
58509
58561
  }
58510
58562
  if (keyInfo.pageUp) return holdComposer(state, {
@@ -58524,6 +58576,21 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
58524
58576
  edge: "latest"
58525
58577
  });
58526
58578
  if (keyInfo.upArrow) {
58579
+ if (state.text.includes("\n")) {
58580
+ const caret = clampCaretIndex(state.text, state.caretIndex);
58581
+ const targetCaret = moveCaretUpLine(state.text, caret);
58582
+ if (targetCaret !== void 0) return {
58583
+ kind: "dispatch",
58584
+ action: { kind: "none" },
58585
+ text: state.text,
58586
+ commandQuery: state.commandQuery,
58587
+ prefixG: false,
58588
+ renaming: state.renaming,
58589
+ caretIndex: targetCaret,
58590
+ historyIndex: state.historyIndex,
58591
+ historyDraft: state.historyDraft
58592
+ };
58593
+ }
58527
58594
  if (state.text === "" && queuedDraft.headText !== void 0) return {
58528
58595
  kind: "dispatch",
58529
58596
  action: { kind: "take-queued-draft" },
@@ -58531,33 +58598,77 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
58531
58598
  commandQuery: void 0,
58532
58599
  prefixG: false,
58533
58600
  renaming: state.renaming,
58534
- caretIndex: queuedDraft.headText.length
58535
- };
58536
- return {
58537
- kind: "dispatch",
58538
- action: {
58539
- kind: "scroll",
58540
- delta: 1
58541
- },
58542
- text: state.text,
58543
- commandQuery: state.commandQuery,
58544
- prefixG: false,
58545
- renaming: state.renaming,
58546
- caretIndex: state.caretIndex
58547
- };
58601
+ caretIndex: queuedDraft.headText.length,
58602
+ historyIndex: void 0,
58603
+ historyDraft: void 0
58604
+ };
58605
+ if (inputHistory.length > 0) {
58606
+ const isBrowsing = state.historyIndex !== void 0;
58607
+ const currentIndex = state.historyIndex ?? inputHistory.length;
58608
+ const nextIndex = Math.max(0, currentIndex - 1);
58609
+ const nextText = inputHistory[nextIndex] ?? "";
58610
+ const savedDraft = isBrowsing ? state.historyDraft : state.text;
58611
+ return {
58612
+ kind: "dispatch",
58613
+ action: { kind: "none" },
58614
+ text: nextText,
58615
+ commandQuery: void 0,
58616
+ prefixG: false,
58617
+ renaming: state.renaming,
58618
+ caretIndex: nextText.length,
58619
+ historyIndex: nextIndex,
58620
+ historyDraft: savedDraft
58621
+ };
58622
+ }
58623
+ return { kind: "none" };
58624
+ }
58625
+ if (keyInfo.downArrow) {
58626
+ if (state.text.includes("\n")) {
58627
+ const caret = clampCaretIndex(state.text, state.caretIndex);
58628
+ const targetCaret = moveCaretDownLine(state.text, caret);
58629
+ if (targetCaret !== void 0) return {
58630
+ kind: "dispatch",
58631
+ action: { kind: "none" },
58632
+ text: state.text,
58633
+ commandQuery: state.commandQuery,
58634
+ prefixG: false,
58635
+ renaming: state.renaming,
58636
+ caretIndex: targetCaret,
58637
+ historyIndex: state.historyIndex,
58638
+ historyDraft: state.historyDraft
58639
+ };
58640
+ }
58641
+ if (state.historyIndex !== void 0) {
58642
+ const nextIndex = state.historyIndex + 1;
58643
+ if (nextIndex < inputHistory.length) {
58644
+ const nextText = inputHistory[nextIndex] ?? "";
58645
+ return {
58646
+ kind: "dispatch",
58647
+ action: { kind: "none" },
58648
+ text: nextText,
58649
+ commandQuery: void 0,
58650
+ prefixG: false,
58651
+ renaming: state.renaming,
58652
+ caretIndex: nextText.length,
58653
+ historyIndex: nextIndex,
58654
+ historyDraft: state.historyDraft
58655
+ };
58656
+ }
58657
+ const restored = state.historyDraft ?? "";
58658
+ return {
58659
+ kind: "dispatch",
58660
+ action: { kind: "none" },
58661
+ text: restored,
58662
+ commandQuery: void 0,
58663
+ prefixG: false,
58664
+ renaming: state.renaming,
58665
+ caretIndex: restored.length,
58666
+ historyIndex: void 0,
58667
+ historyDraft: void 0
58668
+ };
58669
+ }
58670
+ return { kind: "none" };
58548
58671
  }
58549
- if (keyInfo.downArrow) return {
58550
- kind: "dispatch",
58551
- action: {
58552
- kind: "scroll",
58553
- delta: -1
58554
- },
58555
- text: state.text,
58556
- commandQuery: state.commandQuery,
58557
- prefixG: false,
58558
- renaming: state.renaming,
58559
- caretIndex: state.caretIndex
58560
- };
58561
58672
  if (/^[jk]+$/u.test(key) && !keyInfo.ctrl && !keyInfo.meta && state.text === "") {
58562
58673
  let delta = 0;
58563
58674
  for (const char of key) if (char === "k") delta += 1;
@@ -58591,7 +58702,9 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
58591
58702
  renaming: state.renaming,
58592
58703
  caretIndex: caret + 1,
58593
58704
  commandSelectedIndex: 0,
58594
- commandDismissed: false
58705
+ commandDismissed: false,
58706
+ historyIndex: state.historyIndex,
58707
+ historyDraft: state.historyDraft
58595
58708
  };
58596
58709
  }
58597
58710
  if (key === "@") {
@@ -58607,7 +58720,9 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
58607
58720
  mentionDismissed: false,
58608
58721
  commandSelectedIndex: 0,
58609
58722
  commandDismissed: false,
58610
- caretIndex: caret + 1
58723
+ caretIndex: caret + 1,
58724
+ historyIndex: state.historyIndex,
58725
+ historyDraft: state.historyDraft
58611
58726
  };
58612
58727
  }
58613
58728
  if (isTextInput(key, keyInfo)) {
@@ -58624,7 +58739,9 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
58624
58739
  mentionDismissed: false,
58625
58740
  commandSelectedIndex: 0,
58626
58741
  commandDismissed: false,
58627
- caretIndex: caret + key.length
58742
+ caretIndex: caret + key.length,
58743
+ historyIndex: state.historyIndex,
58744
+ historyDraft: state.historyDraft
58628
58745
  };
58629
58746
  }
58630
58747
  return {
@@ -58633,7 +58750,9 @@ function mapKeyEvent(state, key, keyInfo, commands, pane, search2, timeline = {
58633
58750
  text: state.text,
58634
58751
  commandQuery: state.commandQuery,
58635
58752
  prefixG: false,
58636
- renaming: state.renaming
58753
+ renaming: state.renaming,
58754
+ historyIndex: state.historyIndex,
58755
+ historyDraft: state.historyDraft
58637
58756
  };
58638
58757
  }
58639
58758
  function feedbackLabel(feedback) {
@@ -58796,6 +58915,16 @@ function TuiLoop({ title, controller, brandTier = "plain", brandAutoEligible = f
58796
58915
  helpLinesRef.current = helpPane.lines;
58797
58916
  const historyLengthRef = (0, import_react34.useRef)(model.history.length);
58798
58917
  historyLengthRef.current = model.history.length;
58918
+ const sentHistoryRef = (0, import_react34.useRef)([]);
58919
+ const inputHistory = (0, import_react34.useMemo)(() => {
58920
+ const fromModel = model.history.filter((m) => m.kind === "user" && typeof m.text === "string" && m.text.trim().length > 0).map((m) => m.text);
58921
+ const combined = [];
58922
+ for (const item of [...fromModel, ...sentHistoryRef.current]) {
58923
+ const trimmed = item.trim();
58924
+ if (trimmed.length > 0 && combined.at(-1) !== trimmed) combined.push(trimmed);
58925
+ }
58926
+ return combined;
58927
+ }, [model.history]);
58799
58928
  const chordTimerRef = (0, import_react34.useRef)(void 0);
58800
58929
  const clearChord = () => {
58801
58930
  if (chordTimerRef.current !== void 0) {
@@ -58910,7 +59039,7 @@ function TuiLoop({ title, controller, brandTier = "plain", brandAutoEligible = f
58910
59039
  candidateCount: mentionCandidates.length,
58911
59040
  selectedIndex: current.mentionSelectedIndex,
58912
59041
  selectedCandidate: mentionCandidates[current.mentionSelectedIndex]
58913
- }, { headText: queuedDraftText }, { available: (model.compactionDividers?.length ?? 0) > 0 });
59042
+ }, { headText: queuedDraftText }, { available: (model.compactionDividers?.length ?? 0) > 0 }, inputHistory);
58914
59043
  if (effect.kind === "dispatch") {
58915
59044
  const action = effect.action;
58916
59045
  if (isSessionTransitionAction(action) && isSessionTransitionStatus(feedbackRef.current)) {
@@ -58936,7 +59065,17 @@ function TuiLoop({ title, controller, brandTier = "plain", brandAutoEligible = f
58936
59065
  kind: "edge",
58937
59066
  edge: action.edge
58938
59067
  });
58939
- else if (action.kind === "send" || action.kind === "new-session" || action.kind === "select-session") {
59068
+ else if (action.kind === "send") {
59069
+ const trimmed = action.text.trim();
59070
+ if (trimmed.length > 0 && sentHistoryRef.current.at(-1) !== trimmed) sentHistoryRef.current.push(trimmed);
59071
+ issueViewportCommand({ kind: "reset" });
59072
+ controller.dispatch(action);
59073
+ } else if (action.kind === "command") {
59074
+ const queryText = action.query.trim().startsWith("/") ? action.query.trim() : `/${action.query.trim()}`;
59075
+ if (queryText.length > 0 && sentHistoryRef.current.at(-1) !== queryText) sentHistoryRef.current.push(queryText);
59076
+ controller.dispatch(action);
59077
+ } else if (action.kind === "new-session" || action.kind === "select-session") {
59078
+ sentHistoryRef.current = [];
58940
59079
  issueViewportCommand({ kind: "reset" });
58941
59080
  controller.dispatch(action);
58942
59081
  } else if (action.kind === "intake-clipboard-image") controller.intakeClipboardImage().then((result) => {
@@ -58966,7 +59105,9 @@ function TuiLoop({ title, controller, brandTier = "plain", brandAutoEligible = f
58966
59105
  mentionDismissed: effect.mentionDismissed ?? current.mentionDismissed,
58967
59106
  commandSelectedIndex: effect.commandSelectedIndex ?? current.commandSelectedIndex,
58968
59107
  commandDismissed: effect.commandDismissed ?? current.commandDismissed,
58969
- caretIndex: effect.caretIndex ?? (effect.text === current.text ? current.caretIndex : void 0)
59108
+ caretIndex: effect.caretIndex ?? (effect.text === current.text ? current.caretIndex : void 0),
59109
+ historyIndex: effect.historyIndex,
59110
+ historyDraft: effect.historyDraft
58970
59111
  } : current;
58971
59112
  stateRef.current = next;
58972
59113
  setState(next);
@@ -58982,7 +59123,9 @@ function TuiLoop({ title, controller, brandTier = "plain", brandAutoEligible = f
58982
59123
  mentionDismissed: false,
58983
59124
  commandSelectedIndex: 0,
58984
59125
  commandDismissed: false,
58985
- caretIndex: caret + token.length
59126
+ caretIndex: caret + token.length,
59127
+ historyIndex: void 0,
59128
+ historyDraft: void 0
58986
59129
  };
58987
59130
  stateRef.current = next;
58988
59131
  setState(next);
@@ -59023,7 +59166,9 @@ function TuiLoop({ title, controller, brandTier = "plain", brandAutoEligible = f
59023
59166
  mentionDismissed: false,
59024
59167
  commandSelectedIndex: 0,
59025
59168
  commandDismissed: false,
59026
- caretIndex: caret + pasted.length
59169
+ caretIndex: caret + pasted.length,
59170
+ historyIndex: void 0,
59171
+ historyDraft: void 0
59027
59172
  };
59028
59173
  stateRef.current = next;
59029
59174
  setState(next);
@@ -63406,6 +63551,7 @@ var RuntimeController = class _RuntimeController {
63406
63551
  }
63407
63552
  if (!this.deleteCapable()) {
63408
63553
  this.deleteUnavailable = true;
63554
+ this.setFeedback("\u2139 \u5F53\u524D\u4F1A\u8BDD\u5B58\u50A8\u4E3A\u53EA\u8FFD\u52A0\u65E5\u5FD7\uFF0C\u4E0D\u652F\u6301\u7269\u7406\u5220\u9664");
63409
63555
  this.emit();
63410
63556
  return;
63411
63557
  }
@@ -64207,9 +64353,13 @@ var RuntimeController = class _RuntimeController {
64207
64353
  try {
64208
64354
  const items = await persistence.list();
64209
64355
  const liveSession = this.session;
64356
+ const interactiveItems = items.filter((item) => {
64357
+ const header = item.header ?? item;
64358
+ return header.origin !== "subagent" && header.parentSession === void 0;
64359
+ });
64210
64360
  const listedIds = /* @__PURE__ */ new Set();
64211
64361
  const uncached = [];
64212
- for (const item of items) {
64362
+ for (const item of interactiveItems) {
64213
64363
  const header = item.header ?? item;
64214
64364
  const id = header.id;
64215
64365
  listedIds.add(id);
@@ -64228,6 +64378,40 @@ var RuntimeController = class _RuntimeController {
64228
64378
  this.sessionRowCache.delete(id);
64229
64379
  }
64230
64380
  }
64381
+ const initialRows = [];
64382
+ for (const item of interactiveItems) {
64383
+ const header = item.header ?? item;
64384
+ const id = header.id;
64385
+ if (liveSession !== void 0 && liveSession.id === id) {
64386
+ initialRows.push(this.rowForLiveSession(liveSession));
64387
+ } else {
64388
+ const cached = this.sessionRowCache.get(id);
64389
+ if (cached !== void 0) {
64390
+ initialRows.push(cached.row);
64391
+ } else {
64392
+ initialRows.push({
64393
+ id,
64394
+ title: id,
64395
+ updatedAt: header.createdAt ?? 0
64396
+ });
64397
+ }
64398
+ }
64399
+ }
64400
+ if (this.session !== void 0 && !initialRows.some((row) => row.id === this.session?.id)) {
64401
+ initialRows.push(this.rowForLiveSession(this.session));
64402
+ }
64403
+ initialRows.sort((a, b) => b.updatedAt - a.updatedAt);
64404
+ if (this.closed) return;
64405
+ this.sessionList = initialRows;
64406
+ if (preferredId !== void 0) {
64407
+ const preferredIndex2 = initialRows.findIndex((row) => row.id === preferredId);
64408
+ if (preferredIndex2 >= 0) {
64409
+ this.selectedIndex = preferredIndex2;
64410
+ }
64411
+ } else if (this.selectedIndex >= initialRows.length) {
64412
+ this.selectedIndex = Math.max(0, initialRows.length - 1);
64413
+ }
64414
+ this.emit();
64231
64415
  if (uncached.length > 0) {
64232
64416
  const BATCH_SIZE = 16;
64233
64417
  for (let i = 0; i < uncached.length; i += BATCH_SIZE) {
@@ -64242,35 +64426,48 @@ var RuntimeController = class _RuntimeController {
64242
64426
  for (const entry of fetched) {
64243
64427
  this.sessionRowCache.set(entry.id, { row: entry.row, revision: entry.revision });
64244
64428
  }
64245
- }
64246
- }
64247
- if (this.closed) return;
64248
- const rows = [];
64249
- for (const item of items) {
64250
- const header = item.header ?? item;
64251
- const id = header.id;
64252
- if (liveSession !== void 0 && liveSession.id === id) {
64253
- rows.push(this.rowForLiveSession(liveSession));
64254
- } else {
64255
- const cached = this.sessionRowCache.get(id);
64256
- if (cached !== void 0) {
64257
- rows.push(cached.row);
64258
- } else {
64259
- rows.push(await this.rowFor(id));
64429
+ if (!this.closed) {
64430
+ const updatedRows = [];
64431
+ for (const item of interactiveItems) {
64432
+ const header = item.header ?? item;
64433
+ const id = header.id;
64434
+ if (liveSession !== void 0 && liveSession.id === id) {
64435
+ updatedRows.push(this.rowForLiveSession(liveSession));
64436
+ } else {
64437
+ const cached = this.sessionRowCache.get(id);
64438
+ if (cached !== void 0) {
64439
+ updatedRows.push(cached.row);
64440
+ } else {
64441
+ updatedRows.push({
64442
+ id,
64443
+ title: id,
64444
+ updatedAt: header.createdAt ?? 0
64445
+ });
64446
+ }
64447
+ }
64448
+ }
64449
+ if (this.session !== void 0 && !updatedRows.some((row) => row.id === this.session?.id)) {
64450
+ updatedRows.push(this.rowForLiveSession(this.session));
64451
+ }
64452
+ updatedRows.sort((a, b) => b.updatedAt - a.updatedAt);
64453
+ this.sessionList = updatedRows;
64454
+ if (preferredId !== void 0) {
64455
+ const preferredIndex2 = updatedRows.findIndex((row) => row.id === preferredId);
64456
+ if (preferredIndex2 >= 0) {
64457
+ this.selectedIndex = preferredIndex2;
64458
+ }
64459
+ } else if (this.selectedIndex >= updatedRows.length) {
64460
+ this.selectedIndex = Math.max(0, updatedRows.length - 1);
64461
+ }
64462
+ this.emit();
64260
64463
  }
64261
64464
  }
64262
64465
  }
64263
- if (this.session !== void 0 && !rows.some((row) => row.id === this.session?.id)) {
64264
- rows.push(this.rowForLiveSession(this.session));
64265
- }
64266
- rows.sort((a, b) => b.updatedAt - a.updatedAt);
64267
- if (this.closed) return;
64268
- this.sessionList = rows;
64269
- const preferredIndex = preferredId === void 0 ? -1 : rows.findIndex((row) => row.id === preferredId);
64466
+ const preferredIndex = preferredId === void 0 ? -1 : this.sessionList.findIndex((row) => row.id === preferredId);
64270
64467
  if (preferredIndex >= 0) {
64271
64468
  this.selectedIndex = preferredIndex;
64272
- } else if (this.selectedIndex >= rows.length) {
64273
- this.selectedIndex = Math.max(0, rows.length - 1);
64469
+ } else if (this.selectedIndex >= this.sessionList.length) {
64470
+ this.selectedIndex = Math.max(0, this.sessionList.length - 1);
64274
64471
  }
64275
64472
  this.confirmDelete = false;
64276
64473
  this.emit();
@@ -64316,7 +64513,7 @@ var RuntimeController = class _RuntimeController {
64316
64513
  updatedAt: events.at(-1)?.time ?? createdAt
64317
64514
  };
64318
64515
  } catch {
64319
- return { id, title: id, updatedAt: Date.now() };
64516
+ return { id, title: id, updatedAt: 0 };
64320
64517
  }
64321
64518
  }
64322
64519
  /** Queue the newest query and enter loading before its debounce delay. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crazyhappyone/dsh-tui",
3
- "version": "0.1.0-alpha.20",
3
+ "version": "0.1.0-alpha.23",
4
4
  "description": "Source-runtime launcher for the DeepSeek Harness terminal interface",
5
5
  "type": "module",
6
6
  "license": "MIT",