@crazyhappyone/dsh-tui 0.1.0-alpha.22 → 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 +131 -176
  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;
@@ -47433,7 +47434,7 @@ var NARROW_TO_WIDE_EMOJIS = {
47433
47434
  "\u26A0": "\u{1F6A8}",
47434
47435
  "\u2139": "\u{1F4A1}",
47435
47436
  "\u2699": "\u{1F527}",
47436
- "\u23F1": "\u{23F0}",
47437
+ "\u23F1": "\u23F0",
47437
47438
  "\u2709": "\u{1F4E7}",
47438
47439
  "\u270F": "\u{1F4DD}"
47439
47440
  };
@@ -50022,8 +50023,88 @@ function blockPositionRange(node2) {
50022
50023
  end: position2.end.offset ?? -1
50023
50024
  };
50024
50025
  }
50025
- function formatSeconds(ms) {
50026
- return (ms / 1e3).toFixed(1);
50026
+ var dictionaries = {
50027
+ "zh-CN": {
50028
+ on: "\u5F00",
50029
+ off: "\u5173",
50030
+ reasoning: "\u601D\u8003",
50031
+ scrollbar: "\u8F68\u9053",
50032
+ statusDetails: "\u6307\u6807\u8BE6\u60C5",
50033
+ locale: "\u754C\u9762\u8BED\u8A00",
50034
+ metrics: "\u6307\u6807",
50035
+ mode: "\u6A21\u5F0F",
50036
+ tools: "\u5DE5\u5177",
50037
+ context: "\u4E0A\u4E0B\u6587",
50038
+ status: "\u72B6\u6001",
50039
+ effort: "\u5F3A\u5EA6",
50040
+ cacheHit: "\u7F13\u5B58\u547D\u4E2D",
50041
+ retry: "\u91CD\u8BD5",
50042
+ commandStatus: "\u663E\u793A/\u9690\u85CF\u5B8C\u6574\u72B6\u6001\u6307\u6807",
50043
+ commandReasoning: "\u663E\u793A/\u9690\u85CF\u5168\u6587\u601D\u8003 \xB7 Ctrl+O",
50044
+ commandScrollbar: "\u663E\u793A/\u9690\u85CF\u6EDA\u52A8\u8F68\u9053",
50045
+ settingsSaveFailed: "\u2717 \u663E\u793A\u8BBE\u7F6E\u672A\u4FDD\u5B58 \xB7 \u8BF7\u91CD\u8BD5",
50046
+ inputHint: "\u8F93\u5165\u6D88\u606F",
50047
+ sendHint: "Enter \u53D1\u9001",
50048
+ arguments: "\u53C2\u6570",
50049
+ result: "\u7ED3\u679C",
50050
+ diagnostics: "\u8BCA\u65AD\u5143\u6570\u636E",
50051
+ processStatus: "\u8FDB\u7A0B\u72B6\u6001",
50052
+ running: "\u8FD0\u884C\u4E2D",
50053
+ failed: "\u5931\u8D25",
50054
+ remaining: "\u5269\u4F59\u6E90\u884C",
50055
+ toolDetails: "/tools \u8BE6\u60C5",
50056
+ commandTools: "\u9010\u9879\u67E5\u770B\u5DE5\u5177\u53C2\u6570\u3001\u5B8C\u6574\u7ED3\u679C\u4E0E\u8BCA\u65AD",
50057
+ noTools: "\u5F53\u524D\u4F1A\u8BDD\u6CA1\u6709\u5DE5\u5177\u8C03\u7528",
50058
+ toolListHint: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u8BE6\u60C5 \xB7 Esc \u5173\u95ED",
50059
+ toolPageHint: "\u2190\u2192 \u7FFB\u9875 \xB7 d \u8BCA\u65AD \xB7 y \u590D\u5236 \xB7 e \u5BFC\u51FA \xB7 Esc \u8FD4\u56DE",
50060
+ toolCopied: "\u2713 \u5DF2\u590D\u5236\u5B8C\u6574\u5DE5\u5177\u539F\u6587",
50061
+ toolExported: "\u2713 \u5DE5\u5177\u539F\u6587\u5DF2\u5BFC\u51FA",
50062
+ toolCopyFailed: "\u2717 \u5DE5\u5177\u539F\u6587\u590D\u5236\u5931\u8D25",
50063
+ toolExportFailed: "\u2717 \u5DE5\u5177\u539F\u6587\u5BFC\u51FA\u5931\u8D25",
50064
+ toolExportAction: "\u5BFC\u51FA\u5B8C\u6574\u539F\u6587"
50065
+ },
50066
+ "en-US": {
50067
+ on: "on",
50068
+ off: "off",
50069
+ reasoning: "Thinking",
50070
+ scrollbar: "Rail",
50071
+ statusDetails: "Status details",
50072
+ locale: "UI language",
50073
+ metrics: "Metrics",
50074
+ mode: "Mode",
50075
+ tools: "Tools",
50076
+ context: "Context",
50077
+ status: "Status",
50078
+ effort: "Effort",
50079
+ cacheHit: "Cache hit",
50080
+ retry: "Retry",
50081
+ commandStatus: "Show/hide full status metrics",
50082
+ commandReasoning: "Show/hide full thinking text \xB7 Ctrl+O",
50083
+ commandScrollbar: "Show/hide the scroll rail",
50084
+ settingsSaveFailed: "\u2717 Display setting was not saved \xB7 Retry",
50085
+ inputHint: "Type a message",
50086
+ sendHint: "Enter to send",
50087
+ arguments: "Arguments",
50088
+ result: "Result",
50089
+ diagnostics: "Diagnostic metadata",
50090
+ processStatus: "Process status",
50091
+ running: "Running",
50092
+ failed: "Failed",
50093
+ remaining: "source lines remaining",
50094
+ toolDetails: "/tools details",
50095
+ commandTools: "Inspect individual tool arguments, full results, and diagnostics",
50096
+ noTools: "No tool calls in this session",
50097
+ toolListHint: "\u2191\u2193 Select \xB7 Enter Details \xB7 Esc Close",
50098
+ toolPageHint: "\u2190\u2192 Pages \xB7 d Diagnostics \xB7 y Copy \xB7 e Export \xB7 Esc Back",
50099
+ toolCopied: "\u2713 Full tool source copied",
50100
+ toolExported: "\u2713 Tool source exported",
50101
+ toolCopyFailed: "\u2717 Tool source copy failed",
50102
+ toolExportFailed: "\u2717 Tool source export failed",
50103
+ toolExportAction: "Export full source"
50104
+ }
50105
+ };
50106
+ function tuiCopy(key, locale = "zh-CN") {
50107
+ return dictionaries[locale][key];
50027
50108
  }
50028
50109
  var BRAILLE_SPINNER_FRAMES = [
50029
50110
  "\u280B",
@@ -50038,13 +50119,31 @@ var BRAILLE_SPINNER_FRAMES = [
50038
50119
  "\u280F"
50039
50120
  ];
50040
50121
  function getBrailleSpinnerFrame(liveMs) {
50041
- const index = Math.floor(Math.max(0, liveMs ?? 0) / 100) % BRAILLE_SPINNER_FRAMES.length;
50042
- return BRAILLE_SPINNER_FRAMES[index] ?? BRAILLE_SPINNER_FRAMES[0];
50122
+ return BRAILLE_SPINNER_FRAMES[Math.floor(Math.max(0, liveMs ?? 0) / 100) % BRAILLE_SPINNER_FRAMES.length] ?? BRAILLE_SPINNER_FRAMES[0];
50123
+ }
50124
+ var GENERATION_TIPS_ZH = [
50125
+ "\u63D0\u793A\uFF1ACtrl+E \u5C55\u5F00\u5DE5\u5177\u5361 \xB7 /tools \u67E5\u770B\u5B8C\u6574\u8F93\u51FA",
50126
+ "\u63D0\u793A\uFF1ACtrl+O \u5C55\u5F00/\u6536\u8D77\u601D\u8003\u8FC7\u7A0B \xB7 \u968F\u65F6\u8DDF\u8FDB\u63A8\u7406",
50127
+ "\u63D0\u793A\uFF1AShift+Tab \u5207\u6362\u591A\u884C\u8F93\u5165 \xB7 \u2191/\u2193 \u6D4F\u89C8\u5386\u53F2\u6D88\u606F",
50128
+ "\u63D0\u793A\uFF1A\u8F93\u5165 / \u6253\u5F00\u5FEB\u6377\u547D\u4EE4 \xB7 \u8F93\u5165 @ \u63D0\u53CA\u6587\u4EF6\u4E0E\u4E0A\u4E0B\u6587",
50129
+ "\u63D0\u793A\uFF1ACtrl+C \u4E2D\u65AD\u5F53\u524D\u751F\u6210 \xB7 \u968F\u65F6\u5B89\u5168\u505C\u6B62"
50130
+ ];
50131
+ var GENERATION_TIPS_EN = [
50132
+ "Tip: Ctrl+E to expand tool cards \xB7 /tools for full output",
50133
+ "Tip: Ctrl+O to toggle thinking process \xB7 follow reasoning",
50134
+ "Tip: Shift+Tab for multiline input \xB7 \u2191/\u2193 browse history",
50135
+ "Tip: Type / for slash commands \xB7 type @ to mention context",
50136
+ "Tip: Ctrl+C to stop generation safely at any time"
50137
+ ];
50138
+ function getBilingualTip(liveMs, locale = "zh-CN") {
50139
+ const tips = locale === "en-US" ? GENERATION_TIPS_EN : GENERATION_TIPS_ZH;
50140
+ return tips[Math.floor(Math.max(0, liveMs ?? 0) / 4e3) % tips.length] ?? tips[0];
50141
+ }
50142
+ function formatSeconds(ms) {
50143
+ return (ms / 1e3).toFixed(1);
50043
50144
  }
50044
50145
  function thinkingHeader(durationMs, expanded, live = false) {
50045
- const mark = expanded ? "\u25BE " : "";
50046
- const icon = live ? getBrailleSpinnerFrame(durationMs) : "\u273B";
50047
- return paintRow([styled(`${mark}${icon} \u601D\u8003 (${formatSeconds(durationMs)}s)`, "fgDim")]);
50146
+ return paintRow([styled(`${expanded ? "\u25BE " : ""}${live ? getBrailleSpinnerFrame(durationMs) : "\u273B"} \u601D\u8003 (${formatSeconds(durationMs)}s)`, "fgDim")]);
50048
50147
  }
50049
50148
  function bodyRow(line2, key) {
50050
50149
  return (0, import_jsx_runtime.jsx)(Text, { children: paintRow([styled(` ${escapeContent(line2)}`, "fgDim")]) }, key);
@@ -50144,111 +50243,6 @@ var RowSequence = class {
50144
50243
  });
50145
50244
  }
50146
50245
  };
