@deepseek-harness-tui/dsh-tui 0.8.4 → 0.8.6

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 (80) hide show
  1. package/lib/types/activityPrefs.d.ts +10 -0
  2. package/lib/types/activityPrefs.d.ts.map +1 -1
  3. package/lib/types/activityPrefs.js +17 -0
  4. package/lib/types/cc/figures.d.ts +7 -0
  5. package/lib/types/cc/figures.d.ts.map +1 -1
  6. package/lib/types/cc/figures.js +23 -0
  7. package/lib/types/cc/markdown.d.ts.map +1 -1
  8. package/lib/types/cc/markdown.js +47 -14
  9. package/lib/types/cc/syntaxTheme.d.ts +12 -0
  10. package/lib/types/cc/syntaxTheme.d.ts.map +1 -0
  11. package/lib/types/cc/syntaxTheme.js +76 -0
  12. package/lib/types/components/EffortChargeGlyph.d.ts +26 -0
  13. package/lib/types/components/EffortChargeGlyph.d.ts.map +1 -0
  14. package/lib/types/components/EffortChargeGlyph.js +70 -0
  15. package/lib/types/components/EffortInputBorder.d.ts +36 -0
  16. package/lib/types/components/EffortInputBorder.d.ts.map +1 -0
  17. package/lib/types/components/EffortInputBorder.js +73 -0
  18. package/lib/types/components/EffortTierBadge.d.ts +26 -0
  19. package/lib/types/components/EffortTierBadge.d.ts.map +1 -0
  20. package/lib/types/components/EffortTierBadge.js +97 -0
  21. package/lib/types/components/LoadedContextPanel.js +1 -1
  22. package/lib/types/components/MessageList.d.ts +4 -1
  23. package/lib/types/components/MessageList.d.ts.map +1 -1
  24. package/lib/types/components/MessageList.js +9 -11
  25. package/lib/types/components/PromptInput.d.ts.map +1 -1
  26. package/lib/types/components/PromptInput.js +8 -3
  27. package/lib/types/components/SplitDiffView.d.ts +4 -5
  28. package/lib/types/components/SplitDiffView.d.ts.map +1 -1
  29. package/lib/types/components/SplitDiffView.js +18 -65
  30. package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
  31. package/lib/types/components/StreamingMarkdown.js +10 -2
  32. package/lib/types/components/activityFrames.d.ts +7 -28
  33. package/lib/types/components/activityFrames.d.ts.map +1 -1
  34. package/lib/types/components/activityFrames.js +7 -94
  35. package/lib/types/components/design-system/ThemedBox.d.ts.map +1 -1
  36. package/lib/types/components/design-system/ThemedBox.js +4 -1
  37. package/lib/types/components/design-system/ThemedText.js +2 -2
  38. package/lib/types/components/messages/AssistantThinkingMessage.d.ts +12 -6
  39. package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
  40. package/lib/types/components/messages/AssistantThinkingMessage.js +25 -9
  41. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +4 -1
  42. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  43. package/lib/types/components/messages/AssistantToolUseMessage.js +45 -17
  44. package/lib/types/components/messages/UserPromptMessage.d.ts +4 -6
  45. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  46. package/lib/types/components/messages/UserPromptMessage.js +5 -9
  47. package/lib/types/dsh-adapter/channel.d.ts +22 -0
  48. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  49. package/lib/types/dsh-adapter/channel.js +204 -19
  50. package/lib/types/dsh-adapter/index.d.ts +5 -0
  51. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  52. package/lib/types/dsh-adapter/index.js +19 -0
  53. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  54. package/lib/types/dsh-adapter/plugin.js +176 -4
  55. package/lib/types/dsh-adapter/settings-sections.d.ts +13 -0
  56. package/lib/types/dsh-adapter/settings-sections.d.ts.map +1 -1
  57. package/lib/types/dsh-adapter/settings-sections.js +31 -6
  58. package/lib/types/ink/ink.d.ts +9 -0
  59. package/lib/types/ink/ink.d.ts.map +1 -1
  60. package/lib/types/ink/ink.js +24 -1
  61. package/lib/types/screens/Chat.d.ts.map +1 -1
  62. package/lib/types/screens/Chat.js +35 -6
  63. package/lib/types/screens/Settings.d.ts.map +1 -1
  64. package/lib/types/screens/Settings.js +109 -50
  65. package/lib/types/screens/StatusLine.d.ts +8 -0
  66. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  67. package/lib/types/screens/StatusLine.js +62 -39
  68. package/lib/types/settings-sections.d.ts +1 -1
  69. package/lib/types/settings-sections.d.ts.map +1 -1
  70. package/lib/types/theme.d.ts +12 -0
  71. package/lib/types/theme.d.ts.map +1 -1
  72. package/lib/types/theme.js +51 -21
  73. package/lib/types/tips.js +2 -2
  74. package/lib/types/trajectory/effortIgnition.d.ts +66 -0
  75. package/lib/types/trajectory/effortIgnition.d.ts.map +1 -0
  76. package/lib/types/trajectory/effortIgnition.js +142 -0
  77. package/lib/types/tuiDisplayPrefs.d.ts +47 -0
  78. package/lib/types/tuiDisplayPrefs.d.ts.map +1 -0
  79. package/lib/types/tuiDisplayPrefs.js +60 -0
  80. package/package.json +6 -3
