dsh-code 0.9.1 → 1.0.0
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/README.en.md +29 -13
- package/README.md +264 -248
- package/bin/deepseek.mjs +100 -6
- package/cordis.patch.yml +29 -1
- package/lib/index.mjs +2223 -687
- package/lib/startup.mjs +21 -11
- package/lib/{theme-BEi4i_aN.mjs → theme-DCT8Y2xf.mjs} +13 -9
- package/lib/types/app.d.ts +66 -14
- package/lib/types/attachments.d.ts +7 -0
- package/lib/types/editor.d.ts +6 -0
- package/lib/types/fork.d.ts +8 -0
- package/lib/types/git-workflow.d.ts +23 -0
- package/lib/types/index.d.ts +6 -0
- package/lib/types/kernel-panels.d.ts +39 -0
- package/lib/types/keyboard.d.ts +43 -0
- package/lib/types/mentions.d.ts +28 -38
- package/lib/types/presets.d.ts +1 -3
- package/lib/types/provider-settings.d.ts +16 -0
- package/lib/types/render/animations.d.ts +10 -39
- package/lib/types/render/editor.d.ts +137 -0
- package/lib/types/render/export.d.ts +1 -1
- package/lib/types/render/lines.d.ts +6 -2
- package/lib/types/render/markdown.d.ts +3 -1
- package/lib/types/render/projection.d.ts +29 -3
- package/lib/types/render/status.d.ts +5 -12
- package/lib/types/session-directory.d.ts +1 -3
- package/lib/types/startup.d.ts +14 -11
- package/lib/types/store.d.ts +11 -9
- package/lib/types/subagents.d.ts +3 -3
- package/lib/types/theme.d.ts +14 -1
- package/lib/types/version.d.ts +15 -2
- package/package.json +153 -141
- package/src/app.ts +4455 -3917
- package/src/attachments.ts +44 -0
- package/src/editor.ts +51 -0
- package/src/fork.ts +31 -0
- package/src/git-workflow.ts +87 -0
- package/src/index.ts +1510 -1374
- package/src/internals.ts +14 -1
- package/src/kernel-panels.ts +914 -798
- package/src/keyboard.ts +125 -0
- package/src/mentions.ts +72 -117
- package/src/presets.ts +1 -4
- package/src/provider-settings.ts +94 -0
- package/src/render/animations.ts +25 -55
- package/src/render/editor.ts +398 -0
- package/src/render/export.ts +79 -79
- package/src/render/lines.ts +342 -236
- package/src/render/markdown.ts +99 -26
- package/src/render/projection.ts +102 -19
- package/src/render/status.ts +713 -650
- package/src/render/text.ts +150 -150
- package/src/render/tool-detail.ts +3 -1
- package/src/session-directory.ts +3 -3
- package/src/startup.ts +136 -119
- package/src/store.ts +23 -11
- package/src/subagents.ts +13 -5
- package/src/theme.ts +214 -206
- package/src/version.ts +58 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Terminal animation frame tables derived from the web design language:
|
|
3
3
|
* the StateDot "ongoing" pixel chase (3×3 ring, 125ms flat-hold brightness
|
|
4
|
-
* steps, 1s cycle) becomes the
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* steps, 1s cycle) becomes the full-ring clockwise braille chase in
|
|
5
|
+
* {@link BUSY_CHASE_FRAMES}, and the streaming caret blink is the
|
|
6
|
+
* Claude-Code convention.
|
|
7
7
|
*
|
|
8
8
|
* The DeepSeek model-switch easter egg ports Codex's effort-ignition "Wave"
|
|
9
9
|
* style (`codex-rs/tui/src/bottom_pane/effort_ignition_styles.rs`): switching
|
|
@@ -17,10 +17,6 @@
|
|
|
17
17
|
* @module @deepseek-ai/dsh-code/render/animations
|
|
18
18
|
*/
|
|
19
19
|
import type { RgbTriple } from '../theme.ts';
|
|
20
|
-
/** Single-cell stepped pulse: flat holds mirroring the web's 125ms keyframes. */
|
|
21
|
-
export declare const PULSE_FRAMES: readonly ["█", "█", "▆", "▃", "▁", "▃", "▆", "█"];
|
|
22
|
-
/** Pulse frame for a monotonic tick. */
|
|
23
|
-
export declare function pulseFrame(tick: number): string;
|
|
24
20
|
/**
|
|
25
21
|
* The web StateDot "ongoing" chase in terminal form: three cells of the 3×3
|
|
26
22
|
* ring trail clockwise around the eight outer positions, one braille glyph
|
|
@@ -59,15 +55,8 @@ export type DeepseekWaveTier = 'flash' | 'deepseek' | 'unknown';
|
|
|
59
55
|
* One style is picked at random per trigger and never repeats the previous.
|
|
60
56
|
*/
|
|
61
57
|
export type DeepseekWaveStyle = 'wave' | 'aurora' | 'pulse';
|
|
62
|
-
/** All styles in canonical order, for random selection and tests. */
|
|
63
|
-
export declare const DEEPSEEK_WAVE_STYLES: readonly DeepseekWaveStyle[];
|
|
64
58
|
/** Wave half-width in columns — Codex WAVE_HALF_WIDTH (9). */
|
|
65
59
|
export declare const WAVE_HALF_WIDTH = 9;
|
|
66
|
-
/** Pulse ring half-width in columns — Codex PULSE_HALF_WIDTH (4.5). */
|
|
67
|
-
export declare const PULSE_HALF_WIDTH = 4.5;
|
|
68
|
-
/** Sparkle start and frame cadence — Codex SPARK_START / SPARK_FRAME. */
|
|
69
|
-
export declare const SPARK_START_MS = 900;
|
|
70
|
-
export declare const SPARK_FRAME_MS = 100;
|
|
71
60
|
/** Sparkle glyphs in frame order — Codex SPARK_GLYPHS (`· ✦ ✧`). */
|
|
72
61
|
export declare const SPARK_GLYPHS: readonly ["·", "✦", "✧"];
|
|
73
62
|
/**
|
|
@@ -77,8 +66,6 @@ export declare const SPARK_GLYPHS: readonly ["·", "✦", "✧"];
|
|
|
77
66
|
*/
|
|
78
67
|
export type DeepseekWaveBand = readonly [number, number, number];
|
|
79
68
|
export declare const DEEPSEEK_WAVE_BANDS: Readonly<Record<DeepseekWaveStyle, Readonly<Record<DeepseekWaveTier, readonly DeepseekWaveBand[]>>>>;
|
|
80
|
-
/** Extra display time applied to every Codex ignition style. */
|
|
81
|
-
export declare const DEEPSEEK_WAVE_DURATION_EXTENSION_MS = 200;
|
|
82
69
|
/**
|
|
83
70
|
* Total visible duration: the Codex ignition duration plus 200ms so its motion
|
|
84
71
|
* remains readable in a busy terminal.
|
|
@@ -94,14 +81,6 @@ export declare function deepseekWaveDuration(tier: DeepseekWaveTier, style?: Dee
|
|
|
94
81
|
* @returns a style different from `previous`.
|
|
95
82
|
*/
|
|
96
83
|
export declare function deepseekWaveStyleRandom(previous: DeepseekWaveStyle | undefined): DeepseekWaveStyle;
|
|
97
|
-
/**
|
|
98
|
-
* Blank-cell background the wave tint blends toward — fixed approximations
|
|
99
|
-
* of the terminal's default background, mirroring Codex's
|
|
100
|
-
* `user_message_bg_rgb` (which derives a near-black / near-white bubble tint
|
|
101
|
-
* from the terminal background). The Ink layer picks the active theme's one.
|
|
102
|
-
*/
|
|
103
|
-
export declare const WAVE_BASE_DARK: RgbTriple;
|
|
104
|
-
export declare const WAVE_BASE_LIGHT: RgbTriple;
|
|
105
84
|
/**
|
|
106
85
|
* Tier for a `provider/model` label: a model id containing `flash` runs the
|
|
107
86
|
* single-band flash tier; everything else (pro/reasoner/chat) runs the
|
|
@@ -137,14 +116,16 @@ export declare function easeInOut(progress: number): number;
|
|
|
137
116
|
*/
|
|
138
117
|
export declare function envelope(elapsed: number, total: number, fadeIn: number, fadeOut: number): number;
|
|
139
118
|
/**
|
|
140
|
-
* The background color for one composer-
|
|
119
|
+
* The background color for one composer-band column at a tick — Codex
|
|
141
120
|
* `paint_bands` + `Canvas::tint` for all three styles. Bands overlap with a
|
|
142
121
|
* max for Wave/Pulse and a SUM for Aurora (Codex differs by style), the
|
|
143
122
|
* weighted hues mix per column (Wave/Pulse always end on hue 0), the tint
|
|
144
123
|
* blends the mixed hue toward the blank-cell base at the style's alpha cap,
|
|
145
124
|
* and Aurora applies its own fade envelope. Returns `null` when the column
|
|
146
125
|
* should stay transparent, so the row returns to no `backgroundColor` on
|
|
147
|
-
* both ends.
|
|
126
|
+
* both ends. With `rows > 1` each row samples the same timeline shifted by a
|
|
127
|
+
* per-row phase offset, so the crest cascades down the band instead of
|
|
128
|
+
* painting every row identically.
|
|
148
129
|
* @param tick - wave frame (0, 1, … at DEEPSEEK_WAVE_TICK_MS).
|
|
149
130
|
* @param column - column index in the content row (0..width-1).
|
|
150
131
|
* @param width - content-row width in columns.
|
|
@@ -152,9 +133,11 @@ export declare function envelope(elapsed: number, total: number, fadeIn: number,
|
|
|
152
133
|
* @param style - the ignition style.
|
|
153
134
|
* @param hues - the tier's three hues.
|
|
154
135
|
* @param base - the blank-cell base color the tint blends toward.
|
|
136
|
+
* @param row - row index in the band (0..rows-1; default 0 = old single-row).
|
|
137
|
+
* @param rows - band height in rows (default 1).
|
|
155
138
|
* @returns the blended RGB background, or null for transparent.
|
|
156
139
|
*/
|
|
157
|
-
export declare function deepseekWaveColumnBg(tick: number, column: number, width: number, tier: DeepseekWaveTier, style: DeepseekWaveStyle, hues: readonly [RgbTriple, RgbTriple, RgbTriple], base: RgbTriple): RgbTriple | null;
|
|
140
|
+
export declare function deepseekWaveColumnBg(tick: number, column: number, width: number, tier: DeepseekWaveTier, style: DeepseekWaveStyle, hues: readonly [RgbTriple, RgbTriple, RgbTriple], base: RgbTriple, row?: number, rows?: number): RgbTriple | null;
|
|
158
141
|
/**
|
|
159
142
|
* The sparkle glyph for a tick — Codex `spark_frame`, sampled on the same
|
|
160
143
|
* proportionally slowed DeepSeek Wave timeline as the composer background.
|
|
@@ -163,18 +146,6 @@ export declare function deepseekWaveColumnBg(tick: number, column: number, width
|
|
|
163
146
|
* @returns the sparkle glyph, or null outside the stretched tail window.
|
|
164
147
|
*/
|
|
165
148
|
export declare function deepseekWaveSpark(tick: number): string | null;
|
|
166
|
-
/**
|
|
167
|
-
* The composer BORDER color at a tick: the frame breathes with the wave —
|
|
168
|
-
* the palette's static dim blends toward the tier accent as the crest is
|
|
169
|
-
* alive and back, so the frame glows up while the wave sweeps and settles to
|
|
170
|
-
* dim on both ends (first==last frame==dim, no hard jump).
|
|
171
|
-
* @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS.
|
|
172
|
-
* @param tier - the wave tier.
|
|
173
|
-
* @param hues - the tier's three hues; the border blends toward hues[0].
|
|
174
|
-
* @param dim - the palette's static dim RGB (the resting border color).
|
|
175
|
-
* @returns the blended border RGB.
|
|
176
|
-
*/
|
|
177
|
-
export declare function deepseekWaveBorderColor(tick: number, tier: DeepseekWaveTier, style: DeepseekWaveStyle, hues: readonly [RgbTriple, RgbTriple, RgbTriple], dim: RgbTriple): RgbTriple;
|
|
178
149
|
/**
|
|
179
150
|
* Whether the `deepseek` wordmark rides the wave at this tick: it fades in
|
|
180
151
|
* shortly after the first crest launches and out before the wave settles,
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure composer editor model with Codex textarea semantics: a grapheme
|
|
3
|
+
* cursor over a column-safe multiline layout, word/piece motion, single-entry
|
|
4
|
+
* kill + yank, and the shell-recall boundary gate that keeps Up/Down usable
|
|
5
|
+
* inside a multiline draft.
|
|
6
|
+
*
|
|
7
|
+
* The model is intentionally string-offset based (UTF-16 indices clamped to
|
|
8
|
+
* grapheme boundaries) so the React state stays two primitives
|
|
9
|
+
* (value, cursor) and every operation here stays pure and testable.
|
|
10
|
+
*
|
|
11
|
+
* Word motion deviates from Codex's UAX#29 segmentation in one deliberate
|
|
12
|
+
* way: a run of same-class characters is ONE piece, so a CJK run moves as a
|
|
13
|
+
* single word (two hanzi are one Alt+B step, not two).
|
|
14
|
+
*
|
|
15
|
+
* @module @deepseek-ai/dsh-code/render/editor
|
|
16
|
+
*/
|
|
17
|
+
/** One grapheme cluster with its source span and display width in cells. */
|
|
18
|
+
export interface GraphemeSpan {
|
|
19
|
+
text: string;
|
|
20
|
+
start: number;
|
|
21
|
+
end: number;
|
|
22
|
+
width: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Split text into grapheme clusters. Falls back to code points when
|
|
26
|
+
* Intl.Segmenter is unavailable; the fallback still keeps surrogate pairs
|
|
27
|
+
* (emoji) atomic so the cursor can never split one.
|
|
28
|
+
*/
|
|
29
|
+
export declare function splitGraphemes(text: string): readonly GraphemeSpan[];
|
|
30
|
+
/** Clamp a cursor offset to the nearest grapheme boundary (surrogates, ZWJ, marks stay whole). */
|
|
31
|
+
export declare function clampCursor(value: string, offset: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* Delete the final grapheme cluster (append-only drafts without a cursor).
|
|
34
|
+
* Surrogate pairs and multi-codepoint emoji stay whole instead of leaving a
|
|
35
|
+
* lone trailing code unit behind.
|
|
36
|
+
*/
|
|
37
|
+
export declare function deleteLastGrapheme(text: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Step the cursor by whole graphemes (negative steps left). The cursor is
|
|
40
|
+
* assumed to sit on a boundary; any drift is clamped first.
|
|
41
|
+
*/
|
|
42
|
+
export declare function moveCursorBy(value: string, offset: number, delta: number): number;
|
|
43
|
+
/**
|
|
44
|
+
* Normalize text entering the draft: CRLF/CR become LF, tabs become two
|
|
45
|
+
* spaces (terminal tab stops are contextual and cannot join a deterministic
|
|
46
|
+
* row budget), and every other C0 control byte plus DEL is REMOVED — the
|
|
47
|
+
* draft is data, so a stray ESC (Windows Terminal file drops) disappears
|
|
48
|
+
* instead of rendering as literal backslash-x-1-b text. Newlines survive.
|
|
49
|
+
*/
|
|
50
|
+
export declare function sanitizeDraftText(text: string): string;
|
|
51
|
+
/** One physical editor row: wrapped text plus its boundary map. */
|
|
52
|
+
export interface EditorRowModel {
|
|
53
|
+
/** Display text of the row (never contains `\n`; sanitized upstream). */
|
|
54
|
+
readonly text: string;
|
|
55
|
+
/** Source offset of the first grapheme on the row. */
|
|
56
|
+
readonly start: number;
|
|
57
|
+
/** Source offset just past the last grapheme on the row (before its newline). */
|
|
58
|
+
readonly end: number;
|
|
59
|
+
/** Boundary offsets on the row, start to end inclusive. */
|
|
60
|
+
readonly offsets: readonly number[];
|
|
61
|
+
/** Display column of each boundary; `columns[i]` pairs with `offsets[i]`. */
|
|
62
|
+
readonly columns: readonly number[];
|
|
63
|
+
/** Code-unit cut in `text` at each boundary; `cuts[i]` pairs with `offsets[i]`. */
|
|
64
|
+
readonly cuts: readonly number[];
|
|
65
|
+
}
|
|
66
|
+
/** The wrapped physical-row model of one draft. */
|
|
67
|
+
export interface EditorModel {
|
|
68
|
+
readonly rows: readonly EditorRowModel[];
|
|
69
|
+
readonly length: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Hard-wrap the draft into column-safe physical rows. Wide graphemes never
|
|
73
|
+
* split across rows (a grapheme that does not fit flushes the row first) and
|
|
74
|
+
* explicit newlines end their row without occupying a cell.
|
|
75
|
+
*/
|
|
76
|
+
export declare function editorModel(value: string, columns: number): EditorModel;
|
|
77
|
+
/** Where a cursor offset renders: the physical row and its display column. */
|
|
78
|
+
export interface CaretSite {
|
|
79
|
+
row: number;
|
|
80
|
+
column: number;
|
|
81
|
+
}
|
|
82
|
+
/** Map a cursor offset to its caret site on the wrapped rows. */
|
|
83
|
+
export declare function caretSite(model: EditorModel, offset: number): CaretSite;
|
|
84
|
+
/**
|
|
85
|
+
* Move the caret across physical rows keeping a preferred display column
|
|
86
|
+
* (Codex `preferred_col`): horizontal moves reset the preference, vertical
|
|
87
|
+
* moves reuse it, clamped to each row's width.
|
|
88
|
+
*/
|
|
89
|
+
export declare function moveCursorVertically(model: EditorModel, offset: number, preferredColumn: number, delta: number): number;
|
|
90
|
+
/** The start/end offsets of the logical line containing the cursor. */
|
|
91
|
+
export declare function lineBounds(value: string, offset: number): {
|
|
92
|
+
start: number;
|
|
93
|
+
end: number;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Codex `beginning_of_previous_word`: skip whitespace left, then land on the
|
|
97
|
+
* START of the trailing non-space piece (extending over separator pieces).
|
|
98
|
+
*/
|
|
99
|
+
export declare function moveWordLeft(value: string, offset: number): number;
|
|
100
|
+
/**
|
|
101
|
+
* Codex `end_of_next_word`: skip whitespace right, then land on the END of
|
|
102
|
+
* the leading non-space piece (extending over separator pieces).
|
|
103
|
+
*/
|
|
104
|
+
export declare function moveWordRight(value: string, offset: number): number;
|
|
105
|
+
/** One edit outcome: the next draft value, cursor, and killed span (if any). */
|
|
106
|
+
export interface EditResult {
|
|
107
|
+
value: string;
|
|
108
|
+
cursor: number;
|
|
109
|
+
/** Text removed into the kill buffer; undefined when nothing was killed. */
|
|
110
|
+
killed: string | undefined;
|
|
111
|
+
}
|
|
112
|
+
/** Delete the grapheme cluster before the cursor. */
|
|
113
|
+
export declare function deleteBackward(value: string, cursor: number): EditResult;
|
|
114
|
+
/** Delete the grapheme cluster at the cursor. */
|
|
115
|
+
export declare function deleteForward(value: string, cursor: number): EditResult;
|
|
116
|
+
/** Delete back to the start of the previous word (fills the kill buffer). */
|
|
117
|
+
export declare function deleteWordBackward(value: string, cursor: number): EditResult;
|
|
118
|
+
/** Delete forward to the end of the next word (fills the kill buffer). */
|
|
119
|
+
export declare function deleteWordForward(value: string, cursor: number): EditResult;
|
|
120
|
+
/** Ctrl+U: kill from the line start to the cursor; at BOL, kill the newline. */
|
|
121
|
+
export declare function killToLineStart(value: string, cursor: number): EditResult;
|
|
122
|
+
/** Ctrl+K: kill from the cursor to the line end; at EOL, kill the newline. */
|
|
123
|
+
export declare function killToLineEnd(value: string, cursor: number): EditResult;
|
|
124
|
+
/** Insert sanitized text at the cursor. */
|
|
125
|
+
export declare function insertText(value: string, cursor: number, text: string): EditResult;
|
|
126
|
+
/**
|
|
127
|
+
* Composer editor row budget: the editor itself never grows past this many
|
|
128
|
+
* physical rows; deeper drafts scroll internally to keep the caret visible.
|
|
129
|
+
* Short terminals collapse toward one row so the live transcript keeps room.
|
|
130
|
+
*/
|
|
131
|
+
export declare function composerMaxRows(terminalRows: number): number;
|
|
132
|
+
/**
|
|
133
|
+
* Codex `should_handle_navigation`: Up/Down walk history only from an empty
|
|
134
|
+
* draft, or from a boundary of a draft that still exactly matches the last
|
|
135
|
+
* recalled entry. Any interior cursor position keeps vertical caret movement.
|
|
136
|
+
*/
|
|
137
|
+
export declare function shouldRecallNavigate(value: string, cursor: number, lastRecalled: string | null): boolean;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module @deepseek-ai/dsh-code/render/export
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type TranscriptView } from './projection.ts';
|
|
9
9
|
/**
|
|
10
10
|
* Render the transcript as a standalone markdown document.
|
|
11
11
|
* @param view - the folded transcript view to export.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Width-safe styled physical rows for bounded terminal panels. */
|
|
2
|
-
import type
|
|
2
|
+
import { type TranscriptEntry } from './projection.ts';
|
|
3
3
|
import { type MdStyle } from './markdown.ts';
|
|
4
4
|
/** Presentation classes mapped to Ink colors by the app boundary. */
|
|
5
5
|
export type LineStyle = MdStyle | 'brand' | 'success' | 'error' | 'warn' | 'dimItalic';
|
|
@@ -33,5 +33,9 @@ export declare function reasoningLines(text: string, columns: number): readonly
|
|
|
33
33
|
/**
|
|
34
34
|
* Convert one durable transcript entry to its complete scrollable row model.
|
|
35
35
|
* The source entry stays intact; only the caller's visible slice is rendered.
|
|
36
|
+
* Wrapped continuations keep a hanging indent aligned under each row's
|
|
37
|
+
* content (Codex history-cell alignment) instead of resetting to column 0.
|
|
36
38
|
*/
|
|
37
|
-
export declare function transcriptEntryLines(entry: TranscriptEntry, columns: number): readonly StyledLine[];
|
|
39
|
+
export declare function transcriptEntryLines(entry: TranscriptEntry, columns: number, showReasoning?: boolean, reasoningToggleHint?: boolean): readonly StyledLine[];
|
|
40
|
+
/** Settled-history variant carrying the Ctrl+R reasoning fold. */
|
|
41
|
+
export declare function settledEntryLines(entry: TranscriptEntry, columns: number, showReasoning: boolean): readonly StyledLine[];
|
|
@@ -24,4 +24,6 @@ export interface MdLine {
|
|
|
24
24
|
/** Visible width of a run in columns (CJK counts double). */
|
|
25
25
|
export declare function visibleColumns(text: string): number;
|
|
26
26
|
/** Render markdown text into styled lines of at most `width` columns. */
|
|
27
|
-
export declare function renderMarkdown(text: string, width: number
|
|
27
|
+
export declare function renderMarkdown(text: string, width: number, options?: {
|
|
28
|
+
physicalWrap?: boolean;
|
|
29
|
+
}): readonly MdLine[];
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module @deepseek-ai/dsh-tui/render/projection
|
|
8
8
|
*/
|
|
9
|
-
import { type MessageId } from '@deepseek-ai/dsh-llm';
|
|
9
|
+
import { type ImageBlock, type MessageId } from '@deepseek-ai/dsh-llm';
|
|
10
10
|
import type { SessionEvent, TodoItem } from '@deepseek-ai/dsh-session';
|
|
11
11
|
import { type ToolDetail } from './tool-detail.ts';
|
|
12
12
|
/** One user prompt line. */
|
|
@@ -17,6 +17,8 @@ export interface UserEntry {
|
|
|
17
17
|
/** True for collapsed injected context (plugin/continuation notices), which
|
|
18
18
|
* the renderer marks with a dim ↳ instead of the user ❯ prompt. */
|
|
19
19
|
notice: boolean;
|
|
20
|
+
/** Durable image references carried by this prompt. */
|
|
21
|
+
images?: readonly ImageBlock['attachment'][];
|
|
20
22
|
}
|
|
21
23
|
/** One user message waiting in the agent inbox (the web's queued-message row). */
|
|
22
24
|
export interface PendingEntry {
|
|
@@ -27,20 +29,32 @@ export interface PendingEntry {
|
|
|
27
29
|
target: 'next-turn' | 'next-step';
|
|
28
30
|
/** Full message text — Codex PendingSteer renders queued prompts exactly like user rows. */
|
|
29
31
|
text: string;
|
|
32
|
+
/** Durable image references queued with this prompt. */
|
|
33
|
+
images?: readonly ImageBlock['attachment'][];
|
|
30
34
|
}
|
|
31
|
-
/** One assembled assistant reply. */
|
|
35
|
+
/** One authoritative assembled assistant reply. */
|
|
32
36
|
export interface AssistantEntry {
|
|
33
37
|
kind: 'assistant';
|
|
34
38
|
/** Joined text blocks of the assistant message. */
|
|
35
39
|
text: string;
|
|
36
|
-
/** Joined reasoning blocks
|
|
40
|
+
/** Joined reasoning blocks from the same assembled message. */
|
|
37
41
|
reasoning: string;
|
|
42
|
+
/** True when a cancelled stream's delivered prefix was finalized as this
|
|
43
|
+
* entry (rc.8 `assistant/message.interrupted`) — rendered with a marker. */
|
|
44
|
+
interrupted?: true;
|
|
38
45
|
}
|
|
39
46
|
/** One model-requested tool invocation and its settled state. */
|
|
40
47
|
export interface ToolEntry {
|
|
41
48
|
kind: 'tool';
|
|
42
49
|
/** Correlation id shared with the matching `tool/result`. */
|
|
43
50
|
callId: string;
|
|
51
|
+
/**
|
|
52
|
+
* Global tool-call ordinal across the whole transcript (1, 2, 3…, never
|
|
53
|
+
* reset between turns). The tool-card badge and every error line that
|
|
54
|
+
* references the failed call share this number, so "call N" in an error
|
|
55
|
+
* always names the exact card the badge shows.
|
|
56
|
+
*/
|
|
57
|
+
ordinal: number;
|
|
44
58
|
/** Tool name as the model addressed it. */
|
|
45
59
|
name: string;
|
|
46
60
|
/** Raw arguments JSON string exactly as the model produced it. */
|
|
@@ -203,6 +217,12 @@ export interface TranscriptView {
|
|
|
203
217
|
streamingReasoning: string;
|
|
204
218
|
/** Latest whole-list todo snapshot from `todo/write`, empty when none. */
|
|
205
219
|
todos: readonly TodoItem[];
|
|
220
|
+
/**
|
|
221
|
+
* Global tool-call ordinal counter: the number the NEXT `tool/call` lands
|
|
222
|
+
* with (1-based). Never reset, so the counter and the badges/error lines
|
|
223
|
+
* stay consistent across turns and resumed sessions.
|
|
224
|
+
*/
|
|
225
|
+
toolCallOrdinal: number;
|
|
206
226
|
/** True while a durable turn is open (`turn/start` … `turn/end`). */
|
|
207
227
|
busy: boolean;
|
|
208
228
|
/** `turn/start` time of the open turn (0 while idle) — the web TurnStatus clock anchor. */
|
|
@@ -254,6 +274,10 @@ export interface TranscriptView {
|
|
|
254
274
|
turnTools: Map<number, Set<string>>;
|
|
255
275
|
};
|
|
256
276
|
}
|
|
277
|
+
/** Human-readable bounded image labels for transcript, inspector, and export surfaces. */
|
|
278
|
+
export declare function imageLabels(images: readonly ImageBlock['attachment'][] | undefined): string;
|
|
279
|
+
/** Prompt text with its durable image labels, without exposing local paths or bytes. */
|
|
280
|
+
export declare function promptDisplayText(entry: Pick<UserEntry | PendingEntry, 'text' | 'images'>): string;
|
|
257
281
|
/** A fresh, empty transcript view. */
|
|
258
282
|
export declare function createTranscriptView(): TranscriptView;
|
|
259
283
|
/**
|
|
@@ -302,6 +326,8 @@ export interface ReplayAccumulator {
|
|
|
302
326
|
streaming: string;
|
|
303
327
|
streamingReasoning: string;
|
|
304
328
|
todos: readonly TodoItem[];
|
|
329
|
+
/** Global tool-call ordinal counter (see `TranscriptView.toolCallOrdinal`). */
|
|
330
|
+
toolCallOrdinal: number;
|
|
305
331
|
busy: boolean;
|
|
306
332
|
busySince: number;
|
|
307
333
|
model: string;
|
|
@@ -23,13 +23,6 @@ export declare function formatTokens(n: number): string;
|
|
|
23
23
|
* @returns display string.
|
|
24
24
|
*/
|
|
25
25
|
export declare function formatDuration(ms: number): string;
|
|
26
|
-
/**
|
|
27
|
-
* Compact decode rate: one decimal under a hundred, whole below a thousand,
|
|
28
|
-
* then thousands (15.3 / 124 / 1.2K).
|
|
29
|
-
* @param n - tokens per second.
|
|
30
|
-
* @returns display string.
|
|
31
|
-
*/
|
|
32
|
-
export declare function formatRate(n: number): string;
|
|
33
26
|
/**
|
|
34
27
|
* Cache-hit share of billed prompt-side input.
|
|
35
28
|
* @param usage - cumulative token totals.
|
|
@@ -80,13 +73,12 @@ export declare const STATUS_ITEM_SEPARATOR = " \u00B7 ";
|
|
|
80
73
|
export declare const STATUS_CYCLE_HINT = " (shift+tab to cycle)";
|
|
81
74
|
/**
|
|
82
75
|
* Interior columns of the segmented context bar (content-type segments plus
|
|
83
|
-
* the free tail whose right edge carries the usage readout).
|
|
84
|
-
*
|
|
85
|
-
*
|
|
76
|
+
* the free tail whose right edge carries the usage readout). The layout
|
|
77
|
+
* starts every bar at this width so the drop ladder can pre-measure the
|
|
78
|
+
* group, then shrinks the bar inside a tighter budget before dropping it
|
|
79
|
+
* (see CONTEXT_MIN_WIDTH) rather than asking the layout for more room.
|
|
86
80
|
*/
|
|
87
81
|
export declare const CONTEXT_BAR_WIDTH = 24;
|
|
88
|
-
/** Occupancy at which the usage readout flips from brand blue to amber. */
|
|
89
|
-
export declare const CONTEXT_WARN_PERCENT = 90;
|
|
90
82
|
/**
|
|
91
83
|
* Render context occupancy as ONE stepless bar: a solid DeepSeek-blue fill
|
|
92
84
|
* run, a dim dotted free track, and the usage readout riding the track's
|
|
@@ -193,4 +185,5 @@ export declare function permissionTone(permission: string): StatusTone;
|
|
|
193
185
|
export declare function layoutStatusBar(facts: StatusFacts, stats: TranscriptStats, columns: number, options?: {
|
|
194
186
|
busy?: boolean;
|
|
195
187
|
items?: readonly string[];
|
|
188
|
+
contextWidth?: number;
|
|
196
189
|
}): StatusLayout;
|
|
@@ -50,10 +50,8 @@ export interface SessionRow {
|
|
|
50
50
|
readonly preset: string;
|
|
51
51
|
readonly title?: string;
|
|
52
52
|
}
|
|
53
|
-
/** True
|
|
53
|
+
/** True only for delegated subagents; ordinary forks also carry lineage. */
|
|
54
54
|
export declare function isSubagentSession(header: SessionHeader): boolean;
|
|
55
|
-
/** Platform-consistent path equality for session cwd comparisons. */
|
|
56
|
-
export declare function samePath(left: string | undefined, right: string): boolean;
|
|
57
55
|
/**
|
|
58
56
|
* Unique header match by exact id or unique id prefix (root and subagent
|
|
59
57
|
* headers alike); the caller applies any lineage gate.
|
package/lib/types/startup.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The interactive terminal app's command-line provider: parses `--resume`,
|
|
3
|
-
* `--continue`, `--session`, `--mode`, `--theme`,
|
|
3
|
+
* `--continue`, `--session`, `--mode`, `--theme`, `--image`, an optional
|
|
4
|
+
* initial prompt, and `--help`, then
|
|
4
5
|
* publishes {@link TUI_STARTUP_SERVICE} for the runner to consume lazily.
|
|
5
6
|
* Follows the headless bundle's startup shape (a commander action publishing
|
|
6
7
|
* a service through {@link parseCmdline}).
|
|
@@ -25,32 +26,33 @@ import { type ThemeName } from './theme.ts';
|
|
|
25
26
|
export declare const name = "tui-startup";
|
|
26
27
|
/** Services required before the invocation can be resolved. */
|
|
27
28
|
export declare const inject: string[];
|
|
28
|
-
/** Service provided by this plugin and injected by the terminal runner. */
|
|
29
|
-
export declare const TUI_STARTUP_SERVICE = "tuiStartup";
|
|
30
29
|
/** How the runner obtains its session identity. */
|
|
31
|
-
export type TuiStartup = {
|
|
30
|
+
export type TuiStartup = ({
|
|
32
31
|
readonly kind: 'fresh';
|
|
33
32
|
readonly mode?: string;
|
|
34
|
-
|
|
35
|
-
} | {
|
|
33
|
+
} & TuiStartupInput) | ({
|
|
36
34
|
readonly kind: 'named';
|
|
37
35
|
readonly sessionId: string;
|
|
38
36
|
readonly mode?: string;
|
|
39
|
-
|
|
40
|
-
} | {
|
|
37
|
+
} & TuiStartupInput) | ({
|
|
41
38
|
readonly kind: 'resume';
|
|
42
39
|
readonly sessionId: string;
|
|
43
|
-
|
|
44
|
-
} | {
|
|
40
|
+
} & TuiStartupInput) | ({
|
|
45
41
|
readonly kind: 'latest';
|
|
42
|
+
} & TuiStartupInput);
|
|
43
|
+
interface TuiStartupInput {
|
|
46
44
|
readonly theme?: ThemeName;
|
|
47
|
-
|
|
45
|
+
readonly prompt?: string;
|
|
46
|
+
readonly images?: readonly string[];
|
|
47
|
+
}
|
|
48
48
|
export interface TuiStartupOptions {
|
|
49
49
|
readonly resume?: string;
|
|
50
50
|
readonly continue?: boolean;
|
|
51
51
|
readonly session?: string;
|
|
52
52
|
readonly mode?: string;
|
|
53
53
|
readonly theme?: ThemeName;
|
|
54
|
+
readonly prompt?: string;
|
|
55
|
+
readonly images?: readonly string[];
|
|
54
56
|
}
|
|
55
57
|
/** Pure option policy shared by Commander and tests. */
|
|
56
58
|
export declare function resolveTuiStartup(options: TuiStartupOptions): TuiStartup;
|
|
@@ -60,3 +62,4 @@ export declare function resolveTuiStartup(options: TuiStartupOptions): TuiStartu
|
|
|
60
62
|
* @param ctx - plugin context carrying the command line and exit request.
|
|
61
63
|
*/
|
|
62
64
|
export declare function apply(ctx: Context): void;
|
|
65
|
+
export {};
|
package/lib/types/store.d.ts
CHANGED
|
@@ -5,15 +5,17 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Notification coalescing: the fold stays synchronous — `getView()` always
|
|
7
7
|
* returns the latest state the moment `apply` returns — but listener
|
|
8
|
-
* notification is
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
8
|
+
* notification is frame-throttled (~16ms) and deduplicated. The zai/GLM
|
|
9
|
+
* adapter delivers tokens as a sustained stream of sub-millisecond,
|
|
10
|
+
* microtask-spaced bursts: per-burst notification renders at microtask
|
|
11
|
+
* cadence, which chained SyncLane `useSyncExternalStore` rerenders past
|
|
12
|
+
* React's nested-update limit ("Maximum update depth exceeded"), while a
|
|
13
|
+
* bare `setImmediate` merges a whole macrotask turn's bursts into one
|
|
14
|
+
* chunky repaint (streaming text visibly staggers). The frame budget gives
|
|
15
|
+
* both: an event ≥16ms after the last paint notifies via `setImmediate`
|
|
16
|
+
* (sub-millisecond latency for sparse/first tokens), and anything denser
|
|
17
|
+
* defers to the next 16ms boundary — a 60fps render cap that also breaks
|
|
18
|
+
* the nesting chain by construction.
|
|
17
19
|
*
|
|
18
20
|
* @module @deepseek-ai/dsh-tui/store
|
|
19
21
|
*/
|
package/lib/types/subagents.d.ts
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* running state, bounded last-activity text), capped at
|
|
10
10
|
* {@link MAX_SUBAGENT_ROWS}. Rows are advisory display state, rebuilt from
|
|
11
11
|
* live events; nothing here persists or replays. Notification is coalesced
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* by the same ~16ms frame throttle as the transcript store (per-burst
|
|
13
|
+
* microtask notify chained SyncLane rerenders past React's nested update
|
|
14
|
+
* limit; a bare macrotask merge repaints a whole turn's bursts at once).
|
|
15
15
|
*
|
|
16
16
|
* @module @deepseek-ai/dsh-code/subagents
|
|
17
17
|
*/
|
package/lib/types/theme.d.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
/** One RGB triple for a palette token. */
|
|
18
18
|
export type RgbTriple = readonly [number, number, number];
|
|
19
19
|
/** Palette token keys shared by every theme. */
|
|
20
|
-
export type ThemeToken = 'brand' | 'brandBright' | 'brandMid' | 'brandDeep' | 'dim' | 'success' | 'error' | 'warn' | 'text' | 'code';
|
|
20
|
+
export type ThemeToken = 'brand' | 'brandBright' | 'brandMid' | 'brandDeep' | 'dim' | 'success' | 'error' | 'warn' | 'text' | 'code' | 'composerBand';
|
|
21
21
|
/** One full color palette: every token key mapped to an RGB triple. */
|
|
22
22
|
export type ThemePalette = Readonly<Record<ThemeToken, RgbTriple>>;
|
|
23
23
|
/** Selectable theme names: dark, light, or auto (terminal-sensed). */
|
|
@@ -50,6 +50,8 @@ export declare const DARK_PALETTE: {
|
|
|
50
50
|
readonly text: readonly [236, 240, 246];
|
|
51
51
|
/** Inline/fenced code — soft sky blue, distinct from brand accents. */
|
|
52
52
|
readonly code: readonly [125, 211, 252];
|
|
53
|
+
/** Composer three-row band base — neutral light gray, hue-free so wave tints read on it. */
|
|
54
|
+
readonly composerBand: readonly [46, 48, 52];
|
|
53
55
|
};
|
|
54
56
|
/**
|
|
55
57
|
* Light palette tuned for white terminals: the same token keys as dark with
|
|
@@ -78,6 +80,8 @@ export declare const LIGHT_PALETTE: {
|
|
|
78
80
|
readonly text: readonly [21, 21, 23];
|
|
79
81
|
/** Inline/fenced code — Tailwind cyan-700, distinct from brand accents. */
|
|
80
82
|
readonly code: readonly [14, 116, 144];
|
|
83
|
+
/** Composer three-row band base — neutral light gray, hue-free so wave tints read on it. */
|
|
84
|
+
readonly composerBand: readonly [229, 231, 235];
|
|
81
85
|
};
|
|
82
86
|
/** Every palette by theme name; auto resolves through {@link resolveTheme}. */
|
|
83
87
|
export declare const PALETTES: {
|
|
@@ -102,6 +106,8 @@ export declare const PALETTES: {
|
|
|
102
106
|
readonly text: readonly [236, 240, 246];
|
|
103
107
|
/** Inline/fenced code — soft sky blue, distinct from brand accents. */
|
|
104
108
|
readonly code: readonly [125, 211, 252];
|
|
109
|
+
/** Composer three-row band base — neutral light gray, hue-free so wave tints read on it. */
|
|
110
|
+
readonly composerBand: readonly [46, 48, 52];
|
|
105
111
|
};
|
|
106
112
|
readonly light: {
|
|
107
113
|
/** Primary brand blue — unchanged, ≈4.9:1 AA on white. */
|
|
@@ -124,6 +130,8 @@ export declare const PALETTES: {
|
|
|
124
130
|
readonly text: readonly [21, 21, 23];
|
|
125
131
|
/** Inline/fenced code — Tailwind cyan-700, distinct from brand accents. */
|
|
126
132
|
readonly code: readonly [14, 116, 144];
|
|
133
|
+
/** Composer three-row band base — neutral light gray, hue-free so wave tints read on it. */
|
|
134
|
+
readonly composerBand: readonly [229, 231, 235];
|
|
127
135
|
};
|
|
128
136
|
};
|
|
129
137
|
/**
|
|
@@ -131,6 +139,9 @@ export declare const PALETTES: {
|
|
|
131
139
|
* two-palette switch keep compiling and painting identically (the default
|
|
132
140
|
* theme IS dark). New code should read the active palette through
|
|
133
141
|
* {@link getPalette} so a theme switch reaches it.
|
|
142
|
+
*
|
|
143
|
+
* @deprecated Read the active palette through {@link getPalette}; this
|
|
144
|
+
* compatibility alias is removed in the next minor release.
|
|
134
145
|
*/
|
|
135
146
|
export declare const TUI_RGB: {
|
|
136
147
|
/** Primary brand blue — `--dsw-static-deepseek-500`. */
|
|
@@ -153,6 +164,8 @@ export declare const TUI_RGB: {
|
|
|
153
164
|
readonly text: readonly [236, 240, 246];
|
|
154
165
|
/** Inline/fenced code — soft sky blue, distinct from brand accents. */
|
|
155
166
|
readonly code: readonly [125, 211, 252];
|
|
167
|
+
/** Composer three-row band base — neutral light gray, hue-free so wave tints read on it. */
|
|
168
|
+
readonly composerBand: readonly [46, 48, 52];
|
|
156
169
|
};
|
|
157
170
|
/**
|
|
158
171
|
* Resolve a theme name to the palette actually in use. `auto` detection
|
package/lib/types/version.d.ts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
/** Installed dsh-code version exposed by the terminal header. */
|
|
2
|
-
/** Read one package manifest version without making terminal startup depend on it. */
|
|
3
|
-
export declare function readPackageVersion(manifest?: import("url").URL): string;
|
|
4
2
|
/** Version of the installed dsh-code package. */
|
|
5
3
|
export declare const DSH_CODE_VERSION: string;
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the running dsh CLI host's version from its entry file
|
|
6
|
+
* (`process.argv[1]`, e.g. `.../@deepseek-ai/dsh/lib/bin.js`). Only a manifest
|
|
7
|
+
* literally named `@deepseek-ai/dsh` counts, so an unrelated entry (vitest, a
|
|
8
|
+
* plain node script) resolves to undefined instead of faking a kernel version.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveDshHostVersion(entry?: string | undefined): string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* The dsh kernel version the TUI runs on, memoized after the first probe: the
|
|
13
|
+
* host process never changes within a run, and the header reads this on every
|
|
14
|
+
* Static replay.
|
|
15
|
+
*/
|
|
16
|
+
export declare function dshKernelVersion(): string | undefined;
|
|
17
|
+
/** Test-only: forget the memoized kernel version so a new argv can be probed. */
|
|
18
|
+
export declare function _resetDshKernelVersionForTests(): void;
|