dsh-code 0.9.0 → 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 +31 -8
- package/README.md +264 -241
- package/bin/deepseek.mjs +100 -6
- package/cordis.patch.yml +29 -1
- package/lib/index.mjs +2317 -708
- 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 +24 -41
- 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 -117
- package/src/app.ts +4455 -3904
- 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 +74 -60
- 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
package/lib/startup.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { t as THEME_NAMES } from "./theme-
|
|
1
|
+
import { t as THEME_NAMES } from "./theme-DCT8Y2xf.mjs";
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { parseCmdline } from "@deepseek-ai/dsh-cmdline";
|
|
4
4
|
//#region src/startup.ts
|
|
5
5
|
/**
|
|
6
6
|
* The interactive terminal app's command-line provider: parses `--resume`,
|
|
7
|
-
* `--continue`, `--session`, `--mode`, `--theme`,
|
|
7
|
+
* `--continue`, `--session`, `--mode`, `--theme`, `--image`, an optional
|
|
8
|
+
* initial prompt, and `--help`, then
|
|
8
9
|
* publishes {@link TUI_STARTUP_SERVICE} for the runner to consume lazily.
|
|
9
10
|
* Follows the headless bundle's startup shape (a commander action publishing
|
|
10
11
|
* a service through {@link parseCmdline}).
|
|
@@ -41,23 +42,27 @@ function resolveTuiStartup(options) {
|
|
|
41
42
|
if (options.mode === "") throw new Error("--mode needs a preset id");
|
|
42
43
|
if (options.mode !== void 0 && (options.resume !== void 0 || options.continue === true)) throw new Error("--mode applies only to a new session; it cannot be combined with --resume or --continue");
|
|
43
44
|
if (options.theme !== void 0 && !THEME_NAMES.includes(options.theme)) throw new Error("--theme must be dark, light, or auto");
|
|
44
|
-
const
|
|
45
|
+
const input = {
|
|
46
|
+
...options.theme === void 0 ? {} : { theme: options.theme },
|
|
47
|
+
...options.prompt === void 0 || options.prompt.trim() === "" ? {} : { prompt: options.prompt.trim() },
|
|
48
|
+
...options.images === void 0 || options.images.length === 0 ? {} : { images: [...options.images] }
|
|
49
|
+
};
|
|
45
50
|
return options.resume !== void 0 ? {
|
|
46
51
|
kind: "resume",
|
|
47
52
|
sessionId: options.resume,
|
|
48
|
-
...
|
|
53
|
+
...input
|
|
49
54
|
} : options.continue === true ? {
|
|
50
55
|
kind: "latest",
|
|
51
|
-
...
|
|
56
|
+
...input
|
|
52
57
|
} : options.session !== void 0 ? {
|
|
53
58
|
kind: "named",
|
|
54
59
|
sessionId: options.session,
|
|
55
60
|
...options.mode === void 0 ? {} : { mode: options.mode },
|
|
56
|
-
...
|
|
61
|
+
...input
|
|
57
62
|
} : {
|
|
58
63
|
kind: "fresh",
|
|
59
64
|
...options.mode === void 0 ? {} : { mode: options.mode },
|
|
60
|
-
...
|
|
65
|
+
...input
|
|
61
66
|
};
|
|
62
67
|
}
|
|
63
68
|
/**
|
|
@@ -66,13 +71,15 @@ function resolveTuiStartup(options) {
|
|
|
66
71
|
* @returns a fresh program, so one process can parse more than once (tests).
|
|
67
72
|
*/
|
|
68
73
|
function tuiCommand() {
|
|
69
|
-
return new Command().name("dsh --profile cli").description("
|
|
74
|
+
return new Command().name("dsh --profile cli").description("DeepSeek Harness CLI core: the interactive coding terminal.").helpOption("-h, --help", "show this help").option("-r, --resume <session>", "resume the persisted session with this id (or unique id prefix)").option("-c, --continue", "resume the most recent persisted session for this working directory").option("--session <id>", "create a new session under this explicit id").option("--mode <preset>", "agent preset for a newly created session").option("--theme <name>", "color theme: dark (default), light, or auto").option("-i, --image <path>", "attach an image to the initial prompt (repeatable)", (path, paths) => [...paths, path], []).argument("[prompt...]", "initial prompt; sends immediately after startup").addHelpText("after", `
|
|
70
75
|
Examples:
|
|
71
76
|
dsh --profile cli fresh session, minted id
|
|
72
77
|
dsh --profile cli --resume abc123 resume session by id prefix
|
|
73
78
|
dsh --profile cli --continue resume the latest local session
|
|
74
79
|
dsh --profile cli --mode minimal fresh session using the minimal preset
|
|
75
80
|
dsh --profile cli --theme light light palette for bright terminals
|
|
81
|
+
dsh --profile cli "explain this repo" start and send an initial prompt
|
|
82
|
+
dsh --profile cli -i diagram.png "review this diagram"
|
|
76
83
|
`);
|
|
77
84
|
}
|
|
78
85
|
/**
|
|
@@ -82,8 +89,11 @@ Examples:
|
|
|
82
89
|
*/
|
|
83
90
|
function apply(ctx) {
|
|
84
91
|
const program = tuiCommand();
|
|
85
|
-
program.action(() => {
|
|
86
|
-
const options =
|
|
92
|
+
program.action((prompt) => {
|
|
93
|
+
const options = {
|
|
94
|
+
...program.opts(),
|
|
95
|
+
prompt: prompt.join(" ")
|
|
96
|
+
};
|
|
87
97
|
let startup;
|
|
88
98
|
try {
|
|
89
99
|
startup = resolveTuiStartup(options);
|
|
@@ -96,4 +106,4 @@ function apply(ctx) {
|
|
|
96
106
|
parseCmdline(ctx, program);
|
|
97
107
|
}
|
|
98
108
|
//#endregion
|
|
99
|
-
export {
|
|
109
|
+
export { apply, inject, name, resolveTuiStartup };
|
|
@@ -491,6 +491,12 @@ const DARK_PALETTE = {
|
|
|
491
491
|
125,
|
|
492
492
|
211,
|
|
493
493
|
252
|
|
494
|
+
],
|
|
495
|
+
/** Composer three-row band base — neutral light gray, hue-free so wave tints read on it. */
|
|
496
|
+
composerBand: [
|
|
497
|
+
46,
|
|
498
|
+
48,
|
|
499
|
+
52
|
|
494
500
|
]
|
|
495
501
|
};
|
|
496
502
|
/** Every palette by theme name; auto resolves through {@link resolveTheme}. */
|
|
@@ -556,6 +562,12 @@ const PALETTES = {
|
|
|
556
562
|
14,
|
|
557
563
|
116,
|
|
558
564
|
144
|
|
565
|
+
],
|
|
566
|
+
/** Composer three-row band base — neutral light gray, hue-free so wave tints read on it. */
|
|
567
|
+
composerBand: [
|
|
568
|
+
229,
|
|
569
|
+
231,
|
|
570
|
+
235
|
|
559
571
|
]
|
|
560
572
|
}
|
|
561
573
|
};
|
|
@@ -608,17 +620,9 @@ function parseThemeName(value) {
|
|
|
608
620
|
function inkColor(triple) {
|
|
609
621
|
return `rgb(${triple[0]}, ${triple[1]}, ${triple[2]})`;
|
|
610
622
|
}
|
|
611
|
-
/** Paint with the primary brand blue: whale, wordmark, tool names, accents. */
|
|
612
|
-
function brand(text) {
|
|
613
|
-
return chalk.rgb(...activePalette.brand)(text);
|
|
614
|
-
}
|
|
615
623
|
/** Paint muted captions, hints, and meta lines. */
|
|
616
624
|
function dim(text) {
|
|
617
625
|
return chalk.rgb(...activePalette.dim)(text);
|
|
618
626
|
}
|
|
619
|
-
/** Paint failures and error entries. */
|
|
620
|
-
function error(text) {
|
|
621
|
-
return chalk.rgb(...activePalette.error)(text);
|
|
622
|
-
}
|
|
623
627
|
//#endregion
|
|
624
|
-
export {
|
|
628
|
+
export { inkColor as a, chalk as c, getTheme as i, dim as n, parseThemeName as o, getPalette as r, setTheme as s, THEME_NAMES as t };
|
package/lib/types/app.d.ts
CHANGED
|
@@ -21,15 +21,17 @@ import { type TranscriptEntry } from './render/projection.ts';
|
|
|
21
21
|
import type { ApprovalStore } from './approval.ts';
|
|
22
22
|
import type { CommandsView } from './commands.ts';
|
|
23
23
|
import type { ModelDirectory, ModelRow } from './models.ts';
|
|
24
|
-
import type { ProviderSettingsDirectory, ProviderTargetView } from './provider-settings.ts';
|
|
24
|
+
import type { ProviderConfiguration, ProviderSettingsDirectory, ProviderTargetView } from './provider-settings.ts';
|
|
25
25
|
import type { QuestionStore } from './questions.ts';
|
|
26
26
|
import type { SkillsView, SkillRow } from './skills.ts';
|
|
27
27
|
import type { MentionCandidate } from './mentions.ts';
|
|
28
28
|
import type { SubagentFeedView } from './subagents.ts';
|
|
29
|
+
import { type JobRow } from './kernel-panels.ts';
|
|
29
30
|
import type { PresetRow } from './presets.ts';
|
|
30
31
|
import type { PermissionRow } from './permissions.ts';
|
|
31
32
|
import type { PluginRow } from './plugin-inventory.ts';
|
|
32
33
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
34
|
+
import type { GitDiffView } from './git-workflow.ts';
|
|
33
35
|
/** Visual priority for one bounded local notice. */
|
|
34
36
|
export type NoticeTone = 'info' | 'warning' | 'error';
|
|
35
37
|
/** Props the runner hands the app; callbacks stay owned by the runner. */
|
|
@@ -96,6 +98,8 @@ export interface AppProps {
|
|
|
96
98
|
unsetModelProviderCredential?(target: ProviderTargetView): Promise<void>;
|
|
97
99
|
/** Remove one user-owned provider profile and its page-managed credential. */
|
|
98
100
|
removeModelProvider?(target: ProviderTargetView): Promise<void>;
|
|
101
|
+
/** Save endpoint and explicit model capacities through the provider profile. */
|
|
102
|
+
saveModelProviderConfiguration?(target: ProviderTargetView, configuration: ProviderConfiguration): Promise<void>;
|
|
99
103
|
/** Cycle to the next permission preset (Shift+Tab); returns the new label. */
|
|
100
104
|
cyclePermission(): string;
|
|
101
105
|
/** Select or inspect a permission preset without requiring a pre-existing session. */
|
|
@@ -104,12 +108,20 @@ export interface AppProps {
|
|
|
104
108
|
exportTranscript(argument: string): Promise<void>;
|
|
105
109
|
/** Rename the session (/title <text>); returns the outcome line for the notice. */
|
|
106
110
|
renameTitle(argument: string): string;
|
|
111
|
+
/** Copy the latest complete assistant response; resolves to notice text. */
|
|
112
|
+
copyLastResponse(): Promise<string>;
|
|
113
|
+
/** Load a complete read-only Git diff for the file-oriented viewport. */
|
|
114
|
+
loadGitDiff(argument: string): Promise<GitDiffView>;
|
|
115
|
+
/** Start a model review after applying the read-only permission preset. */
|
|
116
|
+
reviewChanges(argument: string): void;
|
|
107
117
|
/** Preset/session/plugin kernel operations. */
|
|
108
118
|
loadPresets(): Promise<readonly PresetRow[]>;
|
|
109
119
|
switchMode(id: string): Promise<string>;
|
|
110
120
|
/** Load the switchable permission presets for the /permission panel. */
|
|
111
121
|
loadPermissions(): Promise<readonly PermissionRow[]>;
|
|
112
122
|
createSession(mode?: string): void;
|
|
123
|
+
/** Fork the active session at a completed-turn boundary. */
|
|
124
|
+
forkSession(argument: string): void;
|
|
113
125
|
loadSessions(options: SessionDirectoryOptions, signal?: AbortSignal): Promise<readonly SessionRow[]>;
|
|
114
126
|
loadSessionTranscript(id: string, signal?: AbortSignal): Promise<string>;
|
|
115
127
|
/** Load this session's subagent conversations (children by lineage). */
|
|
@@ -117,6 +129,8 @@ export interface AppProps {
|
|
|
117
129
|
switchSession(row: SessionRow): void;
|
|
118
130
|
cancelSessionSwitch(): boolean;
|
|
119
131
|
loadPlugins(): readonly PluginRow[];
|
|
132
|
+
/** Caller-visible background jobs (the host jobs registry, read-only). */
|
|
133
|
+
loadJobs(): readonly JobRow[];
|
|
120
134
|
/** Registers the app's notice channel with the runner (called once on mount). */
|
|
121
135
|
onBridgeReady(bridge: {
|
|
122
136
|
notify(text: string, tone?: NoticeTone): void;
|
|
@@ -134,6 +148,17 @@ export interface AppProps {
|
|
|
134
148
|
/** Cancel one queued inbox message by identity (Delete on the empty composer). */
|
|
135
149
|
cancelQueued(messageId: string): void;
|
|
136
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* One-row editor window keeping the logical cursor visible in long drafts.
|
|
153
|
+
* The caret and its surroundings slice at grapheme boundaries: splitting a
|
|
154
|
+
* star-plane surrogate pair would render an isolated half under the block
|
|
155
|
+
* caret with a width the terminal never draws.
|
|
156
|
+
*/
|
|
157
|
+
export declare function editorWindow(value: string, cursor: number, columns: number): {
|
|
158
|
+
before: string;
|
|
159
|
+
caret: string;
|
|
160
|
+
after: string;
|
|
161
|
+
};
|
|
137
162
|
/** One completion candidate row. */
|
|
138
163
|
interface CompletionCandidate {
|
|
139
164
|
/** Insertion text for the command name (with leading slash). */
|
|
@@ -141,7 +166,7 @@ interface CompletionCandidate {
|
|
|
141
166
|
/** Human-readable description shown beside the label. */
|
|
142
167
|
description: string;
|
|
143
168
|
/** Candidate origin; skills land the same literal text but route through the prompt. */
|
|
144
|
-
origin: 'command' | 'skill' | 'mention'
|
|
169
|
+
origin: 'command' | 'skill' | 'mention';
|
|
145
170
|
}
|
|
146
171
|
/**
|
|
147
172
|
* Resolve completion candidates for the current input: TUI-local commands,
|
|
@@ -163,14 +188,14 @@ interface SettledRowRecord {
|
|
|
163
188
|
before: ReactElement | undefined;
|
|
164
189
|
/** The roomy-prompt spacer AFTER the row, or undefined. */
|
|
165
190
|
after: ReactElement | undefined;
|
|
166
|
-
/**
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
showReasoning: boolean;
|
|
191
|
+
/** Physical rows this record contributes (row body plus spacers) — the
|
|
192
|
+
* unit of the rendered-history cap. */
|
|
193
|
+
rows: number;
|
|
170
194
|
}
|
|
171
195
|
/** The incremental settled-history cache (see `computeSettledRows`). */
|
|
172
196
|
interface SettledRowsCache {
|
|
173
|
-
/** The exact settled entries the cache covers (
|
|
197
|
+
/** The exact settled entries the cache covers (the WINDOW: the newest
|
|
198
|
+
* `entries.length` settled entries, oldest dropped entries excluded). */
|
|
174
199
|
entries: TranscriptEntry[];
|
|
175
200
|
/** Records keyed by entry identity; mutated in place so the append path
|
|
176
201
|
* never copies the whole map. */
|
|
@@ -181,10 +206,21 @@ interface SettledRowsCache {
|
|
|
181
206
|
resumed: boolean;
|
|
182
207
|
/** The toggle state the rows were built with. */
|
|
183
208
|
showReasoning: boolean;
|
|
184
|
-
/** The refreshEpoch the rows
|
|
209
|
+
/** The refreshEpoch the rows was built for; a bump forces a full rebuild. */
|
|
185
210
|
epoch: number;
|
|
186
|
-
/** The
|
|
211
|
+
/** The terminal width the rows were wrapped for; a change forces a rebuild. */
|
|
212
|
+
columns: number;
|
|
213
|
+
/** The flat row list (header + optional hint + per-entry before/box/after). */
|
|
187
214
|
flat: ReactElement[];
|
|
215
|
+
/** Settled entries dropped from the window's head (rendering only — the
|
|
216
|
+
* event log keeps everything; Ctrl+O and /export read it directly). */
|
|
217
|
+
droppedEntries: number;
|
|
218
|
+
/** Physical rows the window's entries contribute (excludes header/hint). */
|
|
219
|
+
totalRows: number;
|
|
220
|
+
/** The window overflowed the trim hysteresis; one source-backed replay
|
|
221
|
+
* (epoch bump) will re-window the cache. The append path never mutates
|
|
222
|
+
* flat's head, so <Static> only ever sees tail appends between remounts. */
|
|
223
|
+
needsTrim: boolean;
|
|
188
224
|
}
|
|
189
225
|
/** One step of `computeSettledRows`. */
|
|
190
226
|
interface SettledRowsResult {
|
|
@@ -205,13 +241,29 @@ interface SettledRowsResult {
|
|
|
205
241
|
* rebuild of rows, Map, or MarkdownBody parses). `records` is mutated in place
|
|
206
242
|
* on the append/toggle paths to stay O(delta).
|
|
207
243
|
*
|
|
244
|
+
* RENDERED-HISTORY CAP: the window holds at most `rowCap` physical rows of
|
|
245
|
+
* settled transcript (header and hint reserved on top). The cap exists only
|
|
246
|
+
* here — the event log, the store projection, /export, Ctrl+O, and /resume
|
|
247
|
+
* keep the full history. Ink 5's <Static> is a consumption counter
|
|
248
|
+
* (items.slice(index) keyed on length): deleting head items mid-stream while
|
|
249
|
+
* appending tail items can permanently swallow new rows, so the append branch
|
|
250
|
+
* NEVER drops the head — it only accounts rows and flags `needsTrim` once the
|
|
251
|
+
* window overflows cap + margin. The flag fires one source-backed replay
|
|
252
|
+
* (epoch bump = the existing clear + <Static> remount), whose rebuild branch
|
|
253
|
+
* walks the settled entries BACKWARD from the newest, keeps whole entries
|
|
254
|
+
* until the cap, and counts everything older as `droppedEntries` (those
|
|
255
|
+
* entries never even reach settledEntryLines). Hysteresis bounds replays to
|
|
256
|
+
* at most one per 25% growth; resize / Ctrl+L / idle Ctrl+R replays re-window
|
|
257
|
+
* for free on the same path.
|
|
258
|
+
*
|
|
208
259
|
* Full rebuilds run only on the rare, deliberate paths: no cache yet, a
|
|
209
|
-
* source-backed replay (`epoch` bump: resize / Ctrl+L / Ctrl+R
|
|
210
|
-
* `<Static>` and must re-flush the CURRENT rows
|
|
211
|
-
*
|
|
212
|
-
*
|
|
260
|
+
* source-backed replay (`epoch` bump: resize / Ctrl+L / an idle Ctrl+R fold
|
|
261
|
+
* toggle / a cap trim remounts `<Static>` and must re-flush the CURRENT rows
|
|
262
|
+
* at the CURRENT fold state), a `resumed` change, or a shrink (`store.reset`).
|
|
263
|
+
* While a turn is busy or streaming, Ctrl+R only flips the live region; rows
|
|
264
|
+
* already emitted to native scrollback change exclusively through rebuilds.
|
|
213
265
|
*/
|
|
214
|
-
export declare function computeSettledRows(previous: SettledRowsCache | undefined, entries: readonly TranscriptEntry[], settled: number, showReasoning: boolean, resumed: boolean, epoch: number): SettledRowsResult;
|
|
266
|
+
export declare function computeSettledRows(previous: SettledRowsCache | undefined, entries: readonly TranscriptEntry[], settled: number, showReasoning: boolean, resumed: boolean, epoch: number, columns?: number, rowCap?: number): SettledRowsResult;
|
|
215
267
|
/** The whole terminal app; state arrives via the store, output via Ink. */
|
|
216
268
|
export declare function App(props: AppProps): ReactElement;
|
|
217
269
|
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Terminal image-file adapter over the Harness durable attachment service. */
|
|
2
|
+
import type { AttachmentStore, ImageMediaType } from '@deepseek-ai/dsh-attachment';
|
|
3
|
+
import type { ImageBlock } from '@deepseek-ai/dsh-llm';
|
|
4
|
+
/** Detect the supported encoded raster formats from bytes, never from a path suffix. */
|
|
5
|
+
export declare function detectImageMediaType(data: Uint8Array): ImageMediaType | undefined;
|
|
6
|
+
/** Read, validate, and persist an ordered image path list as model content blocks. */
|
|
7
|
+
export declare function saveImagePaths(paths: readonly string[], attachments: AttachmentStore | undefined): Promise<readonly ImageBlock[]>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Host editor and clipboard adapters used by the terminal surface. */
|
|
2
|
+
import type { TranscriptView } from './render/projection.ts';
|
|
3
|
+
/** Copy UTF-8 text through the platform clipboard command. */
|
|
4
|
+
export declare function copyText(text: string): Promise<void>;
|
|
5
|
+
/** Latest complete assistant text, excluding streaming and reasoning. */
|
|
6
|
+
export declare function latestAssistantText(view: TranscriptView): string | undefined;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Pure session-fork boundary policy shared by the TUI command and tests. */
|
|
2
|
+
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
3
|
+
export interface ForkSeed {
|
|
4
|
+
readonly boundarySeq: number;
|
|
5
|
+
readonly events: readonly SessionEvent[];
|
|
6
|
+
}
|
|
7
|
+
/** Select a completed turn and trailing between-turn metadata. */
|
|
8
|
+
export declare function selectForkSeed(events: readonly SessionEvent[], atSeq?: number): ForkSeed;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Read-only Git inspection used by /diff and /review. */
|
|
2
|
+
export interface GitDiffSpec {
|
|
3
|
+
readonly label: string;
|
|
4
|
+
readonly args: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
/** One file section from a unified diff, retained in source order. */
|
|
7
|
+
export interface GitDiffFile {
|
|
8
|
+
readonly path: string;
|
|
9
|
+
readonly lines: readonly string[];
|
|
10
|
+
}
|
|
11
|
+
/** A parsed diff ready for a file-oriented terminal viewport. */
|
|
12
|
+
export interface GitDiffView {
|
|
13
|
+
readonly title: string;
|
|
14
|
+
readonly files: readonly GitDiffFile[];
|
|
15
|
+
}
|
|
16
|
+
/** Split Git's stable `diff --git` framing without interpreting patch content. */
|
|
17
|
+
export declare function parseGitDiffFiles(text: string): readonly GitDiffFile[];
|
|
18
|
+
/** Parse the intentionally small, option-safe /diff argument vocabulary. */
|
|
19
|
+
export declare function parseGitDiffSpec(argument: string): GitDiffSpec;
|
|
20
|
+
/** Load one complete textual diff without invoking external diff drivers. */
|
|
21
|
+
export declare function loadGitDiff(cwd: string, argument: string): Promise<GitDiffView>;
|
|
22
|
+
/** Review prompt capped before it reaches a provider context window. */
|
|
23
|
+
export declare function buildReviewPrompt(diff: string, label: string, maxChars?: number): string;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { Context } from '@deepseek-ai/cordis';
|
|
12
12
|
import z from '@deepseek-ai/schemastery';
|
|
13
|
+
import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session';
|
|
13
14
|
import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence';
|
|
14
15
|
import type { TuiStartup } from './startup.ts';
|
|
15
16
|
/** Stable Cordis plugin name. */
|
|
@@ -24,6 +25,8 @@ export interface Config {
|
|
|
24
25
|
sessionId?: string;
|
|
25
26
|
mode?: string;
|
|
26
27
|
theme?: string;
|
|
28
|
+
prompt?: string;
|
|
29
|
+
images?: string[];
|
|
27
30
|
};
|
|
28
31
|
}
|
|
29
32
|
export declare const Config: z<Config>;
|
|
@@ -33,6 +36,9 @@ interface Target {
|
|
|
33
36
|
resume: boolean;
|
|
34
37
|
mode?: string;
|
|
35
38
|
cwd?: string;
|
|
39
|
+
seed?: readonly SessionEvent[];
|
|
40
|
+
parentSession?: SessionId;
|
|
41
|
+
seedLength?: number;
|
|
36
42
|
}
|
|
37
43
|
/**
|
|
38
44
|
* Reduce a session id to a filename-safe /export default-name suffix. Session
|
|
@@ -7,6 +7,15 @@ import type { PresetRow } from './presets.ts';
|
|
|
7
7
|
import type { PluginRow } from './plugin-inventory.ts';
|
|
8
8
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
9
9
|
import { type StatusItemId } from './render/status.ts';
|
|
10
|
+
/**
|
|
11
|
+
* Apply one keystroke to a panel search query. IME commits arrive as one
|
|
12
|
+
* multi-character chunk, so the whole printable run is appended; paste
|
|
13
|
+
* markers are stripped and control-laden chunks are ignored.
|
|
14
|
+
*/
|
|
15
|
+
export declare function editQuery(query: string, input: string, key: {
|
|
16
|
+
backspace?: boolean;
|
|
17
|
+
delete?: boolean;
|
|
18
|
+
}): string | undefined;
|
|
10
19
|
export declare function ModePanel({ current, load, select, close }: {
|
|
11
20
|
current: string;
|
|
12
21
|
load(): Promise<readonly PresetRow[]>;
|
|
@@ -24,6 +33,36 @@ export declare function PluginPanel({ load, close, initialQuery }: {
|
|
|
24
33
|
close(): void;
|
|
25
34
|
initialQuery?: string;
|
|
26
35
|
}): ReactElement;
|
|
36
|
+
/** One background job snapshot for the /jobs panel (the registry's read-only view). */
|
|
37
|
+
export interface JobRow {
|
|
38
|
+
/** The registry-issued id (`<kind>-N`). */
|
|
39
|
+
readonly id: string;
|
|
40
|
+
/** Producer kind (bash, subagent, …). */
|
|
41
|
+
readonly kind: string;
|
|
42
|
+
/** One-line model-facing label (the command; the delegation description). */
|
|
43
|
+
readonly label: string;
|
|
44
|
+
/** Lifecycle state. */
|
|
45
|
+
readonly status: 'running' | 'stopping' | 'completed' | 'killed' | 'failed';
|
|
46
|
+
/** Kind-specific status detail once the producer supplied one. */
|
|
47
|
+
readonly detail?: string;
|
|
48
|
+
/** Epoch ms when the job was registered. */
|
|
49
|
+
readonly startedAt: number;
|
|
50
|
+
/** Epoch ms when the job settled; absent while running/stopping. */
|
|
51
|
+
readonly finishedAt?: number;
|
|
52
|
+
}
|
|
53
|
+
/** Web TurnStatus elapsed format: `45s` under a minute, `2m03s` beyond. */
|
|
54
|
+
export declare function runClock(ms: number): string;
|
|
55
|
+
/**
|
|
56
|
+
* The read-only background-job panel: caller-owned and unowned jobs from the
|
|
57
|
+
* host `jobs` registry in registration order, with a local second-hand while
|
|
58
|
+
* the panel is open (elapsed clocks advance and the snapshot re-reads; the
|
|
59
|
+
* interval dies with the panel). Cancel stays upstream-only; an absent
|
|
60
|
+
* registry renders as the plain empty state (a harmless missing service).
|
|
61
|
+
*/
|
|
62
|
+
export declare function JobsPanel({ load, close }: {
|
|
63
|
+
load(): readonly JobRow[];
|
|
64
|
+
close(): void;
|
|
65
|
+
}): ReactElement;
|
|
27
66
|
export declare function ResumePanel({ currentCwd, load, readTranscript, select, requestDelete, deleteConfirmId, reloadToken, deleteMode, close }: {
|
|
28
67
|
currentCwd: string;
|
|
29
68
|
load(options: SessionDirectoryOptions, signal?: AbortSignal): Promise<readonly SessionRow[]>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard enhancement protocol (Codex `keyboard_modes` parity) and the
|
|
3
|
+
* kitty CSI-u normalization layer.
|
|
4
|
+
*
|
|
5
|
+
* The TUI pushes the kitty keyboard protocol with DISAMBIGUATE_ESCAPE_CODES
|
|
6
|
+
* and REPORT_ALTERNATE_KEYS (flags 1|4 = `\x1b[>5u`), which makes terminals
|
|
7
|
+
* report Shift+Enter as `CSI 13;2u` instead of a bare CR. Event types are
|
|
8
|
+
* deliberately NOT requested: Ink 5's parser cannot decode the
|
|
9
|
+
* `:event-type` suffix, and repeat/release reporting buys this surface
|
|
10
|
+
* nothing.
|
|
11
|
+
*
|
|
12
|
+
* Ink 5 also cannot parse most CSI-u forms at all — they fall through its
|
|
13
|
+
* regex as unnamed sequences and get INSERTED AS DRAFT TEXT. The composer's
|
|
14
|
+
* stdin read patch therefore rewrites every CSI-u form it can decode back
|
|
15
|
+
* to the legacy byte or canonical sequence the existing key handling
|
|
16
|
+
* already understands, before Ink ever parses the chunk.
|
|
17
|
+
*
|
|
18
|
+
* @module @deepseek-ai/dsh-code/keyboard
|
|
19
|
+
*/
|
|
20
|
+
/** Push keyboard enhancement (modifyOtherKeys off, kitty flags 1|4). */
|
|
21
|
+
export declare const KEYBOARD_ENHANCE_ENABLE = "\u001B[>4;0m\u001B[>5u";
|
|
22
|
+
/** Pop the enhancement stack and reset modifyOtherKeys (exit path). */
|
|
23
|
+
export declare const KEYBOARD_ENHANCE_DISABLE = "\u001B[<u\u001B[>4;0m";
|
|
24
|
+
/** Enable bracketed paste reporting. */
|
|
25
|
+
export declare const BRACKETED_PASTE_ENABLE = "\u001B[?2004h";
|
|
26
|
+
/** Disable bracketed paste reporting. */
|
|
27
|
+
export declare const BRACKETED_PASTE_DISABLE = "\u001B[?2004l";
|
|
28
|
+
/** Bracketed paste markers as Ink delivers them (it strips the leading ESC). */
|
|
29
|
+
export declare const PASTE_START_MARKER = "[200~";
|
|
30
|
+
export declare const PASTE_END_MARKER = "[201~";
|
|
31
|
+
/**
|
|
32
|
+
* Remove bracketed paste markers from one input chunk. Panel drafts accept raw
|
|
33
|
+
* `input` text, where an unhandled paste would otherwise persist the literal
|
|
34
|
+
* "[200~"/"[201~" markers Ink leaves after stripping the ESC byte.
|
|
35
|
+
*/
|
|
36
|
+
export declare function stripPasteMarkers(text: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Rewrite every decodable kitty CSI-u sequence in one stdin chunk to the
|
|
39
|
+
* legacy form the input layer already handles. Undecodable or non-key
|
|
40
|
+
* sequences pass through untouched, so terminals without the protocol are
|
|
41
|
+
* unaffected.
|
|
42
|
+
*/
|
|
43
|
+
export declare function normalizeKeyboardChunk(chunk: string): string;
|
package/lib/types/mentions.d.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workspace @mention support: file and directory candidates from
|
|
3
|
-
*
|
|
4
|
-
* `sessionReferenceResolver` service, and submission
|
|
5
|
-
* `prepare()` API. Picked session mentions land as
|
|
6
|
-
* `@[label](dsh-session:…)` tokens; on submit the text is parsed
|
|
7
|
-
* readable `@label` text plus structured references, snapshots are
|
|
8
|
-
* via `agent.inject()` before the readable message wakes the driver
|
|
2
|
+
* Workspace @mention support: file and directory candidates from the
|
|
3
|
+
* `fileReferences` service (dsh-file-reference-local), session candidates
|
|
4
|
+
* from the opt-in `sessionReferenceResolver` service, and submission
|
|
5
|
+
* preparation through its `prepare()` API. Picked session mentions land as
|
|
6
|
+
* canonical `@[label](dsh-session:…)` tokens; on submit the text is parsed
|
|
7
|
+
* back into readable `@label` text plus structured references, snapshots are
|
|
8
|
+
* injected via `agent.inject()` before the readable message wakes the driver
|
|
9
9
|
* (`followup` idle, `steer` running) — exactly the upstream README's wiring.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* File discovery lives entirely in the Harness service (per-agent bounded
|
|
12
|
+
* index, `@dir/` listing, symlink guards, tool/result invalidation); this
|
|
13
|
+
* module only maps candidates to menu rows and never re-implements scanning.
|
|
14
|
+
* The service is agent-scoped (the agent supplies the session cwd and the
|
|
15
|
+
* cache key), so before the first session creates an agent the SAME official
|
|
16
|
+
* search class runs against the launch cwd — @ file completion works on a
|
|
17
|
+
* bare launch, model- and session-independent, and the agent-scoped service
|
|
18
|
+
* takes over once a session exists.
|
|
15
19
|
*
|
|
16
20
|
* @module @deepseek-ai/dsh-code/mentions
|
|
17
21
|
*/
|
|
@@ -20,13 +24,6 @@ import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
|
20
24
|
import { parseSessionReferenceText, type SessionReferenceCandidate, type SessionReferenceInput } from '@deepseek-ai/dsh-session-reference';
|
|
21
25
|
/** Parsed submission text: readable text plus structured references. */
|
|
22
26
|
type ParsedSessionReferenceText = ReturnType<typeof parseSessionReferenceText>;
|
|
23
|
-
/** One filesystem entry the @ menu can complete. */
|
|
24
|
-
export interface FileCandidate {
|
|
25
|
-
/** Workspace-relative path with forward slashes. */
|
|
26
|
-
path: string;
|
|
27
|
-
/** Entry kind; directories insert with a trailing slash. */
|
|
28
|
-
kind: 'file' | 'directory';
|
|
29
|
-
}
|
|
30
27
|
/** One merged menu candidate (files and sessions, already ranked). */
|
|
31
28
|
export interface MentionCandidate {
|
|
32
29
|
/** Text inserted after the `@` (directories carry a trailing slash). */
|
|
@@ -45,18 +42,8 @@ export interface PreparedMention {
|
|
|
45
42
|
/** Aggregated snapshot for `agent.inject()`, undefined without references. */
|
|
46
43
|
additionalContext?: import('@deepseek-ai/dsh-session').UserMessage;
|
|
47
44
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Bounded async BFS scan of a workspace; unreadable entries are skipped.
|
|
50
|
-
* Both files and directories are indexed (directories insert with a trailing
|
|
51
|
-
* slash), mirroring Codex's `MatchType::{File,Directory}` index. Dotfiles and
|
|
52
|
-
* the {@link SKIP_DIRS} list are excluded, which is a coarser filter than
|
|
53
|
-
* Codex's gitignore-aware walker but stays dependency-free and bounded.
|
|
54
|
-
*/
|
|
55
|
-
export declare function scanWorkspaceFiles(root: string, signal?: AbortSignal): Promise<readonly FileCandidate[]>;
|
|
56
45
|
/** The mention API the input editor and the runner share. */
|
|
57
46
|
export interface MentionsApi {
|
|
58
|
-
/** Scanned workspace files and directories, cached across one session. */
|
|
59
|
-
files(): Promise<readonly FileCandidate[]>;
|
|
60
47
|
/** Ranked menu candidates for the typed `@` query. */
|
|
61
48
|
candidates(query: string, signal?: AbortSignal): Promise<readonly MentionCandidate[]>;
|
|
62
49
|
/** Parse submission text into readable text plus structured references. */
|
|
@@ -71,17 +58,20 @@ export interface MentionsApi {
|
|
|
71
58
|
}
|
|
72
59
|
/**
|
|
73
60
|
* Create the mention API for one agent's workspace. A missing
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* (a bare launch before any session
|
|
77
|
-
*
|
|
61
|
+
* `fileReferences` service (with an agent present) or `sessionReferenceResolver`
|
|
62
|
+
* degrades that half to empty rows; `prepare` passes text through untouched
|
|
63
|
+
* without references. An undefined agent (a bare launch before any session
|
|
64
|
+
* exists) runs the official WorkspaceFileSearch over the launch cwd — the
|
|
65
|
+
* same class the mounted service uses per agent — so `@` file completion
|
|
66
|
+
* works from the first keystroke; session references wait for the session.
|
|
78
67
|
*
|
|
79
|
-
* `
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* @param ctx - context carrying the optional `
|
|
83
|
-
*
|
|
84
|
-
* @param
|
|
68
|
+
* `candidates` never reaches for `this` — the runner hands it to the input
|
|
69
|
+
* editor as a detached callback, and a `this`-bound method would throw on
|
|
70
|
+
* every `@` key.
|
|
71
|
+
* @param ctx - context carrying the optional `fileReferences` and
|
|
72
|
+
* `sessionReferenceResolver` services.
|
|
73
|
+
* @param agent - the session owner; excluded from its own session candidates.
|
|
74
|
+
* @param cwd - launch working directory; bounds the pre-session search.
|
|
85
75
|
*/
|
|
86
76
|
export declare function createMentions(ctx: Context, agent: Agent | undefined, cwd: string): MentionsApi;
|
|
87
77
|
export {};
|
package/lib/types/presets.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Agent-preset policy kept independent from the Ink surface. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
-
import type { Agent
|
|
3
|
+
import type { Agent } from '@deepseek-ai/dsh-agent';
|
|
4
4
|
import type { Session, SessionEvent } from '@deepseek-ai/dsh-session';
|
|
5
5
|
/** One discoverable agent composition. */
|
|
6
6
|
export interface PresetRow {
|
|
@@ -30,5 +30,3 @@ export declare function resolvePreset(session: Pick<Session, 'header' | 'events'
|
|
|
30
30
|
export declare function selectPreset(service: AgentPresetsService, agent: Agent | undefined, presetId: string): Promise<PresetRow>;
|
|
31
31
|
/** Recompose atomically from the caller's perspective, logging only success. */
|
|
32
32
|
export declare function switchPreset(service: AgentPresetsService, agent: Agent, presetId: string): Promise<PresetRow>;
|
|
33
|
-
/** Minimal handle shape used by lifecycle tests without exposing Agent internals. */
|
|
34
|
-
export type OwnedAgent = Pick<AgentHandle, 'agent' | 'dispose'>;
|
|
@@ -42,6 +42,18 @@ export type ProviderCredentialView = ({
|
|
|
42
42
|
readonly kind: 'error';
|
|
43
43
|
readonly message: string;
|
|
44
44
|
};
|
|
45
|
+
/** One explicit model enabled for a provider profile. */
|
|
46
|
+
export interface ProviderModelSettings {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
readonly name?: string;
|
|
49
|
+
readonly contextWindow?: number;
|
|
50
|
+
readonly maxTokens?: number;
|
|
51
|
+
}
|
|
52
|
+
/** The small, portable subset of a provider profile the terminal edits. */
|
|
53
|
+
export interface ProviderConfiguration {
|
|
54
|
+
readonly baseURL?: string;
|
|
55
|
+
readonly models: readonly ProviderModelSettings[];
|
|
56
|
+
}
|
|
45
57
|
/**
|
|
46
58
|
* One provider row in the TUI provider-management panel: the configurable
|
|
47
59
|
* directory entry joined with its settings profile and credential facts.
|
|
@@ -71,6 +83,8 @@ export interface ProviderTargetView {
|
|
|
71
83
|
readonly suggestedRef: string;
|
|
72
84
|
/** Credential facts, a bounded describe error, or undefined when there is no ref to describe. */
|
|
73
85
|
readonly credential: ProviderCredentialView | undefined;
|
|
86
|
+
/** Endpoint and explicit model overrides visible to the provider editor. */
|
|
87
|
+
readonly configuration: ProviderConfiguration;
|
|
74
88
|
/** The owning adapter reports this route as hand-declared (absent when it draws no distinction). */
|
|
75
89
|
readonly declared?: boolean;
|
|
76
90
|
}
|
|
@@ -120,6 +134,8 @@ export declare function loadProviderSettings(ctx: Context): Promise<ProviderSett
|
|
|
120
134
|
* @throws {@link ProviderSettingsError} with a single-line, key-free message.
|
|
121
135
|
*/
|
|
122
136
|
export declare function saveProviderCredential(ctx: Context, target: ProviderTargetView, rawKey: string): Promise<void>;
|
|
137
|
+
/** Save the endpoint and an explicit model allow-list without rebuilding the profile. */
|
|
138
|
+
export declare function saveProviderConfiguration(ctx: Context, target: ProviderTargetView, configuration: ProviderConfiguration): Promise<void>;
|
|
123
139
|
/**
|
|
124
140
|
* Remove the currently named credential without touching the provider
|
|
125
141
|
* profile. Only the resolved profile's own reference is unset; a dormant or
|