package/lib/types/tips.js CHANGED
@@ -443,8 +443,8 @@ export const TIPS = [
443
443
  {
444
444
  id: 'disp-activity',
445
445
  group: 'display',
446
- zh: '/activity frames comet 换状态行动画(31 种)',
447
- en: '/activity frames comet changes the spinner (31 presets)',
446
+ zh: '/activity frames comet 换状态行动画(35 种)',
447
+ en: '/activity frames comet changes the spinner (35 presets)',
448
448
  },
449
449
  {
450
450
  id: 'disp-diff-layout',
@@ -0,0 +1,66 @@
1
+ /** 三幕时间轴(ms):扫光全长、字样启动(波至中段)、字样渐亮、渐隐起止。边框扫光与输入行字样徽标共用。 */
2
+ export declare const IGNITION_TIMELINE: {
3
+ readonly sweepMs: 1000;
4
+ readonly labelStartMs: 600;
5
+ readonly labelBrightenMs: 160;
6
+ readonly fadeStartMs: 1500;
7
+ readonly fadeEndMs: 2000;
8
+ };
9
+ /**
10
+ * Effort ignition motion math — pure functions, zero dependencies.
11
+ *
12
+ * Waveform semantics ported from Codex CLI's effort_ignition(_styles).rs
13
+ * (openai/codex PR #34365) and revalidated in a dsh-TUI integration: a
14
+ * cosine-bell travelling wave produces per-column colours only — a renderer
15
+ * that keeps glyphs constant and changes colours per frame stays SGR-only
16
+ * by construction.
17
+ *
18
+ * Consumers ride the FOREGROUND channel (a constant block glyph under a
19
+ * varying fg colour): pure-background cells never reached the terminal in
20
+ * the fullscreen log-update pipeline, while foreground is the channel every
21
+ * live element already rides.
22
+ */
23
+ import type { RGBColor } from '../components/Spinner/spinnerUtils.js';
24
+ /** 扫光全长(ms),仅用于把墙钟时间折算成动画秒数,不创建任何定时器。 */
25
+ export declare const SWEEP_TOTAL_MS = 1000;
26
+ export declare function ignitionHues(onLight: boolean): readonly [RGBColor, RGBColor, RGBColor];
27
+ /**
28
+ * 充能色对(前缀强调用):从带底色调暗端到全值,与波共用 hues[0]。
29
+ */
30
+ export declare function accentRamp(onLight: boolean): {
31
+ dim: RGBColor;
32
+ full: RGBColor;
33
+ };
34
+ /** 余弦钟形:`crest(0)=1`、`crest(±1)=0`、之外为 0(负距离同样静默——
35
+ * 现有调用方都传 `Math.abs`,这里兜底防未来调用方拿到全强度)。 */
36
+ export declare function crest(distance: number): number;
37
+ /** ease-out cubic:`1-(1-p)³`,两端 clamp。 */
38
+ export declare function easeOutCubic(progress: number): number;
39
+ /** ease-in-out cubic:前半 `4p³`、后半镜像,两端 clamp。 */
40
+ export declare function easeInOutCubic(progress: number): number;
41
+ /** 线性混色(t=0 → a,t=1 → b,不 clamp)。 */
42
+ export declare function blend(a: RGBColor, b: RGBColor, t: number): RGBColor;
43
+ /**
44
+ * 扫光某一时刻的整行颜色。
45
+ *
46
+ * @param options.elapsedMs - 距触发的时间;达到 {@link SWEEP_TOTAL_MS}
47
+ * 后整行返回空数组(无波,行恢复本底)。
48
+ * @param options.width - 行列数(终端宽)。
49
+ * @param options.onLight - 浅色主题时用浅底色板与浅带底色。
50
+ * @returns 逐列颜色(`rgb(r,g,b)` 字符串);无波的列为 `undefined`,
51
+ * 渲染层应输出本底色,保持行宽恒定。
52
+ */
53
+ export declare function ignitionLineColors(options: {
54
+ elapsedMs: number;
55
+ width: number;
56
+ onLight: boolean;
57
+ }): ReadonlyArray<string | undefined>;
58
+ /**
59
+ * 顶档切入判定:从「已有档位」变为「另一档位」且新档位是档位表末位
60
+ * 最高档。冷启动恢复偏好、单档表、档位表未知都不触发。
61
+ */
62
+ export declare function entersTopTier(previous: string | undefined, current: string | undefined, levels: readonly string[] | undefined): boolean;
63
+ /** 充能时长(ms)与充能进度(钳 [0,1],负 elapsed 钳 0)。 */
64
+ export declare const CHARGE_MS = 150;
65
+ export declare function chargeProgress(elapsedMs: number): number;
66
+ //# sourceMappingURL=effortIgnition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effortIgnition.d.ts","sourceRoot":"","sources":["../../../src/trajectory/effortIgnition.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,eAAO,MAAM,iBAAiB;;;;;;CAMpB,CAAA;AAEV;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAA;AAGrE,yCAAyC;AACzC,eAAO,MAAM,cAAc,OAAO,CAAA;AA8BlC,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAEtF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG;IAAE,GAAG,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAG9E;AAED;0CAC0C;AAC1C,wBAAgB,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAKvD;AAaD,qCAAqC;AACrC,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ,CAMnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;CACjB,GAAG,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,CA0BpC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GACpC,OAAO,CAST;AAED,4CAA4C;AAC5C,eAAO,MAAM,SAAS,MAAM,CAAA;AAE5B,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGxD"}
@@ -0,0 +1,142 @@
1
+ /** 三幕时间轴(ms):扫光全长、字样启动(波至中段)、字样渐亮、渐隐起止。边框扫光与输入行字样徽标共用。 */
2
+ export const IGNITION_TIMELINE = {
3
+ sweepMs: 1000,
4
+ labelStartMs: 600,
5
+ labelBrightenMs: 160,
6
+ fadeStartMs: 1500,
7
+ fadeEndMs: 2000,
8
+ };
9
+ import { rgbString } from './motion.js';
10
+ /** 扫光全长(ms),仅用于把墙钟时间折算成动画秒数,不创建任何定时器。 */
11
+ export const SWEEP_TOTAL_MS = 1000;
12
+ /** 波形宽度参数(列)。 */
13
+ const WAVE_HALF_WIDTH = 14;
14
+ /** 波形参数:`[launch, travel]`(秒)——扫光在何时启动、多久行至右缘。 */
15
+ const BAND = [0.1, 0.75];
16
+ /**
17
+ * 高亮彩色色板:亮蓝/亮青/亮紫三 hue(浅色背景用加深变体——浅底上
18
+ * 亮色没有对比度)。波只点亮 hues[0],前两个 hue 留给未来的多带风格。
19
+ */
20
+ const HUES_DARK = [
21
+ { r: 130, g: 185, b: 255 },
22
+ { r: 140, g: 252, b: 248 },
23
+ { r: 195, g: 172, b: 255 },
24
+ ];
25
+ const HUES_LIGHT = [
26
+ { r: 30, g: 95, b: 235 },
27
+ { r: 10, g: 160, b: 200 },
28
+ { r: 120, g: 80, b: 235 },
29
+ ];
30
+ /**
31
+ * 带底色(波向终端本底淡入的目标色)。近似值:取主题深/浅背景的典
32
+ * 型值而非逐主题读取——波只存活一秒,色差在低 alpha 下不可辨。
33
+ */
34
+ const BAND_DARK = { r: 27, g: 30, b: 40 };
35
+ const BAND_LIGHT = { r: 240, g: 240, b: 242 };
36
+ export function ignitionHues(onLight) {
37
+ return onLight ? HUES_LIGHT : HUES_DARK;
38
+ }
39
+ /**
40
+ * 充能色对(前缀强调用):从带底色调暗端到全值,与波共用 hues[0]。
41
+ */
42
+ export function accentRamp(onLight) {
43
+ const band = onLight ? BAND_LIGHT : BAND_DARK;
44
+ return { dim: blend(band, ignitionHues(onLight)[0], 0.45), full: ignitionHues(onLight)[0] };
45
+ }
46
+ /** 余弦钟形:`crest(0)=1`、`crest(±1)=0`、之外为 0(负距离同样静默——
47
+ * 现有调用方都传 `Math.abs`,这里兜底防未来调用方拿到全强度)。 */
48
+ export function crest(distance) {
49
+ if (distance >= 1 || distance <= -1)
50
+ return 0;
51
+ return 0.5 * (1 + Math.cos(Math.PI * distance));
52
+ }
53
+ /** ease-out cubic:`1-(1-p)³`,两端 clamp。 */
54
+ export function easeOutCubic(progress) {
55
+ const p = Math.min(1, Math.max(0, progress));
56
+ const inverse = 1 - p;
57
+ return 1 - inverse * inverse * inverse;
58
+ }
59
+ /** ease-in-out cubic:前半 `4p³`、后半镜像,两端 clamp。 */
60
+ export function easeInOutCubic(progress) {
61
+ const p = Math.min(1, Math.max(0, progress));
62
+ if (p < 0.5)
63
+ return 4 * p * p * p;
64
+ const inverse = -2 * p + 2;
65
+ return 1 - (inverse * inverse * inverse) / 2;
66
+ }
67
+ /** 单列对波带的采样:三 hue 权重(未归一;单波形只点亮 hue[0])。 */
68
+ function sampleColumn(elapsed, column, width) {
69
+ const weights = [0, 0, 0];
70
+ const [launch, travel] = BAND;
71
+ const progress = (elapsed - launch) / travel;
72
+ if (progress < 0 || progress > 1)
73
+ return weights;
74
+ const center = easeInOutCubic(progress) * (width + 2 * WAVE_HALF_WIDTH) - WAVE_HALF_WIDTH;
75
+ weights[0] = crest(Math.abs(column - center) / WAVE_HALF_WIDTH);
76
+ return weights;
77
+ }
78
+ /** 线性混色(t=0 → a,t=1 → b,不 clamp)。 */
79
+ export function blend(a, b, t) {
80
+ return {
81
+ r: Math.round(a.r + (b.r - a.r) * t),
82
+ g: Math.round(a.g + (b.g - a.g) * t),
83
+ b: Math.round(a.b + (b.b - a.b) * t),
84
+ };
85
+ }
86
+ /**
87
+ * 扫光某一时刻的整行颜色。
88
+ *
89
+ * @param options.elapsedMs - 距触发的时间;达到 {@link SWEEP_TOTAL_MS}
90
+ * 后整行返回空数组(无波,行恢复本底)。
91
+ * @param options.width - 行列数(终端宽)。
92
+ * @param options.onLight - 浅色主题时用浅底色板与浅带底色。
93
+ * @returns 逐列颜色(`rgb(r,g,b)` 字符串);无波的列为 `undefined`,
94
+ * 渲染层应输出本底色,保持行宽恒定。
95
+ */
96
+ export function ignitionLineColors(options) {
97
+ const { elapsedMs, width, onLight } = options;
98
+ const elapsed = elapsedMs / 1000;
99
+ const total = SWEEP_TOTAL_MS / 1000;
100
+ if (width <= 0 || !Number.isFinite(elapsed) || elapsed <= 0 || elapsed >= total)
101
+ return [];
102
+ const hue = ignitionHues(onLight)[0];
103
+ const band = onLight ? BAND_LIGHT : BAND_DARK;
104
+ const colors = new Array(width);
105
+ for (let column = 0; column < width; column++) {
106
+ const weight = sampleColumn(elapsed, column, width)[0];
107
+ if (weight <= 0.01) {
108
+ colors[column] = undefined;
109
+ continue;
110
+ }
111
+ // 波按强度淡入带底色:alpha=1 是纯 hue,alpha→0 收敛回本底;高亮
112
+ // 度档满强度纯 hue 直出。输出前通道量化到 8 步长——渐变列因此能
113
+ // 合并成长段(渲染层 RLE 段数降一个数量级),8/256 的色差在终端
114
+ // cell 分辨率下不可辨。
115
+ const tinted = blend(band, hue, Math.min(weight, 1));
116
+ colors[column] = rgbString({
117
+ r: Math.round(tinted.r / 8) * 8,
118
+ g: Math.round(tinted.g / 8) * 8,
119
+ b: Math.round(tinted.b / 8) * 8,
120
+ });
121
+ }
122
+ return colors;
123
+ }
124
+ /**
125
+ * 顶档切入判定:从「已有档位」变为「另一档位」且新档位是档位表末位
126
+ * 最高档。冷启动恢复偏好、单档表、档位表未知都不触发。
127
+ */
128
+ export function entersTopTier(previous, current, levels) {
129
+ return (current !== undefined &&
130
+ previous !== undefined &&
131
+ current !== previous &&
132
+ levels !== undefined &&
133
+ levels.length > 1 &&
134
+ current === levels[levels.length - 1]);
135
+ }
136
+ /** 充能时长(ms)与充能进度(钳 [0,1],负 elapsed 钳 0)。 */
137
+ export const CHARGE_MS = 150;
138
+ export function chargeProgress(elapsedMs) {
139
+ if (!Number.isFinite(elapsedMs))
140
+ return 0;
141
+ return Math.min(1, Math.max(0, Math.max(0, elapsedMs) / CHARGE_MS));
142
+ }
@@ -0,0 +1,47 @@
1
+ /** Background treatment applied to tool-call cards. */
2
+ export type ToolBackground = 'none' | 'subtle' | 'strong';
3
+ /** Individually selectable fields in the status footer. */
4
+ export interface StatusBarConfig {
5
+ /** Prefer the compact, single-line presentation when space permits. */
6
+ compact: boolean;
7
+ /** Live model id. */
8
+ model: boolean;
9
+ /** Reasoning effort / thinking mode. */
10
+ thinking: boolean;
11
+ /** Session working directory. */
12
+ cwd: boolean;
13
+ /** Current context-window consumption. */
14
+ contextUsage: boolean;
15
+ /** Prompt-cache hit rate. */
16
+ cache: boolean;
17
+ /** Running input/output token totals. */
18
+ tokens: boolean;
19
+ /** Live and recent output speed. */
20
+ tps: boolean;
21
+ /** Current git branch. */
22
+ gitBranch: boolean;
23
+ /** Current session title. */
24
+ sessionTitle: boolean;
25
+ /** Non-default session mode. */
26
+ mode: boolean;
27
+ /** Segmented context progress bar on its own footer row. */
28
+ contextBar: boolean;
29
+ /** Idle working-activity summary. */
30
+ activity: boolean;
31
+ /** Mini trajectory wake rendered at the footer's right edge. */
32
+ trajectory: boolean;
33
+ /** Idle `? for shortcuts` reminder; shortcut keys remain available when hidden. */
34
+ shortcutHint: boolean;
35
+ }
36
+ /** Defaults keep the essential route/context information visible. */
37
+ export declare const DEFAULT_STATUS_BAR: Readonly<StatusBarConfig>;
38
+ /** Normalize untrusted/config-layer values without mutating the input. */
39
+ export declare function normalizeToolBackground(value: unknown): ToolBackground;
40
+ /** Merge a partial settings value over the stable status-bar defaults. */
41
+ export declare function normalizeStatusBar(value: unknown): StatusBarConfig;
42
+ /**
43
+ * Format context-window usage for future status-line consumers.
44
+ * Invalid or unavailable inputs intentionally produce no field.
45
+ */
46
+ export declare function formatContextUsage(used: number | undefined, contextWindow: number | undefined, compact?: boolean): string | undefined;
47
+ //# sourceMappingURL=tuiDisplayPrefs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tuiDisplayPrefs.d.ts","sourceRoot":"","sources":["../../src/tuiDisplayPrefs.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAEzD,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC9B,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAA;IAChB,qBAAqB;IACrB,KAAK,EAAE,OAAO,CAAA;IACd,wCAAwC;IACxC,QAAQ,EAAE,OAAO,CAAA;IACjB,iCAAiC;IACjC,GAAG,EAAE,OAAO,CAAA;IACZ,0CAA0C;IAC1C,YAAY,EAAE,OAAO,CAAA;IACrB,6BAA6B;IAC7B,KAAK,EAAE,OAAO,CAAA;IACd,yCAAyC;IACzC,MAAM,EAAE,OAAO,CAAA;IACf,oCAAoC;IACpC,GAAG,EAAE,OAAO,CAAA;IACZ,0BAA0B;IAC1B,SAAS,EAAE,OAAO,CAAA;IAClB,6BAA6B;IAC7B,YAAY,EAAE,OAAO,CAAA;IACrB,gCAAgC;IAChC,IAAI,EAAE,OAAO,CAAA;IACb,4DAA4D;IAC5D,UAAU,EAAE,OAAO,CAAA;IACnB,qCAAqC;IACrC,QAAQ,EAAE,OAAO,CAAA;IACjB,gEAAgE;IAChE,UAAU,EAAE,OAAO,CAAA;IACnB,mFAAmF;IACnF,YAAY,EAAE,OAAO,CAAA;CACtB;AAED,qEAAqE;AACrE,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,eAAe,CAgBvD,CAAA;AAKF,0EAA0E;AAC1E,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAItE;AAED,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CASlE;AASD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,OAAO,UAAO,GACb,MAAM,GAAG,SAAS,CASpB"}
@@ -0,0 +1,60 @@
1
+ /** Defaults keep the essential route/context information visible. */
2
+ export const DEFAULT_STATUS_BAR = Object.freeze({
3
+ compact: true,
4
+ model: true,
5
+ thinking: true,
6
+ cwd: true,
7
+ contextUsage: true,
8
+ cache: true,
9
+ tokens: false,
10
+ tps: false,
11
+ gitBranch: false,
12
+ sessionTitle: false,
13
+ mode: false,
14
+ contextBar: false,
15
+ activity: false,
16
+ trajectory: false,
17
+ shortcutHint: false,
18
+ });
19
+ const TOOL_BACKGROUNDS = new Set(['none', 'subtle', 'strong']);
20
+ const STATUS_BAR_KEYS = Object.keys(DEFAULT_STATUS_BAR);
21
+ /** Normalize untrusted/config-layer values without mutating the input. */
22
+ export function normalizeToolBackground(value) {
23
+ return typeof value === 'string' && TOOL_BACKGROUNDS.has(value)
24
+ ? value
25
+ : 'none';
26
+ }
27
+ /** Merge a partial settings value over the stable status-bar defaults. */
28
+ export function normalizeStatusBar(value) {
29
+ const normalized = { ...DEFAULT_STATUS_BAR };
30
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
31
+ return normalized;
32
+ const input = value;
33
+ for (const key of STATUS_BAR_KEYS) {
34
+ if (typeof input[key] === 'boolean')
35
+ normalized[key] = input[key];
36
+ }
37
+ return normalized;
38
+ }
39
+ function formatTokenCount(value) {
40
+ const rounded = Math.max(0, Math.round(value));
41
+ if (rounded < 1_000)
42
+ return String(rounded);
43
+ if (rounded < 1_000_000)
44
+ return `${(rounded / 1_000).toFixed(rounded < 10_000 ? 1 : 0)}k`;
45
+ return `${(rounded / 1_000_000).toFixed(rounded < 10_000_000 ? 1 : 0)}m`;
46
+ }
47
+ /**
48
+ * Format context-window usage for future status-line consumers.
49
+ * Invalid or unavailable inputs intentionally produce no field.
50
+ */
51
+ export function formatContextUsage(used, contextWindow, compact = true) {
52
+ if (!Number.isFinite(used) || !Number.isFinite(contextWindow) || used === undefined || contextWindow === undefined || contextWindow <= 0) {
53
+ return undefined;
54
+ }
55
+ const safeUsed = Math.max(0, used);
56
+ const percent = Math.min(999, (safeUsed / contextWindow) * 100);
57
+ const percentText = `${percent < 10 ? percent.toFixed(1) : Math.round(percent)}%`;
58
+ const counts = `${formatTokenCount(safeUsed)}/${formatTokenCount(contextWindow)}`;
59
+ return compact ? `${percentText} (${counts})` : `${counts} (${percentText})`;
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepseek-harness-tui/dsh-tui",
3
- "version": "0.8.4",
3
+ "version": "0.8.6",
4
4
  "description": "Claude Code style interactive TUI front door for DeepSeek Harness agents, built on the ported Ink core.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -113,7 +113,10 @@
113
113
  "verify:plugin-commands": "node --import tsx/esm scripts/verify-plugin-commands.ts",
114
114
  "verify:plugin-negotiation": "node --import tsx/esm scripts/verify-plugin-negotiation.ts",
115
115
  "verify:plugin-lifecycle": "node --import tsx/esm scripts/verify-plugin-lifecycle.ts",
116
- "verify:tips": "node --import tsx/esm scripts/verify-tips.tsx"
116
+ "verify:tips": "node --import tsx/esm scripts/verify-tips.tsx",
117
+ "verify:thinking-preview": "node --import tsx/esm scripts/verify-thinking-preview.tsx",
118
+ "sync:profile": "node scripts/sync-profile.mjs",
119
+ "sync:profile:check": "node scripts/sync-profile.mjs --check"
117
120
  },
118
121
  "peerDependencies": {
119
122
  "@deepseek-ai/cordis": "^4.0.1",
@@ -158,7 +161,7 @@
158
161
  "cli-highlight": "^2.1.11",
159
162
  "code-excerpt": "^3.0.0 || ^4.0.0",
160
163
  "diff": "^8.0.4",
161
- "dsh-working-activity": "^0.3.0",
164
+ "dsh-working-activity": "^0.3.2",
162
165
  "emoji-regex": "^10.0.0",
163
166
  "figures": "^6.1.0",
164
167
  "get-east-asian-width": "^1.0.0",