dsh-code 1.0.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +123 -26
- package/README.md +124 -27
- package/bin/deepseek.mjs +283 -35
- package/cordis.patch.yml +97 -0
- package/lib/index.mjs +5008 -881
- package/lib/session-query.mjs +150 -0
- package/lib/startup.mjs +4 -4
- package/lib/{theme-DCT8Y2xf.mjs → theme-7u5Qo3dF.mjs} +657 -20
- package/lib/types/app.d.ts +106 -62
- package/lib/types/authorization-panel.d.ts +3 -3
- package/lib/types/git-workflow.d.ts +91 -2
- package/lib/types/i18n.d.ts +39 -0
- package/lib/types/index.d.ts +100 -1
- package/lib/types/input-split.d.ts +1 -1
- package/lib/types/kernel-panels.d.ts +107 -29
- package/lib/types/language-panel.d.ts +12 -0
- package/lib/types/locales/en.d.ts +450 -0
- package/lib/types/locales/zh.d.ts +9 -0
- package/lib/types/mentions.d.ts +7 -3
- package/lib/types/models.d.ts +14 -0
- package/lib/types/panel-accent.d.ts +28 -0
- package/lib/types/rainbow.d.ts +69 -0
- package/lib/types/render/animations.d.ts +42 -0
- package/lib/types/render/editor.d.ts +4 -3
- package/lib/types/render/ime-cursor.d.ts +60 -0
- package/lib/types/render/inspector.d.ts +26 -0
- package/lib/types/render/lines.d.ts +21 -1
- package/lib/types/render/markdown.d.ts +1 -1
- package/lib/types/render/projection.d.ts +130 -4
- package/lib/types/render/status.d.ts +9 -9
- package/lib/types/render/text.d.ts +6 -0
- package/lib/types/render/usage.d.ts +113 -0
- package/lib/types/session-directory.d.ts +17 -0
- package/lib/types/session-query.d.ts +92 -0
- package/lib/types/startup.d.ts +1 -1
- package/lib/types/terminal-title.d.ts +66 -0
- package/lib/types/theme-panel.d.ts +2 -2
- package/lib/types/theme.d.ts +271 -52
- package/lib/types/update-panel.d.ts +49 -0
- package/lib/types/update.d.ts +75 -0
- package/lib/types/version.d.ts +4 -3
- package/package.json +246 -90
- package/src/app.ts +1369 -509
- package/src/approval.ts +166 -166
- package/src/authorization-panel.ts +19 -16
- package/src/editor-keys.ts +371 -371
- package/src/git-workflow.ts +229 -3
- package/src/i18n.ts +68 -0
- package/src/index.ts +534 -80
- package/src/input-split.ts +3 -3
- package/src/internals.ts +5 -0
- package/src/kernel-panels.ts +554 -86
- package/src/keyboard.ts +5 -4
- package/src/language-panel.ts +53 -0
- package/src/locales/en.ts +489 -0
- package/src/locales/zh.ts +488 -0
- package/src/mentions.ts +8 -4
- package/src/models.ts +264 -212
- package/src/panel-accent.ts +41 -0
- package/src/presets.ts +1 -1
- package/src/provider-settings.ts +1 -1
- package/src/rainbow.ts +208 -0
- package/src/render/animations.ts +104 -6
- package/src/render/editor.ts +25 -24
- package/src/render/export.ts +116 -95
- package/src/render/ime-cursor.ts +147 -0
- package/src/render/inspector.ts +42 -0
- package/src/render/lines.ts +628 -415
- package/src/render/markdown.ts +15 -3
- package/src/render/projection.ts +572 -21
- package/src/render/status.ts +59 -39
- package/src/render/text.ts +14 -0
- package/src/render/tool-preview.ts +77 -77
- package/src/render/usage.ts +430 -0
- package/src/render/width.ts +2 -2
- package/src/session-directory.ts +8 -6
- package/src/session-query.ts +239 -0
- package/src/startup.ts +3 -3
- package/src/subagents.ts +229 -229
- package/src/terminal-title.ts +190 -0
- package/src/theme-panel.ts +17 -21
- package/src/theme.ts +281 -33
- package/src/update-panel.ts +256 -0
- package/src/update.ts +126 -0
- package/src/version.ts +58 -20
- package/src/whale-glyph.ts +23 -23
package/lib/types/app.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ import type { CommandDescriptor } from '@deepseek-ai/dsh-commands';
|
|
|
18
18
|
import type { ContentBlock, FileBlock, ImageBlock } from '@deepseek-ai/dsh-llm';
|
|
19
19
|
import type { AuthorizationInteraction, AuthorizationStatus } from '@deepseek-ai/dsh-authorization';
|
|
20
20
|
import { type ThemeName } from './theme.ts';
|
|
21
|
+
import { type LanguageName } from './i18n.ts';
|
|
22
|
+
import type { LauncherUpdateStatus } from './update.ts';
|
|
21
23
|
import type { TranscriptStore } from './store.ts';
|
|
22
24
|
import { type TranscriptEntry } from './render/projection.ts';
|
|
23
25
|
import type { ApprovalStore } from './approval.ts';
|
|
@@ -28,16 +30,26 @@ import type { QuestionStore } from './questions.ts';
|
|
|
28
30
|
import type { SkillsView, SkillRow } from './skills.ts';
|
|
29
31
|
import { type MentionCandidate } from './mentions.ts';
|
|
30
32
|
import type { SubagentFeedView } from './subagents.ts';
|
|
31
|
-
import {
|
|
33
|
+
import type { UsageView } from './render/usage.ts';
|
|
34
|
+
import { type JobRow, type SearchRow } from './kernel-panels.ts';
|
|
32
35
|
import type { PresetRow } from './presets.ts';
|
|
33
36
|
import type { PermissionRow } from './permissions.ts';
|
|
34
37
|
import type { PluginRow } from './plugin-inventory.ts';
|
|
35
38
|
import type { SessionDirectoryOptions, SessionRow } from './session-directory.ts';
|
|
36
|
-
import type
|
|
39
|
+
import { type GitDiffView, type ReviewBranch, type ReviewCommit, type ReviewSelection } from './git-workflow.ts';
|
|
37
40
|
import { type ProviderAuthorizationDirectory, type ProviderAuthorizationRow } from './authorization.ts';
|
|
38
41
|
import { type FilePathInspection, type ImagePathInspection } from './attachments.ts';
|
|
39
42
|
/** Visual priority for one bounded local notice. */
|
|
40
43
|
export type NoticeTone = 'info' | 'warning' | 'error';
|
|
44
|
+
/** One mutation the terminal may request for a pending next-turn inbox item. */
|
|
45
|
+
export type QueueMutation = {
|
|
46
|
+
readonly kind: 'remove';
|
|
47
|
+
} | {
|
|
48
|
+
readonly kind: 'edit';
|
|
49
|
+
readonly text: string;
|
|
50
|
+
} | {
|
|
51
|
+
readonly kind: 'steer';
|
|
52
|
+
};
|
|
41
53
|
/** Props the runner hands the app; callbacks stay owned by the runner. */
|
|
42
54
|
export interface AppProps {
|
|
43
55
|
/** Event-fed transcript store for the live session. */
|
|
@@ -76,124 +88,156 @@ export interface AppProps {
|
|
|
76
88
|
* an attachment prepare resolves after the app remounted onto another
|
|
77
89
|
* session, and the runner drops the stale delivery then.
|
|
78
90
|
*/
|
|
79
|
-
dispatch(text: string, attachments?: readonly ContentBlock[], origin?: string)
|
|
80
|
-
/**
|
|
81
|
-
|
|
91
|
+
dispatch: (text: string, attachments?: readonly ContentBlock[], origin?: string) => void;
|
|
92
|
+
/**
|
|
93
|
+
* Submit one line as steering: it joins the turn already running at its next
|
|
94
|
+
* step boundary instead of waiting for the next turn. Same stale-delivery
|
|
95
|
+
* guard as {@link dispatch}.
|
|
96
|
+
*/
|
|
97
|
+
steer: (text: string, attachments?: readonly ContentBlock[], origin?: string) => void;
|
|
82
98
|
/**
|
|
83
99
|
* The FULL current session identity ('' while the first session is pending)
|
|
84
100
|
* — the stale-delivery origin above. Distinct from the short display id.
|
|
85
101
|
*/
|
|
86
102
|
sessionKey: string;
|
|
87
103
|
/** Interrupt the running turn (Esc); true when a turn was cancelled. */
|
|
88
|
-
interrupt()
|
|
104
|
+
interrupt: () => boolean;
|
|
89
105
|
/** Quit: unmount, flush, and request process exit. */
|
|
90
|
-
quit()
|
|
106
|
+
quit: () => void;
|
|
91
107
|
/** Load the selectable model directory (called when /model opens). */
|
|
92
|
-
loadModels()
|
|
108
|
+
loadModels: () => Promise<ModelDirectory>;
|
|
93
109
|
/** Load @mention candidates for the typed query (files + sessions). */
|
|
94
|
-
loadMentions(query: string, signal?: AbortSignal)
|
|
110
|
+
loadMentions: (query: string, signal?: AbortSignal) => Promise<readonly MentionCandidate[]>;
|
|
95
111
|
/** Validate draft image paths without committing attachment objects. */
|
|
96
|
-
inspectImages(paths: readonly string[])
|
|
112
|
+
inspectImages: (paths: readonly string[]) => Promise<readonly ImagePathInspection[]>;
|
|
97
113
|
/** Validate, normalize and persist images immediately before submission. */
|
|
98
|
-
prepareImages(paths: readonly string[], signal?: AbortSignal)
|
|
114
|
+
prepareImages: (paths: readonly string[], signal?: AbortSignal) => Promise<readonly ImageBlock[]>;
|
|
99
115
|
/** Validate draft non-image file paths without committing attachment objects. */
|
|
100
|
-
inspectFiles(paths: readonly string[])
|
|
116
|
+
inspectFiles: (paths: readonly string[]) => Promise<readonly FilePathInspection[]>;
|
|
101
117
|
/** Persist non-image files immediately before submission as durable file blocks. */
|
|
102
|
-
prepareFiles(paths: readonly string[], signal?: AbortSignal)
|
|
118
|
+
prepareFiles: (paths: readonly string[], signal?: AbortSignal) => Promise<readonly FileBlock[]>;
|
|
103
119
|
/** Apply one /model selection (with an advertised reasoning effort, when picked); returns the display label. */
|
|
104
|
-
selectModel(row: ModelRow, effortId?: string)
|
|
120
|
+
selectModel: (row: ModelRow, effortId?: string) => string;
|
|
105
121
|
/** The /subagent override label, '' when delegated agents follow the current model. */
|
|
106
122
|
subagentModel: string;
|
|
107
123
|
/** Apply one /subagent model pick; returns the override label. */
|
|
108
|
-
setSubagentModel(row: ModelRow, effortId?: string)
|
|
124
|
+
setSubagentModel: (row: ModelRow, effortId?: string) => string;
|
|
109
125
|
/** Drop the /subagent override (delegated agents follow the current model). */
|
|
110
|
-
clearSubagentModel()
|
|
126
|
+
clearSubagentModel: () => void;
|
|
111
127
|
/** Delete one session subtree; resolves with the outcome line. */
|
|
112
|
-
deleteSession(id: string)
|
|
128
|
+
deleteSession: (id: string) => Promise<string>;
|
|
113
129
|
/** Load provider/settings/credential facts for the optional /model provider stage. */
|
|
114
|
-
loadModelProviders
|
|
130
|
+
loadModelProviders?: () => Promise<ProviderSettingsDirectory>;
|
|
115
131
|
/** Subscribe to Harness credential/settings/adapter invalidations while /model is open. */
|
|
116
|
-
subscribeModelProviders
|
|
132
|
+
subscribeModelProviders?: (listener: () => void) => () => void;
|
|
117
133
|
/** Store or rotate one provider credential through the Harness credential service. */
|
|
118
|
-
saveModelProviderCredential
|
|
134
|
+
saveModelProviderCredential?: (target: ProviderTargetView, key: string) => Promise<void>;
|
|
119
135
|
/** Remove one writable provider credential without removing its settings profile. */
|
|
120
|
-
unsetModelProviderCredential
|
|
136
|
+
unsetModelProviderCredential?: (target: ProviderTargetView) => Promise<void>;
|
|
121
137
|
/** Remove one user-owned provider profile and its page-managed credential. */
|
|
122
|
-
removeModelProvider
|
|
138
|
+
removeModelProvider?: (target: ProviderTargetView) => Promise<void>;
|
|
123
139
|
/** Save endpoint and explicit model capacities through the provider profile. */
|
|
124
|
-
saveModelProviderConfiguration
|
|
140
|
+
saveModelProviderConfiguration?: (target: ProviderTargetView, configuration: ProviderConfiguration) => Promise<void>;
|
|
125
141
|
/**
|
|
126
142
|
* Interrogate the provider's real endpoint (typed key wins over the stored
|
|
127
143
|
* credential) for the models it actually serves — the discovery stage of
|
|
128
144
|
* the provider setup page.
|
|
129
145
|
*/
|
|
130
|
-
discoverModelProvider
|
|
146
|
+
discoverModelProvider?: (target: ProviderTargetView, request: {
|
|
131
147
|
readonly apiKey?: string;
|
|
132
148
|
readonly baseURL?: string;
|
|
133
|
-
}, signal?: AbortSignal)
|
|
149
|
+
}, signal?: AbortSignal) => Promise<readonly DiscoveredModelView[]>;
|
|
134
150
|
/** Provider authorization flows and value-free stored-record facts. */
|
|
135
|
-
loadProviderAuthorizations
|
|
136
|
-
subscribeProviderAuthorizations
|
|
137
|
-
beginProviderAuthorization
|
|
138
|
-
cancelProviderAuthorization
|
|
139
|
-
logoutProviderAuthorization
|
|
140
|
-
openAuthorizationUrl
|
|
141
|
-
copyTextValue
|
|
142
|
-
/** Cycle to the next
|
|
143
|
-
|
|
151
|
+
loadProviderAuthorizations?: () => Promise<ProviderAuthorizationDirectory>;
|
|
152
|
+
subscribeProviderAuthorizations?: (listener: () => void) => () => void;
|
|
153
|
+
beginProviderAuthorization?: (row: ProviderAuthorizationRow, method: string, interaction: AuthorizationInteraction, signal: AbortSignal) => Promise<AuthorizationStatus>;
|
|
154
|
+
cancelProviderAuthorization?: (row: ProviderAuthorizationRow) => void;
|
|
155
|
+
logoutProviderAuthorization?: (row: ProviderAuthorizationRow) => Promise<void>;
|
|
156
|
+
openAuthorizationUrl?: (url: string) => boolean;
|
|
157
|
+
copyTextValue?: (text: string) => Promise<void>;
|
|
158
|
+
/** Cycle to the next mode station (Shift+Tab): a permission preset or a plan switch; returns the notice label. */
|
|
159
|
+
cycleMode: () => string;
|
|
160
|
+
/** Pre-session plan choice: shows the plan badge before the first session exists. */
|
|
161
|
+
pendingPlan?: boolean;
|
|
144
162
|
/** Select or inspect a permission preset without requiring a pre-existing session. */
|
|
145
|
-
setPermission(id: string)
|
|
163
|
+
setPermission: (id: string) => string;
|
|
146
164
|
/** Export the transcript to a markdown file (/export [path]); reports via notices. */
|
|
147
|
-
exportTranscript(argument: string)
|
|
165
|
+
exportTranscript: (argument: string) => Promise<void>;
|
|
148
166
|
/** Rename the session (/title <text>); returns the outcome line for the notice. */
|
|
149
|
-
renameTitle(argument: string)
|
|
167
|
+
renameTitle: (argument: string) => string;
|
|
150
168
|
/** Copy the latest complete assistant response; resolves to notice text. */
|
|
151
|
-
copyLastResponse()
|
|
169
|
+
copyLastResponse: () => Promise<string>;
|
|
152
170
|
/** Load a complete read-only Git diff for the file-oriented viewport. */
|
|
153
|
-
loadGitDiff(argument: string)
|
|
171
|
+
loadGitDiff: (argument: string) => Promise<GitDiffView>;
|
|
172
|
+
/** Local branches for the /review picker (absent: the picker hides the branch phase's list). */
|
|
173
|
+
listReviewBranches?: (signal?: AbortSignal) => Promise<readonly ReviewBranch[]>;
|
|
174
|
+
/** Recent commits on the current branch for the /review picker. */
|
|
175
|
+
listReviewCommits?: (signal?: AbortSignal) => Promise<readonly ReviewCommit[]>;
|
|
154
176
|
/** Start a model review after applying the read-only permission preset. */
|
|
155
|
-
reviewChanges(
|
|
177
|
+
reviewChanges: (selection: ReviewSelection) => void;
|
|
156
178
|
/** Preset/session/plugin kernel operations. */
|
|
157
|
-
loadPresets()
|
|
158
|
-
switchMode(id: string)
|
|
179
|
+
loadPresets: () => Promise<readonly PresetRow[]>;
|
|
180
|
+
switchMode: (id: string) => Promise<string>;
|
|
159
181
|
/** Load the switchable permission presets for the /permission panel. */
|
|
160
|
-
loadPermissions()
|
|
161
|
-
createSession(mode?: string)
|
|
182
|
+
loadPermissions: () => Promise<readonly PermissionRow[]>;
|
|
183
|
+
createSession: (mode?: string) => void;
|
|
162
184
|
/** Fork the active session at a completed-turn boundary. */
|
|
163
|
-
forkSession(argument: string)
|
|
164
|
-
loadSessions(options: SessionDirectoryOptions, signal?: AbortSignal)
|
|
165
|
-
loadSessionTranscript(id: string, signal?: AbortSignal)
|
|
185
|
+
forkSession: (argument: string) => void;
|
|
186
|
+
loadSessions: (options: SessionDirectoryOptions, signal?: AbortSignal) => Promise<readonly SessionRow[]>;
|
|
187
|
+
loadSessionTranscript: (id: string, signal?: AbortSignal) => Promise<string>;
|
|
188
|
+
/** Read the current session's usage blocks (projections plus per-turn fold). */
|
|
189
|
+
loadUsage: () => Promise<UsageView>;
|
|
190
|
+
/**
|
|
191
|
+
* Full-text search over every persisted session (the in-process
|
|
192
|
+
* session-query engine). Absent when the deployment disabled the row;
|
|
193
|
+
* /search degrades to a notice instead of opening the panel.
|
|
194
|
+
*/
|
|
195
|
+
searchSessions?: (query: string, signal?: AbortSignal) => Promise<readonly SearchRow[]>;
|
|
166
196
|
/** Load this session's subagent conversations (children by lineage). */
|
|
167
|
-
loadSubagents()
|
|
168
|
-
switchSession(row: SessionRow)
|
|
169
|
-
cancelSessionSwitch()
|
|
170
|
-
loadPlugins()
|
|
197
|
+
loadSubagents: () => Promise<readonly SessionRow[]>;
|
|
198
|
+
switchSession: (row: SessionRow) => void;
|
|
199
|
+
cancelSessionSwitch: () => boolean;
|
|
200
|
+
loadPlugins: () => readonly PluginRow[];
|
|
171
201
|
/** Caller-visible background jobs (the host jobs registry, read-only). */
|
|
172
|
-
loadJobs()
|
|
202
|
+
loadJobs: () => readonly JobRow[];
|
|
203
|
+
/** Probe the launcher's aligned update plan (read-only; never installs). */
|
|
204
|
+
probeUpdate: () => Promise<LauncherUpdateStatus>;
|
|
205
|
+
/** Run the launcher's aligned update; streams sanitized lines; resolves with the exit code. */
|
|
206
|
+
applyUpdate: (onLine: (line: string) => void, plan?: {
|
|
207
|
+
readonly dshSpec: string;
|
|
208
|
+
readonly codeSpec: string;
|
|
209
|
+
readonly pluginSpecs: readonly string[];
|
|
210
|
+
}) => Promise<number>;
|
|
173
211
|
/** Registers the app's notice channel with the runner (called once on mount). */
|
|
174
|
-
onBridgeReady(bridge: {
|
|
175
|
-
notify(text: string, tone?: NoticeTone)
|
|
176
|
-
})
|
|
212
|
+
onBridgeReady: (bridge: {
|
|
213
|
+
notify: (text: string, tone?: NoticeTone) => void;
|
|
214
|
+
}) => void;
|
|
177
215
|
/** Ordered enabled status items (/statusline config); the runner owns persistence. */
|
|
178
216
|
statusline: readonly string[];
|
|
179
217
|
/** Persist a new statusline item set; the runner surfaces IO failures as notices. */
|
|
180
|
-
saveStatusline(items: readonly string[])
|
|
218
|
+
saveStatusline: (items: readonly string[]) => void;
|
|
219
|
+
/** Apply and persist one /language selection; the runner owns the language.json file. */
|
|
220
|
+
saveLanguage: (name: LanguageName) => void;
|
|
181
221
|
/** Apply and persist one /theme selection; the runner owns the theme.json file. */
|
|
182
|
-
saveTheme
|
|
222
|
+
saveTheme?: (name: ThemeName) => void;
|
|
183
223
|
/** Whether timed animations run at startup (animations.json; on by default
|
|
184
224
|
* — like parseAnimationsPref, only an explicit false disables them). */
|
|
185
225
|
animations?: boolean;
|
|
186
226
|
/** Apply and persist one /animation toggle; the runner owns the file. */
|
|
187
|
-
saveAnimations
|
|
227
|
+
saveAnimations?: (enabled: boolean) => void;
|
|
188
228
|
/** Persistent cross-session input history (oldest first); the runner owns the file. */
|
|
189
229
|
history: readonly string[];
|
|
190
230
|
/** Persist one submitted prompt to the global history file. */
|
|
191
|
-
recordHistory(text: string)
|
|
192
|
-
/**
|
|
193
|
-
|
|
231
|
+
recordHistory: (text: string) => void;
|
|
232
|
+
/** Mutate one next-turn inbox message; durable inbox splices reconcile the result. */
|
|
233
|
+
updateQueued?: (messageId: string, action: QueueMutation) => void;
|
|
194
234
|
/** Apply the Ctrl+R terminal passthrough to the detected editor (/vscode-keys); resolves to a one-line summary. */
|
|
195
|
-
applyEditorKeys()
|
|
235
|
+
applyEditorKeys: () => Promise<string>;
|
|
196
236
|
}
|
|
237
|
+
/** Rows in the exact next-turn inbox order, never transcript append order. */
|
|
238
|
+
export declare function queuedInboxRows(entries: readonly TranscriptEntry[], ids: readonly string[]): readonly Extract<TranscriptEntry, {
|
|
239
|
+
kind: 'pending';
|
|
240
|
+
}>[];
|
|
197
241
|
/** One completion candidate row. */
|
|
198
242
|
interface CompletionCandidate {
|
|
199
243
|
/** Insertion text for the command name (with leading slash). */
|
|
@@ -16,7 +16,7 @@ export interface ProviderAuthorizationPanelProps {
|
|
|
16
16
|
export declare function ProviderAuthorizationPanel(props: ProviderAuthorizationPanelProps): ReactElement;
|
|
17
17
|
export declare function ProviderAuthorizationLogoutPanel({ row, confirm, done, back }: {
|
|
18
18
|
row: ProviderAuthorizationRow;
|
|
19
|
-
confirm(row: ProviderAuthorizationRow)
|
|
20
|
-
done()
|
|
21
|
-
back()
|
|
19
|
+
confirm: (row: ProviderAuthorizationRow) => Promise<void>;
|
|
20
|
+
done: () => void;
|
|
21
|
+
back: () => void;
|
|
22
22
|
}): ReactElement;
|
|
@@ -28,5 +28,94 @@ export declare function parseGitDiffSpec(argument: string): GitDiffSpec;
|
|
|
28
28
|
* git subprocess instead of letting a stale repository's diff land later.
|
|
29
29
|
*/
|
|
30
30
|
export declare function loadGitDiff(cwd: string, argument: string, signal?: AbortSignal): Promise<GitDiffView>;
|
|
31
|
-
/**
|
|
32
|
-
export
|
|
31
|
+
/** One /review run's selection: what to review plus an optional user note. */
|
|
32
|
+
export type ReviewSelection = {
|
|
33
|
+
readonly kind: 'uncommitted';
|
|
34
|
+
} | {
|
|
35
|
+
readonly kind: 'base-branch';
|
|
36
|
+
readonly branch: string;
|
|
37
|
+
readonly mergeBase?: string;
|
|
38
|
+
} | {
|
|
39
|
+
readonly kind: 'commit';
|
|
40
|
+
readonly sha: string;
|
|
41
|
+
} | {
|
|
42
|
+
readonly kind: 'custom';
|
|
43
|
+
readonly instructions: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The /review argument is always a free-form note applied to the uncommitted
|
|
47
|
+
* working tree (`/review 使用中文` reviews the uncommitted diff in Chinese);
|
|
48
|
+
* branch and commit targets come from the candidate picker, never from
|
|
49
|
+
* argument guessing.
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseReviewArgument(argument: string): ReviewSelection;
|
|
52
|
+
/** The merge base of HEAD and one branch, or undefined when git cannot compute one. */
|
|
53
|
+
export declare function mergeBaseWith(cwd: string, branch: string, signal?: AbortSignal): Promise<string | undefined>;
|
|
54
|
+
/** One commit's own patch (parent..commit), falling back to `git show` for root commits. */
|
|
55
|
+
export declare function loadCommitDiff(cwd: string, sha: string, signal?: AbortSignal): Promise<GitDiffView>;
|
|
56
|
+
/**
|
|
57
|
+
* Build the in-session review prompt: the diff is pasted whole (truncated at
|
|
58
|
+
* the character cap with an explicit marker the model can see), the rubric's
|
|
59
|
+
* essentials ride along — P0-P3 priorities, file/line anchors, only defects
|
|
60
|
+
* this change introduced — and an optional user note (language, focus)
|
|
61
|
+
* prefixes everything as the user's explicit instruction.
|
|
62
|
+
*/
|
|
63
|
+
export declare function buildReviewPrompt(diff: string, label: string, note?: string, maxChars?: number): string;
|
|
64
|
+
/** One branch candidate for the review picker. */
|
|
65
|
+
export interface ReviewBranch {
|
|
66
|
+
readonly name: string;
|
|
67
|
+
}
|
|
68
|
+
/** One commit candidate for the review picker. */
|
|
69
|
+
export interface ReviewCommit {
|
|
70
|
+
readonly sha: string;
|
|
71
|
+
readonly title: string;
|
|
72
|
+
/** Committer timestamp in Unix epoch milliseconds. */
|
|
73
|
+
readonly at: number;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Local branch names for the review picker, newest activity first and with
|
|
77
|
+
* the current branch excluded (reviewing against it is always empty).
|
|
78
|
+
*/
|
|
79
|
+
export declare function listReviewBranches(cwd: string, signal?: AbortSignal): Promise<readonly ReviewBranch[]>;
|
|
80
|
+
/** Recent commits on the current branch for the review picker. */
|
|
81
|
+
export declare function listReviewCommits(cwd: string, signal?: AbortSignal, limit?: number): Promise<readonly ReviewCommit[]>;
|
|
82
|
+
/** One finished review, ready for the terminal's result panel. */
|
|
83
|
+
export interface ReviewResultView {
|
|
84
|
+
/** Panel header naming what was reviewed. */
|
|
85
|
+
readonly title: string;
|
|
86
|
+
/** The reviewer's reply markdown (the findings list). */
|
|
87
|
+
readonly body: string;
|
|
88
|
+
/** Compact summary: finding counts per priority plus the verdict. */
|
|
89
|
+
readonly summary: string;
|
|
90
|
+
/** The review session id, so follow-ups can @-reference its context. */
|
|
91
|
+
readonly sessionId: string;
|
|
92
|
+
}
|
|
93
|
+
/** One parsed review finding from the reviewer's closing JSON block. */
|
|
94
|
+
export interface ReviewFinding {
|
|
95
|
+
/** Priority 0-3 for P0-P3; undefined when the reviewer omitted it. */
|
|
96
|
+
readonly priority?: number;
|
|
97
|
+
/** Finding title, already free of the [P#] prefix when present. */
|
|
98
|
+
readonly title: string;
|
|
99
|
+
/** File path the finding anchors to, when stated. */
|
|
100
|
+
readonly path?: string;
|
|
101
|
+
/** Line range as written, when stated. */
|
|
102
|
+
readonly range?: string;
|
|
103
|
+
}
|
|
104
|
+
/** The parsed conclusion of one review reply. */
|
|
105
|
+
export interface ReviewConclusion {
|
|
106
|
+
readonly findings: readonly ReviewFinding[];
|
|
107
|
+
readonly overall?: 'correct' | 'incorrect';
|
|
108
|
+
readonly explanation?: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Parse the reviewer's reply into a conclusion: whole-text JSON first, then
|
|
112
|
+
* the first balanced JSON object anywhere in the text, then undefined (the
|
|
113
|
+
* reply renders as plain markdown with no summary line). Malformed fields
|
|
114
|
+
* are dropped, never thrown.
|
|
115
|
+
*/
|
|
116
|
+
export declare function parseReviewConclusion(text: string): ReviewConclusion | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* One compact summary line for a finished review: finding counts per
|
|
119
|
+
* priority plus the overall verdict, or a no-findings phrasing.
|
|
120
|
+
*/
|
|
121
|
+
export declare function reviewSummaryLine(conclusion: ReviewConclusion): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface language for the TUI: a module-level current language with a
|
|
3
|
+
* message accessor, mirroring the theme module's setTheme/getPalette shape
|
|
4
|
+
* so a language switch re-renders every translated surface on the next
|
|
5
|
+
* render without touching call sites. English is the default; the persisted
|
|
6
|
+
* choice lives in language.json next to theme.json (see the runner's
|
|
7
|
+
* persistence block).
|
|
8
|
+
*
|
|
9
|
+
* @module @deepseek-ai/dsh-tui/i18n
|
|
10
|
+
*/
|
|
11
|
+
import { type MessageKey } from './locales/en.ts';
|
|
12
|
+
export type { MessageKey } from './locales/en.ts';
|
|
13
|
+
/** Selectable interface languages: English (default) and Chinese. */
|
|
14
|
+
export type LanguageName = 'en' | 'zh';
|
|
15
|
+
/** Valid language names for argument parsing. */
|
|
16
|
+
export declare const LANGUAGE_NAMES: readonly LanguageName[];
|
|
17
|
+
/** One language's picker row. */
|
|
18
|
+
export interface LanguageDescriptor {
|
|
19
|
+
readonly id: LanguageName;
|
|
20
|
+
readonly label: string;
|
|
21
|
+
}
|
|
22
|
+
/** The /language picker rows in canonical order. */
|
|
23
|
+
export declare const LANGUAGES: readonly LanguageDescriptor[];
|
|
24
|
+
/**
|
|
25
|
+
* Parse a persisted or typed language name: only 'en' and 'zh' survive;
|
|
26
|
+
* anything else falls back to English.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseLanguageName(value: unknown): LanguageName;
|
|
29
|
+
/** The language name in force. */
|
|
30
|
+
export declare function getLanguage(): LanguageName;
|
|
31
|
+
/** Switch the active language; the next render paints with the new catalog. */
|
|
32
|
+
export declare function setLanguage(name: LanguageName): void;
|
|
33
|
+
/**
|
|
34
|
+
* One message from the active catalog, with `{n}`-style placeholders filled
|
|
35
|
+
* from the params record. Unknown placeholders stay literal; a missing key
|
|
36
|
+
* falls back to the English entry so a catalog gap degrades visibly but
|
|
37
|
+
* never crashes.
|
|
38
|
+
*/
|
|
39
|
+
export declare function t(key: MessageKey, params?: Readonly<Record<string, string | number>>): string;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -10,10 +10,13 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { Context } from '@deepseek-ai/cordis';
|
|
12
12
|
import z from '@deepseek-ai/schemastery';
|
|
13
|
+
import type { Agent, AgentStatus, Inbox } from '@deepseek-ai/dsh-agent';
|
|
13
14
|
import { type ContentBlock } from '@deepseek-ai/dsh-llm';
|
|
14
|
-
import { SessionId, type SessionEvent } from '@deepseek-ai/dsh-session';
|
|
15
|
+
import { SessionId, type SessionEvent, type SessionHeader, type UserMessage } from '@deepseek-ai/dsh-session';
|
|
15
16
|
import type { SessionPersistence } from '@deepseek-ai/dsh-session-persistence';
|
|
17
|
+
import { type QueueMutation } from './app.ts';
|
|
16
18
|
import type { TuiStartup } from './startup.ts';
|
|
19
|
+
import type { SearchRow } from './kernel-panels.ts';
|
|
17
20
|
/** Stable Cordis plugin name. */
|
|
18
21
|
export declare const name = "tui-runner";
|
|
19
22
|
/** Core services required before the interactive session can start. */
|
|
@@ -39,6 +42,8 @@ interface Target {
|
|
|
39
42
|
cwd?: string;
|
|
40
43
|
seed?: readonly SessionEvent[];
|
|
41
44
|
parentSession?: SessionId;
|
|
45
|
+
/** Marks the session as a subagent conversation in the durable header. */
|
|
46
|
+
origin?: 'subagent';
|
|
42
47
|
seedLength?: number;
|
|
43
48
|
}
|
|
44
49
|
/**
|
|
@@ -73,9 +78,48 @@ export declare function runQuitSequence(steps: readonly QuitCleanupStep[], exit:
|
|
|
73
78
|
/** One composer submission waiting behind the startup delivery. */
|
|
74
79
|
export interface QueuedSubmission {
|
|
75
80
|
readonly text: string;
|
|
81
|
+
/** `steer` inserts into the running turn; `followup` waits for the next one. */
|
|
76
82
|
readonly mode: 'followup' | 'steer';
|
|
77
83
|
readonly images: readonly ContentBlock[];
|
|
78
84
|
}
|
|
85
|
+
/** What one requested queue mutation did; the runner maps it to one notice. */
|
|
86
|
+
export type QueueMutationOutcome = 'removed' | 'edited' | 'steered' | 'unavailable' | 'empty' | 'steerUnavailable';
|
|
87
|
+
/**
|
|
88
|
+
* Replace one queued message's text while keeping its attachments. A queue
|
|
89
|
+
* edit rewrites what the user typed, not what they attached: image and file
|
|
90
|
+
* blocks ride through in delivery order (text first, then attachments, the
|
|
91
|
+
* shape {@link deliverLine} submits). Dropping them here would silently strip
|
|
92
|
+
* an attachment the user already confirmed, so this is the edit's single
|
|
93
|
+
* definition and the panel's read-only marker only mirrors it.
|
|
94
|
+
*/
|
|
95
|
+
export declare function queueEditContent(content: readonly ContentBlock[], text: string): ContentBlock[];
|
|
96
|
+
/**
|
|
97
|
+
* Apply one terminal queue mutation to the live inbox. The decision and the
|
|
98
|
+
* inbox change are pure over the supplied handles so every branch is testable
|
|
99
|
+
* without an agent; steering itself is injected because it wakes the driver
|
|
100
|
+
* rather than mutating the inbox. The durable inbox splices remain the UI's
|
|
101
|
+
* single source of truth — this helper never reports a state the inbox did not
|
|
102
|
+
* actually reach.
|
|
103
|
+
* @param inbox - the live agent inbox (pending lists plus its mutators).
|
|
104
|
+
* @param status - the agent's lifecycle status; steering needs `running`.
|
|
105
|
+
* @param messageId - identity of the queued message to mutate.
|
|
106
|
+
* @param action - the requested mutation.
|
|
107
|
+
* @param steer - submits the removed message as next-step steering.
|
|
108
|
+
* @returns the outcome the caller reports.
|
|
109
|
+
*/
|
|
110
|
+
export declare function applyQueueMutation(inbox: Pick<Inbox, 'nextTurn' | 'append' | 'remove' | 'replace'>, status: AgentStatus, messageId: string, action: QueueMutation, steer: (message: UserMessage) => void): QueueMutationOutcome;
|
|
111
|
+
/**
|
|
112
|
+
* Cancel the active turn while keeping the next-turn queue, then wake the
|
|
113
|
+
* driver again so the preserved messages actually run. `cancel` clears
|
|
114
|
+
* pending work by default and never wakes the driver on its own, so the queue
|
|
115
|
+
* is captured first and re-submitted afterwards: a waking submission latches
|
|
116
|
+
* the wake while the aborted activity converges to idle, which is what turns
|
|
117
|
+
* "preserved" into "sent next" instead of "parked forever". Next-step
|
|
118
|
+
* steering is deliberately dropped — it belonged to the cancelled turn.
|
|
119
|
+
* @param agent - the live agent handle.
|
|
120
|
+
* @returns how many queued messages were preserved across the abort.
|
|
121
|
+
*/
|
|
122
|
+
export declare function cancelPreservingQueue(agent: Pick<Agent, 'inbox' | 'cancel' | 'followup'>): number;
|
|
79
123
|
/**
|
|
80
124
|
* Whether a tagged submission still belongs to the active session. Attachment
|
|
81
125
|
* prepares resolve on the microtask timeline, while a queued session switch
|
|
@@ -85,6 +129,61 @@ export interface QueuedSubmission {
|
|
|
85
129
|
* An untagged (synchronous) or pending-session ('') submission always passes.
|
|
86
130
|
*/
|
|
87
131
|
export declare function submissionBelongsToSession(origin: string | undefined, activeSessionId: string | undefined): boolean;
|
|
132
|
+
/**
|
|
133
|
+
* Root-log catalog facts a resumed session must replay into the subagent
|
|
134
|
+
* feed: constructor seeds never fire on the live bus, so without this the
|
|
135
|
+
* children of a resumed session vanish behind a restart. The empty-child
|
|
136
|
+
* placeholder row (childId '') is a placeholder, not a child, and stays out.
|
|
137
|
+
*/
|
|
138
|
+
export declare function subagentCatalogSeed(events: readonly SessionEvent[]): readonly SessionEvent<'subagent/catalog'>[];
|
|
139
|
+
/**
|
|
140
|
+
* Map one cross-session full-text hit onto the /search panel's row (pure).
|
|
141
|
+
* Labels fall back to the short id form — the engine's hit carries the
|
|
142
|
+
* strongest matching event, not the title observation.
|
|
143
|
+
*/
|
|
144
|
+
export declare function searchHitToRow(hit: {
|
|
145
|
+
header: SessionHeader;
|
|
146
|
+
bestMatch: {
|
|
147
|
+
snippet: string;
|
|
148
|
+
time: number;
|
|
149
|
+
};
|
|
150
|
+
}): SearchRow;
|
|
151
|
+
/** One Shift+Tab station decision for the mode cycle. */
|
|
152
|
+
export type ModeCycleDecision = {
|
|
153
|
+
readonly kind: 'permission';
|
|
154
|
+
readonly preset: string;
|
|
155
|
+
} | {
|
|
156
|
+
readonly kind: 'plan-on';
|
|
157
|
+
} | {
|
|
158
|
+
readonly kind: 'plan-off';
|
|
159
|
+
readonly preset: string;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Decide the next Shift+Tab station. The cycle keeps the preset table's
|
|
163
|
+
* own order (most restrictive first) and inserts ONE plan station between
|
|
164
|
+
* the most restrictive preset and the wrap target: with the shipped three
|
|
165
|
+
* presets the user sees workspace-write → danger-full-access → read-only
|
|
166
|
+
* → plan → workspace-write. Plan IS the most restrictive preset plus the
|
|
167
|
+
* plan prompt layer — entering it switches nothing (the cycle is already
|
|
168
|
+
* parked on read-only), and leaving it lands on the next preset after the
|
|
169
|
+
* most restrictive one. Without the /plan command the cycle is exactly the
|
|
170
|
+
* preset table.
|
|
171
|
+
*
|
|
172
|
+
* `planIntent` covers the committed fold's commit lag: upstream queues a
|
|
173
|
+
* plan switch during an open turn (and the command pipeline is async even
|
|
174
|
+
* idle), so the durable plan/mode event lands AFTER the press that chose
|
|
175
|
+
* it. While an intent from an earlier press is in flight it — not the
|
|
176
|
+
* stale committed fold — decides the station, so repeated presses advance
|
|
177
|
+
* the cycle instead of re-issuing the same plan transition (the stuck
|
|
178
|
+
* plan-on/plan-off toggle). Undefined falls back to the committed fold.
|
|
179
|
+
*/
|
|
180
|
+
export declare function planCycleDecision(input: {
|
|
181
|
+
readonly names: readonly string[];
|
|
182
|
+
readonly current: string;
|
|
183
|
+
readonly inPlan: boolean;
|
|
184
|
+
readonly planAvailable: boolean;
|
|
185
|
+
readonly planIntent?: boolean;
|
|
186
|
+
}): ModeCycleDecision | undefined;
|
|
88
187
|
/**
|
|
89
188
|
* Order-preserving gate for composer input while the startup prompt/images
|
|
90
189
|
* are still preparing. Anything submitted before the startup delivery settles
|