dsh-code 0.9.1 → 1.0.1
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 +278 -249
- package/README.md +131 -102
- package/bin/deepseek.mjs +100 -6
- package/cordis.patch.yml +36 -1
- package/lib/index.mjs +3055 -819
- package/lib/startup.mjs +21 -11
- package/lib/{theme-BEi4i_aN.mjs → theme-DCT8Y2xf.mjs} +13 -9
- package/lib/types/app.d.ts +84 -16
- package/lib/types/attachments.d.ts +20 -0
- package/lib/types/authorization-panel.d.ts +22 -0
- package/lib/types/authorization.d.ts +36 -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 +41 -0
- package/lib/types/mentions.d.ts +30 -38
- package/lib/types/models.d.ts +3 -1
- package/lib/types/permissions.d.ts +4 -14
- package/lib/types/presets.d.ts +5 -20
- package/lib/types/provider-settings.d.ts +16 -0
- package/lib/types/render/animations.d.ts +10 -39
- package/lib/types/render/editor.d.ts +137 -0
- package/lib/types/render/export.d.ts +1 -1
- package/lib/types/render/lines.d.ts +6 -2
- package/lib/types/render/markdown.d.ts +3 -1
- package/lib/types/render/projection.d.ts +29 -3
- package/lib/types/render/status.d.ts +6 -13
- 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 +159 -141
- package/src/app.ts +1490 -663
- package/src/attachments.ts +128 -0
- package/src/authorization-panel.ts +285 -0
- package/src/authorization.ts +147 -0
- package/src/editor.ts +51 -0
- package/src/fork.ts +31 -0
- package/src/git-workflow.ts +87 -0
- package/src/index.ts +1523 -1374
- package/src/internals.ts +14 -1
- package/src/kernel-panels.ts +914 -798
- package/src/keyboard.ts +126 -0
- package/src/mentions.ts +78 -117
- package/src/models.ts +20 -14
- package/src/permissions.ts +5 -13
- package/src/presets.ts +6 -22
- package/src/provider-settings.ts +95 -1
- package/src/render/animations.ts +420 -450
- 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 +106 -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 +4 -4
- 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
|
@@ -15,21 +15,27 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { type ReactElement } from 'react';
|
|
17
17
|
import type { CommandDescriptor } from '@deepseek-ai/dsh-commands';
|
|
18
|
+
import type { ImageBlock } from '@deepseek-ai/dsh-llm';
|
|
19
|
+
import type { AuthorizationInteraction, AuthorizationStatus } from '@deepseek-ai/dsh-authorization';
|
|
18
20
|
import { type ThemeName } from './theme.ts';
|
|
19
21
|
import type { TranscriptStore } from './store.ts';
|
|
20
22
|
import { type TranscriptEntry } from './render/projection.ts';
|
|
21
23
|
import type { ApprovalStore } from './approval.ts';
|
|
22
24
|
import type { CommandsView } from './commands.ts';
|
|
23
25
|
import type { ModelDirectory, ModelRow } from './models.ts';
|
|
24
|
-
import type { ProviderSettingsDirectory, ProviderTargetView } from './provider-settings.ts';
|
|
26
|
+
import type { ProviderConfiguration, ProviderSettingsDirectory, ProviderTargetView } from './provider-settings.ts';
|
|
25
27
|
import type { QuestionStore } from './questions.ts';
|
|
26
28
|
import type { SkillsView, SkillRow } from './skills.ts';
|
|
27
29
|
import type { MentionCandidate } from './mentions.ts';
|
|
28
30
|
import type { SubagentFeedView } from './subagents.ts';
|
|
31
|
+
import { type JobRow } from './kernel-panels.ts';
|
|
29
32
|
import type { PresetRow } from './presets.ts';
|
|
30
33
|
import type { PermissionRow } from './permissions.ts';
|
|
31
34
|
import type { PluginRow } from './plugin-inventory.ts';
|
|
32
35
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
36
|
+
import type { GitDiffView } from './git-workflow.ts';
|
|
37
|
+
import { type ProviderAuthorizationDirectory, type ProviderAuthorizationRow } from './authorization.ts';
|
|
38
|
+
import { type ImagePathInspection } from './attachments.ts';
|
|
33
39
|
/** Visual priority for one bounded local notice. */
|
|
34
40
|
export type NoticeTone = 'info' | 'warning' | 'error';
|
|
35
41
|
/** Props the runner hands the app; callbacks stay owned by the runner. */
|
|
@@ -65,9 +71,9 @@ export interface AppProps {
|
|
|
65
71
|
/** Permission preset selected for the current or pending first session. */
|
|
66
72
|
permission: string;
|
|
67
73
|
/** Submit one line: slash commands to the registry, other text to the agent. */
|
|
68
|
-
dispatch(text: string): void;
|
|
74
|
+
dispatch(text: string, images?: readonly ImageBlock[]): void;
|
|
69
75
|
/** Submit steering: consumed at the running turn's next step boundary. */
|
|
70
|
-
steer(text: string): void;
|
|
76
|
+
steer(text: string, images?: readonly ImageBlock[]): void;
|
|
71
77
|
/** Interrupt the running turn (Esc); true when a turn was cancelled. */
|
|
72
78
|
interrupt(): boolean;
|
|
73
79
|
/** Quit: unmount, flush, and request process exit. */
|
|
@@ -76,6 +82,10 @@ export interface AppProps {
|
|
|
76
82
|
loadModels(): Promise<ModelDirectory>;
|
|
77
83
|
/** Load @mention candidates for the typed query (files + sessions). */
|
|
78
84
|
loadMentions(query: string, signal?: AbortSignal): Promise<readonly MentionCandidate[]>;
|
|
85
|
+
/** Validate draft image paths without committing attachment objects. */
|
|
86
|
+
inspectImages(paths: readonly string[]): Promise<readonly ImagePathInspection[]>;
|
|
87
|
+
/** Validate, normalize and persist images immediately before submission. */
|
|
88
|
+
prepareImages(paths: readonly string[]): Promise<readonly ImageBlock[]>;
|
|
79
89
|
/** Apply one /model selection (with an advertised reasoning effort, when picked); returns the display label. */
|
|
80
90
|
selectModel(row: ModelRow, effortId?: string): string;
|
|
81
91
|
/** The /subagent override label, '' when delegated agents follow the current model. */
|
|
@@ -96,6 +106,16 @@ export interface AppProps {
|
|
|
96
106
|
unsetModelProviderCredential?(target: ProviderTargetView): Promise<void>;
|
|
97
107
|
/** Remove one user-owned provider profile and its page-managed credential. */
|
|
98
108
|
removeModelProvider?(target: ProviderTargetView): Promise<void>;
|
|
109
|
+
/** Save endpoint and explicit model capacities through the provider profile. */
|
|
110
|
+
saveModelProviderConfiguration?(target: ProviderTargetView, configuration: ProviderConfiguration): Promise<void>;
|
|
111
|
+
/** Provider authorization flows and value-free stored-record facts. */
|
|
112
|
+
loadProviderAuthorizations?(): Promise<ProviderAuthorizationDirectory>;
|
|
113
|
+
subscribeProviderAuthorizations?(listener: () => void): () => void;
|
|
114
|
+
beginProviderAuthorization?(row: ProviderAuthorizationRow, method: string, interaction: AuthorizationInteraction, signal: AbortSignal): Promise<AuthorizationStatus>;
|
|
115
|
+
cancelProviderAuthorization?(row: ProviderAuthorizationRow): void;
|
|
116
|
+
logoutProviderAuthorization?(row: ProviderAuthorizationRow): Promise<void>;
|
|
117
|
+
openAuthorizationUrl?(url: string): boolean;
|
|
118
|
+
copyTextValue?(text: string): Promise<void>;
|
|
99
119
|
/** Cycle to the next permission preset (Shift+Tab); returns the new label. */
|
|
100
120
|
cyclePermission(): string;
|
|
101
121
|
/** Select or inspect a permission preset without requiring a pre-existing session. */
|
|
@@ -104,12 +124,20 @@ export interface AppProps {
|
|
|
104
124
|
exportTranscript(argument: string): Promise<void>;
|
|
105
125
|
/** Rename the session (/title <text>); returns the outcome line for the notice. */
|
|
106
126
|
renameTitle(argument: string): string;
|
|
127
|
+
/** Copy the latest complete assistant response; resolves to notice text. */
|
|
128
|
+
copyLastResponse(): Promise<string>;
|
|
129
|
+
/** Load a complete read-only Git diff for the file-oriented viewport. */
|
|
130
|
+
loadGitDiff(argument: string): Promise<GitDiffView>;
|
|
131
|
+
/** Start a model review after applying the read-only permission preset. */
|
|
132
|
+
reviewChanges(argument: string): void;
|
|
107
133
|
/** Preset/session/plugin kernel operations. */
|
|
108
134
|
loadPresets(): Promise<readonly PresetRow[]>;
|
|
109
135
|
switchMode(id: string): Promise<string>;
|
|
110
136
|
/** Load the switchable permission presets for the /permission panel. */
|
|
111
137
|
loadPermissions(): Promise<readonly PermissionRow[]>;
|
|
112
138
|
createSession(mode?: string): void;
|
|
139
|
+
/** Fork the active session at a completed-turn boundary. */
|
|
140
|
+
forkSession(argument: string): void;
|
|
113
141
|
loadSessions(options: SessionDirectoryOptions, signal?: AbortSignal): Promise<readonly SessionRow[]>;
|
|
114
142
|
loadSessionTranscript(id: string, signal?: AbortSignal): Promise<string>;
|
|
115
143
|
/** Load this session's subagent conversations (children by lineage). */
|
|
@@ -117,6 +145,8 @@ export interface AppProps {
|
|
|
117
145
|
switchSession(row: SessionRow): void;
|
|
118
146
|
cancelSessionSwitch(): boolean;
|
|
119
147
|
loadPlugins(): readonly PluginRow[];
|
|
148
|
+
/** Caller-visible background jobs (the host jobs registry, read-only). */
|
|
149
|
+
loadJobs(): readonly JobRow[];
|
|
120
150
|
/** Registers the app's notice channel with the runner (called once on mount). */
|
|
121
151
|
onBridgeReady(bridge: {
|
|
122
152
|
notify(text: string, tone?: NoticeTone): void;
|
|
@@ -134,6 +164,17 @@ export interface AppProps {
|
|
|
134
164
|
/** Cancel one queued inbox message by identity (Delete on the empty composer). */
|
|
135
165
|
cancelQueued(messageId: string): void;
|
|
136
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* One-row editor window keeping the logical cursor visible in long drafts.
|
|
169
|
+
* The caret and its surroundings slice at grapheme boundaries: splitting a
|
|
170
|
+
* star-plane surrogate pair would render an isolated half under the block
|
|
171
|
+
* caret with a width the terminal never draws.
|
|
172
|
+
*/
|
|
173
|
+
export declare function editorWindow(value: string, cursor: number, columns: number): {
|
|
174
|
+
before: string;
|
|
175
|
+
caret: string;
|
|
176
|
+
after: string;
|
|
177
|
+
};
|
|
137
178
|
/** One completion candidate row. */
|
|
138
179
|
interface CompletionCandidate {
|
|
139
180
|
/** Insertion text for the command name (with leading slash). */
|
|
@@ -141,7 +182,7 @@ interface CompletionCandidate {
|
|
|
141
182
|
/** Human-readable description shown beside the label. */
|
|
142
183
|
description: string;
|
|
143
184
|
/** Candidate origin; skills land the same literal text but route through the prompt. */
|
|
144
|
-
origin: 'command' | 'skill' | 'mention'
|
|
185
|
+
origin: 'command' | 'skill' | 'mention';
|
|
145
186
|
}
|
|
146
187
|
/**
|
|
147
188
|
* Resolve completion candidates for the current input: TUI-local commands,
|
|
@@ -163,14 +204,14 @@ interface SettledRowRecord {
|
|
|
163
204
|
before: ReactElement | undefined;
|
|
164
205
|
/** The roomy-prompt spacer AFTER the row, or undefined. */
|
|
165
206
|
after: ReactElement | undefined;
|
|
166
|
-
/**
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
showReasoning: boolean;
|
|
207
|
+
/** Physical rows this record contributes (row body plus spacers) — the
|
|
208
|
+
* unit of the rendered-history cap. */
|
|
209
|
+
rows: number;
|
|
170
210
|
}
|
|
171
211
|
/** The incremental settled-history cache (see `computeSettledRows`). */
|
|
172
212
|
interface SettledRowsCache {
|
|
173
|
-
/** The exact settled entries the cache covers (
|
|
213
|
+
/** The exact settled entries the cache covers (the WINDOW: the newest
|
|
214
|
+
* `entries.length` settled entries, oldest dropped entries excluded). */
|
|
174
215
|
entries: TranscriptEntry[];
|
|
175
216
|
/** Records keyed by entry identity; mutated in place so the append path
|
|
176
217
|
* never copies the whole map. */
|
|
@@ -181,10 +222,21 @@ interface SettledRowsCache {
|
|
|
181
222
|
resumed: boolean;
|
|
182
223
|
/** The toggle state the rows were built with. */
|
|
183
224
|
showReasoning: boolean;
|
|
184
|
-
/** The refreshEpoch the rows
|
|
225
|
+
/** The refreshEpoch the rows was built for; a bump forces a full rebuild. */
|
|
185
226
|
epoch: number;
|
|
186
|
-
/** The
|
|
227
|
+
/** The terminal width the rows were wrapped for; a change forces a rebuild. */
|
|
228
|
+
columns: number;
|
|
229
|
+
/** The flat row list (header + optional hint + per-entry before/box/after). */
|
|
187
230
|
flat: ReactElement[];
|
|
231
|
+
/** Settled entries dropped from the window's head (rendering only — the
|
|
232
|
+
* event log keeps everything; Ctrl+O and /export read it directly). */
|
|
233
|
+
droppedEntries: number;
|
|
234
|
+
/** Physical rows the window's entries contribute (excludes header/hint). */
|
|
235
|
+
totalRows: number;
|
|
236
|
+
/** The window overflowed the trim hysteresis; one source-backed replay
|
|
237
|
+
* (epoch bump) will re-window the cache. The append path never mutates
|
|
238
|
+
* flat's head, so <Static> only ever sees tail appends between remounts. */
|
|
239
|
+
needsTrim: boolean;
|
|
188
240
|
}
|
|
189
241
|
/** One step of `computeSettledRows`. */
|
|
190
242
|
interface SettledRowsResult {
|
|
@@ -205,13 +257,29 @@ interface SettledRowsResult {
|
|
|
205
257
|
* rebuild of rows, Map, or MarkdownBody parses). `records` is mutated in place
|
|
206
258
|
* on the append/toggle paths to stay O(delta).
|
|
207
259
|
*
|
|
260
|
+
* RENDERED-HISTORY CAP: the window holds at most `rowCap` physical rows of
|
|
261
|
+
* settled transcript (header and hint reserved on top). The cap exists only
|
|
262
|
+
* here — the event log, the store projection, /export, Ctrl+O, and /resume
|
|
263
|
+
* keep the full history. Ink 5's <Static> is a consumption counter
|
|
264
|
+
* (items.slice(index) keyed on length): deleting head items mid-stream while
|
|
265
|
+
* appending tail items can permanently swallow new rows, so the append branch
|
|
266
|
+
* NEVER drops the head — it only accounts rows and flags `needsTrim` once the
|
|
267
|
+
* window overflows cap + margin. The flag fires one source-backed replay
|
|
268
|
+
* (epoch bump = the existing clear + <Static> remount), whose rebuild branch
|
|
269
|
+
* walks the settled entries BACKWARD from the newest, keeps whole entries
|
|
270
|
+
* until the cap, and counts everything older as `droppedEntries` (those
|
|
271
|
+
* entries never even reach settledEntryLines). Hysteresis bounds replays to
|
|
272
|
+
* at most one per 25% growth; resize / Ctrl+L / idle Ctrl+R replays re-window
|
|
273
|
+
* for free on the same path.
|
|
274
|
+
*
|
|
208
275
|
* 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
|
-
*
|
|
276
|
+
* source-backed replay (`epoch` bump: resize / Ctrl+L / an idle Ctrl+R fold
|
|
277
|
+
* toggle / a cap trim remounts `<Static>` and must re-flush the CURRENT rows
|
|
278
|
+
* at the CURRENT fold state), a `resumed` change, or a shrink (`store.reset`).
|
|
279
|
+
* While a turn is busy or streaming, Ctrl+R only flips the live region; rows
|
|
280
|
+
* already emitted to native scrollback change exclusively through rebuilds.
|
|
213
281
|
*/
|
|
214
|
-
export declare function computeSettledRows(previous: SettledRowsCache | undefined, entries: readonly TranscriptEntry[], settled: number, showReasoning: boolean, resumed: boolean, epoch: number): SettledRowsResult;
|
|
282
|
+
export declare function computeSettledRows(previous: SettledRowsCache | undefined, entries: readonly TranscriptEntry[], settled: number, showReasoning: boolean, resumed: boolean, epoch: number, columns?: number, rowCap?: number): SettledRowsResult;
|
|
215
283
|
/** The whole terminal app; state arrives via the store, output via Ink. */
|
|
216
284
|
export declare function App(props: AppProps): ReactElement;
|
|
217
285
|
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
/** A validated path retained in the editor until submission persists it. */
|
|
5
|
+
export interface ImagePathInspection {
|
|
6
|
+
readonly path: string;
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly mediaType: ImageMediaType;
|
|
9
|
+
readonly bytes: number;
|
|
10
|
+
}
|
|
11
|
+
/** Detect the supported encoded raster formats from bytes, never from a path suffix. */
|
|
12
|
+
export declare function detectImageMediaType(data: Uint8Array): ImageMediaType | undefined;
|
|
13
|
+
/** Whether a path-like token is worth probing as an image attachment. */
|
|
14
|
+
export declare function looksLikeImagePath(path: string): boolean;
|
|
15
|
+
/** Parse a terminal paste/drop containing only one or more image paths. */
|
|
16
|
+
export declare function parsePastedImagePaths(input: string): readonly string[];
|
|
17
|
+
/** Validate path, byte size and encoded signature without writing an attachment object. */
|
|
18
|
+
export declare function inspectImagePaths(paths: readonly string[], attachments: AttachmentStore | undefined, cwd?: string): Promise<readonly ImagePathInspection[]>;
|
|
19
|
+
/** Read, validate, and persist an ordered image path list as model content blocks. */
|
|
20
|
+
export declare function saveImagePaths(paths: readonly string[], attachments: AttachmentStore | undefined): Promise<readonly ImageBlock[]>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Bounded Ink surfaces for provider login and logout. */
|
|
2
|
+
import { type ReactElement } from 'react';
|
|
3
|
+
import { type AuthorizationInteraction, type AuthorizationStatus } from '@deepseek-ai/dsh-authorization';
|
|
4
|
+
import type { CredentialKey } from '@deepseek-ai/dsh-credentials';
|
|
5
|
+
import type { ProviderAuthorizationRow } from './authorization.ts';
|
|
6
|
+
export interface ProviderAuthorizationPanelProps {
|
|
7
|
+
readonly row: ProviderAuthorizationRow;
|
|
8
|
+
begin(row: ProviderAuthorizationRow, method: string, interaction: AuthorizationInteraction, signal: AbortSignal): Promise<AuthorizationStatus>;
|
|
9
|
+
cancel(key: CredentialKey): void;
|
|
10
|
+
openUrl(url: string): boolean;
|
|
11
|
+
copy(text: string): Promise<void>;
|
|
12
|
+
done(): void;
|
|
13
|
+
back(): void;
|
|
14
|
+
}
|
|
15
|
+
/** Run one upstream authorization flow without letting notices or prompts exceed the panel budget. */
|
|
16
|
+
export declare function ProviderAuthorizationPanel(props: ProviderAuthorizationPanelProps): ReactElement;
|
|
17
|
+
export declare function ProviderAuthorizationLogoutPanel({ row, confirm, done, back }: {
|
|
18
|
+
row: ProviderAuthorizationRow;
|
|
19
|
+
confirm(row: ProviderAuthorizationRow): Promise<void>;
|
|
20
|
+
done(): void;
|
|
21
|
+
back(): void;
|
|
22
|
+
}): ReactElement;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Terminal adapter over the Harness provider-authorization and credential-record seams. */
|
|
2
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { AuthorizationEntry, AuthorizationInteraction, AuthorizationMethod, AuthorizationStatus } from '@deepseek-ai/dsh-authorization';
|
|
4
|
+
import { type CredentialKey, type CredentialRecordInfo } from '@deepseek-ai/dsh-credentials';
|
|
5
|
+
/** One provider login flow joined with its value-free stored-record facts. */
|
|
6
|
+
export interface ProviderAuthorizationRow {
|
|
7
|
+
readonly key: CredentialKey;
|
|
8
|
+
readonly provider: string;
|
|
9
|
+
readonly label: string;
|
|
10
|
+
readonly methods: readonly AuthorizationMethod[];
|
|
11
|
+
readonly inFlight: boolean;
|
|
12
|
+
readonly record: CredentialRecordInfo;
|
|
13
|
+
}
|
|
14
|
+
/** The provider-login directory plus non-fatal record lookup failures. */
|
|
15
|
+
export interface ProviderAuthorizationDirectory {
|
|
16
|
+
readonly rows: readonly ProviderAuthorizationRow[];
|
|
17
|
+
readonly failures: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
/** Load only model-provider flows; unrelated future authorization domains stay out of `/model`. */
|
|
20
|
+
export declare function loadProviderAuthorizations(ctx: Context): Promise<ProviderAuthorizationDirectory>;
|
|
21
|
+
/** Subscribe to login settlement and credential-record changes. */
|
|
22
|
+
export declare function subscribeProviderAuthorizations(ctx: Context, listener: () => void): () => void;
|
|
23
|
+
/** Begin one provider login through the interaction surface owned by the caller. */
|
|
24
|
+
export declare function beginProviderAuthorization(ctx: Context, row: Pick<ProviderAuthorizationRow, 'key'>, method: string, interaction: AuthorizationInteraction, signal?: AbortSignal): Promise<AuthorizationStatus>;
|
|
25
|
+
/** Cancel the attempt currently serving this provider, if any. */
|
|
26
|
+
export declare function cancelProviderAuthorization(ctx: Context, key: CredentialKey): void;
|
|
27
|
+
/** Remove an authorization record without changing the provider's settings profile. */
|
|
28
|
+
export declare function logoutProviderAuthorization(ctx: Context, row: ProviderAuthorizationRow): Promise<void>;
|
|
29
|
+
/** Open an authorization URL with the platform default browser, without invoking a shell. */
|
|
30
|
+
export declare function openAuthorizationUrl(raw: string): boolean;
|
|
31
|
+
/** Compact value-free status for the provider list. */
|
|
32
|
+
export declare function providerAuthorizationStatus(row: ProviderAuthorizationRow | undefined): string;
|
|
33
|
+
/** Find a provider's login flow from a previously loaded directory. */
|
|
34
|
+
export declare function authorizationForProvider(directory: ProviderAuthorizationDirectory | undefined, provider: string): ProviderAuthorizationRow | undefined;
|
|
35
|
+
/** Preserve the upstream entry type in declarations without leaking service internals into the TUI. */
|
|
36
|
+
export type { AuthorizationEntry };
|
|
@@ -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,41 @@
|
|
|
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`). Event types are
|
|
7
|
+
* deliberately NOT requested: Ink 5's parser cannot decode the
|
|
8
|
+
* `:event-type` suffix, and repeat/release reporting buys this surface
|
|
9
|
+
* nothing.
|
|
10
|
+
*
|
|
11
|
+
* Ink 5 also cannot parse most CSI-u forms at all — they fall through its
|
|
12
|
+
* regex as unnamed sequences and get INSERTED AS DRAFT TEXT. The composer's
|
|
13
|
+
* stdin read patch therefore rewrites every CSI-u form it can decode back
|
|
14
|
+
* to the legacy byte or canonical sequence the existing key handling
|
|
15
|
+
* already understands, before Ink ever parses the chunk.
|
|
16
|
+
* @module @deepseek-ai/dsh-code/keyboard
|
|
17
|
+
*/
|
|
18
|
+
/** Push keyboard enhancement (modifyOtherKeys off, kitty flags 1|4). */
|
|
19
|
+
export declare const KEYBOARD_ENHANCE_ENABLE = "\u001B[>4;0m\u001B[>5u";
|
|
20
|
+
/** Pop the enhancement stack and reset modifyOtherKeys (exit path). */
|
|
21
|
+
export declare const KEYBOARD_ENHANCE_DISABLE = "\u001B[<u\u001B[>4;0m";
|
|
22
|
+
/** Enable bracketed paste reporting. */
|
|
23
|
+
export declare const BRACKETED_PASTE_ENABLE = "\u001B[?2004h";
|
|
24
|
+
/** Disable bracketed paste reporting. */
|
|
25
|
+
export declare const BRACKETED_PASTE_DISABLE = "\u001B[?2004l";
|
|
26
|
+
/** Bracketed paste markers as Ink delivers them (it strips the leading ESC). */
|
|
27
|
+
export declare const PASTE_START_MARKER = "[200~";
|
|
28
|
+
export declare const PASTE_END_MARKER = "[201~";
|
|
29
|
+
/**
|
|
30
|
+
* Remove bracketed paste markers from one input chunk. Panel drafts accept raw
|
|
31
|
+
* `input` text, where an unhandled paste would otherwise persist the literal
|
|
32
|
+
* "[200~"/"[201~" markers Ink leaves after stripping the ESC byte.
|
|
33
|
+
*/
|
|
34
|
+
export declare function stripPasteMarkers(text: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Rewrite every decodable kitty CSI-u sequence in one stdin chunk to the
|
|
37
|
+
* legacy form the input layer already handles. Undecodable or non-key
|
|
38
|
+
* sequences pass through untouched, so terminals without the protocol are
|
|
39
|
+
* unaffected.
|
|
40
|
+
*/
|
|
41
|
+
export declare function normalizeKeyboardChunk(chunk: string): string;
|