50147
- var dictionaries = {
50148
- "zh-CN": {
50149
- on: "\u5F00",
50150
- off: "\u5173",
50151
- reasoning: "\u601D\u8003",
50152
- scrollbar: "\u8F68\u9053",
50153
- statusDetails: "\u6307\u6807\u8BE6\u60C5",
50154
- locale: "\u754C\u9762\u8BED\u8A00",
50155
- metrics: "\u6307\u6807",
50156
- mode: "\u6A21\u5F0F",
50157
- tools: "\u5DE5\u5177",
50158
- context: "\u4E0A\u4E0B\u6587",
50159
- status: "\u72B6\u6001",
50160
- effort: "\u5F3A\u5EA6",
50161
- cacheHit: "\u7F13\u5B58\u547D\u4E2D",
50162
- retry: "\u91CD\u8BD5",
50163
- commandStatus: "\u663E\u793A/\u9690\u85CF\u5B8C\u6574\u72B6\u6001\u6307\u6807",
50164
- commandReasoning: "\u663E\u793A/\u9690\u85CF\u5168\u6587\u601D\u8003 \xB7 Ctrl+O",
50165
- commandScrollbar: "\u663E\u793A/\u9690\u85CF\u6EDA\u52A8\u8F68\u9053",
50166
- settingsSaveFailed: "\u2717 \u663E\u793A\u8BBE\u7F6E\u672A\u4FDD\u5B58 \xB7 \u8BF7\u91CD\u8BD5",
50167
- inputHint: "\u8F93\u5165\u6D88\u606F",
50168
- sendHint: "Enter \u53D1\u9001",
50169
- arguments: "\u53C2\u6570",
50170
- result: "\u7ED3\u679C",
50171
- diagnostics: "\u8BCA\u65AD\u5143\u6570\u636E",
50172
- processStatus: "\u8FDB\u7A0B\u72B6\u6001",
50173
- running: "\u8FD0\u884C\u4E2D",
50174
- failed: "\u5931\u8D25",
50175
- remaining: "\u5269\u4F59\u6E90\u884C",
50176
- toolDetails: "/tools \u8BE6\u60C5",
50177
- commandTools: "\u9010\u9879\u67E5\u770B\u5DE5\u5177\u53C2\u6570\u3001\u5B8C\u6574\u7ED3\u679C\u4E0E\u8BCA\u65AD",
50178
- noTools: "\u5F53\u524D\u4F1A\u8BDD\u6CA1\u6709\u5DE5\u5177\u8C03\u7528",
50179
- toolListHint: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u8BE6\u60C5 \xB7 Esc \u5173\u95ED",
50180
- toolPageHint: "\u2190\u2192 \u7FFB\u9875 \xB7 d \u8BCA\u65AD \xB7 y \u590D\u5236 \xB7 e \u5BFC\u51FA \xB7 Esc \u8FD4\u56DE",
50181
- toolCopied: "\u2713 \u5DF2\u590D\u5236\u5B8C\u6574\u5DE5\u5177\u539F\u6587",
50182
- toolExported: "\u2713 \u5DE5\u5177\u539F\u6587\u5DF2\u5BFC\u51FA",
50183
- toolCopyFailed: "\u2717 \u5DE5\u5177\u539F\u6587\u590D\u5236\u5931\u8D25",
50184
- toolExportFailed: "\u2717 \u5DE5\u5177\u539F\u6587\u5BFC\u51FA\u5931\u8D25",
50185
- toolExportAction: "\u5BFC\u51FA\u5B8C\u6574\u539F\u6587"
50186
- },
50187
- "en-US": {
50188
- on: "on",
50189
- off: "off",
50190
- reasoning: "Thinking",
50191
- scrollbar: "Rail",
50192
- statusDetails: "Status details",
50193
- locale: "UI language",
50194
- metrics: "Metrics",
50195
- mode: "Mode",
50196
- tools: "Tools",
50197
- context: "Context",
50198
- status: "Status",
50199
- effort: "Effort",
50200
- cacheHit: "Cache hit",
50201
- retry: "Retry",
50202
- commandStatus: "Show/hide full status metrics",
50203
- commandReasoning: "Show/hide full thinking text \xB7 Ctrl+O",
50204
- commandScrollbar: "Show/hide the scroll rail",
50205
- settingsSaveFailed: "\u2717 Display setting was not saved \xB7 Retry",
50206
- inputHint: "Type a message",
50207
- sendHint: "Enter to send",
50208
- arguments: "Arguments",
50209
- result: "Result",
50210
- diagnostics: "Diagnostic metadata",
50211
- processStatus: "Process status",
50212
- running: "Running",
50213
- failed: "Failed",
50214
- remaining: "source lines remaining",
50215
- toolDetails: "/tools details",
50216
- commandTools: "Inspect individual tool arguments, full results, and diagnostics",
50217
- noTools: "No tool calls in this session",
50218
- toolListHint: "\u2191\u2193 Select \xB7 Enter Details \xB7 Esc Close",
50219
- toolPageHint: "\u2190\u2192 Pages \xB7 d Diagnostics \xB7 y Copy \xB7 e Export \xB7 Esc Back",
50220
- toolCopied: "\u2713 Full tool source copied",
50221
- toolExported: "\u2713 Tool source exported",
50222
- toolCopyFailed: "\u2717 Tool source copy failed",
50223
- toolExportFailed: "\u2717 Tool source export failed",
50224
- toolExportAction: "Export full source"
50225
- }
50226
- };
50227
- function tuiCopy(key, locale = "zh-CN") {
50228
- return dictionaries[locale][key];
50229
- }
50230
- var SWIMMING_FISH_FRAMES = BRAILLE_SPINNER_FRAMES;
50231
- function getSwimmingFishFrame(liveMs) {
50232
- return getBrailleSpinnerFrame(liveMs);
50233
- }
50234
- var GENERATION_TIPS_ZH = [
50235
- "\u63D0\u793A\uFF1ACtrl+E \u5C55\u5F00\u5DE5\u5177\u5361 \xB7 /tools \u67E5\u770B\u5B8C\u6574\u8F93\u51FA",
50236
- "\u63D0\u793A\uFF1ACtrl+O \u5C55\u5F00/\u6536\u8D77\u601D\u8003\u8FC7\u7A0B \xB7 \u968F\u65F6\u8DDF\u8FDB\u63A8\u7406",
50237
- "\u63D0\u793A\uFF1AShift+Tab \u5207\u6362\u591A\u884C\u8F93\u5165 \xB7 \u2191/\u2193 \u6D4F\u89C8\u5386\u53F2\u6D88\u606F",
50238
- "\u63D0\u793A\uFF1A\u8F93\u5165 / \u6253\u5F00\u5FEB\u6377\u547D\u4EE4 \xB7 \u8F93\u5165 @ \u63D0\u53CA\u6587\u4EF6\u4E0E\u4E0A\u4E0B\u6587",
50239
- "\u63D0\u793A\uFF1ACtrl+C \u4E2D\u65AD\u5F53\u524D\u751F\u6210 \xB7 \u968F\u65F6\u5B89\u5168\u505C\u6B62"
50240
- ];
50241
- var GENERATION_TIPS_EN = [
50242
- "Tip: Ctrl+E to expand tool cards \xB7 /tools for full output",
50243
- "Tip: Ctrl+O to toggle thinking process \xB7 follow reasoning",
50244
- "Tip: Shift+Tab for multiline input \xB7 \u2191/\u2193 browse history",
50245
- "Tip: Type / for slash commands \xB7 type @ to mention context",
50246
- "Tip: Ctrl+C to stop generation safely at any time"
50247
- ];
50248
- function getBilingualTip(liveMs, locale = "zh-CN") {
50249
- const tips = locale === "en-US" ? GENERATION_TIPS_EN : GENERATION_TIPS_ZH;
50250
- return tips[Math.floor(Math.max(0, liveMs ?? 0) / 4e3) % tips.length] ?? tips[0];
50251
- }
50252
50246
  var graphemes$1 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
