@toddzheng024/dscode-bundle 0.1.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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +5 -0
  3. package/THIRD_PARTY_NOTICES.md +11 -0
  4. package/bin/apply_patch +4 -0
  5. package/bootstrap.mjs +21 -0
  6. package/cordis.patch.yml +756 -0
  7. package/package.json +327 -0
  8. package/plugins/auto-review/audit.mjs +20 -0
  9. package/plugins/auto-review/index.mjs +181 -0
  10. package/plugins/auto-review/policy.mjs +59 -0
  11. package/plugins/dscode/index.mjs +35 -0
  12. package/plugins/session-metrics/index.mjs +44 -0
  13. package/plugins/session-metrics/pricing.mjs +18 -0
  14. package/plugins/session-metrics/store.mjs +24 -0
  15. package/plugins/session-metrics/view.mjs +58 -0
  16. package/plugins/tui-tools/hooks.mjs +23 -0
  17. package/plugins/tui-tools/index.mjs +164 -0
  18. package/plugins/ultra/policy.mjs +11 -0
  19. package/presets/dscode/agent.cordis.yml +288 -0
  20. package/presets/dscode/preset.yml +3 -0
  21. package/vendor/bash/LICENSE +21 -0
  22. package/vendor/bash/index.js +449 -0
  23. package/vendor/bash/types/background.d.ts +19 -0
  24. package/vendor/bash/types/index.d.ts +22 -0
  25. package/vendor/bash/types/render.d.ts +38 -0
  26. package/vendor/deepseek/LICENSE +21 -0
  27. package/vendor/deepseek/index.js +2102 -0
  28. package/vendor/deepseek/types/adapter.d.ts +163 -0
  29. package/vendor/deepseek/types/file-id.d.ts +19 -0
  30. package/vendor/deepseek/types/file-store.d.ts +83 -0
  31. package/vendor/deepseek/types/files-api.d.ts +103 -0
  32. package/vendor/deepseek/types/image-tokens.d.ts +19 -0
  33. package/vendor/deepseek/types/index.d.ts +106 -0
  34. package/vendor/deepseek/types/request-pricing.d.ts +48 -0
  35. package/vendor/deepseek/types/serialize.d.ts +85 -0
  36. package/vendor/deepseek/types/sse.d.ts +24 -0
  37. package/vendor/deepseek/types/translate.d.ts +37 -0
  38. package/vendor/deepseek/types/types.d.ts +178 -0
  39. package/vendor/deepseek/types/upload-index.d.ts +68 -0
  40. package/vendor/persistent/LICENSE +21 -0
  41. package/vendor/persistent/index.js +386 -0
  42. package/vendor/persistent/types/index.d.ts +24 -0
  43. package/vendor/tui/LICENSE +21 -0
  44. package/vendor/tui/devtools-CdTl3MNy.mjs +3643 -0
  45. package/vendor/tui/index.mjs +39105 -0
  46. package/vendor/tui/invariant.mjs +21 -0
  47. package/vendor/tui/rolldown-runtime-CMFfr-1z.mjs +26 -0
  48. package/vendor/tui/startup.mjs +109 -0
  49. package/vendor/tui/theme-DCT8Y2xf.mjs +628 -0
  50. package/vendor/tui/types/app.d.ts +304 -0
  51. package/vendor/tui/types/approval.d.ts +59 -0
  52. package/vendor/tui/types/attachments.d.ts +52 -0
  53. package/vendor/tui/types/authorization-panel.d.ts +22 -0
  54. package/vendor/tui/types/authorization.d.ts +36 -0
  55. package/vendor/tui/types/commands.d.ts +52 -0
  56. package/vendor/tui/types/editor-keys.d.ts +105 -0
  57. package/vendor/tui/types/editor.d.ts +6 -0
  58. package/vendor/tui/types/fork.d.ts +8 -0
  59. package/vendor/tui/types/git-workflow.d.ts +32 -0
  60. package/vendor/tui/types/history.d.ts +97 -0
  61. package/vendor/tui/types/index.d.ts +124 -0
  62. package/vendor/tui/types/input-split.d.ts +54 -0
  63. package/vendor/tui/types/internals.d.ts +26 -0
  64. package/vendor/tui/types/invariant.d.ts +15 -0
  65. package/vendor/tui/types/kernel-panels.d.ts +167 -0
  66. package/vendor/tui/types/keyboard.d.ts +80 -0
  67. package/vendor/tui/types/mentions.d.ts +81 -0
  68. package/vendor/tui/types/model-capabilities.d.ts +82 -0
  69. package/vendor/tui/types/models.d.ts +119 -0
  70. package/vendor/tui/types/permissions.d.ts +27 -0
  71. package/vendor/tui/types/plugin-inventory.d.ts +11 -0
  72. package/vendor/tui/types/presets.d.ts +22 -0
  73. package/vendor/tui/types/provider-settings.d.ts +239 -0
  74. package/vendor/tui/types/questions.d.ts +54 -0
  75. package/vendor/tui/types/render/animations.d.ts +265 -0
  76. package/vendor/tui/types/render/editor.d.ts +162 -0
  77. package/vendor/tui/types/render/export.d.ts +9 -0
  78. package/vendor/tui/types/render/fuzzy.d.ts +21 -0
  79. package/vendor/tui/types/render/inspector.d.ts +36 -0
  80. package/vendor/tui/types/render/lines.d.ts +66 -0
  81. package/vendor/tui/types/render/markdown.d.ts +29 -0
  82. package/vendor/tui/types/render/projection.d.ts +461 -0
  83. package/vendor/tui/types/render/status.d.ts +196 -0
  84. package/vendor/tui/types/render/text.d.ts +58 -0
  85. package/vendor/tui/types/render/tool-detail.d.ts +94 -0
  86. package/vendor/tui/types/render/tool-preview.d.ts +28 -0
  87. package/vendor/tui/types/render/width.d.ts +29 -0
  88. package/vendor/tui/types/session-directory.d.ts +173 -0
  89. package/vendor/tui/types/session-switch.d.ts +17 -0
  90. package/vendor/tui/types/settings-file.d.ts +41 -0
  91. package/vendor/tui/types/skills.d.ts +47 -0
  92. package/vendor/tui/types/startup.d.ts +65 -0
  93. package/vendor/tui/types/store.d.ts +58 -0
  94. package/vendor/tui/types/subagents.d.ts +70 -0
  95. package/vendor/tui/types/theme-panel.d.ts +24 -0
  96. package/vendor/tui/types/theme.d.ts +215 -0
  97. package/vendor/tui/types/version.d.ts +18 -0
  98. package/vendor/tui/types/whale-glyph.d.ts +6 -0
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Terminal animation helpers derived from the web design language:
3
+ * thinking uses Codex's slow shimmer sweep, the busy composer marker uses the
4
+ * original braille chase, and the streaming caret blink is the Claude-Code
5
+ * convention.
6
+ *
7
+ * The DeepSeek model-switch easter egg ports Codex's effort-ignition "Wave"
8
+ * style (`codex-rs/tui/src/bottom_pane/effort_ignition_styles.rs`): switching
9
+ * INTO an official DeepSeek route sweeps a blue wave across the composer's
10
+ * input row — one column per cell, `backgroundColor` = the sampled wave
11
+ * color — then, on the deepseek (Ultra-equivalent) tier, drops the `· ✦ ✧`
12
+ * sparkle sequence into the rightmost blank cell before fading. The prompt
13
+ * marker keeps the tier accent afterwards (persistent, like Codex's prompt
14
+ * charge). Pure functions only — the Ink layer owns timers and colors.
15
+ *
16
+ * Wave and Pulse deliberately extend the Codex port after in-terminal
17
+ * testing: the per-row phase cascade was removed (Codex tints each column
18
+ * across the whole band), Wave became a WATER SURFACE — one continuous sine
19
+ * swell spanning the band, mirror-symmetric about the center column, its
20
+ * crests flowing outward from the center with a symmetric fade envelope
21
+ * (the deepseek tier adds one faster harmonic crossing it), painted with
22
+ * Aurora's recipe: wide soft gradients, mirrored second-hue mixing, and a
23
+ * low alpha cap — no hard core line — while Pulse became true
24
+ * two-dimensional, cell-aspect-corrected detonations: soft wide rings whose
25
+ * color grades across their width, expanding outward through a symmetric
26
+ * fade envelope and each trailing an echo ripple in the next blue. Aurora
27
+ * keeps Codex's geometry verbatim.
28
+ *
29
+ * @module @deepseek-ai/dsh-code/render/animations
30
+ */
31
+ import type { RgbTriple } from '../theme.ts';
32
+ /** Cadence for the original busy braille chase (8 frames × 125ms = 1s). */
33
+ export declare const BUSY_CHASE_TICK_MS = 125;
34
+ /** Original terminal StateDot chase frames. */
35
+ export declare const BUSY_CHASE_FRAMES: readonly ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"];
36
+ /** Chase frame for a monotonic tick. */
37
+ export declare function busyChaseFrame(tick: number): string;
38
+ /** Clock cadence for the Codex-style Deep diving shimmer. */
39
+ export declare const DEEP_DIVING_SHIMMER_TICK_MS = 33;
40
+ /** Codex shimmer timing and geometry. */
41
+ export declare const DEEP_DIVING_SHIMMER_DURATION_MS = 2000;
42
+ export declare const DEEP_DIVING_SHIMMER_PADDING = 10;
43
+ export declare const DEEP_DIVING_SHIMMER_HALF_WIDTH = 5;
44
+ export declare const DEEP_DIVING_SPARK_BREATH_DURATION_MS = 2000;
45
+ /**
46
+ * Codex's 2-second shimmer sweep, expressed in terminal ticks. The sweep has
47
+ * ten virtual columns of padding on either side and a five-column cosine
48
+ * highlight band, so the text changes gently rather than cycling rapidly.
49
+ */
50
+ export declare function deepDivingShimmerIntensity(index: number, tick: number, graphemeCount: number): number;
51
+ /** Blue RGB color for one grapheme in the Codex-style shimmer. */
52
+ export declare function deepDivingGradientColor(index: number, tick: number, graphemeCount: number, base: RgbTriple, highlight: RgbTriple): RgbTriple;
53
+ /** Smooth breathing intensity for the always-visible Deep diving sparkle. */
54
+ export declare function deepDivingSparkIntensity(tick: number): number;
55
+ /** Blue RGB color for the breathing Deep diving sparkle. */
56
+ export declare function deepDivingSparkColor(tick: number, base: RgbTriple, highlight: RgbTriple): RgbTriple;
57
+ /** Caret blink cadence: one blink step (on or off) per tick. */
58
+ export declare const CARET_BLINK_TICK_MS = 530;
59
+ /** Caret visibility: half the ticks on, half off (530ms blink). */
60
+ export declare function caretVisible(tick: number): boolean;
61
+ /**
62
+ * The one-shot DeepSeek model-switch easter egg: when the status bar model
63
+ * label switches to an official DeepSeek route, the composer's input row
64
+ * plays Codex's effort-ignition "Wave" — a blue crest sweeping the content
65
+ * row column by column (background tint ≤ 0.55 under the draft), plus the
66
+ * Ultra-style `· ✦ ✧` sparkles on the deepseek tier — and the prompt marker
67
+ * keeps the tier accent afterwards. The Ink layer owns the timer and reads
68
+ * the ACTIVE palette anchors (`getPalette`); everything below is pure
69
+ * interpolation over the colors it is given.
70
+ */
71
+ /** Frame cadence of the DeepSeek wave: Codex's IGNITION_FRAME_TICK (33ms ≈ 30fps). */
72
+ export declare const DEEPSEEK_WAVE_TICK_MS = 33;
73
+ /**
74
+ * The DeepSeek wave tiers. The concept maps Codex's reasoning tiers to
75
+ * model ids: `flash` runs the Max parameters, `deepseek` (pro models) runs
76
+ * the Ultra parameters (dual band + tail sparkles on the Wave style).
77
+ * `unknown` is the "Into the Unknown" variant: it reuses the deepseek tier's
78
+ * exact parameters (dual band, durations, sparkles) for NON-DeepSeek models
79
+ * running a reasoning effort above high — the wordmark renders differently
80
+ * but the motion is identical.
81
+ */
82
+ export type DeepseekWaveTier = 'flash' | 'deepseek' | 'unknown';
83
+ /**
84
+ * The three ignition styles — Codex `IgnitionStyle`: a traveling crest
85
+ * (Wave), a drifting multi-hue band (Aurora), and an expanding ring (Pulse).
86
+ * One style is picked at random per trigger and never repeats the previous.
87
+ */
88
+ export type DeepseekWaveStyle = 'wave' | 'aurora' | 'pulse';
89
+ /**
90
+ * The water surface: ONE continuous sine line spanning the whole band,
91
+ * mirror-symmetric about the center column, its crests flowing OUTWARD from
92
+ * the center (phase k·|x − center| − ω·t). No sweep window, no return trip —
93
+ * the surface fades in, flows, and fades out, symmetric in both space and
94
+ * time. The deepseek tier adds one faster, finer HARMONIC line whose crests
95
+ * cross the fundamental's: interleaved richness with both lines still
96
+ * symmetric and still only ever flowing outward.
97
+ */
98
+ export declare const WAVE_SURFACE_AMPLITUDE = 0.8;
99
+ export declare const WAVE_SURFACE_HARMONIC = 0.45;
100
+ export declare const WAVE_SURFACE_WAVELENGTH = 40;
101
+ export declare const WAVE_SURFACE_OMEGA = 9;
102
+ /** Vertical thickness in lane units — Aurora-wide: soft gradients, no hard edges. */
103
+ export declare const WAVE_SURFACE_THICKNESS = 1.2;
104
+ /**
105
+ * The mirrored second-hue profile: the space BELOW the surface carries a
106
+ * second blue at this strength, so color (not just brightness) varies
107
+ * continuously across the wave — Aurora-style hue mixing instead of a
108
+ * single flat tint.
109
+ */
110
+ export declare const WAVE_SURFACE_MIRROR = 0.6;
111
+ /** Aurora-style soft alpha: low gain, capped well under the pulse ring's. */
112
+ export declare const WAVE_SURFACE_ALPHA_GAIN = 0.45;
113
+ export declare const WAVE_SURFACE_ALPHA_CAP = 0.68;
114
+ /** Aurora-grade soft alpha for the detonation — a notch above the swell. */
115
+ export declare const PULSE_ALPHA_GAIN = 0.45;
116
+ export declare const PULSE_ALPHA_CAP = 0.72;
117
+ /** Sparkle glyphs in frame order — Codex SPARK_GLYPHS (`· ✦ ✧`). */
118
+ export declare const SPARK_GLYPHS: readonly ["·", "✦", "✧"];
119
+ /**
120
+ * Band tables — Codex `bands(style, tier)`. Each entry is a triple whose
121
+ * meaning depends on the style: Wave/Pulse use `(launch, travel, strength)`;
122
+ * Aurora uses `(speed, phase, hueIndex)`.
123
+ */
124
+ export type DeepseekWaveBand = readonly [number, number, number];
125
+ export declare const DEEPSEEK_WAVE_BANDS: Readonly<Record<DeepseekWaveStyle, Readonly<Record<DeepseekWaveTier, readonly DeepseekWaveBand[]>>>>;
126
+ /**
127
+ * Total visible duration: the Codex ignition duration plus 200ms so its motion
128
+ * remains readable in a busy terminal.
129
+ * @param tier - the active wave tier.
130
+ * @param style - the active ignition style.
131
+ * @returns the duration in milliseconds.
132
+ */
133
+ export declare function deepseekWaveDuration(tier: DeepseekWaveTier, style?: DeepseekWaveStyle): number;
134
+ /**
135
+ * Pick one ignition style at random, never repeating the previous one —
136
+ * Codex `IgnitionStyle::random`. Falls back to the remaining styles.
137
+ * @param previous - the style of the last trigger, if any.
138
+ * @returns a style different from `previous`.
139
+ */
140
+ export declare function deepseekWaveStyleRandom(previous: DeepseekWaveStyle | undefined): DeepseekWaveStyle;
141
+ /**
142
+ * Tier for a `provider/model` label: a MODEL ID containing `flash` runs the
143
+ * single-band flash tier; everything else (pro/reasoner/chat) runs the
144
+ * dual-band deepseek tier. Mirrors Codex's Max→Ultra mapping. Only the model
145
+ * segment (after the `/`) is matched, so a provider whose name contains
146
+ * `flash` cannot flip an unrelated model onto the flash tier.
147
+ * @param model - the `provider/model` label of the applied model.
148
+ * @returns the wave tier for that model.
149
+ */
150
+ export declare function deepseekWaveTier(model: string): DeepseekWaveTier;
151
+ /**
152
+ * Cosine window — Codex `crest`: 1 exactly under the wave center, 0 from
153
+ * one half-width away.
154
+ * @param distance - distance from the crest center in half-widths.
155
+ * @returns the crest strength in 0..1.
156
+ */
157
+ export declare function crest(distance: number): number;
158
+ /**
159
+ * Cubic ease-in-out — Codex `ease_in_out`: flat at both ends, steepest in
160
+ * the middle, so the crest accelerates and eases instead of sliding linearly.
161
+ * @param progress - raw progress (clamped to 0..1).
162
+ * @returns the eased progress in 0..1.
163
+ */
164
+ export declare function easeInOut(progress: number): number;
165
+ /**
166
+ * Fade-in/fade-out envelope — Codex `envelope`: linear ramp over `fadeIn`
167
+ * at the start and `fadeOut` at the end, plateau at 1 between, 0 outside the
168
+ * total. The Wave style keeps the envelope at 1 (Codex paints Wave without
169
+ * an envelope); exported for the Aurora-style fades and for tests.
170
+ * @param elapsed - seconds since the animation started.
171
+ * @param total - total duration in seconds.
172
+ * @param fadeIn - seconds of fade-in.
173
+ * @param fadeOut - seconds of fade-out.
174
+ * @returns the envelope value in 0..1.
175
+ */
176
+ export declare function envelope(elapsed: number, total: number, fadeIn: number, fadeOut: number): number;
177
+ /**
178
+ * The background color for one composer-band column at a tick — Codex
179
+ * `paint_bands` + `Canvas::tint` for all three styles. Bands overlap with a
180
+ * max for Wave/Pulse and a SUM for Aurora (Codex differs by style), the
181
+ * weighted hues mix per column (Wave/Pulse always end on hue 0), the tint
182
+ * blends the mixed hue toward the blank-cell base at the style's alpha cap,
183
+ * and Aurora applies its own fade envelope. Returns `null` when the column
184
+ * should stay transparent, so the row returns to no `backgroundColor` on
185
+ * both ends. With `rows > 1`: Wave is a water surface — every column
186
+ * lights the row nearest the surface's current height, so the light reads
187
+ * as ONE continuous wavy line spanning the band, symmetric about the center
188
+ * column and flowing outward (a single-row band falls back to a flat glow);
189
+ * Pulse rings in two dimensions around the band's center cell with trailing
190
+ * echo ripples; only Aurora samples the timeline shifted by a per-row phase
191
+ * offset.
192
+ * @param tick - wave frame (0, 1, … at DEEPSEEK_WAVE_TICK_MS).
193
+ * @param column - column index in the content row (0..width-1).
194
+ * @param width - content-row width in columns.
195
+ * @param tier - the wave tier (flash = Max, deepseek = Ultra parameters).
196
+ * @param style - the ignition style.
197
+ * @param hues - the tier's three hues.
198
+ * @param base - the blank-cell base color the tint blends toward.
199
+ * @param row - row index in the band (0..rows-1; default 0 = old single-row).
200
+ * @param rows - band height in rows (default 1).
201
+ * @returns the blended RGB background, or null for transparent.
202
+ */
203
+ 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;
204
+ /**
205
+ * The sparkle glyph for a tick — Codex `spark_frame`, sampled on the same
206
+ * proportionally slowed DeepSeek Wave timeline as the composer background.
207
+ * The Ink layer still must skip occupied cells.
208
+ * @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS.
209
+ * @returns the sparkle glyph, or null outside the stretched tail window.
210
+ */
211
+ export declare function deepseekWaveSpark(tick: number): string | null;
212
+ /**
213
+ * Whether the `deepseek` wordmark rides the wave at this tick: it fades in
214
+ * shortly after the first crest launches and out before the wave settles,
215
+ * so the brand name surfaces through the sweep's middle. The Ink layer
216
+ * places it in the row's blank mid-section (never over real draft text).
217
+ * @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS.
218
+ * @param tier - the wave tier.
219
+ * @returns true while the wordmark should be visible.
220
+ */
221
+ export declare function deepseekWaveWordVisible(tick: number, tier: DeepseekWaveTier, style?: DeepseekWaveStyle): boolean;
222
+ /**
223
+ * The per-character color for the `deepseek` wordmark: the tier's hues
224
+ * cycled per character (d→hue0, e→hue1, e→hue2, …), a brand-gradient text.
225
+ * @param index - character index in the wordmark.
226
+ * @param hues - the tier's three hues.
227
+ * @returns the hue for that character.
228
+ */
229
+ export declare function deepseekWaveWordHue(index: number, hues: readonly [RgbTriple, RgbTriple, RgbTriple]): RgbTriple;
230
+ /**
231
+ * True when a `provider/model` status label addresses the official DeepSeek
232
+ * route: either segment contains `deepseek` (case-insensitive), covering the
233
+ * `deepseek-official` provider route and its `deepseek-*` model ids.
234
+ * @param label - the status bar model label (`provider/model`).
235
+ * @returns whether the label names an official DeepSeek model.
236
+ */
237
+ export declare function isOfficialDeepSeekLabel(label: string): boolean;
238
+ /**
239
+ * True when an effective reasoning effort is STRICTLY above `high` — the
240
+ * trigger gate for the "Into the Unknown" wave on non-DeepSeek routes.
241
+ * Absent efforts and unrecognized ids never qualify.
242
+ * @param effort - the effective reasoning-effort id ('' or undefined when none).
243
+ * @returns whether the effort ranks above high.
244
+ */
245
+ export declare function effortAboveHigh(effort: string | undefined): boolean;
246
+ /**
247
+ * Parse a persisted animations preference (`animations.json`): timed
248
+ * animations are on by default and only an explicit `false` disables them —
249
+ * a missing key, corrupt value, or absent file all mean enabled, so the
250
+ * /animation toggle degrades exactly like every other user preference.
251
+ * @param value - the raw parsed JSON value (expected boolean).
252
+ * @returns whether timed animations should run.
253
+ */
254
+ export declare function parseAnimationsPref(value: unknown): boolean;
255
+ /**
256
+ * One parsed `/animation` argument: '' toggles, `on|true|1` enables,
257
+ * `off|false|0` disables (case-insensitive, surrounding whitespace ignored),
258
+ * and anything else is a usage error the caller surfaces. Kept pure so the
259
+ * command's entire decision table is unit-testable.
260
+ * @param argument - the raw text after `/animation`.
261
+ * @returns `{ enabled }`, `'toggle'`, or `'usage'`.
262
+ */
263
+ export declare function parseAnimationsArgument(argument: string): {
264
+ enabled: boolean;
265
+ } | 'toggle' | 'usage';
@@ -0,0 +1,162 @@
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 follows Codex's piece semantics: whitespace separates runs,
12
+ * punctuation runs stay atomic, and each Han grapheme is its own boundary.
13
+ *
14
+ * @module @deepseek-ai/dsh-code/render/editor
15
+ */
16
+ /** One grapheme cluster with its source span and display width in cells. */
17
+ export interface GraphemeSpan {
18
+ text: string;
19
+ start: number;
20
+ end: number;
21
+ width: number;
22
+ }
23
+ /**
24
+ * Split text into grapheme clusters. Falls back to code points when
25
+ * Intl.Segmenter is unavailable; the fallback still keeps surrogate pairs
26
+ * (emoji) atomic so the cursor can never split one.
27
+ */
28
+ export declare function splitGraphemes(text: string): readonly GraphemeSpan[];
29
+ /** Clamp a cursor offset to the nearest grapheme boundary (surrogates, ZWJ, marks stay whole). */
30
+ export declare function clampCursor(value: string, offset: number): number;
31
+ /**
32
+ * Delete the final grapheme cluster (append-only drafts without a cursor).
33
+ * Surrogate pairs and multi-codepoint emoji stay whole instead of leaving a
34
+ * lone trailing code unit behind.
35
+ */
36
+ export declare function deleteLastGrapheme(text: string): string;
37
+ /**
38
+ * Step the cursor by whole graphemes (negative steps left). The cursor is
39
+ * assumed to sit on a boundary; any drift is clamped first.
40
+ */
41
+ export declare function moveCursorBy(value: string, offset: number, delta: number): number;
42
+ /**
43
+ * Normalize text entering the draft: CRLF/CR become LF, tabs become two
44
+ * spaces (terminal tab stops are contextual and cannot join a deterministic
45
+ * row budget), and every other C0 control byte plus DEL is REMOVED — the
46
+ * draft is data, so a stray ESC (Windows Terminal file drops) disappears
47
+ * instead of rendering as literal backslash-x-1-b text. Newlines survive.
48
+ */
49
+ export declare function sanitizeDraftText(text: string): string;
50
+ /** One physical editor row: wrapped text plus its boundary map. */
51
+ export interface EditorRowModel {
52
+ /** Display text of the row (never contains `\n`; sanitized upstream). */
53
+ readonly text: string;
54
+ /** Source offset of the first grapheme on the row. */
55
+ readonly start: number;
56
+ /** Source offset just past the last grapheme on the row (before its newline). */
57
+ readonly end: number;
58
+ /** Boundary offsets on the row, start to end inclusive. */
59
+ readonly offsets: readonly number[];
60
+ /** Display column of each boundary; `columns[i]` pairs with `offsets[i]`. */
61
+ readonly columns: readonly number[];
62
+ /** Code-unit cut in `text` at each boundary; `cuts[i]` pairs with `offsets[i]`. */
63
+ readonly cuts: readonly number[];
64
+ }
65
+ /** The wrapped physical-row model of one draft. */
66
+ export interface EditorModel {
67
+ readonly rows: readonly EditorRowModel[];
68
+ readonly length: number;
69
+ }
70
+ /**
71
+ * Hard-wrap the draft into column-safe physical rows. Wide graphemes never
72
+ * split across rows (a grapheme that does not fit flushes the row first) and
73
+ * explicit newlines end their row without occupying a cell.
74
+ */
75
+ export declare function editorModel(value: string, columns: number): EditorModel;
76
+ /** Where a cursor offset renders: the physical row and its display column. */
77
+ export interface CaretSite {
78
+ row: number;
79
+ column: number;
80
+ }
81
+ /** Text slices for rendering one physical row with at most one caret. */
82
+ export interface EditorRowParts {
83
+ readonly before: string;
84
+ readonly caret: string;
85
+ readonly after: string;
86
+ readonly hasCaret: boolean;
87
+ }
88
+ /** Split one row around the authoritative caret; every other row stays whole. */
89
+ export declare function editorRowParts(row: EditorRowModel, rowIndex: number, caretRow: number, cursor: number, caretEnabled?: boolean): EditorRowParts;
90
+ /** Map a cursor offset to its caret site on the wrapped rows. */
91
+ export declare function caretSite(model: EditorModel, offset: number): CaretSite;
92
+ /**
93
+ * Move the caret across physical rows keeping a preferred display column
94
+ * (Codex `preferred_col`): horizontal moves reset the preference, vertical
95
+ * moves reuse it, clamped to each row's width.
96
+ */
97
+ export declare function moveCursorVertically(model: EditorModel, offset: number, preferredColumn: number, delta: number): number;
98
+ /** The start/end offsets of the logical line containing the cursor. */
99
+ export declare function lineBounds(value: string, offset: number): {
100
+ start: number;
101
+ end: number;
102
+ };
103
+ /**
104
+ * Codex `beginning_of_previous_word`: skip whitespace left, then land on the
105
+ * START of the trailing non-space piece (extending over separator pieces).
106
+ */
107
+ export declare function moveWordLeft(value: string, offset: number): number;
108
+ /**
109
+ * Codex `end_of_next_word`: skip whitespace right, then land on the END of
110
+ * the leading non-space piece (extending over separator pieces).
111
+ */
112
+ export declare function moveWordRight(value: string, offset: number): number;
113
+ /** One edit outcome: the next draft value, cursor, and killed span (if any). */
114
+ export interface EditResult {
115
+ value: string;
116
+ cursor: number;
117
+ /** Text removed into the kill buffer; undefined when nothing was killed. */
118
+ killed: string | undefined;
119
+ }
120
+ /** Delete the grapheme cluster before the cursor. */
121
+ export declare function deleteBackward(value: string, cursor: number): EditResult;
122
+ /** Delete the grapheme cluster at the cursor. */
123
+ export declare function deleteForward(value: string, cursor: number): EditResult;
124
+ /** Delete back to the start of the previous word (fills the kill buffer). */
125
+ export declare function deleteWordBackward(value: string, cursor: number): EditResult;
126
+ /** Delete forward to the end of the next word (fills the kill buffer). */
127
+ export declare function deleteWordForward(value: string, cursor: number): EditResult;
128
+ /** Ctrl+U: kill from the line start to the cursor; at BOL, kill the newline. */
129
+ export declare function killToLineStart(value: string, cursor: number): EditResult;
130
+ /** Ctrl+K: kill from the cursor to the line end; at EOL, kill the newline. */
131
+ export declare function killToLineEnd(value: string, cursor: number): EditResult;
132
+ /** Insert sanitized text at the cursor. */
133
+ export declare function insertText(value: string, cursor: number, text: string): EditResult;
134
+ /** Ctrl+A: current logical line start, then the previous line start on repeat. */
135
+ export declare function moveToLineStart(value: string, cursor: number, crossOnRepeat: boolean): number;
136
+ /** Ctrl+E: current logical line end, then the next line end on repeat. */
137
+ export declare function moveToLineEnd(value: string, cursor: number, crossOnRepeat: boolean): number;
138
+ /** One stable text range captured before an asynchronous draft operation. */
139
+ export interface DraftRange {
140
+ readonly start: number;
141
+ readonly end: number;
142
+ }
143
+ /**
144
+ * Remap a captured range when all intervening edits are wholly before or
145
+ * wholly after it. An edit overlapping either boundary invalidates the
146
+ * anchor instead of guessing and inserting content at a surprising place.
147
+ */
148
+ export declare function remapStableRange(original: string, current: string, range: DraftRange): DraftRange | undefined;
149
+ /** Replace a current range while preserving a cursor moved after capture. */
150
+ export declare function replaceRangePreservingCursor(value: string, cursor: number, range: DraftRange, replacement: string): EditResult;
151
+ /**
152
+ * Composer editor row budget: the editor itself never grows past this many
153
+ * physical rows; deeper drafts scroll internally to keep the caret visible.
154
+ * Short terminals collapse toward one row so the live transcript keeps room.
155
+ */
156
+ export declare function composerMaxRows(terminalRows: number): number;
157
+ /**
158
+ * History navigation starts with Up on an empty draft, or after visual
159
+ * movement has reached the directional text edge of an unchanged recalled
160
+ * entry. Every other position remains under textarea movement.
161
+ */
162
+ export declare function shouldRecallNavigate(value: string, cursor: number, lastRecalled: string | null, direction: -1 | 1): boolean;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Markdown export of one transcript view: the /export command's pure
3
+ * formatter. Deterministic and side-effect free — the runner owns the file
4
+ * write, so tests drive the builder with folded views directly.
5
+ *
6
+ * @module @deepseek-ai/dsh-code/render/export
7
+ */
8
+ import { type TranscriptView } from './projection.ts';
9
+ export declare function buildExportMarkdown(view: TranscriptView, sessionId: string): string;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared fuzzy ranking for `/` and `@` menu candidates: the query must be a
3
+ * case-insensitive ordered subsequence of the candidate name. Prefix hits
4
+ * rank first, then the strongest alignment score, then the source order of
5
+ * the input. Ported from the upstream web client's ui-primitives
6
+ * (rank-by-name.ts) so the terminal matches the web menu's discovery feel;
7
+ * the algorithm is unchanged, only the module's home moved.
8
+ *
9
+ * @module @deepseek-ai/dsh-code/render/fuzzy
10
+ */
11
+ /**
12
+ * Rank named items by a menu query.
13
+ * @param items - candidates in source order (the caller's composition order
14
+ * is the final tie-breaker, e.g. local commands before registry entries).
15
+ * @param rawQuery - the text typed after the trigger, matched case-insensitively.
16
+ * @returns the matching items: prefix hits first, then by alignment score,
17
+ * then in source order. The input list itself for an empty query.
18
+ */
19
+ export declare function rankByName<T extends {
20
+ readonly name: string;
21
+ }>(items: readonly T[], rawQuery: string): readonly T[];
@@ -0,0 +1,36 @@
1
+ /** Pure viewport, selection, and scrolling rules for exclusive TUI panels. */
2
+ /** Terminal-space allocation for the inspector's one dynamic screen. */
3
+ export interface InspectorViewport {
4
+ /** Maximum dynamic rows, kept strictly below the terminal height. */
5
+ maxHeight: number;
6
+ /** Rows available to the selected entry after border, title, and footer. */
7
+ bodyRows: number;
8
+ /** Optional blank rows separating title/body/footer on roomy terminals. */
9
+ gapRows: 0 | 2;
10
+ /** Columns available inside the horizontal border and padding. */
11
+ contentColumns: number;
12
+ /** Safe outer width for a bordered dynamic panel; never writes column N. */
13
+ outerColumns: number;
14
+ /** Tiny terminals use a borderless one-line close hint. */
15
+ compact: boolean;
16
+ }
17
+ /** One transcript-to-composer gutter, collapsed on short terminals. */
18
+ export declare function layoutGutterRows(rows: number): 0 | 1;
19
+ /**
20
+ * Keep the inspector plus its persistent status/composer chrome below
21
+ * `stdout.rows`: at equality Ink clears the terminal and rewrites all
22
+ * accumulated `<Static>` output on every frame.
23
+ */
24
+ export declare function panelViewport(columns: number, rows: number): InspectorViewport;
25
+ /** Backward-compatible name for the Ctrl+O-specific caller and tests. */
26
+ export declare function inspectorViewport(columns: number, rows: number): InspectorViewport;
27
+ /** Clamp a first-visible row to the range representable by one viewport. */
28
+ export declare function clampScroll(offset: number, totalRows: number, visibleRows: number): number;
29
+ /** Move a viewport by a signed row delta without escaping its content. */
30
+ export declare function moveScroll(offset: number, delta: number, totalRows: number, visibleRows: number): number;
31
+ /** Keep one focused row visible while preserving the current window when possible. */
32
+ export declare function revealRow(offset: number, row: number, totalRows: number, visibleRows: number): number;
33
+ /** Center a selected list row where possible, clamped at both ends. */
34
+ export declare function selectionWindow(cursor: number, totalRows: number, visibleRows: number): number;
35
+ /** Follow appended history only while the inspector cursor was at the tail. */
36
+ export declare function followInspectorCursor(cursor: number, previousLength: number, nextLength: number): number;
@@ -0,0 +1,66 @@
1
+ /** Width-safe styled physical rows for bounded terminal panels. */
2
+ import { type TranscriptEntry } from './projection.ts';
3
+ import { type MdStyle } from './markdown.ts';
4
+ /** Presentation classes mapped to Ink colors by the app boundary. */
5
+ export type LineStyle = MdStyle | 'brand' | 'success' | 'error' | 'warn' | 'dimItalic';
6
+ /** One styled run within a physical terminal row. */
7
+ export interface StyledSegment {
8
+ text: string;
9
+ style: LineStyle;
10
+ }
11
+ /** One row guaranteed not to exceed the requested terminal width. */
12
+ export interface StyledLine {
13
+ segments: readonly StyledSegment[];
14
+ }
15
+ /** Construct one segment without leaking mutable objects into cached rows. */
16
+ export declare function lineSegment(text: string, style?: LineStyle): StyledSegment;
17
+ /**
18
+ * Sanitize and hard-wrap styled content into exact physical rows.
19
+ * Tabs become two visible spaces because terminal tab stops are contextual
20
+ * and therefore cannot participate in a deterministic row budget.
21
+ */
22
+ export declare function styledLines(segments: readonly StyledSegment[], columns: number): readonly StyledLine[];
23
+ /** Plain/dim text convenience over {@link styledLines}. */
24
+ export declare function textLines(text: string, columns: number, style?: LineStyle): readonly StyledLine[];
25
+ /** Markdown rows re-hardened so a single long word cannot escape the budget. */
26
+ export declare function markdownLines(text: string, columns: number): readonly StyledLine[];
27
+ /**
28
+ * Codex-style reasoning rows: the marker occupies the reply gutter and every
29
+ * wrapped or explicit continuation starts with the same two-column indent, so
30
+ * reasoning content and assistant Markdown share one left edge.
31
+ */
32
+ export declare function reasoningLines(text: string, columns: number): readonly StyledLine[];
33
+ /**
34
+ * Convert one durable transcript entry to its complete scrollable row model.
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.
38
+ */
39
+ export declare function transcriptEntryLines(entry: TranscriptEntry, columns: number, showReasoning?: boolean, reasoningToggleHint?: boolean, showToolDetails?: 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[];
42
+ /** The flexible rows of the live region; chrome (composer/notice/status) is never reduced. */
43
+ export interface LiveAllocation {
44
+ /** Settled tail rows currently rendered in the live tree. */
45
+ readonly live: number;
46
+ /** Rows reserved for the streaming reasoning tail or its marker. */
47
+ readonly reasoning: number;
48
+ /** Rows reserved for the streaming answer tail. */
49
+ readonly answer: number;
50
+ }
51
+ /** A clamped allocation plus the invariant-trip warning that triggered it. */
52
+ export interface LiveAllocationAudit {
53
+ readonly allocation: LiveAllocation;
54
+ readonly warning?: string;
55
+ }
56
+ /**
57
+ * Clamp the live-region allocation so the flexible dynamic rows never exceed
58
+ * the post-chrome budget. By construction the caller derives these rows from
59
+ * the same budget; this is the runtime tripwire for a future edit that breaks
60
+ * that derivation. Reduction order: answer first (the freshest content is the
61
+ * live tail), then reasoning, then settled live rows; nothing goes negative.
62
+ * @param allocation - the intended row allocation.
63
+ * @param dynamicRows - the post-chrome row budget.
64
+ * @returns the clamped allocation and a warning string when clamping fired.
65
+ */
66
+ export declare function clampLiveAllocation(allocation: LiveAllocation, dynamicRows: number): LiveAllocationAudit;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Terminal markdown renderer for assistant replies: a pure GFM-subset
3
+ * block/inline parser producing styled line segments the Ink renderer maps
4
+ * to colored text. No ANSI here — the app owns color mapping, tests own the
5
+ * structure. The subset mirrors what agent replies actually emit: headings,
6
+ * emphasis, inline/fenced code, flat lists, blockquotes, links, rules, GFM
7
+ * tables, and wrapped paragraphs. Unknown syntax degrades to plain text.
8
+ *
9
+ * @module @deepseek-ai/dsh-code/render/markdown
10
+ */
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';
13
+ /** One styled run of text. */
14
+ export interface MdSegment {
15
+ /** Visible text (no ANSI). */
16
+ text: string;
17
+ /** Presentation class for the app's color map. */
18
+ style: MdStyle;
19
+ }
20
+ /** One rendered line: a sequence of styled runs. */
21
+ export interface MdLine {
22
+ segments: readonly MdSegment[];
23
+ }
24
+ /** Visible width of a run in columns (grapheme-cluster and emoji aware). */
25
+ export declare function visibleColumns(text: string): number;
26
+ /** Render markdown text into styled lines of at most `width` columns. */
27
+ export declare function renderMarkdown(text: string, width: number, options?: {
28
+ physicalWrap?: boolean;
29
+ }): readonly MdLine[];