dsh-code 1.0.6 → 1.2.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 +123 -26
- package/README.md +124 -27
- package/bin/deepseek.mjs +283 -35
- package/cordis.patch.yml +97 -0
- package/lib/index.mjs +5008 -881
- package/lib/session-query.mjs +150 -0
- package/lib/startup.mjs +4 -4
- package/lib/{theme-DCT8Y2xf.mjs → theme-7u5Qo3dF.mjs} +657 -20
- package/lib/types/app.d.ts +106 -62
- package/lib/types/authorization-panel.d.ts +3 -3
- package/lib/types/git-workflow.d.ts +91 -2
- package/lib/types/i18n.d.ts +39 -0
- package/lib/types/index.d.ts +100 -1
- package/lib/types/input-split.d.ts +1 -1
- package/lib/types/kernel-panels.d.ts +107 -29
- package/lib/types/language-panel.d.ts +12 -0
- package/lib/types/locales/en.d.ts +450 -0
- package/lib/types/locales/zh.d.ts +9 -0
- package/lib/types/mentions.d.ts +7 -3
- package/lib/types/models.d.ts +14 -0
- package/lib/types/panel-accent.d.ts +28 -0
- package/lib/types/rainbow.d.ts +69 -0
- package/lib/types/render/animations.d.ts +42 -0
- package/lib/types/render/editor.d.ts +4 -3
- package/lib/types/render/ime-cursor.d.ts +60 -0
- package/lib/types/render/inspector.d.ts +26 -0
- package/lib/types/render/lines.d.ts +21 -1
- package/lib/types/render/markdown.d.ts +1 -1
- package/lib/types/render/projection.d.ts +130 -4
- package/lib/types/render/status.d.ts +9 -9
- package/lib/types/render/text.d.ts +6 -0
- package/lib/types/render/usage.d.ts +113 -0
- package/lib/types/session-directory.d.ts +17 -0
- package/lib/types/session-query.d.ts +92 -0
- package/lib/types/startup.d.ts +1 -1
- package/lib/types/terminal-title.d.ts +66 -0
- package/lib/types/theme-panel.d.ts +2 -2
- package/lib/types/theme.d.ts +271 -52
- package/lib/types/update-panel.d.ts +49 -0
- package/lib/types/update.d.ts +75 -0
- package/lib/types/version.d.ts +4 -3
- package/package.json +246 -90
- package/src/app.ts +1369 -509
- package/src/approval.ts +166 -166
- package/src/authorization-panel.ts +19 -16
- package/src/editor-keys.ts +371 -371
- package/src/git-workflow.ts +229 -3
- package/src/i18n.ts +68 -0
- package/src/index.ts +534 -80
- package/src/input-split.ts +3 -3
- package/src/internals.ts +5 -0
- package/src/kernel-panels.ts +554 -86
- package/src/keyboard.ts +5 -4
- package/src/language-panel.ts +53 -0
- package/src/locales/en.ts +489 -0
- package/src/locales/zh.ts +488 -0
- package/src/mentions.ts +8 -4
- package/src/models.ts +264 -212
- package/src/panel-accent.ts +41 -0
- package/src/presets.ts +1 -1
- package/src/provider-settings.ts +1 -1
- package/src/rainbow.ts +208 -0
- package/src/render/animations.ts +104 -6
- package/src/render/editor.ts +25 -24
- package/src/render/export.ts +116 -95
- package/src/render/ime-cursor.ts +147 -0
- package/src/render/inspector.ts +42 -0
- package/src/render/lines.ts +628 -415
- package/src/render/markdown.ts +15 -3
- package/src/render/projection.ts +572 -21
- package/src/render/status.ts +59 -39
- package/src/render/text.ts +14 -0
- package/src/render/tool-preview.ts +77 -77
- package/src/render/usage.ts +430 -0
- package/src/render/width.ts +2 -2
- package/src/session-directory.ts +8 -6
- package/src/session-query.ts +239 -0
- package/src/startup.ts +3 -3
- package/src/subagents.ts +229 -229
- package/src/terminal-title.ts +190 -0
- package/src/theme-panel.ts +17 -21
- package/src/theme.ts +281 -33
- package/src/update-panel.ts +256 -0
- package/src/update.ts +126 -0
- package/src/version.ts +58 -20
- package/src/whale-glyph.ts +23 -23
|
@@ -54,6 +54,19 @@ export declare function deepDivingGradientColor(index: number, tick: number, gra
|
|
|
54
54
|
export declare function deepDivingSparkIntensity(tick: number): number;
|
|
55
55
|
/** Blue RGB color for the breathing Deep diving sparkle. */
|
|
56
56
|
export declare function deepDivingSparkColor(tick: number, base: RgbTriple, highlight: RgbTriple): RgbTriple;
|
|
57
|
+
/** One full prismatic flow lap — lively: violet → fuchsia → cyan → violet in 2.4s. */
|
|
58
|
+
export declare const FLOW_PERIOD_MS = 2400;
|
|
59
|
+
/**
|
|
60
|
+
* The prismatic flow color at one elapsed-time sample: a smoothstep walk
|
|
61
|
+
* around the anchor triangle, one full lap per {@link FLOW_PERIOD_MS}. Pure —
|
|
62
|
+
* the Ink layer owns the timer and passes its tick scaled by its own cadence
|
|
63
|
+
* (tick × tickMs). Callers gate on the animations preference and fall back to
|
|
64
|
+
* a static palette color when animation is off.
|
|
65
|
+
* @param elapsedMs - milliseconds since the flow started (any sign or size).
|
|
66
|
+
* @param anchors - the colors to walk, in order (theme.ts FLOW_ANCHORS).
|
|
67
|
+
* @returns the interpolated anchor color at this instant.
|
|
68
|
+
*/
|
|
69
|
+
export declare function flowColor(elapsedMs: number, anchors: readonly RgbTriple[]): RgbTriple;
|
|
57
70
|
/** Caret blink cadence: one blink step (on or off) per tick. */
|
|
58
71
|
export declare const CARET_BLINK_TICK_MS = 530;
|
|
59
72
|
/** Caret visibility: half the ticks on, half off (530ms blink). */
|
|
@@ -174,6 +187,35 @@ export declare function easeInOut(progress: number): number;
|
|
|
174
187
|
* @returns the envelope value in 0..1.
|
|
175
188
|
*/
|
|
176
189
|
export declare function envelope(elapsed: number, total: number, fadeIn: number, fadeOut: number): number;
|
|
190
|
+
/**
|
|
191
|
+
* The /rainbow celebration on the three-row composer band: a FIXED
|
|
192
|
+
* seven-color spectrum (not the rolled palette) that slides across every
|
|
193
|
+
* row as one ribbon. Triggered when switching to rainbow or rerolling the
|
|
194
|
+
* seed; independent of RAINBOW_SEED so the burst always reads as a prism.
|
|
195
|
+
*/
|
|
196
|
+
export declare const RAINBOW_BURST_TICK_MS = 33;
|
|
197
|
+
export declare const RAINBOW_BURST_DURATION_MS = 1800;
|
|
198
|
+
export declare const RAINBOW_BURST_HUES: readonly RgbTriple[];
|
|
199
|
+
/**
|
|
200
|
+
* Smoothstep in 0..1, then wrap-lerp around the seven burst hues.
|
|
201
|
+
* Position 0 is red, wrapping back toward red at 1. Shared by the
|
|
202
|
+
* composer burst and the static rainbow whale header.
|
|
203
|
+
*/
|
|
204
|
+
export declare function rainbowSpectrumHue(position: number): RgbTriple;
|
|
205
|
+
/**
|
|
206
|
+
* Background tint for one composer-band cell during the rainbow burst.
|
|
207
|
+
* Every row of a column shares the same hue (a solid ribbon); edge rows
|
|
208
|
+
* are slightly dimmer so the middle editor row reads as the crest. The
|
|
209
|
+
* spectrum slides ~1.2 widths over the burst, then fades to the band base.
|
|
210
|
+
* @param tick - frame index at {@link RAINBOW_BURST_TICK_MS}.
|
|
211
|
+
* @param column - band column (0..width-1).
|
|
212
|
+
* @param width - band width in columns.
|
|
213
|
+
* @param base - the theme's composerBand color to blend toward.
|
|
214
|
+
* @param row - band row (0..rows-1).
|
|
215
|
+
* @param rows - band height (composer is three rows: pad, editor, pad).
|
|
216
|
+
* @returns the blended RGB, or null after the burst (or at zero alpha).
|
|
217
|
+
*/
|
|
218
|
+
export declare function rainbowBurstColumnBg(tick: number, column: number, width: number, base: RgbTriple, row?: number, rows?: number): RgbTriple | null;
|
|
177
219
|
/**
|
|
178
220
|
* The background color for one composer-band column at a tick — Codex
|
|
179
221
|
* `paint_bands` + `Canvas::tint` for all three styles. Bands overlap with a
|
|
@@ -155,8 +155,9 @@ export declare function replaceRangePreservingCursor(value: string, cursor: numb
|
|
|
155
155
|
*/
|
|
156
156
|
export declare function composerMaxRows(terminalRows: number): number;
|
|
157
157
|
/**
|
|
158
|
-
* History navigation starts with Up on an empty draft, or
|
|
159
|
-
*
|
|
160
|
-
*
|
|
158
|
+
* History navigation starts with Up on an empty draft, or continues from an
|
|
159
|
+
* unchanged recalled entry whenever the caret sits on either text edge
|
|
160
|
+
* (start or end) - moving the caret into the interior returns the keys to
|
|
161
|
+
* ordinary editing until an edge is reached again.
|
|
161
162
|
*/
|
|
162
163
|
export declare function shouldRecallNavigate(value: string, cursor: number, lastRecalled: string | null, direction: -1 | 1): boolean;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IME cursor anchoring for the composer.
|
|
3
|
+
*
|
|
4
|
+
* Ink keeps the real terminal cursor hidden and parks it just below the
|
|
5
|
+
* dynamic tree (after the status row). IME composition text and candidate
|
|
6
|
+
* windows anchor to that real cursor cell - VS Code's integrated terminal
|
|
7
|
+
* positions its hidden IME textarea there, and Windows consoles behave the
|
|
8
|
+
* same - so CJK input appeared at the bottom of the screen instead of at the
|
|
9
|
+
* caret. The anchor moves the real cursor onto the caret cell without
|
|
10
|
+
* touching Ink's relative erase ledger:
|
|
11
|
+
*
|
|
12
|
+
* - the displacement is owned: before any foreign write or re-anchor, the
|
|
13
|
+
* wrapper cancels it (cursor down, column 1), so every writer - Ink's
|
|
14
|
+
* log-update rewrites, the resize replay, protocol pushes - keeps seeing
|
|
15
|
+
* the cursor exactly where it was left;
|
|
16
|
+
* - log-update frame chunks (which start with the erase-line sequence) get
|
|
17
|
+
* the anchor re-appended inside the same write, so a repaint can never
|
|
18
|
+
* leave the cursor behind - in particular the caret blink keeps the anchor
|
|
19
|
+
* stable while an IME composition is open, because the terminal parses the
|
|
20
|
+
* rewrite and the re-anchor as one atomic update.
|
|
21
|
+
*
|
|
22
|
+
* @module @deepseek-ai/dsh-code/render/ime-cursor
|
|
23
|
+
*/
|
|
24
|
+
/** Cancel `rows` of owned upward displacement and return to column 1. */
|
|
25
|
+
export declare function imeCursorRestore(rows: number): string;
|
|
26
|
+
/** Move onto the caret cell: `rows` up from Ink's parked row, 0-based column. */
|
|
27
|
+
export declare function imeCursorMove(rows: number, column: number): string;
|
|
28
|
+
/**
|
|
29
|
+
* Rows between the caret cell and Ink's parked cursor row: the band's bottom
|
|
30
|
+
* blank row, the editor window rows below the caret, the status footer, and
|
|
31
|
+
* Ink's own below-frame row. Rows above the composer (gutter, live content)
|
|
32
|
+
* never enter this distance.
|
|
33
|
+
*/
|
|
34
|
+
export declare function imeCursorRowsUp(input: {
|
|
35
|
+
editorWindowRows: number;
|
|
36
|
+
caretRowInWindow: number;
|
|
37
|
+
rowsBelowComposer: number;
|
|
38
|
+
}): number;
|
|
39
|
+
/** The installed anchor handle. */
|
|
40
|
+
export interface ImeCursorAnchor {
|
|
41
|
+
/** Anchor on the caret cell: `rows` above Ink's parked row at the 0-based
|
|
42
|
+
* `column`; `rows <= 0` releases the anchor. */
|
|
43
|
+
anchor(rows: number, column: number): void;
|
|
44
|
+
/** Cancel the displacement, restore the original write path, and detach. */
|
|
45
|
+
release(): void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Take over `stream.write` so the anchor displacement stays invisible to every
|
|
49
|
+
* other writer. Idempotent per stream: a second install returns the live
|
|
50
|
+
* handle. Returns `undefined` on non-TTY streams where anchoring is meaningless.
|
|
51
|
+
*/
|
|
52
|
+
export declare function installImeCursorAnchor(stream: NodeJS.WriteStream): ImeCursorAnchor | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Keep the real terminal cursor on the composer's caret cell while `active`
|
|
55
|
+
* (the editable composer). The second effect runs after every commit without
|
|
56
|
+
* a dep list: frame rewrites restore the anchor themselves, but any other
|
|
57
|
+
* write (protocol push, resize replay) leaves the cursor at Ink's parked
|
|
58
|
+
* position, and the next commit re-anchors it.
|
|
59
|
+
*/
|
|
60
|
+
export declare function useImeCursorAnchor(active: boolean, rows: number, column: number): void;
|
|
@@ -16,6 +16,32 @@ export interface InspectorViewport {
|
|
|
16
16
|
}
|
|
17
17
|
/** One transcript-to-composer gutter, collapsed on short terminals. */
|
|
18
18
|
export declare function layoutGutterRows(rows: number): 0 | 1;
|
|
19
|
+
/** Measured chrome that sits below (or in) the live region. */
|
|
20
|
+
export interface LiveRegionChrome {
|
|
21
|
+
/** Terminal rows. */
|
|
22
|
+
readonly terminalRows: number;
|
|
23
|
+
/** Editor rows inside the composer band (frozen reports 1). */
|
|
24
|
+
readonly composerRows: number;
|
|
25
|
+
/** Status footer rows. */
|
|
26
|
+
readonly statusBarRows: 1 | 2;
|
|
27
|
+
/** Completion menu rows (0 when closed). */
|
|
28
|
+
readonly menuRows: number;
|
|
29
|
+
/** Transcript-to-composer gutter. */
|
|
30
|
+
readonly gutterRows: 0 | 1;
|
|
31
|
+
/** Notice line present. */
|
|
32
|
+
readonly notice: boolean;
|
|
33
|
+
/** Todo summary line present. */
|
|
34
|
+
readonly todo: boolean;
|
|
35
|
+
/** Agents summary line present. */
|
|
36
|
+
readonly agents: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Rows left for live transcript and streaming after pinning the composer and
|
|
40
|
+
* status at the bottom. Variable chrome (menu, notice, todos, agents, extra
|
|
41
|
+
* status row, extra editor rows) is deducted here so those rows cover the
|
|
42
|
+
* live region instead of growing the tree and moving the bottom bar.
|
|
43
|
+
*/
|
|
44
|
+
export declare function liveRegionBudget(chrome: LiveRegionChrome): number;
|
|
19
45
|
/**
|
|
20
46
|
* Keep the inspector plus its persistent status/composer chrome below
|
|
21
47
|
* `stdout.rows`: at equality Ink clears the terminal and rewrites all
|
|
@@ -2,7 +2,7 @@
|
|
|
2
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
|
-
export type LineStyle = MdStyle | 'brand' | 'success' | 'error' | 'warn' | 'dimItalic';
|
|
5
|
+
export type LineStyle = MdStyle | 'brand' | 'success' | 'error' | 'warn' | 'dimItalic' | 'diffAdd' | 'diffDel' | 'promptRow' | 'promptQueuedRow' | 'promptSteeredRow';
|
|
6
6
|
/** One styled run within a physical terminal row. */
|
|
7
7
|
export interface StyledSegment {
|
|
8
8
|
text: string;
|
|
@@ -14,6 +14,18 @@ export interface StyledLine {
|
|
|
14
14
|
}
|
|
15
15
|
/** Construct one segment without leaking mutable objects into cached rows. */
|
|
16
16
|
export declare function lineSegment(text: string, style?: LineStyle): StyledSegment;
|
|
17
|
+
/**
|
|
18
|
+
* Classify one unified-diff row for coloring: additions and deletions carry
|
|
19
|
+
* the diff tint styles (background on rich terminals), hunk headers and file
|
|
20
|
+
* markers stay brand-blue, and everything else is dim context.
|
|
21
|
+
*/
|
|
22
|
+
export declare function diffLineStyle(line: string): LineStyle;
|
|
23
|
+
/**
|
|
24
|
+
* Extend pure diff-tinted rows to the full width with same-styled padding so
|
|
25
|
+
* the tint reads as one unbroken bar (GitHub-style), including wrapped
|
|
26
|
+
* continuation rows; mixed or non-diff rows pass through untouched.
|
|
27
|
+
*/
|
|
28
|
+
export declare function fillDiffLineBars(lines: readonly StyledLine[], columns: number): readonly StyledLine[];
|
|
17
29
|
/**
|
|
18
30
|
* Sanitize and hard-wrap styled content into exact physical rows.
|
|
19
31
|
* Tabs become two visible spaces because terminal tab stops are contextual
|
|
@@ -30,6 +42,14 @@ export declare function markdownLines(text: string, columns: number): readonly S
|
|
|
30
42
|
* reasoning content and assistant Markdown share one left edge.
|
|
31
43
|
*/
|
|
32
44
|
export declare function reasoningLines(text: string, columns: number): readonly StyledLine[];
|
|
45
|
+
/**
|
|
46
|
+
* Style the lines of one user prompt for display: plain verbatim, except
|
|
47
|
+
* inside ```diff / ```patch fences where added and removed lines take the
|
|
48
|
+
* shared diff tints (the review prompt pastes its diff this way, and the
|
|
49
|
+
* user row does not go through the markdown renderer). The fence markers
|
|
50
|
+
* and file headers stay plain.
|
|
51
|
+
*/
|
|
52
|
+
export declare function userPromptSegments(text: string): readonly StyledSegment[];
|
|
33
53
|
/**
|
|
34
54
|
* Convert one durable transcript entry to its complete scrollable row model.
|
|
35
55
|
* The source entry stays intact; only the caller's visible slice is rendered.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @module @deepseek-ai/dsh-code/render/markdown
|
|
10
10
|
*/
|
|
11
11
|
/** Style classes the renderer emits; the app maps them to colors/props. */
|
|
12
|
-
export type MdStyle = 'plain' | 'bold' | 'italic' | 'boldItalic' | 'code' | 'accent' | 'accentBold' | 'dim' | 'strike';
|
|
12
|
+
export type MdStyle = 'plain' | 'bold' | 'italic' | 'boldItalic' | 'code' | 'accent' | 'accentBold' | 'dim' | 'strike' | 'diffAdd' | 'diffDel';
|
|
13
13
|
/** One styled run of text. */
|
|
14
14
|
export interface MdSegment {
|
|
15
15
|
/** Visible text (no ANSI). */
|
|
@@ -23,6 +23,12 @@ export interface UserEntry {
|
|
|
23
23
|
images?: readonly ImageBlock['attachment'][];
|
|
24
24
|
/** Durable file references carried by this prompt (0.1.5 file blocks). */
|
|
25
25
|
files?: readonly FileAttachmentRef[];
|
|
26
|
+
/**
|
|
27
|
+
* How the prompt reached the agent, when it did not arrive as an ordinary
|
|
28
|
+
* submission: `queued` waited for this turn, `steered` joined it mid-flight.
|
|
29
|
+
* Absent for a prompt typed straight into an idle composer.
|
|
30
|
+
*/
|
|
31
|
+
delivery?: 'queued' | 'steered';
|
|
26
32
|
}
|
|
27
33
|
/** One user message waiting in the agent inbox (the web's queued-message row). */
|
|
28
34
|
export interface PendingEntry {
|
|
@@ -79,6 +85,68 @@ export interface ToolEntry {
|
|
|
79
85
|
* result lands and only when something renderable exists.
|
|
80
86
|
*/
|
|
81
87
|
detail: ToolDetail | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Nested PTC sub-dispatches (`run_code`) in start order, bounded to the
|
|
90
|
+
* newest {@link MAX_TOOL_SUB_DISPATCHES} rows.
|
|
91
|
+
*/
|
|
92
|
+
subs: readonly ToolSubDispatch[];
|
|
93
|
+
/** Sub-dispatches evicted from the bounded window. */
|
|
94
|
+
subsDropped: number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* One nested PTC sub-dispatch under a `run_code` parent call: the durable
|
|
98
|
+
* `tool/ptc-dispatch-start`/`tool/ptc-dispatch` pair folded to one bounded
|
|
99
|
+
* row (upstream contract: pair by `subCallId`, every start settles, and the
|
|
100
|
+
* settle carries `tool/result`'s own vocabulary).
|
|
101
|
+
*/
|
|
102
|
+
export interface ToolSubDispatch {
|
|
103
|
+
/** Opaque sub-call id pairing the start with its settle. */
|
|
104
|
+
subCallId: string;
|
|
105
|
+
/** Sub-call tool name. */
|
|
106
|
+
name: string;
|
|
107
|
+
/** Bounded arguments preview. */
|
|
108
|
+
preview: string;
|
|
109
|
+
/** Lifecycle; `running` until the paired settle lands. */
|
|
110
|
+
state: 'running' | 'done' | 'error';
|
|
111
|
+
/** Bounded first text block of the settle content, '' until it lands. */
|
|
112
|
+
summary: string;
|
|
113
|
+
/** Wall-clock duration (settle − start), 0 while running. */
|
|
114
|
+
durationMs: number;
|
|
115
|
+
}
|
|
116
|
+
/** Bounded sub-dispatch window per tool card (display budget only). */
|
|
117
|
+
export declare const MAX_TOOL_SUB_DISPATCHES = 12;
|
|
118
|
+
/** Bounded member window per workflow run card (display budget only). */
|
|
119
|
+
export declare const MAX_WORKFLOW_MEMBERS = 12;
|
|
120
|
+
/** One workflow member (an `agent()` call inside a `workflow` script). */
|
|
121
|
+
export interface WorkflowMember {
|
|
122
|
+
/** Member sequence within the run (the agent-start/agent-end pairing key). */
|
|
123
|
+
seq: number;
|
|
124
|
+
/** Display label. */
|
|
125
|
+
label: string;
|
|
126
|
+
/** Declared phase title, '' when none. */
|
|
127
|
+
phase: string;
|
|
128
|
+
/** Child session id (cross-links the subagent feed's rows). */
|
|
129
|
+
childId: string;
|
|
130
|
+
/** Settlement; `running` until the paired `tool-workflow/agent-end`. */
|
|
131
|
+
outcome: 'running' | 'completed' | 'failed' | 'cancelled';
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* One durable workflow run (the `tool-workflow/*` record a `workflow` or
|
|
135
|
+
* `ralph` tool appends to the parent session): run identity plus its
|
|
136
|
+
* bounded member list, live until `tool-workflow/run-end` settles.
|
|
137
|
+
*/
|
|
138
|
+
export interface WorkflowEntry {
|
|
139
|
+
kind: 'workflow';
|
|
140
|
+
/** Stable run identity shared by every event of the run. */
|
|
141
|
+
runId: string;
|
|
142
|
+
/** Display name of the run. */
|
|
143
|
+
name: string;
|
|
144
|
+
/** Members in sequence order, bounded to the newest window. */
|
|
145
|
+
members: readonly WorkflowMember[];
|
|
146
|
+
/** Members evicted from the bounded window. */
|
|
147
|
+
membersDropped: number;
|
|
148
|
+
/** Run settlement; `running` until `tool-workflow/run-end`. */
|
|
149
|
+
state: 'running' | 'completed' | 'cancelled' | 'error';
|
|
82
150
|
}
|
|
83
151
|
/** One slash-command execution dispatched through `ctx.commands`. */
|
|
84
152
|
export interface CommandEntry {
|
|
@@ -144,7 +212,7 @@ export interface FilesEntry {
|
|
|
144
212
|
paths: readonly string[];
|
|
145
213
|
}
|
|
146
214
|
/** Ordered transcript items the renderer draws. */
|
|
147
|
-
export type TranscriptEntry = UserEntry | PendingEntry | AssistantEntry | ToolEntry | CommandEntry | ErrorEntry | TurnMarkerEntry | CompactionEntry | RetryEntry | FilesEntry;
|
|
215
|
+
export type TranscriptEntry = UserEntry | PendingEntry | AssistantEntry | ToolEntry | CommandEntry | ErrorEntry | TurnMarkerEntry | CompactionEntry | RetryEntry | FilesEntry | WorkflowEntry;
|
|
148
216
|
/** The live goal the status line badges, folded from `goal/change`. */
|
|
149
217
|
export interface GoalFold {
|
|
150
218
|
/** Human-requested completion objective. */
|
|
@@ -157,14 +225,21 @@ export interface GoalFold {
|
|
|
157
225
|
/** Blocked explanation, empty outside the blocked phase. */
|
|
158
226
|
blocked: string;
|
|
159
227
|
}
|
|
160
|
-
/**
|
|
228
|
+
/**
|
|
229
|
+
* Cumulative token accounting folded from `assistant/message` usage reports.
|
|
230
|
+
* The buckets are disjoint and mirror the provider's report, so the prompt
|
|
231
|
+
* side is never double counted: reasoning tokens are already inside
|
|
232
|
+
* `outputTokens`, and cache reads are never folded into the uncached input.
|
|
233
|
+
*/
|
|
161
234
|
export interface UsageTotals {
|
|
162
|
-
/** Prompt-side
|
|
163
|
-
|
|
235
|
+
/** Prompt-side tokens billed outside the cache. */
|
|
236
|
+
uncachedInputTokens: number;
|
|
164
237
|
/** Completion-side tokens over the whole log. */
|
|
165
238
|
outputTokens: number;
|
|
166
239
|
/** Cache-read tokens over the whole log (0 when the adapter reports none). */
|
|
167
240
|
cacheReadTokens: number;
|
|
241
|
+
/** Cache-write tokens over the whole log (0 when the adapter reports none). */
|
|
242
|
+
cacheWriteTokens: number;
|
|
168
243
|
}
|
|
169
244
|
/**
|
|
170
245
|
* Estimated used tokens per context content type, folded from transcript
|
|
@@ -219,6 +294,38 @@ export interface TranscriptStats {
|
|
|
219
294
|
*/
|
|
220
295
|
reasoningEffort: string;
|
|
221
296
|
}
|
|
297
|
+
/** One active reminder folded from durable `schedule/change` events. */
|
|
298
|
+
export interface ScheduleRow {
|
|
299
|
+
readonly id: string;
|
|
300
|
+
readonly kind: 'after' | 'at' | 'every';
|
|
301
|
+
readonly prompt: string;
|
|
302
|
+
/** Next due time (epoch ms); the /schedule panel derives overdue/relative labels. */
|
|
303
|
+
readonly targetAt: number;
|
|
304
|
+
/** Recurrence seconds for 'every' rows, undefined otherwise. */
|
|
305
|
+
readonly everySeconds?: number;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* The durable `schedule/change` payload shape this fold consumes. Upstream
|
|
309
|
+
* strict-decodes the whole transition stream before appending, so unknown
|
|
310
|
+
* ids here are corrupt-input edges that degrade to a no-op.
|
|
311
|
+
*/
|
|
312
|
+
export interface ScheduleChangeLike {
|
|
313
|
+
readonly operation: 'create' | 'delete' | 'dispatch';
|
|
314
|
+
readonly schedule?: {
|
|
315
|
+
readonly id: string;
|
|
316
|
+
readonly kind: 'after' | 'at' | 'every';
|
|
317
|
+
readonly prompt: string;
|
|
318
|
+
readonly afterSeconds?: number;
|
|
319
|
+
readonly everySeconds?: number;
|
|
320
|
+
readonly scheduledAt: string;
|
|
321
|
+
};
|
|
322
|
+
readonly id?: string;
|
|
323
|
+
readonly acceptedAt?: string;
|
|
324
|
+
}
|
|
325
|
+
/** Fold one `schedule/change` into the active-reminder list (create/delete/dispatch). */
|
|
326
|
+
export declare function applyScheduleChange(rows: readonly ScheduleRow[], data: ScheduleChangeLike): readonly ScheduleRow[];
|
|
327
|
+
/** First anchor-aligned target after `acceptedAt`, stepping from the previous aligned target. */
|
|
328
|
+
export declare function nextEveryTarget(previousTarget: number, acceptedAt: number, everySeconds: number): number;
|
|
222
329
|
/** The complete TUI transcript view for one session. */
|
|
223
330
|
export interface TranscriptView {
|
|
224
331
|
/** Settled entries in log order. */
|
|
@@ -265,6 +372,8 @@ export interface TranscriptView {
|
|
|
265
372
|
sandbox: string;
|
|
266
373
|
/** Current long-running goal folded from the last `goal/change`, undefined when cleared. */
|
|
267
374
|
goal: GoalFold | undefined;
|
|
375
|
+
/** Active reminders folded from `schedule/change` events, oldest target first at render. */
|
|
376
|
+
schedules: readonly ScheduleRow[];
|
|
268
377
|
/**
|
|
269
378
|
* Ordered live message ids per inbox target, mirrored from
|
|
270
379
|
* `agent/inbox/spliced` exactly like the upstream Inbox projection — the
|
|
@@ -274,6 +383,14 @@ export interface TranscriptView {
|
|
|
274
383
|
'next-turn': readonly string[];
|
|
275
384
|
'next-step': readonly string[];
|
|
276
385
|
};
|
|
386
|
+
/**
|
|
387
|
+
* In-flight inbox messages by the list they were inserted into, kept until
|
|
388
|
+
* the durable user message that claims them lands. The claim itself is a
|
|
389
|
+
* plain splice that empties the pending row first, so this map — not
|
|
390
|
+
* {@link pending} — is what lets a settled prompt say it was queued or
|
|
391
|
+
* steered rather than typed into an idle composer.
|
|
392
|
+
*/
|
|
393
|
+
claimOrigin: ReadonlyMap<string, 'next-turn' | 'next-step'>;
|
|
277
394
|
/**
|
|
278
395
|
* Fold-internal timing anchors, never rendered: open step and tool-call
|
|
279
396
|
* start timestamps the next `assistant/message` / `tool/result` resolves
|
|
@@ -285,6 +402,8 @@ export interface TranscriptView {
|
|
|
285
402
|
readonly anchors: {
|
|
286
403
|
stepStart: Map<string, number>;
|
|
287
404
|
toolStart: Map<string, number>;
|
|
405
|
+
/** Open PTC sub-dispatch starts by `subCallId` (duration anchors). */
|
|
406
|
+
subStart: Map<string, number>;
|
|
288
407
|
firstChunkAt: Map<string, number>;
|
|
289
408
|
compactionTokens: Map<string, number>;
|
|
290
409
|
lastPruneTokens: number;
|
|
@@ -341,11 +460,15 @@ export interface ReplayAccumulator {
|
|
|
341
460
|
retryIndex: Map<string, number[]>;
|
|
342
461
|
/** messageId → every index into `entries` holding a `pending` row with that id. */
|
|
343
462
|
pendingIndex: Map<string, number[]>;
|
|
463
|
+
/** runId → every index into `entries` holding a `workflow` row with that id. */
|
|
464
|
+
workflowIndex: Map<string, number[]>;
|
|
344
465
|
/** Tombstone count; zero means `entries` is already the final array. */
|
|
345
466
|
removedCount: number;
|
|
346
467
|
/** Mutable inbox id lists, mirroring `view.pending` order per target. */
|
|
347
468
|
pendingTurn: string[];
|
|
348
469
|
pendingStep: string[];
|
|
470
|
+
/** Mutable mirror of `view.claimOrigin` (see the reducer's field doc). */
|
|
471
|
+
claimOrigin: Map<string, 'next-turn' | 'next-step'>;
|
|
349
472
|
streaming: string;
|
|
350
473
|
streamingReasoning: string;
|
|
351
474
|
todos: readonly TodoItem[];
|
|
@@ -360,9 +483,12 @@ export interface ReplayAccumulator {
|
|
|
360
483
|
systemPrompt: string;
|
|
361
484
|
sandbox: string;
|
|
362
485
|
goal: GoalFold | undefined;
|
|
486
|
+
schedules: readonly ScheduleRow[];
|
|
363
487
|
stats: TranscriptStats;
|
|
364
488
|
stepStart: Map<string, number>;
|
|
365
489
|
toolStart: Map<string, number>;
|
|
490
|
+
/** Open PTC sub-dispatch starts by `subCallId` (duration anchors). */
|
|
491
|
+
subStart: Map<string, number>;
|
|
366
492
|
firstChunkAt: Map<string, number>;
|
|
367
493
|
compactionTokens: Map<string, number>;
|
|
368
494
|
lastPruneTokens: number;
|
|
@@ -10,13 +10,8 @@
|
|
|
10
10
|
* @module @deepseek-ai/dsh-tui/render/status
|
|
11
11
|
*/
|
|
12
12
|
import type { TranscriptStats } from './projection.ts';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* digits), mirroring the web composer's StatsLine format.
|
|
16
|
-
* @param n - token count.
|
|
17
|
-
* @returns display string.
|
|
18
|
-
*/
|
|
19
|
-
export declare function formatTokens(n: number): string;
|
|
13
|
+
import { formatTokens } from './text.ts';
|
|
14
|
+
export { formatTokens };
|
|
20
15
|
/**
|
|
21
16
|
* Compact duration: 45.2s under a minute, 2m42s from there on.
|
|
22
17
|
* @param ms - duration in milliseconds.
|
|
@@ -24,7 +19,9 @@ export declare function formatTokens(n: number): string;
|
|
|
24
19
|
*/
|
|
25
20
|
export declare function formatDuration(ms: number): string;
|
|
26
21
|
/**
|
|
27
|
-
* Cache-hit share of billed prompt-side input.
|
|
22
|
+
* Cache-hit share of billed prompt-side input. The denominator is the same
|
|
23
|
+
* billed total the /usage panel shows (uncached input plus both cache
|
|
24
|
+
* buckets), so the two readouts can never disagree.
|
|
28
25
|
* @param usage - cumulative token totals.
|
|
29
26
|
* @returns percent rounded to one decimal place, or null when no input was billed.
|
|
30
27
|
*/
|
|
@@ -33,7 +30,7 @@ export declare function cacheHitPercent(usage: TranscriptStats['usage']): number
|
|
|
33
30
|
* Presentation tones for status spans; the footer maps each to a theme color
|
|
34
31
|
* (Codex status-line accents: model/path/branch/state/usage categories).
|
|
35
32
|
*/
|
|
36
|
-
export type StatusTone = 'model' | 'live' | 'path' | 'branch' | 'value' | 'label' | 'meta' | 'accent' | 'success' | 'warn' | 'error' | 'ctxFill';
|
|
33
|
+
export type StatusTone = 'model' | 'live' | 'path' | 'branch' | 'value' | 'label' | 'meta' | 'accent' | 'success' | 'plan' | 'warn' | 'error' | 'ctxFill';
|
|
37
34
|
/** One colored run inside the status bar. */
|
|
38
35
|
export interface StatusSpan {
|
|
39
36
|
text: string;
|
|
@@ -70,7 +67,10 @@ export declare const STATUS_GROUP_SEPARATOR = " | ";
|
|
|
70
67
|
/** Separator between trailing state spans. */
|
|
71
68
|
export declare const STATUS_ITEM_SEPARATOR = " \u00B7 ";
|
|
72
69
|
/** The Codex-style mode cycle hint appended to the permission badge. */
|
|
70
|
+
/** English compatibility value for callers that only measure the default layout. */
|
|
73
71
|
export declare const STATUS_CYCLE_HINT = " (shift+tab to cycle)";
|
|
72
|
+
/** Localized mode-cycle hint used by the live layout. */
|
|
73
|
+
export declare function statusCycleHint(): string;
|
|
74
74
|
/**
|
|
75
75
|
* Interior columns of the context bar. The layout starts every bar at this
|
|
76
76
|
* width so the drop ladder can pre-measure the group, then degrades the
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module @deepseek-ai/dsh-code/render/text
|
|
13
13
|
*/
|
|
14
|
+
/**
|
|
15
|
+
* Compact token count: exact below 1K, then one-decimal-ish K/M.
|
|
16
|
+
* @param n - token count.
|
|
17
|
+
* @returns display string.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatTokens(n: number): string;
|
|
14
20
|
/**
|
|
15
21
|
* Escape control and deceptive characters so externally sourced text cannot
|
|
16
22
|
* drive the terminal. C0/C1/DEL render as a literal `\xNN` escape; bidi,
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session usage for the /usage panel: the provider-reported token totals, the
|
|
3
|
+
* context pressure and composition, and the exact per-turn accounting, folded
|
|
4
|
+
* into the styled rows the panel draws.
|
|
5
|
+
*
|
|
6
|
+
* Every figure comes from the harness token meter. The four token buckets are
|
|
7
|
+
* disjoint, so the prompt side is never double counted; the composition block
|
|
8
|
+
* is a density estimate and is labelled as one.
|
|
9
|
+
*
|
|
10
|
+
* @module @deepseek-ai/dsh-tui/render/usage
|
|
11
|
+
*/
|
|
12
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
13
|
+
import type { TokenUsageProjection, TurnTokenUsage } from '@deepseek-ai/dsh-token-meter/client';
|
|
14
|
+
import { type StyledLine } from './lines.ts';
|
|
15
|
+
/** One completed turn's exact provider-reported accounting. */
|
|
16
|
+
export interface UsageTurn {
|
|
17
|
+
/** Durable turn number (`turn/start`). */
|
|
18
|
+
readonly turn: number;
|
|
19
|
+
readonly usage: TurnTokenUsage;
|
|
20
|
+
/**
|
|
21
|
+
* The model that billed this turn, or '' when nothing in the log names one.
|
|
22
|
+
* The meter's own `routes` is preferred; it is absent whenever ONE attempt
|
|
23
|
+
* went unattributed, so the turn's own assistant messages answer instead.
|
|
24
|
+
*/
|
|
25
|
+
readonly model: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Everything the panel reads. The totals come from the mounted projection and
|
|
29
|
+
* the per-turn rows from the meter's own fold; a missing projection renders as
|
|
30
|
+
* explicitly unavailable rather than as zeros, because an unmounted deployment
|
|
31
|
+
* and a session with no traffic are different facts.
|
|
32
|
+
*/
|
|
33
|
+
export interface UsageView {
|
|
34
|
+
/** Provider-reported usage over the whole durable log. */
|
|
35
|
+
readonly totals?: TokenUsageProjection;
|
|
36
|
+
/** Completed turns, oldest first. */
|
|
37
|
+
readonly turns: readonly UsageTurn[];
|
|
38
|
+
}
|
|
39
|
+
/** Prompt-side tokens the provider billed: uncached input plus both cache buckets. */
|
|
40
|
+
export declare function billedInputTokens(totals: TokenUsageProjection): number;
|
|
41
|
+
/** Prompt plus completion tokens over the whole log. */
|
|
42
|
+
export declare function usageTotalTokens(totals: TokenUsageProjection): number;
|
|
43
|
+
/**
|
|
44
|
+
* Cache-hit share of billed prompt-side input.
|
|
45
|
+
* @param totals - cumulative provider-reported buckets.
|
|
46
|
+
* @returns percent rounded to one decimal place, or null when nothing was billed.
|
|
47
|
+
*/
|
|
48
|
+
export declare function usageCacheHitPercent(totals: TokenUsageProjection): number | null;
|
|
49
|
+
/** One complete turn's durable events, in log order. */
|
|
50
|
+
export interface TurnSlice {
|
|
51
|
+
readonly turn: number;
|
|
52
|
+
readonly events: readonly SessionEvent[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Split a durable log into COMPLETE turns. A turn still running has no
|
|
56
|
+
* `turn/end` yet, and an unfinished attempt has no exact accounting, so the
|
|
57
|
+
* trailing slice is dropped rather than guessed at.
|
|
58
|
+
* @param events - the whole durable log, in log order.
|
|
59
|
+
* @returns one slice per `turn/start`…`turn/end` span, oldest first.
|
|
60
|
+
*/
|
|
61
|
+
export declare function completedTurns(events: readonly SessionEvent[]): readonly TurnSlice[];
|
|
62
|
+
/**
|
|
63
|
+
* Exact usage for every completed turn that can be proven.
|
|
64
|
+
* @param events - the whole durable log, in log order.
|
|
65
|
+
* @param derive - the meter's per-turn fold, injected so this module stays pure.
|
|
66
|
+
* @returns one row per provable turn, oldest first; turns whose attempts did
|
|
67
|
+
* not all report usage are omitted rather than estimated, and so is a turn
|
|
68
|
+
* that billed nothing at all — an empty row is noise in a usage table.
|
|
69
|
+
*/
|
|
70
|
+
export declare function turnUsages(events: readonly SessionEvent[], derive: (events: readonly SessionEvent[]) => TurnTokenUsage | undefined): readonly UsageTurn[];
|
|
71
|
+
/** A bucket some turn of a group did not report, leaving the group sum a floor. */
|
|
72
|
+
export type PartialBucket = 'cacheReadTokens' | 'cacheWriteTokens' | 'reasoningTokens';
|
|
73
|
+
/** One model's merged totals across every turn it billed. */
|
|
74
|
+
export interface ModelUsage {
|
|
75
|
+
/** Model names joined with ` + ` (a turn that switched models lists both). */
|
|
76
|
+
readonly model: string;
|
|
77
|
+
/** Turns attributed to this model. */
|
|
78
|
+
readonly turns: number;
|
|
79
|
+
readonly uncachedInputTokens: number;
|
|
80
|
+
readonly outputTokens: number;
|
|
81
|
+
readonly totalTokens: number;
|
|
82
|
+
/** Summed over the turns that reported it; absent when none did. */
|
|
83
|
+
readonly cacheReadTokens?: number;
|
|
84
|
+
/** Summed over the turns that reported it; absent when none did. */
|
|
85
|
+
readonly cacheWriteTokens?: number;
|
|
86
|
+
/** Summed over the turns that reported it; absent when none did. */
|
|
87
|
+
readonly reasoningTokens?: number;
|
|
88
|
+
/**
|
|
89
|
+
* Buckets some turn of the group left unreported. The corresponding sum (and
|
|
90
|
+
* the hit share derived from it) counts only what WAS reported, so the
|
|
91
|
+
* display marks it as a floor rather than hiding the group's known traffic.
|
|
92
|
+
*/
|
|
93
|
+
readonly partial: readonly PartialBucket[];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Merge the per-turn rows by the model that billed them, biggest spender
|
|
97
|
+
* first. A turn lands in exactly one group — the group named by every model it
|
|
98
|
+
* used — so the sums stay additive and a mid-turn model switch never counts
|
|
99
|
+
* the same tokens twice. Each bucket is merged over the turns that reported
|
|
100
|
+
* it, and {@link ModelUsage.partial} records the ones that stayed silent.
|
|
101
|
+
* @param turns - provable per-turn rows, oldest first.
|
|
102
|
+
* @returns one row per model group.
|
|
103
|
+
*/
|
|
104
|
+
export declare function modelTotals(turns: readonly UsageTurn[]): readonly ModelUsage[];
|
|
105
|
+
/** The model attribution for one turn: the meter's routes, else its messages. */
|
|
106
|
+
export declare function turnModel(slice: TurnSlice, usage: TurnTokenUsage): string;
|
|
107
|
+
/**
|
|
108
|
+
* Render the panel body.
|
|
109
|
+
* @param view - the projection totals plus the derived per-turn rows.
|
|
110
|
+
* @param columns - usable content columns inside the panel border.
|
|
111
|
+
* @returns bounded, styled rows ready to draw.
|
|
112
|
+
*/
|
|
113
|
+
export declare function usageLines(view: UsageView, columns: number): readonly StyledLine[];
|
|
@@ -24,6 +24,23 @@ export interface SessionQueryService {
|
|
|
24
24
|
listSessions(signal?: AbortSignal): Promise<SessionRecord[]>;
|
|
25
25
|
readTitleSnapshots(ids: readonly string[], signal?: AbortSignal): Promise<TitleObservationResult[]>;
|
|
26
26
|
readSession(id: string, signal?: AbortSignal): Promise<SessionLogSnapshot>;
|
|
27
|
+
/** Cross-session full-text search (SQLite FTS engine; openAt may gate it). */
|
|
28
|
+
searchSessions(request: {
|
|
29
|
+
query: string;
|
|
30
|
+
limit?: number;
|
|
31
|
+
}, exec?: {
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
}): Promise<{
|
|
34
|
+
items: readonly {
|
|
35
|
+
header: SessionHeader;
|
|
36
|
+
live: boolean;
|
|
37
|
+
persisted: boolean;
|
|
38
|
+
bestMatch: {
|
|
39
|
+
snippet: string;
|
|
40
|
+
time: number;
|
|
41
|
+
};
|
|
42
|
+
}[];
|
|
43
|
+
}>;
|
|
27
44
|
}
|
|
28
45
|
export type SessionScope = 'roots' | 'all';
|
|
29
46
|
export type CwdScope = 'all' | 'current';
|