50253
50247
  function textLines(text4, prefix = "") {
50254
50248
  let length = 1;
@@ -55809,14 +55803,14 @@ function StreamView({ model, presenters, brandTier = "plain", brandAnimation = f
55809
55803
  const visibleParts = displayedParts(rawParts, reasoningExpanded);
55810
55804
  if (generating && visibleParts.length === 0) {
55811
55805
  const liveMs = liveDurationMs ?? turn.reasoningDurationMs;
55812
- const fish = getBrailleSpinnerFrame(liveMs);
55806
+ const spinner = getBrailleSpinnerFrame(liveMs);
55813
55807
  const tip = getBilingualTip(liveMs, locale);
55814
55808
  return (0, import_jsx_runtime.jsxs)(Box_default, {
55815
55809
  flexDirection: "column",
55816
55810
  width: "100%",
55817
55811
  flexShrink: 0,
55818
55812
  children: [(0, import_jsx_runtime.jsx)(Text, { children: paintRow([
55819
- styled(fish, "accentText", void 0, true),
55813
+ styled(spinner, "accentText", void 0, true),
55820
55814
  styled(" \u25CF ", "accentText", void 0, true),
55821
55815
  styled(`\u6B63\u5728\u5904\u7406\u2026 (${formatSeconds(liveMs)}s)`, "fg")
55822
55816
  ]) }), (0, import_jsx_runtime.jsx)(Text, { children: paintRow([styled(` \u2514 ${tip}`, "fgDim")]) })]
@@ -56100,9 +56094,9 @@ function SessionPane({ rows, selectedIndex, currentId, confirmDelete, deleteUnav
56100
56094
  !showControls ? null : confirmDelete ? (0, import_jsx_runtime.jsx)(Text, {
56101
56095
  wrap: "truncate",
56102
56096
  children: styled(`\u518D\u6309 d \u786E\u8BA4\u5220\u9664\u300C${escapeContent(selected?.title ?? "")}\u300D`, "error")
56103
- }) : deleteUnavailable ? (0, import_jsx_runtime.jsx)(Text, {
56097
+ }) : deleteUnavailable ? (0, import_jsx_runtime.jsxs)(Text, {
56104
56098
  wrap: "truncate",
56105
- 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")]
56106
56100
  }) : (0, import_jsx_runtime.jsx)(Text, {
56107
56101
  wrap: "truncate",
56108
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")
@@ -56714,54 +56708,23 @@ function moveCaretByGrapheme(text4, caretIndex, direction) {
56714
56708
  return text4.length;
56715
56709
  }
56716
56710
  function moveCaretUpLine(text4, caretIndex) {
56717
- const lines = text4.split("\n");
56718
- if (lines.length <= 1) return void 0;
56719
56711
  const caret = clampCaretIndex(text4, caretIndex);
56720
- let accumulated = 0;
56721
- let currentRow = 0;
56722
- let col = 0;
56723
- for (let r = 0; r < lines.length; r++) {
56724
- const lineLen = lines[r].length;
56725
- if (caret <= accumulated + lineLen) {
56726
- currentRow = r;
56727
- col = caret - accumulated;
56728
- break;
56729
- }
56730
- accumulated += lineLen + 1;
56731
- }
56732
- if (currentRow === 0) return void 0;
56733
- let targetAcc = 0;
56734
- for (let r = 0; r < currentRow - 1; r++) {
56735
- targetAcc += lines[r].length + 1;
56736
- }
56737
- const prevLineLen = lines[currentRow - 1].length;
56738
- const targetCol = Math.min(col, prevLineLen);
56739
- return targetAcc + targetCol;
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);
56740
56718
  }
56741
56719
  function moveCaretDownLine(text4, caretIndex) {
56742
- const lines = text4.split("\n");
56743
- if (lines.length <= 1) return void 0;
56744
56720
  const caret = clampCaretIndex(text4, caretIndex);
56745
- let accumulated = 0;
56746
- let currentRow = lines.length - 1;
56747
- let col = 0;
56748
- for (let r = 0; r < lines.length; r++) {
56749
- const lineLen = lines[r].length;
56750
- if (caret <= accumulated + lineLen) {
56751
- currentRow = r;
56752
- col = caret - accumulated;
56753
- break;
56754
- }
56755
- accumulated += lineLen + 1;
56756
- }
56757
- if (currentRow >= lines.length - 1) return void 0;
56758
- let targetAcc = 0;
56759
- for (let r = 0; r <= currentRow; r++) {
56760
- targetAcc += lines[r].length + 1;
56761
- }
56762
- const nextLineLen = lines[currentRow + 1].length;
56763
- const targetCol = Math.min(col, nextLineLen);
56764
- return targetAcc + targetCol;
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);
56765
56728
  }
56766
56729
  function composerFrameAnchor(text4, caretIndex, options) {
56767
56730
  const caret = composerCursorPosition(text4, caretIndex);
@@ -58954,15 +58917,11 @@ function TuiLoop({ title, controller, brandTier = "plain", brandAutoEligible = f
58954
58917
  historyLengthRef.current = model.history.length;
58955
58918
  const sentHistoryRef = (0, import_react34.useRef)([]);
58956
58919
  const inputHistory = (0, import_react34.useMemo)(() => {
58957
- const fromModel = model.history
58958
- .filter((m) => m.kind === "user" && typeof m.text === "string" && m.text.trim().length > 0)
58959
- .map((m) => m.text);
58920
+ const fromModel = model.history.filter((m) => m.kind === "user" && typeof m.text === "string" && m.text.trim().length > 0).map((m) => m.text);
58960
58921
  const combined = [];
58961
58922
  for (const item of [...fromModel, ...sentHistoryRef.current]) {
58962
58923
  const trimmed = item.trim();
58963
- if (trimmed.length > 0 && combined.at(-1) !== trimmed) {
58964
- combined.push(trimmed);
58965
- }
58924
+ if (trimmed.length > 0 && combined.at(-1) !== trimmed) combined.push(trimmed);
58966
58925
  }
58967
58926
  return combined;
58968
58927
  }, [model.history]);
@@ -59108,16 +59067,12 @@ function TuiLoop({ title, controller, brandTier = "plain", brandAutoEligible = f
59108
59067
  });
59109
59068
  else if (action.kind === "send") {
59110
59069
  const trimmed = action.text.trim();
59111
- if (trimmed.length > 0 && sentHistoryRef.current.at(-1) !== trimmed) {
59112
- sentHistoryRef.current.push(trimmed);
59113
- }
59070
+ if (trimmed.length > 0 && sentHistoryRef.current.at(-1) !== trimmed) sentHistoryRef.current.push(trimmed);
59114
59071
  issueViewportCommand({ kind: "reset" });
59115
59072
  controller.dispatch(action);
59116
59073
  } else if (action.kind === "command") {
59117
59074
  const queryText = action.query.trim().startsWith("/") ? action.query.trim() : `/${action.query.trim()}`;
59118
- if (queryText.length > 0 && sentHistoryRef.current.at(-1) !== queryText) {
59119
- sentHistoryRef.current.push(queryText);
59120
- }
59075
+ if (queryText.length > 0 && sentHistoryRef.current.at(-1) !== queryText) sentHistoryRef.current.push(queryText);
59121
59076
  controller.dispatch(action);
59122
59077
  } else if (action.kind === "new-session" || action.kind === "select-session") {
59123
59078
  sentHistoryRef.current = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crazyhappyone/dsh-tui",
3
- "version": "0.1.0-alpha.22",